知识库
知识库让 Agent 的答案有根据 —— LLM 不用凭训练数据猜,因为它每一轮都 可以搜你的 runbook、过去的 postmortem、团队文档。
存储结构
一个向量库,三种来源类型。
| 来源类型 | 来自哪里 | 只读? |
|---|---|---|
vault | 内置 ongridio/vault playbook 合集(截至 2026-05-29 有 96 份 markdown 文档) | 是 |
repo | 你注册的 git URL —— public HTTPS 或按仓库身份的 SSH | 否(编辑设置 + 重新同步) |
upload | 通过 SPA 的 /knowledge 页直接上传(md / txt / pdf / docx) | 否(按行编辑 / 删除) |
manual | 通过内联编辑器粘贴 markdown | 否 |
四种类型共享一个 Qdrant collection(ongrid_knowledge)和一个 embedding 模型。搜索命中会返回 source_type payload 字段,UI 据此渲染对应 的 "from vault" / "from your repos" 徽章。
ADR-028 —— 知识来源分层
为什么一个 collection:另一种方案(每个来源类型一个 collection)逼着 LLM 每个问题调 N 次搜索才能覆盖全面,把 tool-call 预算炸掉。一个 collection + source_type 过滤一次查询就拿到同等隔离。
Qdrant 客户端
窄接口,在 internal/manager/biz/knowledge/usecase.go:62:
type QdrantClient interface {
EnsureCollection(ctx context.Context, name string, dim int) error
EnsurePayloadIndex(ctx context.Context, collection, field, schema string) error
Upsert(ctx context.Context, collection string, points []qdrantx.Point) error
DeleteByFilter(ctx context.Context, collection string, mustMatch map[string]any) error
DeleteByID(ctx context.Context, collection string, id uint64) error
GetPoints(ctx context.Context, collection string, ids []uint64) ([]qdrantx.SearchHit, error)
Search(ctx context.Context, collection string, vector []float32, opts qdrantx.SearchOpts) ([]qdrantx.SearchHit, error)
Scroll(ctx context.Context, collection string, opts qdrantx.ScrollOpts) (*qdrantx.ScrollResult, error)
}生产用 internal/pkg/qdrantx 实现,测试里可以 fake。Qdrant 跟 docker-compose 一起发;通过 ONGRID_QDRANT_URL 也支持外接 Qdrant。
vault
vault 是公开的 git 仓库(不要认证),装预先整理好的诊断 playbook。 覆盖话题(截至 2026-05-29):
- 网络:DNS / TCP / TLS / HTTP 排查手册。
- Kubernetes:pod / node / kubelet 症状-原因映射。
- Linux:进程 / 内存 / 磁盘 / journald 调查路径。
- 数据库:MySQL slow-log 分诊、PostgreSQL 复制延迟。
- 诊断:70+ 按症状索引的 playbook。
ADR-029 加了云端同步:manager 按计划拉最新 vault(默认 24h,通过 SPA 设置 配置),有变化就重 embed。本地 checkout 在 /var/lib/ongrid/repos/<vault_id>/ 下;qdrant 上的点带 source=vault 标签, 所以 Sync 只删 vault 的点,从不删你自己的。
别把 vault 当成你的 repo
vault 是内置来源 —— 它从不出现在 /knowledge/repos 的 CRUD 页面里。代码用 isBuiltinVault() / is_builtin 卡这个;别再 substring-match ongridio/vault (见 recurring-pitfalls 反馈)。
你自己的 repo
POST /v1/knowledge/repos,body 带 { url, name } 注册一个 git 仓库。下次 同步 tick 里 manager 会:
git clone --depth=1(或者目录已存在就git pull)到/var/lib/ongrid/repos/<id>/。- 走树找
.md/.txt/.rst/.yaml/.yml/.toml/.json文件。 - 用配置的 embedding 模型对每个文件 embed。
- 原子替换这个 repo 的点集(
source=repo、repo_id=<id>)。
SSH 认证
按仓库身份,通过 ssh_identities 表和 SPA 的 /knowledge/identities 页 管理。Repository 行不带 provider 字段 —— 身份表是 git 凭证的唯一来源 (ADR-023)。
每次同步把 GIT_SSH_COMMAND 指向身份的 key 文件,这样每个 repo 的克隆都用 自己的 key,不会污染 $HOME/.ssh/。
HTTPS 认证
Public HTTPS repo 免认证克隆。Private HTTPS 认证暂缓:SSH 已经覆盖了实际 用例之后,原来的 GitHub-PAT 路径被移走了。在 ADR-018 的 RepoFetcher 落 地前,private 用 SSH。
上传
/knowledge/upload 页接受:
| 格式 | 提取器 |
|---|---|
.md、.txt | 直接读 + 切块 |
.pdf | docextract(internal/pkg/docextract) |
.docx | docextract |
每次上传变成 knowledge_docs 表一行 + qdrant 一个点,带 source=upload。 "组织知识" 树里支持按行内联编辑和删除。
搜索
LLM 拿到一个 query_knowledge BaseTool —— schema 在 query_knowledge_basetool.go。 入参:query,可选的 source_type 过滤,可选的 top_k。返回: {score, source, title, snippet, url?} 命中列表。
coordinator persona 被告知:碰到 "怎么做" / "为什么会出现 X" / "Y 的 runbook 是什么" 这类问题先调它 —— 一次知识搜索的代价远低于一次 5 工具的调查, 而调查最后落到的还是 playbook 已经写好的答案。
chat UI 也提供一个 Quick Action 按钮 "搜索知识",让操作员不进 chat 也能查同 一索引。