CLI Agent 的长任务为什么越做越不可靠
CLI Agent 可以连续工作数小时,也可以容纳几十万 token。任务拉长以后,它仍会忘记早期约束,重复已经否定的方案,或者在局部测试通过后提前宣布完成。
这类现象常被叫作“降智”,但模型参数并没有在会话中逐步变差。真正改变的是 Agent 下一步依据的信息。聊天、代码片段和工具输出不断累积,旧结论留在历史里,仓库却已经被前面的操作改动。模型看到的上下文会逐渐偏离项目此刻可验证的状态。
长任务的可靠性因此取决于两件事。Agent 行动前拿到的项目状态要足够准确;一个错误还没有经过测试或其他外部证据检查时,不能继续影响太多后续操作。后一个量可以称为“未验证跨度”。任务持续多久并不直接决定风险,真正危险的是错误状态在多步行动中没有被发现。
长窗口不等于同样有效的工作记忆
研究最先发现的是位置信息利用不均。《Lost in the Middle》在多文档问答和键值检索中移动相关证据的位置。模型通常更容易利用输入开头和末尾的信息,证据落在长上下文中部时,表现会明显下降。实验对象包括明确支持长上下文的模型。
位置效应无法解释全部退化。《Same Task, More Tokens》保持问题不变,只添加不同长度、类型和位置的填充文本。五个模型都在远低于标称窗口上限时出现推理退化。《Context Length Alone Hurts LLM Performance Despite Perfect Retrieval》进一步控制了检索:即使模型能够逐字取回全部相关证据,五个开源和闭源模型在数学、问答及编码任务上的表现仍随输入增长下降 13.9% 到 85%。研究者把无关内容换成空白,屏蔽无关 token,或者把证据放到问题前面,退化仍然存在。
13.9% 到 85% 的跨度来自不同模型与任务的受控实验,不能当成某个 CLI Agent 的预期降幅。这组实验能支持的结论是:上下文仍在标称窗口以内,也不代表推理质量保持不变;检索到了正确文件,也不代表模型能在长输入中同样好地完成推理。
无关信息还会增加一层干扰。ICML 2023 的 GSM-IC 研究向小学数学题加入不影响答案的句子。各种提示方法都会受影响,在原本能答对的问题中,不超过 18% 能在所有干扰类型下持续答对。加入“忽略无关信息”的指令有所帮助,但没有消除问题。
代码场景也出现了“更多上下文未必更好”的结果。《Repoformer》研究仓库级代码补全,让模型判断一次补全是否需要跨文件检索。大量检索上下文没有带来帮助,部分还会降低表现。Repoformer 会在判断检索无益时拒绝加入上下文,作者报告这种拒绝判断在 80% 以上的实例中正确。Repoformer 研究的是代码补全,还不是会修改仓库和运行测试的 Agent;可支持的工程结论仅限于:代码上下文也应按需进入,窗口足够大并不构成无条件加载的理由。
前面的长上下文实验还不是完整的软件工程轨迹。数学题里的干扰句与真实仓库中的日志、需求变更并不相同。把受控实验外推到 CLI Agent 时,还需要多轮对话证据。
对话会保存旧错误,也会保存无关话题
《LLMs Get Lost in Multi-Turn Conversation》比较了单轮完整指令与多轮逐步补充指令。研究覆盖十五个模型、六类生成任务和二十多万段模拟对话。多轮条件下的平均表现下降 39%。论文把主要损失归为可靠性下降:模型在信息不足的早期先做假设,过早生成方案,后来即使获得新信息,也容易依赖先前路径而没有恢复。它测的是模拟的多轮任务,39% 不能直接套到真实代码仓库。
2026 年预印本 MT-OSC更接近“中途岔开话题”的问题。研究者在 HumanEval、BFCL、Spider 和 GSM 等任务中插入 diversion turns。六个模型的基线在相关但无用的话题岔开后平均下降约 7.88%;重复旧内容或加入空话的下降约为 2.5% 到 3%。岔开轮次增加时,退化继续扩大。选择性凝缩历史最多减少了十轮对话中 72% 的 token,并在多数测试中保持或提高表现。
这是一篇尚未经过正式同行评审的预印本,实验也以合成多轮任务为主。它提供了目前最直接的方向性证据:无关轮次可能影响编码及工具调用任务;它没有证明一次简短插话必然造成可测损失。
另一篇 2026 年预印本《Do LLMs Benefit From Their Own Words?》发现,选择性移除历史中的 assistant 回复,许多轮次的质量并未下降,累计上下文最多缩短十倍。一些任务反而改善,因为模型不再沿用自己先前写下的错误参数、幻觉或风格。容量之外还有历史承诺:模型生成过一个结论以后,后续输出会以它为条件。
ACL 2026 的 Agent 记忆研究把这个问题扩展到跨任务记忆。研究者比较固定记忆、全部写入、粗粒度筛选和用 ground truth 严格筛选四种策略。无条件写入历史在四个被测 Agent 上都劣于固定记忆,严格筛选后的结果最好。论文将其中一部分差距归因于错误传播,并提醒:一条轨迹表面成功,也未必适合作为后续相似任务的示范。这项实验主要使用 GPT-4o-mini,研究 episodic memory 而非单次 CLI 会话;它仍然给出一条直接警告——失败轨迹可以留作诊断证据,不能未经验证就进入可检索的成功记忆。
可以把长任务中的活跃上下文写成一张工程记账表:
是长期指令, 是当前需要的代码与规格, 是截至第 步的对话历史, 是工具调用和测试输出。这个式子不是论文中的模型,也不能计算准确率。这张记账表只提醒我们:每加入一段历史,模型下一次推理的条件就发生了变化。
无关对话由此产生三种成本。第一种是容量成本,它挤占原本可以放代码和测试证据的位置。第二种是选择成本,关键约束更容易被埋在长历史中。第三种是路径成本:旧回答即使错误,也可能继续成为下一轮的前提。临近窗口上限时,系统还会触发压缩;摘要需要决定保留什么,又增加了遗漏细节的可能性。这三种成本可以从前述受控实验和条件生成过程推出,不能据此计算“一次天气提问损失多少 coding 能力”。
长任务首先是状态控制问题
可以用一个状态控制框架串起前面的实验结果。这个框架用于分析工程风险,不是对某款 CLI 内部实现的逆向推断。
CLI Agent 并没有持续读取一个完整、无歧义的项目状态。第 步时,仓库和正在运行的进程处于真实状态 。Agent 通过文件内容、终端输出和用户消息得到观察 ;CLI 的 harness 再从事件历史与外部记忆中挑选内容,组成这次模型调用实际看到的上下文 :
是任务目标, 是计划或进度文件等持久状态。 表示 harness 怎样选择、压缩并排列信息; 是模型在当前上下文下生成行动的条件分布; 是执行命令或修改文件后,真实环境发生的变化。这组式子只记录控制关系。
这张图景解释了为什么“模型很强”仍不足以保证长任务成功。模型依据 行动,并不能直接访问 。如果摘要漏掉一个约束,或者旧日志仍在描述已经修复的状态,模型拿到的就是项目状态的有损表示。上下文越长, 要做的选择越难。前面几项长上下文研究测到的退化,可以看成这种状态重建误差在模型侧的表现。
行动还会改变下一步的输入。一个错误补丁会制造新的报错,错误解释又可能进入进度文件。Microsoft 的多轮实验和 ACL 2026 的记忆研究都观察到了这种路径依赖:模型先前生成的内容会成为后续条件,未经筛选的错误经验会传播。长任务因此不是把同一道题多算几步。每次动作都会改变后续观察和决策条件。
可以用一个极简计算理解“局部很强,整体仍不稳”。假设一项任务包含 个决定性步骤,每步独立做对的概率都是 ,中间也没有发现和恢复错误的机会,那么全程正确的概率是:
即使 ,连续 50 步全部正确也只有约 36.4%。真实 Agent 的步骤并不独立,动作之间存在依赖,测试也可能发现并修复错误,所以这个数字不能当作成功率预测。这个计算只揭示一个结构事实:单步准确率的微小缺口会随任务长度累积。仅提高模型的局部能力,无法自动消除长轨迹风险。
我认为更值得监控的量是“未验证跨度”:从上一次可信检查开始,Agent 连续执行了多少个会改变结果的动作。这里的可信检查可以是回归测试、编译器、浏览器操作,也可以是人工确认的业务约束。跨度越长,错误越可能进入后续状态。反过来,一项总时长很长的任务,只要每个增量都能被检查并能回退,可靠性未必持续下降。一个只有十分钟的数据库修改,如果中间没有备份和验证,也可能拥有很长的有效风险跨度。
因此,我所说的“上下文工程”不只是删 token。更重要的工作是决定当前哪一份状态具有权威性,哪些内容只是历史事件,哪些结论已经通过外部证据。对话记录适合做审计日志,不适合直接充当项目的当前状态。把整段日志反复交给模型,相当于要求模型在每一步重新推导“现在究竟是什么情况”。
记忆写入也应被视为一次状态提交。模型的推测、失败原因和已经验证的事实需要不同类型;来源及验证时间也要保留。否则,记忆系统只会把上下文污染从一次会话延长到后续会话。
用户应该怎样在长任务中插话
OpenAI 的提示与交互文档区分了两种行为。Steer 会把新消息加入当前运行,用于改变方向或补充缺失信息;Queue 等当前运行结束后再处理。Codex 的长任务文档又明确建议:相关上下文和约束可以继续发到主任务;只想询问状态或要求解释时,使用 side conversation,避免打断主任务。
实际交互可以按信息是否改变当前实现来分流:
| 用户的新消息 | 放在哪里 | 原因 |
|---|---|---|
| 新的报错、测试结果、必须遵守的约束 | 当前任务,Steer | 它们会改变下一步实现 |
| 当前工作完成后的相关追加项 | Queue | 保持本轮验收边界稳定 |
| 状态询问、概念解释、临时的无关问题 | /side、/btw 或另一个终端会话 | 不让问答进入主任务历史 |
| 目标已经改变 | 新任务,或先重写规格与验收条件 | 旧目标和新目标同时存在会制造冲突 |
一句“顺便问一下”未必足以让任务失败。风险主要来自反复岔开话题、粘贴长资料,或者在不更新规格的情况下持续改变目标。这些内容会累积在同一条历史中。
把长任务状态移出聊天
Anthropic 的长任务 harness 文章报告了一组内部实验:自动压缩没有让他们测试的 Agent 稳定完成跨多个上下文窗口的应用开发。文章描述的失败包括一次实现过多功能,以及后续会话读取已有代码后提前宣布完成。由于原始轨迹和完整对照条件没有公开,这些结果不能外推为所有 Agent 的规律。
他们没有继续增加总提示,而是把状态写到环境里。第一个 Agent 创建完整功能清单、claude-progress.txt 和启动脚本。后续 Agent 每轮只实现一个 feature,开始时读取进度与 Git 历史,先跑基础 smoke test;结束时提交可工作的状态并更新进度。功能只有经过测试以后才能从 failing 改成 passing。
OpenAI Cookbook 的 ExecPlan/PLANS.md 方法把计划定义为 living document,并持续维护 Progress、Surprises & Discoveries、Decision Log 以及 Outcomes & Retrospective。执行命令和可观察结果也要写入,使下一名 Agent 只读取计划和当前工作树就能继续。公开材料提到一次超过七小时的单提示任务,但没有提供对照数据,不能据此判断这种方法优于其他状态管理方案。
外部状态的价值在于把事实与聊天分开。代码现状由工作树和 Git 记录,正确性由测试结果记录,计划只保存目标、已确认决定和下一步。对话即使被压缩或重置,Agent 仍能从可检查的材料恢复,而不必相信上一轮自然语言中的“已经完成”。
一份最小交接文件可以使用这些字段:
| 字段 | 应记录的事实 |
|---|---|
| Goal | 当前结果,以及明确不在范围内的事项 |
| Acceptance | 可以执行或观察的完成条件 |
| State | 分支、提交、已改文件和当前运行状态 |
| Evidence | 实际运行过的命令、测试结果或截图 |
| Decisions | 已确认的选择及其理由 |
| Risks | 尚未解决的问题和已经失败的方法 |
| Next | 下一项可独立验证的工作 |
交接文件不应复制整段聊天和完整日志,否则外部状态也会被低价值信息淹没。
上下文应该有生命周期
Anthropic 的上下文工程文章建议寻找能产生预期行为的最小高信号 token 集,并介绍压缩、结构化笔记和子代理。这是设计主张,不是最优性的证明。该主张值得测试,是因为前述研究已经观察到长输入和无关内容可能降低表现。压缩可能删掉后来才显得重要的细节;笔记把目标和进度存到窗口外;子代理则把探索产生的长日志隔离在另一个窗口。具体收益仍取决于任务和模型。
Codex 的产品文档把这类现象称为 context pollution 和 context rot,并建议用子代理隔离探索日志。产品文档能够确认 Codex 当前怎样设计子代理,不能证明这种设计在任意任务上优于单 Agent。是否隔离某项工作,仍要比较主线程减少的干扰和多代理增加的协调成本。
因此,长任务不应只在“继续聊”和“全部清空”之间选择。可以采用一套有触发条件的上下文生命周期:
- 启动时读取仓库规则、目标、验收条件和上一轮交接,随后运行基础测试。
- 当前窗口只处理一个能独立验证的增量。代码和资料按需读取,避免一次载入整个仓库。
- 工具输出过长时,保存证据位置和结论,不把原始日志永久留在主线程。
- 每个增量完成后运行相关测试,把结果写入进度文件,再提交可回退的 Git 状态。
- 上下文接近上限但任务仍连续时,先压缩;摘要要保留约束、未解决问题、修改文件和验证命令。
- 目标切换、同一错误反复出现,或者主线程已经被旁支污染时,写好 handoff 后开启新任务。
- 高风险节点用干净上下文的 reviewer,按原始验收条件检查,不把实现 Agent 的自评当成证据。
这里没有一个适用于所有模型的固定 token 阈值。是否重置取决于两项损失的比较:继续保留历史会增加多少干扰,重置又会丢掉多少尚未外部化的有效状态。切换成本也要计算在内。只有前一项超过后两项时,重置才有正收益。这个阈值属于具体模型、CLI、仓库和任务的组合,只能通过本地评测确定。
验收条件决定 Agent 什么时候停
开放式 review 没有停止条件。模型可以继续生成新的候选缺陷,但候选集合变大不等于代码更接近正确。一个问题进入缺陷清单以前,至少要找到可达路径和被违反的契约;严重度还要与实际影响和授权范围相符。
任务没有验收条件时,Agent 只能根据对话判断什么时候停。“继续深入”会让代码审查范式持续占据上下文,生成新问题通常比返回空报告更容易。上下文随之增长,已经排除的猜测还可能被重新包装。
完成条件应先写成外部信号。修复需要复现步骤和回归测试;迁移需要编译结果及兼容性检查;前端任务需要真实浏览器路径。测试可能不完整,但外部反馈至少能让 Agent 根据程序结果修正行动,而不是相信自己刚写出的总结。
TACL 2024 的自我纠错综述没有发现仅凭模型自身反馈就能稳定纠错的普遍证据,少数天然适合自检的任务除外。获得可靠外部反馈以后,自纠错通常更有效。对 CLI Agent 而言,测试和编译器比一句“再仔细检查”更接近可复核的完成信号。
一套可以直接采用的 CLI 工作协议
启动
读取 AGENTS.md / CLAUDE.md、规格、进度文件和 git log
启动环境,运行基础 smoke test
选择一个尚未通过的验收项
执行
只处理一个可独立提交的增量
先确认完成条件,再修改代码
运行最小相关测试,读取失败信息后修复
必要时补端到端验证
收尾
保存实际测试证据
提交可工作的 Git 状态
更新决定、风险和下一步
上下文切换
相关纠正留在主任务
无关问题走 side conversation
目标变化时先更新规格,必要时开新任务
重置前写 handoff,重启后先读状态并跑 smoke test
最终检查
使用干净上下文的 reviewer
按原始验收条件和真实用户路径检查
不以 Agent 的“已完成”作为完成证据
目前能确认到什么程度
现有证据不能给出“CLI Agent 到第 N 轮会损失多少能力”的固定比例。模型、任务和上下文组成不同,结果会变化。能够确认的是风险方向:长输入会降低部分模型利用关键信息的稳定性,多轮历史会延续早期错误,无关轮次还会增加干扰。
对 coding 任务,控制这种风险不能只靠扩大窗口或反复总结。当前状态应由工作树、测试结果和经过确认的决定共同给出。每完成一个会改变结果的增量,就尽快用外部证据检查;一旦目标改变或主线程已经被旁支污染,先写交接,再开启干净上下文。
长任务真正需要缩短的是未验证跨度。对话可以很长,只要 Agent 能从项目中恢复准确状态,并在错误进入后续步骤以前发现它。反过来,即使任务只做十分钟,只要连续改动没有验证,也可能很快偏离原目标。
相关文章
- Agent 的“状态工程”到底在解决什么?:上下文窗口不能自动成为项目的权威状态。State Engineering 真正要解决的是:怎样重建此刻仍然有效的事实,并把当前决策需要的部分交给 Agent。
- 中文“AI 味”是怎样被训练出来的?:为什么多种模型会反复写出相似的中文?本文从训练数据和偏好选择追溯原因,也说明标注外包、跨模型蒸馏的公开证据到哪里为止。
- Skill 到底有没有用?一次没有提升的编程基准实验:公开 Skill benchmark 的结论并不一致。本文对照 SkillsBench、SWE-Skills-Bench 和困难编程任务实测,说明没有提升时应怎样解释结果。