一、问题背景:为什么“随便写个Prompt”在生产环境会出事

最近在做一个商品评论摘要模块,输入是用户对某款蓝牙耳机的多条评论,输出是一段不超过80字的摘要,要求包含“音质、续航、佩戴”三个维度的倾向性。

一开始团队里有人写了个极简Prompt:

总结以下评论。

上线后问题很明显:

  • 有的输出80字,有的输出300字,前端卡片直接被撑爆;
  • 有的只总结“音质”,漏掉续航和佩戴;
  • 中文里混英文,甚至出现“根据评论,音质 good”这种中英夹杂;
  • 最要命的是,Token消耗波动极大,按OpenAI计费,单条从180 Token到900 Token都有,成本不可控。

于是我们决定做一次系统的Prompt Engineering对比实验。目标很明确:在保证输出质量的前提下,把单条平均Token压到可预测范围内。

二、环境与版本

实验环境如下:

  • Python 3.11.9
  • openai==1.52.0
  • transformers==4.46.3
  • vLLM 0.6.3(用于本地Qwen推理)
  • 模型:
  • GPT-4o mini(2024-07-18版本,temperature=0.2,top_p=0.9,max_tokens=256)
  • Qwen2.5-7B-Instruct(本地A100 40G,bfloat16,temperature=0.2,top_p=0.9,max_tokens=256)
  • 数据集:200条真实蓝牙耳机评论,每条评论平均长度约120字,最多15条评论合并为一个输入。
  • 评估指标:
  • 格式合规率:输出是否为纯中文、是否≤80字、是否含三个维度;
  • 人工评分:3人盲评,1-5分,取平均;
  • Token消耗:prompt_tokens + completion_tokens;
  • 成本:按GPT-4o mini输入$0.15/1M tokens、输出$0.60/1M tokens估算。

三、方案设计:6版Prompt的演进

我把6版Prompt分成三组:

  1. 基线组
  2. P0:零样本,极简指令:“总结以下评论。”
  3. P1:零样本+长度约束:“用不超过80字总结以下评论,包含音质、续航、佩戴。”

  4. 结构化组

  5. P2:P1 + 输出格式要求:“输出为纯中文,不要英文,不要分点。”
  6. P3:P2 + JSON Schema:“输出JSON:{“summary”: “...”, “sound”: “...”, “battery”: “...”, “comfort”: “...”}”

  7. Few-shot组

  8. P4:P3 + 1个示例;
  9. P5:P3 + 2个示例,且示例覆盖“正面+负面”两种倾向。

核心实现代码如下,统一封装调用函数:

import os
import json
import time
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def call_gpt(prompt: str, model="gpt-4o-mini-2024-07-18"):
    start = time.time()
    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
        temperature=0.2,
        top_p=0.9,
        max_tokens=256,
    )
    latency = time.time() - start
    usage = resp.usage
    return {
        "text": resp.choices[0].message.content,
        "prompt_tokens": usage.prompt_tokens,
        "completion_tokens": usage.completion_tokens,
        "total_tokens": usage.total_tokens,
        "latency": latency,
    }

Prompt模板统一用字符串拼接,便于对比:

PROMPTS = {
    "P0": "总结以下评论。\n\n{reviews}",
    "P1": "用不超过80字总结以下评论,包含音质、续航、佩戴。\n\n{reviews}",
    "P2": "用不超过80字总结以下评论,包含音质、续航、佩戴。输出为纯中文,不要英文,不要分点。\n\n{reviews}",
    "P3": """用不超过80字总结以下评论,包含音质、续航、佩戴。
输出JSON,字段为summary、sound、battery、comfort,值均为中文。
不要输出JSON以外的内容。

评论:
{reviews}""",
    "P4": """用不超过80字总结以下评论,包含音质、续航、佩戴。
输出JSON,字段为summary、sound、battery、comfort,值均为中文。
不要输出JSON以外的内容。

示例:
评论:音质不错,低音有力,续航大概6小时,戴久了耳朵疼。
输出:{"summary":"音质好,续航6小时,佩戴久了不适","sound":"好","battery":"6小时","comfort":"久戴不适"}

评论:
{reviews}""",
    "P5": """用不超过80字总结以下评论,包含音质、续航、佩戴。
输出JSON,字段为summary、sound、battery、comfort,值均为中文。
不要输出JSON以外的内容。

示例1:
评论:音质不错,低音有力,续航大概6小时,戴久了耳朵疼。
输出:{"summary":"音质好,续航6小时,佩戴久了不适","sound":"好","battery":"6小时","comfort":"久戴不适"}

示例2:
评论:音质一般,高音刺耳,续航只有4小时,佩戴很轻几乎无感。
输出:{"summary":"音质一般高音刺耳,续航4小时,佩戴轻无感","sound":"一般","battery":"4小时","comfort":"轻无感"}

评论:
{reviews}""",
}

四、踩坑与优化:那些文档不会告诉你的细节

坑1:JSON Schema不是越细越好。
P3一开始我写了完整JSON Schema,包括type、required、description,结果模型经常把Schema本身也输出出来。后来改成“只描述字段和值”,格式合规率从72%升到94%。

坑2:Few-shot示例顺序影响很大。
P5里如果两个示例都是正面,模型对负面评论会强行总结成“音质好”。把第二个示例改成负面后,负面样本的评分从2.8升到4.1。

坑3:max_tokens=256对P3/P4/P5不够。
JSON输出容易在字段间加换行和空格,completion_tokens经常冲到220以上。后来把max_tokens提到320,但平均completion_tokens反而下降了,因为模型不再被截断后“硬凑”。

坑4:Qwen2.5-7B-Instruct对英文指令更敏感。
同样的Prompt,中文版在Qwen上格式合规率只有81%,把指令改成英文、示例保留中文后,合规率升到93%。但GPT-4o mini上中英文差异不大,所以最终线上用了两套Prompt。

坑5:Token消耗的大头其实是输入。
200条评论合并后,输入平均在900-1200 Token。P5因为加了2个示例,输入多了约180 Token,但输出反而更短、更稳定,总Token只增加18%。

五、效果数据:6版Prompt的硬核对比

在200条测试集上,GPT-4o mini的结果如下(人工评分取3人平均):

Prompt 格式合规率 人工评分 平均Prompt Token 平均Completion Token 平均总Token 单条成本(USD)
P0 61% 2.4 1020 210 1230 0.000279
P1 78% 3.1 1035 165 1200 0.000254
P2 86% 3.5 1050 140 1190 0.000241
P3 94% 4.0 1080 155 1235 0.000255
P4 96% 4.2 1180 145 1325 0.000264
P5 98% 4.5 1260 135 1395 0.000273

几个关键结论:

  1. P0最便宜但最不可用:格式合规率61%,人工评分2.4,线上会直接崩。
  2. P3是性价比拐点:格式合规率94%,评分4.0,总Token只比P0多0.4%。
  3. P5质量最好但成本最高:评分4.5,总Token比P3多13%,单条成本多7%。
  4. P4和P5差距不大:如果预算紧张,P4是更稳的选择。

在Qwen2.5-7B-Instruct上,P5的格式合规率93%,评分4.1,但P3只有81%和3.4。所以小模型上Few-shot的收益更明显。

六、总结

这次Prompt Engineering实验让我最深的体会是:Prompt不是越长越好,也不是越短越省。 真正影响成本和质量的,是“输出结构是否被约束”和“示例是否覆盖边界情况”。

最终线上方案:

  • GPT-4o mini用P4,Qwen2.5-7B-Instruct用P5英文指令版;
  • max_tokens=320,temperature=0.2;
  • 输入评论先按时间排序,超过15条做截断;
  • 单条平均总Token控制在1350以内,比最初P0的1230只多10%,但格式合规率从61%升到96%。

如果你也在做类似的信息抽取或摘要任务,建议先跑P3,再根据格式合规率决定要不要加Few-shot。不要一上来就堆示例,Token烧得心疼,效果还不一定好。