๐Ÿฆœ๐Ÿ•ธ๏ธ ๋žญ๊ทธ๋ž˜ํ”„ (LangGraph): ํšจ์œจ์ ์ธ AI ์›Œํฌํ”Œ๋กœ์šฐ ๊ตฌ์ถ•

0koangยท2024๋…„ 7์›” 26์ผ
0

AI

๋ชฉ๋ก ๋ณด๊ธฐ
7/7
post-thumbnail





๐Ÿฆœ๐Ÿ•ธ๏ธ LangGraph

LangGraph๋Š” LangChain ์ƒํƒœ๊ณ„์˜ ์ผ๋ถ€๋กœ, ๋ณต์žกํ•œ AI ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ•๋ ฅํ•œ ํ”„๋ ˆ์ž„์›Œํฌ
์œ ์—ฐํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ AI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋น„๊ต์  ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ





โœ… ์ฃผ์š” ํŠน์ง•

  • ์ƒํƒœ ๊ธฐ๋ฐ˜ ๊ทธ๋ž˜ํ”„: ๋ณต์žกํ•œ ๋กœ์ง์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„
  • ์กฐ๊ฑด๋ถ€ ํ๋ฆ„: ๋™์ ์ธ ์˜์‚ฌ ๊ฒฐ์ • ํ”„๋กœ์„ธ์Šค ๊ตฌํ˜„
  • ๋ชจ๋“ˆ์„ฑ: ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ์›Œํฌํ”Œ๋กœ์šฐ ๊ตฌ์„ฑ
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ: ๋ชจ๋“ˆํ™”๋œ ๊ตฌ์กฐ๋กœ ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ ์ˆ˜์ • ์šฉ์ด
  • ํ™•์žฅ์„ฑ: ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋‚˜ ์กฐ๊ฑด์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
  • ๋””๋ฒ„๊น…: ๊ฐ ๋‹จ๊ณ„๋ณ„ ์ƒํƒœ ํ™•์ธ์ด ์šฉ์ด





โœ… ์›Œํฌํ”Œ๋กœ์šฐ ๊ตฌ์ถ• ๊ณผ์ •

  1. ์ƒํƒœ ์ •์˜
  2. ๋…ธ๋“œ (ํ•จ์ˆ˜) ์ •์˜
  3. ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ
  4. ๋…ธ๋“œ ์ถ”๊ฐ€
  5. ์—ฃ์ง€ (์—ฐ๊ฒฐ) ์ •์˜
  6. ์‹œ์ž‘์  ์„ค์ •
  7. ๊ทธ๋ž˜ํ”„ ์ปดํŒŒ์ผ





โœ… ์ƒ์„ธ ๊ตฌํ˜„ ์˜ˆ์ œ

1. ์ƒํƒœ ์ •์˜

from typing import TypedDict, Annotated, Sequence, List
from langchain_core.documents.base import Document

class AgentState(TypedDict):
    actions: str
    context: Sequence[Document]
    answer: str
    question: str
    groundness_status: str
  • AgentState๋Š” ์›Œํฌํ”Œ๋กœ์šฐ์˜ ๊ฐ ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜
  • ๊ฐ ํ•„๋“œ๋Š” ์›Œํฌํ”Œ๋กœ์šฐ์˜ ํŠน์ • ๋ถ€๋ถ„์—์„œ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋‚˜ํƒ€๋ƒ„

2. ๋…ธ๋“œ (ํ•จ์ˆ˜) ์ •์˜

  • ๊ฐ ๋…ธ๋“œ๋Š” ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ •์˜
  • ์ด ๊ธ€์—๋Š” ๋…ธ๋“œ ๊ตฌํ˜„๋ถ€ ์—†์Œ
def extract_actions(state: AgentState) -> AgentState:
    """์•ก์…˜ ์ถ”์ถœ"""
    actions = "์งˆ๋ฌธ์—์„œ ์ถ”์ถœ๋œ ์•ก์…˜๋“ค"
    return AgentState(actions=actions)

def is_exist_actions(state: AgentState) -> str:
    """์•ก์…˜ ์กด์žฌ ์—ฌ๋ถ€ ์ฒดํฌ"""
    # is_exist_actions, is_not_exist_actions
    is_exist_actions = "is_exist_actions"
    return is_exist_actions

def is_exist_docs(state: AgentState) -> str:
    """๊ฒ€์ƒ‰ ๋ฌธ์„œ ์กด์žฌ ์—ฌ๋ถ€ ์ฒดํฌ"""
    # is_exist_docs, is_not_exist_docs
    is_exist_docs = "is_exist_docs"
    return is_exist_docs

def retrieve(state: AgentState) -> AgentState:
    """๋ฌธ์„œ ๊ฒ€์ƒ‰"""
    docs = [Document(page_content="๊ฒ€์ƒ‰๋œ ๋ฌธ์„œ 1"), Document(page_content="๊ฒ€์ƒ‰๋œ ๋ฌธ์„œ 2")]
    return AgentState(context=docs)

def invoke_llm_with_context(state: AgentState) -> AgentState:
    """context์™€ ํ•จ๊ป˜ LLM ํ˜ธ์ถœ"""
    answer = "LLM ๋‹ต๋ณ€"
    return AgentState(answer=answer)

def invoke_llm(state: AgentState) -> AgentState:
    """LLM ํ˜ธ์ถœ"""
    answer = "LLM ๋‹ต๋ณ€"
    return AgentState(answer=answer)
    
def check_groundedness(state: AgentState) -> AgentState:
    """๊ฒ€์ƒ‰ ๋ฌธ์„œ์™€ LLM ๋‹ต๋ณ€์˜ ์ ํ•ฉ์„ฑ ํ™•์ธ"""
    # grounded, notGrounded, notSure
    groundness_status = "grounded" 
    return AgentState(groundness_status=groundness_status)
    
def judgement(state: AgentState) -> str:
    """๋…ธ๋“œ ์žฌํ˜ธ์ถœ ํ˜น์€ ์ข…๋ฃŒ ํŒ๋‹จ"""
    # retry_retrieve, retry_invoke_llm_with_context, END
    judgement = END 
    return judgement

3. ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ

from langgraph.graph import StateGraph

workflow = StateGraph(AgentState)

4. ๋…ธ๋“œ ์ถ”๊ฐ€

workflow.add_node("extract_actions", extract_actions)
workflow.add_node("retrieve", retrieve)
workflow.add_node("invoke_llm", invoke_llm)
workflow.add_node("invoke_llm_with_context", invoke_llm_with_context)
workflow.add_node("check_groundedness", check_groundedness)

5. ์—ฃ์ง€ (์—ฐ๊ฒฐ) ์ •์˜

workflow.add_conditional_edges(
    "extract_actions",
    is_exist_actions,
    {
        "is_exist_actions": "retrieve",
        "is_not_exist_actions": "invoke_llm",
    }
)
workflow.add_conditional_edges(
    "retrieve",
    is_exist_docs,
    {
        "is_exist_docs": "invoke_llm_with_context",
        "is_not_exist_docs": "invoke_llm",
    }
)
workflow.add_edge("invoke_llm_with_context", "check_groundedness")
workflow.add_edge("invoke_llm", END)
workflow.add_conditional_edges(
    "check_groundedness",
    judgement,
    {
        "retry_retrieve": "retrieve",
        "retry_invoke_llm_with_context": "invoke_llm_with_context",
        END: END
    }
)
  • ์กฐ๊ฑด๋ถ€ ์—ฃ์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ ์ธ ํ๋ฆ„ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅ

6. ์‹œ์ž‘์  ์„ค์ •

workflow.set_entry_point("extract_actions")

7. ๊ทธ๋ž˜ํ”„ ์ปดํŒŒ์ผ

app = workflow.compile()





โœ… ์•กํ‹ฐ๋น„ํ‹ฐ ๋‹ค์ด์–ด๊ทธ๋žจ





โœ… ์‹คํ–‰๊ฒฐ๊ณผ

app.invoke(AgentState(question="๋‚ด ์งˆ๋ฌธ"))

profile
์„œ๋น„์Šค ํ•ต์‹ฌ ๊ฐ€์น˜๋ฅผ ์ดํ•ดํ•˜๊ณ , ์ง€์†์ ์ธ ๊ฐœ์„ ์„ ์ด๋„๋Š” ์—”์ง€๋‹ˆ์–ด(๋ฅผ ์ง€ํ–ฅํ•จ)

0๊ฐœ์˜ ๋Œ“๊ธ€