Repository navigation
v0.8.0
v0.8.0 覆盖 v0.5.0 之后的全部改动(A/B/C/D/E 五批,SCHEMA_VERSION 25 → 28)。升级必须重启后端。
新增
模型面(批次 C)
- 主动探活 + 人工接管:真实请求失败只能证明「这次没打通」,分不清「上游真没这个模型」与「额度 / 限流 / 网络抖动」。新表
model_probes+ 后台任务(MODEL_PROBE_MINUTES,默认0= 关闭,可热更)只探仍被blocked负缓存锁住的 (渠道, 模型)——遍历全量模型表要真发几百次对话,耗的是用户额度,而负缓存才是唯一会静默避让一个模型 6–24h 的状态。- 三态判定:成功 → 清该渠道的
blocked负缓存(TTL 走完之外的唯一提前恢复入口);BLOCKED/INVALID→failed,保留负缓存并累加连续失败;额度 / 限流 / 网络 / 超时 / 空流 / 任何异常 →inconclusive,绝不禁用,且把连续失败归零(一串无关故障不该凑成「连续失败」判死好模型)。 - 与生产完全隔离:直连
provider.stream_chat,不经 executor,不写usage_events、不动冷却(除成功时清)、不改健康度、不参与选号。结论落独立的model_probes表——探测失败 ≠ 上游拒绝。 - 端点(operator + CSRF + 审计):
GET /api/models/probes、POST /api/models/probes/probe(立即探活,不受接管限制)、POST /api/models/probes/manual(on/off)。人工接管后自动探活整行跳过,接管不改负缓存。 - 「模型列表」页新增探活面板:三态结论、负缓存号数与最晚到期、最近探活 / 错误摘要、立即探活、接管 / 交还。
- 三态判定:成功 → 清该渠道的
- 模型可用性视图 + 一键黑名单:
GET /api/models/availability(operator)聚合最近 N 天(默认 7、可调 1–30)error_type为upstream_blocked/invalid_request的失败,按(渠道, 模型)给出失败次数、最近失败时刻与「是否已在黑名单」;「模型列表」页可切「疑似下线」筛选,行内「加入黑名单」把该模型追加进model_blocklist(读现值再写,不覆盖既有项)。 - 自定义模型别名(
MODEL_ALIASES,可热更):对外名=模型@渠道;对外名2=模型。列表与请求解析用同一份别名表(不会「列表有、请求 404」),条目带custom_alias: true;与真实 id / 自动别名撞车、目标不存在、渠道不持有该模型时该段记 ERROR 并跳过。 /v1/models补cost与reasoning_efforts:刊例价(输入 / 输出 / 缓存读,USD / 百万 token,缺价时整个字段缺失而不是 0)与生效中的推理档位。GET /v1/models/{id}单模型查询(OpenAI 同形):认原代号 / 归一键 / 展示名 / 自定义别名,带命名空间的原代号也能查;白名单外与不存在同为 404(无法用单查探测池内模型)。
配额与自助用量(批次 B)
usage_events.api_key_id(schema 26):把每条请求归属到发起它的 API Key,作为计量地基;老库补列后历史行为NULL= 未归属。- Key 级配额(schema 27):一个 JSON 字段六项独立,
0/ 留空 = 不限制——daily_requests/daily_tokens/daily_cost_usd/rpm/tpm/max_concurrency。当日类按北京时间自然日(与凭证护栏同口径),速率与并发是进程内滑动窗口(重启清零)。超限 429 +Retry-After指向可重试时刻。判定本身出异常时一律放行并记 warning——计量故障不能把正常请求打死。 GET /v1/usage?days=1|7|30自助用量:持 Key 的调用方查自己的用量、剩余额度与当前速率占用(只读本地明细,不触发上游,不含凭证昵称或池级信息)。
统计(批次 D)
- 失败归因:
GET /api/stats/errors(operator+)按(渠道, 模型, 错误类型)聚合ok=0明细;统计页「失败归因」面板点行即钻取到下方明细并自动加「只看失败」(GET /api/stats/events?ok=0),键盘 Enter / Space 同样触发。 - P50 / P90 / P99 分位:与 P95 同一套 SQL(一次子查询算完四档,nearest-rank,n 为有值样本数);分组表延迟列的表头有四档切换,不铺开四列。只统计成功请求。
- 请求明细实时流(SSE):明细面板「实时」开关打开后订阅
GET /api/stats/events/stream,展示当前筛选范围内刚落库的请求(与历史明细分开展示)。事件在StatsCollector.record事务提交后由进程内 hub 广播(不轮询数据库)。
引擎与出口(批次 A)
- 流式超时(默认关闭,可热更):
STREAM_FIRST_EVENT_TIMEOUT_SECONDS在出帧前超时则换号重试(此时切换安全);STREAM_IDLE_TIMEOUT_SECONDS在已出帧后超时则只发一帧错误收尾——半截输出不可回滚,换号会把两个账号的内容拼给客户端。首事件超时默认必须保持关闭:实测慢上下文首字可达 40–71s,默认值会误杀正常请求(推荐60;空闲推荐300)。 Retry-After解析:上游Retry-After(含Try again in 17h 59m这类文本式)→ 「何时恢复」的 epoch 秒,冷却按真实恢复时刻算,不再一律套固定 TTL。- 短冷却「等待续上」(
SHORT_COOLDOWN_WAIT_SECONDS,默认0):全池都在短冷却、最短剩余不超过该值时等待后重取一次,而不是直接 503;等待期间不占在途租约、不计入轮换预算。 n > 1显式 400:本网关的响应结构只能产出一条候选,此前静默只回一条,客户端以为拿到了 n 条。- 选号加入在途负载键:并发不再全压同一凭证。
cache_control原样透传(Anthropic):落点与 Anthropic 一致,只做结构校验、取值不解释;不带标记时映射结果与旧版逐字节一致。response_format语义收口(chat):text/json_object直通,json_schema展开。
会话与任务(批次 E)
- 会话粘性接受请求头标识:优先级 请求体显式键(
conversation_id/prompt_cache_key)> 请求头(x-session-id/x-opencode-session/x-session-affinity/conversation-id)> 消息前缀指纹兜底。头与指纹值都掺username再哈希(两用户同值不串号),头必须过字符白名单,非法则丢弃退回兜底。 - 签到定时(
CHECKIN_TIMES/CHECKIN_JITTER_MINUTES,可热更):本地时间HH:MM多时点,抖动在时点之前提前0..N分钟把多部署摊开;按「日期 + 时点」去重,抖动只改执行时刻不会跑两次。配了时点后循环改为每 60 秒醒一次(否则抖动 = 0 时窗只有一分钟,必然整天漏签)。留空 = 全天每 10 分钟检查(旧行为)。 - 服务端日志页(
/logs,仅管理员):GET /api/logs取最近若干行、GET /api/logs/streamSSE 先回放缓冲再推新行;级别筛选、关键字过滤、跟随最新、暂停与清空。没有任何写入或执行入口。每行发出前过脱敏白名单,命中token/secret/authorization/cookie/password/api_key或sk-…形状的整行丢弃(LOG_BUFFER_LINES,0= 关闭该页)。 - 请求级结构化日志(
REQUEST_LOG_ENABLED,logfmt):每个业务请求一行event=request request_id=… method=… route=… status=… duration_ms=…;路由用模板不用实际 ID,不写 query string / 请求体 / 用户名,靠request_id关联usage_events。静态资源与探针不记。
管理台
- CodeArts 内置组健康度改按积分账派生:凭证页把 CodeArts 拆成「内置 / 福利」两组、每组只讲一本账,但健康度一直读主账(每日 token 池),导致内置组出现「额度列显示积分还剩 99%、健康度却 0%」的自相矛盾。新增派生的
quota_credits_health(不参与调度,选号仍只读主账health),前端按展示组取对应账本的健康度。
变更
SCHEMA_VERSION25 → 28:新增model_probes表;usage_events.api_key_id、api_keys.quota两个新列(走幂等补列);新增索引idx_usage_key。老库启动时自动迁移,无需手工操作。- 新增可热更项:
MODEL_ALIASES、STREAM_FIRST_EVENT_TIMEOUT_SECONDS、STREAM_IDLE_TIMEOUT_SECONDS、SHORT_COOLDOWN_WAIT_SECONDS、MODEL_PROBE_MINUTES、CHECKIN_TIMES、CHECKIN_JITTER_MINUTES、LOG_BUFFER_LINES、REQUEST_LOG_ENABLED。 - TRAE 上下文压缩预算按实测抬到 1M:
_CHANNEL_WINDOW_FLOOR = {"trae": 1_048_576}。实测 1,450,000 字符(1,035,544 token)答对、1,470,000 字符报4022/4026,此前按更小的窗口提前压掉了本可用的上下文。 - 后台任务由 11 类增至 12 类(新增模型主动探活)。
修复
- CodeArts 积分账与主账健康度串台(见上「管理台」):同一行出现「额度 99% + 额度耗尽」的矛盾状态。
- 签到配了时点后整天漏签:轮询周期仍是 10 分钟、而抖动 = 0 时时窗只有一分钟。
升级
docker compose pull && docker compose up -d镜像:ghcr.io/robbsluo/coding2api:v0.8.0(同时更新 :latest)。
升级注意:
- 数据库 schema 从 v25 升至 v28,启动时自动幂等迁移(建
model_probes表 + 补两列 + 建索引)。升级后必须重启后端,否则会出现「新前端 + 旧后端」错配(新端点 404,页面弹出与真实原因无关的兜底文案)。 - 新增的后台探活默认关闭(
MODEL_PROBE_MINUTES=0)——探活会真发上游请求、消耗额度。要开请在「任务与配置」页填周期(热更,不必重启),实际建议 ≥60 分钟(负缓存本身 6h 起步)。 - 三个流式 / 冷却相关开关默认全关,升级后行为与旧版一致;要启用请按部署实际填(首事件超时推荐
60,空闲超时推荐300)。