跳到正文

Prelude 设计文档

状态:v1(2026-10-27),取代旧的 agent-core.md 和 pi-testmode-plan.md(已删除,可从提交 f5d01c7 查看) 一句话:测试人员只给一个测试目标,AI 自主完成测试并交付报告;每次测完都复盘,把经验写进跨项目共享的知识库。目标是更快地发现问题,尤其是测试人员没覆盖、没注意到的地方。


1. 为什么改

旧实现(pi-testmode,约 1.1 万行)把测试方法、适用判断和经验更新都写成了代码和数据结构。真实运行暴露了三个问题:

  • 慢:一个意图被拆成多个 Mission,每次交接都要重读材料。直接对模型说一次反而更快。
  • 框架在修自己的问题:5 次真实运行修掉的问题,大多是预算口径、评分算法、作弊检测误报这类框架自身的问题。
  • 核心收益没有证据:模板图带来的成本下降,一份写得好的 Skill 很可能也能做到。

新设计的原则:判断交给模型,代码只做模型自己做不到的事。

2. 原则

# 原则 含义
P1 一个上下文做到底 测试主体由同一个模型在同一会话里连续完成。只有独立复验另开上下文
P2 代码只做"支撑" 包括:知识持久化与版本管理、独立复验、安全边界、进度展示、无人值守运行。不替模型选方法、不替模型判断经验是否适用
P3 经验是模型能读的文字 经验写成 Skill,靠 pi 原生的按需加载(平时只放描述,用到才读正文)
P4 只有证据支持的结论才能进知识库 自生成、未经检验的经验和工具,收益可能为负
P5 负反馈是"用错了地方" 经验遇到反例时补充"不适用条件",不删除原内容
P6 重要文件只经代码写入 跨项目知识库只能通过扩展工具修改,由代码调用 git 提交

3. 分工

谁 负责
Prelude 扩展(pi 扩展,代码) 初始化;/test 模式入口;进度与状态展示;知识库的挂载、写入工具与 git 同步;授权范围与危险操作拦截;独立复验;结束检查
模型 接收信息、勾勒目标轮廓、确定方向、选用或自写工具、执行测试、记录发现、写报告、复盘;在当前项目写系统笔记
用户 给出测试目标;回答一次性的接收问题;维护 scope.json;处理 git 冲突

4. 一次测试的流程

流程写在方法论 Skill(test-pilot)里,由模型执行。代码只提供工具和检查。

  1. 接收:判断目标类型(网站、接口、安卓 apk、Windows 程序、CLI 或服务等),读系统笔记和相关的类别经验,然后一次性列出所有缺少的信息问用户:环境地址、测试账号、允许的操作、是否授权安全测试等。之后不再打断用户。
  2. 勾勒轮廓:探索目标,记录功能面、接口、角色与权限、数据流、技术栈。
  3. 确定方向:用户指定了方向就按用户的。否则按风险和"盲区清单"排定优先级。
  4. 选工具:先用知识库里的工具和成熟引擎(Playwright、adb、ZAP、nuclei 等),缺了再自己写。
  5. 执行:每个发现都要有可执行的复现脚本(退出码非 0 表示问题复现),并实时用 finding_record 记录。
  6. 复验:所有发现批量交给独立复验(§7)。
  7. 报告:写清楚测了什么、没测什么及原因、每个问题的复现步骤、证据和复验结论。
  8. 复盘:用知识库工具写入经验和工具,在项目里更新系统笔记。

盲区清单(方法论 Skill 内,每次至少过一遍):边界与异常路径、并发与重复提交、状态流转、权限越权、输入编码与国际化、错误提示与恢复、可访问性、性能退化、配置与环境差异。

5. 知识

5.1 三层

层 内容 位置 谁写
方法论 怎么测,跟系统无关 知识库 skills/test-pilot/ 随扩展发布,人工维护
类别经验 + 工具 一类系统的共性、常见坑、可复用工具 知识库 skills/<类别>/ 模型通过扩展工具写入
系统笔记 某个被测系统的特点 被测项目 .prelude/notes/ 模型直接写

类别按维度组合,不做成分类树。一个系统可以同时属于多个类别,每个维度对应若干类别 Skill:

  • 平台:web、android、windows-desktop、cli
  • 接口:rest-api、graphql
  • 业务领域:ecommerce
  • 技术栈:electron、spring

遇到未知目标时,模型选出最接近的几个类别来读。测完后,如果确实是新的一类,就起草一个新类别。

5.2 一条经验

每条经验存为一个 JSON 文件:skills/<类别>/lessons/<id>.json。一条一个文件,可以减少合并冲突。

{
  "id": "les-7f3a",
  "title": "异步扣减的库存不能立即读取校验",
  "applies_when": "库存或余额扣减经消息队列异步完成",
  "not_applies_when": ["扣减在同一事务内同步完成"],
  "guidance": "压测后先轮询到数值稳定(≥2 次相同读数)再判定守恒",
  "status": "candidate",
  "evidence": [
    { "project": "p-1a2b", "report": "reports/2026-10-27-order.md", "finding": "f-003", "at": "2026-10-27" }
  ],
  "revisions": []
}
  • project 由扩展填写(取自被测项目的 .prelude/project.json),模型不能自己声称。
  • 模型不直接读 JSON。扩展根据 lessons 生成每个类别的 SKILL.md:正式经验放在正文,候选经验单列在"待验证"一节。

5.3 晋升与修订(代码强制)

  • 新经验一律以 candidate 状态入库。
  • 当 evidence 中出现 ≥2 个不同的 project,自动升为 confirmed。
  • 修订:遇到反例时追加 not_applies_when 或改进 guidance,同时把修订前的文本存进 revisions。不能删除经验,只能标记 retired 并写明理由。

5.4 工具

  • 工具放在 skills/<类别>/scripts/<tool>/,包含脚本、README.md(用法与已知的失败情况)和 selfcheck 命令。
  • 入库流程:模型先在项目的 .prelude/work/ 里写好工具并实际用过,再调用 kb_tool_add。扩展运行 selfcheck,通过后才复制进知识库。
  • 复用时出错:能修就修,并在 README 里记下"在什么情况下失败";修不好就标记为废弃。

6. 知识库与 git

6.1 配置

~/.prelude/config.json:

{
  "kb": {
    "dir": "~/.prelude/kb",
    "remote": "git@example.com:team/prelude-kb.git",
    "mainBranch": "main",
    "branch": "kb/alice-desk01-3f9c"
  }
}

branch 在初始化时自动生成(kb/<用户名>-<主机名>-<4 位随机码>),用户可以修改。扩展会检查远程上是否已有同名分支。

6.2 流程(全部由代码调用 git)

时机 动作
进入 /test fetch → 把 origin/<main> 合并进自己的分支。有冲突就问用户
每次知识写入 在自己的分支上提交,提交信息由代码生成(来源项目、报告、改动摘要)
测试结束 把自己的分支合并进 main → 推送 main 和自己的分支。有冲突时不阻塞报告:改动保留在自己的分支上,在状态栏提示,下次进入 /test 时再询问
网络或鉴权失败 用本地知识库继续,并在状态栏提示;没推送的提交下次再推
  • 冲突询问:对每个冲突文件给出选项:保留本地 / 采用远端 / 两者都保留(仅限经验文件,另存为新 id)/ 中止合并。
  • 凭据:git 使用用户本机已有的凭据,扩展不读取、也不保存任何凭据。
  • 防止绕过:模型只能读知识库,write / edit 和 shell 写入都会被闸门拦截。扩展在每次进入模式和每次写入前检查知识库工作区是否干净;发现不是由工具产生的改动,就还原并记入审计。
  • 并发:所有知识写入在进程内串行执行,并用知识库目录下的锁文件防止多个进程同时写入。

7. 独立复验

模型在一个上下文里做测试,会有自我确认的倾向。复验分两步,第一步由代码完成:

  1. 复现(代码):对每个发现,在干净的工作目录里重跑它的复现脚本 k 次(默认 3 次),按退出码算复现率。≥ 0.6 判为复现。
  2. 审查(新上下文的模型):开一个只读子会话(createAgentSession,只有 read / bash),只给它发现描述、复现脚本和证据,不给测试过程。由它判断脚本是否真的证明了所声称的问题,比如断言是否过弱、预期值是否抄自实际输出。结论为 confirmed / rejected。
  • 只有"复现且审查通过"的发现才计入报告中的缺陷。
  • UI/UX 的体验建议没有复现脚本,只做审查,在报告里列为"建议"。

8. 被测项目里的 .prelude/

.prelude/
├── project.json   # 项目 id(初始化时生成)
├── scope.json     # 授权范围,只能人工维护,模型写入一律被拦截
├── notes/         # 系统笔记,模型自由写
├── reports/       # 测试报告
├── work/          # 模型的临时工作区(脚本、草稿工具)
├── evidence/      # 证据文件(按 sha256 命名)
├── runs/          # 每次测试的状态:state.json、findings.jsonl
└── audit.jsonl    # 审计日志:只追加,每行带前一行的哈希
  • 初始化时询问用户 notes/ 和 reports/ 是否纳入项目版本管理,并据此生成 .prelude/.gitignore。work/、evidence/、runs/、audit.jsonl 永远忽略。
  • 项目根的 AGENTS.md 中由扩展追加(不存在则新建)一段说明:系统笔记写在哪里、什么时候更新。测试结束时,扩展检查本次是否更新了笔记,没有则提醒模型一次。

9. 安全边界

  • 授权范围:scope.json 写明允许的目标、测试类型(功能、负载、安全扫描、破坏性)和强度上限。缺失时只允许只读探索。

  • 闸门:在 pi 的 tool_call 钩子里拦截:

    • 访问范围外主机;
    • 危险命令;
    • 写入受保护路径:知识库、scope.json、audit.jsonl、扩展目录;
    • 首次安装依赖需要审批。

    闸门出错时一律拦截。

  • 隔离级别:Windows 上只有工具层策略,不是安全边界;报告中写明这一点,并建议改用官方 Docker 方案运行 pi。macOS/Linux 可以使用改编自官方 sandbox 示例的 OS 级隔离。

  • 打包程序:exe 建议放在 Windows Sandbox 或虚拟机中运行,apk 放在模拟器中运行。不在用户主机上直接安装被测程序。

10. 进度与状态

  • 状态栏:当前阶段(接收 / 轮廓 / 执行 / 复验 / 报告 / 复盘)和已发现问题数(按严重程度分)。
  • 组件区:最近的发现列表,以及知识库同步状态(已同步 / 待推送 / 有冲突)。
  • 模型用 test_progress 报告阶段切换,用 finding_record 记录发现;两者都写入 runs/<id>/ 下的文件。

11. 不做的事

模板图、统计模型、自动分诊和门禁算法、多角色调度、数据库、向量检索、为模型设定方法论之外的固定流程。如果真实使用中发现某一环确实需要结构,再在那一环加最小的结构,并记入计划的决策表。

记录于此。