์ต๊ทผ AI ์ ํ๋ฆฌ์ผ์ด์ , ํนํ LLM(๊ฑฐ๋ ์ธ์ด ๋ชจ๋ธ)์ ํ์ฉํ ์๋น์ค๋ ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํ๊ณ ์์ต๋๋ค. ํ์ง๋ง ๋ง์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ ํ 'ํ๋กฌํํธ-์๋ต'์ด๋ผ๋ ๋จ์ํ ํจํด์ ๋จธ๋ฌผ๋ฌ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ์ง๋ฌธํ๋ฉด, LLM์ด ํ ๋ฒ์ ๋ต๋ณ์ ์์ฑํ๋ ์์ด์ฃ . ์ด๋ ๋ง์น LLM์ ๋๋ํ '์กฐ์'๋ก๋ง ํ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
ํ์ง๋ง ํ๋์ ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ ๋จ์ํ ์ง์์๋ต์ ๋์ด์ญ๋๋ค. ์ฐ๋ฆฌ๋ AI๊ฐ ๋์ ์ด๊ณ , ์ ์ฐํ๋ฉฐ, ๊ณผ๊ฑฐ์ ๋ํ์ ๋งฅ๋ฝ์ '๊ธฐ์ต(Stateful)'ํ๊ธธ ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๊ณ ๊ฐ์ผํฐ ์ฑ๋ด์ด ๋จ์ํ ๋ต๋ณ๋ง ํ๋ ๊ฒ์ด ์๋๋ผ, ์ค์ค๋ก DB๋ฅผ ์กฐํํ๊ณ , ์น ๊ฒ์์ ์ํํ๋ฉฐ, ๋ต๋ณ์ด ๋ถํ์คํ๋ฉด ์ฌ๋(๋ด๋น์)์๊ฒ ์น์ธ์ ์์ฒญํ๋ ๋ฑ, ๋ฅ๋์ ์ธ ์ํฌํ๋ก์ฐ๋ฅผ ์ฒ๋ฆฌํ๊ธธ ๊ธฐ๋ํฉ๋๋ค.
์ด๋ฌํ ์๊ตฌ ์์์ '์์ด์ ํฑ AI ์์คํ (Agentic AI Systems)'์ด๋ผ๋ ๊ฐ๋ ์ด ๋ถ์ํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์์คํ ์ ์ค์ฌ์๋ LLM์ '์กฐ์'๊ฐ ์๋, ์ ์ฒด ์ํฌํ๋ก์ฐ๋ฅผ ์ ์ดํ๋ '๋๋' ๋๋ '์งํ์'๋ก ๋ง๋๋ ๊ฐ๋ ฅํ ํ๋ ์์ํฌ๊ฐ ํ์ํฉ๋๋ค.
์ค๋ ์ฐ๋ฆฌ๊ฐ ๊น์ด ์๊ฒ ๋ค๋ฃฐ ์ฃผ์ ๊ฐ ๋ฐ๋ก '๋ญ๊ทธ๋ํ(LangGraph)'์ ๋๋ค. LangGraph๋ LangChain ์์ ๊ตฌ์ถ๋ ์ค์ผ์คํธ๋ ์ด์ ํ๋ ์์ํฌ๋ก, ๋ณต์กํ๊ณ ์ํ ๊ธฐ๋ฐ์ด๋ฉฐ ์ํ์ ์ธ(cyclic) ์ํฌํ๋ก์ฐ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ์ต์ ํ๋์ด ์์ต๋๋ค.
์ด ๊ธ์์๋ LangGraph๊ฐ ๋ฌด์์ธ์ง, ๊ธฐ์กด LangChain์ ํ๊ณ๋ฅผ ์ด๋ป๊ฒ ๊ทน๋ณตํ๋์ง, ๊ทธ ํต์ฌ ์ํคํ ์ฒ๋ ๋ฌด์์ด๋ฉฐ, ์ด๋ฅผ ํ์ฉํด ์ค๋ฌด์ ์ธ ์์ด์ ํฑ ์์คํ ์ ๊ตฌ์ถํ๋ 5๋จ๊ณ ์ ๊ทผ๋ฒ๊ณผ ๊ธฐ์ ์ ๊ณผ์ ๊น์ง, A๋ถํฐ Z๊น์ง ์ฌ์ธต์ ์ผ๋ก ๋ถ์ํด ๋ณด๊ฒ ์ต๋๋ค.
1. ์์ด์ ํฑ AI ์์คํ ์ด๋ ๋ฌด์์ธ๊ฐ? ๐ค
LangGraph๋ฅผ ์ดํดํ๊ธฐ ์ ์, ์ฐ๋ฆฌ๊ฐ ๋ง๋ค๊ณ ์ ํ๋ '์์ด์ ํฑ ์์คํ '์ด ๋ฌด์์ธ์ง ๋ช ํํ ํด์ผ ํฉ๋๋ค.
์์ด์ ํฑ ์์คํ ์ LLM์ ์ ์ด ๋ฃจํ(control loop)์ ์ค์ฌ์ ๋ฐฐ์นํ์ฌ, ๊ณ ์ ๋ ์์๋ฅผ ๋ฐ๋ฅด๋ ๊ฒ์ด ์๋๋ผ ๋์ ์ผ๋ก ๋ค์ ํ๋์ ๊ฒฐ์ ํ ์ ์๋๋ก ์ค๊ณ๋ ์์คํ ์ ์๋ฏธํฉ๋๋ค.
1.1. LLM ์ ํ๋ฆฌ์ผ์ด์ ์ ์์จ์ฑ ์คํํธ๋ผ
๋ชจ๋ LLM ์ฑ์ด ๋์ผํ ์์ค์ ์์จ์ฑ์ ๊ฐ๋ ๊ฒ์ ์๋๋๋ค. ์ ๋ ๊ฐ์ธ์ ์ผ๋ก ์์จ์ฑ ์์ค์ ๋ค์๊ณผ ๊ฐ์ด 4๋จ๊ณ๋ก ๊ตฌ๋ถํฉ๋๋ค.
- Level 0: ๋จ์ ํ๋กฌํํธ (Single Prompt)
- ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํํ๋ก, ChatGPT์ ๊ฐ์ ์ธํฐํ์ด์ค์์ ์ฌ์ฉ์๊ฐ ์ง์ ํ๋กฌํํธ๋ฅผ ์ ๋ ฅํ๊ณ ๋จ์ผ ์๋ต์ ๋ฐ์ต๋๋ค.
- Level 1: ๊ณ ์ ๋ ์ฒด์ธ (Fixed Chain)
- LangChain์ LCEL (LangChain Expression Language)์ ์ฌ์ฉํด [ํ๋กฌํํธ -> LLM -> ์ถ๋ ฅ ํ์]์ฒ๋ผ ์ ํด์ง ์์(DAG, Directed Acyclic Graph)๋ก ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํฉ๋๋ค.
- Level 2: ๋๊ตฌ ์ฌ์ฉ ์์ด์ ํธ (Tool-using Agent)
- ReAct (Reason + Act)์ ๊ฐ์ ํจํด์ ์ฌ์ฉํด, LLM์ด '์๊ฐ'ํ๊ณ '๋๊ตฌ(Tool)'๋ฅผ ์ ํํ์ฌ ์คํํฉ๋๋ค. (e.g., LangChain์ ๊ธฐ๋ณธ Agents) ํ์ง๋ง ์ฌ์ ํ ์ํ ๊ด๋ฆฌ๊ฐ ์ด๋ ต๊ณ ํ๋ฆ์ด ๊ฒฝ์ง๋ ์ ์์ต๋๋ค.
- Level 3: ๋์ /์ํ ๊ธฐ๋ฐ ์์ด์ ํธ (Stateful Agent)
- ๋ฐ๋ก LangGraph๊ฐ ์งํฅํ๋ ๋ชฉํ์ ๋๋ค. LLM์ด ์ํฌํ๋ก์ฐ์ '์ํ'๋ฅผ ๋ช ํํ ์ธ์งํ๊ณ , ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ถ๊ธฐ(branching)ํ๊ฑฐ๋, ํน์ ์์ ์ ๋ฐ๋ณต(looping)ํ๊ณ , ํ์์ ์ธ๊ฐ์ ๊ฐ์ (human-in-the-loop)์ ์์ฒญํ๋ ๋ฑ ๊ณ ๋๋ก ๋์ ์ธ ์์ ์ํ์ด ๊ฐ๋ฅํฉ๋๋ค.
1.2. ์์ด์ ํฑ ์์คํ ์ 3๋ ํต์ฌ ์์
์์ด์ ํฑ ์์คํ ์ ๋ค์ ์ธ ๊ฐ์ง ์์๊ฐ ์ ๊ธฐ์ ์ผ๋ก ๊ฒฐํฉ๋์ด ์๋ํฉ๋๋ค.
- ๐ง LLM as a "Brain": LLM์ด ์ฌ์ฉ์ ์ ๋ ฅ๊ณผ ํ์ฌ ์ปจํ ์คํธ(์ํ)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค์์ ์ํํ ์์ ์ ๋์ ์ผ๋ก ๊ฒฐ์ ํฉ๋๋ค. (e.g., "๋ฌธ์ ๊ฒ์์ด ํ์ํ๊ฐ?", "์น ๊ฒ์์ด ํ์ํ๊ฐ?", "์ธ๊ฐ์ ์น์ธ์ด ํ์ํ๊ฐ?")
- ๐ ๏ธ ๋๊ตฌ ํตํฉ (Tool Integration): LLM์ ํ๊ณ๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ์ธ๋ถ ๋๊ตฌ(๋ฐ์ดํฐ๋ฒ ์ด์ค, ์น ๊ฒ์ API, ๋ง์ถคํ ๋น์ฆ๋์ค ๋ก์ง)๋ฅผ ํตํฉํ์ฌ ๊ธฐ๋ฅ์ ํ์ฅํฉ๋๋ค.
- ๐๏ธ ์ํ ๋ฐ ๋ฉ๋ชจ๋ฆฌ (State & Memory): ๋ด์ฅ๋ ์ง์์ฑ(persistence) ๋ฐ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฅ์ ํ์ฉํด ๋ํ ์ํ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ฌ๋ฌ ํด์ ๊ฑธ์น ์ฅ๊ธฐ์ ์ธ ์ํธ์์ฉ์์๋ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๊ณ ๋ํ๋ RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ฐํด ๋ด ์๋ค. ๊ธฐ์กด RAG๊ฐ [์ฟผ๋ฆฌ -> ๊ฒ์ -> LLM ์๋ต]์ ๋จ๋ฐฉํฅ ํ๋ฆ์ด์๋ค๋ฉด, ์์ด์ ํฑ RAG๋ ๋ค๋ฆ ๋๋ค.
"์์ด์ ํธ๋ ๋จผ์ ๋ฒกํฐ DB์์ ๋ฌธ์๋ฅผ ๊ฒ์(Tool 1)ํ๊ณ , ํด๋น ๋ฌธ์์ ์ ์ ์ฑ์ ์ค์ค๋ก ํ๊ฐ(LLM Brain)ํฉ๋๋ค. ๋ง์ฝ ๋ฌธ์๊ฐ ๋ถ์ถฉ๋ถํ๋ค๊ณ ํ๋จ๋๋ฉด, ์น ๊ฒ์(Tool 2)์ ์ถ๊ฐ๋ก ์ํํ ์ง ๊ฒฐ์ (LLM Brain)ํ ๋ค, ๋ชจ๋ ์ ๋ณด๋ฅผ ์ข ํฉํ์ฌ ์ต์ข ์๋ต์ ์์ฑ(LLM Brain)ํฉ๋๋ค."
์ด๋ฌํ ๋ณต์กํ '๊ฒฐ์ '๊ณผ 'ํ๋ฆ ์ ์ด'๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ ๊ฒ์ด ๋ฐ๋ก LangGraph์ ๋๋ค.
2. LangGraph ์ํคํ ์ฒ ์ฌ์ธต ๋ถ์ ๐๏ธ
๊ทธ๋ ๋ค๋ฉด LangGraph๋ ๊ธฐ์ ์ ์ผ๋ก ์ด๋ป๊ฒ ์ด๋ฐ ๋ณต์กํ ์์ ์ ์ฒ๋ฆฌํ ๊น์?
2.1. LangChain (LCEL) vs. LangGraph: ์ ์๋ก์ด ํ๋ ์์ํฌ๊ฐ ํ์ํ๋?
LangChain์ LCEL(LangChain Expression Language)์ ํตํด Runnable ๊ฐ์ฒด๋ค์ ํ์ดํ(|)๋ก ์ฐ๊ฒฐํ์ฌ ๋ฉ์ง ์ฒด์ธ์ ๋ง๋ค ์ ์๊ฒ ํด์ฃผ์์ต๋๋ค. ํ์ง๋ง LCEL์ ๊ทผ๋ณธ์ ์ผ๋ก DAG (Directed Acyclic Graph, ๋ฐฉํฅ์ฑ ๋น์ํ ๊ทธ๋ํ)์ ๋๋ค. ์ฆ, ๋ฐ์ดํฐ ํ๋ฆ์ด ํ ๋ฐฉํฅ์ผ๋ก๋ง ํ๋ฅด๊ณ , ์ํ(Loop)์ด๋ ๋ณต์กํ ์กฐ๊ฑด๋ถ ๋ถ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ต์ต๋๋ค.
ํ์ง๋ง ์ฐ๋ฆฌ๊ฐ ๋ง๋ค๋ ค๋ ์์ด์ ํฑ ์์คํ ์ ๋ณธ์ง์ ์ผ๋ก ์ํ์ (Cyclic)์ ๋๋ค. [์๊ฐ -> ํ๋ -> ๊ด์ฐฐ -> ๋ค์ ์๊ฐ...]ํ๋ ReAct ํจํด ์์ฒด๊ฐ ์ํ ๊ตฌ์กฐ์ ๋๋ค.
LangGraph๋ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฑ์ฅํ์ต๋๋ค. ์ด๋ฆ ๊ทธ๋๋ก '๊ทธ๋ํ(Graph)' ๊ตฌ์กฐ๋ฅผ ์ ๋ฉด์ ๋ด์ธ์๋๋ค. LCEL์ด DAG์ ๋จธ๋ฌด๋ฅธ๋ค๋ฉด, LangGraph๋ ์ํ๋ฅผ ๊ฐ์ง๋ ์ํ ๊ทธ๋ํ(Stateful Cyclic Graph)๋ฅผ ๋ง๋ค ์ ์๊ฒ ํด์ค๋๋ค.
2.2. ํต์ฌ ๊ตฌ์ฑ์์ 1: ๋ ธ๋ (Nodes) ๐ฆ
๋ ธ๋(Node)๋ ์ํฌํ๋ก์ฐ์ ๊ฐ๋ณ ์์ ๋๋ ๊ธฐ๋ฅ์ ๋ํ๋ ๋๋ค.
- LLM ํธ์ถ
- ๋ฒกํฐ DB ๊ฒ์ ๋จ๊ณ
- ์ฌ์ฉ์ ์ฟผ๋ฆฌ ์ฌ์์ฑ
- ์ค๋ฅ ์ฒ๋ฆฌ ๋ก์ง
- ์ธ๋ถ API (๋๊ตฌ) ํธ์ถ
๊ฐ ๋ ธ๋๋ Python ํจ์ ๋๋ LCEL Runnable๋ก ๊ตฌํ๋๋ฉฐ, ํน์ ์์ ์ ์ฒ๋ฆฌํ์ฌ ๋ชจ๋ํ๋๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๊ตฌ์ฑ ์์๊ฐ ๋ฉ๋๋ค.
2.3. ํต์ฌ ๊ตฌ์ฑ์์ 2: ์ฃ์ง (Edges) ๐
์ฃ์ง(Edge)๋ ๋ ธ๋ ๊ฐ์ ์ฐ๊ฒฐ์ ์ ์ํ์ฌ ์คํ ํ๋ฆ์ ๊ฒฐ์ ํฉ๋๋ค. LangGraph์ ํต์ฌ์ ์ธ ๊ฐ๋ ฅํจ์ ๋ฐ๋ก ์ด ์ฃ์ง์ ์์ต๋๋ค.
- ์ผ๋ฐ ์ฃ์ง (Direct Edges): (A, B)์ฒ๋ผ A ๋ ธ๋๊ฐ ๋๋๋ฉด ๋ฌด์กฐ๊ฑด B ๋ ธ๋๋ก ์ด๋ํ๋ ๋จ์ ์ฐ๊ฒฐ์ ๋๋ค.
- ์กฐ๊ฑด๋ถ ์ฃ์ง (Conditional Edges): (A, {condition_function})์ฒ๋ผ A ๋ ธ๋์ ์คํ ๊ฒฐ๊ณผ(์ํ)๋ฅผ ๋ฐํ์ผ๋ก, ํน์ ํจ์(condition_function)๊ฐ ๋ค์์ ์ด๋ํ ๋ ธ๋(B, C, ๋๋ D)๋ฅผ ๋์ ์ผ๋ก ๊ฒฐ์ ํฉ๋๋ค.
์ด '์กฐ๊ฑด๋ถ ์ฃ์ง' ๋๋ถ์ LLM์ ์ถ๋ ฅ์ ๋ฐํ์ผ๋ก "๋ค์์ ์ด ๋๊ตฌ๋ฅผ ์จ์ผ๊ฒ ๋ค" ๋๋ "์ด์ ์๋ต์ ์์ฑํด๋ ๋๊ฒ ๋ค"์ ๊ฐ์ ๋ณต์กํ ๋ถ๊ธฐ ๋ก์ง(branching)๊ณผ ๋ฐ๋ณต ๋ก์ง(looping)์ด ๊ฐ๋ฅํด์ง๋๋ค.
2.4. ํต์ฌ ๊ตฌ์ฑ์์ 3: ๊ณต์ ์ํ (Shared State) ๐๏ธ
LangGraph์ ๋ชจ๋ ๋ง๋ฒ์ ์ํ(State) ๊ฐ์ฒด์์ ์ผ์ด๋ฉ๋๋ค. ์ด ์ํ ๊ฐ์ฒด๋ ์์คํ ์ ์ฒด์ '๊ณต์ ๋ฉ๋ชจ๋ฆฌ' ์ญํ ์ ํฉ๋๋ค.
- ์ํ ๊ด๋ฆฌ: ๋ชจ๋ ๋ ธ๋๋ ์ด ๊ณตํต ์ํ๋ฅผ ์ฝ๊ณ (read), ์ผ๋ถ๋ฅผ ์์ ํ์ฌ(update) ๋ค์ ๋ ธ๋๋ก ์ ๋ฌํฉ๋๋ค. ์ด ๊ณต์ ์ปจํ ์คํธ(์ฌ์ฉ์ ์ฟผ๋ฆฌ, ๋ํ ๊ธฐ๋ก, ๋๊ตฌ ์ถ๋ ฅ ๋ฑ)๋ฅผ ํตํด ์ํฌํ๋ก์ฐ๊ฐ ๋์ ์ผ๋ก ๋ฐ์ ํฉ๋๋ค.
- ๊ตฌํ: ๋ณดํต Python์ TypedDict๋ Pydantic ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ํ์ ์คํค๋ง๋ฅผ ๋ช ํํ๊ฒ ์ ์ํฉ๋๋ค. ์ด ์คํค๋ง๋ ๊ทธ๋ํ์ 'ํ๊ด'์ ํ๋ฅด๋ 'ํ์ก'์ ์ฑ๋ถ์ ์ ์ํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
2.5. ํต์ฌ ๊ตฌ์ฑ์์ 4: ์ง์์ฑ (Persistence) ๐พ
๊ทธ๋ํ๊ฐ ์๋ฌด๋ฆฌ ์ ์๋ํด๋, ์๋ฒ๊ฐ ์ฌ์์๋๊ฑฐ๋ ์ฌ์ฉ์๊ฐ ๋ํ๋ฅผ ๋์ค์ ์ด์ด๊ฐ๊ณ ์ถ์ ๋ ๋งฅ๋ฝ์ด ์ฌ๋ผ์ง๋ค๋ฉด ๋ฌด์ฉ์ง๋ฌผ์ ๋๋ค.
LangGraph๋ Checkpointer๋ผ๋ ๊ฐ๋ ฅํ ์ง์์ฑ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค.
- ์ญํ : ์ํฌํ๋ก์ฐ์ '์ํ'๋ฅผ ๋งค ๋จ๊ณ๋ง๋ค (๋๋ ํน์ ๋ ธ๋ ์ดํ์) ์ธ๋ถ ์ ์ฅ์(e.g., Sqlite, Redis, PostgreSQL)์ ์ ์ฅํฉ๋๋ค.
- ์ฅ์ :
- ์ฅ๊ธฐ ์ํธ์์ฉ: ์ฌ์ฉ์๊ฐ ๋ฉฐ์น ๋ค์ ๋ค์ ์ ์ํด๋ ์ด์ ๋ํ ์ํ๋ฅผ ๊ทธ๋๋ก ๋ณต์ํ ์ ์์ต๋๋ค.
- ์ค๋ฅ ๋ณต๊ตฌ: ์ํฌํ๋ก์ฐ ์ค๊ฐ์ ํน์ ๋๊ตฌ API๊ฐ ์คํจํ๋๋ผ๋, ๋ง์ง๋ง '์ฒดํฌํฌ์ธํธ'๋ถํฐ ๋ค์ ์์ํ ์ ์์ต๋๋ค.
- Human-in-the-loop: ์ํฌํ๋ก์ฐ๋ฅผ ํน์ ์ง์ ์์ '์ผ์ ์ค์ง'์ํค๊ณ , ์ธ๊ฐ์ ์น์ธ์ ๋ฐ์ ๋ค ๋ค์ ์ด์ด๊ฐ ์ ์์ต๋๋ค.
3. LangGraph์ ์ฃผ์ ํน์ง ๋ฐ ํ์ฉ ์ฌ๋ก ๐
์ด๋ฌํ ์ํคํ ์ฒ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก LangGraph๋ ๋ช ๊ฐ์ง ๊ฐ๋ ฅํ ํน์ง์ ์ ๊ณตํฉ๋๋ค.
3.1. ๊ฐ๋ ฅํ ๋๊ตฌ ํตํฉ (Tool Integration)
์์ด์ ํธ ์์คํ ์ LLM์ด ๋ชปํ๋ ์ผ(e.g., ์ค์๊ฐ ์น ๊ฒ์, DB ์กฐํ)์ ํ๊ธฐ ์ํด ์ธ๋ถ ๋๊ตฌ์ ์์กดํฉ๋๋ค. LangGraph๋ ToolNode์ ๊ฐ์ ํฌํผ๋ฅผ ์ ๊ณตํ์ฌ ๋๊ตฌ ์ฐ๋์ ๋งค์ฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
์กฐ๊ฑด๋ถ ์ฃ์ง์ ๋๊ตฌ ํตํฉ์ด ๋ง๋๋ฉด, "LLM์ด ์ด๋ค ๋๊ตฌ๋ฅผ ์ธ์ ํธ์ถํ ์ง" ๋์ ์ผ๋ก ๊ฒฐ์ ํ๊ณ , ๋๊ตฌ ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ํ์ ๋ฐ์ํ์ฌ ๋ค์ LLM์ ํ๋จ ๊ทผ๊ฑฐ๋ก ์ฌ์ฉํ๋ ์ ๊ตํ ์ํฌํ๋ก์ฐ๊ฐ ์์ฑ๋ฉ๋๋ค.
3.2. ์ค์๊ฐ ์ฒ๋ฆฌ (Streaming) ๋ฐ ํด๋จผ์ธ๋๋ฃจํ (Human-in-the-loop) ๐
- ์ค์๊ฐ ์ฒ๋ฆฌ: LangGraph๋ ์๋ต์ ํ ํฐ ๋จ์๋ก ์คํธ๋ฆฌ๋ฐ(stream())ํ๋ ๊ฒ์ ์๋ฒฝํ๊ฒ ์ง์ํฉ๋๋ค. ์ด๋ AI๊ฐ "์๊ฐํ๊ณ ์์ ํ๋" ๊ณผ์ ์ ์ฌ์ฉ์์๊ฒ ์ค์๊ฐ์ผ๋ก ๋ณด์ฌ์ฃผ์ด UX๋ฅผ ๊ทน๋ํํฉ๋๋ค.
- ํด๋จผ์ธ๋๋ฃจํ (HITL): ํ๋ก๋์ ๋ ๋ฒจ์ ์์คํ ์์๋ AI์ ๋ชจ๋ ๊ฒฐ์ ์ ์ ๋ขฐํ ์ ์์ต๋๋ค. LangGraph๋ ์ํฌํ๋ก์ฐ์ ํน์ ๋ ธ๋ ์ /ํ(interrupt_before/interrupt_after)์ ์คํ์ '์ผ์ ์ค์ง(interrupt)'ํ๊ณ ์ธ๊ฐ์ ๊ฒํ ๋ ์น์ธ์ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ ์ ์์ต๋๋ค. (e.g., "AI๊ฐ 100๋ง ์ ์ด์ฒด๋ฅผ ์น์ธํ๋ ค ํฉ๋๋ค. ๊ด๋ฆฌ์๋, ์น์ธํ์๊ฒ ์ต๋๊น?")
3.3. ์ ๊ตํ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ (Memory Management)
์ฅ๊ธฐ์ ์ธ ์ํธ์์ฉ์์ ์ปจํ ์คํธ ์ ์ง๋ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ๋จ๊ธฐ ๋ฉ๋ชจ๋ฆฌ (Short-term): ์ํ(State) ๊ฐ์ฒด ๋ด์ messages ๋ฆฌ์คํธ ๋ฑ์ ํตํด ํ์ฌ ๋ํ์ ๋งฅ๋ฝ์ ์ถ์ ํฉ๋๋ค.
- ์ฅ๊ธฐ ๋ฉ๋ชจ๋ฆฌ (Long-term): Checkpointer๋ฅผ ํตํด ๋ํ ๊ธฐ๋ก ์ ์ฒด๋ฅผ ์ ์ฅํฉ๋๋ค. ๋์๊ฐ, Zep๊ณผ ๊ฐ์ ์ฅ๊ธฐ ๋ฉ๋ชจ๋ฆฌ ์๋ฃจ์ ์ด๋ ๋ฒกํฐ DB๋ฅผ ๋๊ตฌ๋ก ํตํฉํ์ฌ, ์์ด์ ํธ๊ฐ "์ง๋์ฃผ์ ์ฌ์ฉ์๊ฐ ์ ํธํ๋ค๊ณ ํ๋ ์คํ์ผ"์ ๊ธฐ์ตํ๊ฒ ๋ง๋ค ์๋ ์์ต๋๋ค.
4. LangGraph๋ก ์์ด์ ํธ ์์คํ ๊ตฌ์ถํ๊ธฐ (5-Step) ๐ ๏ธ
์ด๋ก ์ ์ถฉ๋ถํฉ๋๋ค. ์ด์ ์ค์ ๋ก LangGraph๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ๋ณธ์ ์ธ ์์ด์ ํธ ์์คํ ์ ๊ตฌ์ถํ๋ 5๋จ๊ณ ๊ณผ์ ์ ์ฝ๋๋ฅผ ๊ณ๋ค์ฌ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๐ฏ ๊ฐ์ ์๋๋ฆฌ์ค: "์ฌ์ฉ์ ์ง๋ฌธ์ ๋ฐ์, '๋จ์ ๋ต๋ณ'์ด ๊ฐ๋ฅํ์ง, '๋ฌธ์ ๊ฒ์'์ด ํ์ํ์ง LLM์ด ํ๋จํ๊ณ , ํ์์ ๊ฒ์ ๋๊ตฌ๋ฅผ ์คํํ ๋ค, ์ต์ข ๋ต๋ณ์ ์์ฑํ๋ RAG ์์ด์ ํธ"
4.1. 1๋จ๊ณ: ์ํฌํ๋ก์ฐ ๋ฐ ์ํ ์ ์ (State Definition)
๋จผ์ , ๊ทธ๋ํ ์ ์ฒด์์ ๊ณต์ ๋ '์ํ'์ ์คํค๋ง๋ฅผ TypedDict๋ก ์ ์ํฉ๋๋ค.
import { TypedDict, Annotated } from 'typing_extensions';
from typing import List
from langgraph.graph.message import add_messages # ๋ฉ์์ง ๊ธฐ๋ก์ ์ฝ๊ฒ ์ถ๊ฐ/๊ด๋ฆฌ
# '์ํ' ์ ์: ์ฐ๋ฆฌ ์์ด์ ํธ๊ฐ ๊ธฐ์ตํด์ผ ํ ๋ชจ๋ ๊ฒ
class AgentState(TypedDict):
# messages๊ฐ ํต์ฌ.
# Annotated(add_messages, ...)๋ ์ ๋ฉ์์ง๊ฐ ๋ค์ด์ค๋ฉด ๊ธฐ์กด ๋ฆฌ์คํธ์ '์ถ๊ฐ'ํ๋ผ๋ ์๋ฏธ
messages: Annotated[list, add_messages]
# ์ถ๊ฐ์ ์ผ๋ก ํ์ํ ์ํ๋ค
query: str # ์ฌ์ฉ์์ ์๋ณธ ์ง๋ฌธ
documents: List[str] # ๊ฒ์๋ ๋ฌธ์ ๋ชฉ๋ก
4.2. 2๋จ๊ณ: ๋ ธ๋ ๊ตฌํ (Node Implementation)
๊ฐ ์์ ๋จ๊ณ(๋ ธ๋)๋ฅผ Python ํจ์๋ก ๊ตฌํํฉ๋๋ค. ๊ฐ ํจ์๋ AgentState๋ฅผ ์ ๋ ฅ๋ฐ์, ์ฒ๋ฆฌ ํ ๋ณ๊ฒฝ๋ ์ํ๋ฅผ dict๋ก ๋ฐํํฉ๋๋ค.
from langchain_openai import ChatOpenAI
from langchain_community.vectorstores import FAISS # ์์์ฉ ๋ฒกํฐDB
from langchain_core.documents import Document
# --- ๊ฐ์์ ๋๊ตฌ(VectorDB)์ LLM ์ค์ ---
# (์ค์ ๋ก๋ embedding ๋ชจ๋ธ๊ณผ ํจ๊ป FAISS๋ฅผ ๋ฏธ๋ฆฌ ๋น๋ํด์ผ ํจ)
documents_db = FAISS.from_texts(["LangGraph๋ ๋ฉ์ง๋ค", "AI ์์ด์ ํธ๋ ์ ์ฉํ๋ค"], ...)
retriever = documents_db.as_retriever()
llm = ChatOpenAI(model="gpt-4o")
# --- ๋
ธ๋ 1: ์ฌ์ฉ์ ์ง๋ฌธ์ ์ํ์ ์ ์ฅ (Entry Point) ---
def start_node(state: AgentState):
print("--- 1. ์ํฌํ๋ก์ฐ ์์ ---")
query = state['messages'][-1].content # ๋ง์ง๋ง ์ฌ์ฉ์ ๋ฉ์์ง๋ฅผ query๋ก
return {"query": query}
# --- ๋
ธ๋ 2: ๋ฌธ์ ๊ฒ์ (๋๊ตฌ) ---
def retrieve_node(state: AgentState):
print("--- 2. ๋ฌธ์ ๊ฒ์ ์ค... ---")
query = state['query']
documents = retriever.invoke(query) # ์ค์ ๊ฒ์ ์คํ
doc_texts = [doc.page_content for doc in documents]
return {"documents": doc_texts}
# --- ๋
ธ๋ 3: ์ต์ข
์๋ต ์์ฑ (LLM) ---
def generate_node(state: AgentState):
print("--- 3. ์ต์ข
์๋ต ์์ฑ ์ค ---")
query = state['query']
documents = state['documents']
# ํ๋กฌํํธ ๊ตฌ์ฑ
context = "\n\n".join(documents)
prompt = f"๋ฌธ์: {context}\n\n์ง๋ฌธ: {query}\n\n์ ๋ฌธ์๋ฅผ ๋ฐํ์ผ๋ก ์ง๋ฌธ์ ๋ต๋ณํ์ธ์."
response = llm.invoke(prompt)
return {"messages": [("ai", response.content)]} # AI ์๋ต์ messages์ ์ถ๊ฐ
# --- ๋
ธ๋ 4: ๋จ์ ์๋ต ์์ฑ (LLM) ---
def fallback_node(state: AgentState):
print("--- 3a. ๋จ์ ์๋ต ์์ฑ ์ค (๊ฒ์ ๋ถํ์) ---")
query = state['query']
prompt = f"์ง๋ฌธ: {query}\n\n๊ฒ์ ์์ด, ์ผ๋ฐ์ ์ธ ์ง์์ผ๋ก ๋ต๋ณํ์ธ์."
response = llm.invoke(prompt)
return {"messages": [("ai", response.content)]}
4.3. 3๋จ๊ณ: ๊ทธ๋ํ ๊ตฌ์ฑ ๋ฐ ์ฃ์ง ์ฐ๊ฒฐ (Graph & Edges)
์ด์ StateGraph๋ฅผ ๋ง๋ค๊ณ , ๋ ธ๋์ ์ฃ์ง๋ฅผ ์ฐ๊ฒฐํฉ๋๋ค. ์ฌ๊ธฐ์ '์กฐ๊ฑด๋ถ ์ฃ์ง'๊ฐ ๋น์ ๋ฐํฉ๋๋ค.
from langgraph.graph import StateGraph, END
# --- ์กฐ๊ฑด๋ถ ์ฃ์ง์ฉ ํจ์ (LLM์ด ๊ฒฐ์ ) ---
def router_node(state: AgentState):
print("--- 1a. ๋ผ์ฐํ
: ๊ฒ์์ด ํ์ํ๊ฐ? ---")
query = state['query']
# (๊ฐ๋จํ ์์: ์ค์ ๋ก๋ ๋ ์ ๊ตํ LLM ํธ์ถ๋ก ํ๋จ)
if "langgraph" in query.lower() or "์์ด์ ํธ" in query.lower():
print("-> [๊ฒฐ์ ] ๊ฒ์ ํ์")
return "retrieve" # retrieve_node๋ก ์ด๋
else:
print("-> [๊ฒฐ์ ] ๋จ์ ์๋ต")
return "fallback" # fallback_node๋ก ์ด๋
# --- ๊ทธ๋ํ ๋น๋ ์์ ---
workflow = StateGraph(AgentState)
# 1. ๋
ธ๋ ์ถ๊ฐ
workflow.add_node("start", start_node)
workflow.add_node("router", router_node)
workflow.add_node("retriever", retrieve_node)
workflow.add_node("generator", generate_node)
workflow.add_node("fallback", fallback_node)
# 2. ์ฃ์ง ์ฐ๊ฒฐ
workflow.set_entry_point("start") # ์์์
workflow.add_edge("start", "router") # ์์ -> ๋ผ์ฐํฐ
# 3. **ํต์ฌ: ์กฐ๊ฑด๋ถ ์ฃ์ง**
# router ๋
ธ๋์ ๋ฐํ๊ฐ("retrieve" ๋๋ "fallback")์ ๋ฐ๋ผ ๋ค์ ๋
ธ๋๋ฅผ ๊ฒฐ์
workflow.add_conditional_edges(
"router",
router_node, # router_node ํจ์๋ฅผ ๋ค์ ํธ์ถ (๋๋ ๋ณ๋ router ํจ์ ์ฌ์ฉ)
{
"retrieve": "retriever",
"fallback": "fallback"
}
)
workflow.add_edge("retriever", "generator") # ๊ฒ์ -> ์์ฑ
workflow.add_edge("generator", END) # ์์ฑ -> ์ข
๋ฃ
workflow.add_edge("fallback", END) # ๋จ์์๋ต -> ์ข
๋ฃ
4.4. 4๋จ๊ณ: ์ปดํ์ผ, ์ง์์ฑ ์ค์ ๋ฐ ์คํ (Compile & Persistence)
๊ทธ๋ํ ์ค๊ณ๋ฅผ ๋ง์ณค๋ค๋ฉด, compile()๋ก ์คํ ๊ฐ๋ฅํ ์ฑ์ ๋ง๋ญ๋๋ค. ์ด๋ Checkpointer๋ฅผ ์ค์ ํฉ๋๋ค.
from langgraph.checkpoint.sqlite import SqliteSaver
# (ํ
์คํธ๋ฅผ ์ํด ์ธ๋ฉ๋ชจ๋ฆฌ SQLite ์ฌ์ฉ)
memory = SqliteSaver.from_conn_string(":memory:")
# ์ฒดํฌํฌ์ธํฐ๋ฅผ ์ฐ๊ฒฐํ์ฌ ๊ทธ๋ํ ์ปดํ์ผ
app = workflow.compile(checkpointer=memory)
# --- ์คํ ---
# 'thread_id'๋ ๋ํ ์ธ์
์ ์๋ณํ๋ ๊ณ ์ ID
config = {"configurable": {"thread_id": "user_session_1"}}
# ์
๋ ฅ 1 (๊ฒ์ ํ์)
inputs = [("user", "LangGraph๊ฐ ๋ญ์ฃ ?")]
for event in app.stream({"messages": inputs}, config=config):
for k, v in event.items():
if "messages" in v:
print(f"๐ค AI: {v['messages'][-1].content}")
# ์
๋ ฅ 2 (๊ฒ์ ๋ถํ์. ๋์ผํ thread_id๋ก ์คํํ๋ฉด ๋ํ๊ฐ ์ด์ด์ง)
inputs_2 = [("user", "์๋
? ๋ฐ๊ฐ์")]
for event in app.stream({"messages": inputs_2}, config=config):
for k, v in event.items():
if "messages" in v:
print(f"๐ค AI: {v['messages'][-1].content}")
4.5. 5๋จ๊ณ: ํ๊ฐ, ๋๋ฒ๊น ๋ฐ ๋ฐ๋ณต (Evaluate & Iterate)
LangGraph๋ ์๊ฐํ์ ๋๋ฒ๊น ์ ์ง์ํฉ๋๋ค.
- ASCII ์๊ฐํ: app.get_graph().print_ascii()๋ฅผ ์คํํ๋ฉด ํฐ๋ฏธ๋์์ ๊ทธ๋ํ ๊ตฌ์กฐ๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
- Mermaid ์๊ฐํ: app.get_graph().draw_mermaid_png() (๋๋ draw_mermaid())๋ฅผ ์ฌ์ฉํ๋ฉด Mermaid ๋ฌธ๋ฒ์ ๋ค์ด์ด๊ทธ๋จ์ ์์ฑํ์ฌ, ์์ด์ ํธ์ ๋ณต์กํ ํ๋ฆ์ ํ๋์ ํ์ ํ ์ ์์ต๋๋ค.
5. ์ค๋ฌด์ ๊ณผ์ ์ ๋ชจ๋ฒ ์ฌ๋ก (Challenges & Best Practices) ๐
LangGraph๋ ๊ฐ๋ ฅํ์ง๋ง, ๋ชจ๋ ๊ฒ์ ํด๊ฒฐํด ์ฃผ๋ ์ํํ์ ์๋๋๋ค. ์ค๋ฌด์์ ์์ด์ ํธ๋ฅผ ์ค๊ณํ ๋ ๊ฐ๋ฐ์๋ค์ด ๊ณ ๋ คํด์ผ ํ ๊ณผ์ ๋ค์ด ์์ต๋๋ค.
5.1. ๋์ ๊ณผ์ (Challenges)
- ๋ณต์ก์ฑ๊ณผ ์ ์ด๋ ฅ์ ๊ท ํ: ์ ์ฐ์ฑ์ด ๋์์ง๋ค๋ ๊ฒ์ ๊ณง ์ํฌํ๋ก์ฐ๊ฐ ๋ณต์กํด์ง๋ค๋ ์๋ฏธ์ ๋๋ค. ๋ ธ๋์ ์ฃ์ง๊ฐ ์์ญ ๊ฐ๊ฐ ๋๋ฉด ๋๋ฒ๊น ๊ณผ ๊ด๋ฆฌ๊ฐ ์ด๋ ค์์ง๋๋ค. ๋ถํ์ํ ์ค๋ฒํค๋๋ฅผ ํผํ๊ณ ํ์ฅ์ฑ์ ์ ์งํ๋ ์ค๊ณ๊ฐ ์ค์ํฉ๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ํจ์ : ๋ํ ๊ธฐ๋ก(messages)์ด ๊ธธ์ด์ง๋ฉด, ๋งค๋ฒ LLM์ ํธ์ถํ ๋๋ง๋ค ์ ์ฒด ๊ธฐ๋ก์ ์ปจํ ์คํธ์ ํฌํจ์์ผ ๋น์ฉ์ด ์ฆ๊ฐํ๊ณ ํ ํฐ ์ ํ(Context Window)์ ๋ถ๋ชํ ์ ์์ต๋๋ค.
- ๋๊ตฌ์ ์ ๋ขฐ์ฑ: ์ธ๋ถ API๋ ๊ฒ์ ์์คํ ์ ์ธ์ ๋ ์คํจํ๊ฑฐ๋(e.g., 500 Error) ์์์น ๋ชปํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค. ์ด์ ๋ํ ๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ(Error Handling) ๋ ธ๋์ ์ฌ์๋(Retry) ๋ก์ง์ด ํ์์ ์ ๋๋ค.
5.2. ๋ชจ๋ฒ ์ฌ๋ก (Best Practices)
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ์ํํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค.
- PoC๋ก ์๊ฒ ์์ํ๋ผ: ์ฒ์๋ถํฐ ๊ฑฐ๋ํ ์์ด์ ํธ๋ฅผ ๋ง๋ค๋ ค ํ์ง ๋ง๊ณ , ํต์ฌ ๊ธฐ๋ฅ 2~3๊ฐ ๋ ธ๋๋ก ๊ตฌ์ฑ๋ ์๊ท๋ชจ ๊ฐ๋ ์ฆ๋ช (PoC) ์์ด์ ํธ๋ถํฐ ์์ํ์ฌ ๋ก์ง์ ๊ฒ์ฆํ์ธ์.
- ๋ชจ๋ํ ์ค๊ณ๋ฅผ ์ ์ฉํ๋ผ: ๊ด๋ จ ๋ ธ๋๋ค์ ๋ฌถ์ด ์๋ธ-๊ทธ๋ํ(Sub-graph)๋ก ๋ง๋ค๊ณ , ๊ทธ๋ํ๋ฅผ ์ค์ฒฉ(nesting)ํ์ฌ ๋ณต์ก์ฑ์ ๊ด๋ฆฌํ์ธ์.
- ๋ฉ๋ชจ๋ฆฌ ์์ฝ ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ผ: ๋ํ ํด์ด 10ํ๋ฅผ ๋์ด๊ฐ๋ฉด, ๋ํ ๊ธฐ๋ก์ ์์ฝํ๋ ๋ณ๋์ LLM ๋ ธ๋๋ฅผ ํธ๋ฆฌ๊ฑฐํ์ฌ ์ํ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ์ธ์.
- ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๋ผ: LangSmith๋ LangFuse์ ๊ฐ์ LLM์ต์ค ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ, ์์ด์ ํธ๊ฐ ์ด๋ค '์ํ'์์ ์ด๋ค '๊ฒฐ์ '์ ๋ด๋ฆฌ๊ณ ์ด๋ค '๋๊ตฌ'๋ฅผ ํธ์ถํ๋์ง ์ถ์ ํ๊ณ ๋๋ฒ๊น ํด์ผ ํฉ๋๋ค.
6. ๊ฒฐ๋ก : LangGraph, '์๊ฐํ๋' AI๋ฅผ ์ํ ์ฒญ์ฌ์ง ๐บ๏ธ
LangGraph๋ LLM ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ํจ๋ฌ๋ค์์ ๋ฐ๊พธ๊ณ ์์ต๋๋ค. ๊ฐ๋ฐ์๋ค์ ์ด์ ์ ํด์ง ์์(DAG)์ ๊ฐํ์ง ์๊ณ , ๋์ ์ด๊ณ , ์ํ ๊ธฐ๋ฐ์ด๋ฉฐ, ๊ฒฌ๊ณ ํ ์์ด์ ํธ ๊ธฐ๋ฐ AI ์์คํ ์ ๊ตฌ์ถํ ์ ์๊ฒ ๋์์ต๋๋ค.
๊ทธ๋ํ ๊ธฐ๋ฐ ์ํคํ ์ฒ๋ฅผ ํ์ฉํ๊ณ , ์ธ๋ถ ๋๊ตฌ๋ฅผ ํตํฉํ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ(์ํ)๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํจ์ผ๋ก์จ, LLM์ด ์ง์ ์ผ๋ก ์ํฌํ๋ก์ฐ๋ฅผ '์ฃผ๋'ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๊ณํ ์ ์์ต๋๋ค.
์ ๊ตํ RAG ์์คํ , ๊ฐ์ธํ๋ ์ฑ๋ด, ๋ณต์กํ ์ ๋ฌด ์๋ํ ์์ด์ ํธ๊น์ง. LangGraph๋ ์ฌ๋ฌ๋ถ์ AI ์ ํ๋ฆฌ์ผ์ด์ ์ ๋จ์ํ ํ๋กํ ํ์ ์์ ์ ๋ขฐํ ์ ์๋ ํ๋ก๋์ ์๋น์ค๋ก ํ์ฅํ๋ ๋ฐ ํ๋ฅญํ ๊ธฐ์ ์ ๊ธฐ๋ฐ์ ์ ๊ณตํ ๊ฒ์ ๋๋ค. ์ฐจ์ธ๋ ์์ด์ ํธ ๊ธฐ๋ฐ ์์คํ ์ ํฅํ ์ฌ์ ์ ๊ฐ๋ ฅํ ์ถ์ฒํ๋ ํ๋ ์์ํฌ์ ๋๋ค.
