많은 AI 애플리케이션은 자연어를 통해 사용자와 상호작용합니다. 그러나 일부 사용 사례에서는 모델이 구조화된 입력을 사용하여 API, 데이터베이스 또는 파일 시스템과 같은 외부 시스템과 직접 인터페이스해야 합니다.
Tools는 agents가 작업을 수행하기 위해 호출하는 컴포넌트입니다. Tools는 잘 정의된 입력과 출력을 통해 모델이 세상과 상호작용할 수 있도록 하여 모델의 기능을 확장합니다. Tools는 호출 가능한 함수와 그 입력 스키마를 캡슐화합니다. 이들은 호환되는 chat models에 전달될 수 있으며, 모델이 도구를 호출할지 여부와 어떤 인수를 사용할지 결정할 수 있게 합니다. 이러한 시나리오에서 tool calling은 모델이 지정된 입력 스키마에 맞는 요청을 생성할 수 있도록 합니다.
서버 사이드 tool 사용
일부 chat models(예: OpenAI, Anthropic, Gemini)은 웹 검색 및 코드 인터프리터와 같이 서버 사이드에서 실행되는 built-in tools를 제공합니다. 특정 chat model에서 이러한 도구에 액세스하는 방법을 알아보려면 provider overview를 참조하세요.
Create tools
Basic tool definition
도구를 만드는 가장 간단한 방법은 @tool 데코레이터를 사용하는 것입니다. 기본적으로 함수의 docstring이 도구의 설명이 되어 모델이 언제 사용할지 이해하는 데 도움이 됩니다:
from langchain.tools import tool
@tool
def search_database(query: str, limit: int = 10) -> str:
"""Search the customer database for records matching the query.
Args:
query: Search terms to look for
limit: Maximum number of results to return
"""
return f"Found {limit} results for '{query}'"
타입 힌트는 도구의 입력 스키마를 정의하므로 필수입니다. docstring은 모델이 도구의 목적을 이해하는 데 도움이 되도록 유익하고 간결해야 합니다.
Customize tool properties
Custom tool name
기본적으로 도구 이름은 함수 이름에서 가져옵니다. 더 설명적인 이름이 필요할 때 이를 재정의할 수 있습니다:
@tool("web_search") # Custom name
def search(query: str) -> str:
"""Search the web for information."""
return f"Results for: {query}"
print(search.name) # web_search
Custom tool description
더 명확한 모델 가이드를 위해 자동 생성된 도구 설명을 재정의할 수 있습니다:
@tool(
"calculator",
description="Performs arithmetic calculations. Use this for any math problems."
)
def calc(expression: str) -> str:
"""Evaluate mathematical expressions."""
return str(eval(expression))
Advanced schema definition
Pydantic 모델 또는 JSON 스키마를 사용하여 복잡한 입력을 정의할 수 있습니다:
Pydantic model 사용:
from pydantic import BaseModel, Field
from typing import Literal
class WeatherInput(BaseModel):
"""Input for weather queries."""
location: str = Field(
description="City name or coordinates"
)
units: Literal["celsius", "fahrenheit"] = Field(
default="celsius",
description="Temperature unit preference"
)
include_forecast: bool = Field(
default=False,
description="Include 5-day forecast"
)
@tool(args_schema=WeatherInput)
def get_weather(
location: str,
units: str = "celsius",
include_forecast: bool = False
) -> str:
"""Get current weather and optional forecast."""
temp = 22 if units == "celsius" else 72
result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
if include_forecast:
result += "\nNext 5 days: Sunny"
return result
JSON Schema
weather_schema = {
"type": "object",
"properties": {
"location": {"type": "string"},
"units": {"type": "string"},
"include_forecast": {"type": "boolean"}
},
"required": ["location", "units", "include_forecast"]
}
@tool(args_schema=weather_schema)
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
"""Get current weather and optional forecast."""
temp = 22 if units == "celsius" else 72
result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
if include_forecast:
result += "\nNext 5 days: Sunny"
return result
Accessing Context
왜 이것이 중요한가:
Tools는 agent state, runtime context, 그리고 long-term memory에 액세스할 수 있을 때 가장 강력합니다. 이를 통해 도구가 컨텍스트 인식 결정을 내리고, 응답을 개인화하며, 대화 전반에 걸쳐 정보를 유지할 수 있습니다.
도구는 ToolRuntime 매개변수를 통해 런타임 정보에 액세스할 수 있으며, 다음을 제공합니다:
- State - 실행을 통해 흐르는 가변 데이터(messages, counters, custom fields)
- Context - user ID, session details 또는 애플리케이션별 설정과 같은 불변 설정
- Store - 대화 전반에 걸친 영구적인 장기 메모리
- Stream Writer - 도구가 실행될 때 사용자 정의 업데이트 스트리밍
- Config - 실행을 위한 RunnableConfig
- Tool Call ID - 현재 도구 호출의 ID
ToolRuntime
ToolRuntime을 사용하여 단일 매개변수로 모든 런타임 정보에 액세스할 수 있습니다. 도구 시그니처에 runtime: ToolRuntime을 추가하기만 하면 LLM에 노출되지 않고 자동으로 주입됩니다.
ToolRuntime: state, context, store, streaming, config 및 tool call ID에 대한 액세스를 도구에 제공하는 통합 매개변수입니다. 이는 별도의InjectedState,InjectedStore,get_runtime및InjectedToolCallId주석을 사용하는 이전 패턴을 대체합니다.
Accessing state:
도구는 ToolRuntime을 사용하여 현재 그래프 state에 액세스할 수 있습니다:
from langchain.tools import tool, ToolRuntime
# Access the current conversation state
@tool
def summarize_conversation(runtime: ToolRuntime) -> str:
"""Summarize the conversation so far."""
messages = runtime.state["messages"]
human_msgs = sum(1 for m in messages if m.__class__.__name__ == "HumanMessage")
ai_msgs = sum(1 for m in messages if m.__class__.__name__ == "AIMessage")
tool_msgs = sum(1 for m in messages if m.__class__.__name__ == "ToolMessage")
return f"Conversation has {human_msgs} user messages, {ai_msgs} AI responses, and {tool_msgs} tool results"
# Access custom state fields
@tool
def get_user_preference(
pref_name: str,
runtime: ToolRuntime # ToolRuntime parameter is not visible to the model
) -> str:
"""Get a user preference value."""
preferences = runtime.state.get("user_preferences", {})
return preferences.get(pref_name, "Not set")
tool_runtime매개변수는 모델로부터 숨겨집니다. 위의 예제에서 모델은 도구 스키마에서pref_name만 볼 수 있으며 -tool_runtime은 요청에 포함되지 않습니다.
Updating state:
Command를 사용하여 agent의 state를 업데이트하거나 그래프의 실행 흐름을 제어할 수 있습니다:
from langgraph.types import Command
from langchain.messages import RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langchain.tools import tool, ToolRuntime
# Update the conversation history by removing all messages
@tool
def clear_conversation() -> Command:
"""Clear the conversation history."""
return Command(
update={
"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)],
}
)
# Update the user_name in the agent state
@tool
def update_user_name(new_name: str, runtime: ToolRuntime) -> Command:
"""Update the user's name."""
return Command(
update={"user_name": new_name}
)
Context
runtime.context를 통해 user ID, session details 또는 애플리케이션별 설정과 같은 불변 설정 및 컨텍스트 데이터에 액세스할 수 있습니다.
도구는 ToolRuntime을 통해 런타임 컨텍스트에 액세스할 수 있습니다:
from dataclasses import dataclass
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from langchain.tools import tool, ToolRuntime
USER_DATABASE = {
"user123": {
"name": "Alice Johnson",
"account_type": "Premium",
"balance": 5000,
"email": "alice@example.com"
},
"user456": {
"name": "Bob Smith",
"account_type": "Standard",
"balance": 1200,
"email": "bob@example.com"
}
}
@dataclass
class UserContext:
user_id: str
@tool
def get_account_info(runtime: ToolRuntime[UserContext]) -> str:
"""Get the current user's account information."""
user_id = runtime.context.user_id
if user_id in USER_DATABASE:
user = USER_DATABASE[user_id]
return f"Account holder: {user['name']}\nType: {user['account_type']}\nBalance: ${user['balance']}"
return "User not found"
model = ChatOpenAI(model="gpt-4o")
agent = create_agent(
model,
tools=[get_account_info],
context_schema=UserContext,
system_prompt="You are a financial assistant."
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "What's my current balance?"}]},
context=UserContext(user_id="user123")
)
Memory (Store)
store를 사용하여 대화 전반에 걸쳐 영구 데이터에 액세스할 수 있습니다. store는 runtime.store를 통해 액세스되며, 사용자별 또는 애플리케이션별 데이터를 저장하고 검색할 수 있습니다.
도구는 ToolRuntime을 통해 store에 액세스하고 업데이트할 수 있습니다:
from typing import Any
from langgraph.store.memory import InMemoryStore
from langchain.agents import create_agent
from langchain.tools import tool, ToolRuntime
# Access memory
@tool
def get_user_info(user_id: str, runtime: ToolRuntime) -> str:
"""Look up user info."""
store = runtime.store
user_info = store.get(("users",), user_id)
return str(user_info.value) if user_info else "Unknown user"
# Update memory
@tool
def save_user_info(user_id: str, user_info: dict[str, Any], runtime: ToolRuntime) -> str:
"""Save user info."""
store = runtime.store
store.put(("users",), user_id, user_info)
return "Successfully saved user info."
store = InMemoryStore()
agent = create_agent(
model,
tools=[get_user_info, save_user_info],
store=store
)
# First session: save user info
agent.invoke({
"messages": [{
"role": "user",
"content": "Save the following user: userid: abc123, name: Foo, age: 25, email: foo@langchain.dev"
}]
})
# Second session: get user info
agent.invoke({
"messages": [{
"role": "user",
"content": "Get user info for user with id 'abc123'"
}]
})
# Here is the user info for user with ID "abc123":
# - Name: Foo
# - Age: 25
# - Email: foo@langchain.dev
Stream Writer
도구가 실행되는 동안 runtime.stream_writer를 사용하여 사용자 정의 업데이트를 스트리밍할 수 있습니다. 이는 도구가 수행하는 작업에 대해 사용자에게 실시간 피드백을 제공하는 데 유용합니다.
from langchain.tools import tool, ToolRuntime
@tool
def get_weather(city: str, runtime: ToolRuntime) -> str:
"""Get weather for a given city."""
writer = runtime.stream_writer
# Stream custom updates as the tool executes
writer(f"Looking up data for city: {city}")
writer(f"Acquired data for city: {city}")
return f"It's always sunny in {city}!"
도구 내부에서 runtime.stream_writer를 사용하는 경우, 도구는 LangGraph 실행 컨텍스트 내에서 호출되어야 합니다. 자세한 내용은 Streaming을 참조하세요.
출처: https://docs.langchain.com/oss/python/langchain/tools
Langchain v1.0
- LangChain 개요
- LangChain v1
- LangChain v1 마이그레이션 가이드
- LangChain 설치
- QuickStart
- Philosophy
- Agents
- Models
- Messages
Tools- Short-term memory
- Streaming
- Middleware
- Structured output
- Guardrails
- Runtime
- Context Engineering
- Model Context Protocol (MCP)
- Human-in-the-loop
- Multi-agent
- Retrieval
- Long-term memory
- Studio
- Test
- Deploy
- Agent Chat UI
- Observability
