
最近在后台收到不少私信很多刚接触AI大模型的同学都表示面对海量的概念、框架和代码感觉无从下手不知道如何从零开始构建一个真正能跑起来的应用。网上的资料要么过于学术化要么就是零散的代码片段很难串联成一个完整的项目闭环。今天这篇文章就为你彻底解决这个痛点。我将以一个金融大模型问答机器人项目为蓝本手把手带你走完从环境搭建、模型选择、知识库构建、后端API开发到前端集成的全流程。无论你是刚入门的新手还是有一定基础想系统学习大模型应用落地的开发者这篇教程都能让你获得一套可直接复用的“工程化”解决方案而不仅仅是理论。我们将使用目前业界主流的开源技术栈Qwen通义千问作为基座大模型LangChain作为应用框架FastAPI构建后端服务并结合RAG检索增强生成技术来让模型“读懂”你的私有知识。文中会涵盖模型本地部署、向量数据库使用、Prompt工程、API封装等核心环节并提供完整的、可运行的代码示例。准备好了吗让我们开始这场从0到1的AI应用开发之旅。1. 大模型应用开发核心概念与项目全景在直接写代码之前我们必须先理清几个关键概念和整个项目的架构设计。这能帮助你理解每一步“为什么这么做”而不是机械地复制命令。1.1 什么是RAG为什么它至关重要RAG即检索增强生成Retrieval-Augmented Generation是目前解决大模型“幻觉”和知识滞后问题最有效的工程范式之一。核心思想当用户提问时系统不是让大模型凭空生成答案而是先从你的私有知识库如公司文档、产品手册、金融报告中检索出最相关的信息片段然后将这些片段和用户问题一起“喂”给大模型让它基于这些可靠的上下文来生成答案。解决的问题知识更新大模型的训练数据有截止日期。通过RAG你可以随时更新知识库让模型获取最新信息。减少幻觉模型回答严格限制在提供的上下文内大幅降低了胡编乱造的概率。保护隐私你的私有数据无需上传给模型厂商进行微调只需本地向量化存储保证了数据安全。溯源可查每个答案都能追溯到是依据知识库中哪份文档的哪段内容生成的增强了可信度。在我们的金融问答机器人项目中RAG是让模型能够准确回答公司内部财报分析、特定金融产品条款等问题的技术基石。1.2 项目架构与技术栈选型一个完整的大模型应用通常分为以下几个层次我们的项目也将依此展开用户界面 (Web/App) | v API网关 (FastAPI) | v 应用逻辑层 (LangChain) | |-----------------------| | | v v 大模型 (Qwen) 向量知识库 (Chroma) | ^ | | |-----------------------| v Prompt工程 后处理大模型层 (LLM)我们选择Qwen2.5。它是国内优秀的开源大模型性能强劲对中文支持友好并且提供了方便的本地部署方案。相比于直接调用OpenAI等闭源API本地部署在数据安全、成本控制和网络延迟方面更有优势。应用框架层LangChain。它相当于大模型应用的“脚手架”将调用模型、管理提示词、连接工具如检索器、处理输入输出等流程标准化、模块化让我们能像搭积木一样快速构建应用。向量知识库ChromaDB。一个轻量级、易用的开源向量数据库。它的作用是将我们的文本知识金融文档通过嵌入模型转化为向量一串数字并存储起来。当用户提问时将问题也转化为向量并在库中快速找到最相似的文本片段即检索。后端服务层FastAPI。一个现代、快速高性能的Python Web框架用于构建我们的问答API接口。它自动生成交互式API文档非常适合前后端分离的开发模式。核心流程用户提问 - FastAPI接收 - LangChain调用检索器从ChromaDB找相关文档 - LangChain组装Prompt问题上下文 - 调用Qwen模型生成答案 - FastAPI返回答案。明确了“做什么”和“用什么做”接下来我们就进入实战环节从最基础的环境搭建开始。2. 环境准备打造专属的开发工作站工欲善其事必先利其器。这一节我们将配置一个纯净、可复现的Python开发环境并安装所有必要的依赖。2.1 基础环境与Python版本操作系统推荐使用Ubuntu 22.04 LTS或Windows WSL2。本文示例将在Ubuntu环境下进行命令在WSL2中同样适用。macOS用户也可参考主要区别在于包管理工具。Python版本请确保安装Python 3.10或3.11。这是目前多数AI框架兼容性最好的版本。避免使用Python 3.12等过新版本可能遇到依赖冲突。# 检查Python版本 python3 --version # 如果版本不对可以使用conda或pyenv管理多版本包管理工具强烈推荐使用Conda或venv创建独立的虚拟环境避免污染系统Python环境。# 使用conda创建环境如果已安装Anaconda/Miniconda conda create -n finance_ai python3.10 conda activate finance_ai # 或者使用venv python3 -m venv finance_ai_env source finance_ai_env/bin/activate # Linux/macOS # finance_ai_env\Scripts\activate # Windows2.2 核心依赖安装激活虚拟环境后我们安装项目所需的核心Python库。建议将以下内容保存为requirements.txt文件然后批量安装。# requirements.txt # 应用框架与HTTP服务 langchain0.1.0 langchain-community0.0.10 # 社区集成工具 fastapi0.104.1 uvicorn[standard]0.24.0 # ASGI服务器用于运行FastAPI pydantic2.5.0 # 向量数据库与文本处理 chromadb0.4.22 sentence-transformers2.2.2 # 用于生成文本向量的嵌入模型 pypdf3.17.4 # 用于读取PDF文档 python-docx1.1.0 # 用于读取Word文档 unstructured0.10.30 # 强大的文档解析库 # 大模型相关 transformers4.36.0 # Hugging Face库用于加载Qwen模型 torch2.1.0 # PyTorch深度学习框架 accelerate0.25.0 # 简化模型加载 safetensors0.4.1 # 工具类 python-multipart0.0.6 # FastAPI处理文件上传 httpx0.25.1 loguru0.7.2 # 好用的日志库使用pip进行安装pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple注意安装PyTorch时请根据你的CUDA版本如果有GPU去 PyTorch官网 获取正确的安装命令。上述torch2.1.0是CPU版本。如果有NVIDIA GPU安装GPU版本会极大加速推理。2.3 项目目录结构清晰的目录结构是项目可维护性的第一步。在开始编码前先创建如下目录和文件finance_qa_robot/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI应用主入口 │ ├── chains.py # LangChain链的定义 │ ├── models.py # Pydantic数据模型 │ └── utils.py # 工具函数如文档加载、文本分割 ├── data/ │ ├── raw_documents/ # 存放原始的金融PDF、Word文档 │ └── chroma_db/ # Chroma向量数据库持久化目录 ├── knowledge_base/ │ └── build_kb.py # 构建知识库的脚本 ├── static/ # 存放前端静态文件可选 ├── templates/ # 存放HTML模板可选 ├── requirements.txt ├── .env.example # 环境变量示例 └── README.md现在你的开发环境已经就绪。接下来我们将进入核心环节让大模型在本地“跑起来”。3. 本地部署与调用Qwen大模型虽然可以直接调用云端API但为了数据安全和学习完整性我们选择在本地部署Qwen模型。即使你的电脑没有顶级GPU我们也有应对方案。3.1 下载与加载Qwen模型我们将从Hugging Face模型库下载Qwen2.5-7B-Instruct这个版本。它是一个70亿参数的指令微调模型在保证一定能力的同时对硬件要求相对友好。方案一使用 transformers 直接加载适合有 8GB GPU显存# 文件app/models.py from transformers import AutoModelForCausalLM, AutoTokenizer import torch def load_qwen_model(model_nameQwen/Qwen2.5-7B-Instruct): 加载Qwen模型和分词器。 警告这将消耗大量GPU显存约14GB。若无足够显存请参考方案二。 print(f正在加载模型: {model_name}...) tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.float16, # 使用半精度减少显存占用 device_mapauto, # 自动分配模型层到GPU/CPU trust_remote_codeTrue ) # 将模型设置为评估模式 model.eval() print(模型加载完毕) return model, tokenizer if __name__ __main__: # 测试加载 model, tokenizer load_qwen_model() # 简单的推理测试 prompt 请用一句话介绍人工智能。 inputs tokenizer(prompt, return_tensorspt).to(model.device) with torch.no_grad(): outputs model.generate(**inputs, max_new_tokens50) answer tokenizer.decode(outputs[0], skip_special_tokensTrue) print(f模型回答{answer})方案二使用 Ollama 运行推荐给大多数开发者尤其GPU资源有限Ollama是一个强大的本地大模型运行框架它简化了模型的下载、加载和运行并且支持量化将模型压缩牺牲少量精度换取大幅降低资源消耗。安装Ollama# Linux/macOS curl -fsSL https://ollama.com/install.sh | sh # Windows: 直接从官网下载安装包拉取并运行量化后的Qwen模型# 拉取Qwen2.5 7B的4位量化版本对硬件要求极低约4-5GB内存 ollama pull qwen2.5:7b # 运行模型服务默认监听11434端口 ollama serve 在Python中通过API调用# 文件app/llm_client.py import requests import json class OllamaClient: def __init__(self, base_urlhttp://localhost:11434): self.base_url base_url self.model qwen2.5:7b # 与pull的模型名一致 def generate(self, prompt, streamFalse): 调用Ollama API生成文本 url f{self.base_url}/api/generate payload { model: self.model, prompt: prompt, stream: stream, options: { temperature: 0.1, # 较低的温度使输出更确定 num_predict: 512 # 最大生成token数 } } response requests.post(url, jsonpayload) response.raise_for_status() result response.json() return result.get(response, ).strip() if __name__ __main__: client OllamaClient() answer client.generate(请用一句话介绍人工智能。) print(f模型回答{answer})方案选择建议如果你是初学者或硬件资源有限强烈推荐使用Ollama方案二。它几乎零配置并且量化模型运行效率很高。后续教程我们将基于Ollama进行。3.2 构建第一个LangChain对话链现在我们将Ollama管理的Qwen模型集成到LangChain中创建一个最简单的对话链。# 文件app/chains.py from langchain_community.llms import Ollama from langchain.prompts import PromptTemplate from langchain.chains import LLMChain def create_basic_qa_chain(): 创建一个基础的问答链。 使用Ollama集成模型名为 qwen2.5:7b。 # 1. 初始化LLM llm Ollama(modelqwen2.5:7b, base_urlhttp://localhost:11434) # 2. 定义提示词模板 # {question} 是一个占位符会被用户的实际问题替换 prompt_template PromptTemplate( input_variables[question], template你是一个专业的AI助手。请回答以下问题\n\n问题{question}\n\n回答 ) # 3. 创建链 qa_chain LLMChain(llmllm, promptprompt_template) return qa_chain if __name__ __main__: chain create_basic_qa_chain() question 美联储加息对股市有什么影响 answer chain.run(questionquestion) print(f问题{question}) print(f回答{answer})运行这个脚本你将看到Qwen模型基于其通用知识生成的答案。但这还不够“专业”因为它没有用到我们的金融知识库。接下来我们就来构建这个专属知识库。4. 构建金融领域专属知识库RAG核心这是让我们的机器人变得“专业”的关键一步。我们将把金融文档PDF、Word等转换成向量存储到ChromaDB中。4.1 文档加载与文本分割首先准备一些金融相关的文档如公司年报、产品说明书、行业分析PDF放入data/raw_documents/目录。# 文件knowledge_base/build_kb.py import os from langchain_community.document_loaders import ( PyPDFLoader, Docx2txtLoader, TextLoader, UnstructuredFileLoader ) from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.schema import Document def load_documents(data_dirdata/raw_documents): 加载指定目录下的所有文档 documents [] for filename in os.listdir(data_dir): file_path os.path.join(data_dir, filename) if filename.endswith(.pdf): loader PyPDFLoader(file_path) elif filename.endswith(.docx): loader Docx2txtLoader(file_path) elif filename.endswith(.txt): loader TextLoader(file_path, encodingutf-8) else: # 使用Unstructured处理其他格式 loader UnstructuredFileLoader(file_path) try: loaded_docs loader.load() # 为每个文档片段添加源文件信息 for doc in loaded_docs: doc.metadata[source] filename documents.extend(loaded_docs) print(f成功加载: {filename}, 得到 {len(loaded_docs)} 个文本块) except Exception as e: print(f加载文件 {filename} 时出错: {e}) return documents def split_documents(documents, chunk_size500, chunk_overlap50): 将长文档分割成较小的文本块。 chunk_size: 每个块的最大字符数 chunk_overlap: 块之间的重叠字符数避免上下文断裂 text_splitter RecursiveCharacterTextSplitter( chunk_sizechunk_size, chunk_overlapchunk_overlap, length_functionlen, separators[\n\n, \n, 。, , , , , 、, , ] ) split_docs text_splitter.split_documents(documents) print(f文档分割完成。原始文档数{len(documents)}分割后块数{len(split_docs)}) return split_docs if __name__ __main__: # 测试加载与分割 raw_docs load_documents() if raw_docs: split_docs split_documents(raw_docs) # 查看第一个块的内容和元数据 print(\n--- 示例文本块 ---) print(f内容预览{split_docs[0].page_content[:200]}...) print(f元数据{split_docs[0].metadata})4.2 文本向量化与存储我们需要一个“嵌入模型”将文本块转换成向量。这里使用sentence-transformers库中的多语言模型。# 续上文件knowledge_base/build_kb.py from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma import shutil def create_vectorstore(split_docs, persist_directorydata/chroma_db): 创建向量存储知识库。 1. 初始化嵌入模型。 2. 将文本块转换为向量并存入ChromaDB。 3. 持久化到磁盘。 # 如果目录已存在先删除仅用于演示生产环境应增量更新 if os.path.exists(persist_directory): shutil.rmtree(persist_directory) # 1. 初始化嵌入模型 # 使用一个轻量级且对中文友好的模型 model_name sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 embeddings HuggingFaceEmbeddings( model_namemodel_name, model_kwargs{device: cpu}, # 如果没有GPU使用cpu encode_kwargs{normalize_embeddings: True} # 归一化向量有利于相似度计算 ) # 2. 从文档创建向量存储并持久化 print(正在生成向量并创建知识库...) vectordb Chroma.from_documents( documentssplit_docs, embeddingembeddings, persist_directorypersist_directory ) # 显式持久化 vectordb.persist() print(f知识库构建完成已保存至{persist_directory}) return vectordb def build_knowledge_base(): 构建知识库的主函数 print( 开始构建金融知识库 ) # 步骤1: 加载文档 documents load_documents() if not documents: print(未找到任何文档请将文档放入 data/raw_documents/ 目录。) return None # 步骤2: 分割文档 split_docs split_documents(documents) # 步骤3: 创建向量存储 vectordb create_vectorstore(split_docs) print( 知识库构建完成 ) return vectordb if __name__ __main__: # 运行此脚本构建知识库 build_knowledge_base()运行python knowledge_base/build_kb.py等待片刻你的金融知识向量库就建好了data/chroma_db目录下会保存所有数据。5. 实现RAG问答链让模型“读懂”你的知识知识库建好后我们需要改造之前的简单问答链使其具备“检索-增强”的能力。5.1 检索器与提示词工程# 文件app/chains.py (新增函数) from langchain.chains import RetrievalQA from langchain_community.vectorstores import Chroma from langchain_community.embeddings import HuggingFaceEmbeddings from langchain.prompts import PromptTemplate from langchain_community.llms import Ollama def create_rag_qa_chain(persist_directorydata/chroma_db): 创建基于RAG的问答链。 1. 加载已有的向量数据库。 2. 将其转换为检索器。 3. 设计一个结合上下文和问题的提示词模板。 4. 构建RetrievalQA链。 # 1. 加载嵌入模型必须与构建时使用的模型一致 embeddings HuggingFaceEmbeddings( model_namesentence-transformers/paraphrase-multilingual-MiniLM-L12-v2, model_kwargs{device: cpu}, encode_kwargs{normalize_embeddings: True} ) # 2. 加载已持久化的向量数据库 vectordb Chroma( persist_directorypersist_directory, embedding_functionembeddings ) # 将向量数据库转换为检索器设置返回最相关的k个文档片段 retriever vectordb.as_retriever(search_kwargs{k: 3}) # 3. 初始化LLM (Ollama) llm Ollama(modelqwen2.5:7b, base_urlhttp://localhost:11434) # 4. 设计RAG提示词模板 # 这是Prompt工程的关键{context}和{question}是LangChain会自动填充的变量。 prompt_template 你是一个专业的金融分析师助手。请严格根据以下提供的上下文信息来回答问题。 如果上下文中的信息不足以回答问题请直接说“根据已知信息无法回答此问题”不要编造信息。 上下文信息 {context} 问题{question} 请基于上下文信息给出专业、准确、简洁的回答 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 5. 创建RetrievalQA链 # chain_typestuff 表示将所有检索到的上下文“堆叠”在一起传给模型。 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回源文档便于溯源 ) return qa_chain def ask_question(qa_chain, question): 使用RAG链提问并打印结果 result qa_chain({query: question}) answer result[result] source_docs result[source_documents] print(f\n问题{question}) print(f-*50) print(f回答{answer}) print(f-*50) print(参考来源) for i, doc in enumerate(source_docs): print(f[{i1}] 来源文件{doc.metadata.get(source, 未知)}) print(f 内容片段{doc.page_content[:150]}...) # 预览前150字符 print() if __name__ __main__: # 测试RAG链 print(正在加载RAG问答链...) rag_chain create_rag_qa_chain() print(链加载成功) # 测试几个问题 test_questions [ 我们公司2023年的主营业务收入是多少, # 假设知识库中有年报 什么是市盈率, # 通用金融概念知识库中可能有 明天股市会涨吗, # 知识库中不可能有答案 ] for q in test_questions: ask_question(rag_chain, q)运行这个测试你会看到模型现在能基于你提供的文档上下文进行回答并且对于知识库中没有的信息它会诚实地说“无法回答”。这就是RAG的价值6. 构建FastAPI后端服务现在我们需要将上面的功能封装成Web API以便前端或其他系统调用。6.1 定义API数据模型与路由# 文件app/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional import logging from app.chains import create_rag_qa_chain # 配置日志 logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) # 初始化FastAPI应用 app FastAPI( title金融大模型问答机器人API, description基于Qwen大模型与RAG技术的金融领域智能问答系统, version1.0.0 ) # 全局变量用于缓存QA链避免每次请求都重新加载 qa_chain None # Pydantic数据模型用于定义请求和响应的数据结构 class QuestionRequest(BaseModel): question: str chat_history: Optional[List[str]] None # 可选用于支持多轮对话 class AnswerResponse(BaseModel): success: bool answer: str source_documents: Optional[List[dict]] None # 溯源信息 error_message: Optional[str] None app.on_event(startup) async def startup_event(): 应用启动时加载RAG链 global qa_chain logger.info(正在启动金融问答机器人服务...) try: qa_chain create_rag_qa_chain() logger.info(RAG问答链加载成功) except Exception as e: logger.error(f启动时加载RAG链失败: {e}) # 在生产环境中这里应该进行更优雅的失败处理 app.get(/) async def root(): 根路径健康检查 return {message: 金融大模型问答机器人服务运行中, status: healthy} app.post(/api/ask, response_modelAnswerResponse) async def ask_question(request: QuestionRequest): 核心问答接口。 接收用户问题返回基于知识库的答案。 if qa_chain is None: raise HTTPException(status_code503, detail服务未就绪问答链加载失败) logger.info(f收到问题: {request.question}) try: # 调用RAG链 result qa_chain({query: request.question}) answer result[result] source_docs result.get(source_documents, []) # 格式化溯源信息 sources [] for doc in source_docs: sources.append({ content_preview: doc.page_content[:200], # 只返回预览 source_file: doc.metadata.get(source, 未知), page: doc.metadata.get(page, N/A) }) return AnswerResponse( successTrue, answeranswer, source_documentssources if sources else None ) except Exception as e: logger.error(f处理问题时出错: {e}, exc_infoTrue) return AnswerResponse( successFalse, answer, error_messagef服务器内部错误: {str(e)} ) # 可选添加一个重新加载知识库的接口用于知识库更新 app.post(/api/knowledge_base/reload) async def reload_knowledge_base(): 重新加载知识库例如在后台更新文档后调用 global qa_chain try: # 注意这里需要重新初始化链因为向量数据库内容变了 # 更优的方案是使用链的热更新这里为简化直接重建 qa_chain create_rag_qa_chain() logger.info(知识库重新加载成功) return {message: 知识库重新加载成功} except Exception as e: logger.error(f重新加载知识库失败: {e}) raise HTTPException(status_code500, detailf重新加载失败: {str(e)})6.2 运行API服务在项目根目录下创建一个启动脚本run_api.py# 文件run_api.py import uvicorn if __name__ __main__: # 启动FastAPI应用 # host0.0.0.0 允许外部访问debugTrue 仅用于开发 uvicorn.run( app.main:app, host0.0.0.0, port8000, reloadTrue, # 代码修改后自动重启生产环境应设为False log_levelinfo )然后在终端运行python run_api.py看到Uvicorn running on http://0.0.0.0:8000的输出后服务就启动了。打开浏览器访问http://localhost:8000/docs你会看到自动生成的交互式API文档Swagger UI可以直接在那里测试/api/ask接口。7. 常见问题与排查思路FAQ在实际开发和部署中你几乎一定会遇到下面这些问题。这里整理了完整的排查清单。问题现象可能原因排查步骤与解决方案Ollama服务启动失败或模型拉取慢1. 网络问题无法连接Ollama服务器。2. 端口冲突。3. 磁盘空间不足。1. 检查网络尝试curl -v http://localhost:11434。2. 确认11434端口未被占用lsof -i:11434。3. 使用国内镜像加速OLLAMA_HOST0.0.0.0 ollama serve并设置环境变量OLLAMA_MODELS指向镜像站如有。4. 手动下载模型文件并加载。运行build_kb.py时内存/显存不足嵌入模型或文档太大导致资源耗尽。1. 使用CPU运行嵌入模型确保model_kwargs{device: cpu}。2. 减小chunk_size如从500降到300。3. 分批处理文档每次加载少量文件。调用/api/ask接口返回“服务未就绪”startup_event中加载RAG链失败qa_chain为None。1. 查看服务启动日志确认create_rag_qa_chain()是否报错。2. 检查data/chroma_db目录是否存在且包含数据。3. 检查嵌入模型名称是否与构建时一致。模型回答速度非常慢1. 模型在CPU上运行。2. 检索的文档块k值太多。3. 提示词过长。1. 优先使用GPU运行Ollama和嵌入模型。2. 减小检索器search_kwargs{k: 2}。3. 精简提示词模板移除不必要的指令。答案质量不高答非所问1. 检索到的上下文不相关。2. 提示词模板设计不佳。3. 文本分割不合理破坏了语义。1. 检查知识库内容确保文档质量。尝试不同的嵌入模型如BAAI/bge-large-zh-v1.5。2. 优化提示词明确指令“严格基于上下文”。3. 调整chunk_size和chunk_overlap尝试按段落或句子分割。无法读取某种格式的文档LangChain的Loader不支持该格式或缺少依赖。1. 使用万能的UnstructuredFileLoader。2. 安装额外依赖pip install unstructured[pdf,docx]。3. 将文档转换为PDF或TXT格式再处理。8. 项目优化与进阶实践一个可用的Demo完成了但要用于生产环境还需要考虑更多工程化问题。8.1 前端界面集成简单示例你可以使用任何前端框架Vue, React调用我们的API。这里提供一个极简的HTML示例放在static/index.html!DOCTYPE html html head title金融问答机器人/title meta charsetutf-8 style body { font-family: sans-serif; max-width: 800px; margin: 40px auto; } #chatBox { border: 1px solid #ccc; height: 400px; overflow-y: scroll; padding: 10px; margin-bottom: 20px; } .user { text-align: right; color: blue; } .bot { text-align: left; color: green; } .source { font-size: 0.8em; color: #666; border-left: 3px solid #eee; padding-left: 10px; margin-top: 5px; } input { width: 70%; padding: 10px; } button { padding: 10px 20px; } /style /head body h2 金融知识问答助手/h2 div idchatBox/div div input typetext idquestionInput placeholder请输入关于金融的问题... onkeypresshandleKeyPress(event) button onclickaskQuestion()发送/button /div script const API_URL http://localhost:8000/api/ask; function appendMessage(sender, text, sourcesnull) { const chatBox document.getElementById(chatBox); const msgDiv document.createElement(div); msgDiv.className sender; msgDiv.innerHTML strong${sender}:/strong ${text}; if (sources sources.length 0) { let sourceHtml div classsourcestrong参考来源/strongbr; sources.forEach(s { sourceHtml 文件${s.source_file} br; }); sourceHtml /div; msgDiv.innerHTML sourceHtml; } chatBox.appendChild(msgDiv); chatBox.scrollTop chatBox.scrollHeight; } async function askQuestion() { const input document.getElementById(questionInput); const question input.value.trim(); if (!question) return; appendMessage(用户, question); input.value ; try { const response await fetch(API_URL, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ question: question }) }); const data await response.json(); if (data.success) { appendMessage(机器人, data.answer, data.source_documents); } else { appendMessage(系统, 抱歉出错了 data.error_message); } } catch (error) { appendMessage(系统, 网络请求失败 error.message); } } function handleKeyPress(event) { if (event.key Enter) { askQuestion(); } } /script /body /html并在app/main.py中增加静态文件服务from fastapi.staticfiles import StaticFiles app.mount(/static, StaticFiles(directorystatic), namestatic)然后访问http://localhost:8000/static/index.html即可使用简单的聊天界面。8.2 性能与生产环境优化建议模型量化与加速使用Ollama的更多量化版本如qwen2.5:7b-q4_K_M4位量化在几乎不损失精度的情况下大幅提升推理速度、降低内存占用。考虑使用vLLM或TGI等高性能推理框架部署模型支持动态批处理和持续批处理极大提高吞吐量。检索优化混合检索结合基于关键词的检索如BM25和向量检索提升召回率。重排序使用更精细的交叉编码器模型对检索出的Top-K结果进行重排序将最相关的结果排在最前面。元数据过滤在检索时加入过滤器例如只检索某个年份或某个类型的文档。系统架构异步处理将耗时的文档解析和向量化过程改为异步任务使用Celery或RQ。缓存对常见问题的答案进行缓存如使用Redis减少对模型和向量数据库的重复查询。监控与日志集成Prometheus和Grafana监控API性能、模型延迟使用结构化日志如JSON格式便于排查问题。安全与权限API认证为/api/ask接口添加API Key认证或JWT令牌验证。输入输出过滤对用户输入进行敏感词过滤和长度限制对模型输出进行内容安全检查防止生成有害信息。知识库权限根据不同用户角色设计不同的知识库访问权限。8.3 扩展方向从RAG到智能体当你的基础RAG系统稳定后可以探索更高级的AI应用形态多工具智能体让模型不仅能问答还能执行操作。例如连接财经数据库API查询实时股价连接计算工具进行复利计算。可以使用LangChain Agents或AutoGen框架。多轮对话与记忆当前的链是无状态的。可以集成ConversationBufferMemory或ConversationSummaryMemory让机器人记住之前的对话历史实现连贯的多轮对话。图检索增强对于高度结构化、关系复杂的知识如公司股权关系、金融事件链可以尝试GraphRAG将知识抽取成图结构利用图数据库进行更复杂的推理。至此你已经完成了一个具备企业级应用雏形的金融大模型问答机器人。从环境搭建、模型部署、知识库构建、RAG链开发到API服务封装我们走完了全流程。最重要的是你获得的不是零散的代码而是一个可运行、可扩展、可复用的完整项目框架。