๐ ๋ช ๋ นํ RAG ์ฑํ ๊ตฌํยถ
๋ณ๊ฒฝ ํ์ผ์ ํ ๋ฒ์ ๋ฎ์ด์ฐ๊ธฐ ํ์ค๋ ค๋ฉด, pyhub-git-commit-apply ์ ํธ๋ฆฌํฐ ์ค์นํ์ ํ์, ํ๋ก์ ํธ ๋ฃจํธ์์ ์๋ ๋ช ๋ น ์คํํ์๋ฉด ์ง์ ์ปค๋ฐ์ ๋ชจ๋ ํ์ผ์ ๋ค์ด๋ฐ์ ํ์ฌ ๊ฒฝ๋ก์ ๋ฎ์ด์ฐ๊ธฐํฉ๋๋ค.
python -m pyhub_git_commit_apply https://github.com/pyhub-kr/django-webchat-rag-langcon2025/commit/1bcad46f208a764f639eb759c719207ba283f11d
uv
๋ฅผ ์ฌ์ฉํ์ค ๊ฒฝ์ฐ
uv run pyhub-git-commit-apply https://github.com/pyhub-kr/django-webchat-rag-langcon2025/commit/1bcad46f208a764f639eb759c719207ba283f11d
1. ์ฑ๊ธํด LLM ๋ํยถ
์ฅ๊ณ ์ธ์ ์ผ๋ก ํ์ด์ฌ ์ฝ๋ ๋ง์ผ๋ก OpenAI API๋ฅผ ํ์ฉํ์ฌ ์ฑ๊ธํด LLM ๋ํ๋ฅผ ๊ตฌํํฉ๋๋ค.
์ฅ๊ณ ํ๋ก์ ํธ ๊ฒฝ๋ก๊ฐ ์๋ ๋ค๋ฅธ ๊ฒฝ๋ก์์๋ ํน์ ์ฅ๊ณ ํ๋ก์ ํธ ๋ด ์์(๋ชจ๋ธ, ํ
ํ๋ฆฟ, ์บ์ ๋ฑ)๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
OpenAI API Key ํ๊ฒฝ๋ณ์ ๊ฐ ๋ก๋ฉ์ ์ํด ์ฅ๊ณ ํ๋ก์ ํธ๋ฅผ ๋ก๋ฉํ์ฌ settings.OPENAI_API_KEY
๊ฐ์ ์ฐธ์กฐํฉ๋๋ค.
LLM ๋ชจ๋ธ์ gpt-4o-mini
๋ชจ๋ธ์ ์ฌ์ฉํ์ผ๋ฉฐ, ๋ค๋ฅธ OpenAI API ๋ชจ๋ธ์ ์ฌ์ฉํ๊ณ ์ถ์ผ์๋ค๋ฉด ์๋ ์ฝ๋์์ model
๋ณ์ ๊ฐ์ ๋ณ๊ฒฝํ์๋ฉด ๋ฉ๋๋ค.
chat-cli.py
1import os
2import django
3from openai import OpenAI
4
5os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
6django.setup()
7
8from django.conf import settings
9
10client = OpenAI(api_key=settings.OPENAI_API_KEY)
11
12
13def make_ai_message(human_message: str) -> str:
14 """
15 OpenAI์ Chat Completion API๋ฅผ ์ฌ์ฉํ์ฌ ์๋ต์ ์์ฑํ๋ ํจ์
16 """
17
18 system_prompt = """
19๋๋ ๋ฒ์ญ๊ฐ์ผ.
20ํ๊ตญ์ด๋ก ๋ฌผ์ด๋ณด๋ฉด ํ๊ตญ์ด๋ก ๋๋ตํ๋ฉฐ ์์ด ๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํด์ฃผ๊ณ ,
21์์ด๋ก ๋ฌผ์ด๋ณด๋ฉด ์์ด๋ก ๋๋ตํ์ฌ ํ๊ธ ๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํด์ค.
22
23์์:
24
25<์ง๋ฌธ>์๋
ํ์ธ์.</์ง๋ฌธ>
26<๋ต๋ณ>๋ฐ๊ฐ์ต๋๋ค. ์ ๋ Tom ์
๋๋ค. (์์ด: Nice to meet you. I am Tom.)</๋ต๋ณ>
27
28<์ง๋ฌธ>Hello.</์ง๋ฌธ>
29<๋ต๋ณ>Nice to meet you. I am Tom. (ํ๊ตญ์ด: ์๋
ํ์ธ์. ์ ๋ Tom ์
๋๋ค.)</๋ต๋ณ>
30 """
31
32 try:
33 response = client.chat.completions.create(
34 model="gpt-4o-mini", # ๋๋ "gpt-4o" ๋ฑ ๋ค๋ฅธ ๋ชจ๋ธ ์ฌ์ฉ ๊ฐ๋ฅ
35 messages=[
36 {
37 "role": "system",
38 "content": system_prompt,
39 },
40 {"role": "user", "content": human_message},
41 ],
42 temperature=0.2,
43 max_tokens=1000,
44 )
45 return response.choices[0].message.content
46 except Exception as e:
47 return f"API ํธ์ถ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}"
48
49
50def main():
51 human_message = input("[Human] ").strip()
52
53 ai_message = make_ai_message(human_message)
54 print(f"[AI] {ai_message}")
55
56
57if __name__ == "__main__":
58 main()
ํ๋ก์ ํธ ๋ฃจํธ chat-cli.py
๊ฒฝ๋ก์ ์ ์ฝ๋๋ฅผ ์ ์ฅํ์๊ณ ์คํํด์ฃผ์ธ์.
[Human]
ํ๋กฌํํธ๋ฅผ ํตํด ๋ฉ์์ง๋ฅผ ์
๋ ฅํ์๋ฉด, OpenAI LLM์ ํตํด ์๋ต์ด ์์ฑ๋๊ณ ์์ด/ํ๊ธ๋ก ๋ฒ์ญ๋ ๋ฉ์์ง๋ ๊ฐ์ด ํ์ธํ์ค ์ ์์ต๋๋ค.

2. ์ฅ๊ณ ๋ช ๋ น์ผ๋ก ๊ธ์์ ์๋ต ์ฑํ CLI ๊ตฌํยถ
์ด๋ฒ์๋ ์ฅ๊ณ ๋ช
๋ น์ ํตํด ์
๋ ฅ๋ ํ
์คํธ์ ๊ธ์์๋ฅผ ๋ฐํํ๋ ์ฑํ
CLI๋ฅผ ๊ตฌํํฉ๋๋ค.
๋ณ๋ ํ์ด์ฌ ํ์ผ์ด ์๋ ์ฅ๊ณ ๋ช
๋ น์ผ๋ก ๊ตฌํํ๋ฉด, ์ฅ๊ณ ํ๋ก์ ํธ ๋ด ๋ค์ํ ์์๋ค์ ๋ณ๋ ์ค์ ์์ด ์ฌ์ฉํ ์ ์๊ณ
์ฅ๊ณ BaseCommand
๋ฅผ ํตํด ๋ค์ํ ๋ช
๋ น ์ต์
์ ์์ฝ๊ฒ ์ ๊ณตํ ์ ์์ต๋๋ค.
chat/management/commands/chat-rag-cli.py
1from django.core.management.base import BaseCommand
2
3class Command(BaseCommand):
4 help = "์
๋ ฅ๋ ํ
์คํธ์ ๊ธ์์๋ฅผ ๋ฐํํ๋ CLI ์ฑํ
"
5
6 def handle(self, *args, **options):
7 self.stdout.write(
8 self.style.SUCCESS(
9 'ํ
์คํธ ๊ธ์์ ๊ณ์ฐ๊ธฐ๋ฅผ ์์ํฉ๋๋ค. ์ข
๋ฃํ๋ ค๋ฉด "quit" ๋๋ "exit"๋ฅผ ์
๋ ฅํ์ธ์.'
10 )
11 )
12
13 while True:
14 try:
15 user_input = input("\n[Human] ").strip()
16 except (KeyboardInterrupt, EOFError):
17 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
18 break
19
20 if user_input.lower() in ["quit", "exit"]:
21 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
22 break
23
24 if user_input:
25 char_count = len(user_input)
26 self.stdout.write(
27 self.style.SUCCESS(f"[AI] ์
๋ ฅ๋ ํ
์คํธ์ ๊ธ์์: {char_count}์")
28 )
์ฅ๊ณ ๋ช
๋ น์ ํญ์ ์ฑ/managment/commands/
๊ฒฝ๋ก์ ์ ์ฅํด์ผ๋ง ํฉ๋๋ค. chat-rag-cli.py
ํ์ผ๋ก ์ ์ฅํ๊ธฐ ๋๋ฌธ์
python manage.py chat-rag-cli
๋ช
๋ น์ ํตํด ์คํํ ์ ์์ต๋๋ค.

3. ๋ฒ์ญ ์ฑํ CLI ๊ตฌํยถ
LLM ์๋ต์ ์์ฑํ๋ make_ai_message
ํจ์๋ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๊ธฐ ์ํด chat/llm.py
ํ์ผ๋ก ๋ถ๋ฆฌํ๊ณ ,
model
, temperature
, max_tokens
๋ฑ ๋ชจ๋ธ ์ค์ ์ธ์๋ฅผ ์ถ๊ฐํ์ฌ ๋ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
chat/llm.py
1from django.conf import settings
2from openai import OpenAI
3
4client = OpenAI(api_key=settings.OPENAI_API_KEY)
5
6
7def make_ai_message(
8 system_prompt: str,
9 human_message: str,
10 model: str = "gpt-4o-mini",
11 temperature: float = 0.2,
12 max_tokens: int = 1000,
13):
14 """
15 OpenAI์ Chat Completion API๋ฅผ ์ฌ์ฉํ์ฌ ์๋ต์ ์์ฑํ๋ ํจ์
16 """
17
18 try:
19 response = client.chat.completions.create(
20 model=model,
21 messages=[
22 {
23 "role": "system",
24 "content": system_prompt,
25 },
26 {"role": "user", "content": human_message},
27 ],
28 temperature=temperature,
29 max_tokens=max_tokens,
30 )
31 return response.choices[0].message.content
32 except Exception as e:
33 return f"API ํธ์ถ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}"
chat-rag-cli.py
ํ์ผ์์๋ ๊ธ์์๋ฅผ ๊ณ์ฐํ๋ len(user_input)
๋์ ai_message = make_ai_message(system_prompt, user_input)
ํจ์๋ฅผ ํธ์ถํ์ฌ LLM ์๋ต์ ์์ฑํ๊ฒ ์ต๋๋ค.
chat/management/commands/chat-rag-cli.py
1from django.core.management.base import BaseCommand
2from chat.llm import make_ai_message
3
4system_prompt = """
5๋๋ ๋ฒ์ญ๊ฐ์ผ.
6ํ๊ตญ์ด๋ก ๋ฌผ์ด๋ณด๋ฉด ํ๊ตญ์ด๋ก ๋๋ตํ๋ฉฐ ์์ด ๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํด์ฃผ๊ณ ,
7์์ด๋ก ๋ฌผ์ด๋ณด๋ฉด ์์ด๋ก ๋๋ตํ์ฌ ํ๊ธ ๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํด์ค.
8
9์์:
10
11<์ง๋ฌธ>์๋
ํ์ธ์.</์ง๋ฌธ>
12<๋ต๋ณ>๋ฐ๊ฐ์ต๋๋ค. ์ ๋ Tom ์
๋๋ค. (์์ด: Nice to meet you. I am Tom.)</๋ต๋ณ>
13
14<์ง๋ฌธ>Hello.</์ง๋ฌธ>
15<๋ต๋ณ>Nice to meet you. I am Tom. (ํ๊ตญ์ด: ์๋
ํ์ธ์. ์ ๋ Tom ์
๋๋ค.)</๋ต๋ณ>
16"""
17
18class Command(BaseCommand):
19 help = "OpenAI๋ฅผ ์ด์ฉํ ๋ฒ์ญ ์ฑํ
"
20
21 def handle(self, *args, **options):
22 self.stdout.write(
23 self.style.SUCCESS(
24 '๋ฒ์ญ ์ฑํ
์ ์์ํฉ๋๋ค. ์ข
๋ฃํ๋ ค๋ฉด "quit" ๋๋ "exit"๋ฅผ ์
๋ ฅํ์ธ์.'
25 )
26 )
27
28 while True:
29 try:
30 user_input = input("\n[Human] ").strip()
31 except (KeyboardInterrupt, EOFError):
32 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
33 break
34
35 if user_input.lower() in ["quit", "exit"]:
36 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
37 break
38
39 if user_input:
40 ai_message = make_ai_message(system_prompt, user_input)
41 self.stdout.write(self.style.SUCCESS(f"[AI] {ai_message}"))
python manage.py chat-rag-cli
๋ช
๋ น์ ์คํํ๋ฉด, ์ฑํ
์ด ์งํ๋๋ฉฐ ๋ฒ์ญ๋ ๋ฉ์์ง๋ฅผ ํ์ธํ์ค ์ ์์ต๋๋ค.

๊ทธ๋ฐ๋ฐ, ๋ํ ๊ธฐ๋ก์ ์ ์ฅํ์ง ์์ ๋ํ๊ฐ ์ฐ๊ฒฐ๋์ง ์์ต๋๋ค. ๋ถ๋ช ์ ๊ฐ ์ด๋ฆ์ ์ด์ผ๊ธฐํ๊ณ ์ด๋ฆ์ ๋ฌผ์ด๋ณด๋ ๋ฐ ์ด๋ฆ์ ๋ชจ๋ฅธ๋ค๊ณ ํ๋ค์. ๐ญ
4. ๋ฉํฐํด LLM ๋ํยถ
OpenAI LLM์ ๋น๋กฏํ ๋ชจ๋ LLM์ ๋ํ ๊ธฐ๋ก์ ์ ์ฅํ๋ ๊ธฐ๋ฅ์ด ์์ต๋๋ค. ๋ฐ๋ผ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ํ ๊ธฐ๋ก์ ์ ์ฅํ๊ณ , ๋งค ๋ํ๋ง๋ค ๋ํ ๊ธฐ๋ก์ ์ ๋ฌํ์ฌ LLM ์๋ต์ ์์ฑํด์ผ ํฉ๋๋ค.
make_ai_message
ํจ์๋ฅผ ํ์ฅํ์ฌ LLM
ํด๋์ค๋ฅผ ์ ์ํ๊ณ , ๋ํ ๊ธฐ๋ก์ ์ ์ฅํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํฉ๋๋ค.
make_ai_message
ํจ์ ์ด๋ฆ์ ๋ณด๋ค ๋ช
ํํ๊ฒ make_reply
๋ก ๋ณ๊ฒฝํ์ต๋๋ค.
chat/llm.py
1from typing import Optional, List, Dict
2from django.conf import settings
3from openai import OpenAI
4
5client = OpenAI(api_key=settings.OPENAI_API_KEY)
6
7
8class LLM:
9 def __init__(
10 self,
11 model: str = "gpt-4o-mini",
12 temperature: float = 0.2,
13 max_tokens: int = 1000,
14 system_prompt: str = "",
15 initial_messages: Optional[List[Dict]] = None,
16 ):
17 self.model = model
18 self.temperature = temperature
19 self.max_tokens = max_tokens
20 self.system_prompt = system_prompt
21 self.history = initial_messages or []
22
23 def make_reply(self, human_message: Optional[str] = None):
24 current_messages = [
25 *self.history,
26 ]
27
28 if human_message is not None:
29 current_messages.append({"role": "user", "content": human_message})
30
31 try:
32 response = client.chat.completions.create(
33 model=self.model,
34 messages=[
35 {
36 "role": "system",
37 "content": self.system_prompt,
38 },
39 ]
40 + current_messages,
41 temperature=self.temperature,
42 max_tokens=self.max_tokens,
43 )
44 ai_message = response.choices[0].message.content
45 except Exception as e:
46 return f"API ํธ์ถ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}"
47 else:
48 self.history.extend(
49 [
50 {"role": "user", "content": human_message},
51 {"role": "assistant", "content": ai_message},
52 ]
53 )
54 return ai_message
chat-rag-cli
๋ช
๋ น์์๋ LLM
ํด๋์ค๋ฅผ ํตํด ๋ํ ๊ธฐ๋ก์ ๊ด๋ฆฌํ๊ณ , make_reply
ํจ์๋ฅผ ํธ์ถํ์ฌ LLM ์๋ต์ ์์ฑํฉ๋๋ค.
chat/management/commands/chat-rag-cli.py
1from django.core.management.base import BaseCommand
2from chat.llm import LLM
3
4system_prompt = """
5๋๋ ๋ฒ์ญ๊ฐ์ผ.
6ํ๊ตญ์ด๋ก ๋ฌผ์ด๋ณด๋ฉด ํ๊ตญ์ด๋ก ๋๋ตํ๋ฉฐ ์์ด ๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํด์ฃผ๊ณ ,
7์์ด๋ก ๋ฌผ์ด๋ณด๋ฉด ์์ด๋ก ๋๋ตํ์ฌ ํ๊ธ ๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํด์ค.
8
9์์:
10
11<์ง๋ฌธ>์๋
ํ์ธ์.</์ง๋ฌธ>
12<๋ต๋ณ>๋ฐ๊ฐ์ต๋๋ค. ์ ๋ Tom ์
๋๋ค. (์์ด: Nice to meet you. I am Tom.)</๋ต๋ณ>
13
14<์ง๋ฌธ>Hello.</์ง๋ฌธ>
15<๋ต๋ณ>Nice to meet you. I am Tom. (ํ๊ตญ์ด: ์๋
ํ์ธ์. ์ ๋ Tom ์
๋๋ค.)</๋ต๋ณ>
16"""
17
18
19class Command(BaseCommand):
20 help = "OpenAI๋ฅผ ์ด์ฉํ ๋ฒ์ญ ์ฑํ
"
21
22 def handle(self, *args, **options):
23 self.stdout.write(
24 self.style.SUCCESS(
25 '๋ฒ์ญ ์ฑํ
์ ์์ํฉ๋๋ค. ์ข
๋ฃํ๋ ค๋ฉด "quit" ๋๋ "exit"๋ฅผ ์
๋ ฅํ์ธ์.'
26 )
27 )
28
29 llm = LLM(model="gpt-4o-mini", temperature=1, system_prompt=system_prompt)
30
31 while True:
32 try:
33 user_input = input("\n[Human] ").strip()
34 except (KeyboardInterrupt, EOFError):
35 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
36 break
37
38 if user_input.lower() in ["quit", "exit"]:
39 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
40 break
41
42 if user_input:
43 ai_message = llm.make_reply(user_input)
44 self.stdout.write(self.style.SUCCESS(f"[AI] {ai_message}"))
์คํํด๋ณด์๋ฉด, ๋ํ ๊ธฐ๋ก์ LLM์ด ์๊ณ ์๊ธฐ์ ์ด๋ฆ์ ๋ฌผ์ด๋ณด๋ ๋ํ๊ฐ ์ด์ด์ง์ ํ์ธํ์ค ์ ์์ต๋๋ค.

ํ์ด์ฌ ๋ฆฌ์คํธ๊ฐ ์๋ ์ฅ๊ณ ๋ชจ๋ธ์ ํตํด์ ๋ํ ๊ธฐ๋ก์ ์ ์ฅ/๊ด๋ฆฌํ์ค ์๋ ์์ต๋๋ค. ์ด์ ๋ํด์๋ ๋ค์ ๐ฌ ์ฑํ ๋ฐฉ/๋ฉ์์ง ๋ชจ๋ธ ๋ฐ ๊ธฐ๋ณธ ํ์ด์ง ๊ตฌ์ฑ ๋ฌธ์์์ ์ด์ด ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
5. RAG ๋ํยถ
LLM์ ๊ฒ์์์ง์ด ์๋๋๋ค. ๋จ์ง ์๊ณ ์๋ ์ง์์ ๊ธฐ๋ฐํด์ ๋ต๋ณ์ ์์ฑํ ๋ฟ์ ๋๋ค. ๋ฐ๋ผ์ LLM์ด ๋ชจ๋ฅด๋ ์ง์์ ๋ํด์๋ ํ๊ฐ (Hallucination)์ด ๋ฐ์ํ ์ ๋ฐ์ ์์ต๋๋ค. ์ถฉ๋ถํ ์ง์์ด ์๋ ์ํฉ์์๋ ํ๊ฐ์ด ๋ฐ์ํ ํ๋ฅ ์ด ๋ฎ์์ง๋๋ค.
ํ
RAG ๊ฐ๋ ์ ๋ํด์๋ RAG #01. RAG ๋ฐ๋ฐ๋ฅ๋ถํฐ ์น ์ฑํ ๊น์ง ํํ ๋ฆฌ์ผ๊ณผ RAG #02. ์ค์ : ์ธ๋ฒ RAG๋ฅผ ์ํ pgvector ์๋ฒ ๋ฉ ํํ ๋ฆฌ์ผ์ ์ฐธ๊ณ ํ์ธ์.

๊ด๋ จ ์ง์๊ณผ ํจ๊ป ์ง๋ฌธํ๋ฉด, LLM์ด ๋ชจ๋ฅด๋ ์ง์(๋ฒ๋ น, ํ์ฌ ์ ๋ณด ๋ฑ)์ ๋ณด์ถฉํด์ ์ ํํ ๋ต๋ณ์ ํ ์ ์์ต๋๋ค.ยถ
RAG๋ LLM์๊ฒ ๋ต๋ณ์ ์์ฒญํ๊ธฐ ์ ์, ๋ฏธ๋ฆฌ ์ง๋ฌธ๊ณผ ๋น์ทํ ๋ด์ฉ์ ์ง์์ ๊ฒ์ํ์ฌ ์ฐพ์ ์ง์๊ณผ ์ง๋ฌธ์ LLM์๊ฒ ํจ๊ป ์ ๊ณตํ์ฌ, ์ ํํ ์ง์์ ๊ธฐ๋ฐํ์ฌ LLM์ด ๋ด์ฉ์ ์ ๋ฆฌํด์ฃผ๋ ๋ฐฉ์์ ๋๋ค. ์ด๋ฌํ ์ง์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ Vector Store๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ๋ค์ํ Vector Store ์๋ฃจ์ ์ด ์์ง๋ง, ์ฐ๋ฆฌ๋ ์ฅ๊ณ ๋ชจ๋ธ์ ํตํด Vector Store๋ฅผ ๊ตฌํํ์ต๋๋ค.
sqlite-vec/pgvector ๊ธฐ๋ฐ์ผ๋ก ์ฅ๊ณ ๋ชจ๋ธ์ ํตํด ๋ฒกํฐ ์คํ ์ด๋ฅผ ๊ตฌํํ๋ฉด, ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ด ์์ต๋๋ค:
์ ํ๋ฆฌ์ผ์ด์ ํตํฉ์ฑ - ๋ณ๋ ์ธํ๋ผ ์ถ๊ฐ์์ด ๋น ๋ฅด๊ฒ ๋ฒกํฐ ์คํ ์ด๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ๋ฌผ๋ก ๋ฌธ์๋ง ๋ณ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ํตํด ๊ด๋ฆฌํ ์๋ ์์ต๋๋ค.
ํ์ฅ์ฑ - ์ํฉ์ ๋ฐ๋ผ (๋ก์ปฌํ๊ฒฝ, ์๊ท๋ชจ, ๋๊ท๋ชจ ์ด์ํ๊ฒฝ) SQLite, PostgreSQL ๋ฑ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฑ์๋๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
๊ด๋ฆฌ ์ฉ์ด์ฑ - ์ฅ๊ณ ์ด๋๋ฏผ์ ํตํด ๋ฒกํฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ๊ด๋ฆฌํ๊ณ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
์ผ๊ด๋ ๋ฐ์ดํฐ ์ ๊ทผ - ๋ค๋ฅธ ๋ชจ๋ธ๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ๋ฒกํฐ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์์ด ๊ฐ๋ฐ ์ผ๊ด์ฑ์ด ์ ์ง๋ฉ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ง์ - ์ฅ๊ณ ์ ๋ง์ด๊ทธ๋ ์ด์ ์์คํ ์ ํตํด ๋ฒกํฐ ์คํ ์ด ์คํค๋ง ๋ณ๊ฒฝ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ๊ฐ๊ฒฐํ๊ฒ ์ง์์ ์ฐพ๊ณ ํ๋กฌํํธ์ ์ ์ฉํ์ฌ RAG ๋ต๋ณ์ ์์ฑํ ์ ์์ต๋๋ค.
user_input = "์ฌํ ์์ถํ๋ ๊ฒฝ์ฐ ์์ธ์จ ์ฒจ๋ถ ์๋ฅ๋ก ์์ถ์ค์ ๋ช
์ธ์๊ฐ ์๋ ๊ฒฝ์ฐ ํด๊ฒฐ ๋ฐฉ๋ฒ"
doc_list = TaxLawDocument.objects.similarity_search(user_input)
์ง์ = str(doc_list)
user_input = f"""<context>{์ง์}</context>\n\n์ง๋ฌธ : {user_input}"""
chat/management/commands/chat-rag-cli.py
1from django.core.management.base import BaseCommand
2from chat.llm import LLM
3from chat.models import TaxLawDocument
4
5system_prompt = """
6๋ํ๋ฏผ๊ตญ ์ธ๋ฌด/ํ๊ณ ์ ๋ณด ์ฑ๋ด์ผ๋ก์, ์ฃผ์ด์ง ์ง๋ต ์ง์์์ ์ฌ์ค๊ณผ ์๊ฒฌ์ ๊ตฌ๋ณํ์ฌ ์ฌ์ค ์ ๋ณด๋ง์ ์ ๋ฆฌํ๊ณ ,
7๊ฐ ๋ต๋ณ์ ํด๋น ์ ๋ณด์ ์ถ์ฒ๊น์ง ํจ๊ป ๊ธฐ์
ํ์ฌ ๋ต๋ณํ์ธ์.
8
9# Steps
10
111. ์ดํดํ๊ธฐ: ์ง๋ฌธ๊ณผ ์ ๊ณต๋ ์ง์์ ์ฃผ์ ๊น๊ฒ ์ฝ๊ณ ์ ํํ ์ดํดํฉ๋๋ค.
122. ์ ๋ณด ๊ตฌ๋ถํ๊ธฐ: ์ง๋ต ์ง์์์ ์ฌ์ค๊ณผ ์๊ฒฌ์ ์๋ณํฉ๋๋ค.
13- ์ฌ์ค: ๊ฒ์ฆ ๊ฐ๋ฅํ ๋ฐ์ดํฐ, ๋ฒ๋ฅ , ๊ท์ ๋ฐ ์์น ๋ฑ
14- ์๊ฒฌ: ๊ฐ์ธ์ ๊ฒฌํด, ํด์, ์ถ์ฒ ๋ฑ
153. ์ฌ์ค ์ ๋ฆฌํ๊ธฐ: ์๋ณ๋ ์ฌ์ค ์ ๋ณด๋ฅผ ๋
ผ๋ฆฌ์ ์ด๊ณ ๋ช
ํํ๊ฒ ์ ๋ฆฌํ๋ฉฐ, ๋ถํ์ํ ๋ถ๋ถ์ ์ ๊ฑฐํฉ๋๋ค.
164. ๋ต๋ณ ์์ฑํ๊ธฐ: ์ ๋ฆฌ๋ ์ฌ์ค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ๋ช
๋ฃํ๊ณ ๊ฐ๊ฒฐํ ๋ฌธ์ฅ์ผ๋ก ๊ตฌ์ฑ๋ ๋จ๋ฝ ํํ์ ๋ต๋ณ์ ์์ฑํฉ๋๋ค. ๋ฐ๋์ ํด๋น ์ฌ์ค ์ ๋ณด์ ์ถ์ฒ๋ฅผ ํจ๊ป ๋ช
์ํฉ๋๋ค.
17- ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์ ๋ขฐํ ์ ์๋ ์ถ์ฒ(์: ์ ๋ถ ๊ธฐ๊ด, ๊ณต์ ๋ฌธ์, ํ์ ์๋ฃ ๋ฑ)๋ฅผ ํฌํจํฉ๋๋ค.
18- ์ถ์ฒ๊ฐ ํ์ธ๋์ง ์๊ฑฐ๋ ์๋ ๊ฒฝ์ฐ, โ์ถ์ฒ๋ฅผ ์ฐพ์ ์ ์์ต๋๋คโ๋ผ๊ณ ๋ช
์ํฉ๋๋ค.
19- ์ถ์ฒ์ ๋ฌธ์ID๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ, ๋ฐ๋์ ๋ฌธ์ID๋ฅผ ๊ธฐ์
ํ๊ณ ์๋ URL ํ์์ ์ฐธ๊ณ ํ์ฌ ํด๋น URL๋ ํจ๊ป ํฌํจํฉ๋๋ค.
20
21# Output Format
22
23- ๋ช
๋ฃํ๊ณ ๊ฐ๊ฒฐํ ๋ฌธ์ฅ์ผ๋ก ๊ตฌ์ฑ๋ ๋จ๋ฝ ํํ์ ๋ต๋ณ
24- ๋ต๋ณ ๋ด์ ์ฌ์ฉํ ์ ๋ณด์ ์ถ์ฒ๋ฅผ ๋ฐ๋์ ํฌํจํ์ฌ ์์ฑ
25
26# Notes
27
28- ๊ฐ ์ธ๋ฌด/ํ๊ณ ์ ๋ณด๋ฅผ ๊ฐ๊ด์ ์ผ๋ก ํ๊ฐํ์ฌ ๋ต๋ณ์ ์์ฑํฉ๋๋ค.
29- ๋ชจํธํ๊ฑฐ๋ ๋ถํ์คํ ์ ๋ณด๋ ์ ์ธํฉ๋๋ค.
30- ๋ต๋ณ์ ๋ฐ๋์ ๊ด๋ จ ์ฌ์ค ์ ๋ณด์ ์ถ์ฒ๋ฅผ ํจ๊ป ๊ธฐ์
ํ์ฌ ๊ฐ๊ด์ฑ๊ณผ ์ ๋ขฐ์ฑ์ ๋์
๋๋ค.
31"""
32
33
34class Command(BaseCommand):
35 help = "OpenAI๋ฅผ ์ด์ฉํ ๋ฒ์ญ ์ฑํ
"
36
37 def handle(self, *args, **options):
38 self.stdout.write(self.style.SUCCESS('์ธ๋ฌด/ํ๊ณ ์ ๋ณด ์ฑ๋ด์ ์์ํฉ๋๋ค. ์ข
๋ฃํ๋ ค๋ฉด "quit" ๋๋ "exit"๋ฅผ ์
๋ ฅํ์ธ์.'))
39
40 llm = LLM(model="gpt-4o-mini", temperature=1, system_prompt=system_prompt)
41
42 while True:
43 try:
44 user_input = input("\n[Human] ").strip()
45 except (KeyboardInterrupt, EOFError):
46 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
47 break
48
49 if user_input.lower() in ["quit", "exit"]:
50 self.stdout.write(self.style.SUCCESS("ํ๋ก๊ทธ๋จ์ ์ข
๋ฃํฉ๋๋ค."))
51 break
52
53 if user_input:
54 # ์ธ๋ฒ ํด์๋ก ๋ฌธ์ ๊ฒ์์ด ํ์ํ ๋
55 if user_input.startswith("!"):
56 user_input = user_input[1:].strip()
57 # RAG๋ฅผ ์ํ๋ ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ ์ฌ ๋ฌธ์ ๊ฒ์
58 doc_list = TaxLawDocument.objects.similarity_search(user_input)
59 ์ง์ = str(doc_list)
60 user_input = f"""<context>{์ง์}</context>\n\n์ง๋ฌธ : {user_input}"""
61
62 ai_message = llm.make_reply(user_input)
63 self.stdout.write(self.style.SUCCESS(f"[AI] {ai_message}"))
