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)里,由模型执行。代码只提供工具和检查。
- 接收:判断目标类型(网站、接口、安卓 apk、Windows 程序、CLI 或服务等),读系统笔记和相关的类别经验,然后一次性列出所有缺少的信息问用户:环境地址、测试账号、允许的操作、是否授权安全测试等。之后不再打断用户。
- 勾勒轮廓:探索目标,记录功能面、接口、角色与权限、数据流、技术栈。
- 确定方向:用户指定了方向就按用户的。否则按风险和"盲区清单"排定优先级。
- 选工具:先用知识库里的工具和成熟引擎(Playwright、adb、ZAP、nuclei 等),缺了再自己写。
- 执行:每个发现都要有可执行的复现脚本(退出码非 0 表示问题复现),并实时用
finding_record记录。 - 复验:所有发现批量交给独立复验(§7)。
- 报告:写清楚测了什么、没测什么及原因、每个问题的复现步骤、证据和复验结论。
- 复盘:用知识库工具写入经验和工具,在项目里更新系统笔记。
盲区清单(方法论 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. 独立复验
模型在一个上下文里做测试,会有自我确认的倾向。复验分两步,第一步由代码完成:
- 复现(代码):对每个发现,在干净的工作目录里重跑它的复现脚本 k 次(默认 3 次),按退出码算复现率。≥ 0.6 判为复现。
- 审查(新上下文的模型):开一个只读子会话(
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. 不做的事
模板图、统计模型、自动分诊和门禁算法、多角色调度、数据库、向量检索、为模型设定方法论之外的固定流程。如果真实使用中发现某一环确实需要结构,再在那一环加最小的结构,并记入计划的决策表。