🧠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三要素:

  1. 工具发现 = “模型知道有什么工具”
  2. 参数生成 = “模型知道怎么调用”
  3. 结果整合 = “模型知道怎么使用结果”

典型应用场景:

  • 智能助手:天气查询、日程管理
  • 数据分析:数据库查询、报告生成
  • 客服系统:订单查询、问题解决
  • 开发工具:代码生成、测试执行