🧠AI Agent 与工具调用
Tool Calling
面试回答
常见问法
什么是 Tool Calling?它相比普通聊天调用多了什么能力?
回答
Tool Calling 的本质是让模型不只是输出自然语言,而是能决定”什么时候调用工具、调用哪个工具、传什么参数”。这样模型可以把外部系统能力接进来,比如查天气、搜数据库、调用内部服务。
# Tool Calling系统示例
class ToolCallingSystem:
def __init__(self, llm_client, tool_registry):
self.llm_client = llm_client
self.tool_registry = tool_registry
def execute_with_tools(self, user_query, max_iterations=3):
"""
带工具调用的对话执行
1. 模型决定调用什么工具
2. 执行工具并返回结果
3. 模型基于工具结果生成回答
"""
conversation_history = []
current_query = user_query
for iteration in range(max_iterations):
# 1. 构建工具调用提示
tool_prompt = self.build_tool_prompt(current_query, conversation_history)
# 2. 模型决定调用什么工具
model_response = self.llm_client.generate(tool_prompt)
# 3. 解析工具调用
tool_call = self.parse_tool_call(model_response)
if tool_call:
# 4. 执行工具
tool_result = self.execute_tool(tool_call)
# 5. 记录到历史
conversation_history.append({
'query': current_query,
'tool_call': tool_call,
'tool_result': tool_result
})
# 6. 基于工具结果继续
current_query = f"基于工具结果:{tool_result}\n请继续回答用户问题"
else:
# 7. 模型没有调用工具,生成最终回答
final_answer = model_response
break
return {
'final_answer': final_answer,
'tool_calls': conversation_history,
'iterations': iteration + 1
}
def build_tool_prompt(self, query, history):
"""构建工具调用提示"""
tools_description = []
for tool_name, tool_info in self.tool_registry.items():
tools_description.append(f"""
工具名称:{tool_name}
功能:{tool_info['description']}
参数:{json.dumps(tool_info['parameters'], indent=2)}
""")
prompt = f"""
你是一个智能助手,可以使用以下工具:
{chr(10).join(tools_description)}
用户问题:{query}
历史记录:
{history}
请分析问题,如果需要调用工具,请按以下格式响应:
<tool_call>
{{
"tool_name": "工具名称",
"arguments": {{
"param1": "value1",
"param2": "value2"
}}
}}
</tool_call>
如果不需要调用工具,请直接回答用户问题。
响应:
"""
return prompt
def execute_tool(self, tool_call):
"""执行工具调用"""
tool_name = tool_call['tool_name']
arguments = tool_call['arguments']
if tool_name in self.tool_registry:
tool_function = self.tool_registry[tool_name]['function']
try:
result = tool_function(**arguments)
return {'status': 'success', 'data': result}
except Exception as e:
return {'status': 'error', 'error': str(e)}
else:
return {'status': 'error', 'error': f'工具{tool_name}不存在'}
# 工具注册示例
def search_weather(city, date):
"""查询天气"""
# 模拟天气查询
return f"{city}在{date}的天气:晴天,25°C"
def search_database(query, table_name):
"""数据库查询"""
# 模拟数据库查询
return f"查询{table_name}的结果:{query}"
tool_registry = {
'search_weather': {
'description': '查询指定城市和日期的天气',
'parameters': {
'city': {'type': 'string', 'description': '城市名称'},
'date': {'type': 'string', 'description': '日期'}
},
'function': search_weather
},
'search_database': {
'description': '查询数据库',
'parameters': {
'query': {'type': 'string', 'description': '查询语句'},
'table_name': {'type': 'string', 'description': '表名'}
},
'function': search_database
}
}
# 使用示例
def demo_tool_calling():
system = ToolCallingSystem(llm_client, tool_registry)
# 用户查询天气
result = system.execute_with_tools("北京明天天气怎么样?")
print(f"最终回答:{result['final_answer']}")
print(f"工具调用次数:{len(result['tool_calls'])}")
# 用户查询数据库
result2 = system.execute_with_tools("查询用户表中有多少用户")
print(f"最终回答:{result2['final_answer']}")
print(f"工具调用链:{result2['tool_calls']}")
追问
- 工具描述为什么会显著影响调用准确率?(影响模型理解)
- 工具参数为什么一定要做校验?(安全性和正确性)
- 工具执行失败时应该由谁兜底?(错误处理机制)
原理展开
普通聊天模型只能在已有上下文上生成文本,而 Tool Calling 让模型把一部分任务转成结构化动作。系统层通常要负责工具注册、参数 schema、执行结果回填和异常处理。
这件事的重点不只是”能调工具”,而是”调得可控”。工具能力越强,越需要清晰边界、鉴权和参数约束,否则错误调用会直接放大成业务风险。
# 高级工具调用:参数验证和错误处理
class AdvancedToolCalling:
def __init__(self):
self.validator = ToolParameterValidator()
self.error_handler = ToolErrorHandler()
def validate_and_execute(self, tool_call, user_context):
"""
验证参数并执行工具
1. 参数格式验证
2. 权限检查
3. 执行监控
4. 错误恢复
"""
# 1. 参数验证
validation_result = self.validator.validate(
tool_call['arguments'],
tool_call['tool_name']
)
if not validation_result['valid']:
return {
'status': 'validation_error',
'errors': validation_result['errors']
}
# 2. 权限检查
permission_result = self.check_permissions(
tool_call['tool_name'],
user_context
)
if not permission_result['allowed']:
return {
'status': 'permission_denied',
'reason': permission_result['reason']
}
# 3. 执行工具(带监控)
try:
with ToolExecutionMonitor(tool_call['tool_name']) as monitor:
result = self.execute_tool(tool_call)
# 记录执行指标
monitor.record_success(
execution_time=monitor.get_duration(),
result_size=len(str(result))
)
return result
except ToolExecutionError as e:
# 4. 错误处理
error_handling = self.error_handler.handle(
error=e,
tool_name=tool_call['tool_name'],
user_context=user_context
)
return {
'status': 'execution_error',
'error': str(e),
'recovery_action': error_handling['action']
}
def check_permissions(self, tool_name, user_context):
"""检查用户是否有权限调用工具"""
# 实现权限检查逻辑
allowed_tools = user_context.get('allowed_tools', [])
if tool_name in allowed_tools:
return {'allowed': True}
else:
return {
'allowed': False,
'reason': f'用户无权调用工具{tool_name}'
}
# 工具参数验证器
class ToolParameterValidator:
def validate(self, arguments, tool_name):
"""验证工具参数"""
errors = []
# 根据工具schema验证参数
tool_schema = self.get_tool_schema(tool_name)
for param_name, param_config in tool_schema.items():
# 检查必需参数
if param_config.get('required', False) and \
param_name not in arguments:
errors.append(f"缺少必需参数:{param_name}")
# 检查参数类型
if param_name in arguments:
value = arguments[param_name]
expected_type = param_config['type']
if not self.check_type(value, expected_type):
errors.append(
f"参数{param_name}类型错误:"
f"期望{expected_type},实际{type(value).__name__}"
)
return {
'valid': len(errors) == 0,
'errors': errors
}
易错点
- 只关注调用成功率,不关注错误调用代价
- 把工具描述写得过长又模糊
- 忽略工具执行的性能监控
- 权限检查不严格导致安全风险
记忆技巧
记住Tool Calling三要素:
- 工具发现 = “模型知道有什么工具”
- 参数生成 = “模型知道怎么调用”
- 结果整合 = “模型知道怎么使用结果”
典型应用场景:
- 智能助手:天气查询、日程管理
- 数据分析:数据库查询、报告生成
- 客服系统:订单查询、问题解决
- 开发工具:代码生成、测试执行