์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿฆ™ LangChain + Ollama ์—ฐ๋™ ์™„์ „ ์ •๋ณต: ์ธํ„ฐ๋„ท ์—†์ด ๋‚ด PC์—์„œ ๋Œ์•„๊ฐ€๋Š” ๋กœ์ปฌ AI ์ฑ—๋ด‡ ๋งŒ๋“ค๊ธฐ

๐Ÿฆ™ LangChain + Ollama ์—ฐ๋™ ์™„์ „ ์ •๋ณต: ์ธํ„ฐ๋„ท ์—†์ด ๋‚ด PC์—์„œ ๋Œ์•„๊ฐ€๋Š” ๋กœ์ปฌ AI ์ฑ—๋ด‡ ๋งŒ๋“ค๊ธฐ

#๋กœ์ปฌLLM#LangChain#Ollama#RAG

์•ผ, ํ˜น์‹œ ์ด๋Ÿฐ ์ƒ๊ฐ ํ•ด๋ณธ ์  ์žˆ์–ด? "์ฑ—GPT ๊ฐ™์€ ๊ฑฐ ๋‚ด ์ปดํ“จํ„ฐ์—์„œ ๊ทธ๋ƒฅ ๋Œ๋ฆฌ๋ฉด ์•ˆ ๋˜๋‚˜?"
API ์š”๊ธˆ ๊ฑฑ์ • ์—†์ด, ํšŒ์‚ฌ ๊ธฐ๋ฐ€ ๋ฌธ์„œ๋ฅผ ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด์ง€ ์•Š๊ณ , ์™€์ดํŒŒ์ด๊ฐ€ ๋Š๊ธด ๋น„ํ–‰๊ธฐ ์•ˆ์—์„œ๋„ ๋Œ€ํ™”๋˜๋Š” ๋‚˜๋งŒ์˜ ์ฑ—๋ด‡. ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๊ฒƒ๋„ ์ƒ๊ฐ๋ณด๋‹ค ํ›จ์”ฌ ์‰ฝ๊ฒŒ.

์˜ค๋Š˜์€ ๋กœ์ปฌ LLM ์‹คํ–‰๊ธฐ์˜ ๋ํŒ์™• Ollama์™€, LLM ์•ฑ ์กฐ๋ฆฝ ํ‚คํŠธ์ธ LangChain์„ ์—ฎ์–ด์„œ ๊ธฐ์–ต๋ ฅ ์žˆ๋Š” ์ฑ—๋ด‡ โ†’ ์ŠคํŠธ๋ฆฌ๋ฐ ์ฑ—๋ด‡ โ†’ ๋‚ด ๋ฌธ์„œ๋ฅผ ์ฝ๋Š” RAG ์ฑ—๋ด‡ โ†’ ์›น UI๊นŒ์ง€ ํ•œ ๋ฒˆ์— ์ญ‰ ๊ฐ€๋ณผ ๊ฑฐ์•ผ. ์ปคํ”ผ ํ•œ ์ž” ๋“ค๊ณ  ๋”ฐ๋ผ์™€ โ˜•

๋‚ด PC ์•ˆ์˜ ๋กœ์ปฌ ์ฑ—๋ด‡ ๊ตฌ์กฐ ๐Ÿ’ป ๋‚ด ์ปดํ“จํ„ฐ (์ธํ„ฐ๋„ท ๋ถˆํ•„์š”) ์‚ฌ์šฉ์ž ์งˆ๋ฌธ ์ž…๋ ฅ LangChain ํ”„๋กฌํ”„ํŠธยท๊ธฐ์–ต Ollama ํฌํŠธ 11434 ๋ชจ๋ธ ํŒŒ์ผยทGPU ๐Ÿ“š ๋ฒกํ„ฐDB (Chroma) ๋‚ด ๋ฌธ์„œ๋ฅผ ์ž˜๊ฒŒ ์ชผ๊ฐœ ์ €์žฅํ•˜๊ณ  ์งˆ๋ฌธ๊ณผ ๋‹ฎ์€ ์กฐ๊ฐ์„ ์ฐพ์•„์คŒ

1๋จผ์ € ์นœ๊ตฌ ์†Œ๊ฐœ๋ถ€ํ„ฐ: Ollama์™€ LangChain์€ ๋ˆ„๊ตฌ?

๋‘˜์˜ ์—ญํ• ์„ ์‹๋‹น์— ๋น„์œ ํ•˜๋ฉด ๊น”๋”ํ•ด. Ollama๋Š” ์ฃผ๋ฐฉ์žฅ์ด์•ผ. ์‹ค์ œ๋กœ ์š”๋ฆฌ(ํ…์ŠคํŠธ ์ƒ์„ฑ)๋ฅผ ํ•˜๋Š” LLM์„ ๋‚ด ์ปดํ“จํ„ฐ์—์„œ ๋Œ๋ ค์ฃผ๋Š” ์‹คํ–‰ ์—”์ง„์ด์ง€. LangChain์€ ํ™€ ๋งค๋‹ˆ์ €์•ผ. ์†๋‹˜ ์ฃผ๋ฌธ(์งˆ๋ฌธ)์„ ๋ฐ›์•„์„œ ์ฃผ๋ฐฉ์ด ์•Œ์•„๋“ฃ๊ธฐ ์ข‹๊ฒŒ ์ •๋ฆฌํ•˜๊ณ , ์ด์ „ ๋Œ€ํ™”๋ฅผ ๊ธฐ์–ตํ•˜๊ณ , ํ•„์š”ํ•˜๋ฉด ์ฐฝ๊ณ (๋ฌธ์„œ DB)์—์„œ ์žฌ๋ฃŒ๋ฅผ ๊บผ๋‚ด ์ฃผ๋ฐฉ์— ๋„˜๊ฒจ์ค˜.

๐Ÿฆ™ Ollama๋กœ์ปฌ์—์„œ ์˜คํ”ˆ ์›จ์ดํŠธ LLM(Llama, Qwen, Gemma, Mistral, EXAONE ๋“ฑ)์„ ๋‹ค์šด๋กœ๋“œยท์‹คํ–‰ยท๊ด€๋ฆฌํ•˜๋Š” ๋„๊ตฌ. ๋‚ด๋ถ€์ ์œผ๋กœ llama.cpp ๊ณ„์—ด ์—”์ง„๊ณผ GGUF ์–‘์žํ™” ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜๊ณ , ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋ฒ„๋กœ http://localhost:11434์— REST API๋ฅผ ์—ด์–ด์ค˜.
๐Ÿ”— LangChainLLM ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํŒŒ์ด์ฌ/์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋ ˆ์ž„์›Œํฌ. ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ, ์ถœ๋ ฅ ํŒŒ์„œ, ๋Œ€ํ™” ๊ธฐ๋ก, ๋ฌธ์„œ ๋กœ๋”, ๋ฒกํ„ฐ์Šคํ† ์–ด, ์—์ด์ „ํŠธ ๋“ฑ์„ ๋ ˆ๊ณ ์ฒ˜๋Ÿผ ์กฐ๋ฆฝํ•˜๊ฒŒ ํ•ด์ค˜.
๐Ÿค langchain-ollama๋‘˜์„ ์ด์–ด์ฃผ๋Š” ๊ณต์‹ ํ†ตํ•ฉ ํŒจํ‚ค์ง€. ChatOllama(์ฑ„ํŒ… ๋ชจ๋ธ), OllamaLLM(ํ…์ŠคํŠธ ์™„์„ฑ), OllamaEmbeddings(์ž„๋ฒ ๋”ฉ) ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•ด.
๐Ÿ’ฌ ์™œ ๊ตณ์ด LangChain์„ ์จ?
์‚ฌ์‹ค 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~24GB24GB๊ธ‰ GPU, 32GB ์ด์ƒ ํ†ตํ•ฉ๋ฉ”๋ชจ๋ฆฌ Mac
70B์•ฝ 40GB ์ด์ƒ์›Œํฌ์Šคํ…Œ์ด์…˜๊ธ‰

ํ•œ๊ตญ์–ด ์ฑ—๋ด‡์ด๋ผ๋ฉด qwen2.5, gemma2/gemma3, LG AI์—ฐ๊ตฌ์›์˜ exaone3.5 ๊ฐ™์€ ๋ชจ๋ธ์ด ํ•œ๊ตญ์–ด๋ฅผ ๊ฝค ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‹ค๋ค„. ์ž„๋ฒ ๋”ฉ ์šฉ๋„๋กœ๋Š” nomic-embed-text, ๋‹ค๊ตญ์–ด์— ๊ฐ•ํ•œ bge-m3 ๊ฐ™์€ ์ „์šฉ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ๋”ฐ๋กœ ๋ฐ›์•„๋‘๋ฉด ์ข‹์•„. ๋ชจ๋ธ ๋ผ์ธ์—…์€ ์ •๋ง ๋น ๋ฅด๊ฒŒ ๋ฐ”๋€Œ๋‹ˆ๊นŒ ollama.com์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์ตœ์‹  ๋ชฉ๋ก์„ ํ•œ ๋ฒˆ ํ›‘์–ด๋ณด๋Š” ์Šต๊ด€์„ ๋“ค์ด์ž.

โš ๏ธ GPU๊ฐ€ ์—†์œผ๋ฉด?
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
STEP 1
Ollama ์„ค์น˜ & ์„œ๋ฒ„ ํ™•์ธ
STEP 2
๋ชจ๋ธ pull (์ฑ„ํŒ…์šฉ + ์ž„๋ฒ ๋”ฉ์šฉ)
STEP 3
ํŒŒ์ด์ฌ ๊ฐ€์ƒํ™˜๊ฒฝ & pip ์„ค์น˜
STEP 4
ChatOllama๋กœ ์ฒซ ํ˜ธ์ถœ

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๋กœ ์ž…๋ ฅยท์ถœ๋ ฅ ํ† ํฐ ์ˆ˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด.

์ž์ฃผ ๋งŒ์ง€๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ

temperature๋‹ต๋ณ€์˜ ๋žœ๋ค์„ฑ. ์‚ฌ์‹ค ๊ธฐ๋ฐ˜ Q&A๋Š” 0~0.3, ์ˆ˜๋‹คยท์•„์ด๋””์–ด๋Š” 0.7 ์ด์ƒ.
num_ctx์ปจํ…์ŠคํŠธ ์ฐฝ ํฌ๊ธฐ(ํ† ํฐ). ๊ธฐ๋ณธ๊ฐ’์ด ๋„‰๋„‰ํ•˜์ง€ ์•Š์€ ํŽธ์ด๋ผ ๊ธด ๋ฌธ์„œยท๊ธด ๋Œ€ํ™”์—” 8192 ๋“ฑ์œผ๋กœ ๋Š˜๋ ค์ค˜. ๋Œ€์‹  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋” ๋จน์–ด.
num_predict์ƒ์„ฑํ•  ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜. ๋‹ต๋ณ€์ด ๋„ˆ๋ฌด ๊ธธ๊ฒŒ ๋Š˜์–ด์งˆ ๋•Œ ์ œํ•œ์šฉ.
base_urlOllama ์„œ๋ฒ„ ์ฃผ์†Œ. ๋‹ค๋ฅธ PCยท๋„์ปค์—์„œ ๋Œ๋ฆด ๋•Œ http://์„œ๋ฒ„IP:11434๋กœ ์ง€์ •.
keep_alive๋ชจ๋ธ์„ ๋ฉ”๋ชจ๋ฆฌ์— ์–ผ๋งˆ๋‚˜ ๋ถ™์žก์•„๋‘˜์ง€. ๊ธฐ๋ณธ์€ ๋ช‡ ๋ถ„ ๋’ค ์–ธ๋กœ๋“œ๋ผ์„œ, ์ฒซ ํ˜ธ์ถœ์ด ๋А๋ฆฐ ์ด์œ ๊ฐ€ ๋ฐ”๋กœ ์ด๊ฑฐ์•ผ.
format"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, ๊ฒ€์ƒ‰ ์ฆ๊ฐ• ์ƒ์„ฑ)์•ผ. ๋ชจ๋ธ์€ ์šฐ๋ฆฌ ํšŒ์‚ฌ ๊ทœ์ •์ง‘์ด๋‚˜ ๋‚ด ๊ฐ•์˜ ๋…ธํŠธ๋ฅผ ํ•™์Šตํ•œ ์ ์ด ์—†์ž–์•„? ๊ทธ๋ž˜์„œ ์งˆ๋ฌธ์ด ๋“ค์–ด์˜ค๋ฉด ๊ด€๋ จ ๋ฌธ์„œ ์กฐ๊ฐ์„ ๋จผ์ € ์ฐพ์•„์„œ ํ”„๋กฌํ”„ํŠธ์— ๋ผ์›Œ ๋„ฃ๊ณ , ๊ทธ๊ฑธ ๊ทผ๊ฑฐ๋กœ ๋‹ตํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฑฐ์•ผ. ์˜คํ”ˆ๋ถ ์‹œํ—˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋”ฑ์ด์•ผ.

RAG ํŒŒ์ดํ”„๋ผ์ธ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ โ‘  ์ค€๋น„ ๋‹จ๊ณ„ (ํ•œ ๋ฒˆ) โ‘ก ์งˆ๋ฌธ ๋‹จ๊ณ„ (๋งค๋ฒˆ) ๐Ÿ“„ ๋ฌธ์„œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ โœ‚๏ธ ์กฐ๊ฐ๋‚ด๊ธฐ(์ฒญํฌ) ๐Ÿ”ข ์ž„๋ฒ ๋”ฉ ๋ณ€ํ™˜ ๋ฒกํ„ฐDB ์ €์žฅ Chroma โ“ ์‚ฌ์šฉ์ž ์งˆ๋ฌธ ๐Ÿ” ์œ ์‚ฌ ์กฐ๊ฐ ๊ฒ€์ƒ‰ ๐Ÿงฉ ํ”„๋กฌํ”„ํŠธ ํ•ฉ์น˜๊ธฐ Ollama ๋‹ต๋ณ€ ๊ทผ๊ฑฐ ๊ธฐ๋ฐ˜ ์ƒ์„ฑ

์ž„๋ฒ ๋”ฉ์ด ๋ญ๋ƒ๋ฉด

์ž„๋ฒ ๋”ฉ์€ ๋ฌธ์žฅ์„ ์ˆซ์ž ๋ฒกํ„ฐ(์ขŒํ‘œ)๋กœ ๋ฐ”๊พธ๋Š” ๊ฑฐ์•ผ. ๋œป์ด ๋น„์Šทํ•œ ๋ฌธ์žฅ์€ ์ขŒํ‘œ ๊ณต๊ฐ„์—์„œ ๊ฐ€๊นŒ์ด ๋ชจ์ด๊ฒŒ ๋ผ. "ํœด๊ฐ€ ์‹ ์ฒญ ๋ฐฉ๋ฒ•"๊ณผ "์—ฐ์ฐจ ์“ฐ๋Š” ๋ฒ•"์€ ๋‹จ์–ด๊ฐ€ ๋‹ฌ๋ผ๋„ ๋ฒกํ„ฐ๊ฐ€ ๊ฐ€๊น์ง€. ๊ทธ๋ž˜์„œ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰๋ณด๋‹ค ํ›จ์”ฌ ๋˜‘๋˜‘ํ•˜๊ฒŒ ๊ด€๋ จ ๋‚ด์šฉ์„ ์ฐพ์•„๋‚ด. ์ด ๋ณ€ํ™˜๋„ 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 refusedOllama ์„œ๋ฒ„๊ฐ€ ๊บผ์ ธ ์žˆ์Œ. 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์ด๊ฑธ๋กœ ๋ญ˜ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ? ์•„์ด๋””์–ด ๋ณด๋”ฐ๋ฆฌ

๐Ÿ“‘ ์‚ฌ๋‚ด ๊ทœ์ • Q&A๋ด‡์ธ์‚ฌยท๋ณด์•ˆ ๊ทœ์ • PDF๋ฅผ RAG๋กœ ์—ฐ๊ฒฐ. ๋ฐ์ดํ„ฐ๊ฐ€ ์™ธ๋ถ€๋กœ ์•ˆ ๋‚˜๊ฐ€๋‹ˆ ๋ณด์•ˆํŒ€๋„ OK.
๐Ÿ“ ๊ฐœ์ธ ๋…ธํŠธ ๋น„์„œ์˜ต์‹œ๋””์–ธยท๋งˆํฌ๋‹ค์šด ๋…ธํŠธ๋ฅผ ๋ฒกํ„ฐDB์— ๋„ฃ๊ณ  "์ž‘๋…„์— ์ฝ์€ ์ฑ… ์ •๋ฆฌํ•ด์ค˜".
๐Ÿ’ป ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋„์šฐ๋ฏธ์ฝ”๋“œ ํŠนํ™” ๋ชจ๋ธ๋กœ ์‚ฌ๋‚ด ์ฝ”๋“œ๋ฅผ ์™ธ๋ถ€ ์œ ์ถœ ์—†์ด ๋ฆฌ๋ทฐ.
๐ŸŽ“ ํ•™์Šต ํŠœํ„ฐ๊ฐ•์˜ ์ž๋ฃŒ๋ฅผ ๋„ฃ๊ณ  ํ€ด์ฆˆ ์ƒ์„ฑยท์š”์•ฝยท์งˆ์˜์‘๋‹ต.
๐Ÿฅ ๋ฏผ๊ฐ ๋ฐ์ดํ„ฐ ๋ถ„์„๊ณ ๊ฐ ์ƒ๋‹ด ๊ธฐ๋ก ๋ถ„๋ฅ˜ยท์š”์•ฝ์„ ๋กœ์ปฌ์—์„œ ์ฒ˜๋ฆฌ.
โœˆ๏ธ ์˜คํ”„๋ผ์ธ ๋น„์„œ์ธํ„ฐ๋„ท ์—†๋Š” ํ˜„์žฅยท๊ธฐ๋‚ด์—์„œ๋„ ์“ฐ๋Š” ํœด๋Œ€์šฉ AI.

์ด๋Ÿฐ ๋กœ์ปฌ AI ๊ตฌ์ถ• ์—ญ๋Ÿ‰์€ ์š”์ฆ˜ ํ”„๋ฆฌ๋žœ์„œ ์‹œ์žฅ์—์„œ๋„ ๊ฝค ์ˆ˜์š”๊ฐ€ ์žˆ์–ด. ์‹ค์ œ๋กœ ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ์žฌ๋Šฅ ๊ณต์œ  ํ”Œ๋žซํผ์—์„  ์‚ฌ๋‚ด ๋ฌธ์„œ ์ฑ—๋ด‡ ๊ตฌ์ถ•, RAG ํŒŒ์ดํ”„๋ผ์ธ ์„ธํŒ… ๊ฐ™์€ AI ๊ฐœ๋ฐœ ์˜๋ขฐ๊ฐ€ ๊พธ์ค€ํžˆ ์˜ฌ๋ผ์˜ค๊ณ  ์žˆ์œผ๋‹ˆ, ์˜ค๋Š˜ ๋งŒ๋“  ๊ฑธ ํฌํŠธํด๋ฆฌ์˜ค๋กœ ๋‹ค๋“ฌ์–ด ๋‘๋ฉด ์“ธ๋ชจ๊ฐ€ ๊ฝค ๋งŽ์„ ๊ฑฐ์•ผ.

15์ •๋ฆฌ: ์˜ค๋Š˜ ์šฐ๋ฆฌ๊ฐ€ ์Œ“์€ ๋ ˆ๋ฒจ

LV.1
Ollama ์„ค์น˜ & ๋ชจ๋ธ ์‹คํ–‰
LV.2
ChatOllama ํ˜ธ์ถœ & ํŒŒ๋ผ๋ฏธํ„ฐ
LV.3
ํ”„๋กฌํ”„ํŠธ + LCEL ์ฒด์ธ
LV.4
์ŠคํŠธ๋ฆฌ๋ฐ & ๋Œ€ํ™” ๊ธฐ์–ต
LV.5
RAG ๋ฌธ์„œ ์ฑ—๋ด‡
LV.6
์›น UI ยท ๋„๊ตฌ ํ˜ธ์ถœ

๐Ÿฆ™ ํ•œ ์ค„ ์š”์•ฝ
Ollama๊ฐ€ ๋‚ด PC์—์„œ ๋ชจ๋ธ์„ ๋Œ๋ฆฌ๊ณ , LangChain์ด ํ”„๋กฌํ”„ํŠธยท๊ธฐ์–ตยท๋ฌธ์„œ ๊ฒ€์ƒ‰์„ ์กฐ๋ฆฝํ•ด์ฃผ๋ฉด, ๋น„์šฉ 0์› + ๋ฐ์ดํ„ฐ ์œ ์ถœ 0๊ฑด์˜ ๋‚˜๋งŒ์˜ AI ์ฑ—๋ด‡์ด ์™„์„ฑ๋ผ.

์ฒ˜์Œ์—” ์ž‘์€ 7B ๋ชจ๋ธ๋กœ ๊ฐ€๋ณ๊ฒŒ ์‹œ์ž‘ํ•ด์„œ, ๋‚ด ๋ฌธ์„œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋จน์—ฌ๊ฐ€๋ฉฐ ํ‚ค์›Œ๋ด. ์–ด๋А ๋‚  "์–ด? ์ด๊ฑฐ ๋‚ด๊ฐ€ ๋งŒ๋“  ๊ฑฐ ๋งž์•„?" ์‹ถ์€ ์ˆœ๊ฐ„์ด ๋ถ„๋ช… ์˜ฌ ๊ฑฐ์•ผ. ๊ทธ๋•Œ ์ด ๊ธ€ ์ƒ๊ฐ๋‚˜๋ฉด ์„ฑ๊ณต์ด์•ผ ๐Ÿ˜Ž

โ€ป LangChain๊ณผ Ollama๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ๋งค์šฐ ๋น ๋ฅธ ํ”„๋กœ์ ํŠธ๋ผ ํด๋ž˜์Šค ์ด๋ฆ„ยท๊ธฐ๋ณธ๊ฐ’ยท์ง€์› ๋ชจ๋ธ์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ์–ด. ์‹ค์ œ ์ ์šฉ ์ „์—” LangChain ๊ณต์‹ ๋ฌธ์„œ(python.langchain.com)์˜ Ollama ํ†ตํ•ฉ ํŽ˜์ด์ง€์™€ Ollama ๊ณต์‹ GitHub(github.com/ollama/ollama) ๋ฌธ์„œ๋ฅผ ํ•จ๊ป˜ ํ™•์ธํ•˜๋Š” ๊ฑธ ์ถ”์ฒœํ•ด.

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.