From 910857fd13df05a43948d31478dce4e76e12e001 Mon Sep 17 00:00:00 2001 From: iomgaa Date: Tue, 21 Jul 2026 10:00:11 -0400 Subject: [PATCH] docs: sync env template, migration notes and architecture for M2.5 --- .env.example | 9 +++++++-- research-wiki/ARCHITECTURE.md | 6 ++++-- research-wiki/migrations/chsanalyzer.md | 10 ++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index b98d630..1f726fe 100644 --- a/.env.example +++ b/.env.example @@ -28,7 +28,7 @@ LLM__QWEN__1__TIMEOUT_S=120 LLM_MAX_RETRIES=3 # 总尝试次数(含首次);或 LLM__RETRY__MAX_ATTEMPTS LLM_RETRY_BASE_DELAY=2.0 # 或 LLM__RETRY__BACKOFF_BASE_S LLM_RETRY_MAX_DELAY=30.0 # 或 LLM__RETRY__BACKOFF_MAX_S -LLM_CIRCUIT_BREAKER_THRESHOLD=5 # 有效阈值自动取 max(此值, 并发×2);或 LLM__BREAKER__FAIL_THRESHOLD +LLM_CIRCUIT_BREAKER_THRESHOLD=5 # 连续失败通道;有效阈值取 max(此值, 源级并发×2);或 LLM__BREAKER__FAIL_THRESHOLD LLM_CIRCUIT_BREAKER_COOLDOWN=60 # 或 LLM__BREAKER__COOLDOWN_S # LLM_TIMEOUT=120 # 源缺 TIMEOUT_S 时的缺省 # LLM_TTFT_TIMEOUT=30 # 平铺看门狗缺省(成对生效) @@ -36,7 +36,12 @@ LLM_CIRCUIT_BREAKER_COOLDOWN=60 # 或 LLM__BREAKER__COOLDOWN_S # LLM__BREAKER__PROBE_TTL_S=240 # 缺省派生: max(2×最大源超时, cooldown, 最大源超时+5);显式值须 ≥ 最大源超时+5 # LLM__BACKPRESSURE__STALL_WINDOW_S=300 # stall 双条件判死窗口;须 ≥ 最大源 TTFT # LLM__BACKPRESSURE__POLL_INTERVAL_S=0.05 -# LLM__SELECTOR=round_robin # round_robin(默认) | least_inflight +# LLM__SELECTOR=health_aware # health_aware(默认,M2.5) | round_robin | least_inflight +# ── M2.5 失败率熔断通道(可选,缺省即生产推荐值)── +# LLM__BREAKER__MIN_CALLS=10 # 率通道最小样本(防低流量误判) +# LLM__BREAKER__FAIL_RATE=0.6 # 窗口失败率阈值(429 不计入) +# LLM__BREAKER__WINDOW_S=60 # 失败率窗口(双 30s 桶) +# LLM__BREAKER__MAX_COOLDOWN_S=300 # 开路指数退避封顶(缺省 max(300, cooldown)) # LLM__QUOTA_FULL=wait # wait(默认) | fail_fast # ══ 装配选择(PGW_*)══ diff --git a/research-wiki/ARCHITECTURE.md b/research-wiki/ARCHITECTURE.md index 69e4fe6..48f0421 100644 --- a/research-wiki/ARCHITECTURE.md +++ b/research-wiki/ARCHITECTURE.md @@ -405,9 +405,11 @@ flowchart TB - `InMemoryBreakerState`: 移植 Video-Tree `breaker.py`(时钟由调用方注入,纯确定性可测)。 - `RedisBreakerState`: 移植 CHSAnalyzer `provider_gate.py`,含 **epoch fencing**(防旧世代进程污染新状态)。 -- 阈值指导: 有效阈值 = `max(configured_threshold, concurrency * 2)`(三项目 .env 注释中的手动约定,库内自动计算)。 +- 阈值指导: 有效阈值 = `max(configured_threshold, 源级并发 * 2)`(M2.5 勘误: M2 曾误用**全局**并发,SOAK 并发 100 把阈值抬到 200 使熔断失灵——P6 病灶 2;.env 注释约定的本意是"防单源并发误熔",只应看源级)。 - 源冷却备忘: 开路源在进程本地记冷却截止时刻,选源时跳过,避免白烧 RPM 去探测(移植 `governance.py:107`)。 +**M2.5 双通道开路(2026-07-21,设计 designs/2026-07-21-m25-resilience-design.md;对 CHS 连续失败语义的有意扩展)**: P6 压测实证纯连续失败语义对"高失败率但偶尔成功"的半死源失明(10% 成功率源永不开路,吃掉 76% 尝试)。判据改为满足任一即开路——① 连续失败 ≥ 阈值(CHS 兼容,保留);② 窗口(双 30s 桶,服务器钟)样本 ≥ `min_calls`(缺省 10)且失败率 ≥ `fail_rate`(缺省 0.6)。**429 不入两通道**(限速是背压不是源故障,Envoy outlier detection 同款;交健康选源软处理);ResultInvalid/网关健康拒绝不计窗口样本(坏结果 ≠ 坏服务)。开路时长指数递增 `cooldown × 2^(streak-1)` 封顶 `max_cooldown_s`(缺省 max(300, cooldown)),仅率通道开路与探针失败重开递增 streak(连续通道误熔健康源的代价封顶单次 cooldown);CLOSED 稳定满 2×cooldown_eff 后首次成功衰减归零。探针撞 429 按无果归还语义放下家接管。原则沉淀: **治理状态的粒度必须等于配额的粒度**(限流/账号退避按配额主体建 key;缓存 key 含租户同理)。 + ### 7.5 响应缓存 **key 公式**: `sha256(canonical_json({model, messages_digest, namespace, salt}))`,前缀 `pgw:cache:`。 @@ -423,7 +425,7 @@ flowchart TB ### 7.7 多源与选源 -`SourceConfig`: name/provider/base_url/api_key/model/超时组/限额组(单源并发/RPM/TPM)/`est_tokens`(TPM 预扣常量,亦作 usage 缺失时的保守兜底,移植 CHS `config.py:55`;2026-07-20 缺口 G2 补)/enable_thinking。聚合自环境变量 `{SCOPE}__{PROVIDER}__{N}__{FIELD}`(§9)。`SourceSelector` 端口: `round_robin` / `least_inflight` 首发。**逻辑角色**: Video-Tree 式 SEARCH/JUDGE/VL/EVOLVE 多角色 = 命名的 client 配置组,`from_env()` 支持按角色前缀装配多个 client;禁止两个角色静默共享同一实例却在配置上看似独立(Video-Tree `evolve_llm = llm` 别名的教训——共享必须显式)。 +`SourceConfig`: name/provider/base_url/api_key/model/超时组/限额组(单源并发/RPM/TPM)/`est_tokens`(TPM 预扣常量,亦作 usage 缺失时的保守兜底,移植 CHS `config.py:55`;2026-07-20 缺口 G2 补)/enable_thinking。聚合自环境变量 `{SCOPE}__{PROVIDER}__{N}__{FIELD}`(§9)。`SourceSelector` 端口: `health_aware`(M2.5 新缺省: 成功率 EWMA / (1+在途) 的 P2C,0.05 探索地板,进程本地健康态,可选 `OutcomeAwareSelector` 扩展喂数)/ `round_robin` / `least_inflight`。**逻辑角色**: Video-Tree 式 SEARCH/JUDGE/VL/EVOLVE 多角色 = 命名的 client 配置组,`from_env()` 支持按角色前缀装配多个 client;禁止两个角色静默共享同一实例却在配置上看似独立(Video-Tree `evolve_llm = llm` 别名的教训——共享必须显式)。 **多 client 共享状态后端(2026-07-20,VT 迁移缺口 R5)**: 限流/熔断状态的 key 以 scope+source 为单位,与 client 实例解耦;多个逻辑角色的 client **显式注入同一个状态后端实例**时即共享全局并发/RPM/TPM 闸(Video-Tree `TREE_BUILD_API_CONCURRENCY` 跨 SEARCH+VL 共享 semaphore 的语义由此承接)。共享必须显式注入,禁止隐式全局。 diff --git a/research-wiki/migrations/chsanalyzer.md b/research-wiki/migrations/chsanalyzer.md index 8337749..a1b6320 100644 --- a/research-wiki/migrations/chsanalyzer.md +++ b/research-wiki/migrations/chsanalyzer.md @@ -178,3 +178,13 @@ stack = ExtractionProviderStack( | **G5** | ⚠️ 半开探针租约 TTL(探针持有者死亡后 TTL 过期自动可再探,scripts.py:96-105)与 `release_probe` 操作未见于 ARCH §7.4(只写单探针/epoch fencing);缺失则探针死锁 | M2 | **架构缺口**,修订 §7.4 | | G6 | 装配期不变式守卫:`timeout_s*1000 ≤ lease TTL`(container.py:105-112)、`stall_window ≥ 最慢源 ttft/timeout`(container.py:115-124)须进库 from_env;契约中 settle/release **幂等性**须写进 §7.3 契约文字 | M2 | 缺口(轻),M2 设计补 | | G7 | judge 默认 provider=anthropic:走实验室 OpenAI 兼容中转即可接入,若须直连 Anthropic 官方 API 则需新 transport(D2 有端口无里程碑)——迁移前与人类确认网关路径 | M3 | 决策项,非缺口 | + + +## M2.5 追记(2026-07-21,治理韧性设计的行为偏离) + +| 偏离 | 对 CHS 迁移的影响 | +|---|---| +| 熔断增设失败率通道(窗口样本 ≥ min_calls 且失败率 ≥ fail_rate 即开路;429 不入两通道) | CHS 纯连续失败语义保留为通道 1;高失败率"半死源"将比 CHS 更早被隔离——P6 实证 CHS 语义对 10% 成功率源永不开路(病灶 1) | +| 开路时长指数递增,`retry_after_s` 上限由 cooldown_s(60s)变为 max_cooldown_s(缺省 300s) | **G1 消费点注意**: tracking.py arq defer 延期时长最多放大 5 倍;属期望行为(反复坏的源就该等更久) | +| 阈值自动抬升由全局并发改为源级并发 | CHS .env 注释约定的本意(防并发误熔)保留;全局并发抬升是 M2 错误移植,已废除 | +| 缺省选源 round_robin → health_aware(EWMA×在途 P2C) | 显式配置 `LLM__SELECTOR=round_robin` 者行为不变;迁移时建议直接吃新缺省 |