迁移的真正起点:不只是改个端点
当你看到一个模型版本升级公告,上面写着“XX API 已弃用,请迁移至新 SDK”时,第一反应是替换请求 URL 和参数名。但对于 Function Calling 而言,这种想法恰恰是迁移失败的最大源头。
Function Calling Migration 的核心不是 API 地址更换,而是工具调用机制的范式转换。在 OpenAI 的 Chat Completions 旧 API 中,函数以 functions 参数定义,模型返回 function_call 对象;而在新的 Responses API 或 Assistants API 中,工具定义、调用上下文和状态管理被统一为 tools 参数,并引入了 tool_choice、并行函数调用、以及更严格的输出格式约束。
一个真实案例:某开发团队将旧 API 中的 20 个函数定义直接复制到新 API,发现模型频繁返回“无效工具调用”错误。排查后发现,新 API 要求每个工具的 description 字段必须显式说明参数依赖关系(例如“调用此函数前请确保已获取用户 ID”),旧 API 并未强制这一点。
最容易失败的地方:隐式上下文丢失
迁移中最隐蔽的坑是上下文状态丢失。在旧 API 中,开发者习惯于将函数调用的中间结果拼接回 messages 数组,模型能自然感知历史。但在新 API 的 Agent 循环中(例如使用 run + tool_outputs 模式),工具执行结果必须严格按照 thread 或 step 结构回传。一旦格式出错,模型会忽略之前的所有工具输出,导致 Agent 工作流中断。
具体错误场景:
- 你在一个多步骤工具链中,先调用了
search_database返回 10 条记录,接着调用format_results要求基于前一步结果生成表格。但在新 API 中,如果你将search_database的输出以非标准方式插入tool_outputs,模型会认为该步骤失败,直接跳过format_results。 - 解决方案:严格遵循 SDK 的
submit_tool_outputs接口,确保每个输出都附带对应的tool_call_id,且输出内容不超过模型上下文限制(通常为 4096 token)。

第一步:工具定义 audit 与重构
如果你现在就要落地迁移,第一步不是改代码,而是做工具定义审计:
- 列出现有所有函数:包括名称、参数、返回格式。注意标记那些依赖前置工具输出的函数(例如“生成图表”依赖“查询数据”的结果)。
- 按粒度拆分:新 API 建议每个工具只做一件事。旧 API 中常见的“全能函数”(例如
execute_anything)必须拆成单一职责函数,否则模型容易混淆。 - 重写 description:每个工具的 description 必须包含前置条件、输出格式、以及典型调用场景。例如:
- 旧:
"获取天气数据" - 新:
"根据城市名获取当前天气。需要先调用 check_city_exists 确认城市有效。返回 JSON 格式:{temperature, humidity, condition}"
- 旧:
- 添加错误处理工具:定义一个
report_error工具,专门接收模型无法处理的异常情况,避免循环调用。
完成审计后,在开发环境新建一个 Agent 测试脚本,使用新 API 的 client.responses.create 或 client.beta.threads.runs.create 逐个验证工具调用。

实操路径:一个简单迁移案例
假设你有一个旧 API 代码:
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": "北京天气如何?"}],
functions=[{
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}}
}]
)
迁移至新 API(OpenAI Python SDK v1.x+):
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-4o",
input=[{"role": "user", "content": "北京天气如何?"}],
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}},
"description": "根据城市名获取天气。参数 city 必须是中国城市的中文名称。"
}
}]
)
注意新 API 使用了 input 而非 messages,且 tools 数组内每个工具需要显式 type 和更详细的 description。
未来方向:从 Function Calling 到 Agent 循环
理解迁移背后的逻辑,其实是在为更复杂的 Agent 工作流做准备。当你掌握了工具定义、上下文管理和错误恢复后,就可以进入多工具编排、记忆管理与 MCP 协议集成等高级话题。
如果你想从普通开发者转型成为 Agent 工程师,这篇内容的下一步应该进入更系统的原创付费文章或课程。

暂无评论,快来发表你的见解吧