Agent说“完成了”——对不起,骗你的

17 阅读8分钟

电脑上,Agent 报告已完成,旁边实际运行的页面却仍在报错

快到下班时间,你把一个反复报错的小问题交给 Agent:“帮我修好,跑一下测试,确认没问题。”它忙了几分钟,列出修改过的文件,最后回复:“已修复,测试通过。”你松了口气,打开页面试了一下——熟悉的报错又弹了出来。

你只好重新翻记录:它改的是正在使用的那份配置吗?测试真的运行了吗?通过的测试,检查过这个报错吗?原本想省下的时间,又花在了追问和排查上。更让人发愁的是,下次看到“完成了”,还敢不敢直接相信?

如果用过 Agent 写代码、改配置,你可能熟悉这种落差。它确实做了不少事,回复也很具体,但从“做过这些操作”到“解决了你的问题”,中间还缺一步核对。命令执行成功,可以证明这条命令跑完了;要确认任务完成,还得看它操作的对象是否正确、该做的检查是否做了,以及结果是否满足你的要求。

Agent 可能误解了目标,也可能把没有验证过的结果说得过于肯定。让它再保证一次,仍然回答不了这些问题。我们需要能回头查的记录:改了什么、检查了什么、还有什么没有确认。

这正是 dsh-completion-guard 想解决的问题。它在 DeepSeek Harness(DSH)里保存任务要求,再用工具结果逐项核对。对能够检查的任务,它会生成一份“完成证书”,记录哪些证据支持了完成结论。

执行结束了,任务却没完成

假设任务是:只修改项目 A 的配置文件,把 activation 设为 always,运行项目自检,然后重新读取文件,确认设置已经保存。

下面这些情况都可能产生一条“成功”的工具结果:

  • 改对了字段,但文件属于项目 B;
  • 改了项目 A,却没有运行要求的自检;
  • 自检通过了,但检查的是修改前的缓存;
  • 写入命令成功,却没有重新读取保存后的文件;
  • 要求已经改了,却仍拿之前的检查结果证明任务完成。

问题不在于 Agent 一定会撒谎。更常见的情况是,它把“我执行过一些合理动作”误以为是“任务完成”。长任务一旦经历多轮修改、恢复或上下文压缩,这种近似尤其容易发生。

把“完成了”变成一件可以核对的事

dsh-completion-guard 把任务整理成一张检查表:要做什么、不能做什么、怎样才算完成。后续要求有变化,也会保留修改记录。这样,会话被压缩或恢复后,Agent 仍能查到当前应该遵守哪些要求。

修改文件、运行测试和执行 Git 命令,仍由 DSH 原有的工具完成。Guard 核对已经保存的调用记录和结果:改的是不是指定文件,跑的是不是要求的测试,结果是不是来自这次操作。如果要求修改后重新读取文件,它还会检查是否有这一步,以及读到的内容是否符合要求。

例如,你只要求“运行测试并报告结果”,那么测试确实跑完、Agent 如实说明失败,也可以算完成这项要求。如果你要求“修复到测试通过”,就必须真的通过。文件已经改好、只是还没重新读取确认时,应补上读取检查,而不是再改一遍。这里的判断只适用于插件支持的测试和文件操作。

完成认证流程:任务合同约束持久化证据,匹配后签发证书,最后才允许完成声明

可以把这套关系理解成四个连续问题:

  1. 当前有效的要求是什么?
  2. 哪些操作和结果已经保存在 DSH 会话记录中?
  3. 这些结果是否逐项证明了对应要求?
  4. 重新读取这些记录,还能得出同样的完成结论吗?

完成证书必须能根据保存的记录重新核验。会话恢复后,如果找不到相应证据,就不能继续沿用“已完成”的结论。图中展示的是这条认证流程;对于暂时无法认证的调查或解释,Agent 仍可如实回答,并说明哪些部分尚未得到验证。

接入 DSH,但不接管 DSH

DSH 仍然负责任务目标(Goal)、待办事项(Todo)、会话恢复、上下文压缩、权限与工具执行。dsh-completion-guard 不替代这些能力,也不把自己包装成新的沙箱。

Guard 根据会话记录恢复检查表,并在核对证据后判断任务能否标记完成。如果希望它检查 DSH 的 Goal 完成操作,需要在新会话中执行 /context-guard on。自动记录要求不等于开启这项检查,而且这项检查只覆盖插件接入的完成入口,不能保证拦住 DSH 内部的所有状态修改。

要求和工具结果来自会话记录。如果另外启用了发布或重启保护,相关操作还会留下单独的私有记录;保留会话时,也要一并保留这些记录。记录缺失或损坏,插件就不能确认相应操作已经完成。它也不会因为开启了保护,就替用户授权新的操作。

对“解释这段配置,再修改指定文件并运行测试”这样的请求,解释完了,后两件事仍要做。用户说“继续”,是继续当前可以开展的工作,不是新增任务。如果某项收益需要长期观察,可以明确说明;但已经要求现在运行的测试,不能只靠一句“留待以后”跳过。

独立的 DSH 实现

这个项目移植了 Codex Context Guard 中关于任务合同与完成认证的确定性思路,但不是把 Codex 插件换一个名字重新打包。

Codex 和 DSH 保存会话、调用工具和加载插件的方式不同,因此 DSH 版本用 TypeScript 单独实现。两个项目在部分任务判断规则上保持一致,并通过同一组案例检查结果是否一致;这不代表它们在所有工具和操作系统上都有相同表现。安装、缓存和发布也各自独立。

现在可以怎样试用

安装前,先按兼容性说明检查运行环境,再查看最新发布。使用 DSH 网页界面时,可将插件安装到 Web 配置中:

dsh plugin --profile web add dsh-completion-guard

装好插件后,还要按快速开始完成“宿主锁”检查,确认插件匹配你实际使用的 DSH 安装和配置。检查结果应明确显示 supported,不能只看命令有没有报错。涉及配置修改时先备份;具体步骤和重启顺序以文档为准。完成后,在目标会话中执行:

/context-guard on
/context-guard status

默认的 opt-in 模式需要在每个会话中手动开启。always 模式则从新会话的第一条消息开始自动记录要求,包括只有图片或附件的消息;空白会话不会被提前写入内容。初次使用可以先保留默认模式,用 status 查看是否开启,用 diagnose 查看哪些要求还缺证据。

如果安装过旧包 dsh-context-guard,不要让它与新包同时加载。升级前,按兼容性说明确认旧会话和记录该如何处理。各平台实际验证过哪些功能,可查看发布附件;自动化测试通过、安装成功和正在运行的 DSH 已加载插件,是不同的检查结果。

适用范围

dsh-completion-guard 适合要求明确、能用工具结果逐项检查的任务,例如指定文件修改、测试命令、构建产物、Git 状态检查,或修改后重新读取文件确认结果。任务越长、要求越多、越可能经历恢复或压缩,完成认证的价值越明显。

代码是否符合业务需求,研究结论是否可靠,设计是否好看,仍需专门的检查和人工判断。插件能核对的操作见兼容性文档。例如,要证明“新建了文件”,还得有证据说明它原先不存在;要证明插件已经生效,也不能只看安装目录里有没有文件。

Guard 保存要求和必要的检查记录,不复制完整对话、工具输出或文件内容,也不保存凭据和图像本身。

Guard 让“完成了”多了一步核对:能检查的,就拿出对应记录;暂时检查不了的,就说明结果和限制。