DeepSeek (OpenAI-compatible) as primary with a 智谱 GLM slot that is a real
routing path but raises until the 算法备案 model list is confirmed. Adds scene
routing, failover, a per-provider circuit breaker, structured output with
retry-on-validation-failure, prompts loaded by id+version from prompts/, and
cost attribution written to ob_ai_call for every attempt -- successes,
retries and failures alike.
Two controls exist because they are cheap now and expensive later: a
cache-prefix validator that rejects timestamps, uuids and nicknames in the
cached system prefix (a volatile prefix silently multiplies input cost), and
a hard platform-wide daily budget that rejects non-critical scenes instead of
merely alerting, since a retry storm outruns any human on-call.
Typed pydantic-settings config, structlog JSON logging with request/trace id
propagation and redaction of phone numbers, tokens and face keys, the unified
response envelope and error-code table from 架构文档 §9.2, async SQLAlchemy
session management, ORM models for the eight foundation tables, and the
OpenTelemetry/Prometheus wiring.
packages/domain stays pure logic -- snowflake ids, the quota three-phase
protocol and the tk_task state machine -- so it can be tested without a
database and is held to mypy strict.