基于LLM和RAG的领克汽车智能问答系统

智能RAG问答系统

概述

本系统基于检索增强生成(Retrieval-Augmented Generation, RAG)范式构建,面向从非结构化文档(如 PDF)中高效检索信息并生成可溯源回答的应用场景。系统通过“索引—检索—生成”的流水线式技术路线,将文档解析、语义向量化、向量检索与大语言模型(LLM)生成有机整合,既保证答案的事实性与可追踪性,又兼顾在资源受限环境下的易部署与可扩展性。

技术路线

系统遵循经典 RAG 三阶段流程:

  • 索引(Indexing):对文档进行结构化解析与清洗,采用定长分块(默认 512 字符,50 字符重叠)保持局部上下文连续性;随后使用 SentenceTransformer 嵌入模型对每个文本块进行向量化,构建基于 FAISS 的高维向量索引,并进行归一化以支持余弦相似度检索。
  • 检索(Retrieval):针对用户查询生成查询向量,在向量索引上进行内积检索(归一化后等价于余弦相似度),召回相似度最高的 Top-K 文档片段,并携带相似度分数与元数据返回。
  • 生成(Generation):将检索到的文档片段作为可控上下文输入给大语言模型(默认集成讯飞星火 API),在答案生成阶段引导模型严格依据检索证据作答,降低“幻觉”风险,并在缺乏证据时显式说明。

项目逻辑架构图

项目工程结构展示

预处理过后的文档

主界面展示

1.示例问答:如何启动方向盘加热?

先看文档pdf当中答案原出处,如下所示。

问答系统回复情况如下:

增强型检索rag返回的相似度最高的几个文档如下所示:

2.示例问答:如何开启空调呢?

先查看原pdf当中的原文出处

查看问答系统回复结果

增强型检索返回的原文余弦相似度最高的文档来源:

用户问答时,后端处理用户请求示意如下图所示。

综上所述,系统先把知识库pdf文档进行数据预处理,然后利用向量模型生成向量模型 通过RAG增强型检索以后通过文本向量计算余弦相似度,然后排序知识库里面相似度较高的几位,最后LLM结合文档的内容输出结果,注意,并不是单纯的调用ai直接回复,而是结果文档内容生成最终结果。真正实现了RAG原理以及结合llm生成最终答案给用户。

训练好的结果保存到了results文件夹下。

1.LLM模型选择与实现

该RAG系统采用了讯飞星火大模型作为核心的生成模型,这是一个经过精心设计的架构选择。系统通过SparkModelProxy类实现了对大模型的封装和调用,该类支持多种配置参数包括模型版本,默认为”x1”、温度参数0.7和最大token数2000。在实现层面,系统采用了完善的错误处理机制,包括API密钥验证、请求重试逻辑和响应解析,确保了与外部大模型服务的稳定交互。
系统还预留了多模型支持的扩展性,通过配置文件和环境变量的方式管理不同模型的API参数,这种设计使得系统可以灵活切换不同的LLM提供商。在生成阶段,系统将检索到的相关文档作为上下文信息,结合用户问题构建完整的prompt,然后调用星火大模型生成最终答案。这种架构既保证了答案的专业性和准确性,又维持了系统的可维护性和扩展性。
2.向量数据库选择与实现

该系统选择了FAISS作为向量数据库的核心组件,这是一个经过验证的高性能向量相似性搜索库。FAISS提供了多种索引类型支持,系统主要使用了IndexFlatIP(内积索引)来实现精确的相似性搜索,这种索引类型特别适合处理高维向量数据。系统支持CPU和GPU两种计算模式,通过配置参数可以灵活选择计算设备,在资源受限的环境下可以选择CPU模式,而在需要高性能的场景下可以启用GPU加速。
向量数据库的实现采用了分层架构设计,底层使用FAISS进行向量存储和检索,上层通过VectorIndex类提供统一的接口封装。系统在构建向量索引时,首先使用SentenceTransformer模型将文本块转换为高维向量表示,然后将这些向量批量添加到FAISS索引中。检索阶段通过search方法实现top-k相似性搜索,返回最相关的文档块及其相似度分数。这种实现方式既保证了检索的准确性,又确保了查询的高效性,能够在毫秒级时间内完成大规模文档的相似性搜索。

3.RAG架构实现
该RAG系统实现了完整的检索增强生成架构,采用了模块化设计理念,将整个系统分解为数据加载、模型构建、训练过程和结果展示四个核心模块。在数据加载模块中,系统通过DataLoader类实现了对PDF文档和问答数据的统一处理,包括文档分块、文本清洗和向量化预处理。模型构建模块通过ModelBuilder类实现了嵌入模型和向量索引的构建,支持多种预训练模型的选择和配置。
检索模块是整个RAG架构的核心,系统通过Retriever类实现了基于向量相似性的文档检索功能。该模块接收用户查询,将其转换为向量表示,然后在向量数据库中搜索最相关的文档块,返回top-k个最相似的文档及其相似度分数。生成模块通过Generator类实现了基于检索结果的答案生成,该模块将检索到的相关文档作为上下文信息,结合用户问题构建完整的prompt,然后调用星火大模型生成最终答案。

系统架构与模块

  • 文档处理(DataLoader / 文档处理器):

    • 职责:PDF 文本抽取、清洗与分块;维护数据统计信息。
    • 关键点:句子边界优先分割、重叠窗口设计,兼顾召回与上下文完整性。
  • 向量化与索引(ModelBuilder / 向量化器):

    • 职责:加载 SentenceTransformer 模型(默认 all-MiniLM-L6-v2),批量编码文档块,持久化到 FAISS 向量索引。
    • 实现:内积索引 faiss.IndexFlatIP + 向量归一化,实现等价余弦相似度检索与高并发读性能。
  • 语义检索(Retriever):

    • 职责:对查询进行编码与归一化,执行 Top-K 相似度检索,返回片段与分数。
    • 能力:支持可配置返回数量、相似度阈值与多模型嵌入替换。
  • 答案生成(Generator / LLM Proxy):

    • 职责:将问题与检索上下文拼装为提示词,调用 LLM 生成答案;对异常与超时进行稳健处理。
    • 默认实现:讯飞星火 API(可通过环境变量与 config.py 配置替换与调参)。
  • 训练与评估(TrainingProcess / ResultVisualizer,可选):

    • 职责:针对问答样本进行嵌入对比学习训练与验证,输出指标可视化与报告。
    • 指标:检索准确率、相似度分布、回答质量(可扩展主观或客观打分)。

核心算法与实现要点

  • 文本分块策略:采用定长窗口与重叠控制,结合句号等自然边界优化切分,减少语义截断对召回的影响。
  • 语义向量化:基于 SentenceTransformer(Transformers + Pooling)生成文本块稠密向量,支持 CPU/GPU 透明切换;Batch 编码提升吞吐。
  • 向量检索:使用 FAISS 内积索引;在入库与查询阶段进行 L2 归一化,使内积等价余弦相似度,取得稳定排序效果。
  • 提示词工程:在系统消息中约束回答依据检索上下文,缺证据时应说明,降低模型幻觉与越权推理风险。
  • 稳健性:对外部 API 的网络超时、连接异常、响应格式进行严格校验与降级处理;日志记录贯穿全链路。

核心代码与实现逻辑

以下为关键路径的核心实现片段(带行号与文件路径标注,便于交叉定位):

def _split_text(self, text: str) -> List[str]:
    """将文本分割成块"""
    chunks = []
    start = 0
    while start < len(text):
        end = start + self.chunk_size
        chunk = text[start:end]
        # 尝试在句号处分割
        if end < len(text):
            last_period = chunk.rfind('。')
            if last_period > self.chunk_size // 2:
                chunk = chunk[:last_period + 1]
                end = start + last_period + 1
        chunks.append(chunk.strip())
        start = end - self.chunk_overlap
        if start >= len(text):
            break
    return chunks

实现逻辑:定长窗口 + 重叠滑动,结合句号边界,兼顾语义连续性与召回覆盖。

def build_vector_index(self, chunks: List[str]):
    embeddings = self.embedding_model.encode(chunks, show_progress_bar=True)
    self.documents = [Document(content=chunk, metadata={"id": i, "chunk_id": i}, embedding=emb)
                      for i, (chunk, emb) in enumerate(zip(chunks, embeddings))]
    self.dimension = embeddings.shape[1]
    self.index = faiss.IndexFlatIP(self.dimension)
    embeddings_normalized = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)
    self.index.add(embeddings_normalized.astype('float32'))

实现逻辑:使用内积索引并进行向量归一化,实现等价余弦相似度检索与稳定排序。

def generate_answer(self, question: str, top_k: int = 5) -> Dict[str, Any]:
    query_embedding = self.model.encode([question])
    query_embedding_normalized = query_embedding / np.linalg.norm(query_embedding, axis=1, keepdims=True)
    scores, indices = self.vector_index.search(query_embedding_normalized.astype('float32'), top_k)
    relevant_docs = []
    for score, idx in zip(scores[0], indices[0]):
        if idx < len(self.documents):
            doc = self.documents[idx]
            relevant_docs.append({
                'content': doc.content,
                'similarity_score': float(score),
                'metadata': doc.metadata
            })
    context = "\n\n".join([doc['content'] for doc in relevant_docs])
    answer = self.llm_proxy.get_response(question, context)
    return { 'question': question, 'answer': answer, 'relevant_docs': relevant_docs, 'context': context }

实现逻辑:检索-拼接上下文-经 SparkModelProxy 生成答案,输出含溯源证据与相似度的结构化结果。

class SparkModelProxy:
    def __init__(self, model="x1", temperature=0.7):
        ...  # 环境变量/配置加载
        self._validate_config()
    def get_response(self, prompt, context=""):
        payload = {"model": self.model, "messages": [...], "temperature": self.temperature, "max_tokens": self.max_tokens}
        response = requests.post(self.api_url, json=payload, headers=headers, timeout=60)
        ...  # 异常处理与内容提取

实现逻辑:对外部 LLM API 进行包装,校验配置、统一超时与错误处理,保证生成阶段稳定性。

数据流与执行流程

  1. 文档导入:上传/指定 PDF → 解析文本 → 清洗。
  2. 构建索引:分块 → 语义编码 → 归一化 → 写入 FAISS(持久化存储可选)。
  3. 在线检索:用户问题 → 查询向量 → FAISS Top-K 相似片段。
  4. 结果生成:拼装上下文 → 调用 LLM → 输出答案与溯源片段(含相似度)。

性能与可扩展性

  • 资源适配:默认轻量嵌入模型,CPU 模式可运行,适配内存受限环境。
  • 吞吐优化:批量编码、向量归一化前置、FAISS 批量增量写入;检索阶段 O(1) 量级延迟(取决于索引规模与硬件)。
  • 可扩展性:
    • 嵌入模型可插拔(如 BGE/M3E/SBERT 家族)。
    • 检索策略可扩展(重排序、融合检索、多阶段召回)。
    • 文档类型扩展(DOCX/HTML/Markdown 等)。

典型限制与改进方向

  • 领域适配:通用嵌入在特定领域(法务、医疗)可能不足,建议进行领域微调或使用专用模型。
  • 长上下文:当证据跨片段且跨度较大时,需引入跨段拼接、片段重排或多段摘要以增强可读性与完整性。
  • 重排序与融合:引入基于交叉编码器的重排序(re-ranking)或稀疏/稠密融合(如 BM25 + 向量召回)可进一步提升相关性。
  • 增量更新:针对动态文档库,建议实现向量索引的增量构建与陈旧片段回收机制。

技术栈(Tech Stack)

  • 语言与运行时:Python 3.8+
  • 向量与检索:FAISS(IP 索引,归一化实现余弦相似度)
  • 嵌入模型:Sentence-Transformers(默认 all-MiniLM-L6-v2
  • 文档解析:PyPDF2
  • Web 界面:Streamlit
  • 训练与可视化:Sentence-Transformers、Matplotlib/Seaborn
  • 日志与配置:loggingpython-dotenv
  • 外部模型:讯飞星火 API(可替换)

项目总结

  • 背景:针对企业 PDF 手册等非结构化知识,构建 RAG 问答系统,提升知识检索与问答效率。
  • 角色与贡献:
    • 主导系统架构与核心模块设计(文档处理、向量索引、检索-生成链路)。
    • 实现 FAISS 基于向量的高效检索与可溯源答案生成;封装 LLM 代理,完善超时/异常处理。
    • 搭建最小可用 Web 演示与日志监控,形成评估报告与指标可视化。
  • 难点与优化:
    • 通过重叠分块与句子边界切分,降低语义截断带来的检索召回损失。
    • 引入向量归一化与内积索引,获得稳定的余弦相似度排序;批量编码提升吞吐。
    • 对外部 API 进行健壮封装,处理网络抖动与响应格式异常,保障可用性。
  • 成果:
    • 在 CPU 环境下完成端到端方案落地,Top-K 检索与上下文受控生成稳定运行。
    • 形成技术报告与评估可视化,支持后续领域适配与检索策略升级(如重排序、融合检索)。