从零构建金融大模型问答机器人:基于RAG与LangChain的实战指南
30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度在实际项目中将 AI 大模型从“听说过”变成“用起来”是许多开发者面临的第一道门槛。面对海量的开源模型、复杂的工具链和抽象的概念新手往往不知从何下手。一个真正适合入门的教程不应该只是罗列概念而应该提供一个清晰、可复现的路径让开发者能亲手搭建一个能跑起来的应用并理解每一步背后的逻辑。本文将围绕一个具体的项目——金融大模型问答机器人带你从零开始完成一个具备知识检索增强能力的 AI 应用。你将学习如何整合 LangChain、向量数据库、FastAPI 等核心组件并理解 RAG、模型微调等关键技术的落地方式。无论你是希望转型 AI 应用开发还是想为自己的项目增加智能问答能力这篇教程都将提供一个扎实的起点。1. 理解项目核心为什么是 RAG 与金融问答在开始写代码之前我们需要先厘清要解决什么问题以及为什么选择相应的技术方案。1.1 金融问答的挑战与 RAG 的引入金融领域的问答对准确性和时效性要求极高。一个通用的、未经专门训练的 AI 大模型如 ChatGPT在回答金融问题时可能会面临以下问题知识过时模型训练数据存在截止日期无法获取最新的市场动态、公司财报或政策法规。幻觉问题模型可能基于其训练数据中的模式“自信地”生成一个听起来合理但完全错误或虚构的答案。缺乏领域深度通用模型对特定金融术语、内部业务流程或非公开知识库的理解有限。检索增强生成RAG正是为解决这些问题而生的架构模式。其核心思想是在让大模型生成答案之前先从外部的、可信的知识库中检索出相关的信息片段并将这些信息作为“上下文”和用户问题一起提交给模型。这样模型生成的答案就有了事实依据极大地减少了幻觉并能结合最新知识。1.2 项目技术栈选型解析根据输入材料中提到的技术栈我们进行如下拆解和选型大模型LLM选择Qwen。它是一个优秀的开源中文大模型对中文理解和生成支持良好且提供了不同规模的版本如 Qwen2.5-7B适合在消费级显卡上本地部署或通过 API 调用。应用框架LangChain。它抽象了与大模型交互、文档加载、文本分割、向量化、检索等复杂流程提供了大量可复用的组件能极大提升开发效率。向量数据库虽然输入材料未明确指定但结合 LangChainChromaDB是一个轻量级、易上手的选择适合学习和原型开发。生产环境可考虑Milvus、Pinecone等。后端 APIFastAPI。它现代、快速能自动生成交互式 API 文档非常适合构建 AI 应用的后端服务。核心模式RAG。这是我们项目的基石。进阶技术LoRA/SFT微调、量化。这些用于进一步优化模型使其更贴合特定任务或降低部署资源消耗。对于入门教程我们先聚焦于 RAG 核心流程的实现。项目目标我们将构建一个系统用户可以通过 API 提问如“招商银行2023年净利润是多少”系统从我们预先准备好的金融知识文档中检索相关信息并调用 Qwen 模型生成一个准确、有据可依的回答。2. 环境准备与项目初始化一个稳定的环境是成功的第一步。我们将使用 Conda 管理 Python 环境确保依赖隔离。2.1 基础环境搭建首先确保你的机器已安装 Python3.8和 Git。然后安装 CondaMiniconda 即可。# 1. 创建并激活一个名为 fin-rag 的 Python 3.10 环境 conda create -n fin-rag python3.10 -y conda activate fin-rag # 2. 创建项目目录并进入 mkdir financial_qa_robot cd financial_qa_robot2.2 依赖安装与配置创建requirements.txt文件列出核心依赖。这里我们选择兼容性好、文档齐全的版本。# requirements.txt # 核心框架 langchain0.1.0 langchain-community0.0.10 langchain-chroma0.1.0 # ChromaDB 集成 # 向量数据库与嵌入模型 chromadb0.4.22 sentence-transformers2.2.2 # 用于生成文本向量的嵌入模型 # 大模型 transformers4.37.0 torch2.1.0 # 根据你的 CUDA 版本选择CPU 版用 torch --index-url https://download.pytorch.org/whl/cpu accelerate0.25.0 # 后端与工具 fastapi0.104.1 uvicorn[standard]0.24.0 # ASGI 服务器 pydantic2.5.0 python-dotenv1.0.0 # 管理环境变量 # 文档处理 unstructured0.10.30 # 解析 PDF、Word 等 pypdf3.17.0使用 pip 安装所有依赖pip install -r requirements.txt注意torch的安装需要匹配你的硬件。如果没有 NVIDIA GPU请使用pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu。有 GPU 请查阅 PyTorch 官网获取对应 CUDA 版本的安装命令。2.3 项目结构设计清晰的目录结构有助于管理和维护代码。financial_qa_robot/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 应用入口 │ ├── chains.py # 定义 LangChain 处理链 │ ├── vector_store.py # 向量数据库初始化与操作 │ └── models.py # Pydantic 数据模型 ├── data/ │ └── raw_documents/ # 存放原始的金融知识 PDF/TXT 文件 ├── knowledge_base/ # 存放构建好的向量数据库 ├── .env.example # 环境变量示例 ├── requirements.txt └── README.md现在在data/raw_documents/目录下放置一些你的金融知识文档例如company_report_abc.pdf某公司年报financial_regulations.txt金融法规摘要market_analysis_2024.md市场分析文章3. 构建知识库文档加载、切分与向量化RAG 的“R”检索依赖于一个高质量的向量知识库。这一步我们将原始文档处理成模型可检索的片段。3.1 实现向量数据库管理创建app/vector_store.py文件。# app/vector_store.py import os from typing import List from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_chroma import Chroma class KnowledgeBase: def __init__(self, persist_directory: str ./knowledge_base): 初始化知识库。 :param persist_directory: 向量数据库持久化目录 self.persist_directory persist_directory # 使用开源嵌入模型无需 API Key self.embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5, # 推荐的中文嵌入模型 model_kwargs{device: cpu}, # 有GPU可改为 cuda encode_kwargs{normalize_embeddings: True} ) self.vector_store None def load_and_split_documents(self, data_dir: str ./data/raw_documents) - List: 加载并分割文档。 documents [] # 加载 PDF 文件 pdf_loader DirectoryLoader(data_dir, glob**/*.pdf, loader_clsPyPDFLoader) documents.extend(pdf_loader.load()) # 加载 TXT/MD 文件 text_loader DirectoryLoader(data_dir, glob**/*.txt, loader_clsTextLoader) documents.extend(text_loader.load()) text_loader_md DirectoryLoader(data_dir, glob**/*.md, loader_clsTextLoader) documents.extend(text_loader_md.load()) 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_vector_store(self, documents: List): 创建向量存储并持久化。 self.vector_store Chroma.from_documents( documentsdocuments, embeddingself.embeddings, persist_directoryself.persist_directory ) self.vector_store.persist() print(f向量知识库已创建并保存至 {self.persist_directory}) def load_existing_vector_store(self): 加载已存在的向量存储。 if os.path.exists(self.persist_directory): self.vector_store Chroma( persist_directoryself.persist_directory, embedding_functionself.embeddings ) print(已加载现有向量知识库) return True else: print(未找到已存在的向量知识库) return False def get_retriever(self, search_kwargs: dict {k: 3}): 获取检索器。 :param search_kwargs: 检索参数如返回最相似的k个结果 if self.vector_store is None: if not self.load_existing_vector_store(): raise ValueError(向量知识库未初始化且不存在历史数据。请先运行 create_vector_store。) return self.vector_store.as_retriever(search_kwargssearch_kwargs) # 全局知识库实例 kb KnowledgeBase()关键解释文档加载使用DirectoryLoader按后缀名批量加载 PDF、TXT、MD 文件。PyPDFLoader和TextLoader是 LangChain 内置的文档解析器。文本分割RecursiveCharacterTextSplitter是常用的分割器它会尝试按你指定的分隔符列表如段落、句子递归地分割文本直到每个片段接近chunk_size。chunk_overlap能避免在句子中间切断重要信息。嵌入模型我们选用BAAI/bge-small-zh-v1.5这是一个在中文文本上表现优异的开源向量模型它将文本转换为高维向量嵌入。相似的文本其向量在空间中的距离也更近。向量数据库Chroma.from_documents方法将分割后的文档、嵌入模型和持久化目录结合自动完成向量化计算和存储。persist()方法将数据写入磁盘。3.2 构建知识库脚本在项目根目录创建一个脚本build_kb.py来执行构建过程。# build_kb.py import sys import os sys.path.append(os.path.dirname(os.path.abspath(__file__))) from app.vector_store import kb def main(): # 检查知识库是否已存在 if kb.load_existing_vector_store(): print(知识库已存在如需重建请先删除 knowledge_base 目录。) return # 加载、分割文档 print(开始加载文档...) split_docs kb.load_and_split_documents() if not split_docs: print(未在 ./data/raw_documents/ 目录下找到任何文档。请放置 PDF、TXT 或 MD 文件。) return # 创建向量存储 print(开始构建向量知识库...) kb.create_vector_store(split_docs) print(知识库构建完成) if __name__ __main__: main()运行此脚本以构建你的知识库python build_kb.py如果一切顺利你将看到类似输出开始加载文档... 共加载 3 个文档 分割为 127 个文本片段 开始构建向量知识库... 向量知识库已创建并保存至 ./knowledge_base 知识库构建完成4. 集成大模型与构建问答链知识库准备好后我们需要让大模型能够利用它来回答问题。这里我们使用 Qwen 模型和 LangChain 的RetrievalQA链。4.1 配置 Qwen 模型首先确保你有足够的硬件资源GPU 内存 8GB 为佳来运行模型。我们将使用transformers库加载 Qwen 模型。创建app/chains.py。# app/chains.py import os from typing import Any from langchain.llms import HuggingFacePipeline from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline from app.vector_store import kb def load_qwen_model(model_name: str Qwen/Qwen2.5-7B-Instruct): 加载 Qwen 模型和分词器并封装为 LangChain 的 LLM。 注意首次运行需要下载模型请确保网络通畅且磁盘空间充足。 print(f正在加载模型: {model_name}请耐心等待...) tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypeauto, # 自动选择精度 device_mapauto, # 自动分配设备CPU/GPU trust_remote_codeTrue ) # 创建文本生成管道 pipe pipeline( text-generation, modelmodel, tokenizertokenizer, max_new_tokens512, # 生成的最大长度 temperature0.1, # 较低的温度使输出更确定 do_sampleTrue, top_p0.9, repetition_penalty1.05 ) # 包装为 LangChain LLM llm HuggingFacePipeline(pipelinepipe) print(模型加载完成。) return llm def create_qa_chain(llm: Any): 创建检索问答链。 # 1. 从知识库获取检索器 retriever kb.get_retriever(search_kwargs{k: 4}) # 检索4个最相关片段 # 2. 定义提示词模板指导模型如何利用上下文 prompt_template 基于以下已知信息简洁且专业地回答用户的问题。 如果无法从已知信息中得到答案请明确告知“根据已知信息无法回答该问题”不允许在答案中添加编造成分。 已知信息 {context} 问题 {question} 请用中文回答 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 3. 构建 RetrievalQA 链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 将检索到的所有文档“塞”进上下文 retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回源文档便于追溯 ) return qa_chain # 全局链懒加载 _qa_chain None def get_qa_chain(): global _qa_chain if _qa_chain is None: llm load_qwen_model() _qa_chain create_qa_chain(llm) return _qa_chain关键解释模型加载transformers库的from_pretrained方法会从 Hugging Face 模型库下载并加载 Qwen 模型。device_map”auto”让库自动决定将模型层放在 GPU 还是 CPU 上。提示词工程PromptTemplate定义了给模型的指令。我们明确要求模型基于已知信息回答并在不知道时承认。这是减少幻觉的关键。RetrievalQA 链chain_type”stuff”是最简单直接的方式它将检索到的所有文档片段合并成一个长上下文然后交给模型。对于更长的上下文可以考虑map_reduce或refine等复杂链类型。4.2 创建 FastAPI 后端服务现在我们将问答链包装成 HTTP API。创建app/main.py。# app/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from app.chains import get_qa_chain import uvicorn app FastAPI(title金融问答机器人 API, description基于 RAG 的金融领域智能问答系统) # 定义请求/响应模型 class QuestionRequest(BaseModel): question: str class AnswerResponse(BaseModel): answer: str source_documents: list[str] # 简化显示源文档内容片段 app.post(/ask, response_modelAnswerResponse) async def ask_question(request: QuestionRequest): 接收用户问题返回基于知识库的答案。 try: qa_chain get_qa_chain() # 调用链 result qa_chain.invoke({query: request.question}) # 处理结果 answer result.get(result, 抱歉未能生成答案。) source_docs result.get(source_documents, []) # 提取源文档内容前200字符作为参考 source_texts [doc.page_content[:200] ... for doc in source_docs] return AnswerResponse(answeranswer, source_documentssource_texts) except Exception as e: raise HTTPException(status_code500, detailf处理问题时发生错误: {str(e)}) app.get(/health) async def health_check(): return {status: healthy, service: financial_qa_robot} if __name__ __main__: # 开发环境运行 uvicorn.run(app, host0.0.0.0, port8000)4.3 运行与测试启动服务在项目根目录运行。python -m app.main首次运行会下载 Qwen 模型可能需要较长时间和数十GB磁盘空间。启动成功后控制台会显示Uvicorn running on http://0.0.0.0:8000。测试 API使用curl或浏览器访问http://localhost:8000/docsFastAPI 自动生成的交互式文档。在/docs页面找到/ask接口点击 “Try it out”。输入问题例如{question: 招商银行在2023年的净利润是多少}假设你的知识库文档中有相关信息。点击 “Execute”查看返回的答案和源文档片段。你也可以使用curl命令测试curl -X POST http://localhost:8000/ask \ -H Content-Type: application/json \ -d {question: 什么是存款准备金率}5. 关键配置、参数详解与常见问题排查项目跑通后需要深入理解关键配置并知道如何排查问题。5.1 核心参数调优指南组件参数默认值/示例作用与影响调优建议文本分割器chunk_size500每个文本片段的最大字符数。太小会丢失上下文太大会降低检索精度并增加模型负担。对于金融文档500-800 是常见起点。chunk_overlap50相邻片段重叠的字符数。防止关键信息如一个数字跨两个片段被切断。通常设为chunk_size的 10%-20%。检索器search_kwargs[“k”]3返回最相似的文本片段数量。增加k能提供更多上下文但可能引入噪声。根据问题复杂度调整通常 3-5。嵌入模型model_nameBAAI/bge-small-zh-v1.5用于生成文本向量的模型。中文场景首选bge-*zh*系列。追求精度可用bge-large-zh但更耗资源。大模型max_new_tokens512生成答案的最大长度。根据答案预期长度设置。金融答案通常精炼512 足够。temperature0.1控制输出的随机性0-1。越低越确定、保守。金融问答建议较低值0.1-0.3以减少胡言乱语。top_p0.9核采样参数影响词汇选择范围。与temperature配合使用0.9 是平衡值。5.2 常见问题与排查路径在开发过程中你几乎一定会遇到以下问题。请按此清单排查。问题现象可能原因检查与解决步骤模型加载失败或极其缓慢1. 网络问题无法从 Hugging Face 下载模型。2. 磁盘空间不足。3. 内存/显存不足。1. 检查网络或使用镜像源HF_ENDPOINThttps://hf-mirror.com。2. 清理磁盘确保有 20GB 空间。3. 换用更小模型如Qwen2.5-1.5B或使用 CPU 模式性能差。API 返回错误ValueError: 向量知识库未初始化未构建知识库就直接调用问答链。1. 运行python build_kb.py构建知识库。2. 检查data/raw_documents/目录下是否有文档。答案与文档内容无关幻觉1. 检索到的文档不相关。2. 提示词Prompt指令不够强。3. 模型temperature过高。1. 检查检索结果在vector_store.py中临时增加代码打印检索到的片段。2. 强化提示词明确要求“基于已知信息”。3. 降低temperature到 0.1。答案总是“无法回答”1. 检索器k值太小没找到任何相关文档。2. 嵌入模型不适合你的文档类型。3. 文档分割得太碎丢失了关键信息。1. 增大search_kwargs[“k”]值。2. 尝试其他嵌入模型如m3e-base。3. 调整chunk_size和chunk_overlap。服务响应速度慢1. 模型推理在 CPU 上进行。2. 每次请求都重新加载模型。3. 检索的文档片段过多或过长。1. 确保torch和 CUDA 版本匹配模型加载到 GPU。2. 确保get_qa_chain使用了全局单例避免重复加载。3. 优化chunk_size和k。无法解析 PDF 文档unstructured库依赖缺失。安装 PDF 处理依赖pip install “unstructured[pdf]”或pip install pdf2image等。5.3 生产环境考量学习环境跑通后若想部署到生产环境还需要考虑以下几点模型服务化本地加载模型占用资源且启动慢。考虑使用模型服务化框架如 vLLM, TGI单独部署 Qwen 模型通过 API如 OpenAI 兼容接口调用。LangChain 可以轻松切换 LLM 的调用方式。向量数据库升级ChromaDB 适合原型。生产环境应考虑Milvus、Qdrant或Pinecone云服务它们支持分布式、持久化、高性能检索。API 安全与限流为 FastAPI 添加 API Key 认证、请求限流如slowapi、输入验证和全面的错误处理。异步处理对于长文档解析或复杂问题考虑使用 Celery 或 FastAPI 的 BackgroundTasks 进行异步处理避免阻塞 HTTP 请求。日志与监控集成结构化日志如structlog记录每个问题的检索片段、模型输入输出和耗时。添加健康检查端点如/health和性能监控。知识库更新实现知识库的增量更新机制而不是每次全量重建。ChromaDB 支持add_documents。6. 从 RAG 到进阶微调与优化方向完成基础 RAG 后你可以根据需求向更深处探索。6.1 模型微调LoRA/SFT如果发现 Qwen 基础模型在金融术语、报告格式或推理逻辑上不符合要求可以考虑微调。SFT监督微调准备高质量的问题基于知识的答案配对数据在全量或部分模型参数上继续训练。成本高效果提升可能显著。LoRA低秩适应一种高效的微调方法只训练注入到模型中的少量低秩矩阵极大减少训练参数量和显存消耗。这是目前个人开发者微调大模型最可行的方式。简易 LoRA 微调步骤概念准备训练数据格式为[{instruction: 问题, input: 上下文, output: 理想答案}]的 JSON 文件。使用微调库如peft、trl配置 LoRA 参数r,lora_alpha,target_modules。使用transformers的Trainer进行训练。保存并加载适配器权重与基础模型合并推理。6.2 检索优化混合检索结合向量检索语义相似和关键词检索如 BM25提升召回率。重排序使用一个更精细的模型如bge-reranker对初步检索到的多个结果进行重新排序将最相关的结果排在最前。元数据过滤为文档片段添加元数据如文档类型、年份、章节检索时进行过滤如“只检索2023年以后的年报”。6.3 智能体与工作流对于复杂问题可以引入LangChain Agent的概念。例如一个金融问答智能体可以判断用户问题是关于“财报”还是“法规”。根据问题类型选择不同的知识库或检索策略。可能需要调用计算工具如计算增长率或搜索工具获取实时股价。综合多步结果生成最终答案。6.4 量化与加速为了在资源有限的设备上部署可以对模型进行量化。GPTQ/AWQ4-bit 或 8-bit 量化能大幅减少模型显存占用几乎不掉精度。llama.cpp将模型转换为 GGUF 格式在 CPU 上也能获得不错的推理速度。vLLM专为生产环境高吞吐量推理设计支持 PagedAttention 和连续批处理。通过这个项目你不仅搭建了一个可运行的金融问答机器人更重要的是走通了 AI 大模型应用开发的核心链路从环境准备、数据处理、知识库构建、模型集成到服务部署。接下来你可以用自己领域的文档替换金融文档构建专属的知识问答系统。尝试调整参数观察对答案质量的影响尝试接入不同的开源模型比较它们的表现。真正的学习始于第一个能运行的项目而深化于不断的实验、调优和解决真实问题的过程中。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度