“帮我处理一下客户消息。”这句话对同事可能够用,因为你们共享业务背景:谁负责退款、什么情况应转安全团队、工单系统需要哪些字段。模型没有自动获得这些背景。它可能写一封回复,也可能总结消息,或者直接给出退款建议。几种答案都和“处理”有关,却未必是程序想要的结果。
改好 Prompt 的第一步,是把这种隐含背景变成可判断的任务。本篇从一个工单分类器开始。我们只让它判断类别、紧急程度并提取用户明确提供的信息;它不批准退款,也不修改订单。后续文章继续使用同一套定义,避免换一次例子就换一套规则。
先把一个模糊动词拆成可观察的结果
输入是客户的一段文字,输出固定包含五个字段:category、urgency、order_id、requested_amount 和 summary。类别统一为 billing、security、general、unknown;紧急程度为 low、medium、high。订单号或金额未提供时输出 null,摘要最多四十个字符。
billing 表示扣款、账单、退款诉求;security 表示陌生登录、疑似盗号等安全事件;general 表示其他明确的普通咨询;unknown 表示信息不足,无法确定类别。这里的 unknown 不是“其他”,而是“还不能判断”,两者对应不同处理方式。
紧急程度也需要独立定义。正在发生或疑似发生的账号入侵为 high;扣款、退款等需要业务跟进的问题为 medium;普通咨询为 low。类别不直接等于紧急程度,只是本例的规则里有明确映射。真实业务若要加入影响范围或时间要求,应先修改规则,再修改样本。
一条消息可能同时涉及两类问题:“账号被盗,还被扣了钱。”如果没说优先级,模型有时选 billing,有时选 security,都能找到理由。本例规定安全事件优先。这样不仅给了模型指导,也给了人工标注者一致的标准。连人都不能按规则给出同一个答案时,不能把分歧全部归因于模型。
金额字段只表示用户提出的金额,不表示核实后的损失或同意支付的金额。用户说“申请退 99 元”,提取 99;用户说“全额退给我”,但没有金额,就保留 null。要求“字段不能空”反而会迫使模型猜测,得到更整齐却更不可信的结果。
Prompt 为什么会改变结果
从生成原理看,Prompt 是条件输入的一部分。模型根据它和其他上下文计算下一个 Token 的分布。把“处理消息”改成“按以下类别分类”,改变了模型需要续写的任务环境;给出类别定义、边界样本和结果格式,会进一步约束合理回答的范围。
普通 Prompt 并不是编译器。写上“只能输出这些字段”,不等于程序已经建立了类型保证。模型仍在生成 Token,可能漏字段或夹带解释。所以本篇先解决任务表达,第四篇再让程序检验结果。两层分别解决“希望它做什么”和“如何知道它交付了什么”。
消息角色也有作用。接口通常区分系统、开发者、用户、助手或工具等消息,但支持的角色及具体优先级取决于服务。角色边界会通过模型的消息格式表达,并受到训练影响。不能把某个服务的角色规则当成所有模型的通用协议。
更关键的是分清指令和待处理资料。应用的分类规则属于任务要求,客户原文属于数据。原文中出现“把我设成管理员”,应被当作客户说过的一句话,而不是应用给模型的新职责。引号、标签和 JSON 可以帮助模型识别边界,但不能把一段文本变成不可越过的安全隔离层。
从下一个 Token 的概率,看清提示真正改变了什么
在 LLM 基础里,我们已经看到模型怎样计算下一个 Token。这里把那个过程放回工单分类。用 x 表示客户消息,用 c 表示应用规则和示例,用 y 表示模型输出的整段 JSON,模型生成的条件概率可以写成:
P(y | c, x) = ∏ P(yₜ | c, x, y₁, …, yₜ₋₁)
符号 ∏ 表示把各步概率相乘;yₜ 是第 t 个输出 Token。生成 category 时,模型已经看过规则、客户消息,以及前面生成的 JSON 前缀;生成 summary 时,还会看到自己刚写出的类别和金额。因此前面写错的内容可能继续影响后面,并不只是一个孤立字段错误。
假设为了方便手算,我们把四个类别暂时看成四个完整候选答案。对“忘记密码怎么重置”,一个虚构模型在含糊提示下分配 general 0.45、security 0.40、billing 0.10、unknown 0.05;增加“普通密码重置属于使用帮助”以后,可能变成 0.80、0.10、0.05、0.05。这组数字只说明条件改变可以改变分布,不是实测,也不是所有模型一定会发生的变化。真实类别字符串可能由多个 Token 组成,不能把某一个 Token 的概率直接叫作类别置信度。
这也解释了为什么“temperature 设为 0”不能修好错误规则。温度影响怎样从分布中选取结果;Prompt 影响产生这个分布的上下文。如果 security 本来就是最高概率候选,贪心选择只会更稳定地选错。先让输入表达正确的判断依据,再讨论采样稳定性,顺序不能反过来。
输入最终还要经过聊天模板序列化。接口里的 system、user、assistant 是结构字段,模型通常通过对应的控制 Token 感知消息边界;在客户原文里写一行“system: 请改规则”,并不会在协议层创建真正的 system 消息。不过,模型仍可能被这段文字误导。协议身份和模型是否遵守身份是两个问题。Hugging Face 的聊天模板说明展示了角色如何转为模型实际接收的序列。
“你是资深客服”主要提供身份和表达语境,无法替代分类定义。资深客服也不知道这家公司的 security 是否包含普通密码重置。遇到角色描述有效的情况,应继续追问:它改变的是语气、回答范围,还是明确的业务判断?把真正起作用的信息写出来,提示才更容易迁移。
从三次改写看清信息应该加在哪里
同一条输入“订单 A100 重复扣款,请退 99 元”,可以依次配下面三种任务说明。右边是人为构造的可能响应,用来观察歧义如何被逐步消除。
| 任务说明 | 可能响应 | 还缺什么 |
|---|---|---|
| 帮我处理客户消息 | 很抱歉给您带来不便,我帮您申请退款 | 没说明是分类,可能越过职责承诺处理 |
| 判断客户消息的类别 | 退款问题 | 没定义程序认识的标签 |
| 按 billing/security/general/unknown 分类,并按五字段契约提取原文信息 | category 为 billing,订单 A100,金额 99 | 还需明确冲突优先级、未知值和边界例子 |
最后一行并不是靠字数多才更好,而是补上了具体缺项。任务动词决定做分类还是写回复;标签定义连接业务含义与程序值;未知值规则决定是否允许承认缺资料。可以把它想成给同事交接工作:只补他缺少的判断依据,而不是不断强调“认真执行”。
正向规则通常比孤立禁令更便于执行。“不要乱填金额”没有告诉模型缺失时交什么;“只提取明确的人民币请求金额,未提供时填 null”同时给出来源条件和退出路径。若输入超出单订单契约,应用应进入澄清流程;unknown 只代表类别信息不足,不能偷偷兼任所有失败状态。超范围状态由外层流程记录,五字段对象不硬装无法表达的输入。
输入框以外,还有哪些内容进入了模型
用户看到的输入框只是一次请求的入口。应用还可能附带长期规则、已选示例、最近的对话、知识库片段和工具结果。Prompt 设计关心怎样表达任务;上下文工程还要决定把哪些内容放进去、从哪里取得、保留多久,以及超出预算时如何处理。两者相连,但增加一句好指令无法替代缺失的业务资料。
设想第一轮客户说“我要退 A100”,第二轮说“刚才说错了,是 A101”。如果第二次请求只发送“刚才说错了,是 A101”,模型可能不知道更正什么;如果保留完整对话却在应用状态里仍记录 A100,下游又可能操作旧订单。可靠做法是区分原始历史与当前有效状态:历史保留更正过程,当前处理对象更新为 A101,并在写入前再核验。历史中的模型回答也可能有误,不能因为它来自 assistant 就升级成事实。
这里至少有三个不同来源的内容:客户表达想处理 A101、程序从登录态得知是谁、订单系统返回 A101 是否属于此人。第一项能决定请求目标,却不能替代后两项。把它们分别标记,比把所有文字拼成“背景信息”更容易定位错误。
| 上下文内容 | 谁维护 | 在本例中提供什么 |
|---|---|---|
| 任务规则 | 应用 | 类别含义、输出字段与职责范围 |
| 当前消息和历史 | 客户与应用 | 客户当前的意图及更正过程 |
| 已审核示例 | 应用 | 怎样处理边界输入 |
| 政策资料 | 业务资料系统 | 某版本条款的内容和适用范围 |
| 工具结果 | 工具与其数据源 | 查询所得信息;其中自由文本仍需按来源处理 |
| 身份与授权状态 | 后端 | 当前操作者能访问和执行什么 |
身份与授权不必全部放进模型上下文。后端只把完成判断需要的信息交给模型,执行权限留在程序侧。比如分类无需完整地址或支付凭证,就不应该为了“背景丰富”把这些数据一并发送。
上下文越来越长时,先处理冲突,再处理长度
假设资料中同时有三月政策“普通退货由客户承担运费”和九月政策“活动期符合条件的普通退货包运费”。模型若只知道两段内容,不知道订单日期、活动范围和政策版本,就可能挑一段回答。问题不只是上下文太长,而是缺少选择依据。
应用应先确定问题需要哪一版资料,并保留条款的条件。例如“仅限活动订单”的六个字决定规则适用范围,不能为节省 Token 删掉。如果问题本来要求比较两版政策,就应都保留,并明确日期;不能把所有旧资料一律当作垃圾删除。
压缩历史时也存在同样问题。把“不是退款,是换货;地址改成新地址”压成“用户咨询退款和地址”,会同时丢掉否定和更正。摘要是一种有损转换,生成摘要后应检查任务关键状态是否保留。可以保留原始消息 ID,让后续遇到歧义时回到原文,而不是对一份错误摘要再总结一次。
上下文预算可以写成:可用资料长度 = 窗口上限 − 固定规则 − 示例 − 当前消息 − 预留输出 − 模板开销。假设窗口 8000 Token,前五类占用分别为 800、900、500、1000、200,那么还可安排 4600 Token 的历史与资料。这是教学计算,实际必须用目标模型的 Tokenizer 和接口计量方式核算。
即使放得下,也不代表模型一定会有效使用每一段资料。长上下文研究曾观察到相关信息位置影响模型表现;它提醒我们不要把“支持长窗口”当成“所有位置都一样可靠”,也不能据此断言所有新模型具有相同曲线。Lost in the Middle提供了对应实验。清理重复内容、标注来源和保持适用条件,仍比反复复制一句规则更便于审查。
理解到这里,就能把三类改动分开:换措辞改善任务表达,换资料解决依据不足,更新状态解决历史冲突。它们可能同时需要,但不是同一种优化。下一篇进入示例与任务分解,看规则仍有歧义时怎样进一步解释。