当前位置: 首页 > news >正文

Trae 调用 MiMo API 报错 400?一文搞懂原因并用 Proxy 完美解决

最近在用 Trae 集成 MiMo 模型进行多轮工具调用时,频繁遇到Invalid request (400)错误。经过排查,发现是 MiMo API 新增了对reasoning_content字段的回传要求。本文记录完整排查过程,并介绍社区大佬 Mintneko 提供的 Proxy 解决方案。


一、问题现象

在 Trae 中使用 MiMo 模型(如mimo-v2.5-pro)进行多轮对话,当模型在历史消息中产生过工具调用(tool_calls)后,后续轮次的请求会直接报错:

这个路径之前mimo官方有个trae的对接文档,不知道为啥现在没了?应该就是发那个问题公告的原因:trae现在不支持
之前官方给的trae的对接链接是(在token plan 的基础url上添加chat/completions ,因为trae不会自己添加):所以我这里之前的url是(之前好使,最近不行了。。。。。):
https://token-plan-cn.xiaomimimo.com/v1/chat/completions

Invalid request (Model Provider Error Code: 400, HTTP Status: 400)

单轮对话或者不涉及工具调用的对话一切正常,问题只在多轮 + 工具调用的场景下复现。


二、排查过程

2.1 官方公告

经过搜索,发现 MiMo 官方平台近期发布了一则公告:

公告链接:关于 Agent 类产品多轮会话中回传 reasoning_content 的说明

关于 Agent 类产品多轮会话中回传 reasoning_content 的说明

当在 Agent 类产品的多轮会话中开启 MiMo 思考模式,且历史会话中存在工具调用时,后续所有 user 交互轮次中回传的 assistant 如果包含了工具调用,必须完整回传reasoning_content字段,否则 API 将返回 400 错误。

之所以作此要求,是因为历史reasoning_content一旦缺失,模型上下文将不完整,可能表现出指令遵循下降、幻觉增多等现象。

受影响的产品包括:TRAE、Cursor、Roo Code、GitHub Copilot CLI、Zed、AutoGen、Goose 等。

受影响的模型包括:MiMo-V2.5-Pro、MiMo-V2.5、MiMo-V2-Pro、MiMo-V2-Omni、MiMo-V2-Flash。

2.2 根因分析

简单来说,问题的链条是这样的:

用户发起多轮对话 ↓ Trae 构造请求时,将历史 assistant 消息(含 tool_calls)写入 messages ↓ 但 Trae 没有回传这些 assistant 消息的 reasoning_content 字段 ↓ MiMo API 发现:有 tool_calls 却没有 reasoning_content → 400 错误

为什么 Trae 不传reasoning_content这其实是大多数 Agent 框架的通用行为。这些框架遵循 OpenAI 的标准协议,只关注contenttool_calls字段,对reasoning_content这种扩展字段默认会忽略。所以历史消息中的推理内容在转发过程中被"丢弃"了。

2.3 正确的回传方式

按照官方文档,正确的做法是把 assistant 消息的完整字段都保留下来:

# 错误 ❌ — 缺少 reasoning_content messages.append({ "role": "assistant", "content": "", "tool_calls": [...] }) # 正确 ✅ — 完整回传 messages.append({ "role": "assistant", "content": "", "tool_calls": [...], "reasoning_content": "The user wants to know... I should call..." })

但在 Trae 这类客户端中,我们无法手动控制它构造 messages 的方式。这就需要一个中间层来帮忙——也就是 Proxy。


三、解决方案:MiMo Reasoning Content Proxy

在 GitHub 上找到了社区大佬 Mintneko 提供的代理方案 mimo-proxy,原理非常巧妙。

3.1 核心思路

在 Trae 和 MiMo API 之间加一层本地代理,代理负责:

  1. 1.拦截并缓存:每次 MiMo 返回的 assistant 消息中如果包含reasoning_content,就把它缓存起来
  2. 2.自动注入:后续请求经过代理时,检查历史消息中是否有 assistant 消息缺少reasoning_content,如果有,就从缓存中取出注入回去
  3. 3.兜底降级:如果缓存中找不到(比如代理刚启动、缓存过期等),就把该 assistant 消息的tool_calls剥离掉,降级为纯文本,避免触发 400
Trae ──→ Proxy (localhost:8899) ──→ MiMo API │ │ │ ① 注入 reasoning_content │ │ ② 缓存返回的 reasoning │ │←──────────────────────────←│

3.2 脚本逐模块解析

下面对脚本的各个核心模块做一个详细介绍。

模块一:配置区
MIMO_API_BASE = "https://token-plan-cn.xiaomimimo.com/v1" # MiMo API 地址 LISTEN_HOST = "0.0.0.0" # 监听地址 LISTEN_PORT = 8899 # 监听端口 CACHE_MAX_SIZE = 2000 # 缓存最大条目数 CACHE_TTL = 7200 # 缓存过期时间(秒)

代理监听在本地8899端口,Trae 的 API Base URL 改为http://127.0.0.1:8899/v1即可。缓存采用 LRU 策略,最多存 2000 条,每条 2 小时过期。

模块二:缓存机制

这是整个方案的核心。缓存有两套索引:

索引方式用途
哈希索引SHA256(content + tool_calls)[:16]按消息内容精确匹配
Tool Call ID 索引tool_call_id按工具调用 ID 反查
def _msg_hash(msg: dict) -> str: content = msg.get("content") or "" tool_calls = json.dumps(msg.get("tool_calls") or [], sort_keys=True) raw = f"{content}||{tool_calls}" return hashlib.sha256(raw.encode()).hexdigest()[:16]

为什么要两套索引?因为 Trae 在回传历史消息时,消息内容可能被稍作修改(比如拼接了工具结果),但tool_call_id通常是不变的。所以优先用哈希匹配,匹配不到再用tool_call_id反查,提高命中率。

缓存操作使用 Python 的OrderedDict实现标准 LRU:

def _cache_get(key: str) -> str | None: if key in _cache: val, ts = _cache[key] if time.time() - ts < CACHE_TTL: # 未过期 _cache.move_to_end(key) # 移到末尾(最近使用) return val del _cache[key] # 过期则删除 return None def _cache_set(key: str, value: str): if key in _cache: del _cache[key] _cache[key] = (value, time.time()) while len(_cache) > CACHE_MAX_SIZE: # 超出容量则淘汰最久未用的 _cache.popitem(last=False)
模块三:注入与降级逻辑

这是处理请求的核心函数。遍历messages中的每条 assistant 消息,检查是否需要处理:

def inject_reasoning(messages: list[dict]) -> tuple[int, int]: for i, msg in enumerate(messages): if msg.get("role") != "assistant": continue if not msg.get("tool_calls"): # 没有 tool_calls → 不需要处理 continue if msg.get("reasoning_content"): # 已经有 reasoning_content → 跳过 continue # 尝试从缓存中查找 cached = _cache_get(_msg_hash(msg)) if not cached: cached = _find_by_tool_call_ids(msg) if cached: # ✅ 命中缓存 → 注入 reasoning_content msg["reasoning_content"] = cached else: # ⚠️ 未命中 → 降级:剥离 tool_calls,转为纯文本 del msg["tool_calls"] # 同时在 content 中保留工具调用的摘要 msg["content"] += " [Called get_current_weather]"

降级策略的思路很聪明:MiMo API 只对「有tool_calls但没有reasoning_content」的消息报 400。那我把tool_calls去掉,模型自然就不会要求reasoning_content了。虽然丢失了结构化的工具调用信息,但至少不会报错,而且在 content 中保留了工具调用的文本摘要,模型仍然能理解上下文。

模块四:流式响应处理

代理需要在流式传输过程中同时做两件事:逐块转发给客户端 + 逐步累积完整消息用于缓存。

async def _stream_proxy(client, url, headers, body): acc_content = "" acc_reasoning = "" acc_tool_calls = [] async with client.stream("POST", url, headers=headers, json=body) as resp: async for raw_chunk in resp.aiter_bytes(): # 解析 SSE 数据 # 累积 reasoning_content、content、tool_calls # 原样转发给客户端 yield _sse(payload) # 收到 [DONE] 时,将完整消息缓存 if payload == "[DONE]": if acc_reasoning and (acc_content or acc_tool_calls): _cache_set_with_index(hash, acc_reasoning, tool_call_ids)

这个设计确保了缓存的实时性:模型的每一次响应,只要有reasoning_content,都会在流结束后立即缓存,后续轮次立刻可用。

模块五:错误处理与重试

v1.4 版本重点增强了错误处理:

  • 5xx 错误自动重试:最多 3 次,间隔递增(1s、2s)
  • 4xx 错误直接透传:客户端参数问题,不重试
  • 超时处理:流式模式和非流式模式都有独立的超时重试逻辑
  • 空内容兜底:如果 MiMo 只返回了reasoning_contentcontent为空,自动将reasoning_content作为content返回
# 空 content 兜底 if not msg.get("content") and not msg.get("tool_calls") and msg.get("reasoning_content"): msg["content"] = msg["reasoning_content"]
模块六:API 端点

代理暴露了与 MiMo API 完全兼容的端点:

端点说明
POST /v1/chat/completions核心:聊天补全(带注入/降级逻辑)
GET /v1/models模型列表(直接透传)
GET /代理状态页
GET /health健康检查

四、使用步骤

4.1 拉取mimo-proxy项目

git clone https://github.com/Mintneko/mimo-proxy.git

如果你拉不下来,可以参考我上一篇博客,里面有github处理方案:
用 OpenCode 装 Skills 一直失败,它说是网不好,但浏览器明明能上 git Hub 啊?

或者你也可以将mimo_proxy.py下载到本地,在本地直接启动就行:

4.2 安装依赖

pip install starlette uvicorn httpx

4.3 启动代理

python mimo_proxy.py

启动后会看到:

Microsoft Windows [版本 10.0.26200.8117] (c) Microsoft Corporation。保留所有权利。 D:\SoftWareConfig\mimo-proxy>python mimo_proxy.py 10:10:53 [mimo-proxy] 🚀 MiMo Proxy v1.4 on 0.0.0.0:8899 → https://token-plan-cn.xiaomimimo.com/v1 ============================================================ ✅ 代理已启动!请在 Trae 中配置以下地址: 本机访问: http://127.0.0.1:8899/v1/chat/completions 局域网: http://192.168.1.154:8899/v1/chat/completions ⚠️ 注意: 1. 地址必须是完整路径,包含 /v1/chat/completions 2. 不要用 0.0.0.0,那是监听地址不是访问地址 3. API Key 填你的 MiMo API Key ============================================================ INFO: Started server process [41220] INFO: Waiting for application startup. 10:10:53 [mimo-proxy] 🚀 httpx client initialized INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8899 (Press CTRL+C to quit)

4.4 配置 Trae

在 Trae 的模型设置中:

  • API Base URLhttp://127.0.0.1:8899/v1
  • API Key:填你的 MiMo API Key(代理会原样透传)
  • Modelmimo-v2.5-pro(或其他受影响模型)

4.5 验证

配置完成后,正常在 Trae 中使用 MiMo 模型即可。多轮对话 + 工具调用场景下,400 错误不会再出现。


五、方案原理总结

整个方案可以用一句话概括:

用空间换正确性——通过本地缓存reasoning_content,在请求转发时自动补全缺失字段,从而绕过 Agent 框架不回传扩展字段的问题。

第一轮请求 用户 → Trae → Proxy → MiMo API │ ←←←←←←←←←←←←←←│ 返回 reasoning_content │ │ │ ① 缓存到本地 │ ↓ 本地缓存 第二轮请求(Trae 丢失了 reasoning_content) 用户 → Trae → Proxy ──→ MiMo API │ ↑ │ ② 从缓存 │ │ 注入回去 │ ↓ │ 注入后的完整 messages

三层保障

  1. 1.缓存命中 → 注入:最佳情况,完整保留模型推理上下文
  2. 2.缓存未命中 → 降级:剥离 tool_calls,避免 400,保留基本对话能力
  3. 3.API 错误 → 重试:5xx 自动重试 3 次,提高稳定性

六、写在最后

这个问题本质上是 MiMo 为了保证推理质量而新增的协议要求,与现有 Agent 框架的兼容性还在逐步推进中。在框架方完成适配之前,Mintneko 的这个 Proxy 方案是一个非常实用的过渡方案——部署简单、侵入性低、对 Trae 的使用完全透明。

感谢 Mintneko 大佬的开源贡献。

参考链接

  • MiMo 官方公告:【重要公告】关于 Agent 类产品多轮会话中回传 reasoning_content 的说明
  • mimo-proxy 项目:mimo-proxy
http://www.jsqmd.com/news/844658/

相关文章:

  • 中电金信智能数据挖掘助手,让数据分析像聊天一样简单
  • 告别手动统计!用Python+WeChatMsg给你的微信聊天做个‘年度报告’(附完整代码)
  • Arm Ethos-N78 NPU性能剖析与优化实战
  • 佛山用户亲测:2026年户外伸缩遮阳雨篷选型避坑指南 - 品牌优选官
  • 粤收回收:一家深耕广州的再生资源回收企业如何构建全链条服务体系 - 品牌优选官
  • 从iwlist扫描到自动联网:嵌入式设备RTL8188EUS WiFi完整配置与开机自启教程
  • Clip Converter实战指南:从网页到硬盘,轻松获取高清视频资源
  • 2026年深圳音视频系统集成与多媒体会议方案怎么选?一站式全包vs多头对接深度对比指南 - 企业名录优选推荐
  • 哈密市巨昌商贸:新疆有实力的钢材批发公司 - LYL仔仔
  • 分期乐购物额度回收:让闲置额度变成灵活可用的现金 - 团团收购物卡回收
  • 『App自动化测试之Appium实践篇』| 从零到一:Appium-Inspector跨平台安装与核心配置实战指南
  • 终极指南:如何用Python实现手机号反查QQ号的3种高效方法
  • Unity软体模拟避坑指南:Obi Softbody的Surface与Volume蓝图到底怎么选?
  • 如何快速掌握开源电路仿真工具:CircuitJS1从零开始的完整教程
  • 2026年白色冰箱哪款最值得买?大白405成性价比首选! - 速递信息
  • 2026年诸暨荣怀学校招生简章:七大学部同步招生,报名通道已开启,附招生电话 - 奔跑123
  • 如何永久保存微信聊天记录:本地化备份与深度分析完整指南
  • 2026年深圳音视频系统集成服务商选型指南:从政企指挥中心到文旅展厅的一站式解决方案 - 企业名录优选推荐
  • 2026年被动边坡防护网厂家推荐:河北恒驿路桥工程有限公司,RX-050及环形被动防护网专业供应 - 品牌推荐官
  • WaveTools深度解析:鸣潮性能调优与数据统计的技术实现
  • 告别‘看片难’:手把手教你用HIFUSE网络提升医学图像分类准确率(附代码实战)
  • 医院挂号就诊系统|基于SprinBoot+vue医院挂号就诊系统(源码+数据库+文档)
  • 2026年MBTI测试全攻略:正版中文量表本土权威平台避坑指南 - 品牌种草官
  • 【技术解析】DAS:一种为CNN注入全局感知力的可变形注意力门
  • 佛山车库蓬包选购全攻略:实用避坑指南2026版 - 品牌优选官
  • 2026年05月不锈钢离心泵推荐:口碑好的源头厂家大盘点,离心泵/农田灌溉泵/水泵控制柜/智慧泵房,离心泵供货商哪家权威 - 品牌推荐师
  • 使用Taotoken后API调用延迟与账单清晰度的实际体验分享
  • CAXA 圆弧命令
  • 广州粤收再生资源:深耕循环经济,构建工业资产处置全链条 - 品牌优选官
  • 深挖行业白皮书:2026南京黄金回收避坑清单,建议收藏 - 奢侈品回收测评