
这次我们来看一个偏工程落地的 AI 学习主题基于 Udemy 课程的 AI LLM Engineering Mastery 体系把 GenAI 和 RAG 完整跑通。很多人学 LLM 容易卡在两个地方一是只知道调 API不知道检索增强生成RAG内部到底怎么串起来的二是本地部署一个 RAG 知识库时被文档解析、向量化、召回、重排这些环节搞得一头雾水。这篇文章不重复课程目录而是直接把 RAG 从理论到实战拆开让你看完能自己搭一套知识库问答服务。先说这个体系最核心的 4 个特点第一覆盖 Prompt Engineering、词向量、向量数据库、RAG 检索链路和 Agent 编排第二强调实际动手不只是看概念第三涉及本地模型与 API 模型混用适合做私有知识库第四会讲清楚精度问题 FP16/FP32/BF16 对生成效果和显存的影响。本文会演示三件事搭建一套最小可运行的 RAG 知识库、用 FastAPI 封装检索问答接口、以及批量处理文档时的显存与效果调优方法。适合正在做知识库问答、想入门 GenAI 开发、或者需要把 LLM 接到业务系统的读者。1. 核心能力速览能力项说明项目类型LLM 工程实战体系涵盖 GenAI 基础与 RAG 完整链路核心模型对话模型如 ChatGLM、Qwen、Llama 等开源模型与 Embedding 模型组合主要功能文档解析、文本切分、向量化存储、相似度检索、生成回答、Agent 编排推荐硬件本地部署建议 8G 显存以上纯 CPU 可运行但速度较慢显存占用取决于模型参数量与精度实际需按本机测试为准支持平台Windows / Linux / macOS部分模型依赖 CUDA需注意系统兼容性启动方式命令行启动 WebUI / API 服务是否支持 API支持可封装为独立问答服务是否支持批量任务支持文档批量导入、批量向量化、批量问答适合场景私有知识库问答、企业内部文档检索、RAG 技术学习与原型验证从材料看这套课程体系最大的价值不是教你调一个库而是把 LLM 应用到文档场景的完整链路拉通。学完之后你至少能回答这几个问题RAG 为什么能解决幻觉问题知识库的精度指标怎么理解本地模型和 OpenAI API 在 RAG 链路里各自扮演什么角色2. 适用场景与使用边界2.1 适合谁用第一类是后端开发工程师想在公司内部搭建知识库问答系统需要理解 RAG 的检索链路和接口封装。第二类是算法工程师已经熟悉模型训练但不太熟悉向量检索和文档解析的工程细节。第三类是独立开发者想快速验证一个 AI 产品原型需要把文档问答能力集成到现有系统里。2.2 能解决什么问题RAG 核心解决的是大模型知识更新难和幻觉问题。模型训练数据有截止时间但企业内部文档是持续更新的。把文档预先切分、向量化用户提问时先从知识库检索相关片段再把片段和问题一起交给大模型生成答案回答就有依据了。这套流程就是 RAGRetrieval-Augmented Generation检索增强生成。2.3 不适合什么场景如果你的知识库文档每天更新几十万篇且对召回延迟要求极高那需要更复杂的增量索引和分布式检索方案单机 RAG 原型不够用。如果业务场景完全不需要引用外部知识只需要模型本身的能力RAG 反而是多余的。2.4 合规边界涉及企业内部文档、客户数据、个人敏感信息时必须确认数据使用的合法授权。本地部署 RAG 的优势是数据不出内网但要确保模型文件和向量数据存储安全。如果调用第三方 API 处理数据要确认服务条款允许你的使用场景。人脸、声音、未授权版权内容相关场景严禁在未获授权的情况下处理。3. 环境准备与前置条件3.1 操作系统与硬件本地部署 RAG 的推荐环境是 Linux 或 Windows 10/11配备 NVIDIA GPU。如果是 macOS可以使用 M 系列芯片通过 MLX 或 CPU 运行小参数模型但检索效果和生成速度会受影响。硬件方面纯 CPU 可以跑通流程但 embedding 和生成都慢8G 显存可以运行 7B 以下量化模型16G 显存可以跑 13B 量化模型或 7B 全精度模型。这些都是经验值最终以实际测试为准。3.2 软件依赖通用依赖清单如下Python 3.9 或更高版本PyTorchGPU 版本需要匹配 CUDA 版本Transformers、LangChain 或 LlamaIndex向量数据库FAISS、Chroma、Milvus 或 QdrantEmbedding 模型如 BGE、M3E、text2vec 等文档解析库PyMuPDF、pypdf、docx、Tika框架FastAPI接口服务3.3 环境检查清单# 检查 Python 版本 python --version # 检查 CUDA 可用性GPU 环境 python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0)) # 检查显存 nvidia-smi如果torch.cuda.is_available()返回False需要重新安装匹配的 PyTorch 版本。这一步没做好后面跑模型会直接报错。4. RAG 项目安装部署4.1 创建虚拟环境mkdir rag-demo cd rag-demo python -m venv venv # Windows venv\Scripts\activate # Linux / macOS source venv/bin/activate4.2 安装依赖pip install torch --index-url https://download.pytorch.org/whl/cu118 pip install transformers langchain faiss-cpu chromadb pypdf fastapi uvicorn注意faiss-cpu适合学习和原型验证生产环境数据量大时使用faiss-gpu或独立向量数据库。4.3 准备模型文件RAG 需要两个模型Embedding 模型负责把文本变成向量对话模型负责生成回答。以 Hugging Face 下载为例# 安装 huggingface_hub pip install huggingface_hubfrom huggingface_hub import snapshot_download # 下载 Embedding 模型根据实际模型名替换 snapshot_download(repo_idBAAI/bge-small-zh-v1.5) # 下载对话模型根据实际模型名替换 snapshot_download(repo_idQwen/Qwen2-1.5B-Instruct)国内网络环境下载模型可能较慢建议配置镜像源或从其他可信渠道获取模型文件。4.4 启动文档索引流程这是 RAG 的核心把文档转成向量存进向量数据库。from langchain.document_loaders import PyPDFLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma # 1. 加载文档 loader PyPDFLoader(./docs/company_manual.pdf) documents loader.load() # 2. 切分文本 text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ] ) chunks text_splitter.split_documents(documents) print(f切分后文本块数量: {len(chunks)}) # 3. 初始化 Embedding 模型 embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5, encode_kwargs{normalize_embeddings: True} ) # 4. 存入向量数据库 vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db ) print(向量库构建完成)这一段跑完之后./chroma_db目录下就是你的知识库向量数据。之后每次新增文档只需要加载新文档切分后调用vectorstore.add_documents()即可增量写入。5. RAG 功能测试与效果验证5.1 向量检索测试先跑一个单纯检索测试确认向量库能召回相关内容这一步不调用生成模型。# 检索测试 query 公司的请假制度是怎样的 results vectorstore.similarity_search_with_score(query, k3) for i, (doc, score) in enumerate(results): print(f第 {i1} 个结果相似度: {score}) print(doc.page_content[:300]) print(---)判断标准检索结果是否与问题高度相关。如果召回内容完全无关需要检查切分粒度、Embedding 模型选择或文档本身质量。5.2 生成回答测试把检索到的文档片段拼接进 Prompt再调用对话模型生成最终答案。from transformers import AutoTokenizer, AutoModelForCausalLM import torch # 加载对话模型根据实际模型路径替换 tokenizer AutoTokenizer.from_pretrained(./models/Qwen2-1.5B-Instruct, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( ./models/Qwen2-1.5B-Instruct, torch_dtypetorch.float16, device_mapauto, trust_remote_codeTrue ) def generate_answer(query, contexts): context_text \n\n.join([ctx.page_content for ctx in contexts]) prompt f基于以下资料回答问题。 资料 {context_text} 问题{query} 回答 inputs tokenizer(prompt, return_tensorspt).to(model.device) outputs model.generate( inputs.input_ids, max_new_tokens512, do_sampleTrue, temperature0.7, top_p0.9 ) answer tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokensTrue) return answer # 先检索再生成 results vectorstore.similarity_search(query, k3) answer generate_answer(query, results) print(f问题{query}) print(f回答{answer})判断成功的标准回答内容能在资料片段中找到依据而不是模型自由发挥。如果回答引用的是资料里没有的内容说明 Prompt 约束不够强需要调整提示词。5.3 检索质量评测RAG 效果好不好看两个核心指标命中率和答案准确率。命中率Hit RateTop-K 检索结果里是否包含标注的标准答案片段。MRRMean Reciprocal Rank标准答案片段在检索结果中的排名倒数平均值越高说明排序越好。可以用真值标注的方式做小批量评测准备 20 组问题正确文档片段数据跑检索统计命中率和 MRR。这套评测方法比肉眼观察更可靠。5.4 失败排查现象可能原因处理方式检索结果与问题无关切分 chunks 太大或太小调整 chunk_size 到 300-800 之间检索结果相关但回答错误Prompt 中上下文约束不足增加“请只基于资料回答”的指令生成速度极慢对话模型太大或未用 GPU换小模型或检查 CUDA 是否可用回答出现幻觉retriever 召回片段不够增大 K 值或使用重排序模型6. 接口 API 与批量任务RAG 只有跑通链路过瘾真正能用起来要封装成 API 服务。下面用 FastAPI 做一个问答接口。6.1 FastAPI 服务封装from fastapi import FastAPI from pydantic import BaseModel app FastAPI(titleRAG Knowledge Base API) class QueryRequest(BaseModel): query: str top_k: int 3 class QueryResponse(BaseModel): answer: str sources: list app.post(/api/rag/query, response_modelQueryResponse) def query_rag(req: QueryRequest): # 检索 docs vectorstore.similarity_search(req.query, kreq.top_k) # 生成 answer generate_answer(req.query, docs) # 返回引用来源 sources [ {content: doc.page_content, metadata: doc.metadata} for doc in docs ] return QueryResponse(answeranswer, sourcessources) app.get(/api/health) def health_check(): return {status: ok} if __name__ __main__: import uvicorn uvicorn.run(app, host127.0.0.1, port8000)6.2 curl 调用示例curl -X POST http://127.0.0.1:8000/api/rag/query \ -H Content-Type: application/json \ -d {query: 公司的请假制度是怎样的, top_k: 3}6.3 Python 客户端调用示例import requests url http://127.0.0.1:8000/api/rag/query payload { query: 公司的请假制度是怎样的, top_k: 3 } response requests.post(url, jsonpayload, timeout60) result response.json() print(回答:, result[answer]) print(引用来源:) for source in result[sources]: print(-, source[content][:200])6.4 批量文档处理任务把待处理文档放进指定目录遍历加载并写入向量库import os from langchain.document_loaders import DirectoryLoader # 批量加载一个目录下的所有 PDF loader DirectoryLoader( ./docs_batch, glob**/*.pdf, loader_clsPyPDFLoader, show_progressTrue ) docs loader.load() text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50 ) chunks text_splitter.split_documents(docs) # 写入现有向量库append 模式 vectorstore.add_documents(chunks) print(f新增向量 {len(chunks)} 条)批量处理建议加日志和断点续传机制比如每处理完一个文件记录文件名避免中途崩溃后全部重跑。7. 资源占用与性能观察7.1 如何观察显存占用模型加载后用nvidia-smi实时查看进程占用watch -n 1 nvidia-smi在 Python 里也可以用pynvml读取显存import pynvml pynvml.nvmlInit() handle pynvml.nvmlDeviceGetHandleByIndex(0) info pynvml.nvmlDeviceGetMemoryInfo(handle) print(f总显存: {info.total // 1024**2} MB) print(f已用显存: {info.used // 1024**2} MB)7.2 FP16、FP32、BF16 精度问题实操这个问题在热词里出现频率很高实际部署时也确实关键。FP32完整精度占用显存最大速度最慢通常只在模型训练或精度敏感场景使用。FP16半精度显存占用约为 FP32 的一半推理速度快。但数值范围有限大模型训练时可能出现精度溢出。BF16Brain Floating Point与 FP16 相同显存占用但保留了更大的数值范围训练更稳定在较新的 GPU 上支持较好。推理时的显存估算公式模型显存 ≈ 参数量 × 每个参数的字节数。7B 模型用 FP16 大概是 14GB 显存用 INT8 量化大约 7GB用 INT4 量化约 3.5GB。这只是模型权重还要加上 KV Cache 和中间激活值。7.3 降低显存占用的方法使用量化版本模型如 GGUF 格式或 GPTQ 量化。限制max_new_tokens生成序列越长KV Cache 占用越大。减小批量大小批量问答时逐条处理。使用device_mapauto让模型层分散到多个设备。8. 常见问题与排查方法问题现象可能原因排查方式解决方案安装依赖时 torch 安装失败CUDA 版本与 PyTorch 不匹配nvidia-smi查看驱动支持的最高 CUDA 版本重新安装对应 PyTorch 版本启动后 API 接口访问不了服务未启动或端口被占用检查启动日志netstat -anofindstr 8000模型加载报OutOfMemory显存不足查看nvidia-smi中的显存占用换量化模型或减小输入长度向量库文件损坏写入过程中强制终止检查日志中的写入状态重新构建向量库检索结果为空文档切分后文本块太少查看切分后的 chunk 数量减小 chunk_size 或检查文档是否可解析生成回答与资料无关Prompt 约束不足打印最终的 Prompt 内容在 Prompt 中强调“仅基于资料回答”API 批量任务卡住单条请求生成时间过长查看模型推理日志加超时时间改异步或队列处理中文效果差Embedding 模型不适合中文测试检索相关度换用 BGE、M3E 等中文优化模型8.1 关于 Agent 和 RAG 的区别热搜词里反复出现 Agent 和 Agentic RAG这里简单区分。传统 RAG 是单轮检索 - 生成。Agentic RAG 是在这个基础上引入决策循环模型判断当前问题是否需要多次检索、是否需要调用工具、检索结果是否足够。复杂问题可能需要拆解成多个子问题每个子问题分别检索。如果你的场景是单一文档库问答传统 RAG 足够如果涉及多数据源、多步推理再考虑 Agent 编排。9. 最佳实践与使用建议9.1 文本切分策略切分粒度直接决定检索效果。过小的 chunk 虽然定位精准但可能缺乏上下文过大的 chunk 上下文完整但检索噪音多。实践中的思路是先按章节和段落结构切再用固定长度兜底。分隔符优先级建议先按\n\n、再按句号、最后按空格。对于代码、表格这类特殊内容考虑使用专门解析器。9.2 重排序模型单纯向量检索的 Top-K 结果噪声较大。可以先用向量检索召回 Top-50再用 Cross-Encoder 重排序模型取 Top-3。这样准确率通常比直接 Top-3 高不少。常见的重排序方案有bge-reranker等可以作为后续优化方向。9.3 工程化管理建议建立config.yaml统一管理模型路径、chunk 大小、Top-K 等参数不要写死在代码里。模型文件、输入文档、向量库、输出结果分目录存放。批量任务加日志和失败重试每处理完一个文件记录进度。API 服务默认绑定127.0.0.1避免直接暴露公网需要对外提供时加鉴权。每次调整切分参数后重新构建向量库不要混用不同参数的向量。9.4 合规提醒凡是把企业内部文档、客户资料、未公开数据接入大模型先确认授权范围。本地部署 RAG 虽然数据不出内网但模型文件和向量库都属于敏感资产需要做好访问控制。对外提供服务时Prompt 注入风险也要考虑限定用户输入长度、过滤异常请求。10. 总结与下一步这个体系最值得尝试的点是把 Embedding 模型、向量数据库、对话模型、FastAPI 四个组件串成一套完整的 RAG 问答服务。整个链路跑通后你对 LLM 工程化部署、检索召回、精度选择、接口封装都会有一个整体认识。最先要验证的是文档加载和切分环节这个环节最容易出问题。很多 PDF 解析出来是乱码或空文本向量化之后检索效果自然差。建议先用一两份干净文档跑通全流程再逐步增加复杂格式的文档。最容易踩的坑有两类一是切分参数设置不合理导致召回效果差二是忽略了嵌入模型和对话模型的显存叠加在 8G 显卡上同时加载两个模型直接 OOM。解决办法是 Embedding 用小模型对话模型用量化版或者把两段逻辑拆成两个独立服务。再往后可以继续扩展的方向引入重排序模型提升召回精度加上 LangSmith 或 Langfuse 做链路追踪把检索链路升级成 Agentic RAG支持多轮对话和工具调用。这套课程的价值在于让学习者在真实工程链路里建立直觉而不是停留在 API 调用层面。建议先照着本文把最小系统跑通再逐步往生产级演进。