feat: add governed embedding client with batching

This commit is contained in:
2026-07-21 01:11:48 -04:00
parent 193d67da93
commit 5e01dc738f
5 changed files with 840 additions and 2 deletions
+45
View File
@@ -341,3 +341,48 @@ def _guard_stall(settings: GatewaySettings) -> None:
def _load_lease_ttl(env: Mapping[str, str]) -> float:
found = _first(env, "PGW_LEASE_TTL_S")
return float(_cast(found[1], "float", found[0])) if found else _DEFAULT_LEASE_TTL_S
@dataclass(frozen=True)
class EmbeddingSettings:
"""Embedding scope 装配配置(M2 §7): 复用 GatewaySettings + embedding 专用键。
专用键不进 GatewaySettings(LLM scope 不受影响): `{SCOPE}__BATCH_SIZE`
必填(分批是行为关键,不设默认)、`{SCOPE}__NORMALIZE`/`{SCOPE}__EXPECTED_DIM`
可选。cache/structured 键对 embedding 无意义,装配时忽略。
"""
gateway: GatewaySettings
batch_size: int
normalize: bool = False
expected_dim: int | None = None
@classmethod
def from_env(
cls,
scope: str = "EMBED",
env: Mapping[str, str] | None = None,
*,
env_file: str = ".env",
) -> EmbeddingSettings:
if env is None:
env = {
k: v for k, v in {**dotenv_values(env_file), **os.environ}.items() if v is not None
}
scope_u = scope.upper()
gateway = GatewaySettings.from_env(scope_u, env=env)
key, raw = _require(env, f"{scope_u}__BATCH_SIZE")
batch_size = int(_cast(raw, "int", key))
if batch_size < 1:
raise ValueError(f"{scope_u}__BATCH_SIZE 必须 ≥ 1")
norm = _first(env, f"{scope_u}__NORMALIZE")
dim = _first(env, f"{scope_u}__EXPECTED_DIM")
expected_dim = int(_cast(dim[1], "int", dim[0])) if dim else None
if expected_dim is not None and expected_dim < 1:
raise ValueError(f"{scope_u}__EXPECTED_DIM 必须 ≥ 1")
return cls(
gateway=gateway,
batch_size=batch_size,
normalize=bool(_cast(norm[1], "bool", norm[0])) if norm else False,
expected_dim=expected_dim,
)