工具使用:Agent 的双手
没有工具的 LLM 是一个"只会说话的大脑"——它知道很多,但什么都做不了。工具使用让 Agent 从"问答机器"变成"行动者"。
演进路径
2023: Hard-coded Functions(硬编码函数)
2024: Function Calling(OpenAI 标准化)
2025: Tool Use API(Anthropic 扩展)
2026: MCP + 自主工具发现(工具市场)
第一阶段:Function Calling
基本用法
from openai import OpenAI
client = OpenAI()
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如北京、上海"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "北京今天多少度?"}],
tools=tools,
)
# LLM 返回工具调用
tool_call = response.choices[0].message.tool_calls[0]
# {"name": "get_weather", "arguments": {"city": "北京", "unit": "celsius"}}
# 执行工具
result = get_weather(**json.loads(tool_call.function.arguments))
# 把结果返回给 LLM
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "北京今天多少度?"},
response.choices[0].message,
{"role": "tool", "tool_call_id": tool_call.id, "content": result}
],
tools=tools,
)
多工具并行调用
# 现代 LLM 支持一轮调用多个工具
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "北京和上海今天天气怎么样?"}],
tools=tools,
)
# 返回两个 tool_calls: get_weather(北京) + get_weather(上海)
# 并行执行
results = await asyncio.gather(*[
execute_tool(tc) for tc in response.choices[0].message.tool_calls
])
第二阶段:工具设计原则
原则一:描述要精确
# ❌ 差:描述模糊
{
"name": "search",
"description": "搜索内容"
}
# ✅ 好:描述精确
{
"name": "search_web",
"description": "在互联网上搜索给定查询,返回前10个结果的标题、URL和摘要。适用于查找最新信息、新闻、技术文档。",
"parameters": {
"properties": {
"query": {
"type": "string",
"description": "搜索关键词,30字以内,去除无意义词"
},
"time_range": {
"type": "string",
"enum": ["day", "week", "month", "year", "all"],
"description": "时间范围过滤"
}
}
}
}
原则二:参数要简洁
# ❌ 差:参数太多
{
"name": "send_email",
"parameters": {
"properties": {
"to": {}, "cc": {}, "bcc": {},
"subject": {}, "body": {},
"attachments": {}, "priority": {},
"format": {}, "encoding": {},
"reply_to": {}, "sender_name": {}
}
}
}
# ✅ 好:只保留必要参数
{
"name": "send_email",
"parameters": {
"properties": {
"to": {"type": "string", "description": "收件人邮箱"},
"subject": {"type": "string", "description": "邮件主题"},
"body": {"type": "string", "description": "邮件正文"}
},
"required": ["to", "subject", "body"]
}
}
原则三:错误信息要友好
async def execute_tool(tool_call):
try:
result = await tool_registry[tool_call.name](**tool_call.args)
return {"status": "success", "data": result}
except ValidationError as e:
return {
"status": "error",
"error": f"参数错误:{e}",
"hint": "请检查参数格式和必填项"
}
except Exception as e:
return {
"status": "error",
"error": str(e),
"hint": "如果重试仍失败,请尝试其他方法"
}
第三阶段:MCP(Model Context Protocol)
MCP 是 Anthropic 提出的工具标准协议,让工具可以跨模型使用:
# MCP 服务器定义工具
from mcp import Server
server = Server("my-tools")
@server.tool()
async def search_database(query: str, limit: int = 10):
"""搜索数据库"""
results = await db.search(query, limit)
return results
@server.tool()
async def create_chart(data: list, chart_type: str = "bar"):
"""创建图表"""
return ChartGenerator.create(data, chart_type)
# MCP 客户端自动发现工具
client = MCPClient()
client.connect("my-tools-server")
# Agent 自动获取可用工具列表
tools = await client.list_tools()
# 无需手动定义,Agent 知道有哪些工具可用
MCP vs Function Calling
| 特性 | Function Calling | MCP |
|---|---|---|
| 工具定义 | 每次调用手动传 | 服务器注册 |
| 工具发现 | 手动维护列表 | 自动发现 |
| 跨模型 | 需要适配 | 标准协议 |
| 工具共享 | 代码复制 | 服务器复用 |
| 生态 | 各厂商自有 | 开放标准 |
第四阶段:自主工具发现
class AutonomousToolUser:
"""Agent 自主发现和选择工具"""
def __init__(self):
self.tool_registry = ToolRegistry()
self.tool_history = []
async def solve(self, task):
# 1. 分析任务需要什么能力
needed = await self.analyze_needs(task)
# {"search": True, "calculate": True, "visualize": False}
# 2. 搜索可用工具
candidates = await self.tool_registry.search(needed)
# 3. 选择最佳工具
selected = await self.select_tools(candidates, task)
# 4. 执行
for tool in selected:
result = await self.use_tool(tool, task)
if self.is_sufficient(result):
return result
# 5. 如果现有工具不够,尝试组合
return await self.compose_tools(selected, task)
工具链组合
class ToolChain:
"""工具链式调用"""
async def run(self, task):
# Step 1: 搜索
search_results = await self.use("web_search", query=task)
# Step 2: 提取
content = await self.use("extract_content", url=search_results[0].url)
# Step 3: 分析
analysis = await self.use("analyze", text=content, focus=task)
# Step 4: 可视化
chart = await self.use("create_chart", data=analysis.data)
# Step 5: 输出
return {"analysis": analysis, "chart": chart}
工具权限管理
class ToolPermission:
"""工具调用权限控制"""
PERMISSIONS = {
"read_only": ["search", "get", "list", "analyze"],
"write_allowed": ["create", "update", "send", "delete"],
"dangerous": ["execute_command", "delete_file", "format_disk"],
}
def check(self, tool_name, user_role):
if tool_name in self.PERMISSIONS["dangerous"]:
return user_role == "admin"
if tool_name in self.PERMISSIONS["write_allowed"]:
return user_role in ["admin", "editor"]
return True # read_only 工具所有人可用
常见问题
问题1:LLM 不调用工具
# 原因:工具描述不清晰或温度太低
# 解决:
# 1. 优化工具描述
# 2. 增加温度(temperature: 0.3-0.7)
# 3. 在 system prompt 中强调使用工具
system_prompt = """
你可以使用以下工具来帮助用户。
当用户的问题需要实时信息或计算时,必须使用工具,不要凭记忆回答。
"""
问题2:参数格式错误
# 原因:JSON 解析失败
# 解决:添加参数验证和修复
def parse_tool_args(args_str):
try:
return json.loads(args_str)
except json.JSONDecodeError:
# 尝试修复常见 JSON 错误
fixed = args_str.replace("'", '"').replace("None", "null")
return json.loads(fixed)
问题3:无限工具调用循环
# 解决:设置最大调用次数
class ToolLoopGuard:
def __init__(self, max_calls=10):
self.max_calls = max_calls
self.call_count = 0
def should_continue(self):
self.call_count += 1
return self.call_count <= self.max_calls
结论
工具使用是 Agent 的核心能力。2026 年的最佳实践:
- 工具描述是第一优先级——LLM 靠描述选择工具
- MCP 标准化——用开放协议,不绑死单一模型
- 权限分级——读/写/危险操作三级控制
- 错误友好——工具报错要让 LLM 能理解并修正
- 限制循环——最大工具调用次数保护
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
