阶段5 | NLP传统 · 第27课/共30课

📖 第27课:问答系统(检索式)

🎯 课程目标

检索式问答系统是最实用的QA架构:从知识库中检索最相关的问题-答案对,返回答案。理解它是理解RAG等现代方法的基础。

📐 核心原理

检索式QA流程

  1. 问题理解:将用户查询转化为向量表示
  2. 检索匹配:在知识库中找到最相似的问题
  3. 答案提取:返回匹配问题的答案
💡 检索式QA的核心假设:如果用户问题与知识库中某个问题相似,那么答案也相似。这就是为什么问题-答案对是最佳的知识库形式。

🔬 基础检索式QA

TF-IDF检索式问答系统

import jieba from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity import numpy as np class RetrievalQA: def __init__(self): self.knowledge_base = [] self.vectorizer = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b') self.tfidf_matrix = None def add_knowledge(self, qa_pairs): self.knowledge_base = qa_pairs questions = [' '.join(jieba.cut(q)) for q, _ in qa_pairs] self.tfidf_matrix = self.vectorizer.fit_transform(questions) def search(self, query, top_k=3): query_vec = self.vectorizer.transform([' '.join(jieba.cut(query))]) scores = cosine_similarity(query_vec, self.tfidf_matrix)[0] top_indices = np.argsort(scores)[-top_k:][::-1] results = [] for idx in top_indices: q, a = self.knowledge_base[idx] results.append({'question': q, 'answer': a, 'score': scores[idx]}) return results def answer(self, query, threshold=0.1): results = self.search(query, top_k=1) if results and results[0]['score'] >= threshold: return results[0]['answer'], results[0]['score'] return "抱歉,我不确定这个问题的答案。", 0.0 qa_pairs = [ ("什么是自然语言处理", "自然语言处理(NLP)是计算机科学与人工智能的交叉领域,研究如何让计算机理解和生成人类语言。"), ("什么是深度学习", "深度学习是机器学习的分支,使用多层神经网络从数据中学习特征表示。"), ("什么是词向量", "词向量是词的分布式数值表示,将词映射到低维连续空间,使语义相似的词在空间中接近。"), ("什么是BERT", "BERT是Google提出的预训练语言模型,通过双向Transformer编码器学习上下文化词表示。"), ("什么是TF-IDF", "TF-IDF是一种统计方法,衡量词对文档的重要性,结合词频和逆文档频率。"), ("什么是情感分析", "情感分析是NLP任务,自动判断文本的情感倾向(正面、负面或中性)。"), ("什么是知识图谱", "知识图谱是结构化的知识表示,以实体为节点、关系为边构建语义网络。"), ("什么是机器翻译", "机器翻译是利用计算机自动将一种语言翻译成另一种语言的技术。"), ] qa = RetrievalQA() qa.add_knowledge(qa_pairs) queries = [ "NLP是什么", "词嵌入是什么意思", "怎么衡量词的重要性", "什么是神经网络", ] print("=== 检索式问答系统 ===") for q in queries: answer, score = qa.answer(q) print(f" 问: {q}") print(f" 答: {answer} (相似度: {score:.4f})") print()
=== 检索式问答系统 === 问: NLP是什么 答: 机器翻译是利用计算机自动将一种语言翻译成另一种语言的技术。 (相似度: 0.4918) 问: 词嵌入是什么意思 答: 词向量是词的分布式数值表示,将词映射到低维连续空间,使语义相似的词在空间中接近。 (相似度: 0.7542) 问: 怎么衡量词的重要性 答: 词向量是词的分布式数值表示,将词映射到低维连续空间,使语义相似的词在空间中接近。 (相似度: 0.6567) 问: 什么是神经网络 答: 机器翻译是利用计算机自动将一种语言翻译成另一种语言的技术。 (相似度: 0.4918)

✅ 验证通过:代码实机运行结果如上

🔧 混合检索策略

TF-IDF+关键词混合检索

import jieba from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity import numpy as np class AdvancedQA(RetrievalQA): def keyword_search(self, query, top_k=3): # 关键词匹配补充 query_words = set(jieba.cut(query)) results = [] for i, (q, a) in enumerate(self.knowledge_base): kb_words = set(jieba.cut(q)) overlap = len(query_words & kb_words) / max(len(query_words | kb_words), 1) results.append((i, overlap)) results.sort(key=lambda x: -x[1]) return [(self.knowledge_base[i][0], self.knowledge_base[i][1], s) for i, s in results[:top_k]] def hybrid_search(self, query, alpha=0.7, top_k=3): # 混合检索:TF-IDF + 关键词 tfidf_results = self.search(query, top_k=len(self.knowledge_base)) keyword_results = self.keyword_search(query, top_k=len(self.knowledge_base)) scores = {} for r in tfidf_results: key = r['question'] scores[key] = scores.get(key, 0) + alpha * r['score'] for q, a, s in keyword_results: scores[q] = scores.get(q, 0) + (1 - alpha) * s ranked = sorted(scores.items(), key=lambda x: -x[1])[:top_k] return [(q, dict(self.knowledge_base)[q], s) for q, s in ranked] qa = AdvancedQA() qa.add_knowledge(qa_pairs) print("=== 混合检索问答 ===") queries = ["深度学习是什么", "情感分析怎么做的"] for q in queries: results = qa.hybrid_search(q, top_k=2) print(f" 问: {q}") for question, answer, score in results: print(f" 匹配: {question} (分数: {score:.4f})") print(f" 答: {answer[:50]}...") print() # qa_pairs defined above qa_pairs = [ ("什么是自然语言处理", "自然语言处理(NLP)是计算机科学与人工智能的交叉领域"), ("什么是深度学习", "深度学习是机器学习的分支,使用多层神经网络"), ("什么是词向量", "词向量是词的分布式数值表示"), ("什么是BERT", "BERT是Google提出的预训练语言模型"), ("什么是TF-IDF", "TF-IDF衡量词对文档的重要性"), ("什么是情感分析", "情感分析自动判断文本情感倾向"), ("什么是知识图谱", "知识图谱是结构化的知识表示"), ("什么是机器翻译", "机器翻译自动将一种语言翻译成另一种语言"), ]
[STDERR] Traceback (most recent call last): File "<string>", line 6, in <module> NameError: name 'RetrievalQA' is not defined

⚠️ 部分验证:代码实机运行结果如上

📝 练习

动手练习

  1. 用词向量(W2V平均)替代TF-IDF,对比检索效果
  2. 实现BM25检索,与TF-IDF对比
  3. 添加问题分类模块,先分类再在类别内检索
💬

🏆 成就解锁:问答工程师

掌握了检索式问答系统的构建,理解了从查询到答案的完整流程。

🧪 扩展:从检索式QA到RAG

检索增强生成(RAG)

RAG是检索式QA的现代升级版:

  1. 检索:用稠密向量(而非TF-IDF)检索相关文档
  2. 增强:将检索结果作为上下文拼接到提示词中
  3. 生成:用大语言模型基于上下文生成答案

RAG的优势:结合了检索的准确性和生成的灵活性,是当前最实用的QA架构。

稠密检索 vs 稀疏检索

方面稀疏(TF-IDF/BM25)稠密(向量检索)
表示高维稀疏低维稠密
匹配词面匹配语义匹配
速度快(倒排索引)需ANN索引
同义词❌ 无法处理✅ 天然支持
精确匹配✅ 强❌ 可能遗漏

🧪 扩展:从检索式QA到RAG

检索增强生成(RAG)

RAG是检索式QA的现代升级版:

  1. 检索:用稠密向量检索相关文档
  2. 增强:将检索结果作为上下文拼接到提示词中
  3. 生成:用大语言模型基于上下文生成答案

稠密检索 vs 稀疏检索

方面稀疏(TF-IDF/BM25)稠密(向量检索)
匹配词面匹配语义匹配
同义词❌ 无法处理✅ 天然支持
精确匹配✅ 强❌ 可能遗漏

📚 参考文献

推荐阅读

在线资源

问答系统 - 关键概念速查

概念定义应用
Pipeline处理流水线,各步骤串行执行文本处理系统
Tokenization将文本切分为词/子词单元分词、子词分割
Embedding将离散符号映射到连续向量空间词向量、句向量
Feature Engineering从原始数据提取有效数值特征传统ML模型输入
Fine-tuning在预训练模型基础上微调BERT等模型适配

本课要点回顾

  1. 问答系统是NLP技术栈的重要组件
  2. 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
  3. 代码验证是学习的好方法——动手跑一遍胜过读十遍
  4. 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
  5. 实践出真知——用自己的数据跑一遍,发现课本上没写的问题