STUDY/AI Agent

[AI Agent] LangGraph1

seoyn 2026. 7. 16. 17:34

1. LangGraph๋ž€?

 : LangCahain ์ƒํƒœ๊ณ„์—์„œ ๋งŒ๋“  ๊ทธ๋ž˜ํ”„ ๊ตฌ์กฐ ๊ธฐ๋ฐ˜ ์›Œํฌํ”Œ๋กœ์šฐ/์—์ด์ „ํŠธ ๊ฐœ๋ฐœ์šฉ ๋Ÿฐํƒ€์ž„ ํ”„๋ ˆ์ž„์›Œํฌ 

 • ํŠน์ง• : ์‚ฌ์ดํด(์ˆœํ™˜) ์ง€์› → LCEL๋กœ ๊ตฌํ˜„ ๋ถˆ๊ฐ€๋Šฅํ•œ '๋งŒ์กฑ์Šค๋Ÿฝ์ง€ ์•Š์œผ๋ฉด ๋˜๋Œ์•„๊ฐ€๊ธฐ' ๋กœ์ง ๊ตฌํ˜„ ๊ฐ€๋Šฅ

 • ๊ทธ๋ž˜ํ”„ ๊ตฌ์กฐ : ๋ฐ์ดํ„ฐ ๊ฐ„ ๊ด€๊ณ„ ํ‘œํ˜„ํ•˜๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ - Node(์ž‘์—… ์ˆ˜ํ–‰) + Edge(์ž‘์—… ํ๋ฆ„ ์ •์˜) 

 • ๋Ÿฐํƒ€์ž„ ํ”„๋ ˆ์ž„์›Œํฌ : ๋งŒ๋“  ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์‹คํ–‰ ์‹œ์ ๊นŒ์ง€ ๊ด€๋ฆฌ

 • LangChain vs LangGraph

ํ•ญ๋ชฉ LangChain LangGraph
์‹คํ–‰ ํ๋ฆ„ ์„ ํ˜•/์ˆœ์ฐจ ์ค‘์‹ฌ ๊ทธ๋ž˜ํ”„ ๊ธฐ๋ฐ˜(๋ถ„๊ธฐ/๋ฃจํ”„)
์ƒํƒœ ๊ด€๋ฆฌ ๊ธฐ๋ณธ ๋ฉ”๋ชจ๋ฆฌ/์„ธ์…˜ ์ค‘์‹ฌ ์ง€์† ์ƒํƒœ(durable)
์ถ”์ƒํ™” ์ˆ˜์ค€ LCEL ๊ณ ์ˆ˜์ค€ API ์ €์ˆ˜์ค€ ์ œ์–ด
์ ํ•ฉ ์šฉ๋„ ๊ฐ„๋‹จํ•œ ์—์ด์ „ํŠธ/์›Œํฌํ”Œ๋กœ์šฐ ๋ณต์žกํ•œ ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ, ์ƒํƒœ ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ

   

2. ํ•ต์‹ฌ ๊ฐœ๋…(Node, Edge, State)

1) Node(๋…ธ๋“œ)

 : ์‹ค์ œ ์ž‘์—… ์ˆ˜ํ–‰ํ•˜๋Š” Python ํ•จ์ˆ˜. ํ˜„์žฌ ์ƒํƒœ ์ž…๋ ฅ๋ฐ›์•„ ์—…๋ฐ์ดํŠธ๋œ ์ƒํƒœ ๋ฐ˜ํ™˜

 - ํŠน์ˆ˜ ๋…ธ๋“œ START, END : ์‹คํ–‰ ํ•จ์ˆ˜ ์—†์Œ. add_node()๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š๋Š” ์˜ˆ์•ฝ๋œ ์ƒ์ˆ˜

 

2) State(์ƒํƒœ)

 : ๊ทธ๋ž˜ํ”„ ์‹คํ–‰ ์ค‘ ์œ ์ง€๋˜๋Š” key-value ํ˜•ํƒœ์˜ ์ €์žฅ์†Œ(dict)

 - State Schema(TypedDict or pydantic.BaseModel)๋กœ ๋จผ์„œ ์„ค๊ณ„ → Graph ์ƒ์„ฑ ์‹œ ์ „๋‹ฌ

 - Schema์— ์ •์˜๋œ Field๋งŒ ์ €์žฅ ๊ฐ€๋Šฅ

 • ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๋ฐฉ์‹ 2๊ฐ€์ง€

 โ‘  ์™„์ „ ์žฌ์ •์˜ : ๊ฐ™์€ key๋กœ ๋ฐ˜ํ™˜๋˜๋ฉด ๊ธฐ์กด ๊ฐ’ ๋ฎ์–ด์”€

 โ‘ก Reducer ์‚ฌ์šฉ : Annotated[ํƒ€์ž…, reducerํ•จ์ˆ˜] ํ˜•ํƒœ๋กœ ์ง€์ •, ๋ฆฌ์ŠคํŠธ ๋ˆ„์  ๋“ฑ์— ์‚ฌ์šฉ(ex. add_messages)

 

3. StateGraph ๊ตฌํ˜„ ํ๋ฆ„

from langgraph.graph import StateGraph, START, END

graph = StateGraph(MyState)                     # 1. State Schema๋กœ ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ
graph.add_node("increment", increment_counter)  # 2. ๋…ธ๋“œ ๋“ฑ๋ก
graph.add_edge(START, "increment")              # 3. ์—ฃ์ง€ ์—ฐ๊ฒฐ
graph.add_edge("increment", END)
app = graph.compile()                           # 4. ์ปดํŒŒ์ผ

 • ํ˜ธ์ถœ ๋ฐฉ๋ฒ•

  - invoke(input, config) : ๊ทธ๋ž˜ํ”„ ํ•œ ๋ฒˆ์— ์‹คํ–‰, ์ตœ์ข… State๋งŒ ๋ฐ˜ํ™˜

  - stream(input, config) : ์‹คํ–‰ ์ค‘ ์ด๋ฒคํŠธ ์‹ค์‹œ๊ฐ„ yield

 

4. ๋‹ค์–‘ํ•œ ์—ฃ์ง€ ์œ ํ˜•

 • ๊ธฐ๋ณธ ์—ฃ์ง€(Normal Edge)

  : ๊ณ ์ •๋œ ํ๋ฆ„์œผ๋กœ ์ˆœ์ฐจ ์‹คํ–‰ - add_edge(A, B)

 

 • ์กฐ๊ฑด๋ถ€ ์—ฃ์ง€(Conditional Edge)

  : add_conditional_edges(์†Œ์Šค๋…ธ๋“œ, ๋ผ์šฐํŒ…ํ•จ์ˆ˜, path_map)์œผ๋กœ ์ •์˜

  - 3์š”์†Œ 

  โž€ ์†Œ์Šค ๋…ธ๋“œ : ์กฐ๊ฑด ํ‰๊ฐ€๊ฐ€ ์‹œ์ž‘๋˜๋Š” ๋…ธ๋“œ

  โž ๋ผ์šฐํŒ… ํ•จ์ˆ˜ : ์ƒํƒœ๊ฐ’ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค์Œ ๋…ธ๋“œ ์ด๋ฆ„ ๋ฐ˜ํ™˜

  โž‚ path_map : ๋ฐ˜ํ™˜๊ฐ’ → ์ด๋™ํ•  ๋…ธ๋“œ ๋งคํ•‘(dict or list)

graph.add_conditional_edges(
    "llm_answer", relevance_check,
    {"grounded": END, "not_grounded": "retrieve"}
)

 

 • ๋ฐ˜๋ณต ๊ตฌ์กฐ(์ˆœํ™˜)

 : ๊ฒ€์ƒ‰ ์žฌ์‹œ๋„, ๋‹ต๋ณ€ ์žฌ์ƒ์„ฑ, ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ๋ฐฉ์ง€, HITL(Human-In-The-Loop) ๋“ฑ์— ํ™œ์šฉ

 

 • Command

 : ๋…ธ๋“œ๊ฐ€ '์ƒํƒœ ์—…๋ฐ์ดํŠธ + ๋‹ค์Œ ๋…ธ๋“œ ์ง€์ •' ๋™์‹œ์— ๋ฐ˜ํ™˜

 - ํŒŒ๋ผ๋ฏธํ„ฐ : updata(์ƒํƒœ ๊ฐฑ์‹ ), goto(์ด๋™ํ•  ๋…ธ๋“œ), graph(subgraph → parent ์ด๋™ ์‹œ Command.PARENT ์ง€์ •), resume(interrupt ์žฌ๊ฐœ์šฉ)

๊ตฌ๋ถ„ Conditional Edge Command
ํ๋ฆ„ ์ œ์–ด ์œ„์น˜ ๊ทธ๋ž˜ํ”„ ์ •์˜๋ถ€ ๋…ธ๋“œ ๋‚ด๋ถ€
์‚ฌ์šฉ ์˜ˆ  ๋ถ„๋ฅ˜๊ธฐ, ๋ผ์šฐํ„ฐ ์—์ด์ „ํŠธ ํ•ธ๋“œ์˜คํ”„, ๋™์  ๋ผ์šฐํŒ…

 

Send

 : ํ•˜๋‚˜์˜ ๋…ธ๋“œ์—์„œ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์  ์ƒ์„ฑํ•ด ๋‹ค๋ฅธ ๋…ธ๋“œ๋กœ ๋ณ‘๋ ฌ ์ „๋‹ฌ(Fan-out, map-reduce ํŒจํ„ด)

 - ํŒŒ๋ผ๋ฏธํ„ฐ : node(๋Œ€์ƒ ๋…ธ๋“œ), arg(์ „๋‹ฌํ•  state - ์ „์ฒด Schema์— ์—†๋Š” ํ•„๋“œ๋„ ๊ฐ€๋Šฅ)

๊ตฌ๋ถ„ ๋ฐ˜๋ณต ๊ตฌ์กฐ Send
๋ชฉ์  ์กฐ๊ฑด ๋งŒ์กฑ๊นŒ์ง€ ๊ฐ™์€ ํ๋ฆ„ ๋ฐ˜๋ณต ์—ฌ๋Ÿฌ ์ž‘์—… ๋‚˜๋ˆ  ์‹คํ–‰
ํ•ต์‹ฌ ๊ฐœ๋… Loop Fan-out

'STUDY > AI Agent' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[AI Agent] AI Agent์™€ ToolCalling2  (0) 2026.07.14
[AI Agent] AI Agent์™€ ToolCalling1  (0) 2026.07.13