"""只读探查: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()