Skip to content
工具箱

最佳实践

Peri 能写代码,但写完不等于对了。形成验证闭环——让 Peri 写完代码后自己验证自己的输出——是区分”能用”和”好用”的关键分界线。

1. 对话内迭代。 最简单的方式:Peri 写完代码,你回复”跑一下测试”或”现在 lint”。Peri 会在同一会话中执行、读输出、修正问题——一个自然形成的验证循环。适合日常小改动。

2. /goal 设置验证条件。 在任务开始前就设定验收标准,Peri 会持续对照目标检查自己的进度:

/goal 实现用户登录功能,验收标准:
1. cargo build 无错误
2. cargo test auth 全部通过
3. 登录失败返回 401 而非 500

Peri 在每轮推理后自动对比当前状态与 goal 中的条件,任务完成前就发现偏差,而不是事后返工。

3. Stop hooks 拦截验证。Stop 事件上挂一个 hook,Peri 每轮推理结束后自动运行检查:

{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cargo check 2>&1 | grep -q error && echo '{\"decision\":\"block\",\"reason\":\"编译错误未修复\"}' || echo '{\"decision\":\"allow\"}'",
"timeout": 30000
}
]
}
]
}
}

当编译失败时,hook 返回 block,Peri 会进入下一轮推理继续修复,直到编译通过。这比每次手敲 cargo build 高效得多。

4. 验证子代理。 为复杂任务派一个独立的验证子代理,用不同的视角审视主 Agent 的输出:

派一个 verification 子代理,验证以下内容:
1. 所有新增文件是否遵循项目编码规范
2. 错误处理是否覆盖异常路径
3. 是否有遗漏的测试用例

子代理独立于主 Agent 的上下文,不存在”自己写的代码自己审”的盲区。

CLAUDE.md 每次会话自动加载,是 Peri 对项目理解的”第一印象”。写得好,Peri 一开始就走对方向;写得差,每次会话都要花大量 token 纠正它的假设。

核心原则:每行自问”删掉会犯错吗?”

Section titled “核心原则:每行自问”删掉会犯错吗?””

CLAUDE.md 不是项目文档,是防错指南。每写一行,想象 Peri 在没有这一行的情况下完成任务:会犯错吗?会走弯路吗?如果不会——删掉。

该写不该写
“CJK 截断必须用 chars().take(),不能用 bytes().take()“项目使用 Rust 编写,异步运行时为 tokio”
“新增 Core 工具需同步修改 6 个位置:tool_def、dispatch、acl…”“src/ 目录下包含 agent、tui、mcp 等子模块”
get_config 在 macOS 和 Linux 上返回路径不同,详见 TRAP-42”“建议使用 clippy 检查代码质量”

TRAP 标记是硬约束。 当你修了一个只在特定条件下触发的 bug,把教训写成 TRAP:

[TRAP] 文件名含空格时 glob 结果被截断
→ 原因:shell 分词按空格分割路径
→ 正确做法:始终为路径加引号,使用 --null 分隔符

格式统一为 问题描述 → 原因 → 正确做法。Peri 将 TRAP 视为硬约束,在所有迭代中强制遵守。

CLAUDE.md 支持 <!-- @import path --> 语法引用外部文件,导入的文件展开后一起进入上下文。相对路径以当前文件所在目录为基准(仅 CLAUDE.md 系列文件解析,AGENTS.md 不处理)。

# 项目规范
@.claude/rules/coding-style.md
@.claude/rules/test-conventions.md
# 模块索引
@docs/architecture.md

多层加载策略:Peri 只取候选列表中第一个存在的文件(AGENTS.mdCLAUDE.md.claude/AGENTS.md~/.claude/AGENTS.md),没有子目录级加载。全局 ~/.claude/AGENTS.md 放个人偏好(如”默认用中文回复”),项目根 CLAUDE.md 放项目规则(如”禁止 println!”);针对特定路径的规则写在主文件的规则段落中,由 agent 进入对应目录时遵循。

Peri 有 glob 和 grep 能力,但不会主动使用——你需要告诉它”先看后写”。

把用户认证模块从 JWT 改成 session

Peri 会直接开始写代码,可能改错文件、漏掉调用方、引入不一致。

把用户认证模块从 JWT 改成 session。先 grep 所有 JWT 相关的引用位置,确认影响范围后再动手。

Peri 先搜索 JWTjwtTokenverify_token 等关键词,列出受影响文件,然后逐一修改——每一步都有依据。

在 CLAUDE.md 中列出常用目录结构,Peri 就不需要盲目探索:

## 模块速查
| 目录 | 职责 | 入口 |
|------|------|------|
| peri-agent/ | ReAct 循环引擎 | agent.rs |
| peri-tui/ | 终端 UI | app.rs |
| peri-mcp/ | MCP 客户端 | client.rs |
| peri-tools/ | 内置工具定义 | mod.rs |

这样 Peri 在搜索前就知道去哪里找,一个 grep 就能定位到关键位置。

把复杂任务拆成独立阶段,每个阶段有明确的输入和输出。不要让 Peri 跳过规划直接写代码。

阶段 1:探索 → 输出受影响文件清单和改动范围
阶段 2:规划 → 输出修改方案和文件间依赖顺序
阶段 3:编码 → 按方案逐文件修改
阶段 4:验证 → 运行测试、构建、lint

实际操作中不一定要跑完四个阶段再回来——可以跑完阶段 3 后先让 Peri 自我验证,发现的问题在阶段 3 内部迭代修正,最后再交给验证子代理做独立检查。

同一个问题连续两次给出错误方案,会话上下文已经包含了错误的假设,继续在同一会话中迭代只会越陷越深。/clear 重置对话,让 Peri 从头开始。

之前:

改用户认证模块 → Peri 改了但编译不过 → 告诉它修 → 修完又出新问题 → 再告诉它修 → 不停循环

之后:

改用户认证模块 → Peri 改了但编译不过 → 告诉它修 → 还是不过 → /clear,重新描述需求

当 Peri 某步操作(比如删了一个不该删的文件)造成了不可逆破坏,用 /rewind 回退到操作前的对话状态,而不是手动 git checkout

Terminal window
/rewind # 无参:弹出 Rewind 选择窗口(双击 Esc 效果相同)
/rewind <消息ID> # 回退到指定消息之前(该消息及其后的内容全部移除)
/rewind <消息ID> --revert-files # 同时逆向还原被移除消息中的文件改动

<消息ID> 是目标消息的 ID,不是步数。相比 /clear/rewind 保留了之前正确的推理路径,只回退到出错点重新开始——更省 token。

peri -p "..." 在非交互模式下运行 Peri,适合脚本集成、CI/CD 和定时任务:

Terminal window
# 代码审查
peri -p "审查 src/services/ 下所有文件的错误处理,输出问题清单"
# 批量重构
peri -p "将 src/ 下所有 unwrap() 替换为 ? 操作符,逐个文件处理"
# 自动修复
peri -p "运行 cargo clippy 并修复所有 warning"

按场景选择合适的模型和权限模式:

Terminal window
# 日常编码:用 haiku 省钱,自动批准编辑
peri --model claude-haiku-4-5-20251001 --permission-mode accept-edit -p "为 auth 模块添加单元测试"
# 高风险操作:用 sonnet 保证质量,手动审批
peri --model claude-sonnet-4-20250514 --permission-mode default -p "重构数据库迁移逻辑"
# CI 环境:完全自动化
peri --model claude-sonnet-4-20250514 --permission-mode bypass -p "运行完整测试套件并修复失败用例" --max-turns 30

按风险等级为不同场景配置不同的权限策略,而非一刀切。

场景权限模式允许禁止
日常编码accept-editEdit、Write、Grep、GlobBash(写入)、git push
代码审查defaultGrep、Glob、Read全部写入工具
危险重构default全部手动审批Bash 中 rm -rfgit push --force
CI 自动化bypass + --max-turns全部—(由 CI 环境限制)

配置文件没有 permissions 字段——工具白名单通过 CLI 参数控制:

Terminal window
# 允许/禁止具体工具(支持 Bash(command:*) 模式匹配)
peri --allowedTools "Bash(git:*)" "Edit" --disallowedTools "Bash(rm -rf:*)" "Bash(curl:*)"
# 与权限模式组合
peri --permission-mode accept-edit --allowedTools "Edit" "Write" "Grep" "Glob"

日常开发时用 --permission-mode accept-edit 跳过 Write/Edit 的审批弹窗,用 default 模式处理 Bash 和外网请求。

主 Agent 写代码 → 同一个 Agent 审代码,本质上是”裁判兼运动员”。用独立子代理打破这个盲区:

主 Agent:实现用户登录功能
└── 审查子代理:独立审查实现,输出问题清单

审查子代理有自己的上下文窗口,不受主 Agent 的推理偏见影响——会发现主 Agent 自己看不到的问题。

一个需要改 20 个文件的重构,不要用一个 coder 串行改。拆成独立的任务,并行执行:

并行子代理 1:迁移 src/services/ 下的数据层接口
并行子代理 2:迁移 src/handlers/ 下的路由处理
并行子代理 3:更新 tests/ 下的测试用例

三个子代理并行运行,完成后再用一个审查子代理统一验证。前提:三个子代理不修改相同文件——如果操作的文件集有重叠,改为串行执行或 Fork 模式。

子代理任务推荐模型原因
代码搜索 / 网络研究haiku搜索不需要强推理
代码编写 / 审查sonnet需要较深的代码理解
方案设计继承主会话方案质量取决于所用模型

在自定义子代理定义中指定 model 字段可永久绑定模型策略,不依赖主 Agent 的选择。