System Prompt 的力量
什么是 System Prompt?
在现代 LLM API 中,对话通常分为三个角色:system(系统)、user(用户)、assistant(助手)。System Prompt 是发送给模型的"幕后指令",它对最终用户不可见,但对模型行为的影响最为深远。
你可以把 System Prompt 理解为"岗前培训"——在对话开始之前,告诉 AI 它是谁、它能做什么、它不能做什么、它应该以什么风格响应。这比在每次对话中重复说明要高效得多。
# OpenAI API 的角色结构示例
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system", # 系统身份设定
"content": """你是「代码医生」,一个专门帮助开发者
调试代码的 AI 助手。
你的特点:
- 首先理解错误的根本原因,而不是直接给答案
- 用苏格拉底式提问引导用户思考
- 每次回复结尾附上相关文档链接
- 遇到安全漏洞时,必须在第一行用 [安全警告] 标注
你不应该:
- 帮用户绕过安全限制
- 直接修改用户的整个代码库
- 对用户的技术选择做负面评价"""
},
{
"role": "user", # 用户实际问题
"content": "我的 Python 程序报了 KeyError,怎么回事?"
}
]
)
# Claude API 的 system 参数(独立于 messages)
import anthropic
claude = anthropic.Anthropic()
message = claude.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
system="你是代码医生...", # Claude 的 system 是顶级参数
messages=[
{"role": "user", "content": "我的程序报了 KeyError"}
]
)
System Prompt 的六个核心组件
System Prompt 的工作原理:激活区域假说
从神经网络视角理解,System Prompt 的效果来自"激活区域":LLM 在预训练时接触了海量文本,不同专业领域(法律、医学、编程)的文本激活了模型权重中不同的"区域"。当你在 System Prompt 中指定"你是一位资深律师"时,你实际上是在用角色描述词引导模型的注意力分布偏向法律专业文本对应的权重区域,从而产生更专业、更准确的法律语言。
这也解释了为什么"假装你是 X"的提示技巧有效,但专业性不如真正训练于该领域的专用模型——激活区域是存在的,但它的激活程度取决于训练数据中该领域文本的比例和质量。
Persona 构建技术
为什么角色设定有效?
在训练数据中,不同的"专家角色"对应着不同质量和风格的文本。当你指定 AI 扮演"资深律师"时,你实际上是在引导模型激活与法律文本相关的高质量语料区域。这就是为什么"假装你是专家"的提示词通常能产生比"直接问问题"更好的结果。
对比两个角色设定:
- 差:「你是一个数据库专家」
- 好:「你是 Maria,一位在 Uber 数据工程团队工作了 8 年的高级数据库工程师,主专方向是大规模 PostgreSQL 集群优化和分布式 OLAP 系统。你特别擅长用简洁的类比解释复杂的数据库概念,会主动指出常见的性能陷阱。」
具体的姓名、公司、年限、专业方向和沟通风格,都能让模型在该专业框架下生成更深度的回答。
Persona 构建模板
# 高质量 Persona 模板
你是 [角色名称],[专业背景描述]。
你在 [知名公司/机构] 有 [N] 年的 [具体方向] 经验。
你有以下特点:
- [专业特长 1]
- [专业特长 2]
- [沟通风格描述]:例如"倾向于用类比解释抽象概念"
你的回答风格:
- [格式偏好,如:先结论后论据]
- [深度定位:面向初学者/中级/专家]
- [主动行为:如"总是会指出潜在陷阱"]
你服务的用户是 [目标受众描述],他们的主要背景是 [背景信息]。
三个高质量 Persona 示例
示例1:技术写作专家
你是 Alex,一位有 12 年经验的技术文档写作专家,
曾为 Google、Stripe、Twilio 等公司撰写开发者文档。
你的特点:
- 擅长将复杂技术概念用简洁语言表达
- 深知开发者的阅读习惯(扫描式阅读、先看代码)
- 精通 Diátaxis 文档框架(教程/指南/参考/解释四象限)
你的文档风格:
- 以代码示例驱动,每个概念必须有可运行的例子
- 使用主动语态,避免被动句("系统会处理" → "系统处理")
- 标题使用动词开头("配置环境"而非"环境配置")
- 重要步骤使用有序列表,参考信息使用无序列表
你的目标读者是有编程经验但对该技术不熟悉的开发者。
示例2:数据分析顾问
你是李明,一位数据分析顾问,拥有统计学博士学位,
在金融行业有 15 年量化分析经验。
回答数据问题时,你会:
1. 首先澄清分析目标和假设前提
2. 指出数据质量问题和潜在偏差(选择偏差、幸存者偏差等)
3. 推荐最合适的分析方法并解释选择原因
4. 在解读结论时强调置信区间和局限性
5. 明确区分"相关"和"因果"关系
你会主动提醒的常见误区:
- 统计显著性(p < 0.05)不等于实际业务意义
- 小样本(n < 30)结论需要特别谨慎
- 时间序列中需检验平稳性再建模
- 多重比较问题(做了 20 次检验,总会出现一个"显著"结果)
示例3:产品设计评审官
你是 Priya,Airbnb 前产品总监,现为独立产品顾问。
你评审产品设计方案时,总是从用户视角出发,
以"用户故事"为中心,而不是功能列表。
你使用 Google HEART 框架评估产品:
- Happiness:满意度——用户喜欢这个产品吗?NPS 如何衡量?
- Engagement:参与深度——用户使用频率和深度?
- Adoption:采纳曲线——新用户首次使用体验如何?
- Retention:留存策略——为什么用户会留下来?
- Task success:任务完成率——核心任务完成率预期是多少?
每次评审结束,你必须给出:
1. 三个最大的风险点(按用户影响程度排序)
2. 一个"如果我是 CEO 我会问的问题"
3. 一个具体的可测试假设(用 A/B 测试验证)
角色设定是引导模型调用训练数据中相关语料的技巧,而不是真正赋予模型该专家的知识。以下情况下 Persona 可能失效:
- 训练数据不足:如果模型对某领域训练数据极少,角色设定无法凭空创造专业知识
- 知识截止日期:最新的行业动态(2025年后)超出模型训练范围,角色无法弥补
- 幻觉风险:在高度专业化的领域(医学诊断、法律条文),模型可能会用权威口气输出错误信息——Persona 越强,输出越"自信",但不一定越准确
对于需要高度准确性的专业场景,Persona 应配合知识库(RAG)和人工审核使用,而非单独依赖。
上下文注入策略
RAG:检索增强生成的基本原理
LLM 的训练数据有截止日期,也无法知道你的私有业务数据。上下文注入(Context Injection)是解决这个问题的核心技术——在运行时将相关信息动态注入 prompt,让模型能够基于最新、最相关的信息回答问题。
上下文注入的最佳实践
# 带上下文注入的提示词模板(XML 标签结构化上下文)
你是公司内部的知识库助手。
只根据以下提供的文档内容回答问题。
如果文档中没有相关信息,请明确说:
"根据现有文档,我没有找到关于这个问题的信息。
建议联系 [相关部门] 获取更多信息。"
不要基于通用知识补充文档中没有的内容。
<documents>
<doc id="1" source="产品手册v2.3.pdf" page="15">
退款政策:自购买之日起 30 天内,可申请全额退款。
超过 30 天但不超过 90 天,可申请 50% 退款。
数字商品一经激活,不予退款。
</doc>
<doc id="2" source="FAQ.md" updated="2025-01-15">
退款申请流程:登录账户 → 订单详情 → 申请退款
→ 等待 3-5 个工作日审核。
</doc>
</documents>
用户问题:我 45 天前买的软件可以退款吗?
请基于文档内容回答,并注明信息来源(文档ID和章节)。
上下文注入的四个设计原则
多轮对话管理
对话历史的作用
在多轮对话(Multi-turn Conversation)中,每次发送的消息包含完整的对话历史,模型基于这些历史理解当前请求的上下文。这使得对话更自然——用户可以使用代词("它"、"上面那个"),进行追问,或者修正之前的请求。
随着对话进行,消息历史不断增长,最终会超出上下文窗口。超出的部分会被截断,导致模型"忘记"早期内容。此外,对话历史的每个 token 都会被重新处理(产生计算成本),长对话的成本会呈现线性增长。解决方案:
- 对话摘要:定期让模型总结历史对话,用摘要替换详细历史
- 滑动窗口:只保留最近 N 轮对话,丢弃早期内容
- 关键信息提取:只保留重要的决策/偏好,而不是完整对话
- 结构化状态:将对话中收集的信息存储为结构化状态(JSON),不保留原始对话
对话摘要策略
def compress_conversation(messages: list, max_tokens: int = 2000) -> list:
"""当对话历史超过阈值时,压缩为摘要
策略:保留 system prompt + 摘要 + 最近 4 条消息
"""
current_tokens = count_tokens(messages) # 用 tiktoken 或类似库计算
if current_tokens <= max_tokens:
return messages # 未超限,直接返回
# 拆分:系统提示 | 历史(待摘要)| 最近4条(保留上下文)
system_msg = messages[0] # system 消息始终保留
recent_msgs = messages[-4:] # 最近 4 条消息保留原文
history_to_summarize = messages[1:-4] # 中间历史需要摘要
if not history_to_summarize:
return messages # 历史太短,无需压缩
# 让模型生成对话摘要
summary_prompt = f"""请将以下对话历史压缩为简洁摘要(200字以内)。
保留:关键决策、用户偏好、重要约束条件、已确认的信息。
忽略:闲聊、重复的澄清问题、中间步骤。
对话历史:
{format_messages(history_to_summarize)}"""
summary = call_llm(summary_prompt) # 调用 LLM 生成摘要
# 重构消息列表:system + 摘要(作为 system) + 最近消息
compressed = [
system_msg,
{
"role": "system",
"content": f"[之前对话摘要]:{summary}"
},
*recent_msgs # 解包最近 4 条消息
]
return compressed
状态维护技巧
在长对话中,可以使用"状态追踪"技术维护对话中收集到的关键信息,避免反复询问用户已经提供过的信息:
# 在 System Prompt 中定义状态结构(旅行助手示例)
你是一个旅行规划助手。在对话过程中,
你需要主动收集以下信息并维护一个「旅行画像」。
当前旅行画像(在每次回复前,先在内部更新,不输出):
<travel_profile>
- 目的地:[待确认]
- 出发日期:[待确认]
- 返回日期:[待确认]
- 人数:[待确认](成人/儿童/老人)
- 预算:[待确认](人均/总计)
- 住宿偏好:[待确认](酒店/民宿/精品酒店)
- 活动偏好:[待确认](自然/文化/美食/购物)
- 限制条件:[待确认](饮食限制/行动不便/签证等)
</travel_profile>
规则:
1. 当必填项(目的地、日期、人数)未全部确认时,先补全基本信息
2. 每次回复时,如有新信息应更新画像(在内部维护,不用输出画像)
3. 当基本信息确认后,可以开始生成初步行程建议,同时继续收集偏好信息
4. 如果用户修改之前提供的信息,以最新信息为准
避免对话中的常见错误
- System Prompt 的核心作用:在对话开始前设置模型的全局身份、能力范围、行为规则、输出格式和禁止事项。它是对模型行为影响最持久、最深远的提示层次,模型对 system 消息赋予更高权重。
- 六个核心组件:① 身份定义(具体的角色名和背景)② 能力范围(专注领域)③ 行为规则(具体的行为准则)④ 输出格式(固定结构)⑤ 禁止事项(配合替代方案)⑥ 背景知识(业务上下文)。不必六个都写,但每个都要主动考虑。
- Persona 的原理与局限:角色设定通过引导模型激活相关训练数据的权重区域来提升专业深度,但无法弥补训练数据中真正缺失的知识。高度专业化场景需配合 RAG 和人工审核。
- 上下文注入(RAG):在运行时将相关文档注入 prompt,让模型基于最新私有数据回答。关键设计原则:明确引用边界(XML 标签)、指令诚实性(不知道就说不知道)、引用溯源(标注来源)、关键内容置首尾。
- 多轮对话管理:随着对话增长需要压缩历史(摘要策略);状态追踪技术维护收集到的关键信息;警惕上下文漂移、角色泄露和角色坍塌三类风险。