d9ceaecf20
README gains the key with the reason a single-source scope wants wait, and the price of choosing it. .env.example carries the same warning since README points at it as the full key list. ARCHITECTURE 7.4 records why the missing cell is unrelated to source count -- and why keying on len(sources) would be the worse debt -- plus the six-exit retry_after_s contract and the admission convergence; 9 registers the key. CHANGELOG stays unreleased per the release checklist: the version bump belongs to the release run, not here. Its "read this first" section covers the half-open retry_after_s change, which is visible even on the default fail_fast setting.
144 lines
10 KiB
Bash
144 lines
10 KiB
Bash
# PolyGateway 工程配置模板(复制为 .env 使用;.env 不提交)。
|
||
# 键名清单 = M1 设计文档 §8 定稿;缺关键配置直接报错,不做默认值兜底。
|
||
|
||
# ══ 多源配置: {SCOPE}__{PROVIDER}__{N}__{FIELD} ══
|
||
# PROVIDER 必须是注册表键(qwen/deepseek/openai,或 register_provider 注册后经 registry 传入)。
|
||
# 必填: BASE_URL / API_KEY / MODEL / TIMEOUT_S(或用平铺 LLM_TIMEOUT 作缺省)。
|
||
LLM__QWEN__1__BASE_URL=
|
||
LLM__QWEN__1__API_KEY=
|
||
LLM__QWEN__1__MODEL=
|
||
LLM__QWEN__1__TIMEOUT_S=120
|
||
# 可选(0 = 该闸不启用):
|
||
# LLM__QWEN__1__MAX_CONCURRENCY=8
|
||
# LLM__QWEN__1__RPM=60
|
||
# LLM__QWEN__1__TPM=100000
|
||
# LLM__QWEN__1__EST_TOKENS=2000 # 可选调优覆盖: TPM 入场预扣量;未填则库按 tpm//60 派生
|
||
# LLM__QWEN__1__TTFT_TIMEOUT_S=30 # 须与 INTER_TOKEN 成对;0 < inter < ttft < timeout
|
||
# LLM__QWEN__1__INTER_TOKEN_TIMEOUT_S=15
|
||
# LLM__QWEN__1__ENABLE_THINKING=true # 三态: 缺省=不注入 / true=注入开启 / false=注入关闭
|
||
# LLM__QWEN__1__MISSING_DONE=retry # SSE 缺 [DONE]: retry(默认) | salvage
|
||
# LLM__QWEN__1__TRUST_ENV=true # false = 绕过本地代理(LAN 直连)
|
||
# LLM__QWEN__1__EXTRA_BODY={"temperature":0} # 本源恒定的采样参数(JSON 对象串)
|
||
# 并入请求体,优先级低于 chat(overlay=...);受控实验固定解码用它,免得漏传
|
||
# 禁用键 model/messages/stream/stream_options(会击穿治理),配了直接报错
|
||
# OCR/EMBED scope 不消费该键: 配了会被忽略并 warning(见 issue #4 决策 G)
|
||
|
||
# ══ scope 级全局闸(跨源合计;0/缺省 = 不启用)══
|
||
# LLM__GLOBAL__MAX_CONCURRENCY=8
|
||
# LLM__GLOBAL__RPM=120
|
||
# LLM__GLOBAL__TPM=200000
|
||
|
||
# ══ 韧性参数(平铺键 = 单 scope 简写,沿用三项目习惯;scope 键优先)══
|
||
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_COOLDOWN=60 # 或 LLM__BREAKER__COOLDOWN_S
|
||
# LLM_TIMEOUT=120 # 源缺 TIMEOUT_S 时的缺省
|
||
# LLM_TTFT_TIMEOUT=30 # 平铺看门狗缺省(成对生效)
|
||
# LLM_INTER_TOKEN_TIMEOUT=15
|
||
# LLM__BREAKER__PROBE_TTL_S=240 # 缺省派生: max(2×最大源超时, cooldown, 最大源超时+5);显式值须 ≥ 最大源超时+5
|
||
# LLM__BACKPRESSURE__STALL_WINDOW_S=300 # stall 双条件判死窗口;只计非生产性等待(429 退避/配额轮询/熔断冷却),与 TIMEOUT_S 无耦合,无需按 timeout×retries 放大
|
||
# LLM__BACKPRESSURE__POLL_INTERVAL_S=0.05
|
||
# 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))
|
||
# ── AIMD 自适应并发(M2.5,库常量非 env 键): 每源初始 8,429 ×0.5,成功 +1/limit,
|
||
# ── ceiling = max(64, 源级 MAX_CONCURRENCY);禁用需构造函数注入自定义 pacer ──
|
||
# LLM__QUOTA_FULL=wait # 配额满: wait(默认) | fail_fast
|
||
# ── 熔断全拒时的处置(issue #14)。单源 scope 建议 wait: 只有一个源时
|
||
# ── "停用这个源"等于"整个 scope 停服",fail_fast 会让开路期间的每次调用
|
||
# ── 在几毫秒内死掉且 MAX_ATTEMPTS 一格用不上。wait 不削弱保护(等待期照样
|
||
# ── 不发请求),只是把最坏墙钟拉长到 BACKPRESSURE__STALL_WINDOW_S ──
|
||
# LLM__CIRCUIT_OPEN=fail_fast # 熔断开路: fail_fast(默认) | wait
|
||
|
||
# ══ 装配选择(PGW_*)══
|
||
PGW_LIMITER_BACKEND=memory # memory | redis(redis 需 REDIS_URL;多进程 worker 必须 redis)
|
||
PGW_BREAKER_BACKEND=memory # memory | redis
|
||
PGW_CACHE_BACKEND=none # redis | memory | none(必填,显式优于隐式)
|
||
PGW_TELEMETRY_BACKEND=none # sqlite | postgres | none(必填)
|
||
# PGW_TELEMETRY_SQLITE_PATH=logs/telemetry.db # sqlite 时必填
|
||
# PGW_TELEMETRY_SCHEMA_MODE=manual # auto | manual;三态: 不设 = 按后端派生(sqlite→auto、postgres→manual),
|
||
# # 显式设置则两侧都可覆盖。auto = 库给已存在的旧表自动 ALTER 补列;
|
||
# # manual = 库不发 ALTER,只 warning 点名缺列并打印可执行 SQL,
|
||
# # 按现有列裁剪 INSERT 继续写(遥测不会因缺列而全线丢失)。
|
||
# # 缺省为何不对称: postgres 是共享生产表,ALTER 取 ACCESS EXCLUSIVE 锁,
|
||
# # 会排在长事务后阻塞该表其后的所有查询,而遥测是业务路径上的内联 await;
|
||
# # 且这类部署有 DBA、有迁移工具、讲最小权限,DDL 该由他们择时执行。
|
||
# # sqlite 则是下游自己的本地文件(runs/*.db):没有 DBA、没有迁移工具、
|
||
# # 没有第二个系统碰它,ALTER 是毫秒级元数据操作,强加手工 SQL 步骤是净损失。
|
||
# PGW_TELEMETRY_PG_DSN=postgresql://user:pass@host:5432/polygateway # postgres 时必填;严禁指向在用业务库(实验室约定: 专用库 polygateway)
|
||
# PGW_TELEMETRY_TEXT_CAP=2000 # 遥测落库正文的字符上限,须 > 0;**不设 = 不截断**(缺省,逐字节留全文)。
|
||
# # 作用于 messages 的每条文本 content、多模态 text part、response 与 thinking;
|
||
# # 超出部分头部保留、尾部换成 `…(略 N 字)`。多模态 image_url 的 sha256 摘要不受影响。
|
||
# # 缺省为何是"不截断": 遥测被下游当**审计证据**用——出了问题要回答"当时到底发了什么",
|
||
# # 也要能拿原样的请求复现与重放;截断后这两件事都做不成,而既有下游正依赖这一行为。
|
||
# # 反面同样要看清: 不截断意味着客户合同、标书全文无限期留在 llm_calls 里,
|
||
# # 多租户下还混在同一张表。真在意留存面的部署应显式设一个上限,并配保留期与访问控制。
|
||
# PGW_PRICING_PATH=config/prices.json # 可选: {"<model>": {"input_per_1m": x, "output_per_1m": y}};缺省 cost 恒 None
|
||
# # 可选第三档 "cached_input_per_1m": z —— 供应商 prompt cache 命中部分的单价;
|
||
# # 不填即命中部分也按 input 全额计(库不猜折扣率),cost 会偏高
|
||
# PGW_CACHE_NAMESPACE=<项目名或租户前缀> # 缓存启用时必填(防跨项目毒化)
|
||
# PGW_CACHE_TTL_S=604800 # 缓存启用时必填,须 > 0
|
||
# PGW_STRUCTURED_MAX_RETRIES=2 # 缺省 2(M2.5);0 = 解析失败不重问(CHS 策略)
|
||
# PGW_LEASE_TTL_S=1500 # permit 租约;须 ≥ 最大源 timeout
|
||
|
||
# ══ Redis(缓存 + 分布式限流/熔断)══
|
||
# 实验室纪律: 共享实例的 db0 有在用键,PolyGateway 一律用专用 db3(soak 会 FLUSHDB!)
|
||
# REDIS_URL=redis://:password@host:6379/3
|
||
|
||
# ══ Embedding scope(M2;EmbeddingClient.from_env 装配)══
|
||
# EMBED__QWEN__1__BASE_URL=
|
||
# EMBED__QWEN__1__API_KEY=
|
||
# EMBED__QWEN__1__MODEL=text-embedding-v3
|
||
# EMBED__QWEN__1__TIMEOUT_S=60
|
||
# EMBED__RETRY__MAX_ATTEMPTS=3
|
||
# EMBED__RETRY__BACKOFF_BASE_S=1.0
|
||
# EMBED__RETRY__BACKOFF_MAX_S=10.0
|
||
# EMBED__BREAKER__FAIL_THRESHOLD=5
|
||
# EMBED__BREAKER__COOLDOWN_S=60
|
||
# EMBED__BATCH_SIZE=64 # 必填: 每批条数(分批是行为关键,不设默认)
|
||
# EMBED__NORMALIZE=false # 可选: true = 库内 L2 归一化(VT 语义)
|
||
# EMBED__EXPECTED_DIM=768 # 可选: 维度校验,不符抛 ResultInvalid
|
||
|
||
# ══ SOAK scope(压测 harness 专用;tools/soak/run_soak.py --scope SOAK)══
|
||
# 网关保护(设计 §8.1 签字值,run_soak 强制: 必配且 ≤ 100/600,否则拒跑)
|
||
# SOAK__GLOBAL__MAX_CONCURRENCY=100
|
||
# SOAK__GLOBAL__RPM=600
|
||
# 健康源 + 故障源混编(findings §3): 坏 key 源 / 黑洞源 / 紧看门狗源 / 紧闸源
|
||
# SOAK__MINIMAX__1__BASE_URL= # 健康源(真实网关)
|
||
# SOAK__MINIMAX__1__API_KEY=
|
||
# SOAK__MINIMAX__1__MODEL=
|
||
# SOAK__MINIMAX__1__TIMEOUT_S=180
|
||
# SOAK__MINIMAX__2__BASE_URL= # 坏凭据源: 真实网关 + 错误 API_KEY → 401
|
||
# SOAK__MINIMAX__2__API_KEY=sk-wrong-key-on-purpose
|
||
# SOAK__MINIMAX__3__BASE_URL=http://10.255.255.1/v1 # 黑洞源: 防火墙 DROP → 连接超时
|
||
# SOAK__MINIMAX__4__RPM=5 # 紧闸源: 真实源 + rpm=5 / 并发 1
|
||
# SOAK__MINIMAX__4__MAX_CONCURRENCY=1
|
||
|
||
# ══ OCR scope(M3;MonkeyOCR 自建 LAN 服务,无鉴权故 API_KEY 填占位 "none")══
|
||
# CHS 单源写法:
|
||
# OCR__MONKEY__1__BASE_URL=http://10.77.0.20:7866
|
||
# OCR__MONKEY__1__API_KEY=none # 占位惯例: 服务无鉴权,SourceConfig 非空校验用
|
||
# OCR__MONKEY__1__MODEL=monkey-ocr
|
||
# OCR__MONKEY__1__TIMEOUT_S=300 # /parse 两段协议较慢,给足
|
||
# OCR__MONKEY__1__MAX_CONCURRENCY=4
|
||
# OCR__MONKEY__1__RPM=120
|
||
# VT 双实例写法(原 MONKEY_OCR_URLS 逗号列表拆多源;LAN 直连绕代理配 TRUST_ENV=false):
|
||
# OCR__MONKEY__2__BASE_URL=http://10.77.0.20:7867
|
||
# OCR__MONKEY__2__API_KEY=none
|
||
# OCR__MONKEY__2__MODEL=monkey-ocr
|
||
# OCR__MONKEY__2__TIMEOUT_S=300
|
||
# OCR__MONKEY__2__TRUST_ENV=false
|
||
# OCR__RETRY__MAX_ATTEMPTS=3 # per-scope 韧性键与 LLM scope 同一套
|
||
|
||
# ══ SOAK_OCR scope(P7 OCR 压测;tools/soak/run_soak.py --scenario P7 --scope SOAK_OCR)══
|
||
# 双真实实例 + 黑洞(连接超时)+ 坏端口(连接拒绝)故障池;
|
||
# SOAK_OCR_FAULT_SOURCES 供记分板"坏源吸流占比"不变量归因
|
||
# SOAK_OCR__GLOBAL__MAX_CONCURRENCY=16
|
||
# SOAK_OCR__GLOBAL__RPM=300
|
||
# SOAK_OCR_FAULT_SOURCES=monkey_3,monkey_4
|