读到 client.messages.create(...) 时,很容易把它理解成“Python 调用 LLM 的方法”。但这其实是 Anthropic Python SDK 的一个入口。换一家模型服务,方法名、输入字段和返回结构都可能改变。
设想一个具体任务:用户要求“运行 main.py,只报告结果”。程序把问题和工具说明发给模型,取得运行请求,执行文件,再把除零错误交回模型。现在希望换一家供应商:只改模型名和 API Key,原来的循环还能继续吗?
需要检查的不是一次请求能否发出去,而是请求、响应和下一轮反馈能否连续衔接。以下接口和库的资料核对于 2026-10-20;它们是选定接口的对照,不代表一家厂商只提供一种 API。
同样是请求模型,入口和数据结构并不相同
SDK 是应用调用远程 API 的客户端库。创建客户端时,程序准备认证、服务地址和网络配置;调用生成方法时,SDK 将参数转换成请求,发送到服务端,再把响应解析成 Python 对象。客户端对象本身不是模型,也不能替代对话历史。
下面把几种常见接口并排放在一起。它们都能支持对话与工具调用,但表达方式不同:
| 选定的接口 | Python 调用入口 | 对话输入 | 工具请求与反馈 |
|---|---|---|---|
| Claude Messages | client.messages.create(...) | messages,工作约定放在顶层 system | 响应含 tool_use;应用通过 tool_result 回传,使用 tool_use_id 关联 |
| OpenAI Chat Completions | client.chat.completions.create(...) | messages | assistant 消息含 tool_calls;反馈使用 role: tool 和 tool_call_id |
| OpenAI Responses | client.responses.create(...) | input;可通过 instructions 提供约定 | 输出含 function_call Item;反馈是带 call_id 的 function_call_output Item |
| Google Gen AI 的 Generate Content | client.models.generate_content(...) | contents,可在 config 中提供 system_instruction | 返回函数调用信息,应用回传函数响应 Part |
具体形状分别见 Claude 工具协议、OpenAI 两种 API 的映射和 Google Python SDK 的手动函数调用示例。表格说明的是本地函数工具的往返,不涵盖服务端托管工具。
回到运行文件的例子:原循环若从 response["content"] 中寻找 tool_use,直接换成返回 choices 的接口就接不上了。即使提取出了工具名,也还要把执行结果按新接口要求的角色、字段和调用标识送回去。只把返回对象转成字典,并不会完成这些转换。
兼容 OpenAI,为什么还要读兼容性说明?
一些服务已经提供兼容接口,应用可以继续使用同一个 SDK。例如 DeepSeek 的官方示例使用 OpenAI SDK,配置自己的 base_url、密钥和模型名,再调用 Chat Completions。这可以减少客户端改写;同一家服务如今也可能提供多种协议入口,选择时要连同 API 类型一起确认。DeepSeek 调用文档
但“兼容”需要具体到字段和行为。Claude 的 OpenAI 兼容接口明确说明:函数调用的 strict 会被忽略;system/developer 消息会被提到顶层并拼接。因而请求返回成功,不足以证明严格参数约束生效,也不能假设系统消息的位置语义原样保留。Claude 兼容性说明
假设原应用依赖严格工具参数格式,换服务后仍带着 strict,但新接口忽略了它。此时症状可能不是请求报错,而是模型返回应用不接受的参数。处理时应核对目标接口的支持范围,选择它支持的约束方式,并在工具执行前继续做应用校验。验证应包含缺字段、错类型等拒收输入,不能只看一次成功回答。
已有统一封装,它们统一到哪一层?
跨厂商调用并不需要从零发明。已有开源项目提供统一接口,只是它们选择的公共模型和职责不同:
| 项目 | 提供的抽象 | 适合参考的部分 |
|---|---|---|
| LiteLLM | 以统一函数调用多家服务,completion() 使用 OpenAI 风格的输入输出;另有网关形态 | 希望集中转换供应商接口,或统一路由和调用管理 |
| LangChain | 各供应商集成包实现统一模型接口,提供消息、调用和工具绑定等能力 | 应用已经采用其消息与工具体系 |
| Pydantic AI | 区分 Model、Provider 和 Profile,分别处理模型接口、连接认证和能力差异 | 希望明确区分协议适配、服务地址与模型能力 |
这些是项目自身公开的接口设计,不是所有厂商共同遵守的协议。参考 LiteLLM SDK、LangChain 模型接口与 Pydantic AI 的模型、提供方及能力配置。表中的使用场景是基于这些职责作出的选型建议,不是性能排名。
统一以后,能力差异仍要有处理方式。LiteLLM 默认会对不支持的 OpenAI 参数抛出异常,也允许配置为丢弃。两种选择的结果不同:前者要求应用显式处理不兼容,后者可能让请求继续,但被丢弃的约束不再生效。接入时应明确选择,不能把“调用成功”当成行为完全等价。LiteLLM 参数处理
还要确认谁在推进循环。Google SDK 支持直接传入 Python 函数并自动调用、回传,也提供关闭自动函数调用的配置。若应用正在自己实现执行许可和调用次数控制,就要核对这些自动行为,避免本来想观察一次请求,却把后续工具往返也交给 SDK。Google SDK 函数调用说明
自己封装时,请求与反馈要一起考虑
只接一家服务、正在学习循环时,我会先保留原生 SDK,把每个响应字段的用途看清楚。可以把一次调用收进 ask_claude,但函数名变短,并不意味着程序已经能跨厂商运行。
Agent Loop 实践篇就是这个边界:ask(messages) 方便注入离线测试输入,run_loop 仍然读取 Claude 的 content、tool_use 和 stop_reason。要让同一个循环消费另一种 API,至少要同时处理三件事:
- 转换请求:把历史、工作约定和工具定义转换成目标接口接受的结构。
- 解释响应:保留文字、调用标识、工具名和参数,区分可继续、截断、拒绝等状态;不能只取出一段文字。
- 接回反馈:把结果关联到原调用,按目标协议构造下一轮输入,并保留该协议要求的上下文信息。
不要急着把所有响应缩成 text 和一个成功标记。不同协议有不同的停止和历史规则;如果过早丢掉内容块或必要元数据,下一轮请求可能无法继续。OpenAI Responses 例如允许手动回传输出 Item,也支持用 previous_response_id 承接状态;不能把一种 API 的历史管理规则推广到所有接口。Responses 状态管理说明
真正需要多供应商时,再决定使用成熟封装,还是维护范围明确的适配器。检验标准仍是开头那条链:模型提出运行请求,应用执行并保存除零错误,下一次请求带回对应反馈,模型能够据此报告。模拟 HTTP 可以验证报文、转换和调用次数;在线测试才能观察目标模型实际如何选择工具。两种证据各有用途,不能互相替代。