Skip to content
AI中级阅读约 1 分钟

运维知识库与 RAG ​

本篇定位

解决"大模型不知道你家私有文档、还一本正经瞎编"的问题:用 RAG(检索增强生成)把你的 VitePress 知识库、Runbook、故障记录先检索出来再喂给模型,让它有据可依地回答。含把本仓库 docs/**/*.md 全量入库、问答的完整可跑代码。 本篇版本:Chroma chromadb 1.5.9、Milvus 2.6.21(生产稳定,3.0.0 已 GA)、Qdrant 1.18.0、pgvector 0.8.2、Embedding 模型 BAAI/bge-m3 与 bge-large-zh-v1.5。所有版本以官网当前稳定版为准。

一、为什么需要 RAG ​

1.1 小白类比:开卷考试 vs 闭卷瞎编 ​

直接问大模型"我们公司 K8s 生产环境的 Pod 安全策略是什么",它不知道你公司的内部文档,就会闭卷瞎编一个看起来很合理的答案——这就是"幻觉"。

RAG = 开卷考试:考试前,先把相关的那几页资料翻出来摆在桌上,让它看着资料作答,并且能告诉你"我是根据第几页说的"。

1.2 三个非 RAG 不可的理由 ​

痛点RAG 怎么解
幻觉(模型编造)答案必须基于检索到的真实文档,模型只做"组织语言"
私有知识(内部 Runbook/拓扑/配置)这些没进公开模型训练,只能靠检索喂进去
知识过时模型训练有截止日期;RAG 直接读你最新的文档文件,随时可更新

二、文档加载与切分 ​

2.1 为什么要切分 ​

整篇文档几百 KB,既塞不进上下文,向量检索也分不清"哪段相关"。所以要把文档切成小块(chunk),每块单独向量化。

2.2 chunk 大小与 overlap 经验值 ​

参数经验值说明
chunk_size(每块多少 token)中文 300~800 token太小:上下文不完整;太大:检索不精准、浪费窗口
chunk_overlap(相邻块重叠)chunk_size 的 10%~20%避免一句话从中间被切断,导致两边都不完整
切分边界尽量按标题/段落/代码块切别在一个命令中间硬切

类比:切西瓜。块太大,一口啃不动(检索不精准);块太小,没味(上下文不全)。留 overlap 是为了"接缝处也有完整内容"。

三、Embedding 与向量库 ​

3.1 Embedding 是什么 ​

Embedding 模型把一段文字变成一串数字(向量),语义相近的句子向量距离也近。这样"nginx 502 怎么办"和"502 Bad Gateway 排查"虽然字面不同,向量却很接近——这就是语义检索的原理。

Embedding 模型维度最大长度语言说明
BAAI/bge-m310248192 token多语言(中英都强)推荐主力,568M 参数,支持稠密+稀疏+多向量
BAAI/bge-large-zh-v1.51024512 token中文纯中文场景经典稳
BAAI/bge-large-en-v1.51024512 token英文英文文档用

3.2 向量库选型对比 ​

对比ChromaQdrantMilvuspgvector
定位上手最快、嵌入式生产级、Rust、过滤强大规模、分布式直接在 PostgreSQL 里加向量列
部署pip install 即用Docker / 单机集群较重,分布式现有 PG 里 CREATE EXTENSION
适合规模原型、个人、<百万中小到生产、千万级海量、亿级已有 PG、量不大、想省一个组件
过滤/元数据基础强(payload 过滤)强借 SQL 过滤,灵活
推荐版本chromadb 1.5.91.18.02.6.21(3.0.0 GA)pgvector 0.8.2

个人知识库/本网站:Chroma 起步最省事;想上生产、要过滤和高可用:Qdrant;已经重度用 PostgreSQL、不想多维护一个数据库:pgvector。

四、检索策略 ​

策略怎么工作优缺点
纯向量检索语义相似度找 top-k语义好,但精确名词(指标名、报错码、命令)容易漏
纯关键词(BM25)传统倒排,按词频精确匹配强,但不懂"意思相近"
混合检索(Hybrid)向量 + BM25 结果融合(RRF 排序)推荐:既懂语义又认精确名词
重排 Rerank检索出 top-20,再用 rerank 模型精排取 top-3显著提升相关性,BGE 自带 bge-reranker

五、实战:把本 VitePress 知识库接入 LLM ​

目标:读取本仓库 docs/guide/**/*.md、docs/reference/**/*.md,切分 → BGE 向量化 → 存进 Chroma → 问它问题能命中本站文章。

5.1 安装依赖(版本写死) ​

bash
python3 -m venv .venv && source .venv/bin/activate
pip install "chromadb==1.5.9"
pip install "sentence-transformers==5.1.0"
pip install "openai==1.68.2"   # 用来调你本地的 Ollama/vLLM

5.2 建库脚本 build_kb.py ​

python
# build_kb.py —— 扫描 docs 目录,切分、向量化、写入 Chroma
import glob, os, re
import chromadb
from sentence_transformers import SentenceTransformer

DOCS_ROOT = "/home/user/Doubao/chats/38440928658888706/static-blog/docs"
COLLECTION = "ops_kb"

# 1) 加载本地 Embedding 模型(BGE-M3,首次会自动下载约 2.2GB)
embedder = SentenceTransformer("BAAI/bge-m3")

def split_text(text, chunk_tokens=500, overlap=80):
    """极简按字符切分(中文约1.5字/token 的粗算),带重叠。生产可换 LangChain 文本切分器。"""
    text = re.sub(r"\n{3,}", "\n\n", text)
    step = int(chunk_tokens * 1.5)
    ov = int(overlap * 1.5)
    chunks = []
    for i in range(0, len(text), step - ov):
        piece = text[i:i + step]
        if piece.strip():
            chunks.append(piece)
    return chunks

# 2) 连接 Chroma(本地持久化到 ./chroma_db)
client = chromadb.PersistentClient(path="./chroma_db")
# 重建前先删旧集合,保证和文档同步
try:
    client.delete_collection(COLLECTION)
except Exception:
    pass
col = client.create_collection(COLLECTION, metadata={"hnsw:space": "cosine"})

# 3) 扫描所有 md 文件,切分、入库
files = glob.glob(os.path.join(DOCS_ROOT, "**", "*.md"), recursive=True)
ids, docs, metas = [], [], []
for fpath in files:
    rel = os.path.relpath(fpath, DOCS_ROOT)
    with open(fpath, encoding="utf-8") as f:
        content = f.read()
    for idx, chunk in enumerate(split_text(content)):
        ids.append(f"{rel}#{idx}")
        docs.append(chunk)
        metas.append({"source": rel, "chunk": idx})

# 4) 批量向量化(embeddings 自己算,直接 add 文本让 Chroma 存也行;这里显式算)
emb = embedder.encode(docs, normalize_embeddings=True).tolist()
col.add(ids=ids, documents=docs, embeddings=emb, metadatas=metas)
print(f"入库完成:{len(files)} 个文件,{len(docs)} 个 chunk")

跑一下:

bash
python build_kb.py
# 入库完成:87 个文件,1234 个 chunk

5.3 问答脚本 ask.py ​

python
# ask.py —— 检索知识库 + 调本地 LLM 生成带出处的回答
import chromadb
from sentence_transformers import SentenceTransformer
from openai import OpenAI

embedder = SentenceTransformer("BAAI/bge-m3")
client = chromadb.PersistentClient(path="./chroma_db")
col = client.get_collection("ops_kb")

# 接本地 Ollama(OpenAI 兼容接口,见《大模型部署》)
llm = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="ollama")

def ask(question: str, k: int = 3):
    q_emb = embedder.encode([question], normalize_embeddings=True).tolist()
    res = col.query(query_embeddings=q_emb, n_results=k)
    ctx = "\n\n---\n".join(
        f"[来自 {m['source']}]\n{d}"
        for d, m in zip(res["documents"][0], res["metadatas"][0])
    )
    prompt = f"""你是运维知识库助手。只根据下面提供的资料回答,资料里没有就说"知识库中未找到",不要编造。

参考资料:
{ctx}

用户问题:{question}
"""
    resp = llm.chat.completions.create(
        model="qwen3:8b",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.2,
    )
    print(resp.choices[0].message.content)
    print("\n引用来源:", [m["source"] for m in res["metadatas"][0]])

if __name__ == "__main__":
    ask("K8s 里 pod 一直处于 CrashLoopBackOff 一般怎么排查?")
bash
python ask.py

六、本地 / 私有化方案 ​

不想把内网文档发到公网 API?全栈本地:

组件本地方案命令
EmbeddingOllama 拉本地 embedding 模型,或 sentence-transformers 跑 bge-m3ollama pull bge-m3
向量库Chroma 本地持久化(上面就是)无需额外服务
LLMOllama 跑 Qwen3,OpenAI 兼容接口ollama pull qwen3:8b
bash
# 一键把整条链路跑在本机,数据不出内网
ollama pull bge-m3 && ollama pull qwen3:8b
ollama serve        # 默认 127.0.0.1:11434,提供 /v1/embeddings 和 /v1/chat/completions
python build_kb.py  # 建库(把 embedder 换成调 Ollama embeddings 接口即可)
python ask.py

七、效果评估与常见坑 ​

坑现象解法
chunk 切太大/太小检索不相关或上下文不全中文 300~800 token,overlap 10~20%,按标题/代码块边界切
只做向量检索查指标名、报错码查不到上混合检索(向量+BM25)
没做 reranktop-k 里混着不相关内容加 bge-reranker 精排
文档更新了库没更新问到旧答案重新跑 build_kb.py(本示例先删集合再全量重建)
Embedding 和查询用了不同模型向量对不上,检索全乱入库和查询必须用同一个 embedding 模型
喂太多无关片段LLM 被噪声带偏top-k 别贪多(3~5 段),加 rerank

八、常见问题排错 ​

现象原因解决
ConnectionError 连不上 embedding 模型模型没下下来/没网国内设 export HF_ENDPOINT=https://hf-mirror.com 再下载
Chroma 报维度不匹配换了 embedding 模型但库是旧向量删掉 ./chroma_db 用新模型重建
回答还是瞎编没在 Prompt 里强约束"只根据资料"Prompt 加"资料没有就说没找到,禁止编造"
检索结果全是无关页面chunk 太大 / 元数据没带上调小 chunk;打印检索文档人工看一眼相关性
首次加载 bge-m3 很慢在下载 2.2GB 模型耐心等,或用更小的 bge-base-zh-v1.5

生产红线

  • 向量库和 LLM 服务不要裸露公网:知识库可能含内网拓扑、IP、敏感配置。
  • 版本写死:chromadb==1.5.9、embedding 模型锁定具体版本,升级 embedding 模型必须全量重建向量库。
  • 入库前过滤敏感信息:密钥、密码、内网地址不该被 embedding 后随便检索出来。
  • 私有化场景优先本地模型(Ollama),别把内网文档发到公网大模型 API。

相关速查 ​

官方文档 ​