程云来 / 杭州
返回文章·AI 工程
·约 8 分钟

调用不同厂商的 LLM,究竟要适配什么?

从替换一次模型调用出发,区分原生 API、兼容接口和统一封装,追踪请求、响应与工具结果为什么需要一起适配。


读到 client.messages.create(...) 时,很容易把它理解成“Python 调用 LLM 的方法”。但这其实是 Anthropic Python SDK 的一个入口。换一家模型服务,方法名、输入字段和返回结构都可能改变。

设想一个具体任务:用户要求“运行 main.py,只报告结果”。程序把问题和工具说明发给模型,取得运行请求,执行文件,再把除零错误交回模型。现在希望换一家供应商:只改模型名和 API Key,原来的循环还能继续吗?

需要检查的不是一次请求能否发出去,而是请求、响应和下一轮反馈能否连续衔接。以下接口和库的资料核对于 2026-10-20;它们是选定接口的对照,不代表一家厂商只提供一种 API。

同样是请求模型,入口和数据结构并不相同

SDK 是应用调用远程 API 的客户端库。创建客户端时,程序准备认证、服务地址和网络配置;调用生成方法时,SDK 将参数转换成请求,发送到服务端,再把响应解析成 Python 对象。客户端对象本身不是模型,也不能替代对话历史。

下面把几种常见接口并排放在一起。它们都能支持对话与工具调用,但表达方式不同:

选定的接口Python 调用入口对话输入工具请求与反馈
Claude Messagesclient.messages.create(...)messages,工作约定放在顶层 system响应含 tool_use;应用通过 tool_result 回传,使用 tool_use_id 关联
OpenAI Chat Completionsclient.chat.completions.create(...)messagesassistant 消息含 tool_calls;反馈使用 role: tool 和 tool_call_id
OpenAI Responsesclient.responses.create(...)input;可通过 instructions 提供约定输出含 function_call Item;反馈是带 call_id 的 function_call_output Item
Google Gen AI 的 Generate Contentclient.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,至少要同时处理三件事:

  1. 转换请求:把历史、工作约定和工具定义转换成目标接口接受的结构。
  2. 解释响应:保留文字、调用标识、工具名和参数,区分可继续、截断、拒绝等状态;不能只取出一段文字。
  3. 接回反馈:把结果关联到原调用,按目标协议构造下一轮输入,并保留该协议要求的上下文信息。

不要急着把所有响应缩成 text 和一个成功标记。不同协议有不同的停止和历史规则;如果过早丢掉内容块或必要元数据,下一轮请求可能无法继续。OpenAI Responses 例如允许手动回传输出 Item,也支持用 previous_response_id 承接状态;不能把一种 API 的历史管理规则推广到所有接口。Responses 状态管理说明

真正需要多供应商时,再决定使用成熟封装,还是维护范围明确的适配器。检验标准仍是开头那条链:模型提出运行请求,应用执行并保存除零错误,下一次请求带回对应反馈,模型能够据此报告。模拟 HTTP 可以验证报文、转换和调用次数;在线测试才能观察目标模型实际如何选择工具。两种证据各有用途,不能互相替代。