AI Agent开发中,会话记录(谁的指令、Agent的假设、调用了哪些工具、在哪一步出错)是可复用的工程证据,不应随会话结束而丢弃。
我反复看到同样的失败以不同的形式出现。一个 Agent 完成了一项任务,却没有运行正确的验证。另一个会话发生了漂移,因为我的第一条指令太过模糊。第三个会话则暴露出一个缺失的工具原语——直到 Agent 用 shell 粘合剂把它拙劣地伪造出来之后才发现。这些事件在发生时都不神秘。神秘的是为什么我只能一次一个会话地重新发现它们。
证据其实早已存在。OpenCode 拥有完整的对话记录:我问了什么、Agent 假定了什么、它调用了哪些工具、在哪里停了下来、在哪里纠正了它,以及上周犯的哪个错误又重复出现了。但任务结束后,那些证据大多变回了滚动缓冲区。我可能记得当时的痛苦,也许会在 AGENTS.md 里写下一条规则,也许不会。会话本身从工程流程中消失了。
这种感觉开始变得不对。代码会被审查。日志会被搜索。CI 失败会被归档。生产事故会做复盘。但产生代码、测试运行、糟糕的部署检查或缺失的验证步骤的对话,通常被视为可丢弃的。对于 AI 辅助开发来说,那段对话不是可丢弃的。它是人类-Agent 系统的日志。
我们不审查的那部分
当一个 pull request 出问题时,我可以检查 diff。当部署出问题时,我可以检查日志和指标。当测试失败时,我可以检查失败的命令和输出。这些工件枯燥、持久、可搜索。它们给下一次调试提供了比记忆更可靠的东西。
Agent 会话则不同。它们充满了有用的证据,但很少被视为值得审查的工件。常规审查在代码层面就停止了:补丁编译了吗,测试通过了吗,diff 看起来合理吗?这错过了代码之上的一层——许多 AI 失败实际上是从那里开始的。
指令可能描述不够充分。Agent 可能在读取足够上下文之前就进行了编辑。任务可能需要全局搜索,但对话只提到了一个文件。验证边界可能错了:Agent 检查了命令是否返回成功,而不是返回的数据是否意味着成功应该意味着什么。工具缺口回头看可能很明显,因为 Agent 一直在重新创建相同的脆弱 shell 循环,但没有人停下来问那个循环是否应该成为一个真正的原语。
这些不是代码审查的发现。它们是会话审查的发现。只有把对话当作执行轨迹来读,你才能看到它们。
会话即遥测
一旦我开始把会话视为遥测,有用的问题就变了。不再是:这个答案好吗?这个问题太局部了。一个答案可以很好,而围绕它的流程却坏了。
更好的问题是:什么一直在发生?
如果我纠正同一条指令三次,那就不再是 prompt 问题了。它是一条缺失的规则。如果一个 Agent 反复发明带有 sleep 和 curl 的轮询循环,那不是一次性的 bash 错误。它是一个缺失的工具。如果每个大任务都以我说"你应该也检查一下代码库的其余部分"结束,那不是一次不幸的审查评论。它是一个缺失的检查清单步骤。
这和工程师在其他地方已经做的转变是一样的。一次失败的请求是一个错误。一系列失败的请求是一个 SLO 问题。一次 flaky 测试很烦人。一簇 flaky 测试是关于架构、隔离或所有权的信号。一次糟糕的 Agent 会话只是一次糟糕的会话。一种重复的 Agent 会话形态是流程遥测。
困难的部分是人类不擅长记住这些证据。我对一次会话的情感轮廓的记忆远比实际事件序列的记忆好得多。我记得我很沮丧。我不能可靠地记得第一个错误是指令、Agent 的捷径、缺失的工具,还是一个看起来完整但目标错误的验证步骤。如果我想改进流程而不是仅仅抱怨它,我需要转录。
所以我写了 opencode-session-reflection,一个小的 OpenCode 插件,它添加了一个工具:session_reflection。
安装路径故意做得很无聊:
{ "plugin": ["opencode-session-reflection"] }
重启 OpenCode,然后让它审查最近的会话。注册的 session_reflection 工具是主要接口;/session-review 只是一个可选的本地开发辅助工具。插件通过 OpenCode API 读取会话元数据和转录,通过 /experimental/session 进行跨项目发现;它从不直接访问 SQLite。
分析 prompt 聚焦在三个类别。
第一:开发者到 Agent 的沟通差距。任务框架是否很差?范围是否模糊?我是否没有说明我想要讨论还是实现?我是否省略了我当时实际知道的验收标准或验证要求?
第二:反复出现的 OpenCode 错误。Agent 是否在读取上下文之前就进行了编辑?它是否在没有验证的情况下声称完成?它是否修复了一个报告的问题而没有在其他地方搜索相同模式?它是否忽略了项目规则、过度构建或提前停止?
第三:插件、技能、命令或规则的机会。这是我最重要的类别。目标不是把每个恼人的东西都变成自动化。目标是找到反复出现的摩擦点,在那里 OpenCode 可以观察到一个可靠的触发器并采取安全的行动。有些失败应该变成规则。有些应该变成技能。有些应该变成斜杠命令。少数值得做一个插件。
插件将选定的会话 ID、哈希化的目录路径、消息计数、转录计数、工具调用计数、提示哈希和保存的报告路径写入 OpenCode 配置目录。脱敏的审计元数据保留在本地,不会被插件上传。它不在审计清单中存储原始转录或会话标题。选定的会话证据可能会到达 OpenCode 中配置的模型提供商。
保存的 Markdown 报告与脱敏审计清单不同:它们包含提供的分析,可能保留模型选中的摘录。保存的 Markdown 报告可能包含敏感摘录;用户控制其保留和删除。将报告和本地审计元数据都视为私有的。
这个边界很重要。一个会话审查工具不应该悄悄变成第二个遥测产品。要点是帮助开发者检查他们自己的本地流程,而不是把他们的错误上传到其他地方。
为什么这属于插件生态系统
显而易见的用途是个人用途:在过去几个会话上运行它,看看自己一直在做什么错事。这已经很有用了。但更有趣的用途是在插件设计上游。
我最近写了 opencode-waitfor,因为我一直在看 Agent 用脆弱的 shell 循环伪造就绪检查。这个模式很具体。工具边界很清楚。URL、端口或命令应该被轮询直到条件成立或超时返回最后观察到的状态。这是一个好插件,因为重复的行为是可观察的,而替换原语比它所取代的破碎行为更小。
但并非每个反复出现的失败都那么干净。有些更适合用 AGENTS.md 规则处理。有些需要技能,因为真正的工作是推理纪律,而不是 API 访问。有些只需要一个斜杠命令来打包已知的提示和工具调用序列。有些根本不应该自动化,因为触发器太模糊或动作太危险。
这就是为什么我希望反思步骤询问可行性和价值,而不仅仅是恼人程度。OpenCode 能否在不进行脆弱的转录解析的情况下检测情况?所需数据是否可以通过 SDK 获得?假阳性是什么?现有插件或命令是否已经覆盖了大部分需求?这会帮助其他 OpenCode 用户吗,还是只是我私人工作流中的一个化石?
好的 Agent 工具应该来自反复出现的证据,而不是想象。否则太容易为只发生一次的问题构建令人印象深刻的小工具,或者构建出自动化了本应保留在人类批准之下的部分的工具。会话审查是一个过滤器。它把"这很烦人"变成"这发生了四次,触发器是可见的,安全动作是狭窄的,价值是真实的。"
从一个反复出现的失败开始
如果你使用 OpenCode,有用的实验很小。安装插件,对过去几个会话运行一次审查,寻找一个反复出现的失败。不是十个。是一个。
也许它是一种沟通习惯:你一直在发送描述不充分的请求,然后在两轮之后纠正 Agent。也许它是一种验证习惯:Agent 一直在检查命令是否运行了,而不是正确的事情是否发生了。也许它是一个工具缺口:Agent 一直在合成相同的脆弱 shell 模式,因为不存在更好的原语。挑选最清楚的一个,决定它值得什么样的工件。
如果它适用于未来的会话,写一条规则。如果它是一个推理工作流,写一个技能。如果它是一个反复出现的用户调用流程,写一个命令。如果它是一个 Agent 一直在拙劣伪造的狭窄、可观察的操作,写一个插件。
要点不是让 Agent 变得自省。要点是让工作流变得可观察。一旦会话成为日志,重复的错误就不再是逸事了。它们成为工程输入。