Ver5.0 ๐ฆ LangChain + Ollama ์ฐ๋ ์์ ์ ๋ณต: ์ธํฐ๋ท ์์ด ๋ด PC์์ ๋์๊ฐ๋ ๋ก์ปฌ AI ์ฑ๋ด ๋ง๋ค๊ธฐ

๐ฆ LangChain + Ollama ์ฐ๋ ์์ ์ ๋ณต: ์ธํฐ๋ท ์์ด ๋ด PC์์ ๋์๊ฐ๋ ๋ก์ปฌ AI ์ฑ๋ด ๋ง๋ค๊ธฐ
์ผ, ํน์ ์ด๋ฐ ์๊ฐ ํด๋ณธ ์ ์์ด? "์ฑGPT ๊ฐ์ ๊ฑฐ ๋ด ์ปดํจํฐ์์ ๊ทธ๋ฅ ๋๋ฆฌ๋ฉด ์ ๋๋?"
API ์๊ธ ๊ฑฑ์ ์์ด, ํ์ฌ ๊ธฐ๋ฐ ๋ฌธ์๋ฅผ ์ธ๋ถ ์๋ฒ๋ก ๋ณด๋ด์ง ์๊ณ , ์์ดํ์ด๊ฐ ๋๊ธด ๋นํ๊ธฐ ์์์๋ ๋ํ๋๋ ๋๋ง์ ์ฑ๋ด. ๊ฒฐ๋ก ๋ถํฐ ๋งํ๋ฉด ๋๋ค. ๊ทธ๊ฒ๋ ์๊ฐ๋ณด๋ค ํจ์ฌ ์ฝ๊ฒ.
์ค๋์ ๋ก์ปฌ LLM ์คํ๊ธฐ์ ๋ํ์ Ollama์, LLM ์ฑ ์กฐ๋ฆฝ ํคํธ์ธ LangChain์ ์ฎ์ด์ ๊ธฐ์ต๋ ฅ ์๋ ์ฑ๋ด โ ์คํธ๋ฆฌ๋ฐ ์ฑ๋ด โ ๋ด ๋ฌธ์๋ฅผ ์ฝ๋ RAG ์ฑ๋ด โ ์น UI๊น์ง ํ ๋ฒ์ ์ญ ๊ฐ๋ณผ ๊ฑฐ์ผ. ์ปคํผ ํ ์ ๋ค๊ณ ๋ฐ๋ผ์ โ
1๋จผ์ ์น๊ตฌ ์๊ฐ๋ถํฐ: Ollama์ LangChain์ ๋๊ตฌ?
๋์ ์ญํ ์ ์๋น์ ๋น์ ํ๋ฉด ๊น๋ํด. Ollama๋ ์ฃผ๋ฐฉ์ฅ์ด์ผ. ์ค์ ๋ก ์๋ฆฌ(ํ ์คํธ ์์ฑ)๋ฅผ ํ๋ LLM์ ๋ด ์ปดํจํฐ์์ ๋๋ ค์ฃผ๋ ์คํ ์์ง์ด์ง. LangChain์ ํ ๋งค๋์ ์ผ. ์๋ ์ฃผ๋ฌธ(์ง๋ฌธ)์ ๋ฐ์์ ์ฃผ๋ฐฉ์ด ์์๋ฃ๊ธฐ ์ข๊ฒ ์ ๋ฆฌํ๊ณ , ์ด์ ๋ํ๋ฅผ ๊ธฐ์ตํ๊ณ , ํ์ํ๋ฉด ์ฐฝ๊ณ (๋ฌธ์ DB)์์ ์ฌ๋ฃ๋ฅผ ๊บผ๋ด ์ฃผ๋ฐฉ์ ๋๊ฒจ์ค.
ChatOllama(์ฑํ
๋ชจ๋ธ), OllamaLLM(ํ
์คํธ ์์ฑ), OllamaEmbeddings(์๋ฒ ๋ฉ) ํด๋์ค๋ฅผ ์ ๊ณตํด.์ฌ์ค Ollama๋ง์ผ๋ก๋
requests.post() ํ ์ค์ด๋ฉด ๋๋ต์ ๋ฐ์. ๊ทธ๋ฐ๋ฐ ๋ํ ๊ธฐ์ต, ๋ฌธ์ ๊ฒ์, ์คํธ๋ฆฌ๋ฐ, ๋ชจ๋ธ ๊ต์ฒด ๊ฐ์ ๊ฑธ ๋ถ์ด๊ธฐ ์์ํ๋ฉด ์ฝ๋๊ฐ ์คํ๊ฒํฐ๊ฐ ๋ผ. LangChain์ ์ฐ๋ฉด ๋์ค์ Ollama ๋์ OpenAI๋ ๋ค๋ฅธ ๋ชจ๋ธ๋ก ๋ฐ๊ฟ ๋๋ ๋ชจ๋ธ ๊ฐ์ฒด ํ ์ค๋ง ๊ฐ์๋ผ์ฐ๋ฉด ๋๋จธ์ง ์ฒด์ธ์ ๊ทธ๋๋ก ๋ ์ ์์ด. ์ด๊ฒ ์ง์ง ํฐ ์ฅ์ ์ด์ผ.๋ก์ปฌ ์ฑ๋ด, ์ฅ๋จ์ ์์งํ๊ฒ
| ๊ตฌ๋ถ | ๋ก์ปฌ (Ollama) | ํด๋ผ์ฐ๋ API |
|---|---|---|
| ๋น์ฉ | ํ ํฐ๋น ๋น์ฉ 0์ (์ ๊ธฐยทํ๋์จ์ด ๋น์ฉ๋ง) | ์ฌ์ฉ๋๋งํผ ๊ณผ๊ธ |
| ๋ฐ์ดํฐ ๋ณด์ | ๋ฐ์ดํฐ๊ฐ ๋ด PC ๋ฐ์ผ๋ก ์ ๋๊ฐ | ์ธ๋ถ ์๋ฒ๋ก ์ ์ก๋จ |
| ์คํ๋ผ์ธ | ๋ชจ๋ธ ๋ฐ์ ๋ค์ ์ธํฐ๋ท ๋ถํ์ | ์ธํฐ๋ท ํ์ |
| ์ฑ๋ฅ | ๋ชจ๋ธ ํฌ๊ธฐยทํ๋์จ์ด์ ๋ฐ๋ผ ํ๊ณ | ์ต์์ ๋ํ ๋ชจ๋ธ ์ฌ์ฉ ๊ฐ๋ฅ |
| ์๋ | GPU ์ ๋ฌด์ ํฌ๊ฒ ์ข์ฐ | ๋์ฒด๋ก ์์ ์ |
๊ทธ๋ฌ๋๊น ์ฌ๋ด ๋ฌธ์ Q&A, ๊ฐ์ธ ๋ ธํธ ๋น์, ๋ฏผ๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ, ํ์ต์ฉ ์คํ์ ๋ก์ปฌ์ด ๋ฑ์ด๊ณ , ์ต๊ณ ์์ค์ ์ถ๋ก ์ด ๊ผญ ํ์ํ ์ผ์ ํด๋ผ์ฐ๋๊ฐ ๋ซ๋ค๋ ๊ฑฐ. ๋ ์ค ํ๋๋ง ๊ณ ๋ฅผ ํ์๋ ์์ด. LangChain ๋๋ถ์ ์์ด ์ฐ๊ธฐ๋ ์ฝ๊ฑฐ๋ .
2Ollama ์ค์นํ๊ณ ์ฒซ ๋ชจ๋ธ ๊นจ์ฐ๊ธฐ
์ค์น๋ ์ง์ง ํ๋ฌดํ ๋งํผ ๊ฐ๋จํด. ๊ณต์ ์ฌ์ดํธ(ollama.com)์์ macOSยทWindows์ฉ ์ค์น ํ์ผ์ ๋ฐ์ ์คํํ๋ฉด ๋. ๋ฆฌ๋ ์ค๋ ๊ณต์ ์ค์น ์คํฌ๋ฆฝํธ ํ ์ค์ด๋ฉด ๋ผ.
# Linux
curl -fsSL https://ollama.com/install.sh | sh
# ์ค์น ํ์ธ
ollama --version
์ค์นํ๋ฉด Ollama ์๋ฒ๊ฐ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์๋์ผ๋ก ๋ . ๋ง์ฝ ์ ๋ ์์ผ๋ฉด ollama serve๋ก ์ง์ ์ผ๋ฉด ๋๊ณ . ์ด์ ๋ชจ๋ธ์ ๋ฐ์๋ณด์.
# ๋ชจ๋ธ ๋ค์ด๋ก๋
ollama pull llama3.1:8b
ollama pull qwen2.5:7b
# ํฐ๋ฏธ๋์์ ๋ฐ๋ก ๋ํ
ollama run qwen2.5:7b
# ๋ฐ์๋ ๋ชจ๋ธ ๋ชฉ๋ก / ํ์ฌ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ ๋ชจ๋ธ
ollama list
ollama ps
# ํ์ ์๋ ๋ชจ๋ธ ์ญ์
ollama rm llama3.1:8b
๋ธ๋ผ์ฐ์ ์์
http://localhost:11434 ์ ์ํ๋ฉด "Ollama is running"์ด๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋ . ์ด๊ฒ ๋ณด์ด๋ฉด LangChain์์ ๋ถ์ ์ค๋น ์๋ฃ!๋ด PC์ ์ด๋ค ๋ชจ๋ธ์ด ๋ง์๊น?
๋ก์ปฌ LLM์ ํต์ฌ ๊ณ ๋ฏผ์ ๊ฒฐ๊ตญ ๋ฉ๋ชจ๋ฆฌ์ผ. Ollama ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ธฐ๋ณธ ํ๊ทธ๋ ๋ณดํต 4๋นํธ ์์ํ(Q4 ๊ณ์ด) ๋ฒ์ ์ด๋ผ ์๋ณธ๋ณด๋ค ํจ์ฌ ๊ฐ๋ฒผ์. ๋๋ต์ ์ธ ๊ฐ์ ์ก์๋ณด๋ฉด ์ด๋ (์ปจํ ์คํธ ๊ธธ์ดยท์์ํ ๋ฐฉ์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ์ด๋ฆผ๊ฐ์ด์ผ).
| ๋ชจ๋ธ ๊ท๋ชจ | ๋๋ต ํ์ ๋ฉ๋ชจ๋ฆฌ(Q4) | ์ด๋ฐ ๋ถ๊ป |
|---|---|---|
| 1B~4B | ์ฝ 1~4GB | ๋ ธํธ๋ถ, ์ ์ฌ์ PC, ๋น ๋ฅธ ํ ์คํธ |
| 7B~9B | ์ฝ 5~8GB | ์ ๋ฌธ ์ฃผ๋ ฅ. 16GB RAM ๋๋ 8GB VRAM ๊ทผ์ฒ |
| 12B~14B | ์ฝ 9~12GB | ํ์ง์ ์ข ๋ ์ํ ๋ |
| 27B~32B | ์ฝ 18~24GB | 24GB๊ธ GPU, 32GB ์ด์ ํตํฉ๋ฉ๋ชจ๋ฆฌ Mac |
| 70B | ์ฝ 40GB ์ด์ | ์ํฌ์คํ ์ด์ ๊ธ |
ํ๊ตญ์ด ์ฑ๋ด์ด๋ผ๋ฉด qwen2.5, gemma2/gemma3, LG AI์ฐ๊ตฌ์์ exaone3.5 ๊ฐ์ ๋ชจ๋ธ์ด ํ๊ตญ์ด๋ฅผ ๊ฝค ์์ฐ์ค๋ฝ๊ฒ ๋ค๋ค. ์๋ฒ ๋ฉ ์ฉ๋๋ก๋ nomic-embed-text, ๋ค๊ตญ์ด์ ๊ฐํ bge-m3 ๊ฐ์ ์ ์ฉ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๋ฐ๋ก ๋ฐ์๋๋ฉด ์ข์. ๋ชจ๋ธ ๋ผ์ธ์ ์ ์ ๋ง ๋น ๋ฅด๊ฒ ๋ฐ๋๋๊น ollama.com์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ด์ง์์ ์ต์ ๋ชฉ๋ก์ ํ ๋ฒ ํ์ด๋ณด๋ ์ต๊ด์ ๋ค์ด์.
CPU๋ง์ผ๋ก๋ ๋์๋ ๊ฐ. ๋ค๋ง 7B ๋ชจ๋ธ ๊ธฐ์ค ๋ต๋ณ์ด ํ ๊ธ์์ฉ ๊ฝค ๋๊ธํ๊ฒ ๋์ฌ ์ ์์ด. Apple Silicon Mac์ ํตํฉ ๋ฉ๋ชจ๋ฆฌ์ Metal ๊ฐ์ ๋๋ถ์ ๋ก์ปฌ LLM ๊ถํฉ์ด ์ข์ ํธ์ด๊ณ , NVIDIA GPU๋ CUDA๋ก ๊ฐ์๋ผ.
3ํ์ด์ฌ ํ๊ฒฝ ์ธํ : ํจํค์ง ์ด๋ฆ ํท๊ฐ๋ฆฌ์ง ๋ง๊ธฐ
์ฌ๊ธฐ์ ๋ง์ ์ฌ๋์ด ์ฒซ ์ฝ๋ถํฐ ์๋ํด. ์๋ ๋ธ๋ก๊ทธ ๊ธ์ ๋ณด๋ฉด from langchain.llms import Ollama๋
from langchain_community.chat_models import ChatOllama๋ผ๊ณ ์ ํ ์๋๋ฐ, ์ง๊ธ์ ์ ์ฉ ํจํค์ง langchain-ollama๋ฅผ ์ฐ๋ ๊ฒ ๊ณต์ ๊ถ์ฅ์ด์ผ. ์ปค๋ฎค๋ํฐ ๋ฒ์ ํด๋์ค๋ deprecated(์ฌ์ฉ ์ค๋จ ์์ ) ์ฒ๋ฆฌ๋๊ฑฐ๋ .
# ๊ฐ์ํ๊ฒฝ ๋ง๋ค๊ธฐ (๊ถ์ฅ)
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# ํ์ ํจํค์ง
pip install -U langchain langchain-ollama
# RAG์ UI๊น์ง ํ๋ ค๋ฉด
pip install -U langchain-community langchain-chroma langchain-text-splitters pypdf streamlit
4Hello, ๋ก์ปฌ AI! ์ฒซ ๋ฒ์งธ ํธ์ถ
์, ๋๋ง์ ์ฒซ ์ฝ๋. ๋ฑ ๋ช ์ค์ด์ผ.
from langchain_ollama import ChatOllama
llm = ChatOllama(
model="qwen2.5:7b", # ollama list์ ์๋ ์ด๋ฆ ๊ทธ๋๋ก
temperature=0.7, # ์ฐฝ์์ฑ ์ ๋ (0์ด๋ฉด ์ผ๊ด์ , ๋์์๋ก ๋ค์)
)
response = llm.invoke("๋ก์ปฌ LLM์ ์ฅ์ ์ ์ธ ์ค๋ก ์๋ ค์ค.")
print(response.content)
invoke()์ ๊ฒฐ๊ณผ๋ ๊ทธ๋ฅ ๋ฌธ์์ด์ด ์๋๋ผ AIMessage ๊ฐ์ฒด์ผ. ๊ทธ๋์ ๋ณธ๋ฌธ์ .content๋ก ๊บผ๋ด์ผ ํด. ์ด ๊ฐ์ฒด์ ํ ํฐ ์ฌ์ฉ๋ ๊ฐ์ ๋ฉํ๋ฐ์ดํฐ๋ ๊ฐ์ด ๋ค์ด ์์ด์ response.usage_metadata๋ก ์
๋ ฅยท์ถ๋ ฅ ํ ํฐ ์๋ฅผ ํ์ธํ ์ ์์ด.
์์ฃผ ๋ง์ง๋ ํ๋ผ๋ฏธํฐ
http://์๋ฒIP:11434๋ก ์ง์ ."json"์ ์ฃผ๋ฉด JSON ํํ ์ถ๋ ฅ์ ๊ฐ์ ํ ์ ์์ด.์๋์ผ, ์ ์์ด์ผ! ์ฒซ ํธ์ถ ๋ ์ GB์ง๋ฆฌ ๋ชจ๋ธ์ ๋์คํฌ์์ ๋ฉ๋ชจ๋ฆฌ๋ก ์ฌ๋ฆฌ๋๋ผ ๊ทธ๋. ๋ ๋ฒ์งธ๋ถํฐ๋ ํ ๋นจ๋ผ์ ธ. ์ด๊ฑธ ์ฝ๋ ์คํํธ๋ผ๊ณ ๋ถ๋ฌ.
5ํ๋กฌํํธ ํ ํ๋ฆฟ๊ณผ LCEL: ํ์ดํ(|)๋ก ์ฒด์ธ ์กฐ๋ฆฝํ๊ธฐ
๋งค๋ฒ ์ง๋ฌธ ๋ฌธ์์ด์ ์์ผ๋ก ์กฐ๋ฆฝํ๋ ๊ฑด ๋นํจ์จ์ ์ด์์. LangChain์ ChatPromptTemplate์ผ๋ก "์์คํ
์ญํ + ์ฌ์ฉ์ ์ง๋ฌธ" ํ์ ๋ง๋ค๊ณ , LCEL(LangChain Expression Language)์ด๋ผ๋ ๋ฌธ๋ฒ์ผ๋ก ๋ถํ์ | ๊ธฐํธ๋ก ์ด์ด ๋ถ์ฌ. ๋ฆฌ๋
์ค ํ์ดํ์ฒ๋ผ ์ผ์ชฝ ๊ฒฐ๊ณผ๊ฐ ์ค๋ฅธ์ชฝ ์
๋ ฅ์ผ๋ก ํ๋ฌ๊ฐ๋ ๊ตฌ์กฐ์ผ.
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOllama(model="qwen2.5:7b", temperature=0.3)
prompt = ChatPromptTemplate.from_messages([
("system", "๋๋ ์น์ ํ {role}์ผ. ๋ฐ๋์ ํ๊ตญ์ด๋ก, ์ฝ๊ฒ ์ค๋ช
ํด."),
("human", "{question}"),
])
chain = prompt | llm | StrOutputParser()
answer = chain.invoke({
"role": "ํ์ด์ฌ ์ ์๋",
"question": "๋ฆฌ์คํธ ์ปดํ๋ฆฌํจ์
์ด ๋ญ์ผ?",
})
print(answer)
StrOutputParser()๊ฐ AIMessage์์ ํ
์คํธ๋ง ์ ๋ฝ์์ฃผ๋๊น ๊ฒฐ๊ณผ๊ฐ ๋ฐ๋ก ๋ฌธ์์ด๋ก ๋์. ์ด๋ ๊ฒ ๋ง๋ chain์ Runnable์ด๋ผ๋ ๊ณตํต ์ธํฐํ์ด์ค๋ฅผ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์ invoke()(ํ ๋ฒ), stream()(์ค์๊ฐ), batch()(์ฌ๋ฌ ๊ฐ ๋์) ๋ฉ์๋๋ฅผ ๋๊ฐ์ด ์ธ ์ ์์ด. ๋น๋๊ธฐ ๋ฒ์ ์ธ ainvoke(), astream()๋ ์๊ณ .
6์คํธ๋ฆฌ๋ฐ: ํ์ ์น๋ฏ ๋ต์ด ํ๋ฌ๋์ค๊ฒ
๋ก์ปฌ ๋ชจ๋ธ์ ํด๋ผ์ฐ๋๋ณด๋ค ๋๋ฆฐ ๊ฒฝ์ฐ๊ฐ ๋ง์์, ๋ต์ด ๋ค ์์ฑ๋ ๋๊น์ง ๋ฉํ๋ ๊ธฐ๋ค๋ฆฌ๋ฉด ์ฒด๊ฐ์ด ๋ณ๋ก์ผ. ๊ทธ๋์ ์คํธ๋ฆฌ๋ฐ์ ๋ก์ปฌ ์ฑ๋ด์ ํ์ ์ต์ ์ด์ผ.
for chunk in chain.stream({"role": "์ฌํ ๊ฐ์ด๋", "question": "์ ์ฃผ๋ 2๋ฐ3์ผ ์ฝ์ค ์ถ์ฒํด์ค"}):
print(chunk, end="", flush=True)
์ฒด์ธ ๋์ StrOutputParser๊ฐ ์์ผ๋๊น chunk๊ฐ ๋ฌธ์์ด ์กฐ๊ฐ์ผ๋ก ๋ค์ด์. ๊ฐ์ ์๊ฐ์ด ๊ฑธ๋ ค๋ ์ฒซ ๊ธ์๊ฐ ๋ฐ๋ก ๋ณด์ด๋๊น ์ฌ์ฉ์๊ฐ ๋๋ผ๋ ์๋๋ ์์ ํ ๋ฌ๋ผ์ ธ.
7๊ธ๋ถ์ด ํ์ถ: ๋ํ ๊ธฐ์ต ๋ถ์ด๊ธฐ
LLM์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฌด์ํ(stateless)์ผ. "๋ด ์ด๋ฆ์ ๋ฏผ์์ผ" ํ๊ณ ๋ค์ ์ง๋ฌธ์ "๋ด ์ด๋ฆ ๋ญ๊ฒ?" ํ๋ฉด ๋ชจ๋ฅธ๋ค๊ณ ํด. ๊ธฐ์ต์ ๋ชจ๋ธ์ด ํ๋ ๊ฒ ์๋๋ผ ์ฐ๋ฆฌ๊ฐ ์ด์ ๋ํ๋ฅผ ๋งค๋ฒ ๊ฐ์ด ๋ณด๋ด์ค์ ์๊ธฐ๋ ๊ฑฐ๊ฑฐ๋ . LangChain์์ MessagesPlaceholder๋ก ๋ํ ๊ธฐ๋ก์ด ๋ค์ด๊ฐ ์๋ฆฌ๋ฅผ ๋ง๋ค๊ณ , RunnableWithMessageHistory๋ก ์ธ์ ๋ณ ๊ธฐ๋ก์ ์๋ ๊ด๋ฆฌํด.
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
llm = ChatOllama(model="qwen2.5:7b", temperature=0.5)
prompt = ChatPromptTemplate.from_messages([
("system", "๋๋ ์ ์พํ ํ๊ตญ์ด AI ์น๊ตฌ์ผ. ์งง๊ณ ์ฌ๋ฏธ์๊ฒ ๋ตํด."),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
chain = prompt | llm | StrOutputParser()
store = {} # ์ธ์
ID๋ณ ๋ํ ๊ธฐ๋ก ์ ์ฅ์
def get_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chatbot = RunnableWithMessageHistory(
chain,
get_history,
input_messages_key="input",
history_messages_key="history",
)
config = {"configurable": {"session_id": "minsu"}}
while True:
user = input("\n๋: ")
if user.strip() in ("exit", "quit", "์ข
๋ฃ"):
break
print("AI: ", end="")
for chunk in chatbot.stream({"input": user}, config=config):
print(chunk, end="", flush=True)
์ด์ ํฐ๋ฏธ๋์์ ์ง์ง ๋ํ๊ฐ ์ด์ด์ ธ! session_id๋ฅผ ๋ค๋ฅด๊ฒ ์ฃผ๋ฉด ์ฌ์ฉ์๋ณ๋ก ๊ธฐ์ต์ด ๋ถ๋ฆฌ๋๋๊น ์ฌ๋ฌ ๋ช
์ด ์ฐ๋ ์๋น์ค๋ก ํ์ฅํ๊ธฐ๋ ์ฌ์.
๋ํ๊ฐ ๊ธธ์ด์ง์๋ก ๋งค๋ฒ ๋ณด๋ด๋ history๊ฐ ์ปค์ ธ์ ๊ฒฐ๊ตญ
num_ctx๋ฅผ ๋์ด๊ฐ. ๊ทธ๋ฌ๋ฉด ์๋ถ๋ถ์ด ์๋ฆฌ๊ฑฐ๋ ์๋๊ฐ ๋๋ ค์ง์ง. ์ค์ ์์ langchain_core.messages์ trim_messages๋ก ์ต๊ทผ N๊ฐ ํ ํฐ๋ง ๋จ๊ธฐ๊ฑฐ๋, ์ค๋๋ ๋ํ๋ฅผ ์์ฝํด์ ๋ฃ๋ ๋ฐฉ์์ ์จ. InMemoryChatMessageHistory๋ ํ๋ก๊ทธ๋จ์ ๋๋ฉด ๋ ์๊ฐ๋๊น, ์๊ตฌ ์ ์ฅ์ด ํ์ํ๋ฉด SQLiteยทRedis ๊ฐ์ ์ ์ฅ์ ๊ธฐ๋ฐ ํ์คํ ๋ฆฌ ํด๋์ค๋ฅผ ์ฐ๋ฉด ๋ผ.์ฐธ๊ณ ๋ก LangChain ์ชฝ์์๋ ๋ ๋ณต์กํ ์ํ ๊ด๋ฆฌ(๋ฉํฐํด ์์ด์ ํธ, ์ฒดํฌํฌ์ธํธ ์ ์ฅ ๋ฑ)์ ์๋งค ํ๋ก์ ํธ์ธ LangGraph ์ฌ์ฉ์ ๊ถํ๋ ์ถ์ธ์ผ. ๋จ์ ์ฑ๋ด์ด๋ผ๋ฉด ์ ๋ฐฉ์์ผ๋ก ์ถฉ๋ถํด.
8ํ์ด๋ผ์ดํธ: ๋ด ๋ฌธ์๋ฅผ ์ฝ๋ RAG ์ฑ๋ด
๋ก์ปฌ ์ฑ๋ด์ ์ง์ง ๊ฝ์ RAG(Retrieval-Augmented Generation, ๊ฒ์ ์ฆ๊ฐ ์์ฑ)์ผ. ๋ชจ๋ธ์ ์ฐ๋ฆฌ ํ์ฌ ๊ท์ ์ง์ด๋ ๋ด ๊ฐ์ ๋ ธํธ๋ฅผ ํ์ตํ ์ ์ด ์์์? ๊ทธ๋์ ์ง๋ฌธ์ด ๋ค์ด์ค๋ฉด ๊ด๋ จ ๋ฌธ์ ์กฐ๊ฐ์ ๋จผ์ ์ฐพ์์ ํ๋กฌํํธ์ ๋ผ์ ๋ฃ๊ณ , ๊ทธ๊ฑธ ๊ทผ๊ฑฐ๋ก ๋ตํ๊ฒ ๋ง๋๋ ๊ฑฐ์ผ. ์คํ๋ถ ์ํ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฑ์ด์ผ.
์๋ฒ ๋ฉ์ด ๋ญ๋๋ฉด
์๋ฒ ๋ฉ์ ๋ฌธ์ฅ์ ์ซ์ ๋ฒกํฐ(์ขํ)๋ก ๋ฐ๊พธ๋ ๊ฑฐ์ผ. ๋ป์ด ๋น์ทํ ๋ฌธ์ฅ์ ์ขํ ๊ณต๊ฐ์์ ๊ฐ๊น์ด ๋ชจ์ด๊ฒ ๋ผ. "ํด๊ฐ ์ ์ฒญ ๋ฐฉ๋ฒ"๊ณผ "์ฐ์ฐจ ์ฐ๋ ๋ฒ"์ ๋จ์ด๊ฐ ๋ฌ๋ผ๋ ๋ฒกํฐ๊ฐ ๊ฐ๊น์ง. ๊ทธ๋์ ํค์๋ ๊ฒ์๋ณด๋ค ํจ์ฌ ๋๋ํ๊ฒ ๊ด๋ จ ๋ด์ฉ์ ์ฐพ์๋ด. ์ด ๋ณํ๋ Ollama์ ์๋ฒ ๋ฉ ๋ชจ๋ธ๋ก ๋ก์ปฌ์์ ์ฒ๋ฆฌํ๋๊น ๋ฌธ์๊ฐ ๋ฐ์ผ๋ก ๋๊ฐ ์ผ์ด ์์ด.
ollama pull nomic-embed-text # ๋๋ ๋ค๊ตญ์ด ๊ฐ์ ์ bge-m3
์ ์ฒด RAG ์ฝ๋
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# 1) ๋ฌธ์ ๋ก๋
docs = PyPDFLoader("company_rules.pdf").load()
# 2) ์ฒญํฌ ๋ถํ
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
chunks = splitter.split_documents(docs)
# 3) ์๋ฒ ๋ฉ + ๋ฒกํฐDB ์ ์ฅ (๋์คํฌ์ ์๊ตฌ ๋ณด๊ด)
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectordb = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db",
)
# 4) ๊ฒ์๊ธฐ: ์ง๋ฌธ๊ณผ ๊ฐ์ฅ ๋น์ทํ ์กฐ๊ฐ 4๊ฐ
retriever = vectordb.as_retriever(search_kwargs={"k": 4})
def format_docs(docs):
return "\n\n".join(d.page_content for d in docs)
prompt = ChatPromptTemplate.from_messages([
("system",
"์๋ [๋ฌธ์]๋ง ๊ทผ๊ฑฐ๋ก ํ๊ตญ์ด๋ก ๋ตํด. ๋ฌธ์์ ์์ผ๋ฉด '๋ฌธ์์์ ์ฐพ์ ์ ์์ด์'๋ผ๊ณ ๋งํด.\n\n[๋ฌธ์]\n{context}"),
("human", "{question}"),
])
llm = ChatOllama(model="qwen2.5:7b", temperature=0, num_ctx=8192)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
print(rag_chain.invoke("์ฐ์ฐจ๋ ๋ฉฐ์น ์ ์ ์ ์ฒญํด์ผ ํด?"))
ํฌ์ธํธ๋ฅผ ์ง์ด๋ณผ๊ฒ. ์ฒด์ธ ๋งจ ์์ ๋์
๋๋ฆฌ๊ฐ ํต์ฌ์ด์ผ. ์ง๋ฌธ ๋ฌธ์์ด์ด ๋ค์ด์ค๋ฉด RunnablePassthrough()๋ ์ง๋ฌธ์ ๊ทธ๋๋ก question์ ๋ฃ๊ณ , ๋์์ retriever๊ฐ ๊ทธ ์ง๋ฌธ์ผ๋ก ๋ฌธ์๋ฅผ ๊ฒ์ํด์ format_docs๋ก ํฉ์น ๋ค context์ ๋ฃ์ด์ค. ๋ ๊ฐ๋๊ฐ ๋ณ๋ ฌ๋ก ํ๋ฌ๊ฐ์ ํ๋กฌํํธ์์ ๋ง๋๋ ๊ตฌ์กฐ์ง.
๐ฏ RAG ํ์ง ์ฌ๋ฆฌ๋ ์ค์ ์ฒดํฌ
chunk_size: ๋๋ฌด ์์ผ๋ฉด ๋ฌธ๋งฅ์ด ๋๊ธฐ๊ณ , ๋๋ฌด ํฌ๋ฉด ๊ฒ์์ด ํ๋ฆฟํด์ ธ. 500~1000์ ์ฌ์ด์์ ์์ํด์ ๋ฌธ์ ์ฑ๊ฒฉ์ ๋ง๊ฒ ์กฐ์ .
chunk_overlap: ์กฐ๊ฐ ๊ฒฝ๊ณ์์ ๋ฌธ์ฅ์ด ์๋ฆฌ๋ ๊ฑธ ๋ง๋ ๊ฒน์นจ. ๋ณดํต ์ฒญํฌ์ 10~20%.
temperature=0: ๋ฌธ์ ๊ธฐ๋ฐ ๋ต๋ณ์ ์ฐฝ์์ฑ๋ณด๋ค ์ ํ์ฑ์ด ์ค์ํด.
num_ctx ํ์ฅ: ๊ฒ์๋ ์กฐ๊ฐ 4๊ฐ + ์ง๋ฌธ + ์์คํ
ํ๋กฌํํธ๊ฐ ๋ค ๋ค์ด๊ฐ ๋งํผ ๋๋ํ๊ฒ.
์๋ฒ ๋ฉ ๋ชจ๋ธ ๊ณ ์ : ์ ์ฅํ ๋์ ๊ฒ์ํ ๋ ๋ฐ๋์ ๊ฐ์ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ์จ์ผ ํด. ๋ฐ๊พธ๋ฉด DB๋ฅผ ๋ค์ ๋ง๋ค์ด์ผ ํด.
"๋ชจ๋ฅด๋ฉด ๋ชจ๋ฅธ๋ค" ์ง์: ํ๊ฐ(hallucination)์ ์ค์ด๋ ๊ฐ์ฅ ๊ฐ์ผ ๋ฐฉ๋ฒ.
ํ ๋ฒ ๋ง๋ DB๋ ๋ค์ ์คํ ๋ ๋ค์ ์๋ฒ ๋ฉํ ํ์ ์์ด ์ด๋ ๊ฒ ๋ถ๋ฌ์ค๋ฉด ๋ผ.
vectordb = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
9ํฐ๋ฏธ๋์ ์ด์ ๊ทธ๋ง! Streamlit์ผ๋ก ์น UI ์ ํ๊ธฐ
์น๊ตฌ๋ ํ์ํํ
๋ณด์ฌ์ฃผ๋ ค๋ฉด ํ๋ฉด์ด ์์ด์ผ์ง. Streamlit์ ํ์ด์ฌ๋ง์ผ๋ก ์ฑํ
UI๋ฅผ ๋๋ฑ ๋ง๋ค ์ ์๊ฒ st.chat_input, st.chat_message ๊ฐ์ ์ฑํ
์ ์ฉ ์ปดํฌ๋ํธ๋ฅผ ์ ๊ณตํด. ๊ฒ๋ค๊ฐ st.write_stream์ ์ ๋๋ ์ดํฐ๋ฅผ ๋๊ธฐ๋ฉด ์คํธ๋ฆฌ๋ฐ ์ถ๋ ฅ๋ ์์์ ํด์ค.
# app.py
import streamlit as st
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.messages import HumanMessage, AIMessage
st.set_page_config(page_title="๋ก์ปฌ AI ์ฑ๋ด", page_icon="๐ฆ")
st.title("๐ฆ ๋ด PC ์์ AI ์น๊ตฌ")
model_name = st.sidebar.selectbox("๋ชจ๋ธ ์ ํ", ["qwen2.5:7b", "llama3.1:8b", "gemma2:9b"])
temp = st.sidebar.slider("temperature", 0.0, 1.0, 0.5)
llm = ChatOllama(model=model_name, temperature=temp)
prompt = ChatPromptTemplate.from_messages([
("system", "๋๋ ๋ค์ ํ ํ๊ตญ์ด AI ์น๊ตฌ์ผ."),
MessagesPlaceholder("history"),
("human", "{input}"),
])
chain = prompt | llm | StrOutputParser()
if "messages" not in st.session_state:
st.session_state.messages = []
for msg in st.session_state.messages:
role = "user" if isinstance(msg, HumanMessage) else "assistant"
with st.chat_message(role):
st.markdown(msg.content)
if user_input := st.chat_input("๋ฌด์์ด๋ ๋ฌผ์ด๋ด!"):
with st.chat_message("user"):
st.markdown(user_input)
with st.chat_message("assistant"):
answer = st.write_stream(
chain.stream({"input": user_input, "history": st.session_state.messages})
)
st.session_state.messages.append(HumanMessage(user_input))
st.session_state.messages.append(AIMessage(answer))
streamlit run app.py
๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฆฌ๋ฉด์ ChatGPT ๋น์ทํ ์ฑํ
ํ๋ฉด์ด ์ง ํ๊ณ ๋ํ๋. ์ฌ์ด๋๋ฐ์์ ๋ชจ๋ธ์ ๋ฐ๊ฟ๊ฐ๋ฉฐ ๋น๊ตํด๋ณด๋ ์ฌ๋ฏธ๊ฐ ์ ์ ํด. Streamlit์ ์ฌ์ฉ์ ์
๋ ฅ์ด ์์ ๋๋ง๋ค ์คํฌ๋ฆฝํธ๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ์คํํ๋ ๊ตฌ์กฐ๋ผ์, ๋ํ ๊ธฐ๋ก์ ๊ผญ st.session_state์ ๋ฃ์ด๋ฌ์ผ ๋ ์๊ฐ์ง ์์.
Gradio์
ChatInterface๋ ๋ช ์ค์ด๋ฉด ์ฑํ
UI๊ฐ ๋์. ์ฝ๋ ์์ด ๋ฐ๋ก ์ฐ๊ณ ์ถ์ผ๋ฉด Ollama์ ๋ถ๋ ์คํ์์ค ์น UI์ธ Open WebUI ๊ฐ์ ๋๊ตฌ๋ ์์ด. ํ์ง๋ง "๋ด ๋ก์ง์ ๋ฃ์ ์ฑ๋ด"์ ๋ง๋๋ ๊ฒ ๋ชฉ์ ์ด๋ฉด LangChain + Streamlit ์กฐํฉ์ด ํ์ต ํจ๊ณผ๊ฐ ์ ์ผ ์ข์.10ํ ๋จ๊ณ ๋: Modelfile๋ก ๋๋ง์ ์บ๋ฆญํฐ ๋ชจ๋ธ ๋ง๋ค๊ธฐ
Ollama์ ๋์ปคํ์ผ์ฒ๋ผ ์๊ธด Modelfile์ด ์์ด. ๊ธฐ๋ณธ ๋ชจ๋ธ์ ์์คํ ํ๋กฌํํธ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ๋ฃ์ด์ ์ ์ด๋ฆ์ ๋ชจ๋ธ๋ก ์ ์ฅํ๋ ๊ธฐ๋ฅ์ด์ผ.
# Modelfile
FROM qwen2.5:7b
PARAMETER temperature 0.4
PARAMETER num_ctx 8192
SYSTEM """๋๋ ์ฌ๋ด IT ํฌํ๋ฐ์คํฌ ์ง์ '๋ผ๋ง๋ด'์ด์ผ. ํญ์ ์กด๋๋ง๋ก, ๋จ๊ณ๋ณ๋ก ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์๋ดํด."""
ollama create llamabot -f Modelfile
ollama run llamabot
์ด๋ ๊ฒ ๋ง๋ llamabot์ LangChain์์๋ ChatOllama(model="llamabot")๋ก ๊ทธ๋๋ก ๋ถ๋ฌ ์ธ ์ ์์ด. ์ฌ๋ฌ ์ฑ์์ ๊ฐ์ ์ค์ ์ ๊ณต์ ํ ๋ ํธํ์ง.
11๋๊ตฌ ํธ์ถ(Tool Calling): ์ฑ๋ด์ ์๋ฐ ๋ฌ์์ฃผ๊ธฐ
์ต๊ทผ Ollama๋ ๋๊ตฌ ํธ์ถ์ ์ง์ํ๋ ๋ชจ๋ธ(์: llama3.1, qwen2.5 ๋ฑ)์ ๋ํด function calling์ ์ง์ํด. LangChain์์ bind_tools()๋ก ํ์ด์ฌ ํจ์๋ฅผ ๋ชจ๋ธ์ ์ฐ๊ฒฐํ ์ ์์ด. ๋ชจ๋ธ์ด "์ด ์ง๋ฌธ์ ๊ณ์ฐ๊ธฐ๊ฐ ํ์ํ๊ฒ ๋ค" ํ๋จํ๋ฉด ํจ์ ์ด๋ฆ๊ณผ ์ธ์๋ฅผ ๋ง๋ค์ด ๋๋ ค์ฃผ๋ ๋ฐฉ์์ด์ผ.
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
@tool
def add(a: int, b: int) -> int:
"""๋ ์ ์๋ฅผ ๋ํ๋ค."""
return a + b
llm = ChatOllama(model="qwen2.5:7b", temperature=0)
llm_with_tools = llm.bind_tools([add])
msg = llm_with_tools.invoke("1234 ๋ํ๊ธฐ 5678์?")
print(msg.tool_calls)
# ์: [{'name': 'add', 'args': {'a': 1234, 'b': 5678}, ...}]
์ค์ํ ๊ฑด, ๋ชจ๋ธ์ ํจ์๋ฅผ ์ง์ ์คํํ์ง ์๊ณ "์ด๋ ๊ฒ ํธ์ถํด์ค"๋ผ๋ ์์ฒญ๋ง ๋ง๋ ๋ค๋ ๊ฑฐ์ผ. ์ค์ ์คํ๊ณผ ๊ฒฐ๊ณผ ์ ๋ฌ์ ์ฐ๋ฆฌ ์ฝ๋(๋๋ LangGraph ๊ฐ์ ์์ด์ ํธ ํ๋ ์์ํฌ)๊ฐ ๋งก์. ์์ ๋ก์ปฌ ๋ชจ๋ธ์ ๋๊ตฌ ์ ํ์ด ๊ฐ๋ ์๋ฑํ ์ ์์ผ๋ temperature๋ฅผ ๋ฎ์ถ๊ณ ํจ์ ์ค๋ช (docstring)์ ๋ช ํํ๊ฒ ์จ์ฃผ๋ ๊ฒ ์ข์.
๋ with_structured_output()์ ์ฐ๋ฉด Pydantic ์คํค๋ง์ ๋ง์ถ ๊ตฌ์กฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ์๋ ์์ด. ๋ฆฌ๋ทฐ ๊ฐ์ฑ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ {"๊ฐ์ ": "๊ธ์ ", "์ ์": 0.9} ํํ๋ก ๋ฐ์์ DB์ ๋ฐ๋ก ๋ฃ๋ ์์ผ๋ก ํ์ฉํ๋ฉด ๊ฟ์ด์ผ.
12์ฝ์ง ๋ฐฉ์ง ํธ๋ฌ๋ธ์ํ ๋ชจ์
| ์ฆ์ | ์์ธ๊ณผ ํด๊ฒฐ |
|---|---|
| Connection refused | Ollama ์๋ฒ๊ฐ ๊บผ์ ธ ์์. ollama serve ์คํ ๋๋ ์ฑ ์ฌ์์. ๋์ปค ์์์ ์ ๊ทผ ์ localhost ๋์ ํธ์คํธ ์ฃผ์(์: host.docker.internal) ์ฌ์ฉ. |
| model not found | ๋ชจ๋ธ ๋ฏธ๋ค์ด๋ก๋ ๋๋ ์ด๋ฆ ์คํ. ollama list๋ก ์ ํํ ํ๊ทธ ํ์ธ ํ ollama pull. |
| ImportError / deprecated ๊ฒฝ๊ณ | ์์ import ๊ฒฝ๋ก ์ฌ์ฉ. from langchain_ollama import ChatOllama๋ก ๊ต์ฒด. |
| ๋ต๋ณ์ด ์์ฒญ ๋๋ฆผ | ๋ชจ๋ธ์ด ๋ฉ๋ชจ๋ฆฌ๋ณด๋ค ์ปค์ ์ผ๋ถ๊ฐ CPU๋ก ๋์ด๊ฐ. ollama ps๋ก GPU/CPU ๋น์จ ํ์ธ ํ ๋ ์์ ๋ชจ๋ธ์ด๋ ๋ฎ์ ์์ํ ์ฌ์ฉ. |
| ๊ธด ๋ฌธ์ ๋ด์ฉ์ ๋ฌด์ํจ | ์ปจํ
์คํธ ์ด๊ณผ๋ก ์๋ฆผ. num_ctx ํ์ฅ, ๊ฒ์ ์กฐ๊ฐ ์(k)ยท์ฒญํฌ ํฌ๊ธฐ ์กฐ์ . |
| ํ๊ตญ์ด๊ฐ ์ด์ํ๊ฑฐ๋ ์์ด๋ก ๋ตํจ | ํ๊ตญ์ด์ ๊ฐํ ๋ชจ๋ธ ์ ํ, ์์คํ ํ๋กฌํํธ์ "๋ฐ๋์ ํ๊ตญ์ด๋ก" ๋ช ์. |
| ๋ค๋ฅธ PC์์ ์ ์ ์ ๋จ | ๊ธฐ๋ณธ์ ๋ก์ปฌ๋ง ํ์ฉ. ํ๊ฒฝ๋ณ์ OLLAMA_HOST=0.0.0.0 ์ค์ ํ ์ฌ์์. ๋จ, ์ธ์ฆ ๊ธฐ๋ฅ์ด ์์ผ๋ ๋ฐฉํ๋ฒฝ ๊ด๋ฆฌ ํ์! |
Ollama API๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ์ฆ์ด ์์ด. ํฌํธ 11434๋ฅผ ์ธํฐ๋ท์ ๊ทธ๋๋ก ์ด์ด๋๋ฉด ๋๊ตฌ๋ ๋ด GPU๋ก ๋ชจ๋ธ์ ๋๋ฆด ์ ์์ด. ์ธ๋ถ ๊ณต๊ฐ๊ฐ ํ์ํ๋ฉด ๋ฆฌ๋ฒ์ค ํ๋ก์ + ์ธ์ฆ์ ์์ ๋์.
13๋ณด๋์ค: OpenAI ํธํ ์๋ํฌ์ธํธ
Ollama๋ http://localhost:11434/v1 ๊ฒฝ๋ก๋ก OpenAI ํธํ API๋ ์ ๊ณตํด. ๊ทธ๋์ ๊ธฐ์กด์ OpenAI SDK๋ก ์ง ์ฝ๋๊ฐ ์๋ค๋ฉด base_url๋ง ๋ฐ๊ฟ์ ๋ก์ปฌ ๋ชจ๋ธ๋ก ๋๋ ค๋ณผ ์ ์์ด. LangChain์์๋
ChatOpenAI(base_url="http://localhost:11434/v1", api_key="ollama", model="qwen2.5:7b")์ฒ๋ผ ์ธ ์ ์์ง(api_key๋ ํ์์ ์๋ฌด ๊ฐ์ด๋ ๋ฃ์ด๋ ๋ผ). ๋ค๋ง Ollama ๊ณ ์ ์ต์
์ ์ธ๋ฐํ๊ฒ ์ฐ๋ ค๋ฉด ์ ์ฉ ํด๋์ค์ธ ChatOllama๊ฐ ๋ ์์ฐ์ค๋ฌ์.
14์ด๊ฑธ๋ก ๋ญ ๋ง๋ค ์ ์์๊น? ์์ด๋์ด ๋ณด๋ฐ๋ฆฌ
์ด๋ฐ ๋ก์ปฌ AI ๊ตฌ์ถ ์ญ๋์ ์์ฆ ํ๋ฆฌ๋์ ์์ฅ์์๋ ๊ฝค ์์๊ฐ ์์ด. ์ค์ ๋ก ์ฌ๋ฅ๋ท ๊ฐ์ ์ฌ๋ฅ ๊ณต์ ํ๋ซํผ์์ ์ฌ๋ด ๋ฌธ์ ์ฑ๋ด ๊ตฌ์ถ, RAG ํ์ดํ๋ผ์ธ ์ธํ ๊ฐ์ AI ๊ฐ๋ฐ ์๋ขฐ๊ฐ ๊พธ์คํ ์ฌ๋ผ์ค๊ณ ์์ผ๋, ์ค๋ ๋ง๋ ๊ฑธ ํฌํธํด๋ฆฌ์ค๋ก ๋ค๋ฌ์ด ๋๋ฉด ์ธ๋ชจ๊ฐ ๊ฝค ๋ง์ ๊ฑฐ์ผ.
15์ ๋ฆฌ: ์ค๋ ์ฐ๋ฆฌ๊ฐ ์์ ๋ ๋ฒจ
๐ฆ ํ ์ค ์์ฝ
Ollama๊ฐ ๋ด PC์์ ๋ชจ๋ธ์ ๋๋ฆฌ๊ณ , LangChain์ด ํ๋กฌํํธยท๊ธฐ์ตยท๋ฌธ์ ๊ฒ์์ ์กฐ๋ฆฝํด์ฃผ๋ฉด, ๋น์ฉ 0์ + ๋ฐ์ดํฐ ์ ์ถ 0๊ฑด์ ๋๋ง์ AI ์ฑ๋ด์ด ์์ฑ๋ผ.
์ฒ์์ ์์ 7B ๋ชจ๋ธ๋ก ๊ฐ๋ณ๊ฒ ์์ํด์, ๋ด ๋ฌธ์๋ฅผ ํ๋์ฉ ๋จน์ฌ๊ฐ๋ฉฐ ํค์๋ด. ์ด๋ ๋ "์ด? ์ด๊ฑฐ ๋ด๊ฐ ๋ง๋ ๊ฑฐ ๋ง์?" ์ถ์ ์๊ฐ์ด ๋ถ๋ช
์ฌ ๊ฑฐ์ผ. ๊ทธ๋ ์ด ๊ธ ์๊ฐ๋๋ฉด ์ฑ๊ณต์ด์ผ ๐
โป LangChain๊ณผ Ollama๋ ์ ๋ฐ์ดํธ๊ฐ ๋งค์ฐ ๋น ๋ฅธ ํ๋ก์ ํธ๋ผ ํด๋์ค ์ด๋ฆยท๊ธฐ๋ณธ๊ฐยท์ง์ ๋ชจ๋ธ์ด ๋ฐ๋ ์ ์์ด. ์ค์ ์ ์ฉ ์ ์ LangChain ๊ณต์ ๋ฌธ์(python.langchain.com)์ Ollama ํตํฉ ํ์ด์ง์ Ollama ๊ณต์ GitHub(github.com/ollama/ollama) ๋ฌธ์๋ฅผ ํจ๊ป ํ์ธํ๋ ๊ฑธ ์ถ์ฒํด.
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.