AI Agent框架探秘:拆解 OpenHands(12)--- Function call
·
AI Agent框架探秘:拆解 OpenHands(12)— Function call
一、从基础讲起:什么是 Function Call?在 AI Agent 的日常工作中,模型常常需要调用外部工具或获取实时数据。比如,当用户问“今天北京天气怎么样?”,大语言模型(LLM)自身无法直接访问天气API,这就需要一种机制让模型发出一个“函数调用请求”,然后由系统去执行并返回结果。Function Call(函数调用)就是这样一个桥梁:它允许 LLM 生成结构化的调用指令,而不是纯文本回复。在 OpenHands 框架中,Function call 是 Agent 与外部世界交互的核心机制之一。我们可以把它理解为 Agent 的“手”和“脚”——模型负责思考,函数调用负责执行。下面是一个最简单的 Python 示例,模拟 LLM 发出函数调用请求:python# 示例 1:模拟一个简单的函数调用系统import json# 定义可用的工具函数def get_weather(city: str) -> str: """获取天气信息(模拟)""" weather_data = { "北京": "晴朗,25°C", "上海": "多云,28°C" } return weather_data.get(city, "未知城市")# 模拟 LLM 返回的函数调用请求(通常由 LLM 输出的 JSON 表示)llm_response = { "function": "get_weather", "arguments": {"city": "北京"}}# 执行函数调用if llm_response["function"] == "get_weather": result = get_weather(**llm_response["arguments"]) print(f"函数调用结果:{result}") # 输出:函数调用结果:晴朗,25°C这段代码展示了最核心的流程:定义函数 → 解析调用请求 → 执行并返回结果。但在真实框架中,这个过程要复杂得多。## 二、OpenHands 中的函数调用架构OpenHands 作为一个完整的 AI Agent 框架,将 Function call 抽象为几层结构:1. 工具定义层:声明每个函数的名称、参数类型、描述2. 请求解析层:解析 LLM 输出的函数调用 JSON3. 执行引擎层:安全地调用实际函数4. 结果回传层:将执行结果格式化后送回 LLM这种分层设计使得 Agent 可以灵活地扩展新工具。比如,当我们需要让 Agent 可以操作文件系统,只需添加一个文件操作函数,而无需改动核心逻辑。## 三、实战:构建一个带函数调用的 Agent 核心下面我们编写一个更完整的示例,模拟 OpenHands 风格的函数调用系统。这个 Agent 会接收用户指令,通过 LLM(这里用模拟的)决定调用哪个函数,然后执行并返回结果。python# 示例 2:完整的函数调用 Agent 模拟import jsonfrom datetime import datetimeclass OpenHandsAgent: """模拟 OpenHands 风格的 Agent,支持函数调用""" def __init__(self): # 注册所有可用的工具函数 self.tools = { "get_current_time": { "function": self.get_current_time, "description": "获取当前时间,无参数" }, "calculate": { "function": self.calculate, "description": "执行数学计算,参数:expression (str) 数学表达式" }, "search_knowledge": { "function": self.search_knowledge, "description": "搜索知识库,参数:query (str) 搜索关键词" } } def get_current_time(self) -> str: """工具1:获取当前时间""" return f"当前时间是:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" def calculate(self, expression: str) -> str: """工具2:安全执行数学计算""" try: # 注意:实际项目中应使用更安全的计算方式 result = eval(expression) return f"计算结果:{result}" except Exception as e: return f"计算错误:{str(e)}" def search_knowledge(self, query: str) -> str: """工具3:模拟知识库搜索""" knowledge_base = { "python": "Python 是一种高级编程语言,广泛用于 AI 开发", "agent": "AI Agent 是能自主执行任务的智能系统" } return knowledge_base.get(query.lower(), f"未找到关于 '{query}' 的知识") def simulate_llm_decision(self, user_input: str) -> dict: """模拟 LLM 根据用户输入决定调用哪个函数""" # 实际项目中,这里会调用真正的 LLM API if "时间" in user_input: return {"function": "get_current_time", "arguments": {}} elif "计算" in user_input: # 提取表达式(简单模拟) expr = user_input.replace("计算", "").strip() return {"function": "calculate", "arguments": {"expression": expr}} elif "搜索" in user_input or "知识" in user_input: query = user_input.replace("搜索", "").replace("知识", "").strip() return {"function": "search_knowledge", "arguments": {"query": query}} else: return None # 无法识别的指令 def process_user_input(self, user_input: str) -> str: """处理用户输入的主流程""" # 步骤1:模拟 LLM 决策 decision = self.simulate_llm_decision(user_input) if decision is None: return "抱歉,我没有理解您的指令,请尝试询问时间、计算或搜索知识。" # 步骤2:查找并执行工具函数 tool_name = decision["function"] if tool_name not in self.tools: return f"错误:未知工具 '{tool_name}'" tool_func = self.tools[tool_name]["function"] args = decision["arguments"] # 步骤3:执行函数调用 try: result = tool_func(**args) return result except Exception as e: return f"函数调用失败:{str(e)}"# 运行测试agent = OpenHandsAgent()# 测试各种指令test_inputs = [ "现在几点了?", "计算 3 + 5 * 2", "搜索 Python 知识", "你好世界"]for user_input in test_inputs: print(f"用户:{user_input}") response = agent.process_user_input(user_input) print(f"Agent:{response}\n")运行这段代码,你会看到 Agent 能根据不同的用户指令,自动选择并调用对应的函数。这就是 Function call 在 AI Agent 中的核心价值——让模型突破文本生成限制,具备执行实际动作的能力。## 四、深入 OpenHands 的高级用法OpenHands 在实际实现中,对 Function call 做了许多增强:### 1. 异步执行与错误重试真实场景中,API 调用可能超时或失败。OpenHands 使用 asyncio 实现异步函数调用,并内置重试机制。### 2. 参数校验与类型安全每个函数调用都会经过严格的 JSON Schema 校验,确保 LLM 生成的参数格式正确。例如,如果函数需要一个整数参数,但 LLM 传了字符串,系统会拒绝调用并要求 LLM 重新生成。### 3. 上下文注入函数调用可以访问 Agent 的当前状态(如对话历史、环境变量)。这让函数能做出更合理的决策,比如文件操作函数知道当前工作目录。### 4. 链式调用OpenHands 支持在一次交互中多次调用函数。例如,先“搜索用户信息”,再“根据结果发送邮件”。框架会自动管理调用顺序和数据传递。## 五、最佳实践与注意事项| 实践要点 | 说明 ||---------|------|| 函数描述要详细 | LLM 依赖描述来决定何时调用,应包含参数示例和边界条件 || 避免副作用 | 函数应该纯粹且可预测,修改外部状态前要确认 || 安全性检查 | 对用户输入的参数进行白名单校验,防止注入攻击 || 超时控制 | 每个函数调用设置合理的超时时间,避免 Agent 卡死 |## 总结Function call 是 AI Agent 连接“思考”与“行动”的关键桥梁。从基础的函数注册与调用,到 OpenHands 框架中的异步执行、参数校验和链式调用,这一机制让 LLM 从一个“聊天机器人”进化为能够真正操作外部世界的智能体。通过本文的两个示例,你应该已经掌握了 Function call 的核心原理,并看到了它在实际 Agent 框架中的实现方式。随着 Agent 技术不断发展,函数调用的能力边界也在持续扩展——从简单的 API 调用,到复杂的多步骤工作流,Function call 正在成为构建下一代智能系统的基石。
更多推荐


所有评论(0)