1. Tool Calling Agent
Tool Calling Agent는 자신이 가진 지식만 사용하는 것이 아니라, 외부 도구(API, 데이터베이스, 코드 실행기 등)를 호출해 문제를 해결하는 에이전트입니다. 사용자의 질문을 이해한 뒤 필요한 경우 적절한 툴을 선택하고, 입력값을 구성해 호출하며, 반환된 결과를 다시 가공해 최종 답변을 만듭니다. 쉽게 말해, 단순히 대화만 하는 AI가 아니라 “필요할 때 계산기, 검색엔진, 데이터 조회 도구 같은 도구를 직접 쓸 수 있는 AI”가 Tool Calling Agent입니다.

2. 웹 검색을 하는 챗봇
1. Tavily
Tavily는 웹을 실시간으로 검색해 AI가 최신·정확한 정보를 답변할 수 있도록 돕는 AI용 검색·브라우징 API 플랫폼입니다.

pip install -U tavily-python
API 키발급(https://app.tavily.com/home)
import getpass
import os
def _set_env(var: str):
if not os.environ.get(var):
os.environ[var] = getpass.getpass(f"{var}: ")
_set_env("OPENAI_API_KEY")
_set_env("TAVILY_API_KEY")
!pip install tavily-python
from tavily import TavilyClient
tavily_client = TavilyClient()
response = tavily_client.search("What is AI Agent?", max_results=3) # , topic="news", days = 10
response
- max_results=3 → 검색 결과의 최대 개수를 지정합니다. 3이므로, 검색 결과를 최대 3개까지 가져옵니다.
- topic="news" → 뉴스 기사 위주로 검색
- days=10 → 최근 10일 이내의 자료만 검색
response['results']
# get_search_context: 보통 문자열(string) 형태이며, 여러 개의 검색 결과에서 중요한 내용만 추려서 한 덩어리의 텍스트로 제공합니다.
context = tavily_client.get_search_context(query="What is AI Agent?")
context
# qna_search: Tavily가 반환한 최종 답변. 보통 문자열(string) 형태이며, 한두 문장 정도로 정리된 응답을 제공합니다.
answer = tavily_client.qna_search(query="What is AI Agent?")
answer
2. TavilySearch
파라미터 :
- max_results (optional, int): 검색 결과 반환 수
- topic (optional, str): 검색 카테고리 / "general"(Default), "news", "finance"
- include_answer (optional, bool): 쿼리에 대한 답변 포함 여부
- include_raw_content (optional, bool): 결과 HTML 포함 여부
- include_images (optional, bool): 쿼리 관련 이미지 목록 포함 여부
- include_image_descriptions (optional, bool): 각 이미지에 대한 설명 텍스트 포함 여부
- search_depth (optional, str): 검색 깊이 / "basic"(Default),"advanced"
- time_range (optional, str): 필터링 날짜 범위 - "day", "week", "month", "year"
- include_domains (optional, List[str]): 구체적으로 포함할 도메인 목록
- exclude_domains (optional, List[str]): 구체적으로 제외할 도메인 목록
!pip install langchain_tavily
from langchain_tavily import TavilySearch
tool = TavilySearch(max_results=3)
tool.invoke("What's a 'node' in LangGraph?")
invoke_with_toolcall = tool.invoke({"args": {'query': "What's a 'node' in LangGraph?"}, "type": "tool_call", "id": "foo", "name": "tavily_search"})
invoke_with_toolcall
- .invoke()는 LangChain Tool 호출 형식으로 입력을 받을 수 있습니다.
- 단순 문자열을 넣는 대신, JSON(딕셔너리) 구조로 툴 호출 이벤트(tool call event)처럼 전달하는 방식입니다.
invoke_with_toolcall.content
!pip install langchain_community
from langchain_community.tools.tavily_search import TavilySearchResults
tool = TavilySearchResults(max_results=2)
tool.invoke("What's a 'node' in LangGraph?")

invoke_with_toolcall = tool.invoke({"args": {'query': "What's a 'node' in LangGraph?"}, "type": "tool_call", "id": "foo", "name": "tavily"})
invoke_with_toolcall
# results에 들어 있는 정보
invoke_with_toolcall.content
# 모델의 모든 실행결과
invoke_with_toolcall.artifact
3. 도구 바인딩
from langchain_core.tools import tool
@tool
def add(a: int, b: int) -> int:
return a + b
@tool
def multiply(a: int, b: int) -> int:
return a * b
tools = [add, multiply]
!pip install langchain_openai
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-5-nano") # model="gpt-4o"
llm_with_tools = llm.bind_tools(tools)
query = "What is 3 * 12? Also, what is 11 + 49?"
llm_with_tools.invoke(query).tool_calls
query = "What is 12 % 2?"
llm_with_tools.invoke(query).tool_calls
llm_with_tools = llm.bind_tools(tools,
tool_choice={"type": "function", "function": {"name": "multiply"}}
)
resp = llm_with_tools.invoke("What is 3 * 12? Use tool.")
print(resp.tool_calls) # 이제 비어있지 않음
from langchain_openai import ChatOpenAI
tool = TavilySearch(max_results=2)
tools = [tool]
llm = ChatOpenAI(model="gpt-5-nano")
llm_with_tools = llm.bind_tools(tools) # TavilySearch(tools) 을 호출할 수 있도록 함
llm_with_tools.invoke("안녕")
llm_with_tools.invoke("What is Langgraph?")
llm_with_tools.invoke("What is Langgraph?").tool_calls
!pip install langgraph
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]} # 일반적인 질문에 대한 일반 답변 or tool_calls
graph_builder.add_node("chatbot", chatbot)
4. ToolNode
ToolNode는 LangGraph에서 도구 호출을 실제로 실행해 주는 노드입니다. LLM이 생성한 AIMessage.tool_calls를 읽어 각 호출의 도구 이름과 인자를 매칭해 실행하고, 결과를 ToolMessage로 반환하여 그래프의 상태(대화 기록)에 추가합니다. 보통 “LLM 노드 → ToolNode → LLM 노드” 형태의 루프에서 사용되며, tools_condition 같은 조건부 엣지와 함께 붙여 LLM이 도구를 요청할 때만 ToolNode가 동작하게 합니다. 요약하면, ToolNode는 LLM의 툴 호출 계획을 실제 코드 실행으로 연결하는 브리지로, 도구 레지스트리(이름→함수/툴)만 넘겨주면 호출·에러 처리·결과 전달까지 표준화된 방식으로 처리해줍니다.
import json
from langchain_core.messages import ToolMessage
from langgraph.prebuilt import ToolNode
class BasicToolNode:
def __init__(self, tools: list) -> None:
self.tools_by_name = {tool.name: tool for tool in tools} # ["tavily_search" : TavilySearch()]
def __call__(self, inputs: dict):
if messages := inputs.get("messages", []):
message = messages[-1] # 마지막 message
else:
raise ValueError("No message found in input")
outputs = []
for tool_call in message.tool_calls: # 메시지에서 호출된 도구를 불러옴
tool_result = self.tools_by_name[tool_call["name"]].invoke( # Tool 호출 실행
tool_call["args"]
)
outputs.append( # Tool 호출 결과(ToolMessage) 추가
ToolMessage(
content=json.dumps(tool_result),
name=tool_call["name"],
tool_call_id=tool_call["id"],
)
)
return {"messages": outputs}
tool_node = BasicToolNode(tools=[tool])
# tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
def route_tools(
state: State,
):
if isinstance(state, list):
ai_message = state[-1]
elif messages := state.get("messages", []):
ai_message = messages[-1]
else:
raise ValueError(f"No messages found in input state to tool_edge: {state}")
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},
)
# 엣지 연결
graph_builder.add_edge("tools", "chatbot") # 도구가 호출될 때마다 챗봇으로 돌아가 다음 단계를 결정
graph_builder.add_edge(START, "chatbot")
graph = graph_builder.compile()
graph
def stream_graph_updates(user_input: str):
for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}): # graph 노드 호출 결과 받아옴
for value in event.values():
print("Assistant:", value["messages"][-1].content) # AI 답변 출력
while True:
try:
user_input = input("User: ")
print("User:", user_input)
if user_input.lower() in ["quit", "exit", "q"]:
print("Goodbye!")
break
stream_graph_updates(user_input)
except:
user_input = "What do you know about LangGraph?"
print("User: " + user_input)
stream_graph_updates(user_input)
break
5. create_react_agent
create_react_agent는 LangChain에서 ReAct 패턴(Reason+Act)을 따르는 에이전트를 손쉽게 구성하는 팩토리로, LLM과 사용할 도구 목록, 그리고 적절한 프롬프트를 결합해 “생각→도구 호출→관찰→최종 답변”의 반복 루프를 수행하는 Agent 객체를 만들어줍니다. 이 에이전트는 질문을 해석해 필요한 도구를 선택하고 인자를 구성해 호출한 뒤, 결과를 반영해 다음 행동을 결정하며, 보통 AgentExecutor와 함께 실행하여 다단계 추론과 복수의 툴 호출을 자동으로 오케스트레이션합니다. 핵심은 프롬프트(지침), LLM, 툴 레지스트리(이름→함수/API), 출력 파서를 표준화해 붙여주는 것이며, OpenAI 스타일의 툴콜을 포함한 다양한 LLM과 호환되어 실용적인 “생각하며 도구를 쓰는” 에이전트를 빠르게 구성할 수 있게 해주는 점입니다.
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
tool = TavilySearch(max_results=2)
tools = [tool]
llm = ChatOpenAI(model="gpt-5-nano")
agent = create_react_agent(llm, tools)
response = agent.invoke({"messages": [{"role": "user", "content": "What is LangGraph?"}]})