提示词优化实战:少样本学习Few-shot Learning
提示词优化实战:少样本学习Few-shot Learning
今天我就用这个真实案例,讲讲少样本学习(Few-shot Learning)的坑和优化技巧。
原始代码:问题出在哪?
from openai import OpenAI
client = OpenAI(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 示例数据
examples_data = {
'退货': '我想退掉昨天买的衣服',
'换货': '这个商品有质量问题,能换吗',
'咨询': '这个手机支持 5G 吗',
'投诉': '你们的服务太差了'
}
# 构建 messages
messages = [
{"role": "system", "content": "你是客服助手,将用户问题分类..."}
]
for key, value in examples_data.items():
messages.append({"role": "user", "content": value})
messages.append({"role": "assistant", "content": key})
# 提问
for q in questions:
response = client.chat.completions.create(
model="qwen3.5-plus",
messages=messages + [{"role": "user", "content": q}]
)
乍一看没问题,对吧?有系统提示、有示例、有问答对。
但实际跑起来,模型经常分错。为什么?
问题一:示例和问题的格式不一致
仔细看代码,示例是这样的:
用户:我想退掉昨天买的衣服
助手:退货
但提问的时候是这样的:
用户:按照示例,回答这段文本的分类类别:{用户问题}
模型懵了:前面每个用户消息后面都跟了助手回答,怎么最后一个没有?
更严重的是,提问时还加了个前缀:“按照示例,回答…”,示例里可没有这句话!模型没见过这种格式,自然容易跑偏。
问题二:示例太简单,缺乏上下文
看看原始示例:
'退货': '我想退掉昨天买的衣服'
'换货': '这个商品有质量问题,能换吗'
问题:
- 示例太短了,就一句话
- 没有体现不同场景的表达差异
- 用户实际说话可能更复杂,比如:“我上周在你们店买的那件蓝色衬衫,洗了一次就掉色,能不能退?”
好的示例应该覆盖多种表达方式。
问题三:系统提示太模糊
原始系统提示:
你是客服助手,将用户问题分类为退货、换货、咨询、投诉
问题:
- 没有说明每类的判断标准
- 没有说明输出格式
- 没有边界情况处理(比如用户同时想退货又想投诉)
优化方案:三步走
Step 1:统一格式
确保示例和提问的格式完全一致:
# 示例
用户:{用户问题}
助手:{类别}
# 提问
用户:{用户问题}
助手:
提问时不要加任何前缀,让模型自然续写。
Step 2:丰富示例
每个类别准备 2-3 个不同表达方式的示例:
examples = [
# 退货 - 多种表达方式
("我上周买的那件衬衫,洗了一次就掉色,能不能退?", "退货"),
("这个商品和描述不符,我要申请退货", "退货"),
("尺码不合适,想退掉重新买", "退货"),
# 换货 - 强调质量问题
("收到货发现包装破损,能换个新的吗?", "换货"),
("这个耳机一边没声音,可以换货吗", "换货"),
# 咨询 - 询问信息
("这款手机支持无线充电吗?", "咨询"),
("请问发货地是哪里?大概几天能到?", "咨询"),
("有优惠券可以用吗?", "咨询"),
# 投诉 - 表达不满
("客服态度太差了,我要投诉!", "投诉"),
("物流一个星期了还没到,怎么回事?", "投诉"),
]
特点:
- 每类 2-3 个示例,覆盖不同表达
- 包含具体细节(“洗了一次就掉色”、“一边没声音”)
- 贴近真实用户说话方式
Step 3:强化系统提示
system_prompt = """你是电商客服意图识别专家。
任务:将用户问题分类为以下 4 类之一:
- 退货:用户要求退回商品并退款
- 换货:用户要求更换商品(通常因质量问题)
- 咨询:用户询问商品信息、物流、优惠等
- 投诉:用户表达不满或要求处理问题
输出规则:
- 只输出类别名称,不要解释
- 如果同时涉及多类,按用户核心诉求分类
- 无法确定时输出"转人工"
以下是示例:"""
优化后的完整代码
from openai import OpenAI
client = OpenAI(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="sk-xxx" # 替换为你的 API Key
)
# 系统提示
system_prompt = """你是电商客服意图识别专家。
任务:将用户问题分类为以下 4 类之一:
- 退货:用户要求退回商品并退款
- 换货:用户要求更换商品(通常因质量问题)
- 咨询:用户询问商品信息、物流、优惠等
- 投诉:用户表达不满或要求处理问题
输出规则:
- 只输出类别名称,不要解释
- 如果同时涉及多类,按用户核心诉求分类
- 无法确定时输出"转人工"
以下是示例:"""
# 丰富的示例数据
examples = [
("我上周买的那件衬衫,洗了一次就掉色,能不能退?", "退货"),
("这个商品和描述不符,我要申请退货", "退货"),
("收到货发现包装破损,能换个新的吗?", "换货"),
("这个耳机一边没声音,可以换货吗", "换货"),
("这款手机支持无线充电吗?", "咨询"),
("请问发货地是哪里?大概几天能到?", "咨询"),
("客服态度太差了,我要投诉!", "投诉"),
("物流一个星期了还没到,怎么回事?", "投诉"),
]
# 构建 messages
messages = [{"role": "system", "content": system_prompt}]
for text, label in examples:
messages.append({"role": "user", "content": text})
messages.append({"role": "assistant", "content": label})
# 测试问题
test_questions = [
"我买的鞋子尺码小了,能退吗?",
"这个充电宝充一次就没电了,质量问题",
"你们店满多少包邮?",
"打了三次客服电话都没人接,太失望了",
"今天天气怎么样", # 无关内容,测试边界
]
# 逐个测试
for q in test_questions:
messages.append({"role": "user", "content": q})
response = client.chat.completions.create(
model="qwen3.5-plus",
messages=messages,
temperature=0.1, # 分类任务用小温度
max_tokens=20
)
print(f"输入:{q}")
print(f"输出:{response.choices[0].message.content}")
print("-" * 50)
# 移除最后一个用户消息,保持 messages 不变
messages.pop()
关键改进:
temperature=0.1:分类任务要稳定max_tokens=20:防止模型啰嗦messages.pop():每次提问后移除,保持示例不变- 提问时不加任何前缀
效果对比
优化前:
输入:我买的鞋子尺码小了,能退吗?
输出:换货 # 错,应该是退货
输入:今天天气怎么样
输出:咨询 # 瞎猜
优化后:
输入:我买的鞋子尺码小了,能退吗?
输出:退货 # 正确
输入:今天天气怎么样
输出:转人工 # 正确识别为无关内容
我踩过的坑(血泪教训)
坑 1:示例越多越好?
错。我一开始加了 20 个示例,结果模型反而更困惑。8-12 个高质量示例 > 30 个低质量示例。
坑 2:示例要完全覆盖所有情况?
不用。示例的作用是展示格式和典型特征,不是覆盖所有情况。边界情况交给模型自己泛化。
坑 3:temperature 设成 0 最稳定?
也不是。temperature=0 在某些模型上会有奇怪行为,0.1-0.3 是分类任务的甜点区。
坑 4:系统提示越长越好?
大错特错。系统提示超过 500 字,模型反而会忽略后面的内容。简洁、结构化才是王道。
进阶技巧:动态示例选择
如果你的场景更复杂,可以试试动态选择示例:
def select_relevant_examples(query, examples, k=4):
"""根据查询内容,选择最相关的 k 个示例"""
# 简单版:用关键词匹配
keywords = {
'退货': ['退', '退款', '不要了', '尺码不合适'],
'换货': ['换', '质量问题', '破损', '故障'],
'咨询': ['请问', '支持吗', '多少钱', '多久'],
'投诉': ['投诉', '太差', '失望', '举报'],
}
scores = []
for text, label in examples:
score = sum(1 for kw in keywords.get(label, []) if kw in query)
scores.append((score, text, label))
scores.sort(reverse=True)
return [(text, label) for _, text, label in scores[:k]]
# 使用
relevant_examples = select_relevant_examples(query, examples)
这样可以让示例更贴近当前问题,进一步提升准确率。
通用模板:直接套用
最后给个通用模板,你可以直接改改用:
from openai import OpenAI
client = OpenAI(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="sk-xxx"
)
# 1. 写清楚系统提示(任务 + 类别定义 + 输出规则)
system_prompt = """你是 [领域] 专家。
任务:将输入分类为以下类别之一:
- 类别 1:定义说明
- 类别 2:定义说明
- 类别 3:定义说明
输出规则:
- 只输出类别名称
- 无法确定时输出 [兜底选项]
以下是示例:"""
# 2. 准备 8-12 个高质量示例(每类 2-3 个)
examples = [
("示例文本 1", "类别 1"),
("示例文本 2", "类别 2"),
# ...
]
# 3. 构建 messages
messages = [{"role": "system", "content": system_prompt}]
for text, label in examples:
messages.append({"role": "user", "content": text})
messages.append({"role": "assistant", "content": label})
# 4. 提问(不要加前缀!)
messages.append({"role": "user", "content": "你的问题"})
response = client.chat.completions.create(
model="qwen3.5-plus",
messages=messages,
temperature=0.1,
max_tokens=20
)
print(response.choices[0].message.content)
写在最后
搞完这个案例,我最大的感受是:提示词优化不是玄学,是有方法论的。
核心就三点:
- 格式一致:示例和提问长一个样
- 示例精简:短小、特征明显、覆盖主要场景
- 指令清晰:告诉模型做什么、怎么做、输出什么
别指望一次就完美,多测试、多迭代。同一个模型,提示词改一改,准确率能从 60% 提升到 95%。
最后给个建议:把你的提示词和示例存到版本控制里,每次改动都记录效果。这样你才能知道什么改法有效,什么改法是瞎折腾。
有问题欢迎在评论区交流。如果觉得有用,点个赞再走呗 👍
参考链接:
- Qwen API 文档:https://help.aliyun.com/zh/dashscope/
- 少样本学习论文:https://arxiv.org/abs/2005.14165
- 提示词工程指南:https://platform.openai.com/docs/guides/prompt-engineering
更多推荐


所有评论(0)