Langchain-Chatchat问答置信度评分机制设计
在企业级智能问答系统日益普及的今天,一个看似流畅的回答背后,可能隐藏着“知识幻觉”或推理偏差。尤其是在使用大型语言模型(LLM)处理私有文档时,用户常面临这样的困境:答案听起来很合理,但我能信吗?
这个问题在金融、医疗、人力资源等高敏感场景中尤为突出。Langchain-Chatchat 作为一款基于 LangChain 框架构建的开源本地知识库问答系统,支持将企业内部的 PDF、Word 等文件转化为可检索的知识源,在保障数据隐私的同时实现定制化问答。然而,其核心挑战也正源于此——当知识来源有限、问题模糊或模型“自信地胡说”时,如何让用户判断结果的可靠性?
答案是:引入问答置信度评分机制。这不是简单的“打个分”,而是一套贯穿检索、生成与决策全流程的技术体系,目标是让系统不仅能回答问题,还能“知道自己知道什么、不知道什么”。
从流程切入:置信度在哪里可以被“看见”?
要设计有效的置信度机制,首先要理解 Langchain-Chatchat 的工作流:
[用户提问] ↓ [问题向量化] → [向量数据库检索] → [Top-K 文档返回] ↓ ↘ [构造 Prompt(含上下文)] ←──────────────┘ ↓ [调用 LLM 生成回答] ↓ [输出最终响应]在这个链条中,有两个关键节点蕴含了丰富的置信信号:
- 检索阶段:我们能找到多少相关证据?
- 生成阶段:模型在输出时有多“犹豫”?
如果把整个系统比作一名员工在写报告,那么检索就像他在翻阅资料,生成则是动笔写作。一个靠谱的员工,要么引用充分(高检索得分),要么逻辑清晰且前后一致(低熵、高一致性)。反之,若资料找不到还写得模棱两可,那这份报告显然不值得信任。
向量检索:用语义相似度衡量“有没有依据”
在 Langchain-Chatchat 中,知识库中的文本块会被 Embedding 模型编码为向量,并存入 FAISS 或 Milvus 这类向量数据库。当用户提问时,问题同样被向量化,系统通过计算余弦相似度找出最相关的几个片段。
这个过程本身就提供了第一个置信维度——检索置信度。
from sentence_transformers import SentenceTransformer import numpy as np from sklearn.metrics.pairwise import cosine_similarity model = SentenceTransformer('bge-small-zh-v1.5') query_embedding = model.encode(["员工离职流程"]) doc_embeddings = model.encode([ "员工需提前30天提交辞职申请", "加班费按国家规定发放", "年度体检安排在每年6月" ]) similarities = cosine_similarity(query_embedding, doc_embeddings)[0] print("相似度得分:", similarities) # 输出: [0.87, 0.34, 0.29]这里最高分为 0.87,说明第一条文档高度相关;而其余两项几乎无关。我们可以据此设定阈值规则:
- ≥ 0.7:强匹配,有明确依据
- 0.5 ~ 0.7:弱相关,可能存在间接支持
- < 0.5:无可靠依据,回答可能是“凭空推测”
这一点至关重要。很多所谓的“AI幻觉”其实源自检索失败但模型仍强行作答。如果我们能在这一层就识别出“没找到资料”,就能有效拦截大部分错误源头。
实际部署中建议动态调整阈值。例如,在 HR 政策查询场景下,由于术语规范性强,可设较高门槛(如 0.75);而在开放性咨询中,则可适当放宽至 0.6。
此外,Top-K 的选择也需要权衡。K=3~5 是常见设置,太大容易引入噪声干扰评分,太小则可能遗漏关键信息。一种优化思路是结合 MMR(Maximal Marginal Relevance)算法,在相关性和多样性之间取得平衡。
模型生成:从概率分布看“模型是否犹豫”
即使检索到了相关内容,也不能保证最终输出就是可靠的。LLM 可能误解上下文、过度泛化,或者在多个可能性之间摇摆不定。这时候就需要深入模型内部,观察它的“思考过程”。
现代解码器模型(如 Qwen、Llama)在生成每个 token 时都会输出一个词汇表上的概率分布。如果某个 token 的概率远高于其他选项(比如 90% vs 其余分散),说明模型非常确定;但如果多个选项概率接近(如 30%, 28%, 25%),那就意味着它在“猜”。
我们可以通过计算概率熵来量化这种不确定性:
$$
H(p) = -\sum_{i} p_i \log p_i
$$
熵值越高,表示分布越平坦,模型越不确定。
from transformers import AutoTokenizer, AutoModelForCausalLM import torch import numpy as np def calculate_entropy(probs): probs = np.array(probs) return -np.sum(probs * np.log(probs + 1e-12)) def generate_with_logits(prompt): inputs = tokenizer(prompt, return_tensors="pt").to(llm_model.device) with torch.no_grad(): outputs = llm_model(**inputs, output_logits=True) logits = outputs.logits[0, -1, :] # 最后一个 token 的 logits probs = torch.softmax(logits, dim=-1).cpu().numpy() top_k_probs = sorted(probs, reverse=True)[:5] entropy = calculate_entropy(top_k_probs) print(f"Top-5 Probabilities: {top_k_probs[:3]}") print(f"Entropy: {entropy:.3f}") return entropy prompt = "公司的试用期是几个月?" entropy = generate_with_logits(prompt)实验表明,在典型问答任务中,平均 token 熵低于 1.0 通常对应较稳定的输出;超过 1.5 则提示存在较大不确定性。
更进一步,还可以启用多次采样策略(n=3~5),观察不同生成结果的一致性。例如使用不同的随机种子运行同一 prompt,再用 Sentence-BERT 计算生成文本之间的语义相似度。若多数结果语义相近(相似度 > 80%),则认为模型具有较高内部共识。
需要注意的是,这种方法会增加延迟,不适合对所有请求启用。合理的做法是仅在检索置信度较低时触发重试机制,形成“快速通道 + 审慎模式”的分级处理架构。
综合评分:构建双维度可信评估模型
单独依赖检索或生成都存在盲区。有些问题虽然检索不到直接答案,但模型可以根据常识合理推断(如“春节放假几天?”);相反,也可能出现检索到相关内容但模型误读的情况。
因此,最佳实践是融合两个维度的信息,建立加权评分模型:
$$
\text{Final Score} = w_1 \cdot S_{\text{retrieval}} + w_2 \cdot S_{\text{generation}}
$$
其中:
- $ S_{\text{retrieval}} $:归一化后的最高相似度得分
- $ S_{\text{generation}} $:基于熵或一致性的反向映射(低熵 → 高分)
- 权重分配建议 $ w_1 = 0.6, w_2 = 0.4 $
为何检索权重更高?因为在本地知识库场景下,准确性首要取决于是否有真实依据支撑。模型能力再强,也不能替代事实基础。
最终得分可映射为三级制标签:
| 分数区间 | 置信等级 | 用户提示 |
|---|---|---|
| ≥ 0.8 | ✅ 高置信 | “答案来自《XX制度》第X条” |
| 0.5–0.8 | ⚠️ 中置信 | “仅供参考,建议核实原文” |
| < 0.5 | ❌ 低置信 | “未找到相关信息,无法确认” |
更重要的是,系统应提供可解释性说明。例如,当标记为低置信时,不应只说“我不知道”,而应补充原因:“未检索到匹配内容,当前回答基于通用知识推测”。
实战案例:避免因知识滞后导致误导
设想这样一个场景:公司刚更新了差旅报销标准,但管理员尚未上传新版文件。此时员工提问:“高铁票报销上限是多少?”
旧版文档显示为“二等座全额报销”,而新政策已改为“按职级限额”。由于知识库未更新,检索相似度仅为 0.43,属于低匹配状态。尽管模型仍可能生成“二等座可全额报销”的回答(因为它记得这类信息),但由于检索置信度过低,综合评分将自动降级为“⚠️中置信”,并附注:“依据版本较早,建议联系财务部门确认最新政策”。
这正是置信度机制的价值所在——它不能阻止知识缺失,但能防止系统“装作知道”。
设计细节与工程考量
在落地过程中,还需注意以下几个关键点:
1. 动态阈值校准
初始阈值可通过人工标注测试集进行校准。例如选取 100 个典型问题,请专家判断答案是否可靠,然后回溯对应的相似度和熵值分布,寻找最优切分点。后期可通过 A/B 测试持续优化。
2. 性能开销控制
实时提取 logits 和多次采样会带来额外延迟。建议采用异步评分机制:主路径快速返回回答,后台线程完成置信分析后更新状态。对于低置信结果,可通过弹窗或日志提醒用户复核。
3. 日志闭环与反馈驱动
所有低置信问答对都应记录下来,形成“待澄清问题池”。管理员可定期审查这些条目,决定是否补充知识库或调整检索参数。久而久之,系统会越来越“知道自己擅长什么”。
4. 用户体验设计
不要让用户面对冷冰冰的分数。可以用图标、颜色甚至语音语调传递置信情绪。例如高置信回答用坚定语气朗读,低置信用迟疑语调并主动追问:“我不太确定,您能提供更多背景吗?”
结语:迈向“可信赖AI”的一小步
Langchain-Chatchat 的模块化架构为这类高级功能的扩展提供了天然土壤。通过在RetrievalQA链中注入回调钩子,开发者可以轻松捕获检索结果、模型输入输出及资源消耗等中间信号,进而构建起完整的置信评估流水线。
这套机制的意义不仅在于提升单次问答的质量,更在于建立起人机之间的信任契约:系统不再是一个黑箱,而是能表达自我认知边界的合作方。
未来,随着用户反馈、点击行为、修正记录等信号的积累,我们甚至可以训练一个专门的“置信度预测模型”,实现从规则驱动到数据驱动的跃迁。那时,智能问答系统将真正具备“知道自己不知道”的元认知能力。
而这,或许才是负责任 AI 的起点。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考