λκ·Έλν(LangGraph)λ‘ λ§λλ μν κΈ°λ° AI μν¬νλ‘ κ°λ° κ°μ΄λ
λκ·Έλν(LangGraph)λ‘ λ§λλ μν κΈ°λ° AI μν¬νλ‘ κ°λ° κ°μ΄λ κ°λ°νλ€ λ³΄λ©΄ μ΄λ° μκ°μ΄ μ΅λλ€. βλνλ μ λλλ°, μ¬λ¬...
λκ·Έλν(LangGraph)λ‘ λ§λλ μν κΈ°λ° AI μν¬νλ‘ κ°λ° κ°μ΄λ
κ°λ°νλ€ λ³΄λ©΄ μ΄λ° μκ°μ΄ μ΅λλ€. βλνλ μ λλλ°, μ¬λ¬ λ¨κ³ μμ (κ²μβμ 리βκ²μ¦βμ¬μλ)μ μμ μ μΌλ‘ κ΅΄λ¦¬λ €λ©΄ μ΄λ»κ² νμ§?β ν둬ννΈλ§μΌλ‘λ νλ¦μ΄ μκΎΈ νλ€λ¦¬κ³ , μμΈ μ²λ¦¬λ μ΄λ ΅μ£ . μ΄λ΄ λ λκ·Έλνλ μν(state)μ κ·Έλν κ΅¬μ‘°λ‘ AI μμ μ λμ 보μ΄λ νλ¦μΌλ‘ λ§λ€ μ μκ² λμμ€λλ€.
λκ·Έλνλ 무μμΈκ°
λκ·Έλνλ LLM κΈ°λ° μ ν리μΌμ΄μ μ λ Έλ(node)μ μ£μ§(edge)λ‘ μ°κ²°ν΄, βμ΄λ€ μμλ‘ μ΄λ€ μμ μ μνν μ§βλ₯Ό κ·Έλν ννλ‘ κ΅¬μ±νλ λ°©μμ λλ€. ν΅μ¬μ λ€μ λ κ°μ§μμ.
- μν(State): μν¬νλ‘κ° κ³΅μ νλ λ°μ΄ν°(μ¬μ©μ μ λ ₯, μ€κ° κ²°κ³Ό, μ΅μ’ λ΅ λ±)
- 쑰건 λΆκΈ°(Conditional routing): κ²°κ³Όμ λ°λΌ λ€μ λ Έλλ₯Ό μ ν(μ: βκ²μ¦ μ€ν¨λ©΄ μ¬μλβ) μ¦, λ¨μ 체μΈλ³΄λ€ 볡μ‘ν νλ¦μ ν¨μ¬ μμ μ μΌλ‘ λ€λ£° μ μμ΅λλ€.
μΈμ λκ·Έλνκ° νΉν μ μ©ν κΉ
1) βκ²μ¦ β μ¬μλβκ° νμν κ°λ° κΈ°λ₯
μλ₯Ό λ€μ΄ μ½λ μμ± ν ν μ€νΈ/κ·μΉ κ²μ¬λ₯Ό λλ¦¬κ³ μ€ν¨νλ©΄ λ€μ μμ±νλλ‘ λ§λ€ λμ.
2) λꡬ νΈμΆμ΄ μμΈ λ€λ¨κ³ μμ
- μμ½ λ Έλ β κ²μ/DB μ‘°ν λ Έλ β μ 리 λ Έλ β μ΅μ’ λ΅λ³ λ Έλ μ΄λ° μμΌλ‘ μ± μμ μͺΌκ°λ©΄ λλ²κΉ μ΄ μ¬μμ§λλ€.
3) μ¬μ©μ λνλ₯Ό βνλ¦βμΌλ‘ κ΄λ¦¬νκ³ μΆμ λ
μλ΄λ΄μ²λΌ βμ λ³΄κ° μΆ©λΆνμ§ νμΈ β λΆμ‘±νλ©΄ μΆκ° μ§λ¬Έβ κ°μ ꡬ쑰μ κ°ν©λλ€.
κΈ°λ³Έ ꡬμ±: μν, λ Έλ, λΌμ°ν
μλ μμλ βμμ²μ λΆμ β μ΄μ μμ± β κ°λ¨ κ²μ¦ β ν΅κ³Όλ©΄ μ’ λ£/μ€ν¨λ©΄ μ¬μμ±β νλ¦μ λλ€. (λΌμ΄λΈλ¬λ¦¬ λ²μ μ λ°λΌ APIκ° μ‘°κΈμ© λ€λ₯Ό μ μμ΄, μ€ν νκ²½μ λ§κ² ν¨μλͺ μ μ‘°μ νμΈμ.)
from typing import TypedDict, Optional
# μν μ μ: κ·Έλν μ μ²΄κ° κ³΅μ νλ λ°μ΄ν°
class State(TypedDict):
user_input: str
draft: Optional[str]
is_valid: Optional[bool]
attempts: int
def analyze(state: State) -> State:
text = state["user_input"]
# κ·μΉ: μꡬμ¬νμ λ½μλ΄λ λ¨κ³λΌκ³ κ°μ
return {**state, "draft": None, "is_valid": None}
def write_draft(state: State) -> State:
# μ€μ λ‘λ LLM νΈμΆ κ²°κ³Όκ° λ€μ΄κ°λ€κ³ 보면 λ©λλ€.
draft = f"μ΄μ: {state['user_input']}μ λν λ΅λ³μ μμ±νμ΅λλ€."
return {**state, "draft": draft, "attempts": state["attempts"] + 1}
def validate(state: State) -> State:
draft = state["draft"] or ""
# μμ κ²μ¦: κΈΈμ΄κ° λ무 μ§§μΌλ©΄ μ€ν¨ μ²λ¦¬
is_valid = len(draft) > 20
return {**state, "is_valid": is_valid}
def route(state: State) -> str:
state[]:
state[] >= :
μ΄ κ΅¬μ‘°μ μ₯μ μ μ€ν¨λ₯Ό μ μ λ‘ μ€κ³ν μ μλ€λ μ μ λλ€. βν λ²μ μ λλ©΄ μ’κ³ , μλλ©΄ μμ νκ² λ€μ λλ¦°λ€βκ° μ½λ λ 벨μμ μμ°μ€λ½κ² ννλΌμ.
μ€μ ν: κ°λ°μκ° λ°λ‘ 체κ°νλ ν¬μΈνΈ
1) μνλ βμ΅μ 곡μ , μ΅λ λͺ νβ
μνμ λ무 λ§μ κ°μ λ£μΌλ©΄ μ΄λ λ Έλκ° λ¬΄μμ λ°κΎΈλμ§ μΆμ μ΄ μ΄λ €μμ§λλ€. draft, sources, errors, attemptsμ²λΌ μν μ΄ λΆλͺ ν νλλ§ λμΈμ.
2) λ Έλλ μκ², μ± μμ νλμ©
- βμ΄μ μμ±βκ³Ό βνμ λ§μΆκΈ°βλ₯Ό ν λ Έλμ λͺ°μλ£μΌλ©΄ μμ μ΄ νλλλ€. λ Έλλ₯Ό μͺΌκ°λ©΄ λμ€μ νΉμ λ¨κ³λ§ κ΅μ²΄νκΈ° μ½μ΅λλ€.
3) λΌμ°ν 쑰건μ λ‘κ·Έλ‘ λ¨κΈ°κΈ°
λΆκΈ° κΈ°μ€μ΄ 볡μ‘ν΄μ§μλ‘ βμ μ΄μͺ½μΌλ‘ κ°μ§?βκ° λΉλ²ν΄μ§λλ€. λΌμ°ν ν¨μμμ 쑰건 νλ¨ κ·Όκ±°(is_valid, attempts λ±)λ₯Ό κΈ°λ‘νλ©΄ λλ²κΉ μκ°μ΄ ν μ€μ΄μ.
κ°λ¨ν μ μ© μλ리μ€: κ°λ° λ¬Έμ μμ±κΈ°
κ°λ°νμμ νν μꡬλ₯Ό μλ‘ λ€μ΄λ³Όκ²μ.
- μꡬμ¬ν μ λ ₯(κΈ°λ₯ μ€λͺ , μ μ½, API μ€ν)
- μ΄μ μμ±
- κ·μΉ κ²μ¬: νμ μΉμ (κ°μ/μ μΆλ ₯/μλ¬/μμ ) λλ½ μ¬λΆ νμΈ
- λλ½ μ λ³΄κ° μ§λ¬Έ μμ± λλ μ΄μ 보κ°
- ν΅κ³Όνλ©΄ μ΅μ’ λ¬Έμ μΆλ ₯ μ΄κ±Έ 체μΈμΌλ‘ λ§λ€λ©΄ μ€κ°μ λΉ μ§ μ λ³΄κ° μμ΄λ κ·Έλλ‘ νλ¬κ° λ²λ¦¬λλ°, λκ·Έλν μ€νμΌμ΄λ©΄ λλ½μ κ°μ§νκ³ λ€μ 묻λ νλ¦μ ꡬ쑰μ μΌλ‘ λ£μ μ μμ΅λλ€.
λ§λ¬΄λ¦¬: λκ·Έλνλ₯Ό μμν λμ νμ€μ μΈ ν μ€ μ‘°μΈ
μ²μλΆν° κ±°λν κ·Έλνλ₯Ό λ§λ€κΈ°λ³΄λ€, βκ²μ¦ β μ¬μλβ ν κ°μ§ νλ¦λ§ λ£μ΄λ 체κ°μ΄ ν½λλ€. κ°λ°μ κ²°κ΅ μμΈμ μ€ν¨λ₯Ό λ€λ£¨λ μΌμ΄κ³ , λκ·Έλνλ κ·Έ μ€ν¨λ₯Ό μ€κ³ κ°λ₯ν νλ¦μΌλ‘ λ°κΏμ£Όλ λꡬμ κ°κΉμ΅λλ€.
β¬οΈ μ΄ κΈμ΄ λμμ΄ λμ ¨λ€λ©΄, μλ κ΄κ³ λ₯Ό ν λ²λ§ ν΄λ¦ν΄μ£ΌμΈμ! μ μκ² ν° νμ΄ λ©λλ€ πββοΈ β¬οΈ