导学阶段-提示词与角色
本文整理自 CNB 上的开源课程 《Vibe Agent:从零搭建 Coding Agent》。课程讲义、示例代码与练习仓库均在 CNB 上公开,文中示例出自该仓库对应章节。
同一个模型,同一个问题,只把最前面那条 system 消息换掉,输出的语气、格式、详略就会整体改变。常见的解释是”提示词写得好”,这个说法停留在表面。真正起作用的是两件事:一套固定的消息格式,以及训练阶段形成的服从倾向。
一次调用传的是一份列表
OpenAI 兼容接口的输入是一份 messages 列表,每条消息只有两个字段:role 和 content。
1 | messages = [ |
模型读完整个列表,生成列表的下一条,也就是 assistant 消息。列表本身不保存任何东西,调用结束即丢弃。模型不会因为多轮对话而改变内部状态,能影响下一轮输出的,只有这份列表的内容和顺序。
| 角色 | 由谁写 | 承担什么 |
|---|---|---|
| system | 开发者 | 身份、规则、约束 |
| user | 使用者 | 输入与追问 |
| assistant | 模型自己,也可由程序写入 | 历史回复 |
第四种角色 tool 要等到讲工具调用时才会出现。这里先记住三种。
三种角色并不对等。user 与 assistant 通常交替出现,system 一般只放在最前面一条,整轮对话都以它为背景。
assistant 消息有一个容易被忽略的性质:它可以由程序伪造。程序往里塞一段”模型说过的话”,模型在下一轮会把它当成自己的历史。少样本示例靠这个性质工作,提示词注入也靠它。
模型不保存上一轮
第一轮传入的是 [system, user1],返回 assistant1。第二轮要带上 [system, user1, assistant1, user2],模型才接得住上一句。
如果第二轮只发 user2,模型不会知道之前聊过什么。桌面聊天产品看起来有记忆,是客户端把历史一起拼进了请求。模型这一侧只做一件事:看到什么,续写什么。
轮数一多,这份历史的体积会线性增长,而每次请求都要重新传输、重新计费。所谓长对话越聊越慢、越聊越贵,原因就在这里。
由此可以推出一条对 Agent 很关键的结论:上下文是程序维护的一份数据,不是模型的属性。循环每跑一轮,这份数据就长一截,费用和延迟跟着上涨。历史保留多少、在哪里截断,属于工程问题。
system 的权重来自训练
训练数据里有大量这样的配对:system 写一条规则,assistant 按规则回答。课程里的对照实验很直观:system 写”一位专业的技术助手”,模型自述为标准助手;换成”一只猫娘,每句话以喵结尾”,同一个问题得到带喵的自我介绍。两条 user 消息一字不差,差异全部来自那条 system。
机制在训练阶段。监督微调教会模型这种对话格式,基于人类反馈的强化学习进一步让它倾向于遵循前置指令。system 里的约束于是成为一种高优先级的条件,模型会把它当作当前任务的前提。
这也解释了它为什么是最便宜的行为定制。换模型要改架构和预算,微调要准备数据和算力,改一段文本只需要一次编辑。同一个模型在客服、编程、写作三个场景下表现差异很大,多数时候差异来自 system 内容,模型能力并没有变。做评测时把 system 固定下来,结果才具备可比性。
工程里的 system prompt 是结构化的
真实 Agent 项目的 system prompt 常有几百到几千 token,按块组织:角色说明、规则、输出格式、约束、示例。
1 | SYSTEM = """你是一个代码审查助手。 |
拆成小节的意义是让每条要求都能被单独定位。示例输入输出也常写在这里,本质是塞进 system 的少样本提示:给两组输入输出,模型会照着格式续写,比用一句话描述格式更稳。规则和输出格式混在一段散文里,模型容易顾此失彼;分块之后行为更稳定。
需要分清的是,system prompt 定义的是行为倾向,不提供强制力。使用者可以在 user 消息里写”忽略以上要求”,模型有一定概率照做。要把某类行为真正挡住,得在执行层做:工具参数校验、危险操作二次确认、允许清单。提示词是第一道约束,执行层的检查才是兜底。
两轮对话的实际写法
1 | import os |
关键在两次调用之间那次 append。去掉它,第二轮模型就不知道”排一下”指什么,因为它没有别的途径读取上一轮。这段代码里没有会话对象,也没有 session id,所谓对话就是这个列表在程序内存里的样子。
对搭 Agent 意味着什么
Agent 的结构可以概括成三样东西:一段设计好的 system prompt、一组工具、一个反复拼装 messages 的循环。上面三个事实各自对应一处设计。角色分工决定谁能往哪条消息里写;无状态决定历史必须由程序保存和裁剪;system 的权重决定行为的基线,真正的边界要靠代码守。
下一节换一个角度算账:这份列表按 token 计费,长度也有上限。


