“Knowing yourself is the beginning of all wisdom.” — Aristotle
每次和 AI 编程助手一起工作,我都会遇到同一个问题。纠正过的错误,下次会话照犯。不是模型笨,是结构性的记忆缺失。
举个例子。上周我纠正了模型一个错误,它道歉了,我接受了,我们继续工作。今天重新开始一个新会话,同样的错误又出现了。纠正过程就这样蒸发了。这不是一次性的问题,而是每次对话的常态。模型记住了当前的上下文,但记不住它之前犯过的错误,以及它是怎么被纠正的。
这让我想到,反思的最佳时机其实是错误刚发生的时候。不拖延,不换工具,不打断当前的工作流程。当认知平衡被打破时——模型犯错,用户纠正——元认知驱动的再平衡过程应该在冲突出现后的近期启动,但不能干扰原本的任务。这和我从认知科学里学到的机制类似,但我使用的 Vibe Coding 工具及其插件还没有这个能力。
我决定动手做一个,刚好是实践agent开发的机会,于是有了这个 Aristotle。
三条设计原则
设计 Aristotle 时,我给自己定了三个原则。
第一条,反思启动交给用户,但可以提醒用户。发现错误纠正的信号时,提醒用户启动 /aristotle,不要让用户主动去想"哎呀,这个错误应该记录一下"。用户可能专注在纠正复杂的错误中,而忘记了要反思,但完全的自动反思又有反思信息输入不完整的风险,如果用户还没有完成完整的纠正输入就开始反思,那反思很可能不彻底。
第二条,会话完全隔离。反思过程在后台的子会话里进行,主会话的上下文零污染,不会影响当前任务。此外,模型犯错时,用户情绪可能已经不耐烦了,这时候如果主流程还要等待一个反思任务,而无法继续主任务,用户体验会非常糟糕。隔离的另一个好处是,反思会话可以访问完整的对话记录,但不干扰当前的工作节奏。毕竟反思是模型的责任,不是用户的义务。
第三条,“人在回路”。生成的规则不经用户审批不落盘。AI 可能会把临时性的纠正误判为通用规则,或者把特殊情况当作一般规律。用户的判断是最后一道防线。
Aristotle 的实现
Aristotle 的核心是 5-Why 根因分析。从表面的错误开始,一层层往下问,找到真正的根本原因。比如模型输出了错误的代码,第一层问为什么,可能是误解了需求;第二层再问,为什么误解,可能是上下文信息不足;第三层,为什么不足,可能是用户没有明确说明某个约束条件。连问五次,往往能找到症结所在。
错误被分成 8 类:MISUNDERSTOOD_REQUIREMENT(误解需求)、ASSUMED_CONTEXT(假设上下文)、PATTERN_VIOLATION(违反模式)、HALLUCINATION(幻觉)、INCOMPLETE_ANALYSIS(分析不完整)、WRONG_TOOL_CHOICE(选错工具)、OVERSIMPLIFICATION(过度简化)、SYNTAX_API_ERROR(语法 API 错误)。分类不是目的,是为了让后续的规则匹配更精准。
规则分两层:用户级和项目级。用户级规则跟着个人走,项目级规则在团队内共享。具体的 scope judgment 机制是工程细节,这里就不展开了。重要的是,规则的分层让反思的成果可以在合适的范围内复用,不会过度推广或者局限在一个人的经验里。
oh-my-opencode 的后台任务天然支持隔离子会话。主会话触发一个后台任务,Reflector 在完全独立的环境里读取对话记录,做根因分析,生成规则建议。整个过程对用户透明,不会打断工作流。
顺利的实现过程
OpenCode 的 skill 体系加上 omo 后台任务的基础设施,让 Aristotle 的实现过程出奇地顺。只用了 3 个 commit。
第一个 commit 完整的 SKILL.md,394 行。我一口气写完整个协议,包括 Coordinator-Reflector 双层架构、5-Why 根因分析模板、Stop Hook 自动检测逻辑。Coordinator 只做轻量编排,收集 session ID、项目目录、语言这些元数据。Reflector 在完全隔离的后台会话里做重分析。这个设计从一开始就很清晰,没有反复调整。
第二个 commit 是测试脚本。37 个静态断言加上 E2E live test。测试覆盖了从触发机制到规则生成的完整链路。写测试的时候发现了几个边界情况,比如空对话记录、多轮纠正的场景,都在 SKILL.md 里补充了说明。
第三个 commit 是 README。把设计理念和用法写清楚,算是给这个项目画上句号。
整个过程一气呵成。37 个静态断言加上 E2E 测试全部通过,协议链路从触发到规则生成一气走完。不是因为问题简单,而是 OpenCode 的基础设施已经把最难的部分解决了。skill 体系让自定义命令的实现变得自然,omo 的 task() 后台任务天生支持会话隔离,session 读写 API 又完善。我要做的就是把这些能力组合起来,用一个清晰的框架表达 Aristotle 的设计哲学。
(2026-04-11 补充:这一节的"顺利",后来被证明只是测试的顺利。至于测试没覆盖到的那部分,第四篇再讲。)
反思本身也值得反思
Aristotle 这个名字,我想了很久。最终选定它,是因为那句话。“Knowing yourself is the beginning of all wisdom.” 认识自己是一切智慧的开端。
给 AI 装上反思能力,本质上是在让 AI 认识自己的局限。这不是简单的错误记录,而是结构化的元认知。模型犯错不是因为聪明或者愚蠢,是因为它对自己的盲区没有觉知。Aristotle 通过根因分析,把这些盲区显性化,转化为可学习的规则。
认知科学里有个概念,叫元认知。它指的是"对思考的思考",或者说"知道自己知道什么,知道自己不知道什么"。人类的学习很大程度上依赖于元认知能力。我们遇到困难时,会停下来反思,“我为什么会犯这个错误”,“下次怎么避免”。这种反思不是偶然的,它是学习过程的核心环节。
AI 之前缺的就是这个环节。模型在对话中可以实时学习和调整,但这个学习是临时的、情境化的。会话结束后,经验就丢失了。Aristotle 把这个环节结构化,让模型能够"知道自己不知道什么",并且把这个认识转化为持久的知识。
这不是魔法。Aristotle 生成的规则还是需要人工审核,规则的应用场景也可能有局限。但它在系统层面补上了元认知这一环,让 AI 的学习从临时的、孤立的,变成了持久的、可积累的。
下一步预告
同样的哲学搬到 Claude Code 时,事情没那么简单。
OpenCode 有完整的 skill 体系和后台任务基础设施,实现 Aristotle 是水到渠成。Claude Code 的环境不同,很多能力需要重新设计。下一篇 claude-code-reflect:同样的元认知,落在不同的土壤 会讲这个过程,以及遇到的技术挑战。核心思想不变,但实现路径完全不同。
驾驭 AI 的关键不是提示词,而是让 AI 具备从错误中学习的能力。这是这个系列的起点,也是我认为最重要的一点。