Files
group_fqcd_jr/tools/probe_knowledge_collections.py
lzf_0626 927a6fecc0 评审 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。
2026-09-11 16:51:52 +08:00

80 lines
2.7 KiB
Python
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.
"""只读探查: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()