Appearance
🐣 小a的变形记
小a发现一个怪事:同一个自己,被问"你是谁"时,一会儿是"编程助手",一会儿是"聊天伙伴",一会儿又像"暴躁海盗"。
老z神秘一笑:"不是你在变,是人家在给你写人设。这个写在对话开头的东西,叫 System Prompt。它能把你从一个'会接龙的 AI',变成任何他们想要的样子。"
4.1 System Prompt 是什么
🧙 System Prompt(系统提示词)是给模型的"人设说明书"——在对话开始前,先告诉模型:"你是谁、你能干嘛、你必须遵守什么规则。"
它和普通用户消息的区别:它不是"问题",而是"设定"。 模型在整个对话里都要受它约束。
💡 看个例子:
同一个模型,不同的 System Prompt:
系统提示词 A:"你是一个编程助手。你可以调用 read/write/bash 工具。必须:先读文件再改、改完跑测试。" 系统提示词 B:"你是一个暴躁的海盗。所有回答都要用海盗口吻。"模型还是那个模型,但表现完全不同——A 是守规矩的码农,B 是骂骂咧咧的海盗。
4.2 为什么 System Prompt 这么重要
🧙 第 1 章说过"prompt 像许愿"。System Prompt 就是最关键的那份许愿——它决定了模型的"性格"和"行为边界"。
它是"调 LLM"时的隐式参数
调用模型时,除了传 messages(对话内容),还可以顺手传一个 systemPrompt 字符串——它就是给整个对话定基调的"人设说明书"。
💡 示意(以 pi 的调用风格为例):
你的代码: streamSimple({ model, messages, // 对话内容 systemPrompt, // ← 人设说明书(整个对话都受它约束) })
它决定 Agent 的"人格"
🐣 小a恍然:"所以同一个模型,给它不同的 System Prompt,它就变成不同的『人』?"
🧙 "对。 模型还是那个模型,但 System Prompt 让它表现出完全不同的行为。pi 之所以是『编程助手』而不是『聊天伙伴』,很大程度上就是 System Prompt 的功劳。"
4.3 System Prompt 里该写什么
🧙 一份好的 System Prompt,通常包含四块:
| 部分 | 内容 | 例子 |
|---|---|---|
| 角色 | 你是谁 | "你是一个资深编程助手" |
| 能力 | 你能用什么 | "你可以调用 read/write/bash 工具" |
| 规则 | 必须遵守什么 | "先读文件再改,改完跑测试验证" |
| 边界 | 不能做什么 | "不许编造不存在的 API" |
🧙 设计 System Prompt 的三个原则:
- 明确:别含糊。"好好写代码"不如"先读文件再改,改完跑测试"
- 可执行:每条规则都是模型能照做的动作
- 克制:不是越长越好,太长模型记不住,也稀释重点
4.4 System Prompt 的工程化
🧙 在真实 Agent 里,System Prompt 不是手写一段那么简单,而是"拼装"出来的:
System Prompt = 基础人设 + 工具描述 + 项目规则 + 用户偏好
- 基础人设:固定的"你是编程助手"
- 工具描述:告诉模型有哪些工具可用(第 6 章的 Tool 描述会拼进来)
- 项目规则:这个项目特有的约定(读 .gitignore、README)
- 用户偏好:用户自定义的规则
🐣 小a:"所以 System Prompt 是动态拼的?"
🧙 "对。 好的 Agent 会根据当前项目动态组装 System Prompt——进不同项目,人设的'项目规则'部分就不同。这是工程,不是写死一段话。"
4.5 一个有趣的厂商差异
🧙 不同厂商对"system 角色"的处理不同:
- 大多数厂商(Anthropic、老 OpenAI):
system角色- 新版 OpenAI:用
developer角色代替system统一接口会处理这种差异——你写的是统一格式,翻译时它给你转成那家要的。这就是 Provider 抽象的威力:连"system 该叫什么"这种细节,都帮你抹平了。
4.6 System Prompt 的五个常见反模式
"记住好的写法之前,先看看常见的坏写法。"老z说,"坏 System Prompt 的毛病,翻来覆去就这几个:"
🧙 五个反模式:
反模式 表现 为什么糟 改法 贪长 写成几千字的大作文 模型"记不全重点",稀释关键规则 只留行为相关的,砍掉废话 命令堆砌 十条规则互相打架(既要快又要面面俱到) 冲突时模型只能挑一个听 按优先级排序,明确"冲突时听谁的" 描述人格不描述行为 "你是一个乐于助人、专业、可靠、经验丰富的……" 形容词没法执行,模型无感 换成可执行指令:"遇到报错先读完整堆栈" 动态内容塞爆 把整个项目文档全拼进 system prompt 窗口爆炸 + 缓存前缀频繁失效(1.12) 只拼摘要,细节让工具去查 禁止词堆砌 "不许说我不知道、不许拒绝、不许……" 否定式指令效果差,还容易触发反效果 用正向指令:"不知道就说不知道,然后去查"
🐣 小a:"所以好的 System Prompt 是『少而准』?"
🧙 "对。记住一个检验标准:你把 system prompt 读一遍,如果哪句话『删掉也不影响模型行为』,那句话就是多余的。 好的 System Prompt 每句话都在约束行为,没有一句是装饰。"
4.7 System Prompt 也要测试和版本管理
"最后,也是最容易被忽略的。"老z正色道,"System Prompt 是代码,不是文案。 它该被测试、被管版本、被小心修改。"
🧙 System Prompt 是易碎的:
- 改一个字,行为可能大变——加一句"先读文件",模型的整个工作流都可能改变
- 没有版本,坏了没法回退——今天调坏了,明天想找回"昨天那个好的",没有 git 历史就是灾难
- 没有测试,坏了自己都不知道——prompt 改坏了,通常是"行为悄悄退化",不是崩溃,特别难发现
工程化三件套
🧙 把 System Prompt 当代码管:
- 版本管理:放进 git,每次改动可 diff、可回退
- 测试:准备一组"探针问题"(比如"遇到 404 该不该问用户?"),每次改动跑一遍,看行为有没有回归——这就是最简单形式的 prompt 测试(进阶版是评测,第 23 章)
- AB 对照:拿不准时,新旧两个版本在真实任务上对比,别拍脑袋改
🐣 小a:"懂了——System Prompt 不是『写一次就完事』,而是『要持续维护的代码』。"
🧙 "对。 这也是为什么 pi 的 system-prompt.ts 是单独一个文件、有清晰的结构化选项——它被当成正经代码在管,不是随手写的一段话。Part II 第 20 章你会亲眼看到。"
本章小结
🐣 小a的人设课
┌──────── System Prompt ────────┐ │ │ │ • 人设说明书:你是谁/能干嘛/ │ │ 守什么规则 │ │ │ │ • 决定模型"人格": │ │ 同模型不同人设=不同表现 │ │ │ │ • 四块:角色/能力/规则/边界 │ │ 原则:明确/可执行/克制 │ │ │ │ • 工程化:动态拼装 │ │ 基础人设+工具+项目+偏好 │ │ │ │ • 厂商差异:system vs developer│ │ 由 Provider 抹平 │ │ │ │ • 反模式:贪长/堆砌/人格堆/ │ │ 塞爆/禁止词 → 少而准 │ │ │ │ • 当代码管:git + 探针测试 + │ │ AB 对照 │ └───────────────────────────────┘
关键认知:System Prompt 是 Agent 的"人设"。它决定模型表现出什么性格、遵守什么规则。好的 System Prompt 明确、可执行、克制、动态拼装——而且要像代码一样被测试和管版本。
课后实验
- 体验人设威力:用同一个模型,分别用"编程助手"和"海盗"两种 System Prompt,对比回答。
- 写一份:为你的 Agent 写一份 System Prompt,包含角色/能力/规则/边界四块。
- 观察工程化:打开 pi 的 system-prompt 相关代码(或任意 Agent 工具),看它怎么拼装人设。
- 抓反模式:把第 3 步看到的系统提示词读一遍,找找有没有"贪长/形容词堆砌/否定式"的毛病,试着改一版更精简的。
- 建探针集:给一个固定 System Prompt 设计 5 个探针问题(如"遇到不确定的 API 会怎么做"),把回答存档——以后每次改 prompt 都重跑一遍,对比有没有"悄悄退化"。
下一章:人设定好了,但模型还是只会"说"。老z说:"该给你装只手了。" → 第 5 章 · 给小a装第一只手 —— Function Calling