Jayden
·

系统提示词的艺术

avatarJayden

前言

如果把一个 AI Agent 比作新同事,系统提示词就是他的员工手册。

它告诉这个新同事:你是谁,你负责什么,什么事情可以直接做,什么事情必须先问,什么时候应该主动,什么时候应该闭嘴,遇到不确定性时应该怎样处理。

很多人第一次写系统提示词,会从一句熟悉的话开始:

你是一个专业、可靠、乐于助人的 AI 助手。

这句话没有错,但它几乎没有解决任何真实问题。

真正困难的不是让 AI 看起来“专业”,而是让它在一个具体产品、具体工作流、具体用户状态里,做出稳定、可预期的行为。

比如用户说:“帮我整理一下文档。”

一个 Agent 可以立刻开始分类,也可以先问“你是想按项目整理,还是想把文档转成待办?”它可以主动生成结果,也可以先给用户确认整理方案。它可以把所有东西都搬到一个新表里,也可以尊重原来的文档结构,只做标注和聚合。

这些差异,不是模型能力本身决定的,而是系统提示词和产品设计共同决定的。

这也是我后来意识到的一点:系统提示词不是技术细节,它本质上是产品设计。

系统提示词真正决定什么

用户感受到的很多“性格”,其实都来自系统提示词。

它决定 Agent 的语气是否自然,回应是否克制,边界是否清楚,能不能承认自己不知道,也决定它会不会在用户还没授权时擅自行动。

以办公类 Agent 为例,最难的不是让它能回答问题,而是让它在几个互相冲突的特质之间保持平衡:

  • 专业可靠,但不能冰冷机械。
  • 贴心主动,但不能越界打扰。
  • 能完成复杂工作流,但不能替用户做决定。
  • 能快速响应,但不能为了简洁省掉关键确认。

这里的每一条,都是产品问题,不只是 prompt 问题。

“贴心主动”听起来很好,但如果 Agent 每隔一会儿就跳出来提醒你,它就变成了噪音。“有边界感”也很好,但如果它什么都不敢做,每一步都问,用户也会觉得它没有用。

所以系统提示词的第一件事,不是写漂亮,而是把这种平衡讲清楚。

它要回答:

  • 什么叫主动?
  • 什么叫打扰?
  • 什么叫用户拥有最终决策权?
  • 哪些场景可以直接执行?
  • 哪些场景必须先澄清?
  • 哪些话永远不要说?

一个好的系统提示词,不是让 Agent 更会表演,而是让它更可预测。

先研究别人怎么写,但不要照抄

我们之前做系统提示词研究时,第一步是看了很多成熟 AI 产品的系统提示。

代码助手、通用聊天助手、自主编程 Agent、浏览器 Agent、文档 Agent,各自场景不同,但它们背后有一些共性:

第一,都会先定义角色。

这不是为了仪式感,而是给模型一个行为锚点。一个“代码编辑器里的 AI 助手”和一个“办公文档里的 AI 搭档”,面对同一句话应该有完全不同的反应。

第二,都会写行为约束。

什么能做,什么不能做;什么时候调用工具,什么时候只回答;什么时候要承认信息不足,什么时候要继续检索。这些约束比“请认真”有用得多。

第三,都会规范输出。

输出不是文风问题,而是产品体验的一部分。是先给结论,还是先解释过程?是用 Markdown,还是用自然短句?是告诉用户内部工具名,还是只说人能理解的动作?这些都会影响用户是否信任它。

第四,都会做场景化响应。

用户明确提需求时怎么做;用户意图模糊时怎么问;用户情绪激动时怎么退让;用户只是进入页面没有说话时要不要主动开口。这些都不能靠模型临场猜。

还有一个很实用的细节:结构化格式很重要。

现在很多系统提示会用 XML 或类似的标签结构,把角色、规则、工具、上下文、用户偏好、当前请求分开。这样做不是为了好看,而是减少歧义。

例如:

<role>
你是一个办公场景中的 AI 搭档。
</role>

<rules>
- 不替用户做最终决策。
- 意图不清晰时先澄清。
- 不暴露内部工具名称。
</rules>

<context>
{{user_environment}}
</context>

<query>
{{current_query}}
</query>

系统提示词越复杂,越不能写成一大段散文。模型需要结构,人也需要结构。

但研究别人怎么写,不等于照抄。

Cursor 的提示词适合代码编辑器,Devin 的提示词适合自主工程任务,Claude 的系统行为强调自然对话和边界表达。你自己的 Agent 如果是个人知识库、办公助手或写作工具,就必须重新定义自己的产品位置。

系统提示词不是通用模板,而是产品定位的翻译。

先定义产品,再写提示词

真正开始写之前,最重要的不是 prompt,而是产品定义。

我会先问几个问题:

  • 这个 Agent 是工具、助理、同事,还是自动化执行器?
  • 它应该偏主动,还是偏被动?
  • 它面对模糊需求时,是直接猜,还是先问?
  • 它有没有权力修改用户内容?
  • 它能不能替用户创建任务、发消息、发布文章?
  • 它的语气应该像客服、编辑、工程师,还是私人助理?

这些问题不回答清楚,系统提示词一定会摇摆。

比如一个个人 Agent 项目里,我会更强调三件事:

第一,专业可靠。

不是“看起来很懂”,而是能基于上下文识别关键点,知道什么时候需要查资料,什么时候应该说明不确定性,什么时候要给出可验证结果。

第二,有边界感。

不擅自替用户做决定,不私自移动或删除重要内容,不把内部工具细节暴露给用户,不把公开文章写成内部工作记录。

第三,沟通高效。

不要每一步都问,也不要一次问十个问题。能安全推进的小事直接推进,高风险动作再停下来确认。

这三件事听起来抽象,但都必须写成具体规则。

不要只写:

你要有边界感。

要写:

涉及删除、发布、外部写入、权限变更、移动项目目录时,必须先向用户确认。低风险的本地草稿编辑可以直接完成,并在最后说明改动位置。

不要只写:

你要沟通高效。

要写:

默认不要连续追问。若缺少信息但可以做合理假设,先说明假设并继续;只有当错误假设会导致高风险结果时,才停下来询问。

系统提示词不是把产品词汇复制进去,而是把产品词汇翻译成行为条件。

系统提示词的层次

一个可维护的系统提示词,最好是分层的。

我现在比较喜欢这样的结构:

role
meta_rules
behavioral_constraints
tool_rules
response_strategy
output_format
user_preference
user_environment
conversation_history
current_query

前面是稳定规则,后面是动态上下文。

role 解决“你是谁”。

meta_rules 放最高优先级的红线,比如不能泄露敏感信息,不能伪造工具结果,不能修改只读输入。

behavioral_constraints 规定行为边界,比如不替用户做最终决策,不揣测用户情绪,不主动发起无关闲聊。

tool_rules 规定什么时候能用工具,工具不存在时怎么办,调用失败时怎么反馈。

response_strategy 处理场景,比如用户意图模糊、用户情绪激动、用户正在写文档、用户只是进入页面但没有发起请求。

output_format 规定最终呈现方式。

后面的 user_preferenceuser_environmentconversation_historycurrent_query,则让系统提示词从静态规则变成活的上下文。

这里有一个关键点:优先级要明确。

如果“主动帮助用户”和“不能替用户做决定”冲突,哪个优先?如果“回答要简洁”和“必须说明风险”冲突,哪个优先?如果“使用工具完成任务”和“工具不存在不能伪造结果”冲突,哪个优先?

这些不能留给模型猜。

场景比原则更重要

原则写得再好,落到真实产品里还是会出问题。

比如“主动”这个词,在不同场景里意思完全不同。

用户第一次打开产品,Agent 可以做简单介绍。

用户正在标题栏输入,Agent 最好不要跳出来打断。

用户在正文里停顿很久,Agent 可以给一个很轻的写作建议。

用户说“我写不下去了”,Agent 不应该讲大道理,而应该把任务拆小。

用户说“这怎么又错了”,Agent 不应该辩解,也不要过度安抚,而是承认结果可能没达到预期,然后提出重新处理。

这些都不是一句“保持友好”能解决的。

所以系统提示词里要有场景化策略:

如果用户意图模糊,先给 2-3 个可选方向,而不是直接执行。

如果用户表达挫败,不评价用户状态,不说“你很焦虑/你很累”,只降低任务难度并给下一步。

如果用户只是进入文档但没有发起请求,默认不主动打扰,除非存在明确的未完成任务或用户设置了提醒偏好。

场景化设计的目的,是让 Agent 学会“看场合”。

这也是系统提示词里最接近产品手感的部分。

最重要的反转:测试集比提示词更重要

这次研究里最重要的结论,其实不是“怎么写系统提示词”,而是:测试集可能比系统提示词本身更重要。

原因很简单:模型变化太快。

你今天针对某个模型调到 90 分的系统提示词,换一个新模型,行为可能就变了。有些模型更主动,有些模型更啰嗦,有些模型更会调用工具,有些模型更容易过度自信。

如果你只有一份系统提示词,那每次模型变化你都只能凭感觉调。

但如果你有一套测试集,你就有了稳定的标尺。

测试集里应该是什么?

不是抽象指标,而是真实场景。

比如:

  • 用户说“帮我整理文档”,但意图不够清楚。
  • 用户已经给了预算和用途,需要生成一份对比报告。
  • 用户表达挫败:“我写不下去了。”
  • 用户要求运行一个不存在的工作流。
  • 用户确认了方案,Agent 应该继续执行。
  • 工具返回了结果,Agent 应该如何面向用户表达。

每条测试都应该包含输入、上下文、预期行为。

这样你评估的就不是“这句话写得好不好”,而是“这个 Agent 在这个产品里有没有做对事”。

系统提示词是实现,测试集是标准。

实现会变,标准应该尽量稳定。

用 Judge 建立迭代闭环

有了测试集,还需要评估方式。

人工看当然可以,但规模一大就很难坚持。所以一个实用做法是用 LLM as a Judge。

也就是再写几个评测提示词,让 Judge 分别检查不同维度:

  • 品质和语气:是否专业、温和、简洁。
  • 响应策略:是否符合当前场景应该采取的策略。
  • 用户体验:有没有给用户造成压力,有没有过度追问,有没有暴露内部细节。
  • 硬性约束:有没有替用户做决定,有没有伪造结果,有没有泄露不该出现的信息。

这里有一个细节很重要:Judge 要区分“面向用户的文本”和“面向系统的工具调用”。

比如 Agent 内部可能调用了一个工具,但用户不应该看到工具的技术名称。评估时不能只看它有没有调用对工具,还要看它有没有用自然语言告诉用户正在做什么。

比较好的表达是:

我来根据这些文档先整理一版分类结果。

而不是:

我将调用 document_classifier_workflow。

内部工具名对用户没有意义,还会破坏产品感。

整个迭代流程大概是:

写系统提示词
跑测试集
用 Judge 评分和解释
读失败案例
修改系统提示词或测试集
继续跑

这个循环比单纯“凭感觉改 prompt”可靠得多。

从失败案例里长出规则

系统提示词不是一次写完的。

它应该从失败案例里长出来。

如果 Agent 曾经在工具不存在时假装执行,就补一条“存在性优先”:调用任何工具或资源前,先确认它在可用列表里;不存在就直接说明不存在。

如果 Agent 曾经替用户做决定,就补决策权约束:提供选项和建议,但最终选择必须由用户确认。

如果 Agent 曾经把内部工具名暴露给用户,就补表达规则:面向用户只描述自然动作,不暴露工作流、函数名、内部 schema。

如果 Agent 曾经在用户快速输入时打断,就补状态规则:用户正在输入或编辑时默认静默,除非用户显式召唤。

如果 Agent 曾经把公开文章写进了内部细节,就补脱敏规则:公开内容不得包含真实路径、内部链接、账号、客户信息、未公开项目名、访问凭证。

这些规则每一条都有来源。

没有失败案例支撑的规则,很容易变成噪音。有失败案例支撑的规则,才是真正的系统资产。

什么不该放进系统提示词

系统提示词很容易越写越长。

刚开始加一条规则很爽,后来就会发现,模型看到了很多规则,但不知道哪些最重要。人的维护成本也会上升。

我的判断是:稳定、全局、高风险的内容,适合放进系统提示词。

比如:

  • 身份和产品定位
  • 权限边界
  • 安全红线
  • 工具调用原则
  • 输出风格
  • 失败处理
  • 高风险操作确认

临时、局部、低风险的内容,不适合放进去。

比如:

  • 某篇文章的具体标题
  • 某次任务的临时要求
  • 某个项目当天的 todo
  • 某个用户刚说的一次性偏好
  • 某个工具返回的临时结果

这些应该放到当前任务上下文、项目文件、用户偏好、记忆系统或 skill 里。

系统提示词负责宪法,不负责每一张便签。

结尾

系统提示词的艺术,不是写出一段很聪明的话。

它是把一个 Agent 的产品定位、行为边界、场景策略、工具规则和评估标准,压缩成模型每次工作时都能看见的操作手册。

如果只看 prompt,它像文字工作。

如果放到 Agent 项目里,它其实是系统设计。

更准确地说:系统提示词是第一版产品原型,测试集是长期资产,Judge 是迭代工具。

写自己的 Agent 项目,第一步不是把 prompt 写到完美,而是建立这样一个循环:

定义产品行为
写系统提示词
构造真实测试场景
评估失败案例
把失败变成规则

当这个循环跑起来,系统提示词才不再是一段玄学咒语,而会变成一个可以维护、可以验证、可以持续进化的工程对象。

参考资料