단순히 텍스트만 생성하는 LLM을 넘어, 검색엔진이나 계산기 등 외부 도구를 직접 다루는 Tool Calling Agent를 구축하는 방법을 알아봅니다.
1. 도구 바인딩 (Tool Binding)
LLM은 자신이 어떤 도구를 사용할 수 있는지 스스로 알지 못합니다. 따라서 우리가 직접 사용할 수 있는 도구의 목록과 사용법을 설명해 주어야 합니다.
- @tool 데코레이터: 파이썬 함수 위에 @tool을 붙이고 Docstring("""...""")으로 설명을 적어주면, LLM이 이 함수의 용도를 이해할 수 있습니다.
- bind_tools(): 정의한 도구들을 LLM에 연결합니다.
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
@tool
def add(a: int, b: int) -> int:
"""Add two integers and return the result."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two integers and return the result."""
return a * b
tools = [add, multiply]
llm = ChatOpenAI(model='gpt-5.4-2026-03-05')
# LLM에 도구 바인딩
llm_with_tools = llm.bind_tools(tools)
# LLM이 질문을 분석하고 어떤 툴을 쓸지 결정함 (.tool_calls에 정보가 담김)
response = llm_with_tools.invoke("What is 3 * 12?")
print(response.tool_calls)
Tip: 특정 도구를 무조건 사용하게 하려면 tool_choice 파라미터를 활용해 강제할 수 있습니다.
2. 도구를 직접 실행: ToolNode
LLM이 "어떤 도구를 쓸지" 계획(tool_calls)을 세웠다면, ToolNode는 LangGraph 내에서 그 계획을 실제 코드로 실행하고 결과를 반환하는 역할을 합니다.
- 작동 방식: LLM 노드 ➔ ToolNode ➔ LLM 노드 형태의 루프로 구성됩니다.
- 조건부 라우팅: LLM의 응답에 tool_calls가 포함되어 있으면 ToolNode로 이동하고, 없으면 대화를 종료(END)하도록 설계합니다.
from langgraph.prebuilt import ToolNode
from langgraph.graph import StateGraph, START, END
# 도구 노드 생성 및 그래프에 추가
tool_node = ToolNode(tools)
graph_builder.add_node('tools', tool_node)
# 조건부 엣지: 툴 호출이 필요하면 'tools'로, 아니면 'END'로
def route_tools(state):
ai_message = state["messages"][-1]
if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
return "tools"
return END
graph_builder.add_conditional_edges("chatbot", route_tools, {"tools": "tools", END: END})
3. 알아서 생각하고 행동하는: create_react_agent
직접 노드와 엣지를 연결하는 과정이 번거롭다면, LangGraph에서 제공하는 create_react_agent를 사용할 수 있습니다. 이 함수는 ReAct(Reasoning + Acting) 패턴을 따르는 에이전트를 단 몇 줄 만에 만들어줍니다.
- 질문을 해석하고 ➔ 도구를 선택해 호출하고 ➔ 결과를 관찰한 뒤 ➔ 최종 답변을 내놓는 전체 루프를 자동으로 관리합니다.
from langgraph.prebuilt import create_react_agent
# llm과 tools만 넘겨주면 알아서 ReAct 에이전트 생성
agent = create_react_agent(llm, tools)
response = agent.invoke({"messages": [{"role": "user", "content": "What is LangGraph?"}]})
4. 구조화된 출력 (Structured Output)
LLM의 답변을 단순한 줄글이 아니라, 데이터베이스에 넣기 좋게 JSON이나 특정 객체 형태로 받고 싶을 때 사용합니다. Pydantic을 사용해 원하는 형식을 정의합니다.
- with_structured_output(): 모델이 반드시 지정된 Pydantic 모델의 형식에 맞춰 답변을 생성하도록 강제합니다.
from pydantic import BaseModel, Field
# 1. 원하는 출력 형태 정의
class MovieResponse(BaseModel):
title: str = Field(description="영화 제목")
director: str = Field(description="감독 이름")
genre: str = Field(description="장르")
release_year: int = Field(description="개봉 연도")
# 2. 모델에 출력 형식 바인딩
model_with_structured_output = llm.with_structured_output(MovieResponse)
# 3. 실행 결과는 MovieResponse 객체 형태로 반환됨
response = model_with_structured_output.invoke("메멘토 영화에 대해 설명해주세요")
print(response.title, response.director)
5. 논문 검색을 위한 도구: arXiv API
AI 에이전트에게 전문적인 학술 자료 검색 능력을 부여하고 싶다면 arxiv 라이브러리를 도구로 활용할 수 있습니다. arXiv는 출판 전 논문(프리프린트)을 무료로 공개하는 플랫폼으로, 머신러닝이나 자연어 처리 분야의 최신 논문을 찾기 좋습니다.
# !pip install arxiv
from langchain_community.utilities import ArxivAPIWrapper
arxiv = ArxivAPIWrapper()
# 논문 ID로 검색
docs = arxiv.run("1706.03762")
# 키워드로 검색 (이 기능을 에이전트의 툴로 제공하면 유용합니다)
docs = arxiv.run('transformer attention')
'개념 정리 step2 > AI Agent' 카테고리의 다른 글
| [RAG 시스템 구축] 벡터 데이터베이스, 환경 여부 평가, 코드 설정 (2) (0) | 2026.04.01 |
|---|---|
| [RAG 시스템 구축] 벡터 데이터베이스부터 앙상블 리트리버까지 (1) (0) | 2026.03.31 |
| [AI Agent] "Tool Calling Agent의 개념"과 "Tavily"를 활용한 웹 검색 챗봇 구현 (4) (0) | 2026.03.20 |
| [LangGraph] 상태 업데이트 및 워크플로우 제어 (3) (0) | 2026.03.19 |
| [AI Agent] 랭체인과 랭그래프 핵심 정리 및 구현 (2) (0) | 2026.03.18 |
