๐Ÿ”ฅ 1์ฐจ ์Šคํ”„๋ฆฐํŠธ ์‹œ์ž‘: AI ์„œ๋น„์Šค์˜ ์‹ฌ์žฅ์„ ๋งŒ๋“ค๋‹ค

๋Œ€๋ง์˜ ์ฒซ ๋ฒˆ์งธ ์Šคํ”„๋ฆฐํŠธ. ์ด๋ฒˆ ๋ชฉํ‘œ๋Š” AI ์ƒ๋‹ด ๋ถ„์„ ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ, LLM์„ ํ’ˆ์€ FastAPI ์„œ๋ฒ„๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ์ฒ˜์Œ์ด๋ผ ์„ค๋ ˆ๋ฉด์„œ๋„ ๋ง‰๋ง‰ํ–ˆ์ง€๋งŒ, ์ผ๋‹จ ๋ถ€๋”ชํ˜€๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค. ๊ณผ์—ฐ ์ฒซ ๋‹จ์ถ”๋ฅผ ์ž˜ ๊ฟฐ์—ˆ์„๊นŒ? ๐Ÿค”


๐Ÿฆด ๋ผˆ๋Œ€๋ถ€ํ„ฐ ์„ธ์šฐ๊ธฐ: LLM ์„œ๋ฒ„ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

๊ฐ€์žฅ ๋จผ์ € ํ•œ ์ผ์€ ํ”„๋กœ์ ํŠธ์˜ ๋ผˆ๋Œ€๋ฅผ ์žก๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ๊ธฐ๋Šฅ๋ณ„๋กœ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ–ˆ๋‹ค.

LLM_server/
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ main.py         # FastAPI ์•ฑ ์ดˆ๊ธฐํ™” ๋ฐ ๋ผ์šฐํ„ฐ ์„ค์ •
โ”‚   โ”œโ”€โ”€ schemas.py      # ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ (Pydantic)
โ”‚   โ”œโ”€โ”€ services.py     # ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง (LLM ํ˜ธ์ถœ)
โ”‚   โ””โ”€โ”€ api/
โ”‚       โ””โ”€โ”€ endpoints/
โ”‚           โ”œโ”€โ”€ summary.py    # ์ƒ๋‹ด ์š”์•ฝ API
โ”‚           โ””โ”€โ”€ tagging.py    # ํ‚ค์›Œ๋“œ ํƒœ๊น… API
โ”œโ”€โ”€ core/
โ”‚   โ””โ”€โ”€ config.py       # ์„ค์ • ๊ด€๋ฆฌ (API ํ‚ค ๋“ฑ)
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ test_api.py     # API ํ…Œ์ŠคํŠธ ์ฝ”๋“œ
โ”œโ”€โ”€ .env                # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํŒŒ์ผ (๋ฏผ๊ฐ ์ •๋ณด)
โ”œโ”€โ”€ requirements.txt    # ํ”„๋กœ์ ํŠธ ์˜์กด์„ฑ
โ””โ”€โ”€ README.md           # ํ”„๋กœ์ ํŠธ ์„ค๋ช…์„œ
  • app/: FastAPI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ•ต์‹ฌ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.
  • core/: ํ”„๋กœ์ ํŠธ์˜ ํ•ต์‹ฌ ์„ค์ •์„ ๊ด€๋ฆฌํ•œ๋‹ค.
  • tests/: ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ €์žฅํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ๊ตฌ์กฐ๋ฅผ ์žก์•„๋‘๋‹ˆ ์•ž์œผ๋กœ ์–ด๋–ค ์ฝ”๋“œ๋ฅผ ์–ด๋””์— ์ž‘์„ฑํ•ด์•ผ ํ• ์ง€ ๋ช…ํ™•ํ•ด์กŒ๋‹ค.


๐Ÿ› ๏ธ ๋กœ์ปฌ LLM, ์–ด๋–ป๊ฒŒ ์—ฐ๋™ํ• ๊นŒ?: ๊ธฐ์ˆ  ์Šคํƒ ๊ฒฐ์ •

๋กœ์ปฌ์—์„œ LLM์„ ์–ด๋–ป๊ฒŒ ์—ฐ๋™ํ• ์ง€ ๊นŠ์ด ๊ณ ๋ฏผํ–ˆ๋‹ค. transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง์ ‘ ์“ฐ๋Š” ๋ฐฉ๋ฒ•๊ณผ Ollama ๊ฐ™์€ ์ถ”๋ก  ์„œ๋ฒ„๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•, ๋‘ ๊ฐ€์ง€ ์„ ํƒ์ง€๊ฐ€ ์žˆ์—ˆ๋‹ค.

โš–๏ธ transformers vs. Ollama (์ถ”๋ก  ์„œ๋ฒ„)

ํ•ญ๋ชฉ transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ Ollama (์ถ”๋ก  ์„œ๋ฒ„)
๊ฐœ๋… Python ์ฝ”๋“œ์—์„œ ์ง์ ‘ ๋ชจ๋ธ์„ ๋ถˆ๋Ÿฌ์™€ ์‹คํ–‰ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐฉ์‹ ๋ชจ๋ธ์„ ๋ณ„๋„ ์„œ๋ฒ„๋กœ ์‹คํ–‰ํ•˜๊ณ , ๋‚ด ์•ฑ์€ API๋กœ ์š”์ฒญํ•˜๋Š” ๋ฐฉ์‹
์‚ฌ์šฉ ํŽธ์˜์„ฑ - ๋ณดํ†ต: ์ง์ ‘ ํ•  ๊ฒŒ ๋งŽ๋‹ค. - ๋งค์šฐ ์‰ฌ์›€: ๋ช…๋ น์–ด๋กœ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ์™€ ์„œ๋ฒ„ ์‹คํ–‰์ด ๋๋‚œ๋‹ค. โœจ
์ž์› ๊ด€๋ฆฌ - FastAPI ์•ฑ๊ณผ LLM์ด ์ž์›์„ ๊ณต์œ ํ•œ๋‹ค. - FastAPI ์•ฑ๊ณผ LLM ์„œ๋ฒ„๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.
ํ™•์žฅ์„ฑ - ํ˜„์žฌ ์•ฑ์— ์ข…์†์ ์ด๋‹ค. - ์—ฌ๋Ÿฌ ์„œ๋น„์Šค์—์„œ ํ•˜๋‚˜์˜ LLM ์„œ๋ฒ„์— ๋™์‹œ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์–ด MSA์— ๋”ฑ ๋งž๋Š”๋‹ค.


๐Ÿš€ ์ตœ์ข… ์„ ํƒ: Ollama!

๊ฒฐ๊ตญ ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Ollama๋ฅผ ์“ฐ๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.

  • ์••๋„์ ์ธ ํŽธ์˜์„ฑ: ๋ช‡ ๊ฐœ ๋ช…๋ น์–ด๋กœ ๋ฐ”๋กœ ๋กœ์ปฌ LLM API ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ: FastAPI ์„œ๋ฒ„๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•˜๊ณ , ๋ฌด๊ฑฐ์šด LLM ์‹คํ–‰์€ Ollama๊ฐ€ ์ „๋‹ดํ•˜๋‹ˆ ๊ตฌ์กฐ๊ฐ€ ์•„์ฃผ ๊น”๋”ํ•ด์กŒ๋‹ค.
  • ์•„ํ‚คํ…์ฒ˜์˜ ์ผ๊ด€์„ฑ: ์ „์ฒด ์‹œ์Šคํ…œ์ด ์ง€ํ–ฅํ•˜๋Š” MSA์™€ ๋ฐฉํ–ฅ์ด ๋”ฑ ๋งž์•˜๋‹ค.

๐Ÿง  ์–ด๋–ค ๋ชจ๋ธ์„ ์“ธ๊นŒ?: gemma:2b๋กœ ์‹œ์ž‘ํ•˜๊ธฐ

์„œ๋ฒ„๋Š” ์ •ํ•ด์กŒ๊ณ , ์ด์ œ ์–ด๋–ค LLM์„ ์˜ฌ๋ฆด์ง€ ์ •ํ•  ์ฐจ๋ก€์˜€๋‹ค. ์ดˆ๊ธฐ ๋‹จ๊ณ„์ธ ๋งŒํผ, ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ๋ชจ๋ธ์ด ํ•„์š”ํ–ˆ๋‹ค.

๐Ÿ“ˆ gemma:2b vs. ๋‹ค๋ฅธ ๋ชจ๋ธ๋“ค

  • gemma:2b: ์š”์•ฝ ์„ฑ๋Šฅ์€ ์ข‹์ง€๋งŒ, ํ‚ค์›Œ๋“œ ์ถ”์ถœ์ฒ˜๋Ÿผ ์ •ํ•ด์ง„ ํ˜•์‹์˜ ์ถœ๋ ฅ์„ ์ž˜ ๋”ฐ๋ฅด์ง€ ๋ชปํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์—ˆ๋‹ค.
  • Phi-3-mini: gemma:2b์™€ ๋น„์Šทํ•œ ์ฒด๊ธ‰์—์„œ ์„ฑ๋Šฅ์ด ์•„์ฃผ ์ข‹๋‹ค๊ณ  ์•Œ๋ ค์ง„ ๋ชจ๋ธ.
  • Llama-3-8B: ๋” ํฌ๊ณ  ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๋†’์€ ํ•˜๋“œ์›จ์–ด ์‚ฌ์–‘์„ ์š”๊ตฌํ–ˆ๋‹ค.

๐ŸŽฏ ์šฐ๋ฆฌ์˜ ์ „๋žต

๊ฒฐ๋ก : gemma:2b๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒŒ ์ง€๊ธˆ ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ์ „๋žต์ด์—ˆ๋‹ค.

  1. ์‹ ์†ํ•œ ๊ฐœ๋ฐœ: gemma:2b๋Š” ๊ฐ€๋ณ๊ณ  ๋นจ๋ผ์„œ, ์ „์ฒด API ํ๋ฆ„์„ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ์ตœ์ ์ด์—ˆ๋‹ค.
  2. ์ ์ง„์  ๊ฐœ์„ : ๋จผ์ € gemma:2b๋กœ ํ”„๋กœํ† ํƒ€์ž…์„ ์™„์„ฑํ•˜๊ณ , ์„ฑ๋Šฅ์ด ๋ถ€์กฑํ•˜๋ฉด phi-3-mini ๊ฐ™์€ ๋” ์ข‹์€ ๋ชจ๋ธ๋กœ ์‰ฝ๊ฒŒ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. Ollama๋ฅผ ์“ฐ๋‹ˆ ๋ชจ๋ธ ๊ต์ฒด ๋น„์šฉ์ด ๋งค์šฐ ๋‚ฎ๋‹ค๋Š” ๊ฒŒ ํฐ ์žฅ์ ์ด์—ˆ๋‹ค.

๐Ÿ’ป Sprint Log: ์‚ฝ์งˆ๊ณผ ์„ฑ์žฅ์˜ ๊ธฐ๋ก

๋‚ ์งœ: 2025๋…„ 8์›” 30์ผ

1. FastAPI ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์„ค์ • โœ…

  • main.py, schemas.py, endpoints ๋“ฑ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์žก๊ณ  Pydantic ๋ชจ๋ธ๋กœ ๋ฐ์ดํ„ฐ ํ˜•์‹์„ ์ •์˜ํ–ˆ๋‹ค.

2. LLM ์—ฐ๋™ ์„œ๋น„์Šค ๊ตฌํ˜„ โœ…

  • httpx.AsyncClient๋กœ Ollama API์— ๋น„๋™๊ธฐ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค.
  • ์š”์•ฝ๊ณผ ํ‚ค์›Œ๋“œ ํƒœ๊น…์„ ์œ„ํ•œ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

3. ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…: ์—ญ์‹œ ์ˆœํƒ„์น˜ ์•Š์•˜๋‹ค ๐Ÿ˜ญ

  • ModuleNotFoundError: requirements.txt์— pydantic-settings ์ถ”๊ฐ€๋ฅผ ๊นœ๋นกํ–ˆ๋‹ค. (๊ธฐ๋ณธ์ ์ธ ์‹ค์ˆ˜!)
  • 422 Unprocessable Content ์˜ค๋ฅ˜: FastAPI์˜ /docs UI๊ฐ€ ๊ธด ํ…์ŠคํŠธ์˜ ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ๋ฅผ ๋ชปํ•ด์„œ ์ƒ๊ธด ๋ฌธ์ œ์˜€๋‹ค. curl๋กœ ์ง์ ‘ ํ…Œ์ŠคํŠธํ•˜๋‹ˆ ํ•ด๊ฒฐ๋๋‹ค.
  • gemma:2b์˜ ๋ฐฐ์‹ (!): โ€œํ‚ค์›Œ๋“œ๋งŒ ์ค˜โ€๋ผ๊ณ  ์•„๋ฌด๋ฆฌ ๋งํ•ด๋„ ๋ง์„ ๋“ฃ์ง€ ์•Š๊ณ  ์ž๊พธ ์ค„๊ธ€๋กœ ๋‹ตํ–ˆ๋‹ค. ๋ชจ๋ธ์˜ ์ง€์‹œ ์‚ฌํ•ญ ์ค€์ˆ˜ ๋Šฅ๋ ฅ์— ๋ช…ํ™•ํ•œ ํ•œ๊ณ„๊ฐ€ ์žˆ์Œ์„ ํ™•์ธํ–ˆ๋‹ค.

๐ŸŽ‰ ์ฒซ API ํ˜ธ์ถœ ์„ฑ๊ณต์˜ ์ˆœ๊ฐ„!

์ˆ˜๋งŽ์€ ์˜ค๋ฅ˜๋ฅผ ๊ฑฐ์ณ, ํ„ฐ๋ฏธ๋„์—์„œ curl๋กœ ๋ณด๋‚ธ ์š”์ฒญ์— gemma:2b๊ฐ€ ์š”์•ฝํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋”ฑ! ํ•˜๊ณ  ์ฐํ˜”์„ ๋•Œ. ๊ทธ ์งœ๋ฆฟํ•จ์€ ์ •๋ง ์žŠ์„ ์ˆ˜๊ฐ€ ์—†๋‹ค. ๋“œ๋””์–ด AI ์„œ๋น„์Šค์˜ ์‹ฌ์žฅ์ด ๋›ฐ๊ธฐ ์‹œ์ž‘ํ•œ ์ˆœ๊ฐ„์ด์—ˆ๋‹ค.


๋‹ค์Œ ์Šคํ”„๋ฆฐํŠธ๋ฅผ ํ–ฅํ•ด

์ฒซ ์Šคํ”„๋ฆฐํŠธ๋Š” ์„ฑ๊ณต์ ์ด์—ˆ๋‹ค. ์„œ๋ฒ„๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ , LLM์„ ์—ฐ๋™ํ–ˆ์œผ๋ฉฐ, ์‹ฌ์ง€์–ด ๋ชจ๋ธ์˜ ํ•œ๊ณ„๊นŒ์ง€ ํŒŒ์•…ํ–ˆ๋‹ค. ๋‹ค์Œ ์Šคํ”„๋ฆฐํŠธ ๋ชฉํ‘œ๋Š” ๋ช…ํ™•ํ•ด์กŒ๋‹ค.

  • ๋ชจ๋ธ ๊ต์ฒด ๋ฐ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ: gemma:2b ๋Œ€์‹ , ์ง€์‹œ๋ฅผ ๋” ์ž˜ ๋”ฐ๋ฅด๋Š” phi-3-mini ๋ชจ๋ธ๋กœ ๊ต์ฒดํ•˜๊ณ  ์š”์•ฝ ๋ฐ ํ‚ค์›Œ๋“œ ์ถ”์ถœ ์„ฑ๋Šฅ์„ ๋‹ค์‹œ ํ‰๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค.

์ฒซ์ˆ ์— ๋ฐฐ๋ถ€๋ฅผ ์ˆœ ์—†์ง€๋งŒ, ๋ฐฉํ–ฅ์„ ์ž˜ ์žก์•˜๋‹ค๋Š” ํ™•์‹ ์ด ๋“ ๋‹ค. ๋‹ค์Œ ์Šคํ”„๋ฆฐํŠธ๊ฐ€ ๋” ๊ธฐ๋Œ€๋œ๋‹ค. ๐Ÿ”ฅ