# 极致事件卡片 × WeKnora 适配性评估 V1.0 > 日期:2026-09-23 | 评估对象:`极致事件卡片`(V1.3 口径,10 固定字段 + 所属库专属 N)能否存放在 WeKnora 的知识库模式下 > 方法:**本机 WeKnora 0.8.0 实例实测**(含 5 轮真实调用,非纯推演)+ 源码取证(file:line) > 性质:**评估与方案,未改动任何技能文件,未改动你已有的 `mcnvideoprompt` 知识库**(实验全部用临时库,跑完即删) --- ## 一、结论先行 **适合,但必须换容器:这类卡片要的是「卡片库」,不是「文档库」。** | 判断 | 内容 | |:--:|------| | ✅ **适合** | 卡片天然是「可被检索调用的素材单元」——WeKnora 的 标签 + 检索信道 + 生成式问法 三件套正好对上「定库 → 圈范围 → 召回」这个链路 | | ❌ **不适合** | **不要走文档分块那条路**。实测同一批卡,512 字粒度下**一张卡被切成 4 块、字段组打散、重叠导致字段重复、块还跨越两张卡**(详见第二节矩阵 A/B) | | ⭐ **最优容器** | **FAQ 型知识库**:一条目 = 一分块,不走文档分块器 → 一张卡一个原子单元,字段不打散(实测答案长度 691 / 1149 与原文完全一致) | | ⚠️ **前提** | FAQ 型库有 **3 个默认坑**:索引管线默认关闭(会导致"入库成功但永远检不到"的静默失败)、必须绑 embedding 模型、dry_run 是异步任务。三个都已实测并给出规避参数(第五节) | | 🔒 **边界** | **git 仍是唯一权威源**,WeKnora 只做派生的检索层;**规则类文本(S1-S11 流程 / 35 项清单 / 映射表 / 评估标准)不要进**(第七节) | 一句话:**素材进检索层,规则留在文件里;卡片走 FAQ 容器,不走文档分块。** --- ## 二、实测矩阵(核心证据) 同一批 3 张真实卡(691 / 952 / 1150 字,取自 `极致事件提取_多类别样本_20260922.md`),同一台 WeKnora,只换容器与参数: | # | 路线 | 切成几块 | 字段完整性 | 卡片原子性 | 检索 | |:--:|------|:--:|------|------|------| | **A** | **你当前 `mcnvideoprompt` 的配置**
512 / overlap 80 / auto / 父子 4096-384 | **9 块** | ✗ 卡被拆成「内容层 4 字段 + 3 字段 + 呈现层 4 字段」三片 | ✗ 一卡跨 4 块 | 需靠父子回补+重排,易半卡 | | **B** | heading 策略 512/80 | **9 块** | ✗ 与 A 逐块完全相同 | ✗ 同上 | 同上 | | **C** | 结构化档 1200 / overlap 0 / legacy | 4 块 | △ 字段基本齐全,但仍有跨块 | ✗ 一块含 2 张卡;卡 2 仍被切开 | 一块多卡 | | **D** | 长档 2000 / overlap 0 | 2 块 | ✓ 每块 10/10 字段 | ✗ 一块含 2 张卡 | 一块多卡 | | **E** | ⭐ **FAQ 容器**(一条目 = 一分块) | **2 条目 = 2 单元** | ✓ 10/10 字段整张保留 | ✓ **答案长度 691 / 1149,与卡片原文一致** | ✓ 标准问命中 score **0.8219**;通用 hybrid-search 亦可命中 | **A 的翻车细节(值得记住)**: - 691 字的卡被切成 → `[31 字:只剩卡头 + 元信息行]` + `[4 字段]` + `[3 字段]` + `[4 字段]` - **overlap 80 导致同一字段出现在两块**(`事件标签` 同时出现在第 2、3 块)→ 检索可能返回"同一张卡的两片" - **第 4 块里既装着上一张卡的尾部字段、又装着下一张卡的卡头** → 跨卡污染 - **不可预测**:1150 字的卡反而整块未切(1231 字单块,超过 chunk_size) > 复现脚本与原始输出:`tools/weknora-fit/1_docchunk_fit.py` → `out/1_docchunk.txt`(A/B/C/D);`4_pipeline_verify.py` → `out/4_pipeline.txt`(E) --- ## 三、逐项对齐:卡片契约 ↔ WeKnora 数据模型 ### 3.1 对得上的(可直接支撑) | 卡片侧需求 | WeKnora 对应能力 | 证据 | |------|------|------| | 定库:主标签决定落哪个库 | **`KnowledgeTag`**:KB 内**同名唯一**、可排序、可着色;多对多关系表 | `internal/types/tag.go:12-88` | | 筛条:按标签圈定检索范围 | **`SearchParams.TagIDs` / `ScopeTagIDs`**;`DisableRecallThresholds` 保证圈定范围内不被阈值抹掉 | `internal/types/search.go:20-55, 232-246` | | 主标签优先 / 辅助标签次级 | FAQ 检索的 **两级标签优先** `first_priority_tag_ids` / `second_priority_tag_ids` | `internal/types/faq.go:376-386`、`service/knowledge_faq.go:949-960` | | 一条卡的「多种检索说法」 | FAQ 的 **标准问 + 相似问 + 反例问**;且**反例不参与索引**(只做精度控制) | `service/knowledge_faq.go:1633-1647` | | 卡片正文保真(原话不概括) | FAQ 的 **`Content`(返回给模型的卡面)与 `IndexContent`(向量化内容)分离** | `service/knowledge_faq.go:1633-1647 / 1890-1901` | | 一卡一单元、字段不打散 | FAQ 条目**不走文档分块器**,`Content: buildFAQChunkContent(meta, mode)` 逐条构建 | `service/knowledge_faq.go:189、192` | | 治理:批量改名/换标签/停用 | **按 ID 或按 Tag 批量改字段**(含 `ExcludeIDs`)、导出→编辑→重新导入、append/replace 合并 | `internal/types/faq.go:389-410`、`router/routes_knowledge.go:151-180` | | 入库门禁(10 字段硬规则) | **`dry_run` 批量预校验**:实测 3/3 通过、返回 `success_count / failed_count / 部分失败明细` | `internal/types/faq.go:322-330、367-375`;实测见 `out/2_faq.txt` | | 召回增强(不必手写全部问法) | 文档侧**每 chunk 自动生成 3 个问题并独立索引**(该库已开启) | 实例配置 `question_generation_config` | ### 3.2 对不上的(要么绕、要么放弃) | 卡片侧需求 | 现实 | 处置 | |------|------|------| | **多字段联合硬过滤**(如"铺垫量级=短 **且** 极致类型=反转") | **做不到**。`CustomMetadata`(JSON)**不参与检索过滤**,只在结果里作为 `KnowledgeCustomMetadata` 暴露给模型 | 压成 Tag(把枚举值做成标签)→ 只能两级;或靠 rerank 排序 | | 10 字段顺序 + N 的结构化契约 | WeKnora 无"字段"概念,只有条目/分块/标签/元数据 | 契约由**卡面文本自身**承载(写入时校验,读出不解析) | | 沿革句 / diff / 双向同步 | 没有 git 语义;改动是"重新解析"的异步任务 | **git 保源,WeKnora 保检索**(单向下沉) | | 12 维闭集、禁自造词 | **`auto_tag_config` 会 LLM 自动打 ≤3 个标签**,会破坏闭集 | **必须保持 `enabled=false`**(你的实例当前已是 false,属既有隐性正确配置) | --- ## 四、卡片为什么"天生适合 FAQ 容器"(语义再对齐一次) FAQ 容器常被理解为"用户提问 → 客服答复",但把字段摊开看,它和卡片其实是同构的: | FAQ 条目字段 | 映射到卡片 | 说明 | |------|------|------| | `standard_question` | 这张卡的**主检索意图**(一句话问法) | 如「找一个高温把人打脸的反差事件」 | | `similar_questions` | 这张卡的**其他问法** | 就是 S7 在布位时可能说出的不同措辞 | | `negative_questions` | **不该命中这张卡**的边界(不入索引) | 天然承载"伪极致 / 无效召回"的边界控制 | | `answers[0]` | ⭐ **整张卡正文(10 字段 + N)** | 实测 1149 字整张放入无损 | | `tag_name` | **主标签**(定库依据) | 对应 12 维取值 | | `is_recommended` | 是否进推荐位 | 可对应"爆点级/常规级" | **唯一需要声明的语义错位**:FAQ 有"直接回答"通道(`FAQPriorityEnabled` / `FAQDirectAnswerThreshold`),若素材库与问答库混用,素材卡会被当成"直接答案"抛给用户。→ **素材库必须独立成库**(你已建的 `mcnvideoprompt` 正好空着,但它是 `document` 型,需另建 `faq` 型的素材库)。 --- ## 五、落地配方(已实测可复现) ### 5.1 三个默认坑(全部实测踩到) | # | 坑 | 现象 | 规避 | |:--:|------|------|------| | **P1** ⭐ | **FAQ 型库默认 `vector=false / keyword=false`** | 入库 100% 成功、条目/分块/标签都在,但**检索永远返回空**(`success:true, data:[]`)—— 静默失败,不报错 | 建库时显式传 `indexing_strategy.{vector_enabled,keyword_enabled} = true` | | **P2** | **建库/建条目不绑 embedding 模型** | 导入任务卡在 `processing / 0%`,`progress` 接口的 `error` 字段**为空**,只能翻容器日志看到 `failed to get embedding model: model ID cannot be empty` | 建库时传 `embedding_model_id`(用 `03f0cf45-…` bge-m3) | | **P3** | **`dry_run` 是异步任务,会占用导入通道** | dry_run 之后立刻发起正式导入 → `400 该知识库已有导入任务正在进行中` | dry_run 后轮询其 task 至 `completed`,再发正式导入(实测各约 2 秒) | > P1 的根因日志:`knowledgebase_search.go:195 [HybridSearch] | No retrievable indexing pipelines across 1 KBs` —— FAQ 检索复用 HybridSearch,管线为空就直接短路。 ### 5.2 终验通过的一组参数(实测结果见 `out/4_pipeline.txt`) ``` POST /api/v1/knowledge-bases { "name": "<账号>-极致事件库", "type": "faq", ← FAQ 型容器 "embedding_model_id": "03f0cf45-38dd-4330-aed9-38e394e66160", ← P2 必须 "faq_config": { "index_mode": "question_answer", "question_index_mode": "combined" }, "indexing_strategy": { "vector_enabled": true, "keyword_enabled": true, "graph_enabled": false, "wiki_enabled": false } ← P1 必须 } ``` - 标签:`POST /knowledge-bases/{id}/tags`,把 **12 维取值**建成标签(闭集由人工维护,禁 auto_tag) - 入库:`POST /knowledge-bases/{id}/faq/entries`,`{entries:[…], mode:"append", dry_run:true}` → 轮询 `GET /faq/import/progress/{task_id}` → 再正式导入 - 检索:`POST /knowledge-bases/{id}/faq/search`,可带 `first_priority_tag_ids` **终验实测**:2 条卡 → 导入 2/2 → 排查式检索命中 1 条 `score=0.8219`,返回**答案长度 691 = 整张卡**。 ### 5.3 已知待调项(如实记录) | # | 观察 | 待办 | |:--:|------|------| | 1 | **用"语义改写问法"检索命中 0**(「我需要一个反差感强的事件,人物被高温天气打脸的」→ 0;而标准问原句 → 0.82) | 相似问需覆盖**真实检索口径**(S7 实际会怎么问),或降 `vector_threshold`、或改走通用 `/hybrid-search`(实测该通道对 FAQ chunk 可命中) | | 2 | 按标签优先检索那一次命中 0 | 需在问法匹配成立的前提下复测,标签优先级是否生效尚未独立验证 | | 3 | 当前实例只有 `document` 型的 `mcnvideoprompt`(0 条目),无 FAQ 型库 | 落地需新建 FAQ 型素材库 | | 4 | **MCP 通道拿不到标签能力** | MCP 暴露 40+ 工具,但**无 FAQ / Tag 工具**,`hybrid_search` 参数也没有 `tag_ids` → 走 MCP 无法"按标签圈定 + 建卡",必须走 HTTP API 或扩展 MCP | --- ## 六、推荐的落地形态(三档) | 档 | 做法 | 适用 | |:--:|------|------| | **A(推荐)** | **FAQ 型库 + 一卡一条目 + 12 维做成标签 + 索引管线显式开启**;标准问写主检索意图、相似问写 3 种真实问法、答案放整张卡原文、反例问放"不该命中"的边界 | 要让 S7 在创作时"按需召回素材" | | **B(保守)** | `manual` 型条目(markdown 正文 + `FolderPath`=所属库 + `TagIDs`=主标签),chunk_size 提到 **≥1200 / overlap 0** | 想要原文保真 + 可 diff,能接受"一块多卡" | | **C(不推荐)** | 把整份实测报告/清单文件直接入库 | 实测 A/B 路线:字段打散、跨卡污染、overlap 重复 | > 注:B 档的 `manual` 型也支持 `TagIDs`、`FolderPath`、标题/描述,且有条目级版本(`ManualKnowledgeMetadata`,`types/knowledge.go:288-300`)—— 是"要版本感"时的次优解。 --- ## 七、边界:什么**不**该进 WeKnora | 内容 | 为什么不进 | |------|------| | **规则类文本**:S1-S11 流程、35 项检查清单、`01_极致类型-素材标签映射表`、`03_极致事件评估标准` | RAG 是"检索回来给模型看",召回率不是 100%(`vector_threshold` 默认 0.5 / `keyword_threshold` 0.3 会直接滤掉)。**规则必须 100% 生效 → 只能走技能文件的硬闸门**,进检索层等于把硬约束降级成软建议 | | **沿革句 / 变更日志** | 无 git 语义,且本来就是给人和 git 看的 | | **闭集词表本身**(12 维定义) | 词表要能被机械校验(禁自造词),进 RAG 就变成"参考建议"。**词表留文件,取值做成标签** | 一句话判据:**要"被翻出来看"的进 WeKnora;要"必须遵守"的留文件。** --- ## 八、待你决策 | # | 事项 | 我的建议 | |:--:|------|------| | 1 | 是否落地 WeKnora 作为卡片检索层 | 建议**试跑**:新建 FAQ 型素材库,先灌 12 张存量卡(`mode=append`,实测 3 秒内完成) | | 2 | 素材库与 `mcnvideoprompt` 的关系 | **独立成库**(FAQ 型专库);`mcnvideoprompt` 保持 document 型不动 | | 3 | 落地前是否先修 §5.3-1 的语义问法召回 | 建议先补"真实检索问法"到相似问,再灌量 | | 4 | 是否扩 MCP(补 FAQ / Tag 工具) | 若不扩,S7 只能走 HTTP API —— 需确认技能侧是否允许调用本机 HTTP | --- ## 附:证据索引 | 类别 | 位置 | |------|------| | 实测脚本 | `tools/weknora-fit/1_docchunk_fit.py`(A/B/C/D)・`2_faq_container.py`・`3_search_diag.py`・`4_pipeline_verify.py`(E) | | 原始输出 | `tools/weknora-fit/out/*.txt` | | WeKnora 源码 | `\\wsl.localhost\Ubuntu-24.04\home\maidou\weknora\`(0.8.0) | | 分块规格 | `docs/CHUNKING.md`(512/80 默认;结构化记录建议 overlap 0) | | 实例 | `localhost:31607`;容器 `WeKnora-app / docreader / postgres / redis / frontend` 均已运行 3 天 | | 模型 | `glm-5.3-flash`(KnowledgeQA) ・ `BAAI/bge-m3`(Embedding) ・ `BAAI/bge-reranker-v2-m3`(Rerank) | **未改动**:本评估未修改任何技能文件;未向 `mcnvideoprompt` 写入任何数据;4 个临时实验库已全部删除(删除均有 HTTP 200 回执)。