20차시. Edge 이해
6. 루프 — 되돌아가는 Edge
출처: 원본 PDF 20차시_Edge이해.pdf 12~13쪽 · 쪽 그림 12쪽 13쪽
그래프의 진짜 힘은 여기에 있습니다. 이전 노드로 되돌아갈 수 있습니다.
6-1) 루프 만들기
g.add_edge("verify", "retrieve") # 검증 후 다시 검색으로
→ 이렇게 이미 지난 노드로 Edge를 걸면 루프가 됩니다⚠️ 그런데 이대로 두면 무한 반복입니다
retrieve → generate → verify → retrieve → generate → ...
영원히 돕니다.
· API 비용이 순식간에 폭증합니다
· 프로그램이 멈추지 않습니다
· 사용자는 답을 못 받습니다
루프에는 반드시 종료 조건이 필요합니다.
6-2) 안전한 루프 만들기
📝 재시도 카운터 노드
MAX_RETRY = 2
def bump_node(state: dict) -> dict:
# 재시도 횟수를 1 올린다
n = state.get("retries", 0) + 1
return {"retries": n, "log": [f"[bump] 재시도 {n}회차"]}📝 상한을 확인하는 분기 함수
def route_after_verify(state: dict) -> str:
# ① 통과했으면 종료
if state.get("grade") == "pass":
return "end"
# ② 상한에 도달했으면 강제 종료 ← 안전장치를 위에!
if state.get("retries", 0) >= MAX_RETRY:
return "giveup"
# ③ 그 외에는 재시도
return "retry"📝 연결
g.add_node("bump", bump_node)
g.add_conditional_edges("verify", route_after_verify, {
"end": END,
"giveup": "fallback",
"retry": "bump",
})
g.add_edge("bump", "retrieve") # 카운터 올린 뒤 재검색🔑 왜 카운터를 별도 노드로 둘까?
분기 함수에서 state["retries"] += 1 을 하면 안 됩니다.
(규칙 ②: 분기 함수는 State를 바꾸지 않는다)
그래서 값을 바꾸는 일은 노드가,
판단은 분기 함수가 나눠서 합니다.
이 패턴을 기억해두세요. 27차시에서 그대로 씁니다.