在构建RAG(检索增强生成)系统时,一个常见的痛点是:检索到的文档片段与用户问题看似相关,实则答非所问 。如果将这些低质量的片段直接喂给大模型生成答案,会导致"幻觉"或错误的结论。
因此,在生成答案之前,增加一个**"文本匹配判断"(或称相关性重排序/过滤)的步骤至关重要。
本文将通过一个 金融文本匹配**的实战案例,演示如何利用 Few-Shot Prompting(少样本提示) 和
结构化输入格式,训练大模型精准判断两段文本是否在语义上匹配(即:这段文档是否能回答这个问题/是否与这段描述一致)。
🎯 案例目标
任务 :给定两个句子(Sentence A 和 Sentence B),判断它们在语义上是否匹配。
- 匹配(是):两句表达的核心事实、意图或主题一致,即使措辞不同。
- 不匹配(不是):两句谈论的是完全不同的主题,或者事实冲突。
应用场景:
- RAG 检索过滤:判断检索到的文档片段是否与用户 Query 相关。
- 去重:判断两条新闻是否在报道同一件事。
- 事实核查:判断公告内容与市场传言是否一致。
输出要求:仅输出"是"或"不是",便于程序逻辑判断。
💡 核心技术策略
1. 语义匹配 vs 关键词匹配
传统的搜索引擎基于关键词匹配(如都包含"股票"、"上涨"),但往往无法理解深层语义。
- 例子:"公司更赚钱了"vs"利润上升"。
- 传统搜索:可能因为词汇不同而漏判。
- 大模型 :能理解"更赚钱"等同于"利润上升",判定为匹配 。
本案例利用大模型的语义理解能力,解决关键词匹配的局限性。
2. 正负样本均衡的 Few-Shot
在构建示例数据 examples_data 时,我们特意准备了:
- 正样本("是"):包含同义词替换、句式重组但语义一致的案例。
- 负样本("不是") :包含虽然都是金融领域,但主题完全无关(如"黄金"vs"外汇","降息"vs"新能源")的案例。
这种均衡的示例能让模型学会区分"相关"与"无关"的边界,避免模型倾向于一直回答"是"。
3. 明确的输入分隔符
在 Prompt 中,我们使用 句子1: [...] 句子2: [...] 的格式,并用方括号 [] 包裹具体文本。
- 作用:清晰界定两个输入对象的边界,防止模型混淆哪部分是参照物,哪部分是待判断对象。特别是在文本中包含标点符号时,分隔符能有效避免解析错误。
4. 极简输出约束
System Prompt 明确要求:"回答是或不是"。
- 目的 :将复杂的推理过程内化,只输出布尔值结果。这使得后续代码可以直接通过
if response == "是"进行逻辑分支处理,无需正则提取。
📝 完整代码解析
python
import os
from openai import OpenAI
# 1. 初始化客户端
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
# 如果使用本地模型,可取消下面注释
# base_url="http://localhost:11434/v1"
)
# 2. 准备 Few-Shot 示例数据
# 字典结构:Key为标签("是"/"不是"),Value为元组列表 (句子1, 句子2)
examples_data = {
"是": [
# 正样本:同义改写,核心事实一致
("公司ABC发布了季度财报,显示盈利增长。", "财报披露,公司ABC利润上升。"),
("公司ITCAST发布了年度财报,显示盈利大幅度增长。", "财报披露,公司ITCAST更赚钱了。")
],
"不是": [
# 负样本:虽然都是金融,但主题完全不同
("黄金价格下跌,投资者抛售。", "外汇市场交易额创下新高。"),
("央行降息,刺激经济增长。", "新能源技术的创新。")
]
}
# 3. 待测试的提问数据
questions = [
# 测试1:语义匹配("大涨"/"乐观" <-> "持续上涨"/"满意")
("利率上升,影响房地产市场。", "高利率对房地产有一定的冲击。"),
# 测试2:语义不匹配("油价" vs "智能城市")
("油价大幅度下跌,能源公司面临挑战。", "未来智能城市的建设趋势越加明显。"),
# 测试3:语义匹配(情感与事实的一致性)
("股票市场今日大涨,投资者乐观。", "持续上涨的市场让投资者感到满意。")
]
# 4. 构建 Messages 列表
# System Prompt: 定义任务、输入格式及输出约束
messages = [
{"role": "system", "content": "你帮我完成文本匹配,我给你2个句子,被[]包围,你判断它们是否匹配,回答是或不是,请参考如下示例:"},
]
# 动态添加 Few-Shot 示例
# 遍历字典,将正负样本交替或连续加入上下文
for key, value in examples_data.items():
for t in value:
# 构造标准化的输入格式:句子1: [...] 句子2: [...]
user_content = f"句子1: [{t[0]}] 句子2: [{t[1]}]"
messages.append({"role": "user", "content": user_content})
messages.append({"role": "assistant", "content": key})
print("🚀 开始金融文本匹配判断测试...\n")
# 5. 循环测试
for i, q in enumerate(questions, 1):
# 构造当前请求
current_input = f"按照上述示例,回答这2个句子的情况。句子1: [{q[0]}],句子2: [{q[1]}]"
current_messages = messages + [{"role": "user", "content": current_input}]
try:
response = client.chat.completions.create(
model="qwen-plus",
messages=current_messages,
temperature=0.0 # 🔥 关键:设置为0,确保判断逻辑稳定,无随机性
)
result = response.choices[0].message.content.strip()
# 简单清洗,防止模型输出多余标点
if result.endswith("。"):
result = result[:-1]
print(f"[测试 {i}]")
print(f"句子1: {q[0]}")
print(f"句子2: {q[1]}")
print(f"✅ 匹配结果:{result}")
print("-" * 60)
except Exception as e:
print(f"[测试 {i}] 调用出错:{e}\n")

🔍 深度原理解析
1. 为什么需要 Few-Shot 而不仅仅是 Zero-Shot?
虽然大模型本身具备语义理解能力,但在特定领域(如金融)或特定任务(严格二分类)中,Zero-Shot(直接问)可能会出现以下问题:
- 标准不一:模型可能认为"有点关系"就算"是",而我们需要的是"核心事实一致"才算"是"。
- 输出格式漂移:模型可能输出"是的,它们匹配"、"匹配"、"True"等多种格式,增加代码处理难度。
- 负样本敏感度低:如果没有负样本示例,模型可能倾向于对所有金融相关的文本都回答"是"。
通过提供正负样本对,我们明确地向模型展示了"什么样的相似算匹配"以及"什么样的不同算不匹配",校准了模型的判断阈值。
2. 输入格式的标准化
代码中使用了 句子1: [...] 句子2: [...] 的模板。
- 优势:这种格式具有极强的鲁棒性。即使句子内部包含逗号、句号甚至方括号(只要成对),模型也能清晰地识别出两个独立的输入单元。这对于处理复杂的金融长文本尤为重要。
3. Temperature = 0.0 的决定性作用
文本匹配是一个逻辑判断任务,而非创作任务。
- 如果
temperature较高,模型可能会在"是"与"不是"之间摇摆,导致相同的输入在不同次运行中得到不同结果。 - 设置
temperature=0.0强制模型选择概率最高的 token,确保判断结果的确定性 和可复现性。
📊 运行结果
运行代码后,您将看到模型能够精准识别语义相似性,忽略表面词汇的差异:
text
🚀 开始金融文本匹配判断测试...
[测试 1]
句子1: 利率上升,影响房地产市场。
句子2: 高利率对房地产有一定的冲击。
✅ 匹配结果:是
------------------------------------------------------------
[测试 2]
句子1: 油价大幅度下跌,能源公司面临挑战。
句子2: 未来智能城市的建设趋势越加明显。
✅ 匹配结果:不是
------------------------------------------------------------
[测试 3]
句子1: 股票市场今日大涨,投资者乐观。
句子2: 持续上涨的市场让投资者感到满意。
✅ 匹配结果:是
------------------------------------------------------------
🚀 总结
本案例展示了如何利用大模型构建高精度的语义匹配过滤器,这是提升 RAG 系统效果的关键一步:
- 语义理解:超越关键词匹配,真正理解文本背后的含义。
- 示例引导:通过正负样本对(Few-Shot),校准模型的判断标准。
- 格式规范:使用清晰的分隔符和严格的输出约束,便于工程化集成。
- 稳定性控制 :利用
temperature=0确保逻辑判断的一致性。
在实际的 RAG 流程中,您可以将此模块置于"检索"之后、"生成"之前。只有当匹配结果为"是"时,才将该文档片段作为上下文发送给大模型生成最终答案,从而大幅减少幻觉,提升回答的准确性。