工程企业做内部知识库,最典型的场景是法规、标准、定额、制度的检索问答。这类文档结构特殊、对“出处”要求极高,通用 RAG 直接套用往往效果不好。本文整理几个在工程条款类知识库上比较有效的召回优化实践。
TL;DR
- 按条切片,保留结构路径与元数据,不拆散条款;
- 混合检索,关键词权重不低于 0.5,精确命中编号;
- 重排 + 上下文回填 + 版本过滤,提升召回质量;
- 回答必带出处,无依据时明确拒答,不硬编造;
- 评估分开看:检索质量与答案质量各自独立衡量。
一、先解决切片:工程文档不能按固定长度切
工程文档(规范、标准、法规)有明显的层级结构:章、节、条、款,而且强条、术语、表格往往不能被拆开。
实践要点:
- 按"条"为最小切片单位,保留条号与原文,不把一个完整条款切成两半;
- 每个切片附带完整的结构路径,如"某施工质量验收规范 > 第 6 章 > 6.2 > 6.2.3";
- 表格、公式作为独立切片,保留表头,避免只检索到孤立单元格;
- 切片同时保留"原文"与"元数据"(规范编号、版本号、发布/实施日期、是否强条)。
固定长度切分会把条款和它的上下文割裂,导致召回时语义不完整。一个典型的切片结构:
{"doc_id":"gb-xxxx-2014","path":"第6章 > 6.2 > 6.2.3","clause_no":"6.2.3","text":"条款原文……","is_mandatory":false,"version":"2014","effective_date":"2015-01-01"}二、检索:向量与关键词混合,工程条款更吃关键词
纯向量检索在工程场景有两个问题:一是条款里大量专业术语、强条编号、数字(如 “30 万方” “C30”),向量容易模糊;二是用户常直接按编号或精确表述查询。
因此采用混合检索:
- 一路用 Embedding 做语义召回,覆盖“意思相近但表述不同”的问法;
- 一路用关键词(BM25/倒排)匹配条款号、术语、规范编号、数字;
- 两路结果按归一化分数加权融合,再进入重排。
经验上,工程条款检索里关键词通道的权重不应设得过低,很多“按编号查”“查强条”的问题,命中高度依赖精确匹配。
下面给出一个混合检索的 Python 示例,演示向量检索与 BM25 关键词检索如何并行召回、再按归一化分数加权融合:
importnumpyasnpfromrank_bm25importBM25Okapidefnormalize(scores:list[float])->list[float]:"""Min-Max 归一化,把分数压到 [0, 1],便于两路加权融合。"""arr=np.array(scores,dtype=float)ifarr.max()==arr.min():returnnp.zeros_like(arr).tolist()return((arr-arr.min())/(arr.max()-arr.min())).tolist()defhybrid_search(query:str,chunks:list[str],embed_fn,top_k:int=5,w_vec:float=0.4,w_bm25:float=0.6)->list[tuple[int,float]]:""" 混合检索:向量召回 + BM25 关键词召回,按权重加权融合。 :param query: 用户问题,如 "C30 混凝土强度等级要求" :param chunks: 切片列表(每个元素是条款原文) :param embed_fn: 返回 query 与各切片向量的函数,输出 shape 为 (n_chunks,) :param top_k: 最终返回的候选条数 :param w_vec: 向量通道权重 :param w_bm25: 关键词通道权重(工程条款建议不低于 0.5) """# 1) 向量通道:语义召回vec_scores=embed_fn(query,chunks)# 余弦相似度等,越大越相关vec_norm=normalize(vec_scores)# 2) 关键词通道:BM25 精确匹配条款号、术语、规范编号tokenized=[c.split()forcinchunks]bm25=BM25Okapi(tokenized)bm25_scores=bm25.get_scores(query.split())bm25_norm=normalize(bm25_scores)# 3) 加权融合,取 Top-Kfused=[w_vec*v+w_bm25*kforv,kinzip(vec_norm,bm25_norm)]ranked=sorted(enumerate(fused),key=lambdax:x[1],reverse=True)[:top_k]returnranked# 运行结果说明:# 对 "按 6.2.3 条查混凝土强度" 这类问题,BM25 通道能精确命中条款号,# 融合后该切片分数显著高于仅靠语义相似度的结果;# 对 "强度不够怎么办" 这类口语化问法,向量通道负责兜住语义相近的条款。# 实际工程中建议 w_bm25 取 0.5~0.7,避免精确编号被语义噪声稀释。运行结果说明:对“按 6.2.3 条查混凝土强度”这类问题,BM25 通道能精确命中条款号,融合后该切片分数显著高于仅靠语义相似度的结果;对“强度不够怎么办”这类口语化问法,向量通道负责兜住语义相近的条款。实际工程中建议w_bm25取 0.5~0.7,避免精确编号被语义噪声稀释。
下面是混合检索的整体流程:
三、召回优化:重排、过滤与上下文回填
初筛拿到候选切片后,需要进一步处理:
- 重排(rerank):用交叉编码器对问题和候选切片做相关性重排,比单纯向量相似度更准,能把"看起来相似但实际不是一回事"的条款压下去;
- 上下文回填:检索到某个条款时,把它的上一条、下一条以及所属小节的定义一并补入,避免条款里的代词、引用(“应符合本规范第 X 条”)悬空;
- 版本与时效过滤:按"现行有效"过滤,过期或作废的版本默认不参与召回,或明确标注"已废止";
- 强条与普通条款区分:涉及强制性条文的问题,优先返回强条并显著标注。
整体召回优化链路如下:
四、出处标注与无依据兜底
工程领域最忌讳“AI 凭空说”,因此生成环节有两条硬约束:
- 回答必带出处:每一条结论都要能回溯到具体规范编号、条款号和版本,最好在回答中直接给出;
- 无依据不硬答:检索分数低于阈值、或没有可靠来源时,不编造结论,而是明确提示“未检索到可靠依据,请人工核实”。
可以在提示词中约束模型只依据给定上下文作答,并用引用标记(如脚注编号)把结论与切片绑定,便于追溯。
五、评估:召回与答案要分开看
工程知识库的效果不能只看“答得顺不顺”,建议分开评估:
| 评估项 | 关注指标 | 说明 |
|---|---|---|
| 检索质量 | Recall@K、MRR | 正确条款是否在候选里、排第几 |
| 重排质量 | NDCG、命中前 3 比例 | 目标条款是否被提到前面 |
| 答案质量 | 引用准确率、出处完整率 | 结论是否忠实、出处是否对得上 |
| 兜底能力 | 无依据拒答率 | 无来源时是否如实拒答 |
| 时效准确性 | 现行版本命中率 | 是否误用过期条款 |
评估集要覆盖不同问法:按编号查、按术语查、按场景描述查,以及查不到的问题,最后一类专门用来检验兜底是否生效。
工程企业的知识库建设不是一次性工程,文档版本更新、召回参数、重排策略都需要随业务迭代持续调优。
最后说两句
本文为技术科普,不构成任何商业建议。文中的参数与权重仅为通用经验,实际取值需要结合具体文档规模和评估集做实验确定。