diff --git a/app/service/milvus_service.py b/app/service/milvus_service.py index 5b83ed0..bc7e547 100644 --- a/app/service/milvus_service.py +++ b/app/service/milvus_service.py @@ -5,12 +5,13 @@ Collection 设计(冻结):docs/项目框架设计/表设计/03-milvus-coll 检索必带溯源字段(source_doc_id + source_version),且只返回已生效文档 (effective_date <= today,§2.3 合规约束)。 -环境坑(2026-09-07 实测):pymilvus 3.x 在 **import 阶段** load_dotenv() -并急切解析环境变量 MILVUS_URI,文件 URI(如本项目 .env 的 -./data/milvus.db)会让 ``import pymilvus`` 直接抛 Illegal uri。因此本模块 -在 import pymilvus **之前**用 setdefault 预置一个合法 URI(dotenv 不覆盖 -已存在变量);真实连接由 MilvusClient(uri=...) 显式传入 settings.milvus_uri, -不经过全局单例。若未来接 Standalone(Docker),.env 设合法 http URI 即可。 +环境坑(2026-09-07 实测,含评审 P1 修正):pymilvus 3.x 在 **import 阶段** +load_dotenv() 并急切解析环境变量 MILVUS_URI,文件 URI(如 .env 的 +./data/milvus.db)会让 ``import pymilvus`` 直接抛 Illegal uri。本模块的 +防御顺序:先初始化 settings(干净读 .env),再把 os.environ 的 MILVUS_URI +归位为合法 http 占位(仅替换文件 URI),最后 import pymilvus——任何其他 +顺序都会以 import 炸 / settings 遮蔽(真连接事故)两种方式踩坑。真实连接 +恒走 MilvusClient(uri=...) 显式传参,不经过全局单例。 测试:单测用真 Milvus Lite(tempfile 临时 uri,module 级 fixture 共享), 本机实测可用(0904 交接 + 0907 复测);不做 mock 双轨。 @@ -20,10 +21,22 @@ from __future__ import annotations import os -# ---- 必须先于 from pymilvus import:防 .env 的文件 URI 炸掉 import(见模块注释)---- -os.environ.setdefault("MILVUS_URI", "http://localhost:19530") +from app.config.settings import settings # noqa: E402 -from pymilvus import DataType, MilvusClient +# ---- 环境防御(顺序敏感,评审 P1 修正):必须在 settings 初始化之后、 +# from pymilvus import 之前。原因:pymilvus 3.x import 时 load_dotenv() + +# 急切解析 MILVUS_URI,.env 的文件 URI 会炸 import;但若先改 os.environ 再 +# 初始化 settings,pydantic 会读到被污染的环境变量、把 .env 的 MILVUS_URI +# 也遮蔽掉(import 顺序敏感的真连接事故)。故口径: +# ① settings 先初始化(此时环境干净,milvus_uri 拿到 .env 正确值); +# ② 再把 os.environ 的 MILVUS_URI 归位为合法 http 占位(仅文件 URI 被换, +# 合法 http 值保留),pymilvus 全局单例不再炸 import; +# ③ 真实连接恒走 MilvusClient(uri=settings.milvus_uri) 显式传参。 +_milvus_env_uri = os.environ.get("MILVUS_URI") +if _milvus_env_uri is None or not _milvus_env_uri.startswith(("http://", "https://")): + os.environ["MILVUS_URI"] = "http://localhost:19530" + +from pymilvus import DataType, MilvusClient # noqa: E402 from app.config.settings import settings