🔶 모델을 LM Studio에서 구동해보았다.
유정이가 gguf형식으로 HF모델을 변경했다고 해서 LM Studio에서 모델을 다운받아 돌려보았다.


대부분 대화가 잘 진행될때도 있고, 이상할때도 있다.
LM Studio 서버 구동

5000번 포트번호로 서버를 켰다.
🔶 서버코드
해당 코드는 VSCode에서 작성했다.
파일명: server1.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from langchain_openai import ChatOpenAI
from langchain_core.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
app = FastAPI()
# CORS 설정
origins = [
"http://localhost", # 개발 중인 클라이언트 주소
"http://localhost:3000", # React 개발 서버 주소
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["POST"],
allow_headers=["Content-Type"],
)
llm = ChatOpenAI(
base_url="http://localhost:5000/v1", # LM Studio의 URL
api_key="lm-studio",
model="sangthree/0707_gguf",
streaming=True,
callbacks=[StreamingStdOutCallbackHandler()],
)
class Message(BaseModel):
question: str # 클라이언트에서 question 필드로 전송될 것으로 기대
@app.post("/chat")
async def chat_with_bot(message: Message):
try:
prompt = PromptTemplate.from_template(
"""You are a helpful, smart, kind, and efficient AI assistant. You always fulfill the user's requests to the best of your ability.
You must generate an answer in Korean.
#Question:
{question}
#Answer: """
)
chain = prompt | llm | StrOutputParser()
response = chain.invoke({"question": message.question}) # 클라이언트로부터 받은 질문 사용
return {"response": response} # JSON 형태로 응답
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
서버 코드 실행방법:
uvicorn server1:app --reload
🔶 프론트엔드의 Chat.jsx코드
import React, { useState } from 'react';
import Layout from '../../components/Layout/Layout';
import { useNavigate } from 'react-router-dom';
import Alert from '../../components/Alert/Alert';
import styles from './Chat.module.scss';
function Chat() {
const [messages, setMessages] = useState([]);
const [userMessage, setUserMessage] = useState('');
const [loading, setLoading] = useState(false);
const [showAlert, setShowAlert] = useState(false);
const navigate = useNavigate();
const handleInputChange = (e) => {
setUserMessage(e.target.value);
};
const handleSendMessage = async () => {
if (!userMessage.trim()) return;
const newMessages = [...messages, { sender: '사용자', text: userMessage }];
setMessages(newMessages);
setUserMessage('');
setLoading(true);
try {
const response = await fetch('http://localhost:8000/chat', { // FastAPI 서버 URL로 수정
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question: userMessage }) // 서버에서 question 필드로 요청을 받기 때문에 수정
});
const data = await response.json();
setMessages([...newMessages, { sender: '컴퓨터', text: data.response }]);
} catch (error) {
console.error('Error:', error);
setMessages([...newMessages, { sender: '컴퓨터', text: 'Error: 응답을 가져올 수 없습니다.' }]);
} finally {
setLoading(false);
}
};
const handleStopClick = () => {
setShowAlert(true);
};
const handleCloseAlert = () => {
setShowAlert(false);
};
const handleConfirmExit = () => {
navigate('/result');
};
return (
<Layout>
<div className={styles.chatContainer}>
<div className={styles.chatWrapper}>
<div className={styles.chatHeader}>
<h1>역할놀이 챗봇</h1>
<button className={styles.stopButton} onClick={handleStopClick}>
X
</button>
</div>
<div className={styles.chatBody}>
{messages.map((msg, index) => (
<div key={index} className={`${styles.message} ${msg.sender === '사용자' ? styles.userMessage : styles.computerMessage}`}>
<strong>{msg.sender}:</strong> {msg.text}
</div>
))}
</div>
<div className={styles.userInput}>
<input
type="text"
id="user-message"
value={userMessage}
onChange={handleInputChange}
placeholder="메시지를 입력하세요..."
className={styles.userMessageInput}
/>
<button className={styles.sendButton} onClick={handleSendMessage}>
전송
</button>
</div>
{loading && <div className={styles.loading}>로딩 중...</div>}
</div>
{showAlert && (
<Alert
message="정말로 종료하시겠습니까?"
onConfirm={handleConfirmExit}
onCancel={handleCloseAlert}
/>
)}
</div>
</Layout>
);
}
export default Chat;
🔶 결과
서버를 키고(LM Studio와 fastAPI), npm start로 프론트 페이지를 키니깐, 다음과 같이 결과가 나온다.

모델을 가져와서 사용하고 있다.. 확실히 LM Studio에서 동작하니깐, 큰 모델도 감당할 수 있는 것 같긴한데...답변이 아주 뒤죽박죽..영어 한글 뒤죽박죽 생뚱맞은 답변....이상하다..
🔶 작동 방식
1. React에서 사용자 입력을 받음
- 사용자가 React 웹 애플리케이션의 입력창에 질문을 입력하고 전송 버튼을 누른다.
2. React가 FastAPI 서버로 POST요청을 통해 전달
- React의 'fetch' API를 사용하여 FastAPI서버로 POST요청을 보냅니다.
- 요청 본문에는 사용자가 입력한 질문이 JSON형식으로 포함됩니다.
3. FastAPI 서버가 LM Studio로 요청을 전달하고 응답을 받음
- FastAPI 서버는 React로부터 받은 질문을 받아 LM Studio로 전달합니다.
- LM Studio는 해당 질문에 대한 답변을 생성합니다.
- FastAPI 서버는 LM Studio로부터 답변을 받아 React로 전달할 준비를 합니다.
4. FastAPI 서버가 LM Studio에서 받은 응답을 React로 전달
- FastAPI 서버는 LM Studio에서 받은 답변을 json형식으로 변환하여 React로 응답합니다.
5. React가 FastAPI 서버로부터 받은 답변을 화면에 표시합니다.
🔶 왜 LM Studio를 사용했는가?
물론 그냥 서버(fastAPI)와 프론트 코드만 써서, 응답을 도출할 수 있다.
LM Studio를 끼지 않았을때는 서버코드에서
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# 모델과 토크나이저 로드
model_name = "어쩌구/저쩌구"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
위와같이 파이썬 라이브러리를 사용하여 언어모델을 로컬에서 실행할 수 있게 했으나, 이 Hugging Face Transformers방식은 응답을 도출하는데 정말 많은 시간이 걸린다(gpu가 없기 때문에). 물론 Hugging Face Transformers도 gpu를 제공하지만, 컴퓨터에 gpu가 내장된 사람만 가져다가 쓸 수 있습니다.
따라서 LM Studio와 같이, gpu가 없는 사용자들이 대규모 언어 모델을 사용할 수 있는 도구들을 사용한거다.
🔶 ngrok
클라이언트가 외부에서 테스트하려면 별도의 배포 과정이 필요합니다. 그래서 Ngrok를 사용해서, 로컬 서버를 즉시 외부에 노출시켜 피드백을 빠르게 받을 수 있습니다.
시스템 구성 요소와 역할
- LM Studio: 언어 모델을 실행하고, FastAPI 서버가 모델에 접근하여 응답을 생성하는 역할을 합니다.
- FastAPI: 클라이언트(React)로부터 요청을 받아 LM Studio로 전달하고, 응답을 받아 클라이언트로 반환하는 웹 서버입니다.
- React (JSX): 사용자 인터페이스를 제공하며, 사용자의 입력을 받아 서버로 요청을 보내고 응답을 받아 화면에 표시합니다.
- Ngrok: 로컬에서 실행 중인 FastAPI 서버를 외부에서 접근할 수 있도록 공용 URL을 생성합니다.
각각의 실행
- LM Studio 실행: 로컬에서 포트 5000번으로 LM Studio 서버를 실행합니다.
- FastAPI 서버 실행: 로컬에서 FastAPI 서버를 실행합니다. 이 서버는 LM Studio에 요청을 전달하여 응답을 받아옵니다.
- Ngrok 실행: ngrok http 8000 명령어를 사용하여 FastAPI 서버가 실행 중인 포트(예: 8000)를 외부에 노출시킵니다.
- React (JSX): 클라이언트는 Ngrok이 생성한 공용 URL을 사용하여 FastAPI 서버에 요청을 보냅니다.
데이터의 흐름
사실 Ngrok를 사용하는 경우와 그렇지 않은 경우, 기본적인 데이터 흐름과 프로세스는 동일합니다. 다만, ngrok를 사용하면 로컬에서 실행되는 FastAPI 서버를 외부에서 접근 가능하게 만들어, 로컬 개발 환경에서도 외부에서 쉽게 접근하고 테스트 할 수 있습니다.
ngrok를 사용한 경우 데이터 흐름은 다음과 같습니다.
1. React에서 사용자 입력을 받음
- 사용자가 React 웹 애플리케이션의 입력창에 질문을 입력하고 전송 버튼을 누릅니다.
2. React가 FastAPI 서버로 POST 요청을 통해 전달
- React의 fetch API를 사용하여 ngrok을 통해 외부에서 접근 가능한 FastAPI 서버 URL로 POST 요청을 보냅니다.
- 요청 본문에는 사용자가 입력한 질문이 JSON 형식으로 포함됩니다.
const handleSendMessage = async () => {
if (!userMessage.trim()) return;
const newMessages = [...messages, { sender: '사용자', text: userMessage }];
setMessages(newMessages);
setUserMessage('');
setLoading(true);
try {
const response = await fetch('http://<ngrok_url>/chat', { // ngrok URL을 여기에 입력
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question: userMessage })
});
const data = await response.json();
setMessages([...newMessages, { sender: '컴퓨터', text: data.response }]);
} catch (error) {
console.error('Error:', error);
setMessages([...newMessages, { sender: '컴퓨터', text: 'Error: 응답을 가져올 수 없습니다.' }]);
} finally {
setLoading(false);
}
};
3. FastAPI 서버가 LM Studio로 요청을 전달하고 응답을 받음
- FastAPI 서버는 React로부터 받은 질문을 받아 LM Studio로 전달합니다.
- LM Studio는 해당 질문에 대한 답변을 생성합니다.
- FastAPI 서버는 LM Studio로부터 답변을 받아 React로 전달할 준비를 합니다.
@app.post("/chat")
async def chat_with_bot(message: Message):
try:
prompt = PromptTemplate.from_template(
"""You are a helpful, smart, kind, and efficient AI assistant. You always fulfill the user's requests to the best of your ability.
You must generate an answer in Korean.
#Question:
{question}
#Answer: """
)
chain = prompt | llm | StrOutputParser()
response = chain.invoke({"question": message.question})
return {"response": response}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
4. FastAPI 서버가 LM Studio에서 받은 응답을 React로 전달
- FastAPI 서버는 LM Studio에서 받은 답변을 JSON 형식으로 변환하여 React로 응답합니다.
5. React가 FastAPI 서버로부터 받은 답변을 화면에 표시
- React는 FastAPI 서버로부터 받은 답변을 화면에 표시합니다.
<div className={styles.chatBody}>
{messages.map((msg, index) => (
<div key={index} className={`${styles.message} ${msg.sender === '사용자' ? styles.userMessage : styles.computerMessage}`}>
<strong>{msg.sender}:</strong> {msg.text}
</div>
))}
</div>
=> 그런데 FastAPI 서버를 배포하면 ngrok를 사용할 필요가 없다고 합니다. ngrok는 주로 로컬 환경에서 개발중인 서버를 외부에서 접근할 수 있도록 하기 위해 사용되기 때문입니다. 배포된 서버는 이미 공용 url을 통해 접근 가능하기 때문에 ngrok가 필요 없습니다.
🔶 ngrok 사용 방법
1. 터미널에 choco install ngrok입력
2. ngrok 실행
- 터미널에서
ngrok http 8000 명령어를 실행하여 FastAPI 서버가 실행 중인 포트(예: 8000)를 외부에 노출시킵니다.
- ngrok이 생성한 URL(예: http://<ngrok_url>)을 복사합니다.
3. React에서 ngrok URL 사용
const response = await fetch('http://<ngrok_url>/chat', { // ngrok URL을 여기에 입력
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question: userMessage })
});
아직 ngrok까지 성공은 못했다. 이건 배포여부보고 시도해도 될 듯.
✏️ 해당 이슈와 관련된, 미해결 문제들
1. LM Studio를 사용해야하는 정확한 이유를 모르겠다.
LM Studio를 왜 사용해야하는지 개념 정리가 잘 안되었다. 꼭 사용해야할까? 혹시 다른 방법은 없을까?
처음에 해당 영상(https://www.youtube.com/watch?v=VkcaigvTrug)을 보고 ollama를 lang-serve랑 연결해서 해보려고 했다가...랭체인에 대한 지식이 없어서 실패했다. 그래서 이 영상(https://www.youtube.com/watch?v=bANQk--Maxs)과 이 영상(https://www.youtube.com/watch?v=wBooPEXu_4E)을 합쳐서 LM Studio를 시도해봤는데 뭔가 아직도 헷갈리고 내가 제대로 한건지 모르겠다.
2. LM Studio의 setting들
(https://www.youtube.com/watch?v=bANQk--Maxs)이 영상을 보면, 응답을 반복해서 한다던지, 헛소리를 한다던지 이상한 건, setting?을 설정을 알맞게 못해서 라는데...무슨소리인지 이해가 안가서 영상을 보다가 포기했다. 뭔 프롬프트 등등 여러 설정 고려해야하는 것 같다.
LM Studio에서 우측에 보면 세팅 부분에 여러 카테고리들이 있는데, 그것들이 뭔지 세세하게 찾아보면 좋겠다. 알아야 작업을 하니깐.

3. LM Studio에서 각 상황마다 다른 모델을 어떻게 구동하지?
현재, LM Studio에서는 무조건 하나의 모델만 내보내고 있는데, 생각해보면, 우리는 어떤 놀이인지에 따라서 다른 모델들을 사용해야한다. 음...어떻게 해야하지?
4. LM Studio의 endpoint에 대해서
나는 지금 LM Studio에서 LM Studio의 5000번 포트에서 /v1경로로 전달되게 했는데, 이렇게 코드를 작성했더니, gpt가 http://localhost:5000/v1/completions이게 올바른 LM Studio의 endpoint?라고 하는데... 뭐 LM Studio에서 권장하는 endpoint형식이 있나보다.. 뭐 보니깐 endpoint몇개 있던데.. API문서를 참고하라는데 뭔소린지 모르겠다.
LM Studio의 API문서를 확인하여 올바른 엔드포인트를 확인하고 해당 엔드포인트를 사용해야한다고 한다. 일반적으로 completions와 같은 엔드포인트는 대규모 언어 모델의 결과를 얻기 위해 사용된다는데, 나는 이 엔드포인트를 꼭 써야만 하는걸로 정해진건지, 아니면 형식상만 그런건지 모르겠고, 그 엔드포인트를 써서 얻는 이점도 모르겠다.
5. LM Studio에서 제공하는 여러 코드

여러 코드 제공하던데.. 차이가 뭐지..
🔶 모델을 LM Studio에서 구동해보았다.
유정이가 gguf형식으로 HF모델을 변경했다고 해서 LM Studio에서 모델을 다운받아 돌려보았다.


대부분 대화가 잘 진행될때도 있고, 이상할때도 있다.
LM Studio 서버 구동
5000번 포트번호로 서버를 켰다.
🔶 서버코드
해당 코드는 VSCode에서 작성했다.
파일명: server1.py
서버 코드 실행방법:
🔶 프론트엔드의 Chat.jsx코드
🔶 결과
서버를 키고(LM Studio와 fastAPI),

npm start로 프론트 페이지를 키니깐, 다음과 같이 결과가 나온다.모델을 가져와서 사용하고 있다.. 확실히 LM Studio에서 동작하니깐, 큰 모델도 감당할 수 있는 것 같긴한데...답변이 아주 뒤죽박죽..영어 한글 뒤죽박죽 생뚱맞은 답변....이상하다..
🔶 작동 방식
1. React에서 사용자 입력을 받음
2. React가 FastAPI 서버로 POST요청을 통해 전달
3. FastAPI 서버가 LM Studio로 요청을 전달하고 응답을 받음
4. FastAPI 서버가 LM Studio에서 받은 응답을 React로 전달
5. React가 FastAPI 서버로부터 받은 답변을 화면에 표시합니다.
🔶 왜 LM Studio를 사용했는가?
물론 그냥 서버(fastAPI)와 프론트 코드만 써서, 응답을 도출할 수 있다.
LM Studio를 끼지 않았을때는 서버코드에서
위와같이 파이썬 라이브러리를 사용하여 언어모델을 로컬에서 실행할 수 있게 했으나, 이 Hugging Face Transformers방식은 응답을 도출하는데 정말 많은 시간이 걸린다(gpu가 없기 때문에). 물론 Hugging Face Transformers도 gpu를 제공하지만, 컴퓨터에 gpu가 내장된 사람만 가져다가 쓸 수 있습니다.
따라서 LM Studio와 같이, gpu가 없는 사용자들이 대규모 언어 모델을 사용할 수 있는 도구들을 사용한거다.
🔶 ngrok
클라이언트가 외부에서 테스트하려면 별도의 배포 과정이 필요합니다. 그래서 Ngrok를 사용해서, 로컬 서버를 즉시 외부에 노출시켜 피드백을 빠르게 받을 수 있습니다.
시스템 구성 요소와 역할
각각의 실행
데이터의 흐름
사실 Ngrok를 사용하는 경우와 그렇지 않은 경우, 기본적인 데이터 흐름과 프로세스는 동일합니다. 다만, ngrok를 사용하면 로컬에서 실행되는 FastAPI 서버를 외부에서 접근 가능하게 만들어, 로컬 개발 환경에서도 외부에서 쉽게 접근하고 테스트 할 수 있습니다.
ngrok를 사용한 경우 데이터 흐름은 다음과 같습니다.
1. React에서 사용자 입력을 받음
2. React가 FastAPI 서버로 POST 요청을 통해 전달
3. FastAPI 서버가 LM Studio로 요청을 전달하고 응답을 받음
4. FastAPI 서버가 LM Studio에서 받은 응답을 React로 전달
5. React가 FastAPI 서버로부터 받은 답변을 화면에 표시
=> 그런데 FastAPI 서버를 배포하면 ngrok를 사용할 필요가 없다고 합니다. ngrok는 주로 로컬 환경에서 개발중인 서버를 외부에서 접근할 수 있도록 하기 위해 사용되기 때문입니다. 배포된 서버는 이미 공용 url을 통해 접근 가능하기 때문에 ngrok가 필요 없습니다.
🔶 ngrok 사용 방법
1. 터미널에
choco install ngrok입력2. ngrok 실행
ngrok http 8000명령어를 실행하여 FastAPI 서버가 실행 중인 포트(예: 8000)를 외부에 노출시킵니다.3. React에서 ngrok URL 사용
아직 ngrok까지 성공은 못했다. 이건 배포여부보고 시도해도 될 듯.
✏️ 해당 이슈와 관련된, 미해결 문제들
1. LM Studio를 사용해야하는 정확한 이유를 모르겠다.
LM Studio를 왜 사용해야하는지 개념 정리가 잘 안되었다. 꼭 사용해야할까? 혹시 다른 방법은 없을까?
처음에 해당 영상(https://www.youtube.com/watch?v=VkcaigvTrug)을 보고 ollama를 lang-serve랑 연결해서 해보려고 했다가...랭체인에 대한 지식이 없어서 실패했다. 그래서 이 영상(https://www.youtube.com/watch?v=bANQk--Maxs)과 이 영상(https://www.youtube.com/watch?v=wBooPEXu_4E)을 합쳐서 LM Studio를 시도해봤는데 뭔가 아직도 헷갈리고 내가 제대로 한건지 모르겠다.
2. LM Studio의 setting들
(https://www.youtube.com/watch?v=bANQk--Maxs)이 영상을 보면, 응답을 반복해서 한다던지, 헛소리를 한다던지 이상한 건, setting?을 설정을 알맞게 못해서 라는데...무슨소리인지 이해가 안가서 영상을 보다가 포기했다. 뭔 프롬프트 등등 여러 설정 고려해야하는 것 같다.
LM Studio에서 우측에 보면 세팅 부분에 여러 카테고리들이 있는데, 그것들이 뭔지 세세하게 찾아보면 좋겠다. 알아야 작업을 하니깐.

3. LM Studio에서 각 상황마다 다른 모델을 어떻게 구동하지?
현재, LM Studio에서는 무조건 하나의 모델만 내보내고 있는데, 생각해보면, 우리는 어떤 놀이인지에 따라서 다른 모델들을 사용해야한다. 음...어떻게 해야하지?
4. LM Studio의 endpoint에 대해서
나는 지금 LM Studio에서 LM Studio의 5000번 포트에서 /v1경로로 전달되게 했는데, 이렇게 코드를 작성했더니, gpt가
http://localhost:5000/v1/completions이게 올바른 LM Studio의 endpoint?라고 하는데... 뭐 LM Studio에서 권장하는 endpoint형식이 있나보다.. 뭐 보니깐 endpoint몇개 있던데.. API문서를 참고하라는데 뭔소린지 모르겠다.LM Studio의 API문서를 확인하여 올바른 엔드포인트를 확인하고 해당 엔드포인트를 사용해야한다고 한다. 일반적으로 completions와 같은 엔드포인트는 대규모 언어 모델의 결과를 얻기 위해 사용된다는데, 나는 이 엔드포인트를 꼭 써야만 하는걸로 정해진건지, 아니면 형식상만 그런건지 모르겠고, 그 엔드포인트를 써서 얻는 이점도 모르겠다.
5. LM Studio에서 제공하는 여러 코드
여러 코드 제공하던데.. 차이가 뭐지..