
手寫一個迷你 RAG50 行代碼跑通文檔問答系列RAG 實戰(zhàn)系列 第01篇上一篇MCP vs A2A vs ACP2026 年 Agent 協(xié)議選型指南協(xié)議層系列完結預計閱讀12 分鐘讀完你能得到一個能跑、能改、能接你真實文檔的迷你 RAG——完整 50 行代碼在文末可直接復制引子每個想做 RAG 的人都死在第一周一位讀者的原話私信“想讓公司內部文檔能問答。搜了三天教程LangChain 版本對不上、LlamaIndex 文檔看不懂、還得先裝 Docker 起個 Milvus……我到現在一行代碼都沒跑起來?!边@是 RAG 落地最真實的死法——不是死于技術難是死于框架太重。RAG 的本質其實非常簡單把你的文檔切成小塊 → 變成向量 → 用戶提問時找到最相關的幾塊 → 塞進 prompt 讓大模型回答。就這么四步。什么 LangChain、向量數據庫、Docker都是這四步的工業(yè)化包裝。包裝有價值但你不應該先學包裝再學本質。這篇用 50 行純 Python 跑通上面四步——不用 LangChain不用向量數據庫不用 Docker。跑通之后你會對后面三篇踩坑實錄、向量庫選型、Rerank里的每個概念都有體感。一、環(huán)境準備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 → 創(chuàng)建 → 復制形如sk-xxxx第一次跑SentenceTransformer時會下載模型文件約 100MB一次性。國內網絡慢的話設置鏡像export HF_ENDPOINThttps://hf-mirror.com環(huán)境就緒。下面進入正題——先看全景再逐塊拆。二、全景50 行代碼長什么樣先上完整結構細節(jié)下節(jié)拆。整個 RAG 就三個函數 一段準備# ── 準備文檔 嵌入模型 ────────────────── docs [...] # ① 你的文檔切成塊后的 model SentenceTransformer(...) # ② 嵌入模型本地 doc_vecs model.encode(docs) # ③ 全部向量化建索引 # ── 檢索函數 ────────────────────────────── def retrieve(query, top_k): # ④ 問題向量化 → 余弦相似度 → 排序取前K # ── 生成函數 ────────────────────────────── def answer(question): # ⑤ 檢索 → 拼上下文 → 調大模型沒有向量數據庫。因為 5 條文檔的向量檢索就是一個矩陣乘法——numpy一行搞定。向量數據庫解決的是百萬級向量的檢索性能你先用不到等用到時再看第 03 篇。對照上圖這 50 行覆蓋了管道的核心三層切分→向量化→檢索→生成。工業(yè)級管道里剩下的層清洗、重排、評估是后面三篇的主角。三、逐塊拆解每一行為什么這么寫3.1 文檔塊chunk 是什么docs [ RAG 是檢索增強生成的縮寫通過檢索外部知識來增強大模型的回答。, RAG 系統(tǒng)的核心組件包括文檔切分、向量化、向量存儲、檢索和生成。, RAG 相比微調的優(yōu)勢成本低、知識可隨時更新、不遺忘通用能力。, 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 維。選它是中文 免費 快三個條件的最優(yōu)解?****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 有什么優(yōu)點)) # 期望輸出第一條是「RAG 相比微調的優(yōu)勢成本低、知識可隨時更新……」如果你的第一條不是它先檢查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三個細節(jié)決定回答質量1.****system prompt 里那句資料里沒有就明確說不知道——防幻覺的最低成本手段。沒有它模型會用自己的參數知識補答案跟你的文檔沒關系**2.**帶[1] [2]編號——后續(xù)要求模型引用編號就得到最樸素的引用溯源**3.**只塞 top_k 個塊不塞全部——上下文不是越多越好第 02 篇講中間衰減時會展開3.5 跑起來if __name__ __main__: print(answer(RAG 的核心組件有哪些))預期輸出根據資料 [2]RAG 系統(tǒng)的核心組件包括文檔切分、向量化、向量存儲、檢索和生成。問一個資料里沒有的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 維的矩陣乘法在筆記本上也就百毫秒級。真正的瓶頸在每次都重算全部文檔向量——所以工業(yè)界把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 系統(tǒng)的核心組件包括文檔切分、向量化、向量存儲、檢索和生成。, RAG 相比微調的優(yōu)勢成本低、知識可隨時更新、不遺忘通用能力。, 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 的世界觀模型不必什么都知道——它只需要在回答的那一刻拿到對的那幾頁資料。迷你版的邊界也很清楚沒有重排、沒有混合檢索、沒有評估、向量重算是全量的。這些工業(yè)化的部分正是接下來三篇的內容學AI大模型的正確順序千萬不要搞錯了2026年AI風口已來各行各業(yè)的AI滲透肉眼可見超多公司要么轉型做AI相關產品要么高薪挖AI技術人才機遇直接擺在眼前有往AI方向發(fā)展或者本身有后端編程基礎的朋友直接沖AI大模型應用開發(fā)轉崗超合適就算暫時不打算轉崗了解大模型、RAG、Prompt、Agent這些熱門概念能上手做簡單項目也絕對是求職加分王給大家整理了超全最新的AI大模型應用開發(fā)學習清單和資料手把手幫你快速入門學習路線:?大模型基礎認知—大模型核心原理、發(fā)展歷程、主流模型GPT、文心一言等特點解析?核心技術模塊—RAG檢索增強生成、Prompt工程實戰(zhàn)、Agent智能體開發(fā)邏輯?開發(fā)基礎能力—Python進階、API接口調用、大模型開發(fā)框架LangChain等實操?應用場景開發(fā)—智能問答系統(tǒng)、企業(yè)知識庫、AIGC內容生成工具、行業(yè)定制化大模型應用?項目落地流程—需求拆解、技術選型、模型調優(yōu)、測試上線、運維迭代?面試求職沖刺—崗位JD解析、簡歷AI項目包裝、高頻面試題匯總、模擬面經以上6大模塊看似清晰好上手實則每個部分都有扎實的核心內容需要吃透我把大模型的學習全流程已經整理好了抓住AI時代風口輕松解鎖職業(yè)新可能希望大家都能把握機遇實現薪資/職業(yè)躍遷這份完整版的大模型 AI 學習資料已經上傳CSDN朋友們如果需要可以微信掃描下方CSDN官方認證二維碼免費領取【保證100%免費】