472_问答系统设计¶
一句话说明¶
问答系统(QA System)让机器自动回答用户问题,从抽取式(在文章中找答案片段)到生成式(LLM直接生成回答)形态多样。
核心知识点¶
- 开放域QA vs 阅读理解QA:
- 阅读理解:给定文章找答案(SQuAD数据集)
- 开放域:从大规模文档库检索+阅读(Retriever-Reader架构)
- RAG(检索增强生成):当前最主流方案,先检索相关文档再交给LLM生成答案
- 抽取式QA:预测答案在原文中的起始和结束位置(span prediction)
- 知识库QA(KBQA):从结构化知识图谱(如Wikidata)查询答案
经典方法对比¶
| 方法 | 核心思路 | 优点 | 缺点 |
|---|---|---|---|
| 抽取式 BERT-QA | 预测span起止位置 | 忠实度高 | 答案只能来自原文 |
| 生成式(T5/GPT) | 直接生成答案文本 | 灵活,可推理 | 可能幻觉 |
| RAG | 检索 + 生成 | 知识可更新 | 检索质量影响大 |
| KBQA | 解析问题为SPARQL查询 | 精确可解释 | KB覆盖有限 |
代码示例¶
# ---- 方案1:抽取式QA(BERT在原文中定位答案)----
from transformers import pipeline
# 加载QA流水线
qa_pipeline = pipeline(
"question-answering",
model="deepset/roberta-base-squad2"
)
context = """
BERT (Bidirectional Encoder Representations from Transformers) was introduced
by Google in 2018. It uses a bidirectional Transformer encoder and is pre-trained
on masked language modeling and next sentence prediction tasks.
"""
question = "When was BERT introduced?"
result = qa_pipeline(question=question, context=context)
print(f"答案: {result['answer']}") # 2018
print(f"置信度: {result['score']:.4f}") # 对应位置的概率
# ---- 方案2:RAG系统(检索+生成)----
# pip install langchain chromadb sentence-transformers
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.schema import Document
# 2a. 构建向量知识库
embedding_model = HuggingFaceEmbeddings(
model_name='sentence-transformers/all-MiniLM-L6-v2' # 轻量embedding模型
)
# 模拟文档库(实际从PDF/数据库加载)
docs = [
Document(page_content="BERT于2018年由Google发布,基于双向Transformer。"),
Document(page_content="GPT系列由OpenAI开发,使用自回归语言模型。"),
Document(page_content="T5把所有NLP任务统一成文本到文本的格式。"),
]
# 构建向量数据库(FAISS或Chroma)
vectorstore = Chroma.from_documents(
docs,
embedding=embedding_model,
persist_directory="./chroma_db" # 持久化到磁盘
)
# 2b. 检索最相关文档
retriever = vectorstore.as_retriever(
search_kwargs={"k": 2} # 返回最相似的2个文档
)
query = "BERT是什么时候发布的?"
retrieved_docs = retriever.get_relevant_documents(query)
for doc in retrieved_docs:
print("检索到:", doc.page_content)
# 2c. 用LLM生成最终答案(需配置API)
from langchain.llms import OpenAI
from langchain.chains import RetrievalQA
llm = OpenAI(temperature=0) # temperature=0 减少随机性
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 把所有检索文档塞进prompt
retriever=retriever
)
answer = qa_chain.run(query)
print("RAG答案:", answer)
# ---- 方案3:BERT-QA的span预测原理演示 ----
from transformers import BertForQuestionAnswering, BertTokenizer
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForQuestionAnswering.from_pretrained('bert-large-uncased-whole-word-masking-finetuned-squad')
q = "What is BERT?"
c = "BERT is a language model developed by Google in 2018."
# 问题和上下文一起编码,用[SEP]分隔
enc = tokenizer(q, c, return_tensors='pt')
with torch.no_grad():
outputs = model(**enc)
# start_logits 和 end_logits 对每个token位置打分
start_idx = outputs.start_logits.argmax() # 答案起始token位置
end_idx = outputs.end_logits.argmax() # 答案终止token位置
tokens = tokenizer.convert_ids_to_tokens(enc['input_ids'][0])
answer_tokens = tokens[start_idx: end_idx + 1]
print("答案tokens:", tokenizer.convert_tokens_to_string(answer_tokens))
面试常问点¶
- RAG相比纯LLM的优势?
知识可更新(不需要重新训练)、来源可追溯、减少幻觉
如何评估QA系统质量?
- 抽取式:Exact Match(EM)和 F1
生成式:ROUGE、BERTScore、人工评估
检索质量差导致RAG效果差怎么办?
- HyDE(假设文档嵌入):先让LLM生成假设答案再检索
重排序(Reranking):cross-encoder对候选文档二次排序
KBQA和阅读理解QA的适用场景?
- KBQA:精确事实性问题("哪个城市是法国首都")
- 阅读理解:开放性文档理解、需要推理
速查表¶
| 需求 | 推荐方案 |
|---|---|
| 小规模QA验证 | BERT-QA pipeline |
| 企业知识库问答 | RAG(LangChain + FAISS/Chroma) |
| 精确事实查询 | SPARQL + 知识图谱 |
| 医学文献问答 | PubMedBERT-QA |
| 评估工具 | SQuAD评估脚本、RAGAS |