ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

手写一个迷你 RAG:50 行代码跑通文档问答

手写一个迷你 RAG:50 行代码跑通文档问答 手写一个迷你 RAG50 行代码跑通文档问答系列RAG 实战系列 第01篇上一篇MCP vs A2A vs ACP2026 年 Agent 协议选型指南协议层系列完结预计阅读12 分钟读完你能得到一个能跑、能改、能接你真实文档的迷你 RAG——完整 50 行代码在文末可直接复制引子每个想做 RAG 的人都死在第一周一位读者的原话私信“想让公司内部文档能问答。搜了三天教程LangChain 版本对不上、LlamaIndex 文档看不懂、还得先装 Docker 起个 Milvus……我到现在一行代码都没跑起来。”这是 RAG 落地最真实的死法——不是死于技术难是死于框架太重。RAG 的本质其实非常简单把你的文档切成小块 → 变成向量 → 用户提问时找到最相关的几块 → 塞进 prompt 让大模型回答。就这么四步。什么 LangChain、向量数据库、Docker都是这四步的工业化包装。包装有价值但你不应该先学包装再学本质。这篇用 50 行纯 Python 跑通上面四步——不用 LangChain不用向量数据库不用 Docker。跑通之后你会对后面三篇踩坑实录、向量库选型、Rerank里的每个概念都有体感。一、环境准备2 分钟装好1.1 装依赖只需要两个包Python 3.9pip install sentence-transformers openai包干什么备注sentence-transformers文本向量化本地跑免费会自动带上 torchopenai调大模型 API兼容 DeepSeek 等任何 OpenAI 格式接口1.2 验证安装python -c import sentence_transformers; print(OK, sentence_transformers.__version__) # 输出类似: OK 3.x.x —— 就绪1.3 准备大模型 API Key用 DeepSeek 举例换任何 OpenAI 格式的服务都行**1.**打开 https://platform.deepseek.com/**2.**API Keys → 创建 → 复制形如sk-xxxx第一次跑SentenceTransformer时会下载模型文件约 100MB一次性。国内网络慢的话设置镜像export HF_ENDPOINThttps://hf-mirror.com环境就绪。下面进入正题——先看全景再逐块拆。二、全景50 行代码长什么样先上完整结构细节下节拆。整个 RAG 就三个函数 一段准备# ── 准备文档 嵌入模型 ────────────────── docs [...] # ① 你的文档切成块后的 model SentenceTransformer(...) # ② 嵌入模型本地 doc_vecs model.encode(docs) # ③ 全部向量化建索引 # ── 检索函数 ────────────────────────────── def retrieve(query, top_k): # ④ 问题向量化 → 余弦相似度 → 排序取前K # ── 生成函数 ────────────────────────────── def answer(question): # ⑤ 检索 → 拼上下文 → 调大模型没有向量数据库。因为 5 条文档的向量检索就是一个矩阵乘法——numpy一行搞定。向量数据库解决的是百万级向量的检索性能你先用不到等用到时再看第 03 篇。对照上图这 50 行覆盖了管道的核心三层切分→向量化→检索→生成。工业级管道里剩下的层清洗、重排、评估是后面三篇的主角。三、逐块拆解每一行为什么这么写3.1 文档块chunk 是什么docs [ RAG 是检索增强生成的缩写通过检索外部知识来增强大模型的回答。, RAG 系统的核心组件包括文档切分、向量化、向量存储、检索和生成。, RAG 相比微调的优势成本低、知识可随时更新、不遗忘通用能力。, chunk 是 RAG 中的最小检索单元通常包含 256-512 个 token。, 余弦相似度是 RAG 中最常用的向量相似度度量方法。, ]为什么是一条一条而不是整篇文档因为检索的粒度决定命中的精度你问chunk 多大合适如果索引的是整篇 5000 字文档向量是全文语义的平均值跟问题的相关度就被稀释了。切成小块每块向量语义集中命中率才高。这里的 5 条是演示数据手工切好的。接真实文档时把你的 md/txt 读进来按段落或每 300-500 字切一刀即可——第 02 篇会专门讲切分怎么踩坑。3.2 向量化本地嵌入模型model SentenceTransformer(BAAI/bge-small-zh-v1.5) doc_vecs model.encode(docs, normalize_embeddingsTrue)•****BAAI/bge-small-zh-v1.5中文小模型本地 CPU 可跑512 维。选它是中文 免费 快三个条件的最优解•****normalize_embeddingsTrue把向量归一化成单位长度。这一步是后面矩阵乘法 余弦相似度的前提——不是可选项是伏笔跑完doc_vecs是一个5 × 512的矩阵。你的向量索引建好了就一个 numpy 数组。3.3 检索一个矩阵乘法def retrieve(query: str, top_k: int 2): q_vec model.encode([query], normalize_embeddingsTrue) scores q_vec doc_vecs.T # 余弦相似度 top_idx scores[0].argsort()[::-1][:top_k] return [docs[i] for i in top_idx]这五行是 RAG 的心脏逐行看•q_vec doc_vecs.T1×512乘512×51×5得到问题和 5 个文档块的相似度。因为两边都归一化了矩阵乘积就是余弦相似度——这就是 3.2 那个伏笔的回收•argsort()[::-1]按分数从高到低排序•[:top_k]取前 K 个。K 是超参数迷你版取 2验证一下检索好不好使print(retrieve(RAG 有什么优点)) # 期望输出第一条是「RAG 相比微调的优势成本低、知识可随时更新……」如果你的第一条不是它先检查normalize_embeddingsTrue是不是漏了——没归一化时矩阵乘法算的是点积受向量长度影响排序会错。3.4 生成拼上下文调大模型client OpenAI(api_keysk-xxx, base_urlhttps://api.deepseek.com) def answer(question: str) - str: context \n.join(f[{i1}] {c} for i, c in enumerate(retrieve(question))) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: f仅根据以下资料回答资料里没有就明确说不知道。\n{context}}, {role: user, content: question}, ], ) return resp.choices[0].message.content三个细节决定回答质量1.****system prompt 里那句资料里没有就明确说不知道——防幻觉的最低成本手段。没有它模型会用自己的参数知识补答案跟你的文档没关系**2.**带[1] [2]编号——后续要求模型引用编号就得到最朴素的引用溯源**3.**只塞 top_k 个块不塞全部——上下文不是越多越好第 02 篇讲中间衰减时会展开3.5 跑起来if __name__ __main__: print(answer(RAG 的核心组件有哪些))预期输出根据资料 [2]RAG 系统的核心组件包括文档切分、向量化、向量存储、检索和生成。问一个资料里没有的print(answer(RAG 支持图片检索吗)) # 预期资料里没有提到……而不是模型自己编一段第二个输出比第一个更重要——它验证了知识边界生效这正是 RAG 相比裸模型的全部意义。四、接你的真实文档10 行改造迷你版到真实版就差一个读文件 切分import re def load_chunks(path: str, size: int 300) - list: 读文本文件按段落粗切成 ~size 字的块 text open(path, encodingutf-8).read() paras [p.strip() for p in re.split(r\n\s*\n, text) if p.strip()] chunks, buf [], for p in paras: # 小段合并、大段切开 if len(buf) len(p) size: buf \n p else: chunks.append(buf.strip()); buf p chunks.append(buf.strip()) return [c for c in chunks if len(c) 20] docs load_chunks(你的文档.md) # 替换这里 doc_vecs model.encode(docs, normalize_embeddingsTrue) # 重建索引之后retrieve/answer一行都不用改。这就是分层的红利换数据不动逻辑。千万文档块也别慌1 万块 × 512 维的矩阵乘法在笔记本上也就百毫秒级。真正的瓶颈在每次都重算全部文档向量——所以工业界把doc_vecs存起来这就叫向量库第 03 篇。五、踩坑实录跟做时最容易翻的 4 个坑坑 1模型下载 403/超时症状Connection error卡住。解法export HF_ENDPOINThttps://hf-mirror.com后重跑。坑 2检索结果驴唇不对马嘴症状retrieve第一条永远不对。十有八九是normalize_embeddingsTrue漏了点积冒充了余弦相似度。加上它。坑 3回答是模型自己编的跟文档无关症状问资料外的问题模型对答如流。解法检查 system prompt 的仅根据资料回答没有就说不知道是不是被你精简掉了。这句是防幻觉底线。坑 4中文模型却全是英文文档或反之症状英文文档用bge-small-zh检索质量暴跌。嵌入模型有语言域——中英混合场景换BAAI/bge-m3多语言稍大。这四个坑只是开胃菜。检索效果差的真实原因有 5 大类chunk 边界、中间衰减、嵌入换版……下一篇逐个拆。六、完整代码复制即跑mini_rag.py — 50 行跑通 RAG 文档问答 依赖: pip install sentence-transformers openai import re import numpy as np from sentence_transformers import SentenceTransformer from openai import OpenAI # ── ① 文档块换成 load_chunks(你的文档.md) 即接真实数据── docs [ RAG 是检索增强生成的缩写通过检索外部知识来增强大模型的回答。, RAG 系统的核心组件包括文档切分、向量化、向量存储、检索和生成。, RAG 相比微调的优势成本低、知识可随时更新、不遗忘通用能力。, chunk 是 RAG 中的最小检索单元通常包含 256-512 个 token。, 余弦相似度是 RAG 中最常用的向量相似度度量方法。, ] # ── ② 嵌入模型本地免费 ③ 建索引 ── model SentenceTransformer(BAAI/bge-small-zh-v1.5) doc_vecs model.encode(docs, normalize_embeddingsTrue) # ── ④ 检索 ── def retrieve(query: str, top_k: int 2) - list: q_vec model.encode([query], normalize_embeddingsTrue) scores q_vec doc_vecs.T top_idx scores[0].argsort()[::-1][:top_k] return [docs[i] for i in top_idx] # ── ⑤ 生成 ── client OpenAI(api_keysk-替换成你的, base_urlhttps://api.deepseek.com) def answer(question: str) - str: context \n.join(f[{i1}] {c} for i, c in enumerate(retrieve(question))) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: f仅根据以下资料回答资料里没有就明确说不知道。\n{context}}, {role: user, content: question}, ], ) return resp.choices[0].message.content # ── 接真实文档的切分器可选── def load_chunks(path: str, size: int 300) - list: text open(path, encodingutf-8).read() paras [p.strip() for p in re.split(r\n\s*\n, text) if p.strip()] chunks, buf [], for p in paras: if len(buf) len(p) size: buf \n p else: chunks.append(buf.strip()); buf p chunks.append(buf.strip()) return [c for c in chunks if len(c) 20] if __name__ __main__: print(answer(RAG 的核心组件有哪些))收尾50 行代码里藏着的其实是 RAG 的世界观模型不必什么都知道——它只需要在回答的那一刻拿到对的那几页资料。迷你版的边界也很清楚没有重排、没有混合检索、没有评估、向量重算是全量的。这些工业化的部分正是接下来三篇的内容学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
返回列表