๐ฏ LangGraph
StateGraph ยท Self-RAG ยท ReAct ยท Supervisor ยท HITL ยท Deep Agents
LangGraph
StateGraph ยท Self-RAG ยท ReAct ยท Supervisor ยท HITL
๊ทธ๋ํ๋ก ์์ด์ ํธ์ RAG๋ฅผ ์ ์ดํ๋ค
LCEL์ ์ง์ ํ๊ณ๋ฅผ ๋์ด โ ์กฐ๊ฑด ๋ถ๊ธฐยท๋ฃจํยท์ํ ๊ด๋ฆฌยท๋ฉํฐ์์ด์ ํธ
LangGraph ํต์ฌ ๊ตฌ์กฐ
LCEL ํ๊ณ ยท StateGraph ยท 3์์
ํต์ฌ ๊ตฌ์กฐ
์ง์ ์ ๋๋ 3์์
3์์๋ก ๋ชจ๋ ์ํฌํ๋ก์ฐ๋ฅผ
LCEL์ ์ง์ ํ๊ณ๋ฅผ ์ํ ๊ทธ๋ํ๋ก ๋์ด์ญ๋๋ค โ StateยทNodeยทEdge ์ธ ๊ฐ์ง๋ก ๋ถ๊ธฐ์ ๋ฃจํ๊น์ง ํํํฉ๋๋ค.
- State โ TypedDict ๊ณต์ ๋ฐ์ดํฐ
- Node โ State๋ฅผ ์ฒ๋ฆฌํ๋ Python ํจ์
- Edge โ add_edge ยท add_conditional_edges
- compile() โ invoke/stream ๊ฐ๋ฅํ Runnable
์กฐ๊ฑด ๋ถ๊ธฐยท๋ฃจํยท์ํ ๊ด๋ฆฌ โ LCEL์ด ๋ชป ํ๋ ์ธ ๊ฐ์ง๊ฐ StateGraph์ ์กด์ฌ ์ด์ ์ ๋๋ค.
LCEL vs LangGraph
์ง์ ํ์ดํ๋ผ์ธ์ ํ๊ณ๋ฅผ ์ํ ๊ทธ๋ํ๋ก ํด๊ฒฐ
LCEL
์ง์ ํ์ดํ๋ผ์ธ
- A | B | C โ ํญ์ ๊ฐ์ ์์
- ์กฐ๊ฑด ๋ถ๊ธฐยท๋ฃจํ ๋ถ๊ฐ
- ์ํ ๊ด๋ฆฌ ์์
- ๋น ๋ฅธ ํ๋กํ ํ์ ์ ์ ํฉ
LangGraph
์ํ ๋ฐฉํฅ ๊ทธ๋ํ
- ์กฐ๊ฑด ์ฃ์ง๋ก ๋ถ๊ธฐ
- ์ํ ์ฃ์ง๋ก ๋ฃจํ (์ฌ์๋)
- TypedDict State + Checkpointer
- ํ๋ก๋์ ์์ด์ ํธ์ ์ ํฉ
๋น ๋ฅธ ํ๋กํ ํ์ ์ LCEL๋ก, ๋ถ๊ธฐยท๋ฃจํยท์ํ๊ฐ ํ์ํ ํ๋ก๋์ ์์ด์ ํธ๋ LangGraph๋ก ๊ฐ๋๋ค.
StateGraph 3์์
State + Node + Edge โ ์ด 3๊ฐ๋ก ๋ชจ๋ ์ํฌํ๋ก์ฐ๋ฅผ ํํ
State
TypedDict โ ๊ทธ๋ํ ์ ์ฒด ๊ณต์ ๋ฐ์ดํฐ. Annotated[list, add]๋ก ์๋ ๋์
Node
Python ํจ์ โ State๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ๊ณ ์ ๋ฐ์ดํธ ๋ฐํ
Edge
๋ ธ๋ ๊ฐ ์ฐ๊ฒฐ โ ์ง์ (add_edge) ๋๋ ์กฐ๊ฑด๋ถ(conditional)
State๋ฅผ Node๊ฐ ๊ฐฑ์ ํ๊ณ Edge๊ฐ ๋ค์ ๊ฒฝ๋ก๋ฅผ ๊ณ ๋ฆ ๋๋ค โ ์ ์ ์กฐํฉ๋ง์ผ๋ก ๋ถ๊ธฐยท๋ฃจํยท๋ณ๋ ฌ์ ๋ชจ๋ ํํํฉ๋๋ค.
๋ฌธ์ ํ๋์ ๊ทธ๋ํ ์ฌ์
"๋ฐฐ์ก์ด 3์ผ์งธ ์ ์์" โ ๋ถ๋ฅ ๋ ธ๋์ ์ ํ ํ์ ๊ณผ ์กฐ๊ฑด ์ฃ์ง๊ฐ ๊ณ ๋ฅด๋ ๊ฐ๋ฆผ๊ธธ
"๋ฐฐ์ก์ด 3์ผ์งธ ์ ์์"
๊ณ ๊ฐ ๋ฌธ์ โ State.question
โ
STATEGRAPH โ ๋ฌธ์๊ฐ ์ง๋๋ ๊ธธ
classify ๋ ธ๋
โ
์กฐ๊ฑด ์ฃ์ง โ category?
โ
"๋ฐฐ์ก" โ check_delivery ๋ ธ๋
โ
respond ๋ ธ๋
โณ ํ๋ถ ๋ฌธ์์๋ค๋ฉด
"ํ๋ถ" โ process_refund ๋ ธ๋
โ ๊ฐ์ respond๋ก ํฉ๋ฅ
โ
"๋ด์ผ ๋์ฐฉ ์์ ์ ๋๋ค"
์๋ต โ State.answer
์กฐ๊ฑด ์ฃ์ง๊ฐ State์ category ๊ฐ์ ๋ณด๊ณ ๋ค์ ๋ ธ๋๋ฅผ ๊ณ ๋ฆ ๋๋ค โ A | B | C ์ง์ (LCEL)์ผ๋ก๋ ๊ทธ๋ฆด ์ ์๋ ๊ฐ๋ฆผ๊ธธ
์ด ๊ทธ๋ฆผ์ ๋ถํ์ด ๊ณง 3์์์ ๋๋ค โ ์์๋ Node, ํ์ดํ๋ Edge, ๊ทธ ์ฌ์ด๋ฅผ ํ๋ฅด๋ ๋ฐ์ดํฐ๊ฐ State์ ๋๋ค.
State ์ค๋ ์ท โ ๋ ธ๋๋ฅผ ์ง๋ ๋๋ง๋ค
"๋ฐฐ์ก์ด 3์ผ์งธ ์ ์์" ๋ฌธ์์ ์ฌ์ ์ ๋ฐ์ดํฐ๋ก โ ๋ ธ๋๊ฐ ๋ฐํํ ๊ฐฑ์ ๋ถ์ด State์ ๋ณํฉ๋๋ ๊ณผ์
์ด์ด์ง๋ ์์
"๋ฐฐ์ก์ด 3์ผ์งธ ์ ์์" โ ์ ์ฅ์ ์ฌ์ ์ State๋ก ๋ค์ ๋ด ๋๋ค
(์์ ์์น)
START โ ์ ๋ ฅ ์งํ
question:
"๋ฐฐ์ก์ด 3์ผ์งธ ์ ์์"
}
classify ํต๊ณผ
question: "๋ฐฐ์ก์ดโฆ",
category: "๋ฐฐ์ก"
}
๋ฐํ๊ฐ {"category": "๋ฐฐ์ก"}๋ง ๋ณํฉ
check_delivery ํต๊ณผ
question: "๋ฐฐ์ก์ดโฆ",
category: "๋ฐฐ์ก",
tracking_info:
"๊ฐ์ ์์ฐจ ยท D-1"
}
respond ํต๊ณผ โ END
question: "๋ฐฐ์ก์ดโฆ",
category: "๋ฐฐ์ก",
tracking_info: "โฆD-1",
answer:
"๋ด์ผ ๋์ฐฉ ์์ โฆ"
}
๋ ธ๋๋ State ์ ์ฒด๋ฅผ ๊ณ ์ณ ์ฐ์ง ์๊ณ ๊ฐฑ์ ๋ถ dict๋ง ๋ฐํ โ ๋ณํฉ์ ๊ทธ๋ํ๊ฐ ๋งก์ต๋๋ค (๋ค์ ์ฅ์ ๋ถ๋ณ ๊ฐฑ์ ์์น)
์กฐ๊ฑด ์ฃ์ง๊ฐ ๋ณธ ๊ฒ๋, ๋ต๋ณ ๋ ธ๋๊ฐ ์ด ๊ฒ๋ ์ ๋ถ ์ด State ์์ ๊ฐ์ ๋๋ค โ State ์ค๊ณ๊ฐ ๊ณง ๊ทธ๋ํ ์ค๊ณ์ธ ์ด์ ์ ๋๋ค.
State ์ค๊ณ ์์น
๊ทธ๋ํ์ ๋ฐ์ดํฐ ๊ณ์ฝ โ ํ๋ ์ต์ ยท ๋ถ๋ณ ๊ฐฑ์ ยท ์๋ ๋์
ํต์ฌ ํฌ์ธํธ
- TypedDict
- ์ํ ์คํค๋ง๋ฅผ ํ์ ์ผ๋ก ์ ์ธ โ ํ๋ ๊ตฌ์กฐ๊ฐ ๊ณง ๊ทธ๋ํ์ ๊ณ์ฝ
- ์ต์ ํ๋
- ํ์ํ ๊ฐ๋ง State์ โ ํ๋๊ฐ ๋์๋ก ๋ฉ๋ชจ๋ฆฌ์ ๋๋ฒ๊น ๋ถ๋ด ์ฆ๊ฐ
- ๋ถ๋ณ ๊ฐฑ์
- ๋ ธ๋๋ State๋ฅผ ์ง์ ์์ ํ์ง ์๊ณ ๊ฐฑ์ ๋ถ์ ๋ฐํ โ ํ๋ฆ ์ถ์ ์ฉ์ด
- Annotated[list, add]
- ๋ฆฌ์คํธ ํ๋ ์๋ ๋์ โ messages์ฒ๋ผ ์์ด๋ ๊ฐ์ ์ฌ์ฉ
์ฝ๋
from typing import TypedDict
# ๊ทธ๋ํ ์ ์ฒด๊ฐ ๊ณต์ ํ๋ ์ํ ์คํค๋ง
class RAGState(TypedDict):
question: str
documents: list
relevance_score: float
answer: str
retry_count: int
# ๋
ธ๋๋ State๋ฅผ ๋ฐ์ ๊ฐฑ์ ๋ถ๋ง ๋ฐํํ๋ ์์ ํจ์
def retrieve(state: RAGState):
docs = retriever.invoke(state["question"])
return {"documents": docs}
StateGraph ์ฝ๋ ํจํด
add_node โ add_edge โ compile() โ 3๋จ๊ณ๋ก ๊ทธ๋ํ ์กฐ๋ฆฝ
from langgraph.graph import StateGraph, MessagesState, START, END
# ๋
ธ๋ = State๋ฅผ ๋ฐ์ ์
๋ฐ์ดํธ๋ฅผ ๋ฐํํ๋ ์์ ํจ์
def retrieve(state): ...
def generate(state): ...
# State ์คํค๋ง๋ก ๊ทธ๋ํ ์ ์ธ โ MessagesState๋ messages๋ฅผ ์๋ ๋์
graph = StateGraph(MessagesState)
graph.add_node("retrieve", retrieve)
graph.add_node("generate", generate)
graph.add_edge(START, "retrieve") # START/END ํน์ ๋
ธ๋๋ก ์ง์
ยท์ข
๋ฃ ์ง์
graph.add_edge("retrieve", "generate")
graph.add_edge("generate", END)
app = graph.compile() # ์ปดํ์ผํ๋ฉด invoke/stream ๊ฐ๋ฅํ Runnable์ด ๋จ
RAG ๊ทธ๋ํ ํจํด
Self-RAG ยท CRAG ยท Query Router
RAG ๊ทธ๋ํ ํจํด
๊ฒ์ฆ๊ณผ ์ฌ์๋๋ฅผ ๋ ธ๋๋ก ๋ง๋๋ ์ธ ํจํด
๊ฒ์ฆ์ ๋ ธ๋๋ก ๋ง๋ ๋ค
๊ฒ์ ์ ์๋ ๋ผ์ฐํ , ๊ฒ์ ํ์๋ ๊ด๋ จ์ฑ ๊ฒ์ฆ, ์์ฑ ํ์๋ ๊ทผ๊ฑฐ ๊ฒ์ฆ โ ์ํ ์ฃ์ง๊ฐ ์ฌ์๋๋ฅผ ๋ง๋ญ๋๋ค.
- Self-RAG โ ์์ฑ ํ ๊ทผ๊ฑฐ ๊ฒ์ฆ โ ๋ถํฉ๊ฒฉ ์ ์ฌ์์ฑ
- CRAG โ ๊ฒ์ ํ ๊ด๋ จ์ฑ ๊ฒ์ฆ โ ์น ๊ฒ์ ํด๋ฐฑ
- Query Router โ ์ง๋ฌธ ์ ํ ๋ถ๋ฅ โ ๋ฒกํฐ/ํค์๋/์น ๋ถ๊ธฐ
์ธ ํจํด์ ๊ณตํต๋ถ๋ชจ๋ "๊ฒ์ฆ โ ๋ถํฉ๊ฒฉ ์ ๋ค๋ฅธ ๊ฒฝ๋ก" โ ์ง์ LCEL๋ก๋ ๋ง๋ค ์ ์๋ ๊ตฌ์กฐ์ ๋๋ค.
Self-RAG
์์ฑ ํ "๋ต๋ณ์ด ๋ฌธ์์ ๊ทผ๊ฑฐํ๋๊ฐ" ๊ฒ์ฆ โ ๋ถํฉ๊ฒฉ ์ ์ฌ์์ฑ
ํฉ๊ฒฉ์ด๋ฉด END๋ก, ๋ถํฉ๊ฒฉ์ด๋ฉด ํ๋กฌํํธ๋ฅผ ์์ ํด ์ฌ์์ฑํฉ๋๋ค โ ์ด ์ฌ์๋ ๋ฃจํ๊ฐ ์ํ ์ฃ์ง์ ๋ํ ์ฌ๋ก์ ๋๋ค.
์ฌ์๋ ๋ฃจํ ์์ ์ฅ์น
retry_count์ best effort โ ๋ฌดํ ๋ฃจํ ์๋ ์๊ธฐ ๊ต์
ํต์ฌ ํฌ์ธํธ
- relevance_score >= 0.7
- ํฉ๊ฒฉ์ โ LLM์ด ๋งค๊ธด ๊ด๋ จ์ฑ ์ ์๋ก ์์ฑ ์งํ ์ฌ๋ถ ํ์
- retry_count
- ์ฌ์์ฑ ํ์๋ฅผ State์ ๊ธฐ๋ก โ ์ต๋ 2ํ๋ก ์ ํํด ๋ฌดํ ๋ฃจํ ์ฐจ๋จ
- best effort
- ํ๊ณ ๋๋ฌ ์ ํ์ฌ ๋ฌธ์๋ก ๋ต๋ณ ์์ฑ โ ๋ฉ์ถ์ง ์๊ณ ๋ง๋ฌด๋ฆฌ
- ํ๋จ์ฉ ๊ฒฝ๋ ๋ชจ๋ธ
- ๊ด๋ จ์ฑ ํ์ ์ Haiku๊ธ ๊ฒฝ๋ ๋ชจ๋ธ๋ก โ ์ถ๊ฐ ํธ์ถ ๋น์ฉ ์ต์ํ
์ฝ๋
# ์กฐ๊ฑด ๋ถ๊ธฐ ํจ์ โ ๋ค์ ๋
ธ๋ ์ด๋ฆ์ ๋ฌธ์์ด๋ก ๋ฐํ
def decide_next(state: RAGState) -> str:
if state["relevance_score"] >= 0.7:
return "generate" # ์ถฉ๋ถ โ ๋ต๋ณ ์์ฑ
if state["retry_count"] >= 2:
return "generate" # ์ฌ์๋ ํ๊ณ โ best effort
return "rewrite" # ๋ถ์กฑ โ ์ฟผ๋ฆฌ ์ฌ์์ฑ
# ์ฌ์์ฑ ๋
ธ๋๊ฐ ์นด์ดํฐ๋ฅผ ์ฌ๋ฆฐ๋ค โ ์์ ์ฅ์น์ ์ค์ฒด
def rewrite_query(state: RAGState):
new_query = rewrite_chain.invoke({"question": state["question"]})
return {"rewritten_query": new_query,
"retry_count": state["retry_count"] + 1}
CRAG + Query Router
๊ฒ์ ์ ๋ผ์ฐํ + ๊ฒ์ ํ ๊ด๋ จ์ฑ ๊ฒ์ฆ
-
1
Query Router
์ง๋ฌธ ๋ถ๋ฅ โ ๋ฒกํฐ/ํค์๋/์น ๊ฒ์ ๋ถ๊ธฐ
-
2
Retrieve
์ ํ๋ ๊ฒฝ๋ก๋ก ๋ฌธ์ ๊ฒ์
-
3
Grade Docs
๊ด๋ จ์ฑ LLM ํ์ โ relevant / not relevant
-
4
๋ถ๊ธฐ
๊ด๋ จ ๋ฌธ์ ์์ โ Generate, ์์ โ Web Search ํด๋ฐฑ
-
5
Generate
๊ฒ์ฆ๋ ๋ฌธ์ ๊ธฐ๋ฐ ์ต์ข ๋ต๋ณ ์์ฑ
๊ฒ์ ์ ์๋ ๋ผ์ฐํฐ๊ฐ ๊ฒฝ๋ก๋ฅผ ๊ณ ๋ฅด๊ณ , ๊ฒ์ ํ์๋ LLM์ด ๊ด๋ จ์ฑ์ ํ์ ํฉ๋๋ค โ ๊ด๋ จ ๋ฌธ์๊ฐ ์์ผ๋ฉด ์น ๊ฒ์์ผ๋ก ํด๋ฐฑํฉ๋๋ค.
ReAct ์์ด์ ํธ
ToolNode ยท ์ํ ๋ฃจํ ยท should_continue
ReAct ์์ด์ ํธ
์ถ๋ก โ๋๊ตฌโ๊ด์ฐฐ ์ํ์ ๊ตฌํ
์ํ ๋ฃจํ๊ฐ ์์ด์ ํธ๋ค
์ถ๋ก โ๋๊ตฌโ๊ด์ฐฐ ์ํ์ StateGraph๋ก ์ง์ ๊ตฌํํฉ๋๋ค โ create_react_agent๋ deprecated, ๊ณต์ ๋์ฒด๋ langchain.agents์ create_agent์ ๋๋ค.
- LLM Node โ tool_calls ๋๋ ์ต์ข ๋ต๋ณ ์์ฑ
- ToolNode โ tool_calls ์คํ ๋นํธ์ธ ๋ ธ๋
- should_continue โ ๋๊ตฌ ๋ฃจํ ์ข ๋ฃ ์กฐ๊ฑด ํจ์
๋๊ตฌ ํธ์ถ์ด ๋จ์ ์์ผ๋ฉด ToolNode๋ก, ์์ผ๋ฉด END๋ก โ should_continue ํ ํจ์๊ฐ ๋ฃจํ๋ฅผ ์ ์ดํฉ๋๋ค.
ReAct = StateGraph + ToolNode
์ถ๋ก โ๋๊ตฌโ๊ด์ฐฐ์ ๊ทธ๋ํ ์ํ์ผ๋ก ๊ตฌํ
ReAct ์์ด์ ํธ ์ฝ๋
StateGraph๋ก ๋๊ตฌ ์ํ ๋ฃจํ ์ง์ ๊ตฌํ
from langgraph.prebuilt import ToolNode
# tool_calls๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ messages์ ์ถ๊ฐํ๋ ๋นํธ์ธ ๋
ธ๋
tool_node = ToolNode([get_weather, search])
def should_continue(state):
last = state["messages"][-1]
return "tools" if last.tool_calls else "end" # ๋๊ตฌ ํธ์ถ์ด ์์ผ๋ฉด ๋ฃจํ ์ข
๋ฃ
graph = StateGraph(MessagesState)
graph.add_node("agent", call_model)
graph.add_node("tools", tool_node)
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", should_continue,
{"tools": "tools", "end": END})
graph.add_edge("tools", "agent") # ์ํ!
create_agent vs ์ง์ ๊ตฌ์ฑ
ํ์ค ๋ฃจํ๋ ํ ์ค๋ก, ๋ฃจํ ์์ ๋ฐ๊ฟ์ผ ํ๋ฉด StateGraph๋ก
create_agent
langchain.agents โ ๊ณต์ ํ๋ฆฌ๋นํธ
- ํ์ค ReAct ๋ฃจํ๋ฅผ ํจ์ ํธ์ถ ํ๋๋ก
- LangGraph ์์์ ๋์ โ ๊ทธ๋ํ ์ง์ ์์ฑ ๋ถํ์
- middleware ์์คํ ์ผ๋ก ์คํ ํ ํ์ฅ
- deprecated๋ create_react_agent์ ๊ณต์ ๋์ฒด
StateGraph ์ง์ ๊ตฌ์ฑ
์ธ๋ฐ ์ ์ด
- should_continue ๋ฑ ๋ฃจํ ์กฐ๊ฑด ์ง์ ์ ์
- ๊ฒ์ฆ ยท ์์ฝ ๊ฐ์ ์ปค์คํ ๋ ธ๋ ์์ ์ฝ์
- Self-RAG์ฒ๋ผ ํ์ค์ ๋ฒ์ด๋ ์ํ ๊ตฌํ
- ์ ์ฌ๋ผ์ด๋์ ์ฝ๋ ํจํด์ด ๊ทธ ๊ณจ๊ฒฉ
ํ์ค ๋๊ตฌ ๋ฃจํ๋ฉด create_agent ํ ์ค, ๋ฃจํ ๊ตฌ์กฐ ์์ฒด๋ฅผ ๋ฐ๊ฟ์ผ ํ๋ฉด StateGraph ์ง์ ๊ตฌ์ฑ์ผ๋ก ๋ด๋ ค๊ฐ๋๋ค.
๋ฉํฐ์์ด์ ํธ
Supervisor ยท Swarm ยท HITL ยท Checkpoint
๋ฉํฐ์์ด์ ํธ
ํ์ ํจํด๊ณผ ์ฌ๋์ ๊ฐ์ ์ง์
ํ์ ๋ฐฉ์๋ ๊ทธ๋ํ๋ก
์ฌ๋ฌ ์์ด์ ํธ์ ํ์ ๋ฐฉ์์ ๊ทธ๋ํ๋ก ์ค๊ณํฉ๋๋ค โ ์ํํ ๋จ๊ณ์๋ ์ฌ๋์ ์น์ธ ๊ฒ์ดํธ๋ฅผ ๋ผ์ ๋ฃ์ต๋๋ค.
- Supervisor โ ์ค์ ์์ ยท langgraph-supervisor
- Swarm โ ์์จ ํธ๋์คํ ยท ๋ถ์ฐ ์์ฌ๊ฒฐ์
- HITL โ interrupt() + Command(resume)
๋ช ํํ ์์ ๋ถํด๊ฐ ์์ผ๋ฉด Supervisor, ๋์ ์ํฌํ๋ก์ฐ๋ฉด Swarm โ ๊ณ ์ํ ๋ ธ๋์๋ HITL์ ๊ฒ๋๋ค.
Supervisor vs Swarm
์์ ๋ถํด ๋ฐฉ์์ ๋ฐ๋ผ ํจํด์ ์ ํ
Supervisor
์ค์ ์์
- ์์ LLM์ด ํ์ ์์ด์ ํธ์ ํ์คํฌ ๋ฐฐ์
- ์ ์ฒด ์ํ๋ฅผ Supervisor๊ฐ ๊ด๋ฆฌ
- langgraph-supervisor๋ก ๋น ๋ฅด๊ฒ ๊ตฌ์ถ
- ๋ช ํํ ์์ ๋ถํด๊ฐ ์์ ๋
Swarm
์์จ ํธ๋์คํ
- ์์ด์ ํธ๊ฐ ์ค์ค๋ก ๋ค์์ ์ ๋ฌ
- ๋ถ์ฐ ์์ฌ๊ฒฐ์ โ ์ค์ ์์
- ํธ๋์คํ ํจ์๋ก ์ ํ ์กฐ๊ฑด ์ ์
- ๋์ ์ํฌํ๋ก์ฐ์ ์ ํฉ
์์ ๋ถํด๊ฐ ๋ช ํํ๋ฉด Supervisor๋ก ์ค์์์ ๋ฐฐ์ ํ๊ณ , ํ๋ฆ์ด ๋์ ์ด๋ฉด Swarm์ ์์จ ํธ๋์คํ์ ๋งก๊น๋๋ค.
langgraph-supervisor๋ก ๊ตฌ์ถ
์ค์ ์์ ํจํด์ ํจํค์ง ํ๋๋ก โ ์ง์ ๊ตฌํ ์ ์ ๋จผ์ ๊ฒํ
- pip install langgraph-supervisor
- ๋ณ๋ ํจํค์ง(0.0.31) โ LangGraph 1.x ํธํ ๊ณต์ ํ์ธ
- create_supervisor()
- ํ์ ์์ด์ ํธ ๋ชฉ๋ก์ผ๋ก Supervisor ๊ทธ๋ํ๋ฅผ ๋ฐ๋ก ์์ฑ
- ์ค์ ์ํ ๊ด๋ฆฌ
- ์ ์ฒด ์ํ๋ Supervisor๊ฐ ๋ณด์ โ ํ์ ์์ด์ ํธ๋ ๋ฐฐ์ ๋ฐ์ ํ์คํฌ๋ง
- ์ง์ ๊ตฌํ ์ ํ์
- ๋ฐฐ์ ๋ก์ง์ด ํน์ํด์ง๋ฉด StateGraph + ์กฐ๊ฑด ์ฃ์ง๋ก ์ปค์คํ
ํ์ค ์ค์ ์์์ด๋ฉด ํจํค์ง๋ก ์ถฉ๋ถํฉ๋๋ค โ ๋ฐฐ์ ๋ก์ง์ด ํน์ํด์ง๋ ์๊ฐ์ด ์ง์ ๊ตฌํ์ผ๋ก ๋ด๋ ค๊ฐ๋ ์์ ์ ๋๋ค.
HITL ์น์ธ ๊ฒ์ดํธ
interrupt()๋ก ๊ทธ๋ํ ์ผ์ ์ค์ง โ ์ฌ์ฉ์ ํ์ธ โ Command(resume)๋ก ์ฌ๊ฐ
-
1
invoke()
์ฌ์ฉ์ ์์ฒญ์ผ๋ก ๊ทธ๋ํ ์คํ ์์
-
2
interrupt_before
์ํ ๋ ธ๋ ์ง์ ์ ์๋ ์ค์ง โ Checkpointer์ ์ ์ฅ
-
3
์ฌ์ฉ์ ํ์ธ
"๊ฒฐ์ ๋ฅผ ์น์ธํ์๊ฒ ์ต๋๊น?" ํ์
-
4
Command(resume)
์น์ธ โ True๋ก ๊ทธ๋ํ ์ฌ๊ฐ, ๊ฑฐ๋ถ โ ๋ค๋ฅธ ๊ฒฝ๋ก
์ค๋จ ์์ ์ ์ํ๋ Checkpointer์ ์ ์ฅ๋ฉ๋๋ค โ ์ฌ์ฉ์๊ฐ ์น์ธํ๋ฉด Command(resume)๋ก ๊ทธ ์ง์ ๋ถํฐ ์ฌ๊ฐํฉ๋๋ค.
HITL ๋ฉ์์ง ์๋ณต
์ค๋จ ยท ์ ์ฅ ยท ์ฌ๊ฐ๊ฐ ์ค๊ฐ๋ ์ค์ ์์ โ ํด๋ผ์ด์ธํธ ยท ๊ทธ๋ํ ยท Checkpointer ยท ์น์ธ์
์ฌ๊ฐ๊ฐ ๊ฐ๋ฅํ ์ด์ ๋ ์ค๋จ ์์ ์ํ๊ฐ Checkpointer์ ๋จ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค โ ํ๋ก์ธ์ค๊ฐ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ด ์๋๋ผ ์ํ๊ฐ ๊ธฐ๋ค๋ฆฝ๋๋ค.
Deep Agents์ ํ๋ก๋์
create_deep_agent ยท Checkpoint ยท LangSmith ยท ๋ฐฐํฌ
Deep Agents์ ํ๋ก๋์
์ถ์ํ ์ ํ๊ณผ ๋ฐฐํฌ ์ ์ ๊ฒ
๋น ๋ฅด๊ฒ ์์, ๋จ๋จํ๊ฒ ๋ฐฐํฌ
์์์ Deep Agents์ ๊ณ ์์ค ์ถ์ํ๋ก ๋น ๋ฅด๊ฒ, ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํ๋ฉด StateGraph ์ง์ ๊ตฌ์ฑ์ผ๋ก โ ๋ฐฐํฌ ์ ์ฒดํฌ๋ฆฌ์คํธ๊น์ง ์ง์ต๋๋ค.
- Deep Agents โ create_deep_agent() ํ ์ค
- Checkpointer โ MemorySaver โ PostgresSaver
- LangSmith โ ๋ ธ๋๋ณ Trace ๋๋ฒ๊น
- ๋ฐฐํฌ โ AgentCore Runtime ๋๋ ECS/Lambda
๊ฐ๋ฐ์ฉ MemorySaver๋ฅผ ํ๋ก๋์ PostgresSaver๋ก ๋ฐ๊พธ๋ ๊ฒ์ด ๋ฐฐํฌ ์ ์ฒซ ๋ฒ์งธ ์ ๊ฒ ํญ๋ชฉ์ ๋๋ค.
LangGraph vs Deep Agents
์ง์ ๊ตฌํ vs ๊ณ ์์ค ์ถ์ํ โ ์์์ Deep Agents, ์ ์ด๋ LangGraph
| ํญ๋ชฉ | LangGraph (์ง์ ) | Deep Agents (์ถ์ํ) |
|---|---|---|
| ์์ | StateGraph ์ง์ ๊ตฌ์ฑ | create_deep_agent() ํ ์ค |
| ์ ์ฐ์ฑ | โ ๋ชจ๋ ํจํด ๊ตฌํ ๊ฐ๋ฅ | ํ๋ฆฌ์ ํจํด ๋ด์์ |
| ๋นํธ์ธ | ์์ โ ์ง์ ๊ตฌํ | executeยทeval(์ฝ๋ ์คํ), Harness Profiles |
| ๋ฐฐํฌ | AgentCore Runtime / ์์ฒด | Managed Deep Agents (LangSmith) |
| ๋ฒ์ | LangGraph 1.x (์์ ) | v0.6 (๋น ๋ฅธ ์งํ ์ค) |
์์์ create_deep_agent() ํ ์ค๋ก ๋น ๋ฅด๊ฒ, ํ๋ฆฌ์ ์ ๋ฒ์ด๋๋ ํจํด์ด ํ์ํ๋ฉด StateGraph ์ง์ ๊ตฌ์ฑ์ผ๋ก ๋ด๋ ค๊ฐ๋๋ค.
Checkpointer โ ์ํ ์์ํ
์ค๋ ์ท์ด ๋ง๋๋ ์ธ ๊ฐ์ง ๋ฅ๋ ฅ โ HITL ์ฌ๊ฐ ยท ์ฅ์ ๋ณต๊ตฌ ยท ์๊ฐ์ฌํ
MemorySaver
๊ฐ๋ฐ์ฉ ์ธ๋ฉ๋ชจ๋ฆฌ
- ์ค์ ์์ด ๋ฐ๋ก ์ฌ์ฉ โ ๋น ๋ฅธ ์คํ
- ํ๋ก์ธ์ค ์ข ๋ฃ ์ ์ํ ์์ค
- ๋ก์ปฌ ๊ฐ๋ฐ ยท ๋จ์ ํ ์คํธ์ ์ ํฉ
- ํ๋ก๋์ ์ฌ์ฉ ๊ธ์ง
PostgresSaver
ํ๋ก๋์ ์์ํ
- DB์ ์ํ ์ค๋ ์ท ์ ์ฅ โ ์ฌ์์์๋ ์ ์ง
- HITL ์ฌ๊ฐ์ ์ฅ์ ๋ณต๊ตฌ์ ์ ์ ์กฐ๊ฑด
- ๊ณผ๊ฑฐ ์ฒดํฌํฌ์ธํธ๋ก ๋๋๋ฆฌ๋ ์๊ฐ์ฌํ ๋๋ฒ๊น
- DynamoDB ๋ฑ์ ์ปค๋ฎค๋ํฐ ๊ตฌํ
Checkpointer๋ ํธ์ ๊ธฐ๋ฅ์ด ์๋๋ผ HITL๊ณผ ์ฅ์ ๋ณต๊ตฌ์ ์ ์ ์กฐ๊ฑด์ ๋๋ค โ ๋ฐฐํฌ ์ ๊ต์ฒด๊ฐ ์ฒดํฌ๋ฆฌ์คํธ 1๋ฒ์ธ ์ด์ ์ ๋๋ค.
AgentCore Runtime์ผ๋ก ๋ฐฐํฌ
์ปดํ์ผ๋ ๊ทธ๋ํ๋ฅผ ๊ด๋ฆฌํ ๋ฐํ์์ ์ฌ๋ฆฌ๋ 4๋จ๊ณ
-
1
์ค์บํด๋ ์์ฑ
agentcore create --framework LangChain_LangGraph โ ํ๋ ์์ํฌ ์ต์ ์ผ๋ก LangGraph ํ๋ก์ ํธ ๊ณจ๊ฒฉ์ ๋ง๋ญ๋๋ค.
-
2
๊ทธ๋ํ ์ปดํ์ผ
app = graph.compile(checkpointer=...) โ ์ด๋ Checkpointer๋ ํ๋ก๋์ ๋ฐฑ์๋๋ก ๊ต์ฒดํฉ๋๋ค.
-
3
์ง์ ์ ๋ํ
BedrockAgentCoreApp์ @app.entrypoint๋ก ํธ์ถ ์ง์ ์ ์ ์ ์ธํฉ๋๋ค. bedrock-agentcore ํจํค์ง๋ langgraph extras๋ฅผ ์ ๊ณตํฉ๋๋ค.
-
4
๋ฐฐํฌ
agentcore deploy ํ ๋ฒ์ผ๋ก ํจํค์ง๊ณผ ๋ฐฐํฌ๊ฐ ๋๋ฉ๋๋ค. ์คํ ์ค์ผ์ผ ยท ๋ด์ฅ ๊ด์ธก์ฑ ยท ๋ฒ์ ๊ด๋ฆฌ๋ Runtime์ด ์ ๊ณตํฉ๋๋ค.
ECS/Lambda ์์ฒด ์ด์๊ณผ ๋ฌ๋ฆฌ ์ค์ผ์ผ ยท ๊ด์ธก์ฑ ยท ๋ฒ์ ๊ด๋ฆฌ๊ฐ ๋ฐํ์์ ๋ด์ฅ๋ฉ๋๋ค โ LangGraph ์ฝ๋๋ ๊ทธ๋๋ก, ์ง์ ์ ๋ง ๋ํํฉ๋๋ค.
ํ๋ก๋์ ์ฒดํฌ๋ฆฌ์คํธ
LangGraph ์์ด์ ํธ๋ฅผ ํ๋ก๋์ ์ ๋ฐฐํฌํ๊ธฐ ์ ํ์ธ
-
1
Checkpointer ๊ต์ฒด
MemorySaver(๊ฐ๋ฐ) โ PostgresSaver(ํ๋ก๋์ , DynamoDB๋ ์ปค๋ฎค๋ํฐ ๊ตฌํ) โ ์ํ ์์ํ ํ์
-
2
LangSmith ์ฐ๋
๋ ธ๋๋ณ ์คํ ์๊ฐยทํ ํฐยท์๋ฌ ์๊ฐํ โ ๋ณ๋ชฉ ๋ฐ๊ฒฌ
-
3
interrupt ์ค๊ณ
๊ณ ์ํ ๋ ธ๋์ interrupt_before ์ค์ โ HITL ๊ฒฝ๋ก ํ๋ณด
-
4
๋ฐฐํฌ ์ ํ
AgentCore Runtime(๊ด๋ฆฌํ) ๋๋ ECS/Lambda(์์ฒด ์ด์)
Checkpointer ๊ต์ฒดยทLangSmith ์ฐ๋ยทinterrupt ์ค๊ณยท๋ฐฐํฌ ์ ํ โ ๋ค ๊ฐ์ง๋ฅผ ํ์ธํ ๋ค ํ๋ก๋์ ์ผ๋ก ๋ด๋ณด๋ ๋๋ค.
์์ด์ ํธ์ ๋๋ ํ๋ก
StateยทNodeยทEdge 3์์ ์์ Self-RAGยทReActยทSupervisorยทHITL โ ๊ทธ๋ํ๊ฐ ๊ณง ์์ด์ ํธ ์ค๊ณ
๊ทธ๋ํ๋ก ์์ด์ ํธ์ RAG๋ฅผ ์ ์ดํ๋ค
StateยทNodeยทEdge 3์์ ์์ Self-RAGยทReActยทSupervisorยทHITL โ LangGraph๋ ์์ด์ ํธ์ ๋๋ ํ๋ก๋ฅผ ์ค๊ณํ๋ ๋๊ตฌ์ ๋๋ค.
StateGraph ์์ RAG ๋ฃจํ ยท ReAct ยท Supervisor ยท HITL ํจํด ๊ตฌํ