Agent 跑长任务时,大家最怕什么?
很多人会说:请求失败、模型超时、网络断开、Gateway 掉线。
但 NousResearch/hermes-agent issue #18458 暴露了一个更隐蔽的问题:真正危险的不是某一次中断,而是上下文压缩刚好在中断时失败,然后系统用静态占位符替代真实摘要。
任务表面上没有崩。
会话继续活着。
但中间一大段对话、工具调用、决策过程被压掉了,却没有生成真正 summary。
这就是长任务里的“静默失忆”。
现象:incomplete chunked read 之后,Hermes 插入静态 fallback marker
issue 里描述的是长时间运行的 Hermes Agent session。
自动 context compression 在调用 auxiliary summary 时遇到网络/streaming 中断:
peer closed connection without sending complete message body (incomplete chunked read)
日志里出现类似内容:
Failed to generate context summary: peer closed connection without sending complete message body (incomplete chunked read).
Further summary attempts paused for 60 seconds.
Summary generation failed — inserting static fallback context marker
Auxiliary compression: using auto (...) at ...
关键不只是 summary 失败,而是后续行为:
插入静态 fallback context marker
移除中间 conversation turns
没有真实摘要
这意味着压缩完成了,但压缩结果不是“摘要”,而是“这里曾经有内容,但我没总结出来”。
为什么这比直接失败更危险?
如果任务直接失败,用户至少知道要重试。
但静态 fallback marker 的问题是:
系统继续运行,看起来没有大事
后续 assistant 可能继续工作,但它已经失去了:
- 中间做过哪些尝试;
- 哪些方案被排除;
- 用户临时改过什么要求;
- 哪些文件已经写过;
- 哪些链接已经查过;
- 哪些结论只是草稿,哪些已经确认;
- 哪些外部操作已经完成。
于是长任务会出现很典型的后遗症:
- 重复检索;
- 重复执行;
- 忘记用户刚刚确认的方向;
- 把已发布内容当成未发布;
- 需要从文件、日志、session search 里人工恢复;
- 甚至产生前后矛盾的答复。
这类问题不是“模型不聪明”,而是任务交接摘要丢了。
context compression 本来是为了解决什么?
长任务里,Agent 的上下文会越来越大:
- 用户消息;
- assistant 推理与计划;
- 工具调用结果;
- web fetch 内容;
- 文件读写;
- 代码 diff;
- 发布结果;
- 错误日志。
如果一直把所有内容塞进模型上下文,成本高、速度慢,也容易超出 context window。
所以 Hermes 会做 context compression:
把中间大量 conversation turns 压缩成一段摘要
保留任务连续性
释放上下文空间
这个设计本身是对的。
问题在于:压缩摘要生成也是一次 LLM 调用,也会失败。
尤其是长任务中,压缩 prompt 本身可能很大,auxiliary summary response 也可能是长连接请求,更容易遇到:
- incomplete chunked read;
- peer closed connection;
- unexpected EOF;
- response ended prematurely;
- timeout;
- proxy 中断;
- provider streaming close。
当前问题:把 transient error 当成最终失败
issue 提出的核心改进是:这些错误应该被识别为 transient connection errors,而不是直接走最终静态 fallback。
需要识别的典型字符串包括:
incomplete chunked read
peer closed connection
unexpected eof
response ended prematurely
connection was closed
这些不是 prompt 错误,也不是认证错误,更不是模型拒答。
它们通常意味着:
这次连接半路断了,但重试可能成功
所以更合理的行为应该是:
1. 短暂重试; 2. 如果使用 auxiliary.compression.provider: auto,尝试 fallback provider; 3. 只有重试和 fallback 都失败后,才插入静态 marker; 4. 日志明确区分“retry 成功 / provider fallback 成功 / 最终静态 fallback”。
更稳的压缩流程应该长什么样?
理想流程可以这样设计:
触发 context compression
↓
调用 auxiliary summary provider
↓
如果成功:写入真实 summary
↓
如果 transient connection error:重试 1-2 次
↓
如果仍失败且 provider=auto:切换 fallback provider
↓
如果 fallback 成功:写入真实 summary
↓
全部失败:插入 static fallback marker
这样做的好处是:
- 保留“不崩溃”的安全性;
- 降低静默失忆概率;
- 对网络抖动更鲁棒;
- 长任务续接质量更稳定。
静态 fallback marker 应该是最后防线,不应该是第一次 summary 连接中断后的默认结果。
为什么长工具任务更容易踩中?
issue 里提到,这更可能发生在 very long、tool-heavy tasks。
原因很简单:
1. 压缩 prompt 更大
工具结果越多,压缩输入越长。
更长的输入意味着辅助模型处理时间更久,也更容易触发代理、网关、provider 的连接边界。
2. summary 输出也可能更长
长任务摘要不能太短,否则保不住关键决策。输出越长,请求持续时间越久。
3. 任务状态更复杂
短任务即使丢一点上下文,也容易从最近几轮恢复。
长任务一旦丢中间段,损失的是完整工作链路。
4. Gateway 场景更脆弱
issue 的环境备注里提到,这是在 gateway / Feishu 长时间 workflow 中观察到的。
Gateway 长任务常常叠加:
- 消息平台;
- 网络代理;
- LLM provider;
- auxiliary provider;
- context compression;
- 工具调用。
链路越长,偶发连接错误越正常。
如何判断自己遇到了“压缩失忆”?
如果 Hermes 长任务突然变得“像换了个人”,可以查这些迹象。
1. 日志出现 incomplete chunked read
重点搜索:
incomplete chunked read
peer closed connection
Failed to generate context summary
Summary generation failed
static fallback context marker
2. 任务没有崩,但开始重复工作
例如:
- 又去查已经查过的 issue;
- 又写已经写过的文件;
- 忘记刚刚发布过的文章;
- 忘记用户刚改过的标题要求;
- 需要你重复“继续”。
3. 压缩后摘要明显过短或只是占位
正常 summary 应该包含任务目标、已完成步骤、关键文件、未完成动作。
如果只有静态 marker,那就不是摘要。
对用户的临时建议
在修复完全落地前,跑长任务时可以这样降低风险。
1. 关键节点写文件
不要只依赖会话上下文。
每完成一篇文章、一个发布动作、一个结论,写入:
- research card;
- daily memory;
- TODO 文件;
- 发布日志;
- git commit。
文件比上下文压缩更可靠。
2. 长任务分段提交
例如每 1-3 篇文章 commit 一次,而不是全部做完再提交。
3. 使用稳定 auxiliary provider
如果压缩摘要经常失败,优先给 auxiliary/compression 配置更稳定的 provider。
4. 保留 session / tool logs
压缩丢摘要时,日志和文件是恢复上下文的救命绳。
和 DeepAI API 中转站的关系
如果你用 DeepAI API 中转站作为 OpenAI-compatible provider:
Base URL: https://api.deepai.wang/v1
API Key: 你的 DeepAI Key
Model: 以 DeepAI 控制台为准
需要区分两件事:
1. 主任务模型调用; 2. auxiliary compression summary 调用。
如果 Hermes 的 auxiliary compression 也走某个 OpenAI-compatible provider,那么连接稳定性、长响应处理、超时、代理链路都会影响压缩成功率。
DeepAI 可以统一 API 入口,减少多 provider 配置复杂度;但如果网络链路或上游响应中途断开,Hermes 仍然需要在 compression 层做好 retry / fallback。
所以这篇的重点不是“换 provider 就解决”,而是:
压缩摘要失败不能第一次就丢上下文
FAQ
incomplete chunked read 是什么?
通常表示 HTTP 响应还没完整传完,连接就提前关闭了。长响应、streaming、代理链路中比较常见。
为什么不直接插入 fallback marker?
可以插,但应该作为最后兜底。第一次遇到 transient 网络错误就丢掉中间上下文,会让长任务静默失忆。
context compression 失败会让任务崩溃吗?
不一定。issue 中的问题是任务继续运行,但中间 turns 被移除且没有真实 summary,导致后续上下文质量下降。
最好的修复是什么?
识别 premature response / streaming close 为 connection error,增加 1-2 次短重试,并在 auxiliary.compression.provider: auto 时走 fallback provider。
DeepAI API 中转站能避免这个问题吗?
DeepAI 可以作为统一 API 入口,但 Hermes compression 层仍需处理网络中断、长响应失败和 provider fallback。两者不是同一层问题。
总结
#18458 的真正教训是:
长任务最怕的不是一次请求失败,而是失败发生在“记忆压缩”这一刻。
如果 summary 生成被 incomplete chunked read 打断,Hermes 不应该马上把中间对话删掉并插入静态占位。
更稳的策略是:先重试,再 fallback,最后才 static marker。
因为对 Agent 来说,压缩摘要不是装饰品,而是长任务继续工作的记忆桥。