V1.8.8 - #1386
Merged
Merged
V1.8.8#1386
Conversation
…ocolPaths) Providers mount OpenAI/Anthropic compatible APIs under different base paths (e.g. Bailian /compatible-mode/v1 vs /apps/anthropic, Kimi Code /coding/v1 vs /coding, Volcengine /api/v3). AIConf.ProtocolPaths maps a model protocol to the provider's upstream base path (the path part of the protocol SDK base_url); doSingleAIForward rewrites standard /v1/... entry paths to the configured prefix for the detected protocol. - AIConf: new ProtocolPaths field; AIConfCheck rejects unknown protocol keys and malformed values at load time (same precedent as ValidateProtocols) - bfe_server/ai_path_rewrite.go: rewriteUpstreamPath formula (anthropic appends full path, openai strips /v1) and applyAIProtocolPathRewrite which writes a private URL copy so the inbound request is never mutated and every cluster attempt (incl. route-level fallback) recomputes from the original client path - reverseproxy.go: invoke the rewrite in doSingleAIForward - tests: unit tests for formula/validation/fallback-recompute; new SC17 integration scenario (6 cases, real BFE process) - docs: sys_design/ai_protocol_paths.md, modifications record, zh/en configuration reference Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
feat(ai_gateway): add per-protocol upstream path rewrite (AIConf.ProtocolPaths)
improve wrr and wlc
- EPPTLSConf 新增 Plaintext 字段:明文拨号,与 Insecure/CAFile 互斥,fail-fast 校验
- GslbBasicConfCheck 对 nil EPPTLS 自动填充 {Insecure: true},告警移至填充点,
将原"缺省配置退化为仅 Insecure"的 legacy 语义形式化
- buildEPPRuntimeConf 删除 nil 分支(由 check 保证非 nil)
- epp.NewGrpcConn 增加 plaintext 参数;epp_runtime 的 newEPPRuntime/probe 按 plaintext
使用 insecure.NewCredentials()
- 运维约束:滚动升级须先全量升 BFE 二进制再下发含 Plaintext 的配置
(旧 BFE 忽略未知字段将退化为无 CAFile 的 TLS 配置并拒绝加载)
修改说明:docs/zh_cn/modifications/2026-09-14-epp-plaintext-dial/
Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
feat(epp): EPP client 增加明文拨号选项,EPPTLS 默认值形式化
rewriteUpstreamPath 的 openai 分支由"仅改写 /v1 标准入口"改为"上游 API 基路径"语义:剥离可选 /v1 前缀后命中 OpenAI 标准端点(chat/completions、 embeddings、models 等 allowlist)即拼接到 base,否则原样透传。带不带 /v1 入口不再影响最终上游路径(Trae 等直连 base_url 的客户端场景), provider 原生路径与自定义路径的透传模式不受影响;anthropic/gemini 分支、fallback 重算语义不变。 - 新增 stripV1Prefix / isOpenAIEndpoint 纯函数,端点表与 DetectModeFromPath 口径对齐 - 单测补 issue 四场景、无 /v1 端点改写与透传保护用例 - SC17 集成测试新增 TC-07(无 /v1 入口改写)/ TC-08(无 /v1 入口 未配置透传)及配套设计文档 - 修复方案文档:docs/zh_cn/modifications/2026-09-21-openai-path-rewrite-no-v1-entry/ Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
DetectModeFromPath 原只认 /v1/... 前缀,不带 /v1 的非 chat 端点请求 (/embeddings、/images/generations 等)被误识别为 ModeChat:价差端点 按 chat 价误计费(多收),图像/视频按次计数的提取被 mode 门控跳过。 issue #1379 的改写修复使这类请求从上游 404 变为成功,误计费可达面 扩大,本期修复。 - 新增 bfe_basic/openai_endpoint.go:openAIEndpointModes 端点表 + IsOpenAIEndpoint/StripV1Prefix 共享函数 - DetectModeFromPath 重写为"剥离可选 /v1 前缀 + 查共享表",删 10 个 硬编码分支;带 /v1 路径、/v10/xxx、/v1beta/... 等行为逐字节不变 - bfe_server 改写公式改调共享表,删 openAIEndpoints/isOpenAIEndpoint/ stripV1Prefix 私有副本,改写 eligible 与计费 mode 强制同一份定义 - 单测:DetectModeFromPath 全矩阵(带/不带 /v1 对照 + 边界) - SC05 集成新增 TC-16:断言 PB access log 的 AiMode 不依赖客户端 入口是否带 /v1;SC05 场景说明/总体说明同步(补登 TC-15) - 修复方案文档:docs/zh_cn/modifications/2026-09-21-ai-mode-detect-no-v1-entry/ (前序 openai-path-rewrite-no-v1-entry §5.3 已知限制同步标注解决) Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
fix 1 issue
#1381) Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
…t 模式致价格 miss (fixes #1382) Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
fix 2 issues
…400 误拒 (fixes #1384) Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
fix(token_auth): token model 白名单校验支持 gemini 路径 model,原生 Gemini 请求不再被400 误拒 (fixes #1384)
模型 allow/block 校验从鉴权期(请求体原始模型)后移到转发期,校验对象改为 computeTargetModel 输出(路由目标覆盖+裁剪前缀+模型重定向后的最终模型): - 新增 mod_ai_token_auth.ValidateTargetModel,经 TokenAuthContext 取有效列表 - doSingleAIForward 在 clusterInvoke 前注入校验,本地 400 停 key 轮换、 集群级 fallback 按各 attempt 目标模型复校验 - fallback 成功时清除残留 RejectReason,避免成功请求日志带拒绝原因 新增集成场景 SC18(6 TC) 与设计文档;SC16/SC08 回归通过 Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
#1387 姊妹卡) - bfe_module 新增 AI 转发阶段回调点 HandleAfterAITargetModel(目标模型解析后、转发前,按集群 attempt 触发) - mod_ai_rate_limit 迁移到该回调点:TPM/RPM/最大并发按 targetModel 匹配;PolicyLimiterContext 兼作每请求一次幂等守卫 - mod_ai_token_auth 的 allow/block 目标模型校验一并迁移(GetModule 硬编码注入移除,注册序保证先于限流) - 本地限流 429 置 bfe_basic.ErrAiRateLimit(sentinel 全局化):key 轮换与集群 fallback 双守卫阻断,上游 429 行为不变 - 集成测试:新场景 SC19 六 TC;回归 SC18/SC07/SC02/SC08/SC03 全绿 - 设计文档:docs/zh_cn/modifications/2026-09-23-issue-1387-sister-rate-limit-models-target-model/ Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
…ubset 语义 (fixes #1389) #1381 设计前提有误:OpenAI Responses API 的 input_tokens 已含 cached_tokens (total = input + output,subset 语义,同 Chat Completions/Gemini),代码据此实现的 PromptTokens += CacheRead + CacheWrite 归一化导致 cached tokens 重复计费: - 未配 cache 价格:虚增后的 PromptTokens 全按 input 价计(fixture 100/50/20 实扣 220000,应扣 200000) - 已配 cache 价格:cached 同时计入 normalInput(input 全价)与 cache 项,同样多扣 cached×input 价 修复: - usage_parse.go 删除 Responses 链 additive 归一化,PromptTokens 直接取 input_tokens; Anthropic 链归一化(input_tokens 不含 cache)保留不动 - 单测预期更正(140→100、90→80、140→100) - SC03 fixture 改为合法 subset 形态(input 10000 含 cached 8000),TC-18/19/20 扣减重算 仍为 900000;新增 TC-21 无 cache 价格回归(issue 受控 fixture,期望扣减 200000) - 测试设计文档 TC-18/19/20 同步更正、新增 TC-21 文档,场景说明补用例清单 - #1381 设计文档追加更正标注;sys_design(rmb_quota/model_protocol_adapter)补记录 Responses 解析链与 subset 语义、复数字段优先(单数兼容) 验证:gofmt/go vet 干净;相关包 go test 全部 ok;SC03 集成测试 TC-01~TC-21 全绿 设计文档:docs/zh_cn/modifications/2026-09-24-issue-1389-responses-api-cached-tokens-double-billing/ Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
fix(billing): Responses API cached_tokens 重复计费,删除误加的 additive 归一化恢复 subset 语义 (fixes #1389)
#1391) mod_access_pb3 的 reqTimeInfoGen 计算 proxy_delay_time 时未校验 BackendFirst 有效性:未调用后端即结束的请求(401 鉴权拒绝、无路由 404、redirect、close) BackendFirst 保持 time.Time 零值,zero.Sub(ReadReqEnd) 饱和到 math.MinInt64, uint32 截断后成为恒定垃圾值 2217714954(> MySQL INT 上限 2147483647), log-reader mod_log_mysql 批量 INSERT 报 Error 1264,整批(含正常行)重试 耗尽后丢弃(观测窗口 5 次丢批、至少 17 行)。 修复: - request_log.go 新增 durationMsUint32 helper(IsZero + ms>=0 双防护), ClusterServeTime/BackendServeTime/WriteClientTime/SessionOffsetTime/ ProxyDelayTime 五字段收口;未调用后端/负值一律写 0 - 同函数次生隐患一并消除:SessionOffsetTime 在 BfeHandlerClose 路径 (ResponseEnd 零值)同样会回绕溢出 - 单测新增 4 例(401 同构/正常精确值/close 同构/helper 表驱动 6 臂) - SC05 集成测试新增 TC-18(401 无效 Key 臂 + 429 配额耗尽臂,断言耗时 字段为 0 且不超 math.MaxInt32),sendRequestToPath 重构委托 sendRequestWithKey - 测试设计文档新增 TC-18、场景说明同步 验证:mod_access_pb3 单测全过;gofmt/go vet 干净;SC05 集成测试 TC-01~TC-18 全绿 设计文档:docs/zh_cn/modifications/2026-09-24-issue-1391-proxy-delay-time-overflow-fix/ Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
fix(access_log): 未调用后端请求 proxy_delay_time 溢出,uint32 回绕值致下游落库整批丢弃 (fixes #1391)
Signed-off-by: zhangmiao <zhangmiao@yf-networks.com>
chore(release): prepare v1.8.8 release
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.