
人工智能AI AgentAgent 框架DeepSeek【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址https://gitcode.com/gh_mirrors/de/deepseek-harness点击查看免费下载本文深入解析 DeepSeek Harnessdeepseek-ai/dsh-llm-pi-ai适配器中一次针对 pi-ai 传输层截断错误分类的修复当模型流式连接在提供方终止事件之前断开表现为裸terminated或Anthropic stream ended before message_stop等措辞时如何将其从兜底的PI_AI_ERROR重新归类为可重试的TRANSPORT从而让llm-retry策略默认重试而不是放弃整个回合。读者将掌握 pi-ai 错误扁平化的上游机制、classifyPiAiError的完整分类规则与文本匹配模式以及错误分类如何与llm-retry的重试策略联动。背景一次被吞掉的重试机会一次 TUI 运行中模型连接在流式输出中途断开界面上只浮现出单条terminated通知另一个被截断的 Anthropic 响应则浮现出Anthropic stream ended before message_stop。从语义上看这两者都是传输层截断transport truncation——连接在提供方的终止 SSE 事件之前就已死亡——然而dsh-llm-pi-ai中的classifyPiAiError对这两种措辞都不匹配最终落入兜底的PI_AI_ERROR。问题的后果不止于错误码不准确PI_AI_ERROR不在llm-retry的DEFAULT_RETRYABLE_CODES之中因此一次本可恢复的连接断开被当作永久性失败处理永远不会被重试直接导致整个回合失败。这正是本次修复要解决的痛点可恢复的传输故障必须被识别并路由到重试路径上。上游根因pi-ai 在终止事件前就扁平化了错误修复决策的出发点是一段无法在适配器内绕过的上游事实细节丢失发生在 pi-ai 内部且不可恢复。pi-ai 在推送终止error事件之前把捕获到的错误缩减为error.message其api/anthropic-messages.js中的逻辑为errorMessage error instanceof Error ? error.message : JSON.stringify(error)丢弃了原始的Error对象及其cause链。具体链路是undiciNode.js 内置的 HTTP 客户端把可据以采取行动的SocketError放在cause上但只交给 fetch 包装层一个裸的terminatedpi-ai 只保留了这个词进一步把cause抹掉dsh-llm-pi-ai适配器最终拿到的只是errorMessage字符串没有任何结构化错误可供解析。同时pi-ai 的SimpleStreamOptions没有暴露任何 fetch/dispatcher/client 钩子适配器无法在细节被扁平化之前自行捕获cause。因此文本匹配是 pi-ai 当前唯一交付给下游的信号分类只能基于消息文本进行——这也是整个修复方案的核心约束。修复决策扩展分类器识别两类传输措辞本次修复的核心改动位于 packages/llm/llm-pi-ai/src/stream.ts 中的classifyPiAiError函数。该函数接收 pi-ai 终止事件携带的errorMessage字符串返回 Harness 的稳定错误码mapStopReason在stopReason error时调用它见 stream.ts。修复新增了对两类传输措辞的识别均映射到TRANSPORT流式输出中途的套接字断开呈现为裸的terminatedundici 扁平化后的产物或Premature closeNode 流层措辞在终止事件之前被截断的流每个 pi-ai 提供方各自抛出不同措辞包括Anthropic stream ended before message_stop… before a terminal response event… ended without a terminal eventStream ended without finish_reason第二类的匹配模式统一为stream ended (?:before|without)\b大小写不敏感见 stream.ts。第一类则通过扩展原有的网络/连接相关正则覆盖将terminated与premature close加入匹配集合见 stream.ts。完整分类规则一览以下为修复后classifyPiAiError的完整匹配顺序自上而下先命中者优先其中TRANSPORT相关的两条规则即为本次新增匹配模式正则忽略大小写返回的错误码语义\b(?:401|403)\bAUTH认证失败isQuotaExceededError(message)QUOTA配额/余额耗尽终止性失败\b429\b或rate.?limitRATE_LIMIT请求速率限制可重试\b413\b、failed to buffer the request body: length limit exceeded、payload too large、request body too largeINVALID_REQUEST请求体被拒绝重发无法成功\b400\b或invalid.?requestINVALID_REQUEST无效请求\b5\d\d\bSERVER服务端错误可重试time(?:d)?\s*out或timeoutTIMEOUT超时可重试stream ended (?:before|without)\bTRANSPORT新增终止事件前流被截断\b(?:network|connection|socket|fetch)\b、\bECONN[A-Z]\b、other side closed、HTTP2 request did not get a response、WebSocket closed unexpectedly、\bterminated\b、premature closeTRANSPORT扩展网络/连接/套接字断开含裸terminated与Premature close以上均不命中PI_AI_ERROR兜底未分类失败值得注意的是INVALID_REQUEST的分类顺序在SERVER5xx之前因为413属于请求体大小超限——这是网关或提供方的请求体上限重发相同请求不可能成功因此被归类为无效而非瞬时故障。代码中的上游注记分类器携带一条XXX(pi-ai upstream)注记见 stream.ts点名扁平化发生的具体位置并说明期望的修复方式如果 pi-ai 有朝一日转发原始的Error或提供一个让我们捕获cause的钩子就应改为基于code/cause分类。在此之前分类仍是尽力而为的文本匹配XXX标记其为一个权宜之计而非最终状态。被否决的替代方案修复过程中评估过三个替代方案各有明确的技术理由被否决理解它们有助于把握方案边界通过 pi-ai 的 fetch/dispatcher/client 钩子捕获cause否决。pi-ai 0.81.1 一个都没有暴露。StreamOptions只提供onPayload/onResponse而onResponse在响应体流被消费之前触发无法观察到流式输出中途的断开。Anthropic 路径虽接受一个client对象但为拦截传输错误而为每个请求构造并注入提供方 SDK client只为一个诊断字符串就越过了适配器的服务边界得不偿失。把两种错误都保留为PI_AI_ERROR并放宽llm-retry的可重试集合否决。PI_AI_ERROR是真正未分类失败的兜底其中包含不可重试的失败畸形的提供方响应、意料之外的 SDK bug。让兜底可重试会重试那些永远不会成功的失败修复之道是分类出可恢复的那种情况而不是模糊整个桶。在适配器里把扁平化后的错误包装成LlmError(TRANSPORT, { cause })仿照 DeepSeek 适配器否决。DeepSeek 适配器包装的是拿到响应之前的fetch拒绝其cause仍然完好因此链式包装保留了真实细节而在 pi-ai 路径中终止事件的errorMessage已经是一个没有cause可链的扁平化字符串包装只会加一层却恢复不了任何东西——分类出 code 是唯一还能增加的价值。这一对比也解释了为什么 Harness 的两个 LLM 适配器对传输错误的处理路径不同。与重试策略的联动TRANSPORT为什么可重试分类的最终价值体现在llm-retry插件上。deepseek-ai/dsh-llm的默认可重试错误码集合定义在 packages/llm/llm/src/retry-policy.tsconst DEFAULT_RETRYABLE_CODES Object.freeze([ EMPTY_RESPONSE_CODE, // EMPTY_RESPONSE RATE_LIMIT, SERVER, TIMEOUT, TRANSPORT, ])重试执行器位于 packages/llm/llm-retry/src/index.ts其判定逻辑清晰当策略为normal模式且!policy.retryableCodes.includes(failure.code)时直接return next()放弃重试。换言之错误码是否落在retryableCodes内直接决定了一次失败是否值得重试。修复前传输截断落入PI_AI_ERROR不在默认集合内被当作永久失败修复后这些失败携带TRANSPORT默认即被重试无需任何额外配置。默认策略为 normal 模式、最多 5 次重试初始退避 500ms、最大延迟 10s、抖动比例 0.1默认值均定义于 retry-policy.ts组合方也可通过配置文件中的retryPolicy覆盖这些参数。测试验证文本匹配的完整覆盖本次修复的测试用例位于 packages/llm/llm-pi-ai/tests/convert.spec.ts用it.each参数化地验证了全部传输措辞都映射为TRANSPORT见 convert.spec.tsit.each([ other side closed, HTTP2 request did not get a response, WebSocket closed unexpectedly, // undici flattens a mid-stream socket drop to this bare word (its SocketError // cause is discarded upstream before it reaches us). terminated, Premature close, // pi-ais per-provider throws when the wire closes before the terminal event. Anthropic stream ended before message_stop, OpenAI Responses stream ended before a terminal response event, openrouter stream ended without a terminal event, Stream ended without finish_reason, ])(maps pi-ai transport wording %j, (errorMessage) { expect(mapStopReason(assistant({ stopReason: error, errorMessage }))) .toMatchObject({ kind: error, failure: { code: TRANSPORT } }) })同一测试文件中还验证了既有分类规则未受回归影响HTTP 401 → AUTH、HTTP 429 → RATE_LIMIT、429 insufficient_quota → QUOTA、HTTP 500 → SERVER、provider timed out → TIMEOUT、ECONNRESET socket closed → TRANSPORT、上下文超限与INVALID_REQUEST等见 convert.spec.ts。值得留意的是vector length limit exceeded仍正确落入PI_AI_ERROR说明新的传输匹配规则没有过度捕获包含 length limit exceeded 字样的非传输错误。文档同步Known-Limitations 条目与代码改动配套llm-pi-ai/README.md在 Known Limitations and Deferred Work 一节新增了对应条目记录 pi-ai 会扁平化 cause 链、因此 Harness 的错误码是从消息文本分类而来见 packages/llm/llm-pi-ai/README.md。该条目与既有的 Provider HTTP status is unavailablepi-ai 错误事件不暴露稳定的 HTTP 状态共同界定了适配器在错误可观测性上的边界。修复后的行为与残留风险改进后的行为流式输出中途的传输层断开和终止前的流截断现在都携带TRANSPORT组合出的llm-retry策略会默认重试而不是让该回合失败通知文本不变仍是terminated/Anthropic stream ended before message_stopcause 细节在适配器看到之前就已丢失因此errorChain见 packages/llm/llm/src/error.ts用于渲染完整 cause 链的诊断工具没有更多内容可渲染只有被路由的code得到了改善。残留风险分类仍然依赖字符串匹配且依赖提供方的措辞。未来某个 pi-ai 版本若改写这些错误的措辞就会静默回退到PI_AI_ERROR直到匹配模式被更新——这正是XXX(pi-ai upstream)注记存在的意义它指向那个持久的修复方向基于 pi-ai 转发的code/cause路由而非文本分类是尽力而为的无法覆盖 pi-ai 未来新增提供方的全部措辞需要随测试用例持续补充。延伸阅读pi-ai 适配器实现总览 —dsh-llm-pi-ai的完整配置、登录与故障恢复说明以及新增的 Known-Limitations 条目重试策略与执行器 — 默认可重试错误码与退避配置的完整定义llm-retry 插件 —retryableCodes判定与重试执行逻辑错误码与错误链 —HarnessError.code、errorChain等诊断基础设施LLM 流式子系统文档 —StreamChunk协议与适配器契约赞分享人工智能AI AgentAgent 框架DeepSeek【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址https://gitcode.com/gh_mirrors/de/deepseek-harness点击查看免费下载相关推荐functime社区贡献指南如何参与开源项目并提交你的代码functime社区贡献指南如何参与开源项目并提交你的代码 functime是一个专注于大规模时间序列机器学习的开源项目基于Polars构建专为面板数据的机器学习数据分析Convert to it 项目源码结构导览80 处理器目录组织思路完整解读Convert to it 项目源码结构导览80 处理器目录组织思路完整解读 Convert to it 是一个「真正通用」的在线 文件转换工具 univDeepSeek Harness 结构化错误分类体系基于 HarnessError 的跨 Seam 错误路由与分类实践DeepSeek Harness 结构化错误分类体系基于 HarnessError 的跨 Seam 错误路由与分类实践 导读 本文深入解析 DeepSeek人工智能AI AgentAgent 框架DeepSeek创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考