19차시. Node 이해
6. 실습 ② — Generate 노드 만들기
출처: 원본 PDF 19차시_Node이해.pdf 13~14쪽 · 쪽 그림 13쪽 14쪽
📝 src/nodes/generate.py
import re
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
import config
from prompts import PROMPTS
load_dotenv()
_chain = (PROMPTS[config.PROMPT_VER]
| ChatOpenAI(model=config.LLM_MODEL,
temperature=config.TEMPERATURE)
| StrOutputParser())
NO_INFO = "자료에서 확인할 수 없습니다"
def _build_context(docs):
return "\n\n---\n\n".join(
f"[{i}] {d.metadata['filename']} p.{d.metadata['page_no']}\n"
f"{d.page_content}"
for i, d in enumerate(docs, 1))
def generate_node(state: dict) -> dict:
# 생성만 담당한다.
docs = state.get("documents") or []
if not docs:
return {"answer": config.MSG_NO_DOC,
"insufficient": True,
"has_citation": False,
"log": ["[generate] 근거 없음 — 생성 생략"]}
answer = _chain.invoke({"context": _build_context(docs),
"question": state["question"]})
nums = [int(n) for n in re.findall(r"\[(\d+)\]", answer)]
cited = bool(nums) and all(1 <= n <= len(docs) for n in nums)
return {
"answer": answer,
"insufficient": NO_INFO in answer,
"has_citation": cited,
"log": [f"[generate] {len(answer)}자 생성 "
f"(인용 {'정상' if cited else '미확인'})"],
}
if __name__ == "__main__":
from nodes.retrieve import retrieve_node
s = {"question": "환불은 며칠 이내인가요?"}
s.update(retrieve_node(s)) # 검색 먼저
print(generate_node(s)["answer"]) # 생성 테스트실행 결과 예시 (코드를 읽고 만든 예상 화면입니다. 실제 실행 결과, 특히 모델의 답은 다를 수 있습니다)
환불은 상품 수령 후 7일 이내에 신청하실 수 있습니다 [1]. 단순 변심의 경우 왕복 배송비는 고객 부담입니다 [1].🔗 노드를 이어서 테스트하는 방법
그래프를 만들지 않아도
딕셔너리에 update로 합치면 됩니다.
s.update(retrieve_node(s))
s.update(generate_node(s))
LangGraph가 하는 일도 결국 이것입니다.
이렇게 손으로 해보면 그래프의 동작이 이해됩니다.