Files
mcn-short-video/极致事件卡片_WeKnora适配性评估_V1.0_20260923.md
maogeigei 6e4ce9441c feat(skill): 素材层切换 WeKnora + 方法层接线
定性:素材载体切换(本地 md -> WeKnora 容器),非扩容;驱动方向由素材驱动改为方法驱动。

- 新建 references/接口调用/WeKnora_极致事件检索.md 调用契约:MCP hybrid_search(服务 weknora)/ kb_id 用库名禁写死 UUID / match_count=3 / vector_threshold=0.5 显式 / 不传 keyword_threshold / 零命中判据 success=true 且 data=null / 只读 chunk_metadata.answers[0] / 禁用 chat 与 agent_chat / 复筛<=2条每节点 / 取材不取形转译 / 降级矩阵 / 成本控制
- S7 布位表新增「候选创作方法」列(4->5 列)打通方法层(此前 05_极致事件 6 个方法文件在创作流程中 0 调用)
- S7 新增「极致触点素材检索」按需环节 + {material_content} 定死结构 + 极致触点机制自检([期待A]-被X打破->[结果B]);输入章节素材库改双层源(主源 WeKnora / 降级 md,md 永不删除)
- 6 个方法文件补「素材供给」块(极致标签 / 定库检索入口 / 问法②打破方式填法)
- SKILL.md MCP 依赖节增 WeKnora 检索层(含静默降级口径);S7 小节补调用链;frontmatter updated_at
- 索引_知识素材库.md 修正 03/05/06/07/08/11 定性(实为字段结构模板而非素材库);新增「接口调用」章节
- S9 输入增 {material_cards} + 新增台词毛边三档参考;S11 类1「爆点贯穿」升级为爆点溯源 4 判据,八类35项清单同步
- 根目录补 3 份方案/规范文档 + 2 份 09-23 WeKnora 文档;变更日志归档
2026-09-24 14:47:19 +08:00

181 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 极致事件卡片 × 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` 的配置**<br>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 回执)。