Agent & RAG 测试工程笔记 06:一次「命中但不该回答」的问题是如何被发现的
前言:
在前一篇里,已经把 RAG 的检索过程单独拆出来跑了一遍,可以确认:
知道“命中了哪段文档”,这件事已经不是黑盒。
在继续测试的过程中,无意中撞到一个明显不对劲的回答。
一、先把整条 RAG 流程再过一遍(从行为角度)
为了后面能准确定位问题,先把当前系统真实在跑的流程按顺序过一遍。
Step 1:PDF → page_texts
-
PDF 被解析为按页组织的纯文本
-
每一页是一个独立的文本单元
这一层目前没有明显问题,页数和文本内容都稳定。
Step 2:page_texts → chunks
-
每一页文本单独做切分
-
使用固定窗口大小(chunk_size)+ overlap
-
每切出一段,就生成一个 chunk
每个 chunk 都带上两个关键信息:
-
page:该 chunk 来自哪一页(不跨页) -
chunk_id = p{page}-c{index}:切分坐标
需要注意的点:
chunk_id 只表示切分顺序,不表示语义顺序或重要性。
Step 3:question → retrieval(检索)
scored_chunks = []
for chunk in all_chunks:
chunk_words = extract_keywords(chunk["text"])
# 计算关键词重合个数(这就是相关性分数)
score = len(keywords & chunk_words)
if score > 0:
scored_chunks.append((chunk, score))
# 按分数从高到低排序
scored_chunks.sort(key=lambda x: x[1], reverse=True)
# 如果没有结果,或最高分低于阈值,返回空(拒答)
if not scored_chunks or scored_chunks[0][1] < min_score:
return []
-
输入用户问题
-
对每个 chunk 计算一个 score
-
按 score 排序,取 TopK
当前的 score 表现更像是基于关键词命中的计分:
-
命中关键词越多,score 越高
-
score 只用于排序 TopK
这一点也比较关键。
Step 4:TopK → answer(回答阶段)
当前系统的回答策略可以概括为两种情况:
-
TopK 为空 → 直接拒答
-
TopK 非空 → 使用 Top chunk 的文本作为答案依据
问题正是从这里开始出现的。
二、问题触发过程
在交互模式下,继续测试一些边界问题。
其中一个问题是:
项目用了什么向量数据库?
系统给出的完整输出是:
[RETRIEVAL]
p1-c2 score=4
p1-c0 score=1
p1-c1 score=1
[答案]
in、向量数据库、embedding等外部依赖。不做工程抽象
第一反应并不是“系统错了”,而是:
-
检索命中了 p1-c2(可以理解)
-
但这个回答明显不像是在回答“用了什么”
三、为什么这个回答“看起来就不对”
这里不需要复杂分析,靠直觉就能发现问题:
-
问题问的是:用了什么向量数据库
-
答案里:
-
没有任何具体名称
-
只是把文档中的一句话原样贴了出来
-
更准确地说,这个回答做的是:
证明文档里“提到过向量数据库”
而不是
回答“项目使用了什么向量数据库”
这一步,是“意识到不对劲”的时刻。
四、重复测试后,问题轮廓变清晰了
继续用不同问法去试同一类问题:
-
项目是否依赖向量数据库?
-
是否使用了 embedding 相关组件?
可以看到一个非常稳定的行为模式:
情况一:检索为空 → 拒答(表现很好)
例如:
-
embedding 模型?
-
是否具备通用性?
-
是否上线?
-
未来规划?
这类问题全部被干净地拒答。
情况二:检索非空 → 倾向“贴一句当答案”(危险)
例如:
-
向量数据库
-
是否依赖向量数据库
只要 chunk 中出现了关键词,系统就会:
-
命中 chunk
-
把那段文本直接当成答案
到这里,已经可以确认这不是“偶发错误”,而是一类稳定可复现的行为。
五、回顾:问题不在检索,而在“把命中当成了答案”
把整条链路梳理后,问题位置:
-
检索层:
-
做的是“相关性判断”
-
命中 p1-c2 是合理的
-
-
chunk 内容本身:
-
确实包含“向量数据库”这个词
-
但语义是:不使用
-
-
回答层:
-
把“文档里提到过 X”
-
当成了“文档回答了关于 X 的问题”
-
这是一个典型的场景:
false answer with citation
—— 看起来有来源,但答案本身并不成立。
六、这一轮测试暴露出的系统边界
不引入任何解决方案,仅从行为上,可以明确几条边界:
-
命中 chunk ≠ 证据足以回答问题
-
引用了来源 ≠ 回答一定可信
-
score 只决定“选哪些 chunk”,不决定“能不能答”
也就是说:
检索解决的是“找哪里”,不是“能不能回答”。
小结
第一次意识到:
RAG 在“命中证据但证据不足”时,会开始装懂。
这个问题并不是设计出来的,而是在反复测试中自然暴露的。
下一篇梳理一下RAG 拒答与兜底策略!
更多推荐

所有评论(0)