
之前的几篇文章我们已经探讨了Function Calling和流式输出这些技术细节,构建了一个能查数据库、并行调用工具并总结结果的Agent。但当我真正把这些成果展示给老板时,老板还是皱起了眉头。你知道为什么吗?因为大模型生成的分析报告虽然内容对,但格式却一团糟——有时候像是一段散文,有时候又是无聊的数字,老板看得直发愁。
我试着质问大模型:“我不是让你‘给出详细分析’吗?怎么会乱写?”结果大模型明显感到冤屈。对它来说,“详细分析”这几个字实在太抽象了,它头脑里有成百上千种方式来解释,只是不知道我想要的是哪一种。
这就引出了今天的主题:提示词工程中非常实用的一招——Few-shot少样本提示。简单来说,就是在给指令的同时,提供一些样例,让它知道我期望的结果大致是什么样的。
一、 为何大模型有时像个轴子,怎么教都教不会
1.1 回顾我们之前的模糊指令
想想之前我们给大模型的指令,像是:“请仔细分析这段数据,找出其中是否存在异常波动的点。如果有,请告诉我异常发生的时间点,以及当时的数值。最后简单分析一下可能的原因。”
听上去很清晰吧?但实际上,大模型对这些话的理解往往会和我们预期有偏差。
你可能以为“简单分析一下原因”是要它列个条目,每个条目写一两句话,但大模型可能理解为写一段长篇大论,把各种可能混在一起。这就是我们常说的认知差异。大模型是基于训练数据生成的,它接触过各种文本,却不知道你们团队里对“分析报告”的真正定义是什么。
1.2 它没见过你这套业务的真实套路
更棘手的是,不同的业务在处理时序分析时的套路完全不一样。
比如在运维中,分析CPU异常的步骤可能是“看GC情况 -> 检查流量是否满载 -> 看是否发生死锁”;而在金融业务中,分析股票异常的逻辑则是“关注宏观政策 -> 看资金流向 -> 评估技术面背离”。
如果你只给一句“分析原因”,大模型可能会用金融的套路去分析CPU异常,那结果可想而知,肯定会出错。
它并不是不聪明,只是对你这边的规矩一无所知。所以,解决办法就是把这些规矩具体地展示给它。
二、 Few-shot到底是什么,为什么这么有效
2.1 通俗来说,就是照猫画虎
Few-shot可以理解为少样本提示,乍听起来挺学术,其实就是个简单易懂的道理。
想象我们带新员工,如果你只是说:“去,写个周报。”新人肯定会写得五花八门。但如果你给他看一份优秀的周报,并说:“照着这个写。”那他写出来的东西基本上就能符合你的期待了。
同样,大模型在提示词中不仅要有指令,还需要提供一两个示例,包括输入的数据和输出的分析。这让大模型一看,立刻就明白了你想要的格式和推理逻辑。
2.2 Zero-shot、One-shot、Few-shot的区别
这里有几个行业术语:
Zero-shot:不给例子,只给指令。
One-shot:给一个例子。
Few-shot:给两到三个例子。
一般来说,One-shot和Few-shot的效果会更好。Zero-shot往往容易出错。而且给太多例子也不太行,因为这样不仅费Token,还可能让模型反而抓不住重点。
因此,在时序分析中,通常给出一到两个典型样例,就已经足够帮助大模型理解了。
三、 如何构造一个好用的样例
构建样例是一门技术,随便找段数据当样例可不行,这样只会误导模型。
3.1 样例的输入要一致
样例输入必须与实际数据格式完全一致。
假设我们的数据格式是:“时间, 指标名, 数值”,那么你的样例输入也必须是这种格式。选择一段典型的历史数据,像这样:
2023-09-15 10:00:00, CPU, 25%
2023-09-15 10:01:00, CPU, 26%
2023-09-15 10:02:00, CPU, 88%
2023-09-15 10:03:00, CPU, 91%
2023-09-15 10:04:00, CPU, 27%
这个输入简短,但却包含了典型的异常模式。
3.2 输出格式要符合预期
这是最重要的部分。你希望得到什么样的报告,就得手动写一份完美的报告作为样例。
如果你想要结构化的列表,就这样写:
【异常检测报告】
1. 异常时间点:2023-09-15 10:02:00 与 10:03:00
2. 异常指标及数值:CPU使用率分别飙升至88%和91%
3. 关联分析:该时段内存使用率未见明显上升,网络流量正常,初步排除GC和流量冲击。
4. 原因推测:极大可能为某个离线计算任务突发启动占用大量CPU,建议排查定时任务调度日志。
看这份手写的报告,标题清晰,逻辑分明。大模型以后看到新数据,就会努力模仿这个结构去写,结果就会变得条理清晰。
3.3 不要给太长的样例
切记,样例不要写得太长。
有些朋友可能会写一千字的报告作为例子,这样不仅浪费Token,还容易让模型抓不住重点,反而模仿一些无关的细节。
样例要简洁有力,数据和报告都保持在五到六行就足够了,确保格式和推理清晰,立刻打住。
四、 将Few-shot应用到我们的代码中
接下来,我们要把上面的样例逻辑实现到代码里。
4.1 改造Prompt拼接函数
在OpenAI兼容的API中,Few-shot并不是直接放在同一条用户消息里。最佳的做法是将其伪装成历史对话。
也就是说,首先将一条虚拟的用户消息(样例输入)放入 messages 列表中,然后加上一条虚拟的助手消息(样例输出),最后再添加用户的真实消息。
这样大模型看到前面的对话历史,以为之前已经成功合作过了,它就会顺应这个惯性继续执行下去。
我们可以写个函数来拼接这些内容:
def build_few_shot_prompt(real_data_text):
# --- 构造样例输入 ---
example_input = """
2023-09-15 10:00:00, CPU, 25%
2023-09-15 10:01:00, CPU, 26%
2023-09-15 10:02:00, CPU, 88%
2023-09-15 10:03:00, CPU, 91%
2023-09-15 10:04:00, CPU, 27%
"""
# --- 构造样例输出(你手写的完美报告) ---
example_output = """
【异常检测报告】
1. 异常时间点:2023-09-15 10:02:00 与 10:03:00
2. 异常指标及数值:CPU使用率分别飙升至88%和91%
3. 关联分析:该时段内存使用率未见明显上升,网络流量正常,初步排除GC和流量冲击。
4. 原因推测:极大可能为某个离线计算任务突发启动占用大量CPU,建议排查定时任务调度日志。
接下来,我们将这些拼装成 messages 列表:
messages = [
{
"role": "user",
"content": f"请分析以下时序数据:\n{example_input}"
},
{
"role": "assistant",
"content": example_output
},
{
"role": "user",
"content": f"请按照刚才的格式,分析以下新的时序数据:\n{real_data_text}"
}
]
return messages
看这个 messages 列表。它包含三条信息,前两条是我们的样例,第三条是我们想得到的结果。
在真实的提问中,我特意加了一句“请按照刚才的格式”,就像是一个温馨提示,让大模型的注意力回到样例上,避免它跑偏。
4.2 完整代码演示与解读
接下来稍微调整主流程,使用新拼装的函数。
import requests
# 假设 api_key 和 real_data 都已经准备好了
def ask_with_few_shot(messages_list, api_key):
url = "https://ai.timecho.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
payload = {
"model": "timecho-model",
"messages": messages_list # 直接把拼好的messages塞进去
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
result = response.json()
return result['choices'][0]['message']['content']
if __name__ == "__main__":
# 假设这是我们刚从数据库查出来的真实数据
my_real_data = """
2023-10-25 10:00:00, CPU, 22%
2023-10-25 10:01:00, CPU, 24%
2023-10-25 10:02:00, CPU, 89%
2023-10-25 10:03:00, CPU, 92%
2023-10-25 10:04:00, CPU, 21%
"""
# 1. 拼装带Few-shot的Messages
my_messages = build_few_shot_prompt(my_real_data)
# 2. 发请求
print("正在请求大模型(带Few-shot示范)...")
final_answer = ask_with_few_shot(my_messages, my_key)
print("\n=== 大模型的分析报告 ===")
print(final_answer)
运行这段代码,你就能看到大模型的表现不再随意,它像是刚被你手把手教过的实习生,输出的内容整齐划一,完全符合预期。
五、 试试效果,格式是不是瞬间规整了
5.1 没给样例时的混乱输出
为了比较,你可以把前面那段 messages 列表中的样例删掉,只留真实的提问,再跑一次。
你会发现,大模型可能给的回复是这样的:
“经过分析,我发现数据在10:02和10:03出现了异常,数值达到了89%和92%。这种情况通常是突发任务导致的,建议去查日志。”
这话虽然没错,但条理性差,老板看得很累。如果他要把这段话放到周报里,还得自己重新整理。
5.2 加上样例后的整齐输出
加上Few-shot后,大模型的输出一般会是这样的:
“【异常检测报告】
异常时间点:2023-10-25 10:02:00 与 10:03:00
异常指标及数值:CPU使用率分别飙升至89%和92%
关联分析:该时段内未见其他指标的异常,无法做交叉对比。
原因推测:短暂的突刺一般是后台某个重计算任务触发,建议排查应用日志。”
你看,标题清晰,序号分明,逻辑链条与样例一模一样。这样一来,老板只需复制粘贴到周报里,轻松搞定。
通过写Few-shot,这省下来的沟通成本和时间可真不少。
六、 Few-shot的进阶坑:样例选得不好反而带沟里去
6.1 样例里的逻辑错误
Few-shot虽然强大,但也是把双刃剑。如果你给的样例存在错误,大模型也会把这些错误学过去。
比如你的样例推理中写了“CPU高是因为内存泄漏”,但实际上那段样例数据里根本没有内存数据。这就是明显的逻辑错误。
大模型可不懂这是个问题,它会认为“哦,原来你要这么推理。”等它拿到真实数据时,就算数据里内存正常,它也可能硬说“可能是内存泄漏”。

