pstack 拆解 22 · 自我改进:改仓库、改技能、生成入口
同一个错犯第二次,就该把它编码进结构,而不是再提醒一次。这一篇讲同一个想法的三个尺度:改仓库、改技能、生成你自己的入口。
自我改进的三个:correct、reflect、automate-me
这三个是同一个想法的三个尺度:系统要自己变好,靠的是把教训编码进结构,而不是靠人反复教。 它们一个改仓库,一个改 skill,一个生成你自己。
correct
correct 改的是仓库。它对付的是"你反复纠正 agent 同一件事"。一次纠正只帮一次,而一次结构改动帮所有未来的会话,所以它要把"反复纠正"变成"结构强制":系统变好,靠的不是你记得提醒,而是让错的路根本走不通。它按一个固定的强度顺序修:先架构,再类型,再一个报错就说清正确写法的 lint,再测试,把文档放最后,因为文字是唯一一种被跳过也不会失败的东西。它有一个判断前提,值得原样抄下来:
假设每一个贡献者都是一个只看到自己打开的文件、照抄最近一个例子、走最短能编译的路的 agent。
所以你要把仓库设计成:从一个文件里做对的事,对整个仓库也是对的。
它先找出错误类。素材是最近的提交、回退、review 评论、agent 指令文件,以及那些解释 workaround 的注释。它把这些错误分组,一个类出现过两次才算数。
然后每一类在能奏效的最高层级上修。顺序是硬的。
- 用架构消掉它。 给每份状态一个所有者,每个任务一条支持的路。把内部藏起来,让错误的 import 直接失败。用手工同步的列表换成一个事实来源。删掉旧路和死代码,因为 agent 会照抄。
- 用类型拦住它,让坏状态写不出来。 如果坏代码还能编译,就加一条 lint 或 CI 检查,让它的报错点名该用的文件、类型或函数。如果这个模式已经很常见,就只在一次改动新增更多时才失败。
- 用测试。 修掉或删掉任何"所有被它调用的函数都返回空也照样通过"的测试。
- 写文档或规则,放最后,而且只给判断类的事。 一条规则被跳过时,不会有任何东西失败。
然后它修最高频的那几类,一类一个 commit,并且证明每个新检查在一个真实的过去错误上失败。同一条命令本地和 CI 都要跑。例外要写在出问题的那一行上,带上一个理由、一个到期日,和一个人的批准。
它最后维护一张规则表,放在 agent 指令文件里,把每条规则和强制它的东西配起来。当你又纠正它一次,它修掉这个错误并补上规则;如果这条规则本来就在、却没有东西强制它,那是一次重复,它要在同一次改动里把它修到最高层级。一条规则一旦对应的错误不可能再发生,就把它删掉。
reflect
reflect 改的是 skill。从一次会话里提炼教训,最大的风险是过拟合:一次怪异的会话,可能让你把一条只对那次成立的偏好写进每个未来的会话。所以它的难点不是提炼,是分清"一次轶事"和"一条规则",而且任何 skill 改动都要先给你看、等你批准,因为一次编辑影响之后每一个会话。你在一次会话之后觉得"这次花了太久",敲它。
它先定位当前会话的 transcript。每个 harness 的路径不一样:Cursor 在系统提示里给的 agent-transcripts/ 目录,Claude Code 在 ~/.claude/projects/<slug>/,Pi 在 ~/.pi/agent/sessions/--<slug>--/,Codex 按 payload.cwd 匹配。它只读当前工作区的会话,绝不跨项目全局扫描,因为那会读到无关项目的私密聊天。
然后它派三个并行 reviewer,各拿一个镜头:判断、工具、发散。三个都用 agent 模式,因为 reviewer 需要 MCP 访问去找上下文里提到的 ticket、聊天和可观测性记录,只读模式会把 MCP 剥掉。
结果交给一个合成器,排成三份:Accepted、Rejected、Backlog。在应用任何 Accepted 之前,它把完整的合成结果给你看,等你明确批准。它有一条很重要的克制:一次怪异的会话是一个轶事,不是一条规则,只有能改变未来某个决定的提案才值得接受。Backlog 项自动进你们的 devex 追踪器。它还有一步"结构性强制检查":任何一条如果用一个 lint、脚本、元数据标志或运行时检查来强制会更可靠,就从 Accepted 挪到 Backlog。
批准之后,它按路由字段决定谁来改:一行 bullet、一句收紧、一个过时事实的修正,它自己做;一个新 section、一个新模式表、超过十来行的实质编辑,交给 skill-authoring 流程(create-skill)跑它的起草、测试、迭代循环;如果问题是"这个 skill 该触发的时候没触发",那是一次描述优化;如果是新 skill,也走 create-skill,不许凭空发明形状。
automate-me
automate-me 生成的是你自己的 mode。工具应该适配使用者,而不是反过来:poteto-mode 是某个人的风格,你未必要一模一样。它从你实际怎么工作里把风格读出来,而不是让你描述自己,因为人对自己的习惯往往看不清。生成之后你保留 pstack 做底,在旁边得到自己的入口。
它先检查你已经有没有一个 <handle>-mode skill(在项目级或用户级的 skill 目录里,category 子目录也要找)。有的话,默认是更新,而更新模式会改掉后面的流程:只挖 skill 上次编辑之后的历史,只问"变了什么、缺了什么",在原地编辑,保住你没推翻的 section。
然后挖你的历史。它把每个 workspace 的 transcript 切成几片并行挖(比如最近两到四周切成三片,让每片有足够素材)。每个切片挖的是六类默认信号:回复偏好、委派习惯、验证姿态、代码和散文纪律、流程约定、元偏好。跨切片交叉验证:两片以上都看到的信号是高置信度,单片的弱信号通常直接丢掉。
挖完还要问你,因为它挖不到你还没展示出来的意图:它给你一两道结构化多选(每道 4 到 6 个选项),先问宽的,再跟着你选的追问。它明确说"不要一口气问二十个问题"。
然后把信号聚成 section(回复风格、自主度、先理解、subagent、散文与代码纪律、评审与验证、流程、skill),再用 create-skill 起草。起草有几条护栏:不要过拟合到一次对话(一个说法只出现一次、又被另一次推翻,那是噪声,要多次出现才成文);不要耍聪明(把别的 skill 内容重述一遍、发明比喻、给 agent 读者写"诗意"的散文,都是只有成本没有收益);引用,不要内联(你依赖的别的 skill 用路径引用,不要贴片段);最小化 section(只有你有一条具体的、非默认的规则时才加一节,"沟通要清晰"不算,"短段落,比较选项时用表格,只有条目真的并列时才用 bullet"才算);命名用"用户"或"人",不用作者的名字;不要强求对称。
最后它在一个 worktree 里提交、开 PR,不直接推 main。
这三个的分工记住一句就够:reflect 从一次会话改 skill,correct 改仓库让错误类回不来,automate-me 生成你自己的入口。
参考
原文都在 pstack 上游仓库(cursor/plugins):