资讯中心

从传统开发到企业级大模型应用:RAG、智能体与LoRA微调实战指南

📅 2026/8/24 2:48:44
从传统开发到企业级大模型应用:RAG、智能体与LoRA微调实战指南
在实际技术转型过程中很多开发者发现从传统软件开发转向大模型应用开发最大的障碍不是学习某个新框架的API而是对整个技术栈的认知断层。传统开发关注业务逻辑、数据库CRUD和系统架构而大模型开发的核心变成了提示工程、上下文管理、向量检索和模型服务化。这种转变让很多付费课程也显得隔靴搔痒要么过于理论化要么只演示理想环境下的“玩具”项目。本文将围绕一条清晰的主线如何将一个传统开发者视角平滑过渡到能够独立完成企业级大模型应用落地的能力。我们会从最基础的本地环境搭建开始通过构建一个具备知识问答和自动化任务能力的智能体项目串联起RAG、微调、部署等核心环节确保每个步骤都有可运行的代码、可验证的结果和可排查的路径。1. 理解大模型开发的核心范式从“编程”到“引导”在开始写第一行代码之前必须扭转思维。传统编程是给计算机下达精确的指令序列而大模型开发更像是引导一个拥有海量知识但“性格”不确定的专家。你的工作从“编写逻辑”变成了“设计交互上下文、提供精准知识、定义任务流程”。1.1 智能体、RAG与微调解决不同层面的问题这三个关键词构成了大模型应用开发的铁三角各自有明确的职责和适用场景混淆它们会导致项目设计混乱。智能体这是一个执行单元。它接收用户目标通过思考、调用工具、检索知识来规划并执行一系列动作最终达成目标。你可以把它理解为一个“项目经理”它自己不生产知识但会协调各方资源。RAG这是一种知识增强技术。当大模型自身知识不足、过时或需要精确参考时RAG通过检索外部知识库如向量数据库将相关文档片段作为上下文提供给模型从而生成更准确、可靠的回答。它是智能体的“资料库管理员”。微调这是一种模型行为定制技术。通过用特定领域的数据对预训练大模型进行额外训练改变其内在的权重使其输出风格、格式或特定任务能力更符合你的需求。比如让模型学会用固定的JSON格式回复。它是从底层塑造模型的“性格”和“专业能力”。一个典型的企业级应用往往是这样的一个智能体作为大脑当遇到需要专业知识的问题时它调用RAG系统从企业知识库中查找资料而这个智能体本身或者其中负责特定任务的小模型可能已经通过微调来适应了企业的对话风格和任务规范。1.2 本地化部署能力、成本与隐私的平衡“部署”是让技术产生价值的最后一公里。对于大模型部署方式直接决定了成本、性能和可控性。全量部署在自有GPU服务器上运行整个大模型如Llama 3、Qwen。优点是完全自主、数据不出域、可深度定制。缺点是硬件成本高显存要求大技术栈复杂。API调用使用云服务商如OpenAI、DeepSeek、MiniMax提供的接口。优点是开箱即用、免运维、按需付费。缺点是存在数据隐私顾虑、网络延迟、持续调用成本可能很高。轻量级部署使用Ollama、vLLM等工具在本地运行量化后的模型。它在性能和资源之间取得了很好的平衡是个人学习和中小项目原型的首选。对于学习和企业内网场景从Ollama开始是阻力最小的路径。它简化了模型下载、加载和服务的全过程。2. 环境准备搭建可复现的本地开发沙盒在开始任何项目前一个干净、可复现的环境是高效开发和排查问题的基石。我们将使用Conda管理Python环境用Docker运行向量数据库用Ollama运行本地大模型。2.1 基础软件安装清单请确保你的开发机建议使用Linux或macOSWindows可使用WSL2已安装以下软件软件推荐版本作用验证命令Python3.9 - 3.11主开发语言python --versionConda最新版创建隔离的Python环境conda --versionDocker最新版容器化运行数据库等服务docker --versionGit最新版版本控制和代码获取git --versionOllama最新版本地大模型的运行和管理ollama --version注意避免使用系统自带的Python务必通过Conda创建独立环境防止包依赖冲突。2.2 创建并激活专属的Python环境# 创建一个名为llm-dev的Python 3.10环境 conda create -n llm-dev python3.10 -y # 激活环境 conda activate llm-dev激活后你的命令行提示符前通常会显示(llm-dev)表示已进入该环境。2.3 启动向量数据库ChromaDB我们将使用ChromaDB作为向量数据库它轻量且易于集成。通过Docker运行可以避免复杂的本地安装。# 拉取ChromaDB的Docker镜像 docker pull chromadb/chroma # 在后台运行ChromaDB将容器的8000端口映射到本机的8000端口 docker run -d -p 8000:8000 --name chroma chromadb/chroma运行后可以通过docker ps命令查看容器是否正常运行。访问http://localhost:8000/api/v1/heartbeat若能收到响应则说明服务已就绪。2.4 安装核心Python依赖库在激活的llm-dev环境中安装项目所需的核心库。我们将使用langchain作为智能体框架chromadb作为客户端sentence-transformers用于文本向量化。pip install langchain langchain-community langchain-chroma pip install sentence-transformers pip install pydantic python-dotenv pip install fastapi uvicorn # 用于后续构建API服务2.5 下载并运行本地大模型Llama 3.1Ollama极大地简化了本地运行大模型的过程。这里我们选择8B参数的Llama 3.1它在性能和精度上比较平衡。# 拉取Llama 3.1 8B模型 (约4.7GB) ollama pull llama3.1:8b # 在后台运行该模型服务指定服务端口 ollama run llama3.1:8b运行后Ollama会在http://localhost:11434提供一个兼容OpenAI API格式的接口。你可以通过简单的curl命令测试curl http://localhost:11434/api/generate -d { model: llama3.1:8b, prompt: Hello, how are you?, stream: false }如果收到一个包含回答的JSON响应说明模型服务运行成功。至此你的本地沙盒环境已经包含独立的Python环境、向量数据库服务、本地大模型服务。这是后续所有实战的基础。3. 实战一构建你的第一个RAG知识库问答系统RAG的核心流程是“检索-增强-生成”。我们将创建一个能够回答特定领域例如“公司内部技术规范”问题的系统。3.1 项目结构与数据准备创建一个项目目录并组织文件结构my_rag_project/ ├── data/ # 存放原始知识文档 │ └── handbook.pdf # 示例员工手册PDF ├── docs/ # 存放处理后的文本片段 ├── vector_db/ # 存放向量数据库持久化文件 ├── config.py # 配置文件 ├── ingest.py # 知识库入库脚本 ├── query.py # 问答查询脚本 └── requirements.txt # 依赖列表在data/目录下放置你的知识文档支持.txt, .pdf, .md, .docx等格式。ingest.py脚本负责读取文档、切分文本、生成向量并存入数据库。3.2 实现知识库入库脚本ingest.py是RAG的“数据预处理管道”。它的质量直接决定检索效果。# ingest.py import os from langchain_community.document_loaders import PyPDFLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_chroma import Chroma from langchain.schema import Document # 1. 加载文档 def load_documents(data_dir): documents [] for filename in os.listdir(data_dir): filepath os.path.join(data_dir, filename) if filename.endswith(.pdf): loader PyPDFLoader(filepath) elif filename.endswith(.txt): loader TextLoader(filepath, encodingutf-8) else: continue loaded_docs loader.load() documents.extend(loaded_docs) print(f已加载 {len(documents)} 个文档) return documents # 2. 分割文本 def split_documents(documents): # 递归字符分割器按段落、句子、单词进行分割尽量保持语义完整 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个文本块的最大字符数 chunk_overlap50, # 块之间的重叠字符数避免上下文断裂 separators[\n\n, \n, 。, , , , ] ) chunks text_splitter.split_documents(documents) print(f文档被分割成 {len(chunks)} 个文本块) return chunks # 3. 生成向量并存入数据库 def create_vector_store(chunks, persist_directory./vector_db): # 使用开源模型生成文本向量无需API Key embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5 # 中文小模型效果不错 ) # 创建向量数据库并持久化到本地 vector_store Chroma.from_documents( documentschunks, embeddingembeddings, persist_directorypersist_directory ) print(f向量数据库已创建并保存至 {persist_directory}) return vector_store if __name__ __main__: data_dir ./data # 执行流水线 raw_docs load_documents(data_dir) text_chunks split_documents(raw_docs) vectordb create_vector_store(text_chunks) print(知识库构建完成)关键参数解释chunk_size500这是平衡检索精度和上下文长度的关键。太小会丢失信息太大会引入噪声。对于中文500-800是个不错的起点。chunk_overlap50重叠部分能确保一个完整的句子或概念不会因为被切分在两段而丢失是提升召回率的重要技巧。BAAI/bge-small-zh-v1.5这是一个在中文语义相似度任务上表现优异的开源向量模型适合本地部署。运行脚本python ingest.py。如果data/目录下有文档你会看到加载、分割和保存的日志。3.3 实现问答查询脚本query.py是RAG的“检索-生成”核心。# query.py from langchain_chroma import Chroma from langchain_community.embeddings import HuggingFaceEmbeddings from langchain.prompts import PromptTemplate from langchain_community.llms import Ollama from langchain.chains import RetrievalQA # 1. 加载已持久化的向量数据库 def load_vector_store(persist_directory./vector_db): embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vector_store Chroma( persist_directorypersist_directory, embedding_functionembeddings ) return vector_store # 2. 定义提示词模板 prompt_template 请根据以下上下文信息回答问题。如果上下文信息不足以回答问题请直接说“根据现有资料无法回答该问题”不要编造信息。 上下文 {context} 问题{question} 请给出专业、准确的回答 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 3. 构建检索问答链 def create_qa_chain(): # 加载向量库 vectordb load_vector_store() # 连接本地Ollama服务 llm Ollama(base_urlhttp://localhost:11434, modelllama3.1:8b) # 创建检索器设置返回最相关的3个文本块 retriever vectordb.as_retriever(search_kwargs{k: 3}) # 构建链检索 - 组合上下文 - 生成回答 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 最简单的方式将所有检索到的上下文拼接到提示词中 retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回源文档便于溯源 ) return qa_chain if __name__ __main__: qa_chain create_qa_chain() while True: question input(\n请输入您的问题 (输入 quit 退出): ) if question.lower() quit: break result qa_chain.invoke({query: question}) print(f\n答案{result[result]}) print(\n--- 参考来源 ---) for i, doc in enumerate(result[source_documents]): print(f[{i1}] {doc.page_content[:200]}...) # 打印前200字符运行脚本python query.py。输入关于你知识文档内容的问题系统会从向量库中检索相关片段并让模型生成基于上下文的回答。3.4 RAG系统常见问题排查问题现象可能原因检查点与解决方案回答“根据现有资料无法回答”但资料中明明有相关内容。1. 检索失败向量相似度低。2. 文本分割不合理关键信息被切碎。3. 提示词模板限制了模型。1.检查检索结果在query.py中打印retriever.get_relevant_documents(question)看返回的文本块是否相关。2.调整分割策略减小chunk_size或调整separators。3.优化提示词在模板中强调“请仔细阅读上下文”。回答包含事实性错误或“幻觉”。模型过度依赖自身知识忽略了提供的上下文。1.强化提示词在模板开头使用更强烈的指令如“必须严格依据上下文禁止使用外部知识”。2.调整温度在Ollama初始化时加入temperature0.1降低随机性。3.使用map_reduce链对于长上下文stuff方式可能使模型忽略中间部分可尝试chain_typemap_reduce。检索速度慢。1. 向量模型太大。2. 向量库未使用索引。1.换更小的向量模型如paraphrase-multilingual-MiniLM-L12-v2。2.确认索引Chroma默认会创建索引确保数据量增大后依然有效。4. 实战二开发一个任务导向的智能体智能体的核心是“思考-行动-观察”循环。我们将使用LangChain的ReAct框架构建一个能查询天气、计算数学、搜索知识库的简单智能体。4.1 设计智能体工具智能体通过工具与世界交互。首先我们定义几个工具函数。# agent_tools.py import requests import json import math from typing import Type from pydantic import BaseModel, Field # 工具1天气查询工具 class WeatherInput(BaseModel): city: str Field(description需要查询天气的城市名称例如北京) def get_weather(city: str) - str: 根据城市名查询实时天气。 # 注意这里使用一个模拟API真实项目需替换为真实天气API如和风、OpenWeatherMap # 请遵守相关API的使用条款。 try: # 模拟返回 weather_data { 北京: 晴15-25°C微风, 上海: 多云18-28°C东南风3级, 深圳: 阵雨22-30°C南风2级 } return weather_data.get(city, f未找到{city}的天气信息。) except Exception as e: return f查询天气时出错{str(e)} # 工具2数学计算工具 class CalculatorInput(BaseModel): expression: str Field(description需要计算的数学表达式例如3 * 7 5) def calculate(expression: str) - str: 计算一个数学表达式的结果。 try: # 警告使用eval存在安全风险仅用于演示。生产环境应使用安全表达式解析库如asteval。 result eval(expression, {__builtins__: None}, {math: math}) return str(result) except Exception as e: return f计算表达式 {expression} 时出错{str(e)} # 工具3知识库问答工具复用之前的RAG系统 from query import create_qa_chain qa_chain create_qa_chain() # 注意这里需要先运行RAG项目并导入 class KnowledgeBaseInput(BaseModel): question: str Field(description需要咨询的、关于公司知识库的问题) def query_knowledge_base(question: str) - str: 从公司内部知识库中查找信息来回答问题。 result qa_chain.invoke({query: question}) return result[result]4.2 构建智能体并运行使用LangChain的create_react_agent来组装智能体。# agent_main.py from langchain import hub from langchain.agents import create_react_agent, AgentExecutor from langchain_community.llms import Ollama from langchain.tools import Tool from agent_tools import get_weather, WeatherInput, calculate, CalculatorInput, query_knowledge_base, KnowledgeBaseInput # 1. 初始化大模型 llm Ollama(base_urlhttp://localhost:11434, modelllama3.1:8b) # 2. 将函数封装成LangChain工具 tools [ Tool( nameWeather, funcget_weather, description查询指定城市的天气情况。输入应为城市名。, args_schemaWeatherInput ), Tool( nameCalculator, funccalculate, description计算一个数学表达式的结果。输入应为有效的数学表达式如 3 * 7 5。, args_schemaCalculatorInput ), Tool( nameKnowledgeBase, funcquery_knowledge_base, description查询公司内部知识库获取关于规章制度、技术文档等问题的答案。, args_schemaKnowledgeBaseInput ) ] # 3. 从LangChain Hub拉取一个ReAct风格的提示词模板 prompt hub.pull(hwchase17/react) # 4. 创建智能体 agent create_react_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # 5. 运行智能体 if __name__ __main__: queries [ 北京今天的天气怎么样, 125乘以38等于多少, 我们公司的年假规定是怎样的, # 这个问题会触发知识库工具 先查一下上海天气然后计算一下如果温度是25度华氏度是多少 ] for query in queries: print(f\n{*50}) print(f用户问题: {query}) print(f{*50}) try: result agent_executor.invoke({input: query}) print(f最终答案: {result[output]}) except Exception as e: print(f执行出错: {e})运行python agent_main.py。你会看到详细的verbose日志展示智能体“思考”决定用哪个工具、“行动”调用工具、“观察”得到工具结果的完整循环最终整合出答案。4.3 智能体开发的关键要点与排错工具描述至关重要智能体完全依赖description字段来决定是否以及如何调用工具。描述必须清晰、准确说明输入格式和工具用途。处理解析错误handle_parsing_errorsTrue能防止智能体因输出格式不符合预期而崩溃让它有机会重试。控制复杂度初期工具不宜过多3-5个为宜避免智能体陷入选择困难。复杂的任务应该被拆分成子任务由更高级的智能体或编排器来调度。常见错误工具调用失败检查工具函数本身是否能独立运行输入输出格式是否符合args_schema。智能体陷入循环设置max_iterations参数在AgentExecutor中来限制最大思考步数防止死循环。回答冗长或离题优化提示词模板从Hub拉取的prompt在系统指令中强调简洁和专注。5. 实战三使用LoRA对模型进行高效微调当智能体或RAG系统在特定格式、风格或专业领域任务上表现不佳时就需要微调。全参训练成本极高LoRA是一种参数高效微调技术它只训练注入到模型中的少量低秩矩阵却能达到接近全参微调的效果。5.1 微调准备数据与环境我们以让模型学会按固定JSON格式回复为例进行微调。1. 准备训练数据(data/train.jsonl) 每行是一个JSON对象包含instruction指令和output期望输出。{instruction: 查询用户张三的信息。, output: {\name\: \张三\, \department\: \研发部\, \status\: \在职\}} {instruction: 报告昨天的系统错误。, output: {\date\: \2023-10-26\, \error_count\: 5, \level\: \WARNING\}} {instruction: 将以下任务标记为完成更新文档。, output: {\task\: \更新文档\, \status\: \completed\, \updated_at\: \2023-10-27 10:00:00\}}需要准备几百到几千条这样的高质量配对数据。2. 安装微调专用库pip install transformers datasets peft accelerate trl bitsandbytes3. 确认GPU可用python -c import torch; print(torch.cuda.is_available())如果输出True则可以使用GPU加速。5.2 编写LoRA微调脚本以下是基于transformers和peft库的核心微调脚本 (finetune_lora.py)# finetune_lora.py from datasets import load_dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling ) from peft import LoraConfig, get_peft_model, TaskType import torch # 1. 加载模型和分词器 model_name meta-llama/Llama-3.1-8B # 或使用本地路径 tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) # 设置填充令牌 if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token model AutoModelForCausalLM.from_pretrained( model_name, load_in_4bitTrue, # 使用QLoRA技术4位量化加载极大减少显存占用 bnb_4bit_compute_dtypetorch.float16, device_mapauto, trust_remote_codeTrue ) # 2. 配置LoRA lora_config LoraConfig( task_typeTaskType.CAUSAL_LM, # 因果语言模型任务 r8, # LoRA秩影响参数量通常8-32 lora_alpha32, # 缩放参数 lora_dropout0.1, target_modules[q_proj, v_proj] # 针对LLaMA模型通常注入到注意力层的查询和值投影矩阵 ) model get_peft_model(model, lora_config) model.print_trainable_parameters() # 打印可训练参数量应该只占原模型很小一部分 # 3. 加载并预处理数据 def preprocess_function(examples): # 将指令和输出组合成模型训练的文本格式 texts [fInstruction: {ins}\nOutput: {out}|endoftext| for ins, out in zip(examples[instruction], examples[output])] # 令牌化 tokenized tokenizer(texts, truncationTrue, paddingmax_length, max_length512) tokenized[labels] tokenized[input_ids].copy() # 对于因果LM标签就是输入ID本身 return tokenized dataset load_dataset(json, data_files./data/train.jsonl, splittrain) tokenized_dataset dataset.map(preprocess_function, batchedTrue) # 4. 定义训练参数 training_args TrainingArguments( output_dir./lora_finetuned_model, num_train_epochs3, # 训练轮数 per_device_train_batch_size4, # 根据GPU显存调整 gradient_accumulation_steps4, # 梯度累积模拟更大批次 warmup_steps100, logging_steps10, save_steps200, evaluation_strategyno, # 示例中未准备验证集 save_total_limit2, fp16True, # 混合精度训练节省显存 push_to_hubFalse, # 不推送至Hugging Face Hub ) # 5. 创建Trainer并开始训练 trainer Trainer( modelmodel, argstraining_args, train_datasettokenized_dataset, data_collatorDataCollatorForLanguageModeling(tokenizertokenizer, mlmFalse), ) trainer.train() trainer.save_model() # 保存LoRA权重 tokenizer.save_pretrained(training_args.output_dir) print(f训练完成模型保存在 {training_args.output_dir})5.3 加载与使用微调后的模型训练完成后会得到原始的基座模型加上一个额外的LoRA权重文件adapter_model.bin。使用时需要合并加载。# load_and_use_lora.py from transformers import AutoModelForCausalLM, AutoTokenizer from peft import PeftModel base_model_name meta-llama/Llama-3.1-8B lora_model_path ./lora_finetuned_model # 加载原始模型 model AutoModelForCausalLM.from_pretrained(base_model_name, device_mapauto) tokenizer AutoTokenizer.from_pretrained(base_model_name) # 加载LoRA权重并合并到原模型 model PeftModel.from_pretrained(model, lora_model_path) model model.merge_and_unload() # 将LoRA权重合并到原模型便于后续部署 # 使用微调后的模型进行推理 prompt Instruction: 查询用户李四的信息。\nOutput: inputs tokenizer(prompt, return_tensorspt).to(model.device) outputs model.generate(**inputs, max_new_tokens50) response tokenizer.decode(outputs[0], skip_special_tokensTrue) print(response) # 期望输出{name: 李四, department: ..., status: ...} 类似的JSON格式5.4 微调过程中的常见问题问题原因与解决方案CUDA out of memory1.减小批次大小降低per_device_train_batch_size。2.启用梯度检查点在model.from_pretrained中设置use_cacheFalse。3.使用梯度累积已设置gradient_accumulation_steps。4.使用更低精度确保fp16True并可尝试bf16True如果硬件支持。训练损失不下降1.学习率不合适尝试调整learning_rate在TrainingArguments中。2.数据质量差检查训练数据train.jsonl的指令和输出是否匹配、格式是否一致。3.LoRA参数不当增大r如从8调到16或调整target_modules。模型输出格式不符合预期1.训练数据不足或噪声大增加高质量数据。2.提示词不一致确保推理时的提示词格式Instruction: ...\nOutput:与训练时完全一致。3.训练轮数不够增加num_train_epochs。6. 生产级部署与服务化一个实验性质的脚本和可用于生产的API服务之间有巨大鸿沟。我们需要考虑并发、监控、稳定性、配置管理。这里使用FastAPI将我们训练好的RAG问答系统封装成HTTP API。6.1 构建FastAPI应用创建api_service.py# api_service.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from query import create_qa_chain # 导入之前写好的RAG链 import logging import uvicorn # 配置日志 logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) # 初始化FastAPI应用 app FastAPI(title企业知识库QA API, version1.0.0) # 全局加载QA链避免每次请求重复加载 # 注意在生产中需要考虑更复杂的生命周期管理和健康检查 try: qa_chain create_qa_chain() logger.info(QA链加载成功。) except Exception as e: logger.error(f初始化QA链失败: {e}) qa_chain None # 定义请求/响应模型 class QueryRequest(BaseModel): question: str user_id: str | None None # 可用于审计和限流 class QueryResponse(BaseModel): answer: str sources: list[str] | None None success: bool error_message: str | None None # 健康检查端点 app.get(/health) async def health_check(): return {status: healthy, model_loaded: qa_chain is not None} # 核心问答端点 app.post(/query, response_modelQueryResponse) async def query_knowledge_base(request: QueryRequest): if qa_chain is None: raise HTTPException(status_code503, detail服务未就绪QA链加载失败) try: logger.info(f收到用户 {request.user_id} 的查询: {request.question}) result qa_chain.invoke({query: request.question}) sources [doc.page_content[:500] for doc in result.get(source_documents, [])] return QueryResponse( answerresult[result], sourcessources, successTrue ) except Exception as e: logger.error(f处理查询时出错: {e}, exc_infoTrue) return QueryResponse( answer, sourcesNone, successFalse, error_messagef内部服务错误: {str(e)} ) if __name__ __main__: # 启动服务绑定到所有网络接口的8001端口 uvicorn.run(app, host0.0.0.0, port8001)6.2 使用Docker容器化部署创建Dockerfile以构建可移植的镜像# Dockerfile FROM python:3.10-slim WORKDIR /app # 复制依赖文件并安装 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 复制应用代码和模型数据 COPY . . # 暴露端口 EXPOSE 8001 # 启动命令 CMD [python, api_service.py]创建.dockerignore文件排除不必要的文件__pycache__/ *.pyc *.pyo *.pyd .Python env/ venv/ *.egg-info/ dist/ build/ vector_db/ # 注意向量数据库数据较大建议通过卷挂载而非打包进镜像 data/构建并运行Docker容器# 构建镜像 docker build -t my-rag-api . # 运行容器将本地向量数据库目录挂载到容器内并映射端口 docker run -d -p 8001:8001 -v $(pwd)/vector_db:/app/vector_db --name rag-service my-rag-api6.3 生产环境部署清单与监控将服务跑起来只是第一步生产环境需要更多保障配置管理将模型路径、API密钥、数据库连接等配置外置为环境变量或配置文件不要硬编码在代码中。日志与监控日志使用结构化日志如JSON格式并输出到标准输出stdout方便Docker和K8s收集。集成logging库区分不同级别INFO, ERROR。监控为FastAPI集成Prometheus监控指标使用prometheus-fastapi-instrumentator监控请求延迟、错误率和流量。健康检查实现/health和/ready端点用于负载均衡器和编排系统如K8s探活。性能与扩展模型服务分离将Ollama模型服务与业务API服务分离模型服务可以独立扩展GPU资源。向量数据库集群对于大规模知识库考虑使用ChromaDB集群或更强大的向量数据库如Milvus、Weaviate。缓存对常见查询结果进行缓存如使用Redis减少对模型和向量数据库的重复调用。安全API认证为/query端点添加API Key或JWT认证。输入验证对用户输入的question进行长度和内容过滤防止提示词注入攻击。网络隔离确保服务在内网运行或通过API网关对外暴露。从本地实验到生产部署核心思想是解耦、监控、弹性。每一个组件模型、向量库、业务逻辑都应可独立部署、伸缩和故障恢复。通过本文的实践路径你不仅掌握了各个模块的搭建也获得了将它们串联成一个健壮企业级应用的基础蓝图。接下来的方向可以是深入优化RAG的检索质量、设计更复杂的多智能体协作流程或是探索模型量化以进一步降低部署成本。