인공지능 개발자 수다(유튜브 바로가기) 자세히보기

자연어처리/LangGraph

[LangGraph] 모델(Model)과 툴(tool)

Suda_777 2025. 8. 10. 19:02

목차

    반응형

    langgraph 버전: 0.6.4

    내용 출처 : LangGrapn Docs

     

    LangGraph

    LangGraph Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents. Get started Install LangGr

    langchain-ai.github.io

     

    1. 개요

    LangGraph는 단순히 LLM을 호출하는 프레임워크가 아니라, LLM과 다양한 도구(Tool)를 결합해 복잡한 작업을 자동화할 수 있는 워크플로우 엔진입니다.

    여기서 말하는 모델(Model)은 GPT나 Claude, LLaMA 같은 대형 언어 모델이고, 툴(Tool)은 모델이 직접 처리하기 어려운 특정 기능(예: 웹 검색, 데이터 변환, DB 조회 등)을 수행하는 외부 함수나 API입니다.

     

    이 글에서는

    • LangGraph에서 모델을 연결하는 방법
    • 툴을 정의하고 호출하는 방법
    • 모델과 툴을 조합해 하나의 그래프를 완성하는 방법
    • 을 차례로 살펴봅니다.

     


    2. 모델 (Model)

    2.1. 모델 개념

    LangGraph에서 모델(Model)은 LLM을 호출하는 하나의 노드로 동작합니다.

    LangGraph는 LangChain과 호환되기 때문에, LangChain에서 지원하는 대부분의 LLM 래퍼(ChatOpenAI, ChatAnthropic, ChatGroq 등)를 그대로 사용할 수 있습니다.

     

    모델은

    • 그래프의 한 단계로 배치되며, 입력 상태(State)를 받아서 모델 호출 결과를 반환
    • 다른 노드(예: 툴 호출 노드)와 자연스럽게 연결 가능
    • Streaming, temperature, max_tokens 등의 파라미터를 쉽게 조정 가능

    2.2 예시 코드

    2.2.1. Graph API

    1. State: 모델 입력(user_input)과 출력(model_output)을 담는 구조 정의
    2. 모델 생성: OpenAI GPT 모델 래퍼(ChatOpenAI) 사용
    3. 노드 함수: 입력 상태에서 user_input을 꺼내 모델 호출, 결과를 model_output에 저장
    4. 그래프 연결: 단일 모델 노드 → END로 연결
    5. 실행: 입력을 주면 모델의 응답을 반환
    from typing import TypedDict
    from langgraph.graph import StateGraph, END
    from langchain_openai import ChatOpenAI
    
    # 1. 상태 정의
    class State(TypedDict):
        user_input: str
        model_output: str
    
    # 2. 모델 객체 생성
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    
    # 3. 모델 노드 함수 정의
    def call_model(state: State):
        response = llm.invoke(state["user_input"])
        return {"model_output": response.content}
    
    # 4. 그래프 생성 및 노드 등록
    graph = StateGraph(State)
    graph.add_node("model_node", call_model)
    graph.set_entry_point("model_node")
    graph.add_edge("model_node", END)
    
    # 5. 그래프 컴파일
    app = graph.compile()
    
    # 6. 실행
    result = app.invoke({"user_input": "What's the capital of France?"})
    print(result)

     

    2.2.1. Function API

    • Functional API에서는 add_node()add_edge() 없이, 함수 안에서 모델 호출 로직을 작성
    • 단순 직렬 처리일 때 코드가 매우 간결
    from langgraph.func import entrypoint
    from langchain_openai import ChatOpenAI
    
    # 모델 객체 생성
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    
    @entrypoint()
    def workflow(state: dict):
        response = llm.invoke(state["user_input"])
        return {"model_output": response.content}
    
    # 실행
    output = workflow.invoke({"user_input": "What's the capital of France?"})
    print(output)

     


    3. 툴 (Tool)

    3.1. 툴 개념

    LangGraph에서 툴(Tool)은 LLM이 직접 처리하기 어려운 작업을 대신 수행하는 외부 기능입니다.

    툴은 주로 다음과 같은 형태로 사용됩니다.

    • API 호출 (날씨, 뉴스, 검색 등)
    • 데이터 변환 및 분석 (JSON 파싱, 수치 계산 등)
    • 파일 입출력 또는 DB 연동

     

    LangGraph는 LangChain의 Tool 개념과 호환되기 때문에, LangChain의 @tool 데코레이터나 StructuredTool 클래스를 그대로 활용할 수 있습니다.

     


    3.2. 툴 정의 / 등록하기

    3.2.1. Graph API 예시

    아래 예시는 간단한 덧셈 함수를 툴로 정의하는 방법입니다.

     

    @tool 테코레이터를 사용합니다.

    이렇게 정의하면, 툴은 함수이지만 LangGraph에선 노드처럼 등록해서 사용할 수 있습니다.

    from typing import TypedDict
    from langgraph.graph import StateGraph, END
    from langchain_core.tools import tool
    
    # 상태 정의
    class State(TypedDict):
        a: int
        b: int
        sum_result: str
    
    # 툴 정의
    @tool
    def add_numbers(a: int, b: int) -> str:
        """두 숫자를 더합니다."""
        return str(a + b)
    
    # 데코레이터로 노드 함수 정의
    def call_tool(state: State) -> State:
        result = add_numbers.invoke({"a": state["a"], "b": state["b"]})
        return {"sum_result": result}
    
    # 그래프 생성 및 구성
    graph = StateGraph(State)
    graph.add_node("sum_tool", call_tool)
    graph.set_entry_point("sum_tool")
    graph.add_edge("sum_tool", END)
    
    app = graph.compile()
    
    # 실행
    out = app.invoke({"a": 5, "b": 7})
    print(out)

     

    3.2.2. Functional API 예시

    from langgraph.func import entrypoint
    from langchain_core.tools import tool
    
    # 툴 정의
    @tool
    def add_numbers(a: int, b: int) -> str:
        """두 숫자를 더합니다."""
        return str(a + b)
    
    @entrypoint()
    def workflow(state: dict):
        result = add_numbers.invoke({"a": state["a"], "b": state["b"]})
        return {"sum_result": result}
    
    # 실행
    output = workflow.invoke({"a": 10, "b": 20})
    print(output)

     

     


    4. 모델 + 툴 통합

    4.1. 설명

    LangGraph에서 모델과 툴을 결합하면, LLM이 자연어 입력을 이해하고, 필요한 경우 외부 작업을 실행한 뒤, 그 결과를 활용해 응답을 만들 수 있습니다.

     

    대표적인 패턴은 다음과 같습니다.

     

    1.모델 분석 노드

    사용자의 입력을 해석하고 어떤 툴을 호출할지 결정

    툴 호출에 필요한 매개변수를 추출

     

    2.툴 실행 노드

    모델이 결정한 툴과 파라미터로 실제 작업 수행

     

    3.응답 생성 노드

    툴 실행 결과를 바탕으로 최종 사용자 응답 작성

     


    4.2. 예시 시나리오

    사용자가 “10과 25를 더해줘”라고 말하면

    • 모델이 입력에서 두 숫자를 추출
    • add_numbers 툴을 호출해 합계를 구함
    • 결과를 자연어로 포맷해 반환
    from typing import TypedDict
    from langgraph.graph import StateGraph, END
    from langchain_openai import ChatOpenAI
    from langchain_core.tools import tool
    from pydantic import BaseModel, Field
    from langchain_core.prompts import ChatPromptTemplate
    
    # 상태 정의
    class State(TypedDict):
        user_input: str
        a: int
        b: int
        sum_result: str
        final_answer: str
    
    # 툴 정의
    @tool
    def add_numbers(a: int, b: int) -> str:
        """두 숫자를 더합니다."""
        return str(a + b)
    
    # 모델 준비
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    
    # 1. 모델 분석 노드
    class Numbers(BaseModel):
        a: int = Field(..., description="first integer")
        b: int = Field(..., description="second integer")
    
    extract_chain = (
        ChatPromptTemplate.from_messages([
            ("system", "Extract exactly two integers from the user's message. "
                       "Return ONLY a JSON object with keys a and b."),
            ("human", "{text}")
        ])
        | llm.with_structured_output(Numbers)  # 모델이 Numbers 스키마에 맞춰 반환
    )
    
    def parse_request(state: State):
        parsed: Numbers = extract_chain.invoke({"text": state["user_input"]})
        return {"a": parsed.a, "b": parsed.b}
    
    # 2. 툴 실행 노드
    def run_tool(state: State) -> State:
        result = add_numbers.invoke({"a": state["a"], "b": state["b"]})
        return {"sum_result": result}
    
    # 3. 응답 생성 노드
    def create_answer(state: State) -> State:
        answer_prompt = f"The sum of {state['a']} and {state['b']} is {state['sum_result']}."
        return {"final_answer": answer_prompt}
    
    # 그래프 생성
    graph = StateGraph(State)
    graph.add_node("parse_request", parse_request)
    graph.add_node("run_tool", run_tool)
    graph.add_node("create_answer", create_answer)
    
    graph.set_entry_point("parse_request")
    graph.add_edge("parse_request", "run_tool")
    graph.add_edge("run_tool", "create_answer")
    graph.add_edge("create_answer", END)
    
    # 실행
    app = graph.compile()
    result = app.invoke({"user_input": "10과 25를 더해줘"})
    print(result["final_answer"])

     

     


    5. 코드

    https://colab.research.google.com/drive/15nLfPA6VYIxdHdKfIO3lmYpNqb60pXUH?usp=sharing

     

    [LangGraph] 모델(Model)과 툴(tool).ipynb

    Colab notebook

    colab.research.google.com

     

    반응형