从零构建金融RAG问答机器人:基于LangChain与Qwen的实战指南
30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度最近在后台收到不少私信很多刚接触AI大模型的朋友都表示面对海量的开源模型、复杂的部署流程和眼花缭乱的技术栈感觉无从下手学习曲线陡峭。确实从零开始构建一个能跑起来、能对话、甚至能解决实际问题的AI应用涉及环境、模型、框架、工程化等多个环节任何一个环节卡住都可能让人放弃。本文正是为了解决这个问题而生。我将以“金融大模型问答机器人”这个极具代表性的项目为蓝本为你拆解一套从零到一的完整实战路径。无论你是想入门AI应用开发的在校学生还是希望将大模型能力集成到现有业务中的开发者都能从这篇教程中找到清晰的步骤、可运行的代码和避坑指南。学完后你将掌握如何搭建一个具备私有知识问答能力的智能助手并理解其背后的核心技术原理。1. 背景与核心概念为什么需要RAG问答机器人在开始敲代码之前我们首先要理解我们要解决什么问题以及为什么选择特定的技术方案。1.1 大模型的能力与局限当前的主流大语言模型LLM如 GPT、Qwen、LLaMA 等在通用知识、逻辑推理和文本生成上表现惊人。它们经过了海量互联网数据的训练堪称“万事通”。然而它们也存在明显的短板知识滞后性模型的训练数据有截止日期无法获取最新的信息例如今天的股价、刚发布的企业财报。缺乏领域深度对于金融、法律、医疗等专业领域模型缺乏深度的、非公开的私有知识例如公司内部的业务规则、产品手册、机密报告。“幻觉”问题模型可能会生成看似合理但完全错误的事实性内容。成本与隐私直接调用商用API如 OpenAI处理大量私有文档存在数据泄露风险和成本压力。1.2 RAG检索增强生成为了解决上述问题RAGRetrieval-Augmented Generation检索增强生成技术应运而生。它巧妙地将信息检索与大模型生成能力结合检索Retrieval将你的私有知识库如PDF、Word、数据库进行切片、向量化并存入向量数据库。增强Augmented当用户提问时系统先从向量数据库中检索出与问题最相关的文档片段。生成Generation将这些检索到的片段作为“参考材料”连同用户问题一起提交给大模型让模型基于这些可靠材料生成答案。简单比喻大模型就像一个聪明但记忆有限的学生RAG 则为他配备了一个强大的“外部知识库”向量数据库和一位“图书管理员”检索系统。考试回答用户问题时学生可以快速查阅图书管理员提供的精准资料从而写出更准确、更有依据的答案。1.3 项目全景图金融问答机器人我们的目标就是构建一个基于 RAG 架构的金融领域智能问答系统。它的核心工作流程如下用户提问 -- 向量化检索 -- 拼接上下文 -- 大模型生成 -- 返回答案技术栈上我们将采用当前业界最流行、最适合入门的组合LLM 底座Qwen通义千问开源模型性能优异中文支持好可本地部署。应用框架LangChain用于编排整个RAG流程加载、切分、检索、提示。向量数据库Chroma轻量级易于上手适合学习和原型开发。后端APIFastAPI快速构建高性能的Web服务接口。前端可选简单的Streamlit页面或Vue/React用于演示。接下来我们从零开始一步步实现它。2. 环境准备与版本说明一个稳定的环境是成功的第一步。为了避免后续出现各种依赖冲突强烈建议使用 Conda 或 Venv 创建独立的 Python 虚拟环境。2.1 基础环境配置本文以Ubuntu 20.04/22.04或Windows WSL2环境为例macOS 同样适用。安装 Python确保系统已安装 Python 3.8 - 3.11 版本。不建议使用 Python 3.12因为某些深度学习库的兼容性可能还不完善。python3 --version # 输出应为 Python 3.8.x 或更高创建并激活虚拟环境# 使用 venv python3 -m venv rag_env source rag_env/bin/activate # Linux/macOS # 或 rag_env\Scripts\activate # Windows # 使用 conda conda create -n rag_env python3.10 conda activate rag_env2.2 核心依赖安装我们将主要依赖langchain和chromadb。为了运行 Qwen 模型还需要安装transformers,torch等深度学习库。请注意torch的安装命令需要根据你的CUDA版本进行调整。# 升级pip pip install --upgrade pip # 安装 PyTorch (请访问 https://pytorch.org/get-started/locally/ 获取最适合你系统的命令) # 例如对于CUDA 11.8 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 或仅安装CPU版本 # pip install torch torchvision torchaudio # 安装LangChain及其社区工具包 pip install langchain langchain-community # 安装文本嵌入模型和向量数据库 pip install sentence-transformers chromadb # 安装用于加载各种文档的Loader pip install pypdf python-docx markdown # 安装FastAPI和前端依赖 pip install fastapi uvicorn pip install streamlit # 可选用于快速构建演示界面 # 安装Qwen模型所需的特定库 pip install transformers accelerate2.3 项目结构初始化创建一个清晰的项目文件夹管理起来会更方便。mkdir financial_rag_robot cd financial_rag_robot mkdir data docs core api static templates touch requirements.txt README.md main.py你的项目结构大致如下financial_rag_robot/ ├── data/ # 存放原始金融文档PDF、TXT等 ├── docs/ # 存放处理后的向量数据库 ├── core/ # 核心业务逻辑 │ ├── __init__.py │ ├── knowledge_base.py # 知识库构建与加载 │ └── qa_chain.py # 问答链构建 ├── api/ # FastAPI 后端接口 │ └── main.py ├── static/ # 静态文件 ├── templates/ # 前端模板如果用的话 ├── requirements.txt # 依赖列表 ├── README.md └── main.py # 可能的统一启动入口将之前安装的依赖导出到requirements.txtpip freeze requirements.txt3. 核心技术原理拆解在动手编码前理解以下几个核心组件的原理至关重要。3.1 文本嵌入与向量检索计算机无法直接理解文本。我们需要将文本转换为数值向量即嵌入向量。语义相似的文本其向量在空间中的距离也更近。嵌入模型我们使用sentence-transformers库中的paraphrase-multilingual-MiniLM-L12-v2模型。它是一个轻量级的多语言模型能将中文句子映射到384维的向量空间并且效果不错。向量数据库Chroma 会存储这些向量。当用户提问时问题也会被转换成向量Chroma 通过计算余弦相似度快速找出库中最相似的几个文本片段。3.2 LangChain 框架的角色LangChain 不是一个大模型而是一个编排框架。它像乐高积木的说明书将不同的组件模型、提示模板、检索器、记忆等连接成一个可执行的“链”Chain。在我们的RAG流程中LangChain 负责Document Loader加载data/目录下的PDF、TXT文件。Text Splitter将长文档切割成大小适中的片段如500字符一段并保留部分重叠以防止上下文断裂。Vectorstore封装与 Chroma 的交互实现文档的存储和检索。RetrievalQA Chain这是核心链。它内部集成了检索器从向量库找资料和LLM根据资料生成答案。3.3 Qwen 模型的本地加载与调用我们将使用Qwen-1.8B-Chat这个相对较小的对话模型它可以在消费级GPU甚至CPU上运行适合学习和测试。通过transformers库加载模型和分词器并利用pipeline功能方便地调用。关键是要理解“对话模板”Qwen 模型需要将用户提问和检索到的上下文按照特定格式组装例如|im_start|system 你是一个专业的金融助手请严格根据提供的背景资料回答问题。 |im_end| |im_start|user 背景资料[检索到的文本] 问题用户的问题是什么 |im_end| |im_start|assistant4. 完整实战案例构建金融RAG问答机器人现在让我们把理论付诸实践。请跟随以下步骤一步步完成系统搭建。4.1 第一步构建私有知识库首先在data/文件夹中放入你的金融文档例如公司年报.pdf、理财产品说明书.txt等。然后创建core/knowledge_base.py文件# core/knowledge_base.py import os from langchain_community.document_loaders import PyPDFLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma class KnowledgeBase: def __init__(self, data_path./data, persist_path./docs/chroma_db): self.data_path data_path self.persist_path persist_path # 初始化嵌入模型 self.embeddings HuggingFaceEmbeddings( model_namesentence-transformers/paraphrase-multilingual-MiniLM-L12-v2, model_kwargs{device: cpu}, # 使用GPU可改为 cuda encode_kwargs{normalize_embeddings: True} ) self.vectorstore None def load_and_split_documents(self): 加载并分割文档 documents [] for filename in os.listdir(self.data_path): file_path os.path.join(self.data_path, filename) if filename.endswith(.pdf): loader PyPDFLoader(file_path) documents.extend(loader.load()) elif filename.endswith(.txt) or filename.endswith(.md): loader TextLoader(file_path, encodingutf-8) documents.extend(loader.load()) # 可以继续添加对docx, html等格式的支持 print(f成功加载 {len(documents)} 个文档片段) # 分割文档 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个片段约500字符 chunk_overlap50, # 片段间重叠50字符保持上下文 separators[\n\n, \n, 。, , , , , 、, , ] ) split_docs text_splitter.split_documents(documents) print(f分割后得到 {len(split_docs)} 个文本块) return split_docs def create_vectorstore(self, docs): 创建并持久化向量数据库 self.vectorstore Chroma.from_documents( documentsdocs, embeddingself.embeddings, persist_directoryself.persist_path ) self.vectorstore.persist() print(f向量数据库已创建并保存至 {self.persist_path}) return self.vectorstore def load_existing_vectorstore(self): 加载已存在的向量数据库 if os.path.exists(self.persist_path): self.vectorstore Chroma( persist_directoryself.persist_path, embedding_functionself.embeddings ) print(f已从 {self.persist_path} 加载现有向量数据库) return self.vectorstore else: print(未找到已有的向量数据库请先创建。) return None if __name__ __main__: # 首次运行构建知识库 kb KnowledgeBase() docs kb.load_and_split_documents() kb.create_vectorstore(docs)运行这个脚本处理你的文档python core/knowledge_base.py4.2 第二步加载Qwen模型并创建问答链创建core/qa_chain.py文件# core/qa_chain.py from langchain.llms import HuggingFacePipeline from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline import torch class QwenQAChain: def __init__(self, vectorstore): self.vectorstore vectorstore self.llm self._load_qwen_model() self.qa_chain None def _load_qwen_model(self): 加载Qwen-1.8B-Chat模型 model_name Qwen/Qwen-1.8B-Chat print(f正在加载模型: {model_name}请耐心等待...) # 加载分词器 tokenizer AutoTokenizer.from_pretrained( model_name, trust_remote_codeTrue, padding_sideleft ) # 加载模型 model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.float16, # 半精度减少内存占用 device_mapauto, # 自动分配GPU/CPU trust_remote_codeTrue ) model.eval() # 设置为评估模式 # 创建文本生成管道 text_generation_pipeline pipeline( text-generation, modelmodel, tokenizertokenizer, max_new_tokens512, # 生成答案的最大长度 temperature0.1, # 较低的温度使输出更确定 do_sampleTrue, top_p0.9, repetition_penalty1.1, pad_token_idtokenizer.eos_token_id ) # 包装成LangChain的LLM接口 llm HuggingFacePipeline(pipelinetext_generation_pipeline) print(模型加载完成) return llm def create_chain(self): 创建检索问答链 # 定义提示模板指导模型根据上下文回答 prompt_template 你是一个专业的金融问答助手。请严格根据以下提供的背景信息来回答问题。如果背景信息中没有相关答案请直接说“根据现有资料我无法回答这个问题”不要编造信息。 背景信息 {context} 问题{question} 请根据背景信息提供专业、准确的回答 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 构建检索器从向量库中获取最相关的4个片段 retriever self.vectorstore.as_retriever(search_kwargs{k: 4}) # 创建 RetrievalQA 链 self.qa_chain RetrievalQA.from_chain_type( llmself.llm, chain_typestuff, # 将所有检索到的上下文“塞”进提示词 retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回参考来源 ) print(问答链创建成功) return self.qa_chain def ask(self, question): 提问并获取答案 if not self.qa_chain: self.create_chain() result self.qa_chain({query: question}) answer result[result] source_docs result[source_documents] return answer, source_docs4.3 第三步创建FastAPI后端服务创建api/main.py文件# api/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from core.knowledge_base import KnowledgeBase from core.qa_chain import QwenQAChain import uvicorn app FastAPI(title金融RAG问答机器人API, version1.0) # 全局变量用于缓存知识库和问答链 kb None qa_system None class QuestionRequest(BaseModel): question: str class AnswerResponse(BaseModel): answer: str sources: list[str] app.on_event(startup) async def startup_event(): 服务启动时加载知识库和模型 global kb, qa_system try: print(正在初始化知识库...) kb KnowledgeBase() vectorstore kb.load_existing_vectorstore() if not vectorstore: raise RuntimeError(向量数据库未找到请先运行知识库构建脚本。) print(正在加载问答系统...) qa_system QwenQAChain(vectorstore) qa_system.create_chain() print(系统启动完成准备接收请求。) except Exception as e: print(f启动失败: {e}) raise app.get(/) def read_root(): return {message: 金融RAG问答机器人服务已启动} app.post(/ask, response_modelAnswerResponse) async def ask_question(req: QuestionRequest): if qa_system is None: raise HTTPException(status_code503, detail问答系统未就绪) try: answer, source_docs qa_system.ask(req.question) # 提取来源文档的前缀作为参考 source_list [doc.metadata.get(source, 未知来源) for doc in source_docs] return AnswerResponse(answeranswer, sourcessource_list) except Exception as e: raise HTTPException(status_code500, detailf处理问题时出错: {str(e)}) if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8000)4.4 第四步运行与测试启动后端服务cd financial_rag_robot python api/main.py看到“系统启动完成准备接收请求”的日志后服务就在http://localhost:8000运行了。使用curl测试APIcurl -X POST http://localhost:8000/ask \ -H Content-Type: application/json \ -d {question: 请总结一下本公司去年的主要财务表现}可选创建简单的Streamlit前端 在项目根目录创建app.py# app.py import streamlit as st import requests st.title( 金融知识问答助手) st.markdown(基于RAG和Qwen大模型构建可查询您的私有金融文档。) question st.text_input(请输入您的问题, placeholder例如什么是市盈率) if st.button(提交) and question: with st.spinner(正在思考...): try: response requests.post( http://localhost:8000/ask, json{question: question}, timeout30 ) if response.status_code 200: result response.json() st.success(回答) st.write(result[answer]) if result[sources]: st.info(参考来源) for src in result[sources]: st.write(f- {src}) else: st.error(f请求失败: {response.status_code}) except Exception as e: st.error(f连接出错: {e})运行前端streamlit run app.py然后在浏览器中打开http://localhost:8501即可体验交互界面。5. 常见问题与排查思路在实践过程中你可能会遇到以下问题。这里提供一份排查清单。问题现象可能原因解决思路运行knowledge_base.py时报错提示缺少库依赖未安装完整。检查requirements.txt确保已安装pypdf,python-docx,sentence-transformers等。加载Qwen模型时内存/显存不足模型太大硬件资源不够。1. 换用更小的模型如Qwen-1.8B-Chat。2. 使用device_map“cpu”强制使用CPU速度慢。3. 启用模型量化如bitsandbytes库的8位量化。模型生成答案质量差胡言乱语1. 提示词Prompt没写好。2. 检索到的上下文不相关。3. 模型温度temperature参数过高。1. 优化提示词明确指令“严格根据上下文”。2. 检查文本分割是否合理调整chunk_size和chunk_overlap。3. 尝试降低temperature如0.1使输出更确定。API请求超时或无响应1. 模型首次推理慢。2. 后端服务崩溃。3. 向量检索耗时过长。1. 首次请求耐心等待。2. 查看后端日志api/main.py的输出。3. 确保Chroma数据库已正确创建并加载。答案未基于提供的资料仍是通用回答检索器未找到相关文档或提示词未生效。1. 检查ask函数返回的source_docs看检索到的内容是否相关。2. 在提示词中更加强调背景信息例如用“你必须依据以下信息回答”开头。中文支持不好出现乱码或分割错误1. 文本加载编码问题。2. 嵌入模型不适合中文。3. 文本分割器切分了中文字符。1. 确保TextLoader指定encoding‘utf-8’。2. 使用我们推荐的多语言MiniLM模型。3. 在RecursiveCharacterTextSplitter的separators中加入中文标点。6. 最佳实践与工程建议当你成功运行起第一个Demo后如果想将其升级为一个更健壮、可用于生产环境原型的系统请关注以下方面6.1 知识库构建优化文档预处理在加载前清洗文档中的无关字符如页眉页脚、特殊格式。对于扫描版PDF需要使用OCR工具如paddleocr,tesseract先提取文字。智能分块简单的按字符长度分割会切断句子完整性。可以尝试按语义分割如langchain的SemanticChunker或利用文档结构如按标题分割。元数据增强在分割文档时为每个片段添加丰富的元数据如source文件名、page页码、category文档类型。这有助于后续检索和答案溯源。增量更新实现知识库的增量更新功能避免每次添加新文档都全量重建。Chroma 支持向已有集合中添加文档。6.2 检索策略增强混合检索结合向量检索语义相似和关键词检索如BM25。langchain的EnsembleRetriever可以合并两者的结果提高召回率。重排序初步检索出10-20个片段后使用一个更精细的交叉编码器模型对它们进行重排序只将最相关的3-4个片段送给LLM提升答案精度并节省上下文窗口。元数据过滤允许用户在前端选择“仅在年报中搜索”或“仅搜索某章节”通过向检索器传递元数据过滤器实现。6.3 提示工程与模型优化迭代提示词根据测试结果不断优化你的系统提示词。可以加入角色设定、输出格式要求、拒绝回答的规则等。考虑流式输出对于长答案使用FastAPI的StreamingResponse或langchain的回调函数实现逐词输出提升用户体验。模型微调如果领域术语非常特殊或回答风格有固定要求可以考虑使用少量高质量数据对Qwen模型进行微调例如使用LoRA等高效微调技术让模型更“懂行”。6.4 系统部署与监控环境隔离使用Docker容器化你的应用确保环境一致性。编写Dockerfile和docker-compose.yml。配置管理将模型路径、Chroma存储路径、API端口等配置项抽离到环境变量或配置文件中如.env。日志记录为关键步骤文档加载、检索、模型调用添加详细的日志便于问题追踪。可以使用logging模块。基础监控记录每个问答请求的耗时、Token消耗、用户问题注意脱敏用于分析性能和优化成本。备选方案对于核心服务可以考虑将向量数据库升级为更成熟的Milvus或Qdrant将LLM替换为性能更好的Qwen-7B或通过API调用云端大模型需注意数据安全。从本地文档处理到智能问答生成我们完成了一个完整的RAG系统闭环。这个项目麻雀虽小五脏俱全涵盖了AI应用开发的核心流程数据处理、模型集成、服务封装和前端展示。掌握它你就拿到了进入大模型应用开发领域的钥匙。接下来你可以尝试用更复杂的金融报告测试它优化检索效果或者将其改造成一个客服机器人、知识库助手。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度