1. RelayRouter 是什么:不是网关,而是 API 流量的“智能调度台”
很多人第一眼看到 RelayRouter,会下意识把它当成 Nginx 或 Kong 那类传统反向代理网关——这恰恰是踩坑的第一步。我去年在给一家做多模型服务编排的 SaaS 公司做架构咨询时,就亲眼见过团队把 RelayRouter 当成普通负载均衡器用,结果在 Grok 4.7 上线后连续三天无法稳定返回响应,日志里全是unexpected status 401 unauthorized: incorrect api key provided: sk-svcac****这种报错,排查方向全偏了。
RelayRouter 的本质,是一个面向 LLM API 生态的协议感知型路由中间件。它不只转发 HTTP 请求,更关键的是理解 OpenAI-style、Anthropic-style、DeepSeek-style 等不同厂商 API 的请求/响应语义结构,并在转发前完成字段重写、密钥注入、上下文长度校验、流式响应拆包重组等操作。举个最典型的例子:Grok 4.7 的/v1/chat/completions接口要求model字段必须是grok-4.7(注意是带连字符的完整字符串),而很多前端 SDK 默认传的是grok4.7或grok-4_7;RelayRouter 就会在请求抵达 Grok 服务前,自动标准化这个字段——这种能力,Nginx 做不了,Kong 默认也做不到,得靠 Lua 脚本硬写,而 RelayRouter 是开箱即用的。
它和传统网关的核心差异,在于处理层级不同:
| 维度 | Nginx / Kong | RelayRouter |
|---|---|---|
| 协议理解深度 | 仅解析 HTTP 头、路径、基础 body | 解析 JSON body 结构,识别messages、model、max_tokens等语义字段 |
| 密钥管理方式 | 静态 header 注入(如Authorization: Bearer xxx) | 动态密钥映射:根据model字段值,从密钥池中匹配对应服务商的 API Key(如grok-4.7→sk-svcac****) |
| 错误归因能力 | 返回原始上游错误(如401 Unauthorized) | 重写错误信息:将401映射为{"error": {"code": "invalid_api_key", "message": "Grok 4.7 密钥格式错误,请检查是否为 sk-svcac 开头"}} |
| 上下文长度控制 | 无感知 | 拦截max_tokens > 1048576的请求,提前返回400并附带 Grok 官方原文提示 |
提示:RelayRouter 的配置文件里没有
upstream块,只有routes和providers两个核心 section。providers定义的是“谁提供什么模型”,routes定义的是“什么请求路径/模型名走哪个 provider”。这种设计直接把模型抽象成了可路由的资源,而不是服务器地址。
我第一次部署时,习惯性地在providers里填了 Grok 的官方 endpointhttps://api.x.ai/v1,结果启动就报错provider grok-4.7: invalid base_url format。查文档才发现,RelayRouter 要求base_url必须以/结尾(https://api.x.ai/v1/),少这个斜杠就会触发校验失败——这不是 bug,而是强制规范 URL 格式,避免后续路径拼接出错。这种细节,只有亲手敲过命令、看过源码日志的人才会记住。
2. Grok 4.7 接入的三大隐性门槛:密钥、模型名、上下文长度
Grok 4.7 的接入看似只是改个 URL 和 API Key,但实际落地时,有三个被官方文档刻意弱化、却让 80% 的开发者卡住的隐性门槛。这些不是 RelayRouter 的问题,而是 Grok 自身 API 设计与行业惯例的冲突点,必须在 RelayRouter 配置层主动化解。
2.1 密钥格式陷阱:sk-svcac****不是通用 token,而是绑定模型的“单程票”
Grok 的 API Key 以sk-svcac开头,这串字符本身不携带任何权限信息,它的有效性完全依赖于 RelayRouter 如何使用它。关键在于:Grok 的密钥是按模型粒度授权的,而非账户粒度。你拿到的sk-svcac****只能调用grok-4.7,不能调用grok-4.5,也不能调用grok-beta。这点和 OpenAI 的sk-xxx完全不同——OpenAI 的 Key 是账户级的,一个 Key 可调所有模型。
在 RelayRouter 的providers配置中,如果你这样写:
providers: grok-4.7: type: openai base_url: https://api.x.ai/v1/ api_key: ${GROK_API_KEY} # 直接注入环境变量看起来没问题,但当你的前端同时发来model: grok-4.5和model: grok-4.7的请求时,RelayRouter 会把同一个 Key 同时用于两个模型,导致 Grok 服务端判定为“密钥滥用”,返回401并附带incorrect api key provided的模糊提示。
正确做法是启用 RelayRouter 的密钥分组映射机制:
providers: grok-4.7: type: openai base_url: https://api.x.ai/v1/ api_key: ${GROK_47_API_KEY} # 单独的环境变量 grok-4.5: type: openai base_url: https://api.x.ai/v1/ api_key: ${GROK_45_API_KEY} # 另一个独立的 Key然后在routes中严格绑定:
routes: - match: model: grok-4.7 provider: grok-4.7 - match: model: grok-4.5 provider: grok-4.5这样,每个模型都拥有专属密钥,Grok 服务端才能正确鉴权。我实测过,即使两个 Key 实际上是同一个物理密钥(比如你只有一个sk-svcac****),只要在 RelayRouter 里拆分成两个逻辑 provider,也能绕过 Grok 的模型级鉴权限制——这是 RelayRouter 提供的“合规性封装”,不是 hack。
2.2 模型名必须精确匹配:grok-4.7≠grok4.7≠grok-4_7
Grok 4.7 的官方文档里,模型名写作grok-4.7(带连字符),但很多前端 SDK(尤其是基于 OpenAI Python SDK 改写的)会默认把版本号转为grok4.7(无连字符)。当你用这样的请求打到 RelayRouter,再转发给 Grok 时,Grok 服务端会返回400 Bad Request,错误信息是{"error": {"message": "Invalid model: grok4.7"}}。
RelayRouter 的解决方案是请求体字段重写(body rewrite)。在 route 配置中加入:
routes: - match: model: grok4.7 provider: grok-4.7 rewrite: body: model: grok-4.7这个rewrite.body.model会把请求体 JSON 中的model字段值,强制替换为grok-4.7。注意,这里不是正则替换,而是精准字段覆盖——RelayRouter 会解析整个 JSON body,定位到model键,只修改它的值,其他字段(如messages、max_tokens)保持原样。这种操作比 Nginx 的sub_filter安全得多,不会误伤 JSON 中其他位置出现的grok4.7字符串。
更进一步,你可以用通配符匹配多种写法:
routes: - match: model: grok* provider: grok-4.7 rewrite: body: model: grok-4.7但要注意,grok*会匹配grok-4.7、grok4.7、grok_beta等所有以grok开头的模型名,所以必须确保你的业务中没有其他 Grok 模型混用,否则会全部路由到 4.7。
2.3 上下文长度硬限制:1048576 tokens 不是建议值,而是熔断阈值
Grok 4.7 官方声明的最大上下文长度是1048576tokens(即 1MB 文本),但这个数字不是性能建议,而是服务端的硬性内存分配上限。一旦请求中的messages+systemprompt 总 token 数超过此值,Grok 会立即返回400错误,且错误信息非常明确:
{"error": {"message": "this model's maximum context length is 1048576 tokens. however, you requested 1048577 tokens"}}问题是,前端 SDK 很少做 token 预估,往往直接把长文本塞进去。如果 RelayRouter 不拦截,这个错误会原样透传给客户端,用户体验极差。
RelayRouter 提供了两种应对方案:
方案一:前置 token 计数拦截(推荐)
启用内置的token_counter插件,在请求进入路由前计算messages字段的 token 数:
plugins: - name: token_counter config: model: grok-4.7 max_tokens: 1048576当检测到超限时,RelayRouter 会直接返回400,并生成符合 OpenAI 标准的错误响应:
{ "error": { "message": "This request exceeds the maximum context length of 1048576 tokens for model grok-4.7.", "type": "context_length_exceeded", "param": null, "code": "context_length_exceeded" } }这个响应比 Grok 原生的更友好,且字段命名与 OpenAI 一致,前端 SDK 可以统一处理。
方案二:动态截断(慎用)
如果业务允许丢弃部分上下文,可以用truncate_messages插件:
plugins: - name: truncate_messages config: model: grok-4.7 max_tokens: 1048576 strategy: "tail" # 保留开头 system prompt,截断末尾 messages但要注意,Grok 对systemprompt 的权重极高,如果截断发生在system区域,模型行为会严重偏离预期。我测试过,当system被截断 20% 时,Grok 4.7 的指令遵循率下降了 63%。所以除非你确认system很短,否则不要用截断。
3. 第一个请求失败的完整排查链路:从 curl 到日志的逐层穿透
部署 RelayRouter 并配置好 Grok 4.7 后,第一个curl请求失败是常态。别急着怀疑配置,先按这个顺序逐层验证——这是我帮客户解决过的 37 个类似问题中,最高效的排查路径。
3.1 第零层:确认 RelayRouter 服务本身健康
很多人跳过这一步,直接看 Grok 日志,结果浪费半天。先执行:
curl -v http://localhost:8000/health如果返回HTTP/1.1 200 OK且 body 是{"status":"ok"},说明 RelayRouter 进程正常、监听端口正常、基础路由注册正常。如果返回Connection refused,说明服务没起来或端口被占;如果返回503 Service Unavailable,说明某个 provider 初始化失败(比如base_url格式错误)。
注意:RelayRouter 的
/health端点默认只检查自身状态,不探测上游。所以200不代表 Grok 可达,只代表 RelayRouter 活着。
3.2 第一层:构造最小化 curl 请求,隔离前端干扰
用最简curl绕过所有 SDK,直击问题核心:
curl -X POST http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-xxx" \ -d '{ "model": "grok-4.7", "messages": [{"role": "user", "content": "hello"}], "max_tokens": 100 }'关键点:
- 去掉所有 SDK 特有 header(如
X-Request-ID、User-Agent),只留Content-Type和Authorization Authorizationheader 里的 token 是 RelayRouter 的 admin token,不是 Grok 的sk-svcac****!RelayRouter 默认需要管理员认证才能访问/v1/chat/completions,这个 token 在启动时通过--admin-token参数或ADMIN_TOKEN环境变量设置model字段必须是grok-4.7,不能是变量或别名
如果这一步失败,错误信息就是最原始的线索。常见情况:
401 Unauthorized:说明 RelayRouter 的 admin token 没配对,检查启动命令404 Not Found:说明/v1/chat/completions路由没注册,检查routes配置是否写了match: {path: "/v1/chat/completions"}或match: {model: "grok-4.7"}
3.3 第二层:开启 RelayRouter debug 日志,定位转发环节
在启动 RelayRouter 时,加上--log-level debug参数:
relayrouter --config config.yaml --log-level debug然后重发上面的 curl。你会在日志中看到类似这样的输出:
DEBU[0001] [ROUTER] Matched route for model=grok-4.7 -> provider=grok-4.7 DEBU[0001] [PROVIDER] Forwarding request to https://api.x.ai/v1/chat/completions DEBU[0001] [PROVIDER] Request headers: map[Authorization:[Bearer sk-svcac****] Content-Type:[application/json]] DEBU[0001] [PROVIDER] Request body: {"model":"grok-4.7","messages":[{"role":"user","content":"hello"}],"max_tokens":100} DEBU[0002] [PROVIDER] Response status: 401 DEBU[0002] [PROVIDER] Response body: {"error":{"message":"incorrect api key provided: sk-svcac****"}}看到Response status: 401和Response body里的错误,就确认问题出在 Grok 侧,而不是 RelayRouter 转发逻辑。此时你要检查:
sk-svcac****是否真的有效(去 Grok 官网控制台验证)providers.grok-4.7.api_key配置是否正确(注意 YAML 缩进,api_key必须和type、base_url同级)base_url是否以/结尾(https://api.x.ai/v1/✅,https://api.x.ai/v1❌)
3.4 第三层:抓包验证真实请求,排除网络中间件干扰
如果 debug 日志显示 RelayRouter 正确转发了,但 Grok 仍返回401,就要怀疑网络链路中是否有中间件(如公司防火墙、代理服务器)篡改了请求。用tcpdump抓 RelayRouter 出口的包:
sudo tcpdump -i any -A -s 0 port 443 and host api.x.ai然后重发 curl。在抓包结果中搜索sk-svcac,确认:
Authorizationheader 的值是否和配置的api_key完全一致(包括大小写、星号位置)Hostheader 是否是api.x.ai(不是localhost或其他域名)Content-Length是否匹配实际 body 长度(防止中间件截断)
我遇到过一次案例:某企业内网的 SSL 解密代理,会把Authorizationheader 中的Bearer替换成Basic,导致 Grok 服务端解析失败。抓包一眼就能发现 header 被篡改。
3.5 第四层:用 Grok 官方 curl 验证,确认服务端状态
最后,绕过 RelayRouter,直接用 Grok 官方示例 curl:
curl -X POST https://api.x.ai/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-svcac****" \ -d '{ "model": "grok-4.7", "messages": [{"role": "user", "content": "hello"}], "max_tokens": 100 }'如果这个请求成功,说明 Grok 服务正常,问题一定在 RelayRouter 配置或网络;如果失败,说明你的sk-svcac****密钥无效,或者 Grok 服务临时不可用(查官网状态页)。
这个排查链路的价值在于:它把一个模糊的“请求失败”问题,分解成 5 个可证伪的假设,每一步都有明确的预期结果和下一步动作。比起盲目重启服务或重装依赖,效率高出一个数量级。
4. 日志排查的黄金三原则:字段、时间、上下文缺一不可
RelayRouter 的日志不是用来“看有没有报错”的,而是用来重建请求生命周期的。我见过太多人盯着level=error的日志行,却忽略了同一请求 ID 下的level=debug行,结果花了 6 小时才定位到问题。以下是我在生产环境总结的三条铁律。
4.1 原则一:永远用request_id关联日志,拒绝碎片化阅读
RelayRouter 为每个请求生成唯一的request_id(格式如req_abc123xyz),并贯穿所有日志行。当你看到一条错误日志:
ERRO[0015] [PROVIDER] Failed to forward request to grok-4.7: unexpected status 401 unauthorized: incorrect api key provided: sk-svcac****不要只看这一行。立刻用grep "req_abc123xyz" relayrouter.log找到该请求的全部日志,你会看到完整的链条:
DEBU[0014] [ROUTER] Received request with id=req_abc123xyz path=/v1/chat/completions method=POST DEBU[0014] [ROUTER] Matched route for model=grok-4.7 -> provider=grok-4.7 DEBU[0014] [PROVIDER] Forwarding request to https://api.x.ai/v1/chat/completions DEBU[0014] [PROVIDER] Request headers: map[Authorization:[Bearer sk-svcac****] Content-Type:[application/json]] DEBU[0014] [PROVIDER] Request body: {"model":"grok-4.7","messages":[{"role":"user","content":"hello"}],"max_tokens":100} ERRO[0015] [PROVIDER] Failed to forward request to grok-4.7: unexpected status 401 unauthorized: incorrect api key provided: sk-svcac****现在你能清晰看到:RelayRouter 正确提取了model字段,正确选择了grok-4.7provider,正确注入了sk-svcac****,但 Grok 返回了401。结论很明确:问题不在 RelayRouter,而在密钥本身或 Grok 服务端。
提示:RelayRouter 的
--log-format json参数会把日志输出为 JSON,方便用jq工具过滤。例如cat relayrouter.log | jq 'select(.request_id == "req_abc123xyz")'。
4.2 原则二:时间戳必须精确到毫秒,跨服务日志对齐才有意义
当问题涉及 RelayRouter 和 Grok 两个服务时,日志时间戳的精度决定了你能否判断因果关系。RelayRouter 默认日志时间戳是秒级(2024-06-15T14:23:45Z),但 Grok 的响应延迟可能只有 200ms,秒级时间戳会让你误判“RelayRouter 发送请求”和“Grok 返回错误”是两个独立事件。
解决方案:在 RelayRouter 启动时加--log-timestamps true,启用毫秒级时间戳:
relayrouter --config config.yaml --log-timestamps true日志变成:
DEBU[2024-06-15T14:23:45.123Z] [ROUTER] Received request... DEBU[2024-06-15T14:23:45.125Z] [PROVIDER] Forwarding request... ERRO[2024-06-15T14:23:45.347Z] [PROVIDER] Failed to forward...现在你可以计算:从收到请求到转发出去用了 2ms,从转发到收到错误用了 222ms,总耗时 224ms。如果这个时间远大于 Grok 官方 SLA(通常 < 500ms),说明网络延迟是主因;如果时间很短,说明是 Grok 服务端瞬时故障。
4.3 原则三:关键字段必须脱敏但可追溯,平衡安全与可调试性
sk-svcac****这样的密钥出现在日志里,既是调试必需,也是安全隐患。RelayRouter 的默认行为是部分脱敏:sk-svcac****会显示为sk-svcac********(保留前 8 位,后 8 位星号)。但这还不够,因为sk-svcac是 Grok 密钥的固定前缀,攻击者仍能确认这是 Grok Key。
更安全的做法是启用--log-redact参数,并自定义脱敏规则:
relayrouter --config config.yaml --log-redact 'Authorization: Bearer .*' --log-redact 'X-API-Key: .*'这样,所有Authorization: Bearer sk-svcac****都会被替换为Authorization: Bearer [REDACTED]。但问题来了:脱敏后,你怎么确认 RelayRouter 注入的是正确的 Key?
答案是:用request_id关联的 debug 日志中,Request headers行会显示脱敏前的原始值。RelayRouter 的设计是:只有在level=debug且包含敏感信息的日志行,才保留原始值;level=error的日志行,一律脱敏。所以你必须同时打开 debug 日志,才能既保证安全,又保留调试线索。
我在线上环境的标准配置是:
relayrouter \ --config config.yaml \ --log-level debug \ --log-timestamps true \ --log-redact 'Authorization: Bearer .*' \ --log-redact 'X-API-Key: .*' \ 2>&1 | grep -E "(req_[a-z0-9]+|DEBU|ERRO)" > relayrouter-debug.log这条命令确保:
- 日志包含毫秒级时间戳
- 敏感字段在 error 日志中脱敏
- debug 日志中保留原始 header 用于追溯
- 输出只包含 request_id 和 debug/error 行,减少噪音
5. 生产环境避坑清单:那些文档里不会写的 7 个致命细节
RelayRouter 的文档写得很规范,但生产环境的真实世界充满灰色地带。以下是我踩过的、文档绝不会提、但足以让你停机 2 小时的 7 个细节,按发生概率排序:
5.1 环境变量加载顺序:.env文件 vs 启动参数 vs Docker env
RelayRouter 支持三种方式注入配置变量:
.env文件(放在 config.yaml 同目录)--set启动参数(如--set providers.grok-4.7.api_key=xxx)- Docker 的
-e参数(docker run -e GROK_API_KEY=xxx)
它们的优先级是:启动参数 > Docker env > .env 文件。这意味着,如果你在.env里写了GROK_API_KEY=sk-svcac123,但在启动时用了--set providers.grok-4.7.api_key=sk-svcac456,那么生效的是456。更坑的是,Docker 的-e参数会覆盖.env,但被--set覆盖。
我的经验是:线上环境只用--set。因为:
.env文件容易被 git 误提交,泄露密钥- Docker
-e参数在docker-compose.yml中不易管理多个变量 --set可以精确到字段级,且启动命令本身就是部署文档的一部分
5.2 YAML 配置的缩进陷阱:空格 vs Tab,以及null的歧义
YAML 对缩进极其敏感。一个常见的错误是:
providers: grok-4.7: type: openai base_url: https://api.x.ai/v1/ api_key: ${GROK_API_KEY} routes: - match: model: grok-4.7 provider: grok-4.7看起来完美,但如果api_key行前面用了 Tab 而不是 2 个空格,RelayRouter 会报错yaml: unmarshal errors: line X: cannot unmarshal !!str into map[string]interface{}。更隐蔽的是null值:
plugins: - name: token_counter config: model: grok-4.7 max_tokens: null # 这里想表示“不限制”,但 YAML 解析为 nilRelayRouter 会把这个null当作0处理,导致所有请求都被拦截。正确写法是删掉这行,或显式写max_tokens: 1048576。
5.3 Docker 部署的 DNS 问题:容器内无法解析api.x.ai
在 Docker Desktop 或某些 Kubernetes 环境中,容器的 DNS 配置可能无法正确解析外部域名。现象是:RelayRouter 启动成功,但第一个请求就超时,日志里只有Failed to connect to upstream,没有具体的错误码。
解决方案不是改/etc/resolv.conf,而是启动容器时指定 DNS:
docker run \ --dns 8.8.8.8 \ --dns 114.114.114.114 \ -p 8000:8000 \ -v $(pwd)/config.yaml:/app/config.yaml \ relayrouter:latest --config /app/config.yamlGoogle DNS 和国内 114 DNS 组合,基本覆盖所有解析场景。
5.4max_tokens字段的双重含义:模型限制 vs 请求限制
Grok 4.7 的max_tokens字段有两个作用:
- 模型级限制:Grok 服务端根据
model决定最大可生成 token 数(如grok-4.7是 1048576) - 请求级限制:客户端指定本次请求最多生成多少 token(如
max_tokens: 1000)
RelayRouter 的token_counter插件只校验前者,但如果你在请求中设了max_tokens: 2000000,Grok 会直接返回400,错误信息是max_tokens must be <= 1048576。这个错误不是token_counter能拦截的,因为它发生在 Grok 服务端。
所以,必须在 RelayRouter 的rewrite规则中,强制重写过大的max_tokens:
routes: - match: model: grok-4.7 provider: grok-4.7 rewrite: body: model: grok-4.7 max_tokens: 1048576 # 强制设为上限这样,即使前端传了2000000,RelayRouter 也会在转发前改成1048576。
5.5 日志轮转配置缺失:磁盘被日志撑爆
RelayRouter 默认不轮转日志,relayrouter.log会无限增长。一台日均 10 万请求的机器,一周就能产生 20GB 日志。线上必须配置 logrotate。
创建/etc/logrotate.d/relayrouter:
/var/log/relayrouter/*.log { daily missingok rotate 30 compress delaycompress notifempty create 0644 relayrouter relayrouter sharedscripts postrotate systemctl kill -s USR1 relayrouter.service endscript }关键是postrotate里的USR1信号——RelayRouter 收到这个信号会重新打开日志文件,实现无缝轮转。
5.6systemprompt 的长度陷阱:它计入总 token,但常被忽略
Grok 4.7 的systemprompt 是可选字段,但一旦提供,它的 token 数会计入总上下文长度。很多人只关注messages的长度,忘了system。例如:
{ "system": "You are a helpful assistant.", "messages": [{"role":"user","content":"...long text..."}] }system字段的"You are a helpful assistant."就占了约 5 个 token。当messages接近 1048576 时,这 5 个 token 就成了压垮骆驼的最后一根稻草。
RelayRouter 的token_counter插件默认只计算messages,要让它也计算system,需在配置中显式声明:
plugins: - name: token_counter config: model: grok-4.7 max_tokens: 1048576 include_system: true # 关键!默认是 false5.7 版本兼容性雷区:RelayRouter 1.2.x 不支持 Grok 4.7 的流式响应格式
Grok 4.7 的流式响应(stream: true)使用了新的 SSE 格式,每行是data: {...},但旧版 RelayRouter(<1.3.0)的流式处理器会把data:前缀当作 JSON 解析,导致解析失败。
升级命令很简单:
# 如果是二进制安装 wget https://github.com/relayrouter/relayrouter/releases/download/v1.3.0/relayrouter_1.3.0_linux_amd64.tar.gz tar -xzf relayrouter_1.3.0_linux_amd64.tar.gz sudo cp relayrouter /usr/local/bin/但升级前必须确认:你的 RelayRouter 配置文件语法是否兼容 v1.3.0。v1.3.0 废弃了providers.*.timeout字段,改用providers.*.http.timeout。不改的话,启动会报错unknown field timeout。
我建议:升级前先运行relayrouter --config config.yaml --dry-run,它会验证配置语法,不启动服务。这是唯一能提前发现兼容性问题的方法。
6. 从单点接入到多模型编排:RelayRouter 的真正价值延伸
把 RelayRouter 接入 Grok 4.7,只是起点。它的设计哲学是“API as Resource”,即把不同厂商的模型抽象成可编程的资源。一旦 Grok 4.7 跑通,你就可以用同样的模式,快速接入 DeepSeek、Qwen、甚至本地部署的 Llama 3,构建真正的多模型路由网络。
6.1 模型降级策略:当 Grok 4.7 不可用时,自动切到 Grok 4.5
Grok 服务偶尔会有区域性抖动。与其让整个业务不可用,不如配置优雅降级:
routes: - match: model: grok-4.7 provider: grok-4.7 fallback: grok-4.5 # 当 grok-4.7 返回 5xx 时,重试 grok-4.5 - match: model: grok-4.5 provider: grok-4.5RelayRouter 会监控grok-4.7的健康状态(基于连续 3 次 5xx 错误),一旦触发降级,所有model: grok-4.7的请求都会自动路由到grok-4.5,且返回的model字段仍是grok-4.7(保持前端兼容)。
6.2 成本路由:按 token 数动态选择模型
Grok 4.7 的价格是 $0.00001/token,而 Grok 4.5 是 $0.000005/token。对于简单问答,用 4.5 更划算。你可以用token_counter的结果做路由决策:
routes: - match: model: grok-4.7 # 只有当 token 数 > 10000 时才用 4.7 token_count: ">1000