工具使用
工具使用(Tool Use)是AI智能体从"能说"进化到"能做"的关键能力。通过工具使用,Agent不再局限于文本生成,而是能够调用外部API、执行代码、查询数据库、操作文件系统,从而在真实世界中产生实际影响。工具使用能力直接决定了Agent的实用价值。
一、函数调用(Function Calling)
函数调用是现代LLM提供的核心能力之一。它允许模型在推理过程中决定调用预定义的函数,并生成符合函数签名的参数。这种机制让LLM能够与外部系统交互,而不需要修改模型本身。
函数调用的工作流程:
- 工具定义:开发者定义可用工具的函数签名(名称、参数、描述)。
- 模型推理:LLM在推理时分析用户需求,决定是否调用工具以及调用哪个工具。
- 参数生成:模型生成符合JSON Schema的工具调用参数。
- 函数执行:系统根据模型输出调用实际函数,获取返回结果。
- 结果整合:将函数返回结果传回模型,模型基于结果生成最终回答。
# OpenAI 风格的函数调用示例
tools = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "在互联网上搜索信息。当需要获取最新数据或验证事实时使用。",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索查询词,应该简洁明确"
},
"max_results": {
"type": "integer",
"description": "最大返回结果数,默认5",
"default": 5
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "execute_code",
"description": "执行Python代码并返回结果。用于数据计算、文件处理等。",
"parameters": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "要执行的Python代码"
},
"timeout": {
"type": "integer",
"description": "执行超时时间(秒),默认30",
"default": 30
}
},
"required": ["code"]
}
}
},
{
"type": "function",
"function": {
"name": "query_database",
"description": "查询数据库获取结构化数据。仅支持SELECT语句。",
"parameters": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "SQL查询语句(仅支持SELECT)"
},
"database": {
"type": "string",
"description": "目标数据库名称",
"enum": ["users", "orders", "products"]
}
},
"required": ["sql", "database"]
}
}
}
]
# Agent调用函数的处理流程
def process_with_tools(user_message, conversation_history):
response = llm.chat(
messages=conversation_history + [{"role": "user", "content": user_message}],
tools=tools,
tool_choice="auto" # 让模型自行决定是否调用工具
)
# 检查模型是否决定调用工具
if response.tool_calls:
for tool_call in response.tool_calls:
# 执行工具
result = execute_tool(
tool_call.function.name,
json.loads(tool_call.function.arguments)
)
# 将结果返回给模型
conversation_history.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
# 模型基于工具结果生成最终回答
final_response = llm.chat(
messages=conversation_history,
tools=tools
)
return final_response.content
else:
return response.content
二、API 集成
工具使用的核心是将外部API封装为Agent可调用的工具。良好的API集成需要考虑接口设计、错误处理、认证授权等多个方面。
常见的API集成模式:
- RESTful API:通过HTTP请求调用远程服务,如搜索引擎、天气API、翻译服务等。
- 数据库查询:直接查询SQL/NoSQL数据库获取结构化数据。
- 代码执行:在沙箱环境中执行代码,用于数据分析和计算。
- 文件系统操作:读写文件、创建目录、处理文档等。
- 系统命令:执行Shell命令进行系统管理(需要严格的安全控制)。
class ToolRegistry:
"""工具注册表:管理Agent可用的所有工具"""
def __init__(self):
self.tools = {}
self.categories = {}
def register(self, tool):
"""注册一个工具"""
self.tools[tool.name] = tool
category = tool.category or "general"
if category not in self.categories:
self.categories[category] = []
self.categories[category].append(tool.name)
def get_schemas(self):
"""获取所有工具的JSON Schema描述"""
return [tool.to_schema() for tool in self.tools.values()]
def execute(self, tool_name, arguments):
"""执行工具调用"""
if tool_name not in self.tools:
raise ToolNotFoundError(f"工具 '{tool_name}' 不存在")
tool = self.tools[tool_name]
# 参数验证
validated_args = tool.validate_arguments(arguments)
# 权限检查
if not tool.check_permissions():
raise PermissionError(f"无权执行工具 '{tool_name}'")
# 执行工具
try:
result = tool.run(**validated_args)
return ToolResult(success=True, data=result)
except Exception as e:
return ToolResult(success=False, error=str(e))
# 具体的API集成示例
class WebSearchTool(BaseTool):
"""网页搜索工具"""
name = "web_search"
description = "在互联网上搜索信息,获取最新数据和事实"
category = "information"
def __init__(self, api_key):
self.api_key = api_key
self.client = SearchClient(api_key)
def to_schema(self):
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"num_results": {
"type": "integer",
"description": "返回结果数量(1-10)",
"default": 5
}
},
"required": ["query"]
}
}
}
def run(self, query, num_results=5):
results = self.client.search(query, limit=num_results)
return [
{
"title": r.title,
"snippet": r.snippet,
"url": r.url
}
for r in results
]
三、工具描述设计
工具描述的质量直接影响Agent选择和使用工具的准确性。一个好的工具描述应该让LLM清楚地理解:这个工具能做什么、什么时候应该使用、参数如何填写。
工具描述的最佳实践:
- 清晰的功能描述:用一句话说明工具的核心功能,避免模糊表述。
- 使用场景说明:明确说明在什么情况下应该使用这个工具。
- 参数详细描述:每个参数都要有类型、描述、约束说明。
- 限制和边界:说明工具的能力边界和已知限制。
- 返回值说明:描述工具返回的数据格式和含义。
工具描述的"黄金法则"
工具描述本质上是写给LLM看的"使用手册"。想象你是一个向同事介绍工具的人:你需要说清楚它能做什么、什么时候该用它、怎么用。好的工具描述能显著提高Agent的工具选择准确率,减少不必要的试错调用。在OpenClaw中,建议使用中文编写工具描述,因为中文描述对中文任务场景更精准。
四、工具选择策略
当Agent拥有大量工具时,如何从中选择最合适的工具是一个关键挑战。工具选择策略包括:
- 直接选择:LLM直接从工具列表中选择一个工具。适合工具数量较少(少于20个)的场景。
- 两阶段选择:先用轻量模型或规则筛选候选工具,再由LLM从候选中选择。适合工具数量较多的场景。
- 语义检索:将工具描述编码为向量,根据用户查询语义检索最相关的工具。
- 层级选择:先选择工具类别,再从类别中选择具体工具。
class SmartToolSelector:
"""智能工具选择器"""
def __init__(self, all_tools, embedding_model):
self.all_tools = all_tools
self.embedding_model = embedding_model
# 预计算工具描述的向量
self.tool_embeddings = {
tool.name: embedding_model.encode(
f"{tool.name}: {tool.description}"
)
for tool in all_tools
}
def select_tools(self, query, top_k=5):
"""基于语义相似度选择候选工具"""
query_embedding = self.embedding_model.encode(query)
# 计算与每个工具的相似度
similarities = {}
for tool_name, tool_emb in self.tool_embeddings.items():
sim = cosine_similarity(query_embedding, tool_emb)
similarities[tool_name] = sim
# 返回最相似的top_k个工具
sorted_tools = sorted(
similarities.items(),
key=lambda x: x[1],
reverse=True
)
return [name for name, score in sorted_tools[:top_k]]
def select_with_llm(self, query, context):
"""两阶段选择:先检索候选,再由LLM选择"""
# 阶段1:语义检索候选工具
candidates = self.select_tools(query, top_k=8)
candidate_tools = [
self.all_tools[n] for n in candidates
]
# 阶段2:LLM从候选中选择
prompt = f"""用户需求:{query}
当前上下文:{context}
可用工具:
{self._format_tools(candidate_tools)}
请从以上工具中选择1-3个最适合的工具来完成用户需求。
返回工具名称列表。"""
selected = llm.generate(prompt)
return self._parse_tool_selection(selected)
# 工具组合使用示例
class ToolChain:
"""工具链:按顺序调用多个工具"""
def __init__(self, steps):
self.steps = steps # [(tool_name, arg_mapping), ...]
def execute(self, initial_input):
context = {"input": initial_input}
for tool_name, arg_mapping in self.steps:
# 从上下文中提取参数
args = {
param: context.get(source, source)
for param, source in arg_mapping.items()
}
# 执行工具
result = tool_registry.execute(tool_name, args)
# 将结果存入上下文
context[f"{tool_name}_result"] = result.data
return context
五、工具安全与权限管理
工具使用带来了强大的能力,但也引入了安全风险。Agent可能调用危险的工具、传入恶意参数、或泄露敏感数据。因此,工具安全是Agent系统设计中不可忽视的环节。
- 最小权限原则:Agent只应拥有完成任务所需的最少工具权限。
- 参数验证:所有工具参数在使用前必须经过严格验证。
- 沙箱执行:代码执行类工具应在隔离的沙箱环境中运行。
- 操作审计:记录所有工具调用的详细日志,支持事后审计。
- 速率限制:限制工具调用频率,防止滥用。
工具使用的演进方向
工具使用能力正在快速发展。从最初的固定函数调用,到动态工具发现、工具创建,再到Agent间工具共享,工具使用的范式不断演进。MCP(Model Context Protocol)等标准协议的出现,正在建立统一的工具集成规范。在OpenClaw中,工具系统支持热插拔,Agent可以在运行时动态加载新工具,极大提升了系统的灵活性。
六、工具使用的性能优化
在实际部署中,工具使用的性能优化至关重要:
- 并行调用:当多个工具调用之间没有依赖关系时,可以并行执行以节省时间。
- 结果缓存:对相同参数的工具调用结果进行缓存,避免重复执行。
- 超时控制:为每个工具调用设置合理的超时时间,防止长时间阻塞。
- 降级策略:当工具调用失败时,Agent应能使用替代方案继续执行。
- 批量操作:将多个小操作合并为批量调用,减少网络开销。
工具使用是Agent连接数字世界的桥梁。通过精心设计的工具描述、智能的工具选择策略和严格的安全管理,我们可以让Agent安全高效地利用各种外部工具,真正发挥AI智能体的实用价值。这也是OpenClaw框架的核心竞争力之一——丰富的工具生态和灵活的工具集成机制。