test: apply evidence-based live checks without hiding regressions

This commit is contained in:
2026-09-09 02:40:13 -04:00
parent 16fa0ca474
commit 73008ad7d5
9 changed files with 2350 additions and 1359 deletions
+72 -70
View File
@@ -1,89 +1,91 @@
"""真实网关 /embeddings 端点探测(M2 设计 §11.6;人类默认口径: 实现时探测)。
对 .env 的 LLM 源网关发一次真实 embeddings 请求: 支持则记录向量证据,
不支持(404/翻译为领域错误)则 skip 并把响应记录进 tests/outputs/
(降级证据)。无 EMBED scope 配置时复用 LLM 源的 base_url/api_key。
"""
from __future__ import annotations
"""真实 embedding 探测;404 仅证明请求型号不可用,不外推端点能力。"""
import dataclasses
import os
from datetime import datetime
from pathlib import Path
from uuid import uuid4
import httpx
import pytest
from dotenv import dotenv_values
from polygateway.errors import PolyGatewayError
from polygateway import GatewaySettings
from polygateway.transports.openai_compat import OpenAICompatTransport
from polygateway.types import SourceConfig
from tests.e2e.conftest import LiveCapture, ObservedTransport, enforce_verdict
from tests.live_evidence import (
LiveVerdict,
classify_live_failure,
messages_digest,
request_is_valid,
safe_attempts,
write_live_round,
)
_ENV = {k: v for k, v in {**dotenv_values(".env"), **os.environ}.items() if v is not None}
# 真实网关调用: 与 test_thinking_live.py 同待遇标 slow(pytest addopts 默认排除,
# 显式 `pytest -m slow` 运行)。理由见 test_compat_projects.py 同处注释。
pytestmark = [
pytest.mark.slow,
pytest.mark.skipif(
"LLM__MINIMAX__1__BASE_URL" not in _ENV,
reason="缺真实网关配置(.env)",
),
pytest.mark.skipif("LLM__MINIMAX__1__BASE_URL" not in _ENV, reason="缺少矩阵必需配置,未覆盖"),
]
_OUT = Path("tests/outputs/embedding")
def _record(name: str, lines: list[str]) -> Path:
_OUT.mkdir(parents=True, exist_ok=True)
path = _OUT / f"{name}_{datetime.now():%Y%m%d_%H%M%S}.md"
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
return path
async def test_probe_real_gateway_embeddings():
source = SourceConfig(
name="probe_1",
provider="minimax",
base_url=_ENV["LLM__MINIMAX__1__BASE_URL"],
api_key=_ENV["LLM__MINIMAX__1__API_KEY"],
model=_ENV.get("PGW_EMBED_PROBE_MODEL", "text-embedding-v1"),
timeout_s=30.0,
est_tokens=8,
"""沿已校验源的 timeout/trust_env,所有路径 finally 关闭。"""
settings = GatewaySettings.from_env("LLM", env=_ENV)
configured = next(s for s in settings.sources if s.name == "minimax_1")
source = dataclasses.replace(
configured, model=_ENV.get("PGW_EMBED_PROBE_MODEL", "text-embedding-v1")
)
transport = OpenAICompatTransport()
texts = ["polygateway embedding probe"]
url = httpx.URL(source.base_url)
capture = LiveCapture(
expectations={
source.name: {
"model": source.model,
"origin": str(url.copy_with(path="", query=None)).rstrip("/"),
"path": url.path.rstrip("/") + "/embeddings",
"input_shape": 1,
"control": {},
"messages_digest": messages_digest(texts),
}
}
)
real = OpenAICompatTransport(client_factory=capture.client_factory)
transport = ObservedTransport(real, capture)
run_id, parent, call_id = uuid4().hex, uuid4().hex, uuid4().hex
verdict = LiveVerdict("FAIL", "轮次未完成")
try:
result = await transport.embed(
texts=["polygateway embedding probe"], source=source, call_id="probe"
)
except PolyGatewayError as exc:
path = _record(
"probe_unsupported",
[
"# Embedding 端点探测: 网关不支持",
f"- base_url: {source.base_url}",
f"- model: {source.model}",
f"- 错误分类: {type(exc).__name__}",
f"- status_code: {exc.status_code}",
f"- 详情: {exc}",
"",
"结论: e2e 按设计 §11.6 降级,embedding 行为由 unit 全覆盖。",
],
)
await transport.aclose()
pytest.skip(f"网关不支持 embeddings({type(exc).__name__}),证据: {path}")
else:
await transport.aclose()
assert result.dim > 0 and len(result.vectors) == 1
_record(
"probe_supported",
[
"# Embedding 端点探测: 网关支持",
f"- base_url: {source.base_url}",
f"- model: {source.model}",
f"- dim: {result.dim}",
f"- usage: {result.prompt_tokens}({result.usage_source})",
f"- 向量前 5 维: {result.vectors[0][:5]}",
f"- raw: {dataclasses.asdict(result)['raw']}",
],
)
with capture.round_context(session_id=run_id, parent_call_id=parent):
try:
result = await transport.embed(texts=texts, source=source, call_id=call_id)
events = [
e
for a in capture.attempts(session_id=run_id, parent_call_id=parent)
for e in a.http
]
assert len(events) == 1 and request_is_valid(events[0])
assert result.dim > 0 and len(result.vectors) == 1
verdict = LiveVerdict("PASS", "向量形状与实发请求合格")
except Exception as error:
verdict = classify_live_failure(
error, capture.attempts(session_id=run_id, parent_call_id=parent)
)
finally:
write_live_round(
Path("tests/outputs/134/live"),
run_id=run_id,
matrix_id="embedding",
round_index=1,
safe_fields={
"status": verdict.status,
"reason": verdict.reason,
"session_id": run_id,
"parent_call_id": parent,
"attempts": safe_attempts(
capture.attempts(session_id=run_id, parent_call_id=parent)
),
"evidence_notes": capture.notes(session_id=run_id, parent_call_id=parent),
},
)
finally:
await real.aclose()
enforce_verdict(verdict)