본문 바로가기
Data & Research

[LangGraph] Tool/Tool binding

by 물박사의 저장공간 2025. 11. 2.

2025.04.03 - [Data & Research] - [Langchain & Langgraph] Table of Contents


1. LangGraph의 Tool

이제 LLM은 어려운 질문도 척척 대답해주는 수준에 이르렀습니다. 그럼에도 불구하고 이상하리만큼 쉬운 질문에 대한 답을 잘 못하는 경우들도 있었는데요. 대표적인 것이 구구단 같은 단순 연산입니다. LLM은 "확률적 언어 모델"입니다. 좀 더 단순하게 표현해보면 "이전 단어들이 주어졌을 때 다음에 나올 가능성이 가장 높은 토큰은 무엇인가?"를 학습하는 것이지요. 그 전에 자주 봐왔던 패턴을 기반으로 정보를 생성해내는 것은 잘하지만 "기호적 정확성"에는 영 젬병인 것 입니다. 

 

그렇다고 무한한 수의 곱셈 예시를 train data에 넣어줄 수 있는 것도 아니고 할 수 있다고 하더라도 엄청난 자원의 낭비일 것입니다. 그런데, 한번 더 생각해보면 이런 연산은 LLM이 등장하기 훨씬 전부터 "계산기"가 이미 잘 해주고 있었습니다. 이렇게 LLM이 내재적으로 직접 수행하기 어렵거나 가성비가 떨어지는 task경우에 이를 보조해 줄 수 있는 도구(Tool)를 달아주는 방법이 해법이 되기 시작한 겁니다. 

 

도구(Tool)만 놓고 보면 "특정 영역의 문제"에 대처하는 "특정한 기능"을 수행하는 모듈이라고 보시면 될 것 같습니다. 

 

2. LangGraph Tool Binding

Tool 함수를 langgraph.tools decorator를 이용해서 만들어줍니다. 

Tool를 불러올 것인가 하는 것은 사람이 아니라 LLM이 판단할 것이기 때문에 그 판단을 위한 정보 및 주석을 제공해주어야 합니다. 

아래 예시에서 2가지 방식으로 이 정보를 제공했는데요

1) Doctstring

"""두 수를 곱한 결과를 반환합니다.""" 와 같은 형태로 이 함수가 무엇을 하는지 알려줍니다. 애초에 Docstring은 내(인간)가 만든 코드를 다른 사람(인간)에게 이해시키기 위한 목적이었지만 Tool에서는 LLM을 이해시키기 위한 목적이 되는 것이죠. 

2) Annotated 타입 힌트

Annotated[int, "첫 번째 정수"]와 같은 형태로 각 인자가 무엇을 의미하는지 힌트를 제공합니다. Annotated가 없어도 작동하긴 하지만 복잡한 도구를 호출한다든가 함수 이름과 인자가 유사한 상황 등에서는 되도록 사용하는 것이 좋습니다. 

 

# LangGraph의 기본 tool 예시

from langchain_openai import ChatOpenAI
from langgraph.tools import tool
from langgraph.graph import Graph

# Tool 정의
@tool
def multiply(
    a: Annotated[int, "첫 번째 정수"],
    b: Annotated[int, "두 번째 정수"]
) -> int:
    """두 수를 곱한 결과를 반환합니다."""
    return a * b

@tool
def greet(name: str) -> str:
    """이름을 받아 인사 메시지를 생성합니다."""
    return f"안녕하세요, {name}님!"

# LLM 모델 생성
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 그래프 구성 (모델 + tool 연결)
graph = Graph(model=model, tools=[multiply, greet])

# 실행
result1 = graph.invoke({"input": "5와 8을 곱한 결과를 알려줘"})
result2 = graph.invoke({"input": "홍길동에게 인사해줘"})

print(result1)
print(result2)

 

또 위 예시에서 볼 수 있는 것처럼 도구가 2개 이상인 경우 list로써 전달해주면 됩니다. 

 

참고로 도구가 호출되었는지 확인하는 가장 확실하고 수학적인 방법은, LLM이 반환하는 메시지 객체(Message Object) 내부에 tool_calls 필드가 존재하는지, 그리고 그 필드가 비어있지 않은지 확인하는 것입니다.

from langchain_core.messages import AIMessage

# 가정: LLM이 반환한 응답 객체
response: AIMessage = model.invoke("오늘 날씨를 알려줘") 

# 도구 호출 발생 여부 확인
is_tool_called = bool(response.tool_calls)

if is_tool_called:
    print("도구 호출이 감지되었습니다.")
    # 호출된 도구의 이름과 인수를 확인
    for tool_call in response.tool_calls:
        print(f"   - 호출된 도구: {tool_call.name}")
        print(f"   - 전달된 인수: {tool_call.args}")
else:
    print("도구 호출 없이 최종 답변을 생성했습니다.")
    print(f"   - 답변 내용: {response.content}")

'Data & Research' 카테고리의 다른 글

[LangGraph] LangGraph에서의 Loop  (0) 2025.11.02
[LangGraph] Agent  (0) 2025.11.02
[LangGraph] Reducer  (0) 2025.11.01
[LangGraph] Graph 구성  (0) 2025.11.01
[LangGraph] GraphState  (1) 2025.10.31