kimi-for-dsh
第三方模型(Kimi 系为主)在 DeepSeek Harness 里的路由修复插件
解决什么问题
DSH 通过内置的 @deepseek-ai/dsh-llm-pi-ai 适配器(上游库 @earendil-works/pi-ai)接入 Kimi 等第三方模型。实测存在四类缺口:
① 上下文溢出不被识别 → 不触发自动压缩
Kimi 的两个硬限制报错:
total message size 5943865 exceeds limit 2097152 # 2MB 请求字节墙 → HTTP 400
Your request exceeded model token limit: 262144 # token 上限 → HTTP 400
这两段文本都不含 DSH 内置 isContextWindowExceededError 词表要求的关键词,于是被归类为 INVALID_REQUEST —— agent-loop 不知道这是"上下文爆了",不会触发压缩自愈,轮次直接失败。
本插件把这些报错改写为 CONTEXT_WINDOW_EXCEEDED,让 DSH 的压缩恢复链路正常接管。
② 配额型 429 被当成普通限流白重试
| 报错 | 语义 | 正确处置 |
|---|---|---|
The engine is currently overloaded |
引擎过载 | 退避重试 ✓ |
You've reached your usage limit for this period |
5 小时滚动窗口耗尽 | 重试无意义,应终止 |
You've reached kimi monthly usage limit... |
月度配额耗尽 | 重试无意义,应终止 |
本插件把配额型改写为 QUOTA_EXCEEDED(干净终止、不再浪费配额重试),过载型保持 RATE_LIMIT 不变。
③ k3 提前收尾(premature natural turn-end)→ 流内自救
实测现象(36 小时内 24 个 k3 轮次中 2 次):k3 输出一段计划性意图文本("Let me first locate…" / "Let me run the searches now…")后自然停止(stopReason: "stop"),不发出任何工具调用——DSH 记为正常 completed,用户看到的就是"他自己中断了"。两次早收尾步有一个共同签名:该步完全没有 thinking 块(pi-ai 目录为 k3 配置 forceAdaptiveThinking,adaptive 模式允许模型跳过思考)。Kimi Code 官方客户端的 kimiAnthropicTrait 使用 thinking:{type:"enabled"};这是当前最强的请求差异线索,但小规模 A/B 实验(3 变体 × 各 10 次真实工具循环)没有复现提前收尾,尚未建立因果关系。
请求体级修复(强制 enabled + context_management 契约)插件无法触达——请求体在 pi-ai 内部构造,llm/stream waterfall 的 options 是固定白名单不转发 onPayload/transport(已逐行验证)。因此本模块在流层自救:
- 包装 kimi 系路由的流,轻量收集
block-end块与finish; - 命中判定(全部满足才救):自然
stop+ 本响应无 tool-call 块 + 尾句命中未竟意图词表("let me / 让我 / 接下来 / 先去…")且非完结语气 + 最近历史有工具活动(干活中途); - 吞掉原
finish,构造续接请求(历史 + 合成 assistant 消息 + 双语续接指令),经ctx.llm.stream发出(symbol 标记防递归,最多续一层); - 续接块的 index 重映射、合成 replayState(满足
readReplayState的块数/类型契约),agent-loop 与用户看到的都是无缝继续; - 节流:滑动窗口(默认 10 分钟 3 次),续接失败优雅回退原 finish(行为等同未装插件)。
命中时输出日志:[kimi-for-dsh] premature-stop rescued, continuing in-stream :: tail=…
④ Preserved Thinking 的 anthropic-beta 头
Kimi 官方默认契约含 context-management-2025-06-27 beta 头 + context_management.edits(clear_thinking_20251015, keep:"all",见 kimi-code resolveThinkingKeep 默认值)。pi-ai 适配器只读 profile.headers(settings.yaml 的 provider 配置),waterfall options.headers 无下游消费者(实测验证)——所以这个头必须走 settings.yaml:
llm-pi-ai:
providers:
kimi-coding:
headers:
anthropic-beta: context-management-2025-06-27
请求体 edit 注入待 DSH 提供 body 级挂点或 pi-ai 上游支持(见"上游事项")。
安装
dsh plugin --profile web add github:BoltBlue121/kimi-for-dsh
或在 DSH 设置 → 插件里添加。
配置
全部可选项(默认值即推荐值):
# ~/.dsh/settings.yaml
kimi-for-dsh:
reclassifyErrors: true # 错误重分类(①②)
rescuePrematureStop: true # k3 提前收尾流内自救(③)
rescueWindowMs: 600000 # 自救滑动窗口(默认 10 分钟)
rescueMaxInWindow: 3 # 窗口内最大自救次数
extraProviders: [] # 除自动识别的 kimi/moonshot 系外,额外纳入修复的 provider id
从 v0.1 升级时,旧配置项 thinkingKeep 仍被接受,但已不再产生请求头注入;请改用上面的 llm-pi-ai.providers.<route>.headers 配置。
工作原理
挂在 DSH 的 llm/stream waterfall(cordis 的标准拦截点)上,仅对 kimi 系路由(provider id 含 kimi/moonshot,或 extraProviders 指定)生效:
- 重分类器:包装流式返回,遇到
finish.reason.kind === "error"的 chunk 时按报错文本改写failure.code,后续的重试(llm-retry)、压缩(compaction)、终止逻辑自动按正确语义执行。 - 提前收尾自救:见 ③。所有资源挂
ctx.effect,热重载/卸载即净。
已知限制
- 重分类与自救判定基于报错文本与尾句启发式(Kimi 未提供结构化信号),Kimi 若改措辞需更新正则——欢迎提 issue。
- 会员权益类报错("Your current plan supports only ... 256K context")故意不改写:它是 401 语义,正确动作是升级套餐或调低 contextWindow,不是压缩。
- 自救启发式有误报可能(模型确实说完了但尾句像意图)——只检查最后一句、排除正常交还用户的结尾、滑动节流并限制为单流单层续接;观察到误伤可设
rescuePrematureStop: false关闭。
上游事项(建议给 DSH/pi-ai 提的)
dsh-llm-pi-ai的 streamSimple options 是固定白名单,不转发 pi-ai 的onPayload/transport钩子——第三方路由无法做请求体级定制(如 Kimi 的context_managementedit、thinking.type覆写)。- pi-ai 目录
kimi-coding.json为 k3 配置forceAdaptiveThinking: true(thinking:{type:"adaptive"}+display:"summarized");Kimi 官方客户端(kimi-codekimiAnthropicTrait)硬编码thinking:{type:"enabled"}且不带display。实测 DSH 下 k3 偶发无思考步 + 提前收尾,官方客户端无此现象,建议对齐或提供覆写开关。
背景调研
本插件源于一次完整调研(会话日志统计 + pi-ai/kimi-code 源码逐行 diff + 双轮受控 A/B 实验)。核心结论:DSH↔Kimi 的核心链路可用、缓存命中正常、思考签名回传正常;缺口集中在错误语义映射与提前收尾行为。同类契约差异亦见 MoonshotAI/Kimi-K2#129。
License
BSD-3-Clause
No comments yet. Be the first to write one.