<!-- Canonical URL: https://ask.atlascloud.ai/zh/why-tool-calls-fail-after-switching-coding-agent-models -->

# 为什么更换编码智能体模型后工具调用会失败？

> 更换模型后工具调用失败，通常不是模型名称本身的问题，而是协议、工具 Schema、参数序列化、流式事件或会话状态契约发生了变化。应把它当作接口契约迁移，而不是简单替换模型名称。

最有效的第一项测试不需要完整编码基准。让替换后的模型调用一个只有两个必填参数的只读函数：如果失败，问题位于规划层以下；如果成功，再依次加入流式输出、多工具、会话状态和写入操作，直到找到第一个契约断点。

切换模型会暴露旧集成里隐含的假设。编码智能体不只是提示词加模型，而是一套连接模型输出、流解析器、工具注册表、执行器以及工具结果回传循环的状态机。即使普通文本输出看起来正常，任何边界都可能已经不兼容。

## 区分模型能力与请求协议

模型擅长编码，不代表它能通过客户端当前使用的协议工作。另一个模型也可能接受请求，却没有在该路由上开放工具调用。修改模型名称前，先检查能力元数据。

[Atlas Cloud 的 LLM 协议指南](https://www.atlascloud.ai/docs/llm-protocols?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=why-tool-calls-fail-after-switching-coding-agent-models)列出了同一 Base URL 下支持的 OpenAI Chat Completions、Responses、Anthropic Messages、Google Gemini 等格式，也明确说明并非所有模型都支持全部协议。应以模型的 `supported_apis` 和工具能力为准。

| 层级 | 迁移时要确认的问题 | 失败信号 |
|---|---|---|
| 端点 | 模型是否接受当前协议？ | 返回 400 或忽略字段 |
| 能力 | 该路由是否声明支持工具？ | 只回复文字而不调用 |
| Schema | 名称与 JSON Schema 是否有效？ | 参数缺失或格式错误 |
| 流式处理 | 参数增量是否正确拼接？ | JSON 被截断 |
| 循环 | 工具结果是否以正确角色返回？ | 重复调用或回合停滞 |

## 把工具 Schema 缩减为单一契约

先使用短函数名、两个必填字符串、没有联合类型和可选嵌套的函数。复杂 Schema 会把模型行为和校验器行为混在一起，延长诊断时间。

```json
{
  "type": "function",
  "function": {
    "name": "read_file",
    "description": "Read a UTF-8 text file from the workspace.",
    "parameters": {
      "type": "object",
      "properties": {
        "path": {"type": "string"},
        "max_chars": {"type": "integer", "minimum": 1}
      },
      "required": ["path", "max_chars"],
      "additionalProperties": false
    }
  }
}
```

如果协议支持强制选择工具，就强制调用该函数。这样可以区分“模型无法调用工具”和“模型经过规划后选择不调用”。

## 先测试非流式，再测试流式

非流式响应会在一个载荷里给出完整工具对象；流式响应则可能把函数名、调用 ID 和 JSON 参数拆成多个事件。只有收到协议定义的 final 或 done 事件后才能解析并执行参数。

不要因为中间缓冲区恰好能被解析成 JSON 就提前执行，后续增量仍可能继续追加。应按调用 ID 保存缓冲区、拒绝重复完成，并在迁移测试中记录原始事件顺序。

| 流式不变量 | 必须满足的行为 |
|---|---|
| 稳定的调用身份 | 所有增量进入同一个调用缓冲区 |
| 有序拼接 | 参数片段按事件顺序追加 |
| 明确完成 | 等待最终事件后再执行 |
| 单次执行 | 完成的调用最多执行一次 |

## 明确定义智能体循环的内部格式

不要让供应商特有字段散落在执行器各处。把响应统一转换为 `assistant_text`、`tool_calls`、`usage`、`stop_reason` 等内部字段，再通过协议适配器把工具结果转换回目标格式。

调用 ID 应视为不透明值；协议需要关联时必须原样保留。执行前校验参数，遇到不合法 JSON 时向模型返回结构化错误，而不是静默修改。

## 首次对比时重置会话状态

旧会话可能包含推理块、工具结果角色、状态句柄或新路由不接受的助手消息。先用相同系统指令创建全新会话，再重放一段经过规范化的短历史。

状态快捷方式通常与协议绑定。上一次响应的句柄并不意味着开发者指令会自动带入下一次请求。把指令是否持续生效设为明确测试项，而不是默认前提。

## 建立分阶段迁移测试

按以下顺序运行同一组测试夹具：

* 普通文本响应。
* 强制调用一个只读工具，非流式。
* 自动选择一个工具，非流式。
* 强制调用一个工具，流式。
* 两个相互独立的工具。
* 一次工具错误与恢复。
* 一个简短的多轮编码任务。

遇到第一个失败就停止并检查原始通信数据，不要从健康检查直接跳到自主修改仓库。

## 判断是否需要独立适配器

如果差异只是字段名或事件名，共享适配器通常足够；如果模型要求不同协议、历史表示或工具结果语义，独立适配器更安全。

Atlas Cloud 使用一个密钥和 Base URL 暴露多种格式以及持续更新的[LLM 模型目录](https://www.atlascloud.ai/llm-models?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=why-tool-calls-fail-after-switching-coding-agent-models)，便于进行模型实验，但不能省略能力检查。应同时记录模型、协议、Schema 版本、流式模式和测试结果。

## 结论

切换模型后工具调用失败，根本原因通常是把行为与协议迁移误当成字符串替换。先验证路由，缩减 Schema，通过非流式强制调用测试，再验证流式拼接，最后加入会话状态。如果两个模型的消息或事件语义存在实质差异，应保留独立适配器，不要隐藏差别。

## FAQ

### 为什么新模型只回复文字而不调用工具？

该模型可能不支持当前协议下的工具调用，也可能需要不同的 tool choice 设置，或对工具描述的理解不同。先核对能力元数据，再测试一次强制工具调用。

### 两个 OpenAI 兼容模型的工具调用格式仍可能不同吗？

可能。外层请求格式兼容，不代表流式增量、调用 ID、参数完成方式和结束原因完全一致。

### 切换模型后应该继续使用旧会话吗？

只有在确认新模型和协议接受同样的历史消息后才应复用。更安全的做法是从全新会话开始，再逐步加入状态。

### 最快的诊断测试是什么？

强制调用一个 Schema 很小、结果确定的只读工具，关闭流式输出并记录原始请求与响应；通过后再测试完整智能体循环。

### Atlas Cloud 会把所有模型统一成完全相同的工具接口吗？

不会。Atlas Cloud 支持多种协议，每个模型都会公布自己支持的 API 和能力。客户端必须选择该模型实际支持的协议。

### 什么时候应该为两个模型保留不同的适配器？

如果两者的状态对象、流式事件、工具结果消息或错误语义无法安全映射到同一套内部契约，就应保留独立适配器。
