Files
lzf_0626 fef4c826ff fix(worker): 知识写入 Milvus 必须探测字段名并补齐必填字段
背景:走 `POST /api/v1/knowledge/upload` 灌了 22 块场内基金知识,MySQL 全部写入成功、
向量事件也全部投递,却全部同步失败(重试 3 次进死信),客服检索不到新知识。
逐层定位出三个真问题,都在写入侧:

1) **字段名硬编码**。检索侧早已按 AGENTS.md 改用运行时探测
   (`app/core/knowledge_schema.py`:`doc_id`↔`knowledge_id`、`content`↔`snippet`),
   写侧却一直硬编码 `knowledge_id` / `snippet`。本机集合实际是
   `doc_id`/`content`/`chapter`/`visibility`/…(架构师那套 schema),于是
   `Attempt to insert an unexpected field knowledge_id` 整条失败。
   现在两侧共用 `resolve_schema` 的同一份映射表,调用方只用**逻辑**字段名;
   集合没有的字段(如另一套环境无 `intent`)跳过而不是报错。

2) **非 nullable 必填字段没给**。改完名字后报
   `Insert missed an field chapter to collection without set nullable==true`:
   集合里存在、调用方没提供的 VARCHAR 字段必须补值。VARCHAR 的判据用
   `params.max_length`,不必 import pymilvus 的枚举。

3) **补值不能一律空串**:`visibility` 留空会被检索侧
   `visibility == "public"` 的过滤整行排除。这条最隐蔽 —— `query` 查得到、`search`
   查不到,表现为「入库成功但客服永远答不出新知识」,比写入直接失败更难定位。
   现在按 `FIELD_DEFAULTS` 给有语义的字段默认值。

Worker 侧把 `fields` 的键改成逻辑名(`snippet` → `content`),上限表随之改名。

**测试**:原来的桩没有 `describe_collection`,所以这条路径从未覆盖到真机 schema
(这正是缺陷长期存在的原因)。现在桩提供两套真实 schema 并参数化,另加
「跳过集合没有的字段」「探测不出必要字段必须失败关闭」两个用例。

**验证**:22 块重新同步后 `fin_product_collection` 236 行、`visibility` 全为 `public`;
问「南方沪深300ETF 的起投金额是多少」命中新块 `score=0.7932`(≥ `HIGH_SCORE` 0.75),
客服从「转人工」变为直接作答,端到端 3.34 秒。

**另**:新增 `docs/43-场内基金产品手册(知识库入库版).md` —— 从 `docs/42` 抽出
**客户可见**的纯净内容(去掉全部内部决策备注)供入库;`docs/42` 保留为草稿与决策记录。
2026-09-13 20:08:31 +08:00
..