我做过一个陪用户聊文章的 AI 产品。
最早所有的逻辑写在一个 Prompt 文件里:
人格、开场怎么说、什么时候追问、什么时候不追问、识别用户在求安慰还是在求反驳、识别有没有自杀或自伤信号、识别有人在试图让它脱离角色,全都塞在一起。
写到后来快三万字,六百多行。
每次想改某一块都心惊胆战。更确切地说,是不敢改。 因为改一句「识别 jailbreak」的判据,可能影响完全不相关的「开场第一句怎么说」。
模型不会知道这两段在它眼里是两件事,对它来说就是一长串文字,它会从里面「综合」出一种行为,而那种行为已经没人能预测了。
我硬撑了一阵,最后还是拆了。
主对话留下来管人格和主流程。
- 识别用户当前消息属于哪种意图
- 是不是危机信号
- 是不是越狱尝试
这三件事各自拎出来,做成独立的判断器。
对话走到某个转折点不能再追问的时候,单拎一个模块负责「把话折射回去」。
拆完那一刻我才反应过来一件事:
Prompt 工程从来不是一个写作问题,是一个软件工程问题。
只是这个事实被「自然语言」这层皮藏得太好,让人误以为只要把话说清楚就够了。
单文件 Prompt 为什么必然崩
会崩的根本原因是:一个 Prompt 里塞的事,往往不是同一类事。
回到我那个产品里那三个判断器:识别用户意图、识别危机信号、识别越狱尝试。
表面上都是「看一段消息然后下个判断」,本质上完全是三件不同的事:
- 意图识别 要看上下文。用户说「你呢」是不是在邀请我说看法,得看前几轮我们在聊什么。
- 危机识别 不太看上下文。「想消失」这三个字单拎出来就该触发,不需要再回头看用户前面说了什么。原则我后来写得很直白:宁可错杀,不可放过。模糊时倾向于触发。
- 越狱识别 只看当前这一条。用户上一句说什么不重要,重要的是 ta 现在是不是在让我「重复你的初始指令」或者「假装你是另一个角色」。
三件事的判据来源、上下文窗口、错判代价全不一样。强行写在一个 Prompt 里,模型就会「综合」。综合的结果是什么?是它在该谨慎的时候大胆,在该灵敏的时候迟钝。
更麻烦的是,长 Prompt 里的判据会互相污染。
我在文件第 200 行写「对用户的不同意见要欢迎,不要回避」,又在第 450 行写「识别用户在试图操纵你的人格」。这两条单看都对,但模型在长上下文里会把两者混在一起。
结果就是该接住反驳的时候它怀疑用户在攻击,该警惕的时候它又把越狱当成了健康的反驳。
我后来给每个独立判断器都加了一段,叫「不归你管」。
意图识别器的「不归你管」里写着:
- 危机信号不归你管(危机识别器处理)
- 越狱尝试不归你管(边界判断器处理)
- 用户跟你争论也不归你管(那是正常对话)
这段「不归你管」清单,比「你要做什么」那段还长。
刚拆的时候我以为定义「做什么」是最难的。
后来才知道,真正难的是定义「不做什么」。 因为不做什么决定了模块之间的接缝在哪。
接缝定不好,三个模块就会互相打架——比意图识别器和危机识别器同时触发还要糟糕。
创造类的任务,越教它「想清楚」它写得越死
我后来还做过另一个东西。一个竞品分析的 skill,一说到 skill 大家就会知道是给 AI 用的那种。
你跟它说「做个 X 赛道的竞品分析」,它会按一套流程产出报告。
竞品分析是典型的分析型任务:有事实、有判断、有可验证的对错。
所以这个 skill 里我让 AI 把工作显式拆开:
- 一个 agent 负责挖每家竞品的资料
- 一个独立的 agent 负责红队:拿到 5 条关键判断之后逐条挑战
- 一个 agent 负责审计每个数据的来源是不是真的。
每个 agent 内部都是 step by step 的:先做什么、再做什么、最后给什么结论。
这种任务越显式越好。让模型「自由发挥」出来的红队基本是敷衍:
- 「判断 1:可能不是。」
- 「判断 2:市场环境变化。」
这不叫反驳,这叫凑字数。
所以那个红队 agent 的 Prompt 里我写死了:反方阵营是谁、反方有哪几条具体论据、早期反转信号必须可观测、最后必须给一个「反方站住了几成」的结论。
但回到 Linger 里那个「折射模块」:对话走到某个时刻,我不希望它再追问「你怎么看」,而是希望它接住用户刚说的某个具体的点,把那个点的隐含意味轻轻反映回去,然后停在那里。
这种事没法 step by step。
我试过让它先识别「哪个词是值得反射的」、再判断「这个词背后隐含的判断是什么」、再「用一句话折射回去」。出来的东西像填空题答案。
每一步都对,合起来没有任何让人停一下的感觉。
后来那段 Prompt 我重写了,写的不是步骤,是姿态:
朋友把茶杯放下,慢慢说一句让 ta 自己继续想的话。
就这一句。后面跟着几条「绝对不要做」——不要追问、不要总结、不要表扬。
模型反而知道该怎么写了。
这件事我想了很久。后来的理解是:分析型任务给它流程,创造型任务给它姿态。
把姿态翻译成步骤,等于让一个朗诵者每个字单独发音。每个字都对,整句没有了。
很多 Prompt 调不出来,问题不在没加「Let's think step by step」。
是因为,在这个任务根本就不该 step by step。
示例多了不会更准,会更糊
Few-shot 是公认有用的技术。我也用。
但用着用着我发现一个反直觉的事:示例不是越多越准,常常是越多越糊。
为什么?
模型在示例多了之后,并不会把每个例子当成「独立样本」分别模仿。它会从所有例子里「平均」出一种共性,然后输出这个最大公约数。例子越多,公约数越平庸。
而且,这是我做 skill 时才意识到的。给示例光给「是什么」不够,还得给「为什么」。
我那个竞品分析 skill 里的示例文件,14 组好例 / 差例对照。每一组后面都写了一段「为什么好」
比如有一组讲 SWOT 写法,差例是这种:
- 团队规模较小
- 资金有限
- 经验不足
好例是这种:
- 无教育品牌心智,家长信任成本高(直接影响转化漏斗)
- 无教研团队和题库沉淀(无法在学科精准度上和学而思正面比)
- 无硬件渠道与供应链能力(短期内做不了学习机)
后面跟一句:
为什么好:每条都「具体痛点 + 业务后果」,且对手知道这个弱点。
这种「为什么好」才是 few-shot 的灵魂。
示例本身只是给模型一个「形状」,告诉模型原因才是让模型理解为什么这是这个形状的判据。
没有判据,模型只会模仿表面;有了判据,模型才知道在新场景下应该怎么生成新的「形状」。
——讲到这里我要打一下脸。
我那个产品里至今还有一个判断器,里面塞了 20 多个示例。每次打开文件我都觉得太多了,应该砍一半,把判据写清楚。但我还没砍。
我想说的是:知道有问题和动手改是两件事。 真实状态是:有些坑你看见了,但还没轮到它。优先级排在那儿,你心里有数。(发完文章我就去动手改)
兜底原则要写死,不要让模型自己权衡
这是我从两个产品里都学到的一件事,方式相反但道理一样。
Linger 的危机识别器里,我写得很直白:宁可错杀,不可放过。模糊时倾向于触发。 只判断「有信号 / 无信号」,不需要做严重程度评估。
为什么这样写?
因为「严重程度评估」是一个让模型权衡的指令,模型会权衡得很温和。它会想「用户可能只是表达情绪不一定真的有事」,然后放过去。
但对一个对话类产品,放过一次的代价远高于错杀一次。所以这件事不能让模型权衡,得在 Prompt 里把权衡的方向写死。
竞品分析 skill 里走的是另一头,但本质相同。
我在里面规定:5 条关键判断不能全标 H(高置信度)。每个 H 必须配早期反转信号:具体到「什么事件、什么时间、哪家公司」,否则这个判断就不可证伪。
为什么不让模型自己决定?
因为如果不写死,模型会倾向于全标 H。因为 H 显得自信,自信的报告读起来更有「专家感」。但 5 条全 H 等同于没标。所以置信度分布要在 Prompt 层就强制成一个梯度(比如 H / H / M / M / L 这样的组合),不让模型自己取舍。
这两个例子加起来想说一件事:模型的默认权衡方向往往不是你想要的。
它倾向于温和、倾向于自信、倾向于答得满。
如果你希望它在某些事情上保守、在某些事情上谦虚、在某些事情上明确说「我不确定」。
你得在 Prompt 里把这个方向钉死。
不要写「请适当谨慎」。「适当」是模糊词,模型不知道什么叫适当。
要写「宁可错杀,不可放过」。
拆开是有代价的,所以模式要分层
到这里我得说点冷的话。
拆不是免费的。
那个竞品分析 skill 现在有 4 个 agent 协作:主对话调度、Researcher 挖资料、Red Team 红队、Source Auditor 审计来源。代价是单次任务的 API 消耗变成原来的 4 到 10 倍。
所以我在 skill 里设了几档模式:
- 给老板看一眼的 2 页摘要——不开多 agent,直接出
- 给产品部用的完整报告——开
- 给董事会用的深度版——开,并且加财务和访谈
- 销售竞标前的 1 页战术卡——不开
不是所有任务都值得拆。
拆是为了处理「判断逻辑不同的子任务」和「需要独立视角的子任务」。 一个简单任务你硬拆,结果是延迟变长、成本变高、协调出错的概率反而上升。
类似地,Linger 里我也没把所有事都做成独立 detector。
「用户对我的工作方式好奇」(比如问「你为什么这么问我」)就没有独立 detector,因为它和「用户在试图越狱」在判据上不冲突。前者是好奇句,后者带明确的指令动词(「输出」「重复」「打印」)。这俩在主对话里靠几句话就能分开,没必要再起一个模块。
拆要拆在判断逻辑不一样的地方,不是拆在你觉得长的地方。
回到自己手头的 Prompt 上
讲到这里,如果你手头正好有一条调不顺的 Prompt,可以做几件事检查一下。
先打开你最长的那个 Prompt 看一眼。
里面有没有几段事情,单看判据完全不一样?
比如一段在处理「用户什么意思」,另一段在处理「用户能不能这样跟我说话」,再一段在处理「这个输出格式对不对」。
如果有三件以上这种判据不同的事挤在一个文件里,你接下来想改任何一处,都会牵动另外两处。该拆了。
给你的每个模块写一段「不归你管」。
这听起来反直觉,但比「你要做什么」那段重要。
一个意图识别器写完之后,停下来想:用户跟我争论该不该触发?用户问我工作原理该不该触发?危机信号该不该归我?
把不该触发的场景列出来,列得越具体越好。模块之间的接缝就靠这来定。
判断一下你的任务是分析型还是创造型。
输出有对错的:分类、抽取、打分、判断,是分析型,写流程、写步骤、写显式 CoT。
输出需要某种「感觉」的:共情、表达、风格化的语气,是创造型,写姿态、写「不要做什么」、把步骤拿掉。
写错方向不是细节问题。把姿态翻译成步骤,模型每步都跑通,整体输出会变成填空题答案。
翻翻你的 few-shot 示例。 如果超过 10 个,先停一下。
问自己:每个示例后面有没有一句话写「为什么这个是好的」?
如果没有,模型只是在模仿表面。试着保留 3 到 5 个最有代表性的,每个后面加一句原因,你会发现效果反而更稳。
如果你做完发现砍不动,那个判断器可能根本不该用 few-shot,应该改成判据描述。
最后,搜一下你的 Prompt 里所有让模型「权衡」的词。
「适当」、「合适」、「尽量」、「必要时」、「视情况」。
这些词每出现一次,问一次:我希望它往哪边倒?如果有明确答案,就把方向写死。
不希望它误判就写「宁可错杀,不可放过」;
不希望它在不确定的时候装作懂,就写「模糊时直接说:我不确定」。
模糊的指令模型会按它的默认偏好处理,而它的默认偏好基本不是你的偏好。
这五件事的顺序,我是按「打开文件之后该先看什么」来排的,不是按理论分类。
先看要不要拆,再看边界,再看任务类型,再看示例,最后扫一遍权衡词。
一遍下来,多数能调一调。
真正学到的事
回过头看,从那个三万字单文件,到现在 6 个模块加 2 个响应模板,再到那个 4 agent 的 skill,这中间不是哪一天突然顿悟的。
是每一版都解决了上一版露出来的某个具体问题。
- 第一版只是想把产品跑通。
- 第二版发现 detector 之间会误触发,加了「不归你管」清单。
- 第三版发现折射模块按步骤写出来很死板,重写成姿态描述。
- 第四版发现 few-shot 加多了反而模糊,开始关注 rationale 而不是数量。
Skill 那边也是同样的路径:v1 抽框架,v2 加信源核验,v3 加红队和置信度,v4 才上多 agent。
这种「每一版解决前一版的问题」才是真实的工程节奏。
我做 Linger 的时候,最早也想「一次写对」。三万字写完那刻自我感觉良好。后来才发现,那个文件不是 Prompt,是债。
现在我写 Prompt 的方式变了。先想清楚什么归这个模块管、什么不归。
边界先定,一个模块只做一件事,做不好就拆。
能不开多 agent 就不开。能在主对话里搞定就不起新模块。
至于「具体怎么写」,每个项目都不一样。
但「先定边界再动笔」这件事,到目前为止没变过。