Agentpath
原理8 / 31 节 · 预计 30 分钟

系统提示词、AGENTS.md 与 SYSTEM.md

同一个模型、同一套工具,换一份系统提示词就是另一个 agent。Pi 把这层完全交给你改。

学完这节你能做到

  • 读懂 Pi 的默认系统提示词分了哪几块、各自解决什么问题
  • 为自己的项目写出一份有效的 AGENTS.md,并说明它和 SYSTEM.md 的分工
  • 判断某条规则应该写进提示词、写进工具描述、还是做成 skill

同一个模型、同一套工具,换一份系统提示词就是另一个 agent。这一层是你调整 agent 行为 最便宜的手段 —— 也是最容易写砸的一层。

Pi 的三层:默认提示词、上下文文件、系统提示文件

Pi 把这件事拆成三层,各管一件事:

文件作用谁该写
默认系统提示词Pi 内置(--system-prompt 可整体替换)身份、工具约定、行为边界一般不动
上下文文件AGENTS.md / CLAUDE.md这个项目的事实与规矩每个项目都该写
系统提示文件SYSTEM.md / APPEND_SYSTEM.md换掉或追加系统提示做专用 agent 时

上下文文件的层叠规则

AGENTS.md(或 CLAUDE.md)从三处读,叠加生效:

~/.pi/agent/AGENTS.md      ← 全局:你个人的偏好,跨项目通用
<从 cwd 往上的每一级父目录>   ← 单仓多项目时,公共约定放上层
<cwd>/AGENTS.md             ← 当前项目

某一级目录下放了 AGENTS.override.md,这一级就用它替代自己的 AGENTS.md / CLAUDE.md, 其它层照常叠加。--no-context-files-nc)整体关掉。

系统提示文件

.pi/SYSTEM.md              # 项目级:整体替换默认系统提示
~/.pi/agent/SYSTEM.md      # 全局:同上
.pi/APPEND_SYSTEM.md       # 追加而不是替换
~/.pi/agent/APPEND_SYSTEM.md
!替换默认提示词是个大动作

默认提示词里有大量关于工具怎么用、输出格式、边界的约定。整体换掉之后, 「它突然不会用 edit 工具了」这类问题会一起来。做专用 agent(只跑一类任务)时才替换, 平时用 APPEND_SYSTEM.md 追加。

AGENTS.md 该写什么

这份文件的读者是模型,判断标准只有一个:它写在这里,能让 agent 少犯一次错吗?

值得写:

# 项目约定

## 构建与验证
- 包管理用 bun,不要用 npm(lockfile 会打架)
- 改完跑 `bun run typecheck`,这是唯一的准入检查
- 测试很慢(约 4 分钟),只在改动涉及 src/core/ 时跑

## 边界
- 不要改 src/generated/ 下的任何文件,那是代码生成产物
- 数据库迁移只能新增文件,不许改历史迁移

## 事实
- 生产环境是 K8s,日志在 Loki,指标在 Prometheus
- API 的 OpenAPI 定义在 api/openapi.yaml,改接口先改它

不值得写:

  • 代码结构说明 —— 让它自己 lsgrep,比你写的更新。
  • 通用编程规范 —— 「变量名要有意义」这种,模型本来就会。
  • 超长的架构文档 —— 每轮都在付这个钱,而且大部分任务用不上。放到 skill 或 普通文档里,让 agent 需要时自己读。
一条经验法则

AGENTS.md 里的每一行都在每一轮被重发。如果一条规则十次任务里只有一次用得上, 它就该是 skill 而不是 AGENTS.md。

规则该放哪一层

同一条约束有三个可能的位置,选错了就不生效:

约束放哪理由
「不许 force push」工具层(确认门 / 拦截)提示词是软的,模型可能忽略;真要拦就拦在执行处
「用 bun 不用 npm」AGENTS.md高频、跨任务、说一次就够
「写 PDF 报表的完整流程」skill低频、长、只在特定任务需要
「这个工具超过 400 行会截断」工具的 description就近说明,模型用到时才看见
×别指望提示词当安全边界

Pi 的文档说得很直白:project trust「不是沙箱,也不限制模型能让工具做什么」。 提示词里写一百遍「不要删文件」,也挡不住一次误判。真正的边界只有两种: 在工具执行处拦(L2 的权限门),或者用操作系统 / 容器隔离(L3 的沙箱)。

规则不生效的三个常见原因

  1. 和默认提示词冲突 —— 你说「回答要简短」,默认提示词说「改动前先解释计划」。 模型在冲突里选一个,通常不是你要的那个。冲突要在同一层解决:用 SYSTEM.md 替换, 而不是在 AGENTS.md 里对着喊。
  2. 位置太靠后、正文太长 —— 三千字的 AGENTS.md 里第 47 条规则,注意力权重很低。 规则超过二十条就该分层。
  3. 写成了描述而不是指令 —— 「本项目使用 bun」是事实陈述, 「安装依赖必须用 bun install,不要用 npm」是指令。写指令。

用扩展动态改系统提示

Pi 留了钩子:before_agent_start 事件可以注入消息、也可以链式修改系统提示。 用它做「按任务类型切换人格」「注入当前分支/环境信息」这类事:

pi.on("before_agent_start", async (event, ctx) => {
  // 注入动态信息 —— 注意放在消息里,别塞进系统提示,否则缓存全废
})

ctx.getSystemPrompt() 能读到当前完整的系统提示,调试时很有用。命令上下文里还有 getSystemPromptOptions() —— 文档特别提醒它可能包含上下文文件全文,属于敏感内容, 别写进日志。

检查点单选

团队要求:agent 绝对不能对 main 分支执行 git push。这条约束最该放在哪?

这一节的结论

  1. 三层分工:默认提示词(别动)、AGENTS.md(项目事实与规矩)、SYSTEM.md(换人格)。
  2. AGENTS.md 每轮都在花钱 —— 十次里用一次的规则应该是 skill。
  3. 写指令不写描述;规则超过二十条就该分层。
  4. 禁止性约束必须落到工具层或系统隔离,提示词只是第一道软防线。

延伸资料