Appearance
知识库检索(Tier B)—— 分块、父子、混合检索
读者:要把「文档进知识库 → Agent 能引用章节」接到自己 SaaS 上的建设者或 AI coding agent。 状态基准:2026-09-03。结构感知分块、父子两级检索、
hybrid双路召回、chapter_path面包屑均已实装。存量 KB 标legacy,不 rebuild 则行为不变。 活契约:本节 curl 对齐当前 FastAPI 请求体(KnowledgeBaseCreateIn/KnowledgeSearchIn)。仓库openapi.yaml里知识库创建 schema 仍带scope/slug等设计意向字段,不要照抄那份创建体。 鉴权:建设态用管理面 JWT(knowledge:create/knowledge:ingest/knowledge:debug/knowledge:rebuild)。运行态检索由会话内置工具kb_search完成,接入方不直接调 search。
0. 心智(30 秒)
上传文档 → 按 KB 冻结的 chunk_strategy 切块
→ 子块建向量;父块 = 章节文本、不建向量
→ 检索命中子块后上卷父块(单次结果有体量预算)
→ hit 带 chapter_path(章节面包屑);legacy 库为 null
绑到会话 Agent 的 bindings.knowledge_base_ids 后,模型经 kb_search 取上下文改分块策略不会立刻重切已有文档:chunk_strategy 冻结的是「下一次 rebuild 用什么」。要看到新策略,必须显式 rebuild。
1. 创建知识库
bash
curl -sk -X POST "$BASE/api/v1/builder/knowledge-bases" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"project_id":"'$PROJECT_ID'",
"name":"退款政策",
"description":"售后与退款FAQ",
"embedding_model_id":"'$EMBED_MODEL_ID'",
"embedding_dim":1536,
"chunk_strategy":{
"strategy":"auto",
"min_chars":256,
"max_chars":768,
"overlap_chars":96
}
}'
# → Envelope.data.id = KB_ID
# embedding_model_id / embedding_dim 写入后冻结;换模型 = 新建 KB约束(照抄会 422):
| 字段 | 实装口径 |
|---|---|
project_id | 必填 UUID(KB 挂项目,不是租户级 slug) |
embedding_model_id | 已注册的 embedding 模型 UUID |
embedding_dim | 必须 1536(当前基线;其它维度直接拒) |
chunk_strategy | 可省略;省略则管线用默认。写入后改策略只影响下次 rebuild |
strategy | auto | by_section | by_paragraph | fixed |
auto:按 markdown 标题切 section,section 内按中英分句符合并,不跨标题。by_section / by_paragraph / fixed 顾名思义。中文分句符(。!?;)会保留,不会被吞成空格硬切。
存量、未写策略的 KB:chunk_strategy.strategy = "legacy"。它们继续走旧切法,直到你 PATCH 策略并 rebuild。
2. 上传文档与 rebuild
建设台(web-builder → 项目 → Resource Modeling → Knowledge Bases)或 API:
- 登记 / 上传文档:
POST /api/v1/builder/knowledge-bases/{kb_id}/documents(multipart 上传或登记外部源) - 支持文件类型(实装白名单):
txt/markdown/json/csv/pdf - 异步流水线:
pending → queued → parsing → chunking → embedding → completed(失败可 retry) - 全库重切:
POST /api/v1/builder/knowledge-bases/{kb_id}/rebuild(staging 版本 + 原子切换;大库耗时与内存随文档量上升,先在小库试)
调试预览分块:GET .../documents/{document_id}/chunks,预览项含 chapter_path。
3. 调试检索(建设态)
bash
curl -sk -X POST "$BASE/api/v1/builder/knowledge-bases/$KB_ID/search" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"query":"七天无理由退款要多久处理?","top_k":5,"hybrid":true}'请求体(KnowledgeSearchIn):
| 字段 | 含义 |
|---|---|
query | 必填 |
top_k | 1~50,默认 4 |
score_threshold | 可选;hybrid=true 时作用在融合分上 |
hybrid | 默认 false = 纯向量。true = 向量 + CJK bigram 全文双路,RRF(k=60) 融合 |
每条 hit:
json
{
"chunk_id": "...",
"document_id": "...",
"chunk_index": 0,
"content": "……章节或段落文本……",
"score": 0.81,
"chapter_path": "售后政策 / 退款 / 七天无理由",
"metadata": {}
}chapter_path:结构感知分块的章节面包屑;legacy库为null。- 父子检索:命中的是子块向量;返回内容按父块上卷、同父合并。单次工具结果有体量预算(约 16KiB),超限按命中子块邻域截断,避免撑爆轮次 token 护栏。
- rerank:平台侧可对融合结果再排;计量写入
cost_records(call_kind=rerank)。接入方无新扣点字段。
4. 绑到会话 Agent
发布会话 Agent 时把 KB 放进 bindings.knowledge_base_ids(可多库)。发布体对齐活着的 AgentPublishIn,与 hello-agent §10.1 / cookbook §3 同一形状:
json
"bindings": {
"primary_model_group_id": "<GROUP_UUID>",
"knowledge_base_ids": ["<KB_UUID>"],
"skill_ids": [],
"tool_ids": []
}运行时模型调用内置 kb_search。工具输出每条含 content 与 chapter_path,便于引用「来自哪一节」。接入方不要自己再打建设态 search——会话通道已经包好。
chat-dry-run 的配置读数含 kb_count,发布前可确认绑定生效。
5. 给产品经理的预期
| 现象 | 原因 | 处置 |
|---|---|---|
| 中文长文检索像「切碎的字」 | 仍是 legacy 切法 | PATCH chunk_strategy 为 auto 后 rebuild |
| hit 没有章节名 | chapter_path 为 null | 同上;或文档本身没有标题结构 |
| 换了策略但检索没变 | 策略只作用于下次 rebuild | 显式 rebuild,等 staging 切到 active |
| 一轮里 Agent「看到的」被截断 | 父子上卷触达体量预算 | 缩小查询、拆 KB、或接受截断(护栏优先于灌全文) |
hybrid=true 仍偏向量 | CJK bigram 是零依赖起步,不是 jieba 级分词 | 对专名 / 货号类查询更有帮助;不够再走后续分词升级 |
6. 相关页
- 会话接入:cookbook · 协议
- 能力现状(含开闸边界):platform-status.md
- 契约 SSOT:openapi.yaml(检索
hybrid/chapter_path已收录;创建体以本文为准)