知识库 RAG 实现详解:从 Milvus 入库到 deepagents Skill
本文基于 mystu 项目中的 rag-pack,说明「组织知识库 RAG」的完整搭建过程、检索链路、Skill 如何被大模型发现与使用、如何封装为可复用 pack,以及在其他 Agent 项目中如何接入。
适用读者:需要在 deepagents / LangGraph Agent 上落地 Milvus 向量检索,且希望工作流可拷贝复用的开发者。
结构化问数(SQL)请参见 智能问数实现详解。
一、什么是「组织知识库 RAG」
组织知识库 RAG 指:用户用自然语言提问(如「最近周报对 PB 粉港口库存怎么看?」),由 LLM 驱动的 Agent 自动完成:
- 识别这是需要引用内部文档、政策原文、周报观点的非结构化问题;
- 调用
search_knowledge_base做向量检索; - 从 Milvus(或内存降级存储)取回相关文本片段;
- 综合片段内容生成带标题、来源、doc_type 的自然语言回答。
技术链路:用户问句 → Embedding 向量化 → Milvus 相似度检索 + 部门过滤 → LLM 解读 hits。
对话 LLM 不参与入库;入库阶段只用 Embedding 模型做向量化(当前未做 LLM 摘要/改写)。
与智能问数的边界:
| 问题类型 | 应走哪条通道 |
|---|---|
| 政策怎么说、周报观点、新闻背景 | 本 Skill + RAG |
| 库存多少、环比、发运量等具体数字 | structured-query Skill + SQL |
二、整体架构
三层分工:
| 层级 | 职责 | 代码/文件位置 |
|---|---|---|
| Skill(工作流) | 告诉 LLM「何时用 RAG、何时转 SQL、如何引用片段」 | rag-pack/skills/knowledge-retrieval/SKILL.md |
| Toolkit(能力) | search_knowledge_base + Milvus/内存存储 + 入库管线 |
rag-pack/rag_pack/ |
| Host 接入(装配) | CompositeBackend、工具注入、Admin 入库 API、部门上下文 | mystu 的 deepagent.py、knowledge_admin_api.py |
三、大模型如何发现并使用 Skill(含 iron-ore.md 说明)
与智能问数 Skill 相同机制,理解这一点是正确使用 RAG 的关键。
3.1 SkillsMiddleware:只扫描 SKILL.md 的 frontmatter
Agent 配置了 skills=["/skills/"] 后,SkillsMiddleware 在会话开始时:
- 通过
CompositeBackend列出/skills/下子目录(mystu 同时有structured-query/与knowledge-retrieval/); - 仅读取 每个目录里的
SKILL.md; - 解析 YAML frontmatter(
name、description、allowed-tools); - 把 skill 摘要追加到系统提示词,例如:
- **knowledge-retrieval**: 铁矿石组织知识库检索:使用 search_knowledge_base 检索周报、政策、新闻...
-> Allowed tools: search_knowledge_base
-> Read `/skills/knowledge-retrieval/SKILL.md` for full instructions
这叫做 渐进式披露(Progressive Disclosure):大模型先看到「有哪些 skill、干什么用」,不会在启动时把 SKILL.md 全文塞进上下文。
3.2 大模型何时读 SKILL.md 全文
deepagents 在系统提示词中指示大模型:
- 判断用户问题是否匹配某个 skill 的
description(如政策解读、周报观点 →knowledge-retrieval); - 需要时调用内置
read_file,路径为/skills/knowledge-retrieval/SKILL.md; - 按 SKILL.md 中的工作流调用
search_knowledge_base。
3.3 iron-ore.md 不会自动加载
路径:
/skills/knowledge-retrieval/references/iron-ore.md
磁盘对应:
rag-pack/skills/knowledge-retrieval/references/iron-ore.md
重要事实:
| 文件 | 是否自动进上下文 | 说明 |
|---|---|---|
SKILL.md frontmatter 摘要 |
是 | SkillsMiddleware 启动时注入 |
SKILL.md 全文 |
否 | 大模型按需 read_file |
references/iron-ore.md |
否 | SkillsMiddleware 不扫描 references/ |
iron-ore.md 是 mystu 的领域 overlay,内容包括 doc_type 口径、典型问句、与 structured-query 的双通道分工。运行时不会自动推送给大模型。
3.4 mystu 中铁矿石领域知识实际从哪来
| 来源 | 注入方式 | 内容 |
|---|---|---|
configure.py --preset iron-ore |
渲染进 SKILL.md 正文 |
示例问句、doc_type、检索 query 示例 |
| 系统提示词 | 每条消息始终可见 | 双通道规则(见 iron_ore_forecast.md) |
iron-ore.md |
不自动 | 可选;需 LLM 主动 read_file 或显式引导 |
MILVUS_COLLECTION=iron_ore_knowledge |
环境变量 | 决定连哪个 collection,不进 prompt |
3.5 若希望大模型「必定使用」iron-ore.md
在 SKILL.md 的「领域补充」一节增加显式指令,例如:
## 领域补充
执行检索前,请先阅读:
`/skills/knowledge-retrieval/references/iron-ore.md`
其中包含 doc_type 口径、典型问句与结构化查数分工。
四、RAG 搭建过程:从 0 到可检索
4.1 第一步:拷贝并安装 rag-pack
将整个 rag-pack/ 复制到项目仓库根目录:
pip install -e ./rag-pack
# 或 uv sync(mystu 已在 pyproject.toml 中声明 editable 依赖)
4.2 第二步:配置 Milvus 与 Embedding
.env 示例(mystu 生产/开发):
# Milvus / Zilliz
MILVUS_URI=https://your-cluster.zillizcloud.com:19530
MILVUS_TOKEN=your-api-key
MILVUS_DB_NAME=default
MILVUS_COLLECTION=iron_ore_knowledge
# Embedding(二选一)
EMBEDDING_PROVIDER=local
EMBEDDING_MODEL=BAAI/bge-m3
EMBEDDING_DEVICE=cpu
EMBEDDING_DIMENSIONS=1024
# 或使用百炼
# EMBEDDING_PROVIDER=dashscope
# DASHSCOPE_API_KEY=sk-...
# EMBEDDING_BASE_URL=https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
# EMBEDDING_MODEL=text-embedding-v4
# 分块
RAG_CHUNK_SIZE=512
RAG_CHUNK_OVERLAP=64
| 变量 | 说明 |
|---|---|
MILVUS_URI |
未配置 → 使用 InMemoryKnowledgeStore(重启丢失,适合本地调试) |
MILVUS_COLLECTION |
pack 默认 knowledge_base;mystu 用 iron_ore_knowledge |
EMBEDDING_USE_FAKE |
测试用 true,不加载真实模型 |
原则:入库与检索必须使用同一套 Embedding 配置,否则 query 向量与 document 向量不在同一语义空间。
4.3 第三步:渲染 Skill
# 通用项目
python rag-pack/configure.py
# mystu 铁矿石预设
python rag-pack/configure.py --preset iron-ore
确认 skills/knowledge-retrieval/SKILL.md 中无残留 {{...}} 占位符。
4.4 第四步:准备文档并入库
入库管线(pack 内 rag_pack/ingest/):
原始文件/文本 → parsers(PDF/DOCX/HTML/txt/md)→ chunker(固定窗口分块)→ Embedding → Milvus upsert
mystu 入库入口(需 admin 登录且完成改密):
| API | 用途 |
|---|---|
POST /admin/api/knowledge/ingest/batch |
批量上传 PDF/DOCX/HTML 等 |
POST /admin/api/knowledge/ingest/article |
单篇 policy/news 文本入库 |
表单/请求体关键字段:
| 字段 | 说明 |
|---|---|
doc_type |
weekly_report / policy / news |
visibility_tags |
JSON 数组,如 ["all"] 或 ["research","sales"] |
published_at |
可选 Unix 时间戳 |
测试环境也可直接调用 Python API:
from rag_pack.ingest.pipeline import ingest_text_document
from rag_pack.store import get_knowledge_store
await ingest_text_document(
doc_type="weekly_report",
title="2026-W25 铁矿石周报",
source="internal/weekly/2026-w25.html",
text="PB粉港口库存延续累库,需求端...",
visibility_tags=["all"],
store=get_knowledge_store(),
)
4.5 第五步:接入 Agent
mystu 参考实现(与 structured-query 双 skill 并存):
# mystu/buildagent/agent/deepagent.py(节选)
from mystu.buildagent.agent.agent_skills import SKILLS_VIRTUAL_PREFIX, build_agent_skills_backend
from mystu.buildagent.agent.knowledge_tools import search_knowledge_base
from mystu.buildagent.agent.sql_toolkit import get_sql_toolkit_tools
def _build_knowledge_tools(model):
return [search_knowledge_base, *get_sql_toolkit_tools(model)]
return create_deep_agent(
model=model,
tools=[*other_tools, *_build_knowledge_tools(model)],
system_prompt=load_iron_ore_forecast_prompt(),
backend=build_agent_skills_backend(), # 挂载两个 skill 子目录
skills=[SKILLS_VIRTUAL_PREFIX],
)
agent_skills.py 为每个 skill 单独挂载路由:
SKILL_MOUNT_POINTS = {
"structured-query": SQL_SKILLS_ROOT / "structured-query",
"knowledge-retrieval": RAG_SKILLS_ROOT / "knowledge-retrieval",
}
4.6 第六步:启动与验证
Web 服务 lifespan 会调用 init_knowledge_store():Milvus ping 失败则降级内存存储,不阻断启动。
验收清单见 rag-pack/CHECKLIST.md,至少确认:
- 启动后日志有 Milvus 连接成功,或明确的内存降级提示;
- 入库后
search_knowledge_base能返回 hits; - SkillsMiddleware 摘要中出现
knowledge-retrieval; - 对话中能按 skill 工作流完成检索并引用来源。
五、一次完整检索的执行逻辑
以用户问题「最近周报对 PB 粉港口库存怎么看?」为例。
5.1 阶段 0:Agent 启动时装配
init_knowledge_store()连接 Milvus(或降级内存);get_knowledge_retrieval_tools()注入search_knowledge_base;build_agent_skills_backend()挂载/skills/knowledge-retrieval/;skills=["/skills/"]启用 SkillsMiddleware。
5.2 阶段 1:匹配 skill 并读取工作流
大模型根据摘要判断:问题核心是文档观点而非具体数字 → 匹配 knowledge-retrieval → read_file 读取 SKILL.md。
若用户问的是「青岛港 PB 粉最新库存多少」,Skill 正文要求转 structured-query,不应强行 RAG。
5.3 阶段 2:调用 search_knowledge_base
| 参数 | 示例值 | 说明 |
|---|---|---|
query |
"PB粉 港口库存 周报" |
检索问句 |
doc_type |
"weekly_report" |
可选过滤 |
top_k |
5 |
返回片段数 |
工具内部(rag_pack/knowledge_tools.py):
- 从
runtime.context读取department(mystu 注入AgentContext); - 调用
get_knowledge_store().search(...); - 返回 JSON:
{ "hits": [...], "count": N }。
5.4 阶段 3:Milvus 检索与部门过滤
rag_pack/store.py 中 MilvusKnowledgeStore.search():
- 用 Embedding 对
query做embed_query; similarity_search_with_score,附带 Milvus 表达式过滤:visibility_tags含"all"或当前用户department;- 可选
doc_type == "weekly_report";
- 返回
SearchHit列表(text、title、source、doc_type、published_at、score)。
5.5 阶段 4:生成最终回答
LLM 综合 hits[].text,回答时:
- 注明 title、source、doc_type;
count: 0时明确「知识库中暂无相关资料」,勿编造;- 勿把片段里出现的数字当作权威指标(数字类问题应走 SQL 查数)。
六、工具层与 pack 实现细节(rag_pack)
pack 目录结构:
rag-pack/
├── rag_pack/ # Python 包
│ ├── config.py # MILVUS_* / EMBEDDING_* / RAG_CHUNK_*
│ ├── embedding.py # local / dashscope / FakeEmbeddings
│ ├── store.py # MilvusKnowledgeStore + InMemoryKnowledgeStore
│ ├── models.py # DocumentChunk、SearchHit 等
│ ├── knowledge_tools.py # search_knowledge_base + get_knowledge_retrieval_tools
│ └── ingest/
│ ├── parsers.py # PDF / DOCX / HTML / txt
│ ├── chunker.py # 固定窗口分块
│ └── pipeline.py # 解析 → 分块 → upsert
├── skills/
│ └── knowledge-retrieval/
│ ├── SKILL.md.template
│ ├── SKILL.md # configure 渲染产物
│ └── references/
│ ├── README.md
│ └── iron-ore.md # mystu overlay(不自动加载)
├── configure.py
├── INSTALL.md
├── CHECKLIST.md
└── wiring/deepagent_example.py
6.1 配置加载(config.py)
| 环境变量 | 说明 |
|---|---|
MILVUS_URI |
Milvus 连接 URI;未设 → 内存存储 |
MILVUS_TOKEN |
Zilliz Cloud API Key |
MILVUS_COLLECTION |
Collection 名,默认 knowledge_base |
EMBEDDING_PROVIDER |
local(默认)或 dashscope |
EMBEDDING_MODEL |
local: BAAI/bge-m3;dashscope: text-embedding-v4 |
RAG_CHUNK_SIZE / RAG_CHUNK_OVERLAP |
默认 512 / 64 |
6.2 存储层(store.py)
| 实现 | 场景 |
|---|---|
MilvusKnowledgeStore |
配置了 MILVUS_URI 且 ping 成功 |
InMemoryKnowledgeStore |
未配置 Milvus,或连接失败降级 |
Milvus metadata 字段:doc_id、doc_type、title、source、chunk_index、visibility_tags(ARRAY)、published_at。
同一 doc_id 再次入库会先 delete 再 upsert(覆盖更新)。
6.3 检索工具(knowledge_tools.py)
get_knowledge_retrieval_tools() 支持 host 注入:
get_knowledge_retrieval_tools(
get_department=lambda ctx: ctx.department,
get_user_id=lambda ctx: ctx.user_id,
doc_type_hint="weekly_report、policy、news",
)
mystu 在 knowledge_tools.py 中绑定 AgentContext。
6.4 与 mystu 的集成方式
mystu 通过 editable 依赖 pack,mystu/rag/* 仅为薄转发:
# pyproject.toml
dependencies = ["rag-pack", "structured-query-pack", ...]
[tool.uv.sources]
rag-pack = { path = "rag-pack", editable = true }
Admin 入库 API、鉴权、Pydantic 请求模型留在 host 项目(knowledge_admin_api.py),pack 只提供 ingest_* 函数。
七、双通道:RAG Skill 与问数 Skill 如何协作
mystu 采用 双通道检索,两个 Skill 并行注册,由 LLM 按问题类型选择:
| Skill | 工具 | 典型问题 |
|---|---|---|
knowledge-retrieval |
search_knowledge_base |
政策怎么说、周报观点 |
structured-query |
sql_db_list_tables 等 |
库存多少、环比多少 |
两个 Skill 的 SKILL.md 正文都写明「何时转另一条通道」,系统提示词(iron_ore_forecast.md)再次强调,避免混用来源。
八、为什么封装成 deepagents Skill
8.1 Skill 解决什么问题
| 若只有工具、没有 Skill | 加上 Skill 之后 |
|---|---|
| LLM 可能对任何問題都先 RAG | Skill 明确「文档类用 RAG、数字类转 SQL」 |
| 工具描述偏技术,缺工作流 | Skill 提供 5 步标准流程与示例 |
| 工作流散落在系统提示词,难复用 | Skill 是独立 Markdown,可拷贝 |
| 升级 Milvus 封装不影响工作流 | Skill 与 Toolkit 解耦 |
8.2 通用模板 + 领域 overlay
SKILL.md.template:占位符{{DOMAIN_NAME}}、{{EXAMPLE_QUERY}}等;references/iron-ore.md:mystu overlay,不自动加载;configure.py --preset iron-ore:把示例问句、doc_type 烘焙进SKILL.md。
python rag-pack/configure.py --preset iron-ore
8.3 Skill 与 Cursor Skill 的区别
| deepagents Skill(本项目) | Cursor Skill(.cursor/skills/) |
|
|---|---|---|
| 运行环境 | Agent 运行时(FastAPI / LangGraph) | Cursor IDE 里的 AI 助手 |
| 加载方式 | SkillsMiddleware + /skills/ 虚拟路径 |
用户手动 attach |
二者名称相似,不是同一套东西。
九、Skill 文件结构说明
9.1 Frontmatter
---
name: knowledge-retrieval
description: 铁矿石组织知识库检索:使用 search_knowledge_base 检索周报、政策、新闻...
allowed-tools:
- search_knowledge_base
---
name:对应/skills/knowledge-retrieval/;allowed-tools:须与get_knowledge_retrieval_tools()注入的工具名 完全一致。
9.2 正文章节
| 章节 | 作用 |
|---|---|
| 何时使用 | 非结构化 vs 数值类问题的分界 |
| 可用工具 | search_knowledge_base 参数说明 |
| 推荐工作流 | 判断通道 → 构造 query → 调用 → 回答 |
| 安全与约束 | 部门可见性、勿编造、勿混用数字来源 |
| 示例 | 渲染后的领域问句 + 检索参数 |
| 常见错误处理 | count=0、error 字段、误用 RAG 查数字 |
| 领域补充 | 可指向 references/*.md(需显式引导) |
十、如何在其他项目中使用这个 Skill
10.1 拷贝 pack
将整个 rag-pack/ 复制到目标仓库根目录。
10.2 安装与配置
见 第四节 与 rag-pack/INSTALL.md。
10.3 单 pack 最小接入示例
参考 rag-pack/wiring/deepagent_example.py:
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend
from deepagents.backends.filesystem import FilesystemBackend
from rag_pack import AGENT_SKILLS_DIR, SKILLS_VIRTUAL_PREFIX, get_knowledge_retrieval_tools
def build_backend():
return CompositeBackend(
default=StateBackend(),
routes={
SKILLS_VIRTUAL_PREFIX: FilesystemBackend(
root_dir=str(AGENT_SKILLS_DIR),
virtual_mode=True,
),
},
)
tools = [*your_tools, *get_knowledge_retrieval_tools()]
agent = create_deep_agent(
model=your_model(),
tools=tools,
system_prompt="说明何时走知识库检索",
backend=build_backend(),
skills=[SKILLS_VIRTUAL_PREFIX],
)
10.4 与 structured-query-pack 并存
为每个 skill 子目录单独挂载路由(参考 mystu agent_skills.py),避免两个 pack 的 skills/ 目录互相覆盖。
10.5 编写领域 overlay(可选)
在 skills/knowledge-retrieval/references/domain.md 写 doc_type 口径与双通道规则。记住:不会自动加载;若希望大模型使用,须在 SKILL.md 或系统提示词中写明 read_file 路径。
十一、安全与权限模型
| 层级 | 机制 |
|---|---|
| 入库 | mystu Admin API 需 admin 角色 + 完成改密 |
| 检索 | visibility_tags 过滤:仅 "all" 或用户 department 可见 |
| 存储 | Milvus collection 与业务库隔离;token 鉴权 |
| Agent 沙箱 | deepagents 默认 StateBackend;真实数据访问在 search_knowledge_base 与 Milvus |
| 与问数分工 | 数值权威来源是 SQL 查数,不是 RAG 片段 |
RAG 检索为只读操作,未配置 HITL 人工审批。
十二、常见问题排查
12.1 启动日志:Milvus 连接失败,降级内存
| 现象 | 常见原因 |
|---|---|
| 每次重启知识库为空 | 使用了 InMemoryKnowledgeStore,未配 MILVUS_URI |
| ping 失败 | URI/Token 错误、网络、Zilliz 集群未就绪 |
| collection 不存在 | 首次入库时 langchain-milvus 会自动创建;检查 MILVUS_COLLECTION |
12.2 检索始终 count: 0
- 是否已成功入库(Admin API 或测试脚本);
doc_type过滤是否过严(可去掉重试);visibility_tags是否与用户department匹配;- Embedding 配置是否与入库时一致(换模型会导致语义空间不一致)。
12.3 Skill 未生效
skills=["/skills/"]是否传入create_deep_agent;CompositeBackend是否路由到knowledge-retrieval目录;SKILL.md是否存在(需先运行configure.py);- frontmatter
allowed-tools是否含search_knowledge_base。
12.4 iron-ore.md 写了但模型好像没用
预期行为:overlay 不会自动加载。确认是否在 SKILL.md 或系统提示词里写了 read_file 路径,或用 configure.py --preset iron-ore 烘焙进 SKILL.md。
12.5 用户问数字,模型却去 RAG
在系统提示词与两个 Skill 中都已强调双通道;可检查 SkillsMiddleware 是否同时加载了 structured-query 摘要,以及 SQL_READONLY_DSN 是否配置(问数工具未注入时 LLM 可能只能 RAG)。
12.6 Embedding 加载慢或失败
local 模式首次运行需下载 BAAI/bge-m3;无 GPU/无网络时可设 EMBEDDING_USE_FAKE=true 做链路调试(检索质量无意义)。
十三、扩展与演进
| 方向 | 说明 |
|---|---|
| 新 doc_type | 扩展入库 API 校验 + SKILL 模板 + overlay |
| 混合检索 | 当前为稠密向量;可扩展 BM25 + 向量 hybrid |
| LLM 增强入库 | 摘要、语义分块(当前未实现) |
| 独立入库 CLI | 当前 mystu 走 Admin API;pack 提供 Python API |
| 独立 PyPI 包 | 当前采用「复制文件夹」分发 |
十四、相关文档与代码索引
| 资源 | 路径 |
|---|---|
| 可拷贝 pack | rag-pack/ |
| 接入指南 | rag-pack/INSTALL.md |
| 验收清单 | rag-pack/CHECKLIST.md |
| mystu Agent 装配 | mystu/buildagent/agent/deepagent.py |
| 双 skill 路由 | mystu/buildagent/agent/agent_skills.py |
| Admin 入库 API | mystu/controller/knowledge_admin_api.py |
| 领域 overlay(不自动加载) | rag-pack/skills/knowledge-retrieval/references/iron-ore.md |
| 智能问数 Skill 指南 | docs/structured-query-skill-guide.md |
| RAG 全链路(含问数) | docs/rag-pipeline-deep-dive.md |
| 领域词汇 | CONCEPTS.md |
十五、小结
组织知识库 RAG 的本质是 「Embedding 向量化 + Milvus 检索 + LLM 编排 + Skill 工作流文档」:
- 入库管线(parsers → chunker → embed → Milvus)在 pack 内可复用;Admin API 等 host 逻辑留在业务项目;
- Toolkit 提供
search_knowledge_base与部门过滤; - Skill 提供可拷贝的工作流;SkillsMiddleware 只注入摘要,全文靠
read_file按需加载; references/iron-ore.md等 overlay 不会自动加载,领域信息应写入渲染后的SKILL.md,或显式引导read_file;- 与 structured-query Skill 组成双通道:文档走 RAG,数字走 SQL,勿混为同一来源。
按 rag-pack/INSTALL.md 接入后,任何 deepagents 项目均可获得同构的组织知识库检索能力。
更多推荐


所有评论(0)