评审 NL_develop 交付说明:三个环境前提必须先对齐

产出 docs/NL_develop交付说明-评审意见.md(可直接转给组员),以及一个只读探查工具
tools/probe_knowledge_collections.py(Milvus 集合 schema 与行数)。

核查中发现的硬矛盾,都有可复核的证据:

1. 配置库不是同一个。对方说 active=216、合并前生效版本是 186;我这边实测 active=201,
   最近 5 条 id 就是 201/198/197/196/195 —— release.id 自增,同库不可能一边 216 一边 201。
   所以他以为已发布的 customer_service:faq=[search_knowledge, query_customer_profile]
   在这边并不存在,而他的画像出口复用的正是这个 key ⇒ 合并后被 ToolExecutor 失败关闭。
   同理他说的 fund_query_demo:fund_quote 缺失,我这边是存在的。

2. Milvus 也不是同一个。对方说现库字段是 knowledge_id/snippet、无 visibility、行数
   106/177/73;我这边实测是 doc_id/content/chapter/section/.../visibility 共 15 个字段、
   行数 125/297/214,且与 knowledge_search_service.py 的 OUTPUT_FIELDS 逐字一致。
   他这次的字段映射改动(doc_id→knowledge_id)在这边会直接报 field knowledge_id not
   exist,把客服知识检索整条打挂 —— 比他自述的"关闭 visibility 隔离"严重得多。
   建议不是 A/B/C 三选一,而是第四种:运行时探测字段名,两套 schema 都能跑。

3. 解释器不同。他用 .venv(项目里不存在,那是他机器上的 gitignore 目录),约定是
   D:\conda\envs\jr_py313。所以"mypy 151→181"跑不到本基线 —— 这边是 138 文件 0 错。

另指出:docs/26-JWT密钥管理与轮换.md 会与已存在的 docs/21-JWT密钥管理与轮换.md 重复,
建议并入 21;驳回删除 docs/04/06/10/13/99。

四项待裁决的答复:同意 agent_type 方案(要求补审计);字段映射改为运行时探测;
驳回删除编号文档;26 并入 21。
This commit is contained in:
2026-09-11 16:51:52 +08:00
parent 5bbf8481ef
commit 927a6fecc0
5 changed files with 661 additions and 1 deletions
+79
View File
@@ -0,0 +1,79 @@
"""只读探查:Milvus 知识集合的真实 schema(用于评审 NL_develop 的字段映射改动)。
只做 describe / query,不写入。结果写 `docs/evidence/knowledge-collections.json`:
python tools/probe_knowledge_collections.py
要回答的问题(对应交付说明 §4.2):
1. 现库集合的**实际字段名**是什么 —— 是 `doc_id`/`content`/`visibility` 那套,
还是 `knowledge_id`/`snippet` 那套?他选的字段映射(A 方案)建立在这个前提上;
2. 每个集合有多少行;
3. 有没有 `visibility` 字段 —— 没有的话,检索层的内部资料硬隔离就是关着的。
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from app.core.config import get_settings
OUTPUT = Path("docs/evidence/knowledge-collections.json")
def _client() -> Any:
from pymilvus import MilvusClient # type: ignore[import-untyped]
settings = get_settings()
return MilvusClient(uri=settings.milvus_uri, token=settings.milvus_token or None)
def collect() -> dict[str, Any]:
client = _client()
report: dict[str, Any] = {"collections": []}
for name in sorted(client.list_collections()):
try:
described = client.describe_collection(name)
fields = [
{
"name": str(field.get("name")),
"type": str(field.get("type")),
"is_primary": bool(field.get("is_primary", False)),
}
for field in described.get("fields", [])
]
stats = client.get_collection_stats(name)
row_count = stats.get("row_count") if isinstance(stats, dict) else None
except Exception as exc: # 单个集合探测失败不影响其余
report["collections"].append(
{"collection": name, "error": f"{type(exc).__name__}: {exc}"}
)
continue
report["collections"].append(
{
"collection": name,
"row_count": row_count,
"field_names": [field["name"] for field in fields],
"fields": fields,
"has_visibility": any(field["name"] == "visibility" for field in fields),
"looks_like_legacy_schema": any(
field["name"] in {"doc_id", "chapter", "doc_no"} for field in fields
),
}
)
return report
def main() -> None:
report = collect()
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
OUTPUT.write_text(
json.dumps(report, ensure_ascii=False, indent=2, default=str),
encoding="utf-8",
)
print(f"wrote {OUTPUT}")
if __name__ == "__main__":
main()