很多人发现自己建立的AI知识库非常不准确,那么用一下几个方法,优化优化看看效果吧!
1. 混合检索策略(稀疏 + 稠密检索)
功能选型:
- 稀疏检索:选用 BM25 算法,如 Elasticsearch 内置的 BM25(成熟、易用、对词频敏感)。
- 稠密检索:选用基于预训练嵌入模型的检索,如使用 Hugging Face 的 “all-MiniLM-L6-v2” 模型,通过 Faiss 或 Pinecone 进行向量化检索。
实现方式:
- 数据预处理:对文档进行文本清洗和合理切分(如滑动窗口或递归分块),确保关键信息完整保留。
- 独立检索模块:
- 使用 Elasticsearch 实现 BM25 检索。
- 使用 Faiss(或 Pinecone 等向量数据库)对文档进行向量化,并实现稠密检索。
- 混合策略:将两种检索得到的候选结果按权重组合,例如: 综合得分 = α * BM25 得分 + (1 – α) * 嵌入相似度得分
通过调整 α 来平衡两者,确保召回结果既能捕捉到关键词匹配,也能理解语义相似性。
参考实现示例(Python + Elasticsearch + Faiss):
# BM25 检索(Elasticsearch 示例)
from elasticsearch import Elasticsearch
es = Elasticsearch("http://localhost:9200")
bm25_results = es.search(index="docs", body={"query": {"match": {"content": query}}})
# 稠密检索(Faiss 示例)
import faiss
import numpy as np
# 假设 embeddings_matrix 是所有文档的向量表示,query_vec 是查询向量
index = faiss.IndexFlatL2(embedding_dim)
index.add(embeddings_matrix)
_, dense_indices = index.search(np.array([query_vec]), k=10)
# 结合两种得分(示例伪代码)
combined_results = []
for doc in candidate_docs:
score = alpha * doc.bm25_score + (1 - alpha) * doc.dense_score
combined_results.append((doc, score))
combined_results.sort(key=lambda x: x[1], reverse=True)
2. 重排序模块(多阶段检索)
功能选型:
- 候选文档精排:采用交叉编码器(Cross-Encoder)模型,如 “cross-encoder/ms-marco-MiniLM-L-6-v2”,可以更好地捕捉 query 与候选文档之间的交互信息。
实现方式:
- 第一阶段:使用混合检索策略快速召回一批候选文档(例如 top 100)。
- 第二阶段:将 query 与每个候选文档拼接,输入交叉编码器模型,获得精确的相关性得分,然后重新排序,选择最优的 top K(例如 top 5)供生成模型使用。
参考实现示例(基于 Hugging Face Transformers):
from transformers import AutoTokenizer, AutoModelForSequenceClassification
tokenizer = AutoTokenizer.from_pretrained("cross-encoder/ms-marco-MiniLM-L-6-v2")
model = AutoModelForSequenceClassification.from_pretrained("cross-encoder/ms-marco-MiniLM-L-6-v2")
def rerank(query, candidates):
scores = []
for doc in candidates:
inputs = tokenizer.encode_plus(query, doc, return_tensors="pt", truncation=True)
outputs = model(**inputs)
score = outputs.logits.item() # 得到相关性分数
scores.append(score)
# 按得分排序
ranked_docs = [doc for _, doc in sorted(zip(scores, candidates), reverse=True)]
return ranked_docs
# 调用示例
final_results = rerank(query, candidate_docs)
3. 查询重写与上下文压缩
功能选型:
- 查询重写:利用大语言模型(例如 GPT-3.5 / GPT-4 或开源模型如 ChatGLM)将用户原始查询改写为更明确、更细化的版本,从而提高检索器的召回率。
- 上下文压缩:使用 LLM 或专门的摘要模型(如 T5、PEGASUS)对召回的文档进行压缩,只保留与查询最相关的部分,减少无关信息干扰生成过程。
实现方式:
- 查询重写模块:构建一个函数,将原始查询发送给 LLM API,返回改写后的查询文本。
- 上下文压缩模块:对每个候选文档,调用摘要模型生成“精炼版”上下文,然后再将这些压缩后的内容传给生成模块。
参考实现示例:
def rewrite_query(query):
# 调用 LLM API,例如 OpenAI 的 GPT-3.5
rewritten = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": "请将查询重写为更明确的版本。"},
{"role": "user", "content": query}]
)
return rewritten.choices[0].message["content"]
def compress_context(doc_content, query):
# 调用 LLM API 对文档内容进行压缩(摘要)
compressed = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": "请根据查询提取文档中最相关的部分。"},
{"role": "user", "content": f"查询:{query}\n文档内容:{doc_content}"}]
)
return compressed.choices[0].message["content"]
# 使用示例
enhanced_query = rewrite_query(original_query)
# 进行检索后对每个文档进行上下文压缩
compressed_docs = [compress_context(doc.content, enhanced_query) for doc in retrieved_docs]
4. 用户反馈与持续优化
功能选型:
- 在线反馈机制:集成反馈按钮或评分系统,让用户标注回答的准确性。
- 持续优化:定期使用收集的反馈数据进行模型微调(可以采用自监督或知识蒸馏方法),进一步提高嵌入模型与检索器的表现。
实现方式:
- 在系统前端为每个回答添加“反馈”按钮,记录用户评分和意见;
- 后台记录反馈日志,构建反馈数据集;
- 利用反馈数据(正反馈和负反馈样本)进行再训练或使用增量学习策略来调整检索模块(例如对负样本进行hard negative mining)或微调交叉编码器的排序能力。
参考实现思路:
# 前端(示例伪代码)
if user_clicks_feedback:
feedback_log.append({
"query": current_query,
"retrieved_doc": doc_id,
"user_rating": rating_value
})
# 后端:定期导出 feedback_log 并构建微调数据集,
# 利用 PyTorch 或 TensorFlow 进行模型再训练。
总结
通过以上功能模块的选型与实现,可以构建一个具有以下能力的优化系统:
- 混合检索 能同时利用 BM25 和嵌入模型的优势;
- 重排序模块 通过交叉编码器精细调整候选文档顺序;
- 查询重写与上下文压缩 优化检索输入和结果内容;
- 用户反馈 帮助不断迭代和优化模型效果。