์ฃผ์ ๋จ๊ณ:
๊ฒ์ ๊ฒฐ์ (Retrieval Decision):
x ๋๋ ์ง๋ฌธ x์ ์์ฑ๋ ๋ต๋ณ yR์ ์ฌ์ฉํ์ฌ D ๊ฐ์ ์ฒญํฌ๋ฅผ ๊ฒ์ํ ์ง ๊ฒฐ์ ๊ฒ์๋ ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ:
x์ ๊ฐ ๊ฒ์๋ ์ฒญํฌ d์์ฑ๋ ๋ต๋ณ์ ํ๊ฐ ํ๊ฐ:
x, ์ฒญํฌ d, ์์ฑ๋ ํ
์คํธ y์์ฑ๋ ๋ต๋ณ์ ์ ์ฉ์ฑ ํ๊ฐ:
x์ ์์ฑ๋ ํ
์คํธ y๋ ผ๋ฌธ: https://arxiv.org/abs/2310.11511
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
embeddings_model = OpenAIEmbeddings(model="text-embedding-3-small")
# Chroma ์ธ๋ฑ์ค ๋ก๋
vector_db = Chroma(
embedding_function=embeddings_model,
collection_name="restaurant_menu",
persist_directory="./chroma_db",
)
# ๊ฒ์๊ธฐ ์์ฑ
retriever= vector_db.as_retriever(search_kwargs={"k":3})
# ๊ฒ์ ํ
์คํธ
query = "์คํ
์ดํฌ์ ์ด์ธ๋ฆฌ๋ ์์ธ์ ์ถ์ฒํด์ฃผ์ธ์."
results = retriever.invoke(query)
pprint(results)
- ์ถ๋ ฅ
[Document(id='9c439fb7-5b36-462e-9020-ce8b1d0298c8', metadata={'menu_name': '์์ฌ ์คํ
์ดํฌ ์๋ฌ๋', 'menu_number': 8, 'source': './data/restaurant_menu.txt'}, page_content='8. ์์ฌ ์คํ
์ดํฌ ์๋ฌ๋\n โข ๊ฐ๊ฒฉ: โฉ26,000\n โข ์ฃผ์ ์์ฌ๋ฃ: ์๊ณ ๊ธฐ ์์ฌ, ๋ฃจ๊ผด๋ผ, ์ฒด๋ฆฌ ํ ๋งํ , ๋ฐ์ฌ๋ฏน ๊ธ๋ ์ด์ฆ\n โข ์ค๋ช
: ๋ถ๋๋ฌ์ด ์์ฌ ์คํ
์ดํฌ๋ฅผ ์๊ฒ ์ฌ๋ผ์ด์คํ์ฌ ์ ์ ํ ๋ฃจ๊ผด๋ผ ์์ ์ฌ๋ฆฐ ๋ฉ์ธ ์๋ฆฌ ์๋ฌ๋์
๋๋ค. ์ฒด๋ฆฌ ํ ๋งํ ์ ํ๋ง์ฐ ์น์ฆ ํ๋ ์ดํฌ๋ก ํ๋ฏธ๋ฅผ ๋ํ๊ณ , ๋ฐ์ฌ๋ฏน ๊ธ๋ ์ด์ฆ๋ก ๋ง๋ฌด๋ฆฌํ์ฌ ๊ณ ๊ธฐ์ ํ๋ฏธ๋ฅผ ํ์ธต ๋์ด์ฌ๋ ธ์ต๋๋ค.'),
Document(id='315f4f43-b824-496f-a575-bd526310c694', metadata={'menu_name': '๋์คํฐ ๋น์คํฌ', 'menu_number': 7, 'source': './data/restaurant_menu.txt'}, page_content='7. ๋์คํฐ ๋น์คํฌ\n โข ๊ฐ๊ฒฉ: โฉ28,000\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋์คํฐ, ์ํฌ๋ฆผ, ๋ธ๋๋, ํํ๋ฆฌ์นด\n โข ์ค๋ช
: ๋์คํฐ ๊ป์ง๊ณผ ์ก์๋ก ์ค๋ ์๊ฐ ์ฐ๋ ค๋ธ ์งํ ๋น์คํฌ ์ํ์
๋๋ค. ์ํฌ๋ฆผ์ผ๋ก ๋ถ๋๋ฌ์ด ์ง๊ฐ์ ๋ํ๊ณ ๋ธ๋๋๋ก ๊น์ ํ๋ฏธ๋ฅผ ์ด๋ ธ์ต๋๋ค. ์์ ๋์คํฐ ์ด์ ํ ํ์ผ๋ก ์ฌ๋ ค ๊ณ ๊ธ์ค๋ฌ์์ ๋ํ์ต๋๋ค.'),
Document(id='2d9aa586-8de2-4a67-b69a-5dfb153e7a86', metadata={'menu_name': '์๊ทธ๋์ฒ ์คํ
์ดํฌ', 'menu_number': 1, 'source': './data/restaurant_menu.txt'}, page_content='1. ์๊ทธ๋์ฒ ์คํ
์ดํฌ\n โข ๊ฐ๊ฒฉ: โฉ35,000\n โข ์ฃผ์ ์์ฌ๋ฃ: ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์, ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค\n โข ์ค๋ช
: ์
ฐํ์ ํน์ ์๊ทธ๋์ฒ ๋ฉ๋ด๋ก, 21์ผ๊ฐ ๊ฑด์กฐ ์์ฑํ ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ์ ์ฌ์ฉํฉ๋๋ค. ๋ฏธ๋์ ๋ ์ด๋ก ์กฐ๋ฆฌํ์ฌ ์ก์ฆ์ ์ต๋ํ ๋ณด์กดํ๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ํฅ์ ๊ฐ์์ ์์ญํ ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค๊ฐ ๊ณ๋ค์ฌ์ง๋๋ค. ๋ ๋์์ธ ์์ค์ ํจ๊ป ์ ๊ณต๋์ด ํ๋ถํ ๋ง์ ๋ํฉ๋๋ค.')]
๊ฒ์ ํ๊ฐ์๋ ํค์๋ ๊ด๋ จ์ฑ๊ณผ ์๋ฏธ์ ๊ด๋ จ์ฑ์ ๊ธฐ์ค์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ํ๊ฐ
ํ๊ฐ๋ 'yes/no' ์ด์ง๋ฒ์ผ๋ก ์งํํ๋ฉฐ ๋ถํ์คํ ๊ฒฝ์ฐ 'no' ์ฒ๋ฆฌ
๋ถ๋ถ ๊ด๋ จ์ฑ์ด๋ ๋งฅ๋ฝ ์ ๋ณด๋ ๋ต๋ณ ํ์ฑ ๊ธฐ์ฌ๋ ๊ธฐ์ค์ผ๋ก ํ๊ฐ
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from typing import Literal
# ๊ฒ์๋ ๋ฌธ์์ ๊ด๋ จ์ฑ ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ ์ ์
class GradeDocuments(BaseModel):
"""Binary score for relevance check on retrieved documents."""
binary_score: Literal['yes', 'no'] = Field(
description="Documents are relevant to the question, 'yes' or 'no'"
)
# LLM ๋ชจ๋ธ ์ด๊ธฐํ ๋ฐ ๊ตฌ์กฐํ๋ ์ถ๋ ฅ ์ค์
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
structured_llm_grader = llm.with_structured_output(GradeDocuments)
# ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ๋ฅผ ์ํ ์์คํ
ํ๋กฌํํธ ์ ์
system_prompt = """๋น์ ์ ์ ๋ฅํ ๋ฌธ์ ์ฒ๋ฆฌ ์ ๋ฌธ๊ฐ์
๋๋ค.
ํ๊ฐ ๊ธฐ์ค:
- ์ฌ์ฉ์ ์ง๋ฌธ์ ๋ํ ๊ฒ์ ๊ฒฐ๊ณผ์ ๊ด๋ จ์ฑ์ ํ๊ฐํฉ๋๋ค
์ ์ ์ฒด๊ณ:
- ๊ด๋ จ ์์ผ๋ฉด 'yes', ์์ผ๋ฉด 'no'๋ก ํ๊ฐ
์ฃผ์์ฌํญ:
- ๋จ์ ๋จ์ด ๋งค์นญ์ด ์๋ ์ง๋ฌธ์ ์ ์ฒด ๋งฅ๋ฝ์ ๊ณ ๋ คํ์ธ์
"""
human_prompt = """
๋ค์ ๋ฌธ์๊ฐ ์ฌ์ฉ์ ์ง๋ฌธ์ ๊ด๋ จ ์๋์ง ํ๊ฐํด์ฃผ์ธ์.
[๋ฌธ์]
{document}
[์ง๋ฌธ]
{question}
[ํ๊ฐ]
"""
# ์ฑ์ ํ๋กฌํํธ ํ
ํ๋ฆฟ ์์ฑ
grade_prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", human_prompt),
])
# Retrieval Grader ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
retrieval_grader = grade_prompt | structured_llm_grader
# ๊ด๋ จ์ฑ ํ๊ฐ ์คํ
question = "์ด ์๋น์ ๋ํํ๋ ๋ฉ๋ด๋ ๋ฌด์์ธ๊ฐ์?"
retrieved_docs = vector_db.similarity_search(question, k=2)
print(f"๊ฒ์๋ ๋ฌธ์ ์: {len(retrieved_docs)}")
print("===============================================================================")
print()
relevant_docs = []
for doc in retrieved_docs:
print("๋ฌธ์:", doc.page_content)
print("---------------------------------------------------------------------------")
relevance = retrieval_grader.invoke(
input={"question": question, "document": doc},
config={
"callbacks": [langfuse_handler],
"tags":["self-rag", "relevance-grader"],
}
)
print(f"๋ฌธ์ ๊ด๋ จ์ฑ: {relevance}")
if relevance.binary_score == 'yes':
relevant_docs.append(doc)
print("===========================================================================")
- ์ถ๋ ฅ
๊ฒ์๋ ๋ฌธ์ ์: 2
===============================================================================
๋ฌธ์: 1. ์๊ทธ๋์ฒ ์คํ
์ดํฌ
โข ๊ฐ๊ฒฉ: โฉ35,000
โข ์ฃผ์ ์์ฌ๋ฃ: ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์, ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค
โข ์ค๋ช
: ์
ฐํ์ ํน์ ์๊ทธ๋์ฒ ๋ฉ๋ด๋ก, 21์ผ๊ฐ ๊ฑด์กฐ ์์ฑํ ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ์ ์ฌ์ฉํฉ๋๋ค. ๋ฏธ๋์ ๋ ์ด๋ก ์กฐ๋ฆฌํ์ฌ ์ก์ฆ์ ์ต๋ํ ๋ณด์กดํ๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ํฅ์ ๊ฐ์์ ์์ญํ ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค๊ฐ ๊ณ๋ค์ฌ์ง๋๋ค. ๋ ๋์์ธ ์์ค์ ํจ๊ป ์ ๊ณต๋์ด ํ๋ถํ ๋ง์ ๋ํฉ๋๋ค.
---------------------------------------------------------------------------
๋ฌธ์ ๊ด๋ จ์ฑ: binary_score='yes'
===========================================================================
๋ฌธ์: 3. ์ฐ์ด ํ๋ฅดํ๋ฅด
โข ๊ฐ๊ฒฉ: โฉ18,000
โข ์ฃผ์ ์์ฌ๋ฃ: ๋
ธ๋ฅด์จ์ด์ฐ ์์ฐ์ด, ์๋ณด์นด๋, ์ผ์ดํผ, ์ ์ํ
โข ์ค๋ช
: ์ ์ ํ ๋
ธ๋ฅด์จ์ด์ฐ ์์ฐ์ด๋ฅผ ๊ณฑ๊ฒ ๋ค์ ธ ์๋ณด์นด๋, ์ผ์ดํผ, ์ ์ํ์ ํจ๊ป ์์ด ๋ง๋ ํ๋ฅดํ๋ฅด์
๋๋ค. ๋ ๋ชฌ ๋๋ ์ฑ์ผ๋ก ์ํผํ ๋ง์ ๋ํ์ผ๋ฉฐ, ๋ฐ์ญํ ๋ธ๋ฆฌ์ค์ฌ ํ ์คํธ์ ํจ๊ป ์ ๊ณต๋ฉ๋๋ค. ์ ์ฑ์๋ฆฌ๋ก ์๋ฒฝํ ๋ฉ๋ด์
๋๋ค.
---------------------------------------------------------------------------
๋ฌธ์ ๊ด๋ จ์ฑ: binary_score='no'
===========================================================================
# ๊ธฐ๋ณธ RAG ์ฒด์ธ
from langchain_core.output_parsers import StrOutputParser
def generator_answer(question, docs):
template = """
์ ์๋ ๋ฌธ๋งฅ์ ๊ธฐ๋ฐ์ผ๋ก ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ ์์ฑํ์ธ์.
[๋ฌธ๋งฅ]
{context}
[์ง๋ฌธ]
{question}
[๋ต๋ณ]
"""
prompt = ChatPromptTemplate.from_template(template)
llm = ChatOpenAI(model='gpt-4o-mini', temperature=0)
def format_docs(docs):
return "\n\n".join([d.page_content for d in docs])
rag_chain = prompt | llm | StrOutputParser()
generation = rag_chain.invoke(
{"context": format_docs(docs), "question": question},
config={
"callbacks": [langfuse_handler],
"tags": ["self-rag", "answer-generator"],
}
)
return generation
# ๊ด๋ น์ฑ ํ๊ฐ๋ฅผ ํต๊ณผํ ๋ฌธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ง๋ฌธ์ ๋ํ ๋ต๋ณ ์์ฑ
generation = generator_answer(question, docs=relevant_docs)
print(generation)
- ์ถ๋ ฅ
์ด ์๋น์ ๋ํํ๋ ๋ฉ๋ด๋ '์๊ทธ๋์ฒ ์คํ
์ดํฌ'์
๋๋ค.
# ํ๊ฐ(Hallucination) ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ ์ ์
class GradeHallucinations(BaseModel):
"""Binary score for hallucination present in generation answer."""
binary_score: str = Field(
description="Answer is grounded in the facts, 'yes' or 'no'"
)
# LLM ๋ชจ๋ธ ์ด๊ธฐํ ๋ฐ ๊ตฌ์กฐํ๋ ์ถ๋ ฅ ์ค์
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
structured_llm_grader = llm.with_structured_output(GradeHallucinations)
# ํ๊ฐ ํ๊ฐ๋ฅผ ์ํ ์์คํ
ํ๋กฌํํธ ์ ์
system_prompt = """
๋น์ ์ ์ฃผ์ด์ง ์ฌ์ค์ ๊ทผ๊ฑฐํ ๋ต๋ณ์ ํ๊ฐํ๋ ์ ๋ฌธ๊ฐ์
๋๋ค.
[ํ๊ฐ ๊ธฐ์ค]
- ๋ต๋ณ์ด ์ฌ์ค์ ๊ทผ๊ฑฐํ๊ณ ์์ ํ ์ง์๋๋ ๊ฒฝ์ฐ 'yes'
- ๋ต๋ณ์ ์ฌ์ค์ ๊ทผ๊ฑฐํ์ง ์์ ์ ๋ณด๋ ์ฃผ์ฅ์ด ํฌํจ๋ ๊ฒฝ์ฐ 'no'
"""
human_prompt = """
๋ค์ ๋ต๋ณ์ด ์ฌ์ค์ ๊ทผ๊ฑฐํ๋์ง ํ๊ฐํด์ฃผ์ธ์.
[์ฌ์ค]
{documents}
[๋ต๋ณ]
{generation}
[ํ๊ฐ]
"""
# ํ๊ฐ ํ๊ฐ ํ๋กฌํํธ ํ
ํ๋ฆฟ ์์ฑ
hallucination_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", human_prompt),
]
)
# Hallucination Grader ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
hallucination_grader = hallucination_prompt | structured_llm_grader
# ํ๊ฐ ํ๊ฐ ์คํ
hallucination = hallucination_grader.invoke(
{"documents": relevant_docs, "generation": generation},
config={
"callbacks": [langfuse_handler],
"tags": ["self-rag", "hallucination-grader"],
}
)
print(f"ํ๊ฐ ํ๊ฐ: {hallucination}")
- ์ถ๋ ฅ
ํ๊ฐ ํ๊ฐ: binary_score='yes'
# ๋ต๋ณ ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ ์ ์
class GradeAnswer(BaseModel):
"""Binary score to assess answer addresses question."""
binary_score: str = Field(
description="Answer addresses the question, 'yes' or 'no'"
)
# LLM ๋ชจ๋ธ ์ด๊ธฐํ ๋ฐ ๊ตฌ์กฐํ๋ ์ถ๋ ฅ ์ค์
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
structured_llm_grader = llm.with_structured_output(GradeAnswer)
# ๋ต๋ณ ํ๊ฐ๋ฅผ ์ํ ์์คํ
ํ๋กฌํํธ ์ ์
system_prompt = """
๋น์ ์ ์ฌ์ฉ์ ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ ํ๊ฐํ๋ ์ ๋ฌธ๊ฐ์
๋๋ค.
[ํ๊ฐ ๊ธฐ์ค]
- ๋ต๋ณ์ด ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์๋ ๊ฒฝ์ฐ 'yes'
- ๋ต๋ณ์ด ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์์ง ์์ ๊ฒฝ์ฐ 'no'
"""
human_prompt = """
๋ค์ ๋ต๋ณ์ด ์ฌ์ฉ์ ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์๋์ง ํ๊ฐํด์ฃผ์ธ์.
[์ง๋ฌธ]
{question}
[๋ต๋ณ]
{generation}
[ํ๊ฐ]
"""
# ๋ต๋ณ ํ๊ฐ ํ๋กฌํํธ ํ
ํ๋ฆฟ ์์ฑ
answer_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", human_prompt),
]
)
# Answer Grader ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
answer_grader = answer_prompt | structured_llm_grader
# ๋ต๋ณ ํ๊ฐ ์คํ
print("Question:", question)
print("Generation:", generation)
answer_score = answer_grader.invoke(
{"question": question, "generation": generation},
config={
"callbacks": [langfuse_handler],
"tags": ["self-rag", "answer-grader"],
}
)
print(f"๋ต๋ณ ํ๊ฐ: {answer_score}")
- ์ถ๋ ฅ
Question: ์ด ์๋น์ ๋ํํ๋ ๋ฉ๋ด๋ ๋ฌด์์ธ๊ฐ์?
Generation: ์ด ์๋น์ ๋ํํ๋ ๋ฉ๋ด๋ '์๊ทธ๋์ฒ ์คํ
์ดํฌ'์
๋๋ค.
๋ต๋ณ ํ๊ฐ: binary_score='yes'
def rewrite_question(question: str) -> str:
"""
์ฃผ์ด์ง ์ง๋ฌธ์ ๋ฒกํฐ ์ ์ฅ์ ๊ฒ์์ ์ต์ ํ๋ ํํ๋ก ๋ค์ ์์ฑํฉ๋๋ค.
:param question: ์๋ณธ ์ง๋ฌธ ๋ฌธ์์ด
:return: ๋ค์ ์์ฑ๋ ์ง๋ฌธ ๋ฌธ์์ด
"""
# LLM ๋ชจ๋ธ ์ด๊ธฐํ
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# ์์คํ
ํ๋กฌํํธ ์ ์
system_prompt = """
๋น์ ์ ์ ๋ฌธ์ ์ธ ์ง๋ฌธ ๋ค์ ์ฐ๊ธฐ ์ ๋ฌธ๊ฐ์
๋๋ค.
[์ง์นจ]
- ์ง๋ฌธ์ ๋ ๋ช
ํํ๊ณ ๊ฐ๊ฒฐํ๊ฒ ๋ค์ ์์ฑํ์ธ์
- ์ง๋ฌธ์ ์๋๋ฅผ ์ ์งํ๋ฉด์ ๋ถํ์ํ ์ ๋ณด๋ฅผ ์ ๊ฑฐํ์ธ์
"""
human_prompt = """
๋ค์ ์ง๋ฌธ์ ๋ ๋ช
ํํ๊ณ ๊ฐ๊ฒฐํ๊ฒ ๋ค์ ์์ฑํ์ธ์.
[์๋ณธ ์ง๋ฌธ]
{question}
[๊ฐ์ ๋ ์ง๋ฌธ]
"""
# ์ง๋ฌธ ๋ค์ ์ฐ๊ธฐ ํ๋กฌํํธ ํ
ํ๋ฆฟ ์์ฑ
re_write_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", human_prompt),
]
)
# ์ง๋ฌธ ๋ค์ ์ฐ๊ธฐ ์ฒด์ธ ๊ตฌ์ฑ
question_rewriter = re_write_prompt | llm | StrOutputParser()
# ์ง๋ฌธ ๋ค์ ์ฐ๊ธฐ ์คํ
rewritten_question = question_rewriter.invoke(
{"question": question},
config={
"callbacks": [langfuse_handler],
"tags": ["self-rag", "question-rewriter"],
},
)
return rewritten_question
# ์ง๋ฌธ ๋ค์ ์ฐ๊ธฐ ํ
์คํธ
rewritten_question = rewrite_question(question)
print(f"์๋ณธ ์ง๋ฌธ: {question}")
print(f"๋ค์ ์ด ์ง๋ฌธ: {rewritten_question}")
- ์ถ๋ ฅ
์๋ณธ ์ง๋ฌธ: ์ด ์๋น์ ๋ํํ๋ ๋ฉ๋ด๋ ๋ฌด์์ธ๊ฐ์?
๋ค์ ์ด ์ง๋ฌธ: ์ด ์๋น์ ๋ํ ๋ฉ๋ด๋ ๋ฌด์์ธ๊ฐ์?
# ๋ค์ ์ด ์ง๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ฒกํฐ ์ ์ฅ์์์ ๋ฌธ์ ๊ฒ์
query = rewritten_question
retrieved_docs = vector_db.similarity_search(query, k=2)
print(len(retrieved_docs))
print("===========================================================================")
for doc in retrieved_docs:
print("๋ฌธ์:", doc.page_content)
print("---------------------------------------------------------------------------")
- ์ถ๋ ฅ
2
===========================================================================
๋ฌธ์: 1. ์๊ทธ๋์ฒ ์คํ
์ดํฌ
โข ๊ฐ๊ฒฉ: โฉ35,000
โข ์ฃผ์ ์์ฌ๋ฃ: ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์, ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค
โข ์ค๋ช
: ์
ฐํ์ ํน์ ์๊ทธ๋์ฒ ๋ฉ๋ด๋ก, 21์ผ๊ฐ ๊ฑด์กฐ ์์ฑํ ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ์ ์ฌ์ฉํฉ๋๋ค. ๋ฏธ๋์ ๋ ์ด๋ก ์กฐ๋ฆฌํ์ฌ ์ก์ฆ์ ์ต๋ํ ๋ณด์กดํ๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ํฅ์ ๊ฐ์์ ์์ญํ ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค๊ฐ ๊ณ๋ค์ฌ์ง๋๋ค. ๋ ๋์์ธ ์์ค์ ํจ๊ป ์ ๊ณต๋์ด ํ๋ถํ ๋ง์ ๋ํฉ๋๋ค.
---------------------------------------------------------------------------
๋ฌธ์: 3. ์ฐ์ด ํ๋ฅดํ๋ฅด
โข ๊ฐ๊ฒฉ: โฉ18,000
โข ์ฃผ์ ์์ฌ๋ฃ: ๋
ธ๋ฅด์จ์ด์ฐ ์์ฐ์ด, ์๋ณด์นด๋, ์ผ์ดํผ, ์ ์ํ
โข ์ค๋ช
: ์ ์ ํ ๋
ธ๋ฅด์จ์ด์ฐ ์์ฐ์ด๋ฅผ ๊ณฑ๊ฒ ๋ค์ ธ ์๋ณด์นด๋, ์ผ์ดํผ, ์ ์ํ์ ํจ๊ป ์์ด ๋ง๋ ํ๋ฅดํ๋ฅด์
๋๋ค. ๋ ๋ชฌ ๋๋ ์ฑ์ผ๋ก ์ํผํ ๋ง์ ๋ํ์ผ๋ฉฐ, ๋ฐ์ญํ ๋ธ๋ฆฌ์ค์ฌ ํ ์คํธ์ ํจ๊ป ์ ๊ณต๋ฉ๋๋ค. ์ ์ฑ์๋ฆฌ๋ก ์๋ฒฝํ ๋ฉ๋ด์
๋๋ค.
---------------------------------------------------------------------------
from typing import List, TypedDict
from langchain_core.documents import Document
class GraphState(TypedDict):
question: str # ์ฌ์ฉ์์ ์ง๋ฌธ
generation: str # LLM ์์ฑ ๋ต๋ณ
documents: List[Document] # ์ปจํ
์คํธ ๋ฌธ์ (๊ฒ์๋ ๋ฌธ์)
num_generations: int # ์ง๋ฌธ or ๋ต๋ณ ์์ฑ ํ์ (๋ฌดํ ๋ฃจํ ๋ฐฉ์ง์ ํ์ฉ)
# Node ์ ์
def retrieve(state: GraphState) -> GraphState:
"""๋ฌธ์๋ฅผ ๊ฒ์ํ๋ ํจ์"""
print("--- ๋ฌธ์ ๊ฒ์ ---")
question = state["question"]
# ๋ฌธ์ ๊ฒ์ ๋ก์ง
documents = vector_db.similarity_search(question)
return {"documents": documents} # ๊ฐ์ฅ ๋ง์ง๋ง์ ๊ฒ์ํ ๋ฌธ์ ๊ฐ์ฒด๋ค๋ก ์ํ๋ฅผ ์
๋ฐ์ดํธ
def generate(state: GraphState) -> GraphState:
"""๋ต๋ณ์ ์์ฑํ๋ ํจ์"""
print("--- ๋ต๋ณ ์์ฑ ---")
question = state["question"]
documents = state["documents"]
# RAG๋ฅผ ์ด์ฉํ ๋ต๋ณ ์์ฑ
generation = generator_answer(question, docs=documents)
# ์์ฑ ํ์ ์
๋ฐ์ดํธ
num_generations = state.get("num_generations", 0)
num_generations += 1
return {"generation": generation, "num_generations": num_generations} # ๋ต๋ณ, ์์ฑํ์ ์
๋ฐ์ดํธ
def grade_documents(state: GraphState) -> GraphState:
"""๊ฒ์๋ ๋ฌธ์์ ๊ด๋ จ์ฑ์ ํ๊ฐํ๋ ํจ์"""
print("--- ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ ---")
question = state["question"]
documents = state["documents"]
# ๊ฐ ๋ฌธ์ ํ๊ฐ
filtered_docs = []
for d in documents:
score = retrieval_grader.invoke({"question": question, "document": d})
grade = score.binary_score
if grade == "yes":
print("---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---")
filtered_docs.append(d)
else:
print("---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---")
return {"documents": filtered_docs} # ๊ด๋ จ์ฑ ํ๊ฐ์ ํฉ๊ฒฉํ ๋ฌธ์๋ค๋ง ์ ์ฅ (override)
def transform_query(state: GraphState) -> GraphState:
"""์ง๋ฌธ์ ๊ฐ์ ํ๋ ํจ์"""
print("--- ์ง๋ฌธ ๊ฐ์ ---")
question = state["question"]
# ์ง๋ฌธ ์ฌ์์ฑ
rewritten_question = rewrite_question(question)
# ์์ฑ ํ์ ์
๋ฐ์ดํธ
num_generations = state.get("num_generations", 0)
num_generations += 1
return {"question": rewritten_question, "num_generations": num_generations} # ์ฌ์์ฑํ ์ง๋ฌธ์ ์ ์ฅ, ์์ฑํ์ ์
๋ฐ์ดํธ
def decide_to_generate(state: GraphState) -> str:
"""๋ต๋ณ ์์ฑ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ ํจ์"""
num_generations = state.get("num_generations", 0)
if num_generations > 2:
print("--- ๊ฒฐ์ : ์์ฑ ํ์ ์ด๊ณผ, ๋ต๋ณ ์์ฑ (-> generate)---")
return "generate"
print("--- ํ๊ฐ๋ ๋ฌธ์ ๋ถ์ ---")
filtered_documents = state["documents"]
if not filtered_documents:
print("--- ๊ฒฐ์ : ๋ชจ๋ ๋ฌธ์๊ฐ ์ง๋ฌธ๊ณผ ๊ด๋ จ์ด ์์, ์ง๋ฌธ ๊ฐ์ ํ์ (-> transform_query)---")
return "transform_query"
else:
print("--- ๊ฒฐ์ : ๋ต๋ณ ์์ฑ (-> generate)---")
return "generate"
def grade_generation(state: GraphState) -> str:
"""์์ฑ๋ ๋ต๋ณ์ ํ์ง์ ํ๊ฐํ๋ ํจ์"""
num_generations = state.get("num_generations", 0)
if num_generations > 2:
print("--- ๊ฒฐ์ : ์์ฑ ํ์ ์ด๊ณผ, ์ข
๋ฃ (-> END)---")
return "end"
# 1๋จ๊ณ: ํ๊ฐ ์ฌ๋ถ ํ์ธ
print("--- ํ๊ฐ ์ฌ๋ถ ํ์ธ ---")
question, documents, generation = state["question"], state["documents"], state["generation"]
hallucination_grade = hallucination_grader.invoke(
{"documents": documents, "generation": generation}
)
if hallucination_grade.binary_score == "yes":
print("--- ๊ฒฐ์ : No ํ๊ฐ (๋ต๋ณ์ด ์ปจํ
์คํธ์ ๊ทผ๊ฑฐํจ) ---")
# 1๋จ๊ณ ํต๊ณผํ ๊ฒฝ์ฐ -> 2๋จ๊ณ: ์ง๋ฌธ-๋ต๋ณ ๊ด๋ จ์ฑ ํ๊ฐ
print("---์ง๋ฌธ-๋ต๋ณ ๊ด๋ จ์ฑ ํ์ธ---")
relevance_grade = answer_grader.invoke({"question": question, "generation": generation})
if relevance_grade.binary_score == "yes":
print("--- ๊ฒฐ์ : ์์ฑ๋ ๋ต๋ณ์ด ์ง๋ฌธ์ ์ ๋ค๋ฃธ (-> END) ---")
return "useful"
else:
print("--- ๊ฒฐ์ : ์์ฑ๋ ๋ต๋ณ์ด ์ง๋ฌธ์ ์ ๋๋ก ๋ค๋ฃจ์ง ์์ (-> transform_query) ---")
return "not useful"
else:
print("--- ๊ฒฐ์ : ์์ฑ๋ ๋ต๋ณ์ด ๋ฌธ์์ ๊ทผ๊ฑฐํ์ง ์์, ์ฌ์๋ ํ์ (-> generate) ---")
return "not supported"
from langgraph.graph import StateGraph, START, END
from IPython.display import Image, display
# ์ํฌํ๋ก์ฐ ๊ทธ๋ํ ์ด๊ธฐํ
builder = StateGraph(GraphState)
# ๋
ธ๋ ์ ์
builder.add_node("retrieve", retrieve) # ๋ฌธ์ ๊ฒ์
builder.add_node("grade_documents", grade_documents) # ๋ฌธ์ ํ๊ฐ
builder.add_node("generate", generate) # ๋ต๋ณ ์์ฑ
builder.add_node("transform_query", transform_query) # ์ง๋ฌธ ๊ฐ์
# ๊ทธ๋ํ ๊ตฌ์ถ
builder.add_edge(START, "retrieve")
builder.add_edge("retrieve", "grade_documents")
# ์กฐ๊ฑด๋ถ ์ฃ์ง ์ถ๊ฐ: ๋ฌธ์ ํ๊ฐ ํ ๊ฒฐ์
builder.add_conditional_edges(
"grade_documents",
decide_to_generate,
{
"transform_query": "transform_query",
"generate": "generate",
},
)
builder.add_edge("transform_query", "retrieve")
# ์กฐ๊ฑด๋ถ ์ฃ์ง ์ถ๊ฐ: ๋ต๋ณ ์์ฑ ํ ํ๊ฐ
builder.add_conditional_edges(
"generate",
grade_generation,
{
"not supported": "generate", # ํ๊ฐ์ด ๋ฐ์ํ ๊ฒฝ์ฐ -> ๋ต๋ณ์ ๋ค์ ์์ฑ
"not useful": "transform_query", # ์ง๋ฌธ๊ณผ ๋ต๋ณ์ ๊ด๋ จ์ฑ์ด ๋ถ์กฑํ ๊ฒฝ์ฐ -> ์ฟผ๋ฆฌ ๊ฐ์ ํด์ ๋ค์ ๊ฒ์
"useful": END,
"end": END,
},
)
# ๊ทธ๋ํ ์ปดํ์ผ
graph = builder.compile()
# ๊ทธ๋ํ ์๊ฐํ
display(Image(graph.get_graph().draw_mermaid_png()))
- ์ถ๋ ฅ

inputs = {"question": "์ด ์๋น์ ๋ํ ๋ฉ๋ด๋ ๋ฌด์์ธ๊ฐ์? ์ฃผ์ฌ๋ฃ๋ ๋ฌด์์ธ๊ฐ์?"}
final_output = graph.invoke(inputs,
config={
"callbacks": [langfuse_handler],
"tags": ["self-rag", "workflow"]
},
)
- ์ถ๋ ฅ
--- ๋ฌธ์ ๊ฒ์ ---
--- ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ ---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
--- ํ๊ฐ๋ ๋ฌธ์ ๋ถ์ ---
--- ๊ฒฐ์ : ๋ต๋ณ ์์ฑ (-> generate)---
--- ๋ต๋ณ ์์ฑ ---
--- ํ๊ฐ ์ฌ๋ถ ํ์ธ ---
--- ๊ฒฐ์ : No ํ๊ฐ (๋ต๋ณ์ด ์ปจํ
์คํธ์ ๊ทผ๊ฑฐํจ) ---
---์ง๋ฌธ-๋ต๋ณ ๊ด๋ จ์ฑ ํ์ธ---
--- ๊ฒฐ์ : ์์ฑ๋ ๋ต๋ณ์ด ์ง๋ฌธ์ ์ ๋ค๋ฃธ (-> END) ---
# ์ต์ข
๋ต๋ณ
final_output["generation"]
- ์ถ๋ ฅ
'์ด ์๋น์ ๋ํ ๋ฉ๋ด๋ ์๊ทธ๋์ฒ ์คํ
์ดํฌ์
๋๋ค. ์ฃผ์ฌ๋ฃ๋ก๋ ์ต์๊ธ ํ์ฐ ๋ฑ์ฌ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์, ๊ทธ๋ฆด๋ ์์คํ๋ผ๊ฑฐ์ค๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.'
inputs = {"question": "๊น์น์ฐ๊ฐ ๋ฉ๋ด๊ฐ ์๋์?"}
for output in graph.stream(inputs,
config={
"callbacks": [langfuse_handler],
"tags": ["self-rag", "workflow"]
},
):
for key, value in output.items():
# ๋
ธ๋ ์ถ๋ ฅ
pprint(f"Node '{key}':")
pprint(f"Value: {value}", indent=2, width=80, depth=None)
print("\n----------------------------------------------------------\n")
- ์ถ๋ ฅ
--- ๋ฌธ์ ๊ฒ์ ---
"Node 'retrieve':"
("Value: {'documents': [Document(id='d61dfeea-17be-4cec-917b-90325c957d15', "
"metadata={'menu_name': '๋์น ๋จ ์ฐน', 'menu_number': 27, 'source': "
"'./data/restaurant_menu.txt'}, page_content='27. ๋์น ๋จ ์ฐน\\n โข ๊ฐ๊ฒฉ: "
'โฉ33,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ด์ง๋๋์ฐ ์๊ฐ๋น, ํ์, ๋ง๋, ๋ ๋์์ธ ์์ค\\n โข ์ค๋ช
: ๋ด์ง๋๋์ฐ ์๊ฐ๋น๋ฅผ '
'ํ์๊ณผ ๋ง๋๋ก ํฅ์ ๋ด์ด ๋ฏธ๋์์ผ๋ก ๊ตฌ์๋ธ ์๋ฆฌ์
๋๋ค. ๋ ๋์์ธ ์์ค๋ก ๊น์ ๋ง์ ๋ํ์ผ๋ฉฐ, ๊ตฌ์ด ์ง์คํด์ ์ผ์ฑ์ ํด๋ ํ๋ฅผ '
"๊ณ๋ค์
๋๋ค.'), Document(id='f22453dd-3476-4ad9-8898-fb3c5ab02424', "
"metadata={'menu_name': '์นํจ ์ฝํผ', 'menu_number': 9, 'source': "
"'./data/restaurant_menu.txt'}, page_content='9. ์นํจ ์ฝํผ\\n โข ๊ฐ๊ฒฉ: "
'โฉ23,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ญ๋ค๋ฆฌ์ด, ํ๋ธ, ๋ง๋, ์ฌ๋ฆฌ๋ธ ์ค์ผ\\n โข ์ค๋ช
: ๋ญ๋ค๋ฆฌ์ด์ ํ๋ธ์ ๋ง๋์ ๋ฃ์ ์ฌ๋ฆฌ๋ธ '
'์ค์ผ์ ์ ์จ์์ ์ฅ์๊ฐ ์กฐ๋ฆฌํ ํ๋์ค ์๋ฆฌ์
๋๋ค. ๋ถ๋๋ฝ๊ณ ์ด์ดํ ์ก์ง์ด ํน์ง์ด๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์์ ์ ์ฒ ์ฑ์๋ฅผ ๊ณ๋ค์ฌ ์ ๊ณตํฉ๋๋ค. ๋ ๋ชฌ '
"์ ์คํธ๋ฅผ ๋ฟ๋ ค ์ํผํ ํฅ์ ๋ํ์ต๋๋ค.'), Document(id='595554b8-a3c3-4370-8389-bc9a253cc3d4', "
"metadata={'menu_name': '์คํ ๋ธ๋ฆฌ์ ์คํ
์ดํฌ', 'menu_number': 26, 'source': "
"'./data/restaurant_menu.txt'}, page_content='26. ์คํ ๋ธ๋ฆฌ์ ์คํ
์ดํฌ\\n โข ๊ฐ๊ฒฉ: "
'โฉ42,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ํ๋ฆฌ๋ฏธ์ ์์ฌ ์คํ
์ดํฌ, ํธ์๊ทธ๋ผ, ํธ๋ฌํ ์์ค\\n โข ์ค๋ช
: ์ต์๊ธ ์์ฌ ์คํ
์ดํฌ์ '
'ํธ์๊ทธ๋ผ๋ฅผ ์ฌ๋ฆฌ๊ณ ํธ๋ฌํ ์์ค๋ฅผ ๊ณ๋ค์ธ ํด๋์ ํ๋ ์น ์๋ฆฌ์
๋๋ค. ๋ถ๋๋ฌ์ด ์ก์ง๊ณผ ๊น์ ํ๋ฏธ๊ฐ ํน์ง์ด๋ฉฐ, ๊ทธ๋ฆฐ ์์คํ๋ผ๊ฑฐ์ค์ ๊ฐ์ '
"๊ทธ๋ผํ์ ํจ๊ป ์ ๊ณตํฉ๋๋ค.'), Document(id='1042c919-0711-4b2b-9644-aae8632c1d63', "
"metadata={'menu_name': '๊ฐ๋ ์๋ฌ๋', 'menu_number': 5, 'source': "
"'./data/restaurant_menu.txt'}, page_content='5. ๊ฐ๋ ์๋ฌ๋\\n โข ๊ฐ๊ฒฉ: "
'โฉ12,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ์ ๊ธฐ๋ ๋ฏน์ค ๊ทธ๋ฆฐ, ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ, ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ\\n โข ์ค๋ช
: ์ ์ ํ ์ ๊ธฐ๋ '
'์ฑ์๋ค๋ก ๊ตฌ์ฑ๋ ๊ฑด๊ฐํ ์๋ฌ๋์
๋๋ค. ์์ญํ ์๊ฐ์ ๋ฏน์ค ๊ทธ๋ฆฐ์ ๋ฌ์ฝคํ ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ์ ๋ํด ๋ค์ํ ๋ง๊ณผ ์๊ฐ์ ์ฆ๊ธธ ์ '
"์์ต๋๋ค. ํน์ ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ์ด ์ฑ์ ๋ณธ์ฐ์ ๋ง์ ์ด๋ ค์ค๋๋ค.')]}")
----------------------------------------------------------
--- ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ ---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
--- ํ๊ฐ๋ ๋ฌธ์ ๋ถ์ ---
--- ๊ฒฐ์ : ๋ชจ๋ ๋ฌธ์๊ฐ ์ง๋ฌธ๊ณผ ๊ด๋ จ์ด ์์, ์ง๋ฌธ ๊ฐ์ ํ์ (-> transform_query)---
"Node 'grade_documents':"
"Value: {'documents': []}"
----------------------------------------------------------
--- ์ง๋ฌธ ๊ฐ์ ---
"Node 'transform_query':"
"Value: {'question': '๊น์น์ฐ๊ฐ ๋ฉ๋ด๊ฐ ์์ต๋๊น?', 'num_generations': 1}"
----------------------------------------------------------
--- ๋ฌธ์ ๊ฒ์ ---
"Node 'retrieve':"
("Value: {'documents': [Document(id='d61dfeea-17be-4cec-917b-90325c957d15', "
"metadata={'menu_name': '๋์น ๋จ ์ฐน', 'menu_number': 27, 'source': "
"'./data/restaurant_menu.txt'}, page_content='27. ๋์น ๋จ ์ฐน\\n โข ๊ฐ๊ฒฉ: "
'โฉ33,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ด์ง๋๋์ฐ ์๊ฐ๋น, ํ์, ๋ง๋, ๋ ๋์์ธ ์์ค\\n โข ์ค๋ช
: ๋ด์ง๋๋์ฐ ์๊ฐ๋น๋ฅผ '
'ํ์๊ณผ ๋ง๋๋ก ํฅ์ ๋ด์ด ๋ฏธ๋์์ผ๋ก ๊ตฌ์๋ธ ์๋ฆฌ์
๋๋ค. ๋ ๋์์ธ ์์ค๋ก ๊น์ ๋ง์ ๋ํ์ผ๋ฉฐ, ๊ตฌ์ด ์ง์คํด์ ์ผ์ฑ์ ํด๋ ํ๋ฅผ '
"๊ณ๋ค์
๋๋ค.'), Document(id='f22453dd-3476-4ad9-8898-fb3c5ab02424', "
"metadata={'menu_name': '์นํจ ์ฝํผ', 'menu_number': 9, 'source': "
"'./data/restaurant_menu.txt'}, page_content='9. ์นํจ ์ฝํผ\\n โข ๊ฐ๊ฒฉ: "
'โฉ23,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ญ๋ค๋ฆฌ์ด, ํ๋ธ, ๋ง๋, ์ฌ๋ฆฌ๋ธ ์ค์ผ\\n โข ์ค๋ช
: ๋ญ๋ค๋ฆฌ์ด์ ํ๋ธ์ ๋ง๋์ ๋ฃ์ ์ฌ๋ฆฌ๋ธ '
'์ค์ผ์ ์ ์จ์์ ์ฅ์๊ฐ ์กฐ๋ฆฌํ ํ๋์ค ์๋ฆฌ์
๋๋ค. ๋ถ๋๋ฝ๊ณ ์ด์ดํ ์ก์ง์ด ํน์ง์ด๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์์ ์ ์ฒ ์ฑ์๋ฅผ ๊ณ๋ค์ฌ ์ ๊ณตํฉ๋๋ค. ๋ ๋ชฌ '
"์ ์คํธ๋ฅผ ๋ฟ๋ ค ์ํผํ ํฅ์ ๋ํ์ต๋๋ค.'), Document(id='595554b8-a3c3-4370-8389-bc9a253cc3d4', "
"metadata={'menu_name': '์คํ ๋ธ๋ฆฌ์ ์คํ
์ดํฌ', 'menu_number': 26, 'source': "
"'./data/restaurant_menu.txt'}, page_content='26. ์คํ ๋ธ๋ฆฌ์ ์คํ
์ดํฌ\\n โข ๊ฐ๊ฒฉ: "
'โฉ42,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ํ๋ฆฌ๋ฏธ์ ์์ฌ ์คํ
์ดํฌ, ํธ์๊ทธ๋ผ, ํธ๋ฌํ ์์ค\\n โข ์ค๋ช
: ์ต์๊ธ ์์ฌ ์คํ
์ดํฌ์ '
'ํธ์๊ทธ๋ผ๋ฅผ ์ฌ๋ฆฌ๊ณ ํธ๋ฌํ ์์ค๋ฅผ ๊ณ๋ค์ธ ํด๋์ ํ๋ ์น ์๋ฆฌ์
๋๋ค. ๋ถ๋๋ฌ์ด ์ก์ง๊ณผ ๊น์ ํ๋ฏธ๊ฐ ํน์ง์ด๋ฉฐ, ๊ทธ๋ฆฐ ์์คํ๋ผ๊ฑฐ์ค์ ๊ฐ์ '
"๊ทธ๋ผํ์ ํจ๊ป ์ ๊ณตํฉ๋๋ค.'), Document(id='1042c919-0711-4b2b-9644-aae8632c1d63', "
"metadata={'menu_name': '๊ฐ๋ ์๋ฌ๋', 'menu_number': 5, 'source': "
"'./data/restaurant_menu.txt'}, page_content='5. ๊ฐ๋ ์๋ฌ๋\\n โข ๊ฐ๊ฒฉ: "
'โฉ12,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ์ ๊ธฐ๋ ๋ฏน์ค ๊ทธ๋ฆฐ, ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ, ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ\\n โข ์ค๋ช
: ์ ์ ํ ์ ๊ธฐ๋ '
'์ฑ์๋ค๋ก ๊ตฌ์ฑ๋ ๊ฑด๊ฐํ ์๋ฌ๋์
๋๋ค. ์์ญํ ์๊ฐ์ ๋ฏน์ค ๊ทธ๋ฆฐ์ ๋ฌ์ฝคํ ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ์ ๋ํด ๋ค์ํ ๋ง๊ณผ ์๊ฐ์ ์ฆ๊ธธ ์ '
"์์ต๋๋ค. ํน์ ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ์ด ์ฑ์ ๋ณธ์ฐ์ ๋ง์ ์ด๋ ค์ค๋๋ค.')]}")
----------------------------------------------------------
--- ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ ---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
--- ํ๊ฐ๋ ๋ฌธ์ ๋ถ์ ---
--- ๊ฒฐ์ : ๋ชจ๋ ๋ฌธ์๊ฐ ์ง๋ฌธ๊ณผ ๊ด๋ จ์ด ์์, ์ง๋ฌธ ๊ฐ์ ํ์ (-> transform_query)---
"Node 'grade_documents':"
"Value: {'documents': []}"
----------------------------------------------------------
--- ์ง๋ฌธ ๊ฐ์ ---
"Node 'transform_query':"
"Value: {'question': '๊น์น์ฐ๊ฐ๊ฐ ์๋์?', 'num_generations': 2}"
----------------------------------------------------------
--- ๋ฌธ์ ๊ฒ์ ---
"Node 'retrieve':"
("Value: {'documents': [Document(id='d61dfeea-17be-4cec-917b-90325c957d15', "
"metadata={'menu_name': '๋์น ๋จ ์ฐน', 'menu_number': 27, 'source': "
"'./data/restaurant_menu.txt'}, page_content='27. ๋์น ๋จ ์ฐน\\n โข ๊ฐ๊ฒฉ: "
'โฉ33,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ด์ง๋๋์ฐ ์๊ฐ๋น, ํ์, ๋ง๋, ๋ ๋์์ธ ์์ค\\n โข ์ค๋ช
: ๋ด์ง๋๋์ฐ ์๊ฐ๋น๋ฅผ '
'ํ์๊ณผ ๋ง๋๋ก ํฅ์ ๋ด์ด ๋ฏธ๋์์ผ๋ก ๊ตฌ์๋ธ ์๋ฆฌ์
๋๋ค. ๋ ๋์์ธ ์์ค๋ก ๊น์ ๋ง์ ๋ํ์ผ๋ฉฐ, ๊ตฌ์ด ์ง์คํด์ ์ผ์ฑ์ ํด๋ ํ๋ฅผ '
"๊ณ๋ค์
๋๋ค.'), Document(id='37b2ed8e-72e8-4cc3-a841-504f93569a72', "
"metadata={'menu_name': '๋ธ๋ฃจ๋ฒ ๋ฆฌ ์น์ฆ์ผ์ดํฌ', 'menu_number': 29, 'source': "
"'./data/restaurant_menu.txt'}, page_content='29. ๋ธ๋ฃจ๋ฒ ๋ฆฌ ์น์ฆ์ผ์ดํฌ\\n โข ๊ฐ๊ฒฉ: "
'โฉ10,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ํฌ๋ฆผ์น์ฆ, ์ ๊ธฐ๋ ๋ธ๋ฃจ๋ฒ ๋ฆฌ, ๊ทธ๋ผํจ ํฌ๋์ปค\\n โข ์ค๋ช
: ๋ถ๋๋ฌ์ด ํฌ๋ฆผ์น์ฆ ๋ฌด์ค์ '
'์ ์ ํ ๋ธ๋ฃจ๋ฒ ๋ฆฌ ์ฝคํฌํธ๋ฅผ ์ธต์ธต์ด ์์ ๋ง๋ ๋์ ํธ์
๋๋ค. ๋ฐ์ญํ ๊ทธ๋ผํจ ํฌ๋์ปค ๋ฒ ์ด์ค์ ์์ ๋ธ๋ฃจ๋ฒ ๋ฆฌ ์์ค๊ฐ ์กฐํ๋ฅผ ์ด๋ฃจ๋ฉฐ, ๋ฏผํธ ์์ผ๋ก '
"์ฅ์ํ์ต๋๋ค.'), Document(id='1042c919-0711-4b2b-9644-aae8632c1d63', "
"metadata={'menu_name': '๊ฐ๋ ์๋ฌ๋', 'menu_number': 5, 'source': "
"'./data/restaurant_menu.txt'}, page_content='5. ๊ฐ๋ ์๋ฌ๋\\n โข ๊ฐ๊ฒฉ: "
'โฉ12,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ์ ๊ธฐ๋ ๋ฏน์ค ๊ทธ๋ฆฐ, ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ, ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ\\n โข ์ค๋ช
: ์ ์ ํ ์ ๊ธฐ๋ '
'์ฑ์๋ค๋ก ๊ตฌ์ฑ๋ ๊ฑด๊ฐํ ์๋ฌ๋์
๋๋ค. ์์ญํ ์๊ฐ์ ๋ฏน์ค ๊ทธ๋ฆฐ์ ๋ฌ์ฝคํ ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ์ ๋ํด ๋ค์ํ ๋ง๊ณผ ์๊ฐ์ ์ฆ๊ธธ ์ '
"์์ต๋๋ค. ํน์ ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ์ด ์ฑ์ ๋ณธ์ฐ์ ๋ง์ ์ด๋ ค์ค๋๋ค.'), "
"Document(id='f22453dd-3476-4ad9-8898-fb3c5ab02424', metadata={'menu_name': "
"'์นํจ ์ฝํผ', 'menu_number': 9, 'source': './data/restaurant_menu.txt'}, "
"page_content='9. ์นํจ ์ฝํผ\\n โข ๊ฐ๊ฒฉ: โฉ23,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ญ๋ค๋ฆฌ์ด, ํ๋ธ, ๋ง๋, ์ฌ๋ฆฌ๋ธ "
'์ค์ผ\\n โข ์ค๋ช
: ๋ญ๋ค๋ฆฌ์ด์ ํ๋ธ์ ๋ง๋์ ๋ฃ์ ์ฌ๋ฆฌ๋ธ ์ค์ผ์ ์ ์จ์์ ์ฅ์๊ฐ ์กฐ๋ฆฌํ ํ๋์ค ์๋ฆฌ์
๋๋ค. ๋ถ๋๋ฝ๊ณ ์ด์ดํ ์ก์ง์ด '
"ํน์ง์ด๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์์ ์ ์ฒ ์ฑ์๋ฅผ ๊ณ๋ค์ฌ ์ ๊ณตํฉ๋๋ค. ๋ ๋ชฌ ์ ์คํธ๋ฅผ ๋ฟ๋ ค ์ํผํ ํฅ์ ๋ํ์ต๋๋ค.')]}")
----------------------------------------------------------
--- ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ ---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
--- ํ๊ฐ๋ ๋ฌธ์ ๋ถ์ ---
--- ๊ฒฐ์ : ๋ชจ๋ ๋ฌธ์๊ฐ ์ง๋ฌธ๊ณผ ๊ด๋ จ์ด ์์, ์ง๋ฌธ ๊ฐ์ ํ์ (-> transform_query)---
"Node 'grade_documents':"
"Value: {'documents': []}"
----------------------------------------------------------
--- ์ง๋ฌธ ๊ฐ์ ---
"Node 'transform_query':"
"Value: {'question': '๊น์น์ฐ๊ฐ๊ฐ ์์ต๋๊น?', 'num_generations': 3}"
----------------------------------------------------------
--- ๋ฌธ์ ๊ฒ์ ---
"Node 'retrieve':"
("Value: {'documents': [Document(id='d61dfeea-17be-4cec-917b-90325c957d15', "
"metadata={'menu_name': '๋์น ๋จ ์ฐน', 'menu_number': 27, 'source': "
"'./data/restaurant_menu.txt'}, page_content='27. ๋์น ๋จ ์ฐน\\n โข ๊ฐ๊ฒฉ: "
'โฉ33,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ด์ง๋๋์ฐ ์๊ฐ๋น, ํ์, ๋ง๋, ๋ ๋์์ธ ์์ค\\n โข ์ค๋ช
: ๋ด์ง๋๋์ฐ ์๊ฐ๋น๋ฅผ '
'ํ์๊ณผ ๋ง๋๋ก ํฅ์ ๋ด์ด ๋ฏธ๋์์ผ๋ก ๊ตฌ์๋ธ ์๋ฆฌ์
๋๋ค. ๋ ๋์์ธ ์์ค๋ก ๊น์ ๋ง์ ๋ํ์ผ๋ฉฐ, ๊ตฌ์ด ์ง์คํด์ ์ผ์ฑ์ ํด๋ ํ๋ฅผ '
"๊ณ๋ค์
๋๋ค.'), Document(id='37b2ed8e-72e8-4cc3-a841-504f93569a72', "
"metadata={'menu_name': '๋ธ๋ฃจ๋ฒ ๋ฆฌ ์น์ฆ์ผ์ดํฌ', 'menu_number': 29, 'source': "
"'./data/restaurant_menu.txt'}, page_content='29. ๋ธ๋ฃจ๋ฒ ๋ฆฌ ์น์ฆ์ผ์ดํฌ\\n โข ๊ฐ๊ฒฉ: "
'โฉ10,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ํฌ๋ฆผ์น์ฆ, ์ ๊ธฐ๋ ๋ธ๋ฃจ๋ฒ ๋ฆฌ, ๊ทธ๋ผํจ ํฌ๋์ปค\\n โข ์ค๋ช
: ๋ถ๋๋ฌ์ด ํฌ๋ฆผ์น์ฆ ๋ฌด์ค์ '
'์ ์ ํ ๋ธ๋ฃจ๋ฒ ๋ฆฌ ์ฝคํฌํธ๋ฅผ ์ธต์ธต์ด ์์ ๋ง๋ ๋์ ํธ์
๋๋ค. ๋ฐ์ญํ ๊ทธ๋ผํจ ํฌ๋์ปค ๋ฒ ์ด์ค์ ์์ ๋ธ๋ฃจ๋ฒ ๋ฆฌ ์์ค๊ฐ ์กฐํ๋ฅผ ์ด๋ฃจ๋ฉฐ, ๋ฏผํธ ์์ผ๋ก '
"์ฅ์ํ์ต๋๋ค.'), Document(id='1042c919-0711-4b2b-9644-aae8632c1d63', "
"metadata={'menu_name': '๊ฐ๋ ์๋ฌ๋', 'menu_number': 5, 'source': "
"'./data/restaurant_menu.txt'}, page_content='5. ๊ฐ๋ ์๋ฌ๋\\n โข ๊ฐ๊ฒฉ: "
'โฉ12,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ์ ๊ธฐ๋ ๋ฏน์ค ๊ทธ๋ฆฐ, ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ, ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ\\n โข ์ค๋ช
: ์ ์ ํ ์ ๊ธฐ๋ '
'์ฑ์๋ค๋ก ๊ตฌ์ฑ๋ ๊ฑด๊ฐํ ์๋ฌ๋์
๋๋ค. ์์ญํ ์๊ฐ์ ๋ฏน์ค ๊ทธ๋ฆฐ์ ๋ฌ์ฝคํ ์ฒด๋ฆฌ ํ ๋งํ , ์ค์ด, ๋น๊ทผ์ ๋ํด ๋ค์ํ ๋ง๊ณผ ์๊ฐ์ ์ฆ๊ธธ ์ '
"์์ต๋๋ค. ํน์ ๋ฐ์ฌ๋ฏน ๋๋ ์ฑ์ด ์ฑ์ ๋ณธ์ฐ์ ๋ง์ ์ด๋ ค์ค๋๋ค.'), "
"Document(id='f22453dd-3476-4ad9-8898-fb3c5ab02424', metadata={'menu_name': "
"'์นํจ ์ฝํผ', 'menu_number': 9, 'source': './data/restaurant_menu.txt'}, "
"page_content='9. ์นํจ ์ฝํผ\\n โข ๊ฐ๊ฒฉ: โฉ23,000\\n โข ์ฃผ์ ์์ฌ๋ฃ: ๋ญ๋ค๋ฆฌ์ด, ํ๋ธ, ๋ง๋, ์ฌ๋ฆฌ๋ธ "
'์ค์ผ\\n โข ์ค๋ช
: ๋ญ๋ค๋ฆฌ์ด์ ํ๋ธ์ ๋ง๋์ ๋ฃ์ ์ฌ๋ฆฌ๋ธ ์ค์ผ์ ์ ์จ์์ ์ฅ์๊ฐ ์กฐ๋ฆฌํ ํ๋์ค ์๋ฆฌ์
๋๋ค. ๋ถ๋๋ฝ๊ณ ์ด์ดํ ์ก์ง์ด '
"ํน์ง์ด๋ฉฐ, ๋ก์ฆ๋ฉ๋ฆฌ ๊ฐ์์ ์ ์ฒ ์ฑ์๋ฅผ ๊ณ๋ค์ฌ ์ ๊ณตํฉ๋๋ค. ๋ ๋ชฌ ์ ์คํธ๋ฅผ ๋ฟ๋ ค ์ํผํ ํฅ์ ๋ํ์ต๋๋ค.')]}")
----------------------------------------------------------
--- ๋ฌธ์ ๊ด๋ จ์ฑ ํ๊ฐ ---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
---๋ฌธ์ ๊ด๋ จ์ฑ: ์์---
--- ๊ฒฐ์ : ์์ฑ ํ์ ์ด๊ณผ, ๋ต๋ณ ์์ฑ (-> generate)---
"Node 'grade_documents':"
"Value: {'documents': []}"
----------------------------------------------------------
--- ๋ต๋ณ ์์ฑ ---
--- ๊ฒฐ์ : ์์ฑ ํ์ ์ด๊ณผ, ์ข
๋ฃ (-> END)---
"Node 'generate':"
"Value: {'generation': '๋ค, ๊น์น์ฐ๊ฐ๊ฐ ์์ต๋๋ค.', 'num_generations': 4}"
----------------------------------------------------------
# ์ต์ข
๋ต๋ณ
print(value["generation"])
- ์ถ๋ ฅ
๋ค, ๊น์น์ฐ๊ฐ๊ฐ ์์ต๋๋ค.