本节摘要:RAG 的本质是"先查资料再回答"——把私有文档切块、向量化、按问题检索出最相关的几段,连同问题一起交给模型。本节用 Ollama 加不到一百行 Python 实现一个完整可用的管线,并讨论切块粒度、检索质量评测、与微调的取舍这三个决定成败的工程问题。
本地 7B 模型的参数化知识既过时也不含你的私有数据。把公司规范塞进提示词的路子在 3.2 节已见其上限:上下文窗口有限、成本随对话增长、检索精度差。RAG 换了个思路——知识不进参数也不进系统提示词,而是放在外部的向量库里,每次提问只取最相关的片段动态拼进 prompt。模型的角色从"知识载体"变成"阅读理解与综合表达器",7B 模型也足以胜任。
完整管线五步:加载文档 → 切块 → 嵌入向量化 → 存入向量库 → 查询时检索 top-k 拼上下文生成。下面全部落地。
pip install chromadb ollama pull nomic-embed-text # 嵌入模型 ollama pull qwen2.5:7b # 生成模型
import chromadb import ollama client = chromadb.PersistentClient(path="./rag_store") col = client.get_or_create_collection("docs") def add_docs(paths): for p in paths: text = open(p, encoding="utf-8").read() # 按 500 字滑窗切块,相邻块重叠 80 字,避免句子被拦腰截断 chunks, step = [], 580 for i in range(0, len(text), step - 80): chunk = text[i:i + step].strip() if chunk: chunks.append(chunk) embs = ollama.embed(model="nomic-embed-text", input=chunks)["embeddings"] col.add(ids=[f"{p}-{i}" for i in range(len(chunks))], embeddings=embs, documents=chunks, metadatas=[{"src": p}] * len(chunks)) def ask(question, k=4): qe = ollama.embed(model="nomic-embed-text", input=[question])["embeddings"] hits = col.query(query_embeddings=qe, n_results=k)["documents"][0] context = "\n\n".join(f"[片段{i+1}] {h}" for i, h in enumerate(hits)) out = ollama.chat(model="qwen2.5:7b", options={"temperature": 0.2}, messages=[ {"role": "system", "content": "仅依据给出的资料片段回答;资料没有的信息就回答'资料中未提及',禁止编造。"}, {"role": "user", "content": f"资料:\n{context}\n\n问题:{question}"}, ]) return out["message"]["content"] if __name__ == "__main__": add_docs(["handbook.md", "faq.md"]) print(ask("请假超过三天的审批流程是什么?"))
这段代码具备生产管线的全部骨架:持久化存储、滑窗切块、top-k 检索、防幻觉系统提示词。可以直接当作内部工具的起点。
切块粒度。 块太大,检索出的片段夹带大量无关内容稀释注意力;块太小,语义被切碎检索不准。经验起点是 300-600 字符、10%-15% 重叠。文档有结构(标题、条款号)时按结构切块显著优于定长滑窗——Markdown 按 ## 切,法律文档按"条"切,表格整块保留不切。
检索质量才是天花板。 生成模型再好,检不出对的片段就全是空谈。两个低成本提升:查询改写(让模型先把口语问题改写成适合检索的陈述句)与混合检索(向量检索之外叠加关键词匹配,专业术语、型号、人名这类精确词 BM25 往往比向量更准)。评测方法是自建一组"问题-出处"测试对,只跑检索看命中率,先修检索再调生成。
引用与可追溯。 生产系统务必让答案标注出处片段编号,并让系统提示词明确"只依据片段"。用户对内部知识库的信任建立在"每句话能点回原文"上,这比答案文采重要得多。
知识注入选 RAG 还是 LoRA 微调?判据:知识更新频率高、需要引用出处、数据量在文档级别——选 RAG,改了文档重建索引即可生效。要求改变风格/格式/领域话术而非注入事实——微调更合适,且 3.2 节的 ADAPTER 机制允许把 LoRA 产物直接挂进 Ollama。两者也可叠用:微调管"怎么说话",RAG 管"说什么"。本地场景下,先做 RAG 几乎总是对的——成本一个数量级的差距。
落地时的迭代顺序也别颠倒:先拿五十个真实问题做检索命中率测试,把切块与嵌入参数调到满意;再调生成的系统提示词(引用格式、拒答口径);最后才考虑重排序、查询改写这些进阶组件。多数团队在检索还没调准时就急着换更大的模型,方向反了——生成模型读到的片段不对,再大的模型也只能将错就错。
下一步把"回答问题"升级为"完成任务":让模型自己决定调用什么工具、循环执行直到目标达成——Agent 与工作流构建。