跳到正文

用脚本做协议翻译修正

跨协议翻译是网关的核心能力,但有时候你需要做些超出默认翻译的事情——按客户端协议分支处理字段、按分组注入不同参数、修正某协议的方言差异等。本章给几个 before / after 槽脚本的实战例子。

前置:先读 写第一个脚本变换 了解基本结构、挂载方式、Context API。

按 Claude Code plan 模式切换模型的完整脚本已独立成页,见 用脚本按 Claude Code plan 模式切换模型

例 1:多模态检测 + 路由切换(before 槽)

检测图片输入或联网搜索参数,切换到多模态模型。放在 before 槽request_transform_before):

javascript
function transform(body, context) {
    const proto = context.sourceProtocol;
    let hasImage = false;

    if (proto === "OpenAIChatCompletions") {
        const msgs = body.messages;
        if (Array.isArray(msgs)) {
            for (const msg of msgs) {
                if (Array.isArray(msg.content) &&
                    msg.content.some(b => b.type === "image_url")) {
                    hasImage = true;
                    break;
                }
            }
        }
    } else if (proto === "Anthropic") {
        const msgs = body.messages;
        if (Array.isArray(msgs)) {
            for (const msg of msgs) {
                if (Array.isArray(msg.content) &&
                    msg.content.some(b => b.type === "image")) {
                    hasImage = true;
                    break;
                }
            }
        }
    } else if (proto === "Google") {
        const contents = body.contents;
        if (Array.isArray(contents)) {
            for (const c of contents) {
                if (Array.isArray(c.parts) &&
                    c.parts.some(p => p.inlineData || p.fileData)) {
                    hasImage = true;
                    break;
                }
            }
        }
    }

    if (hasImage) {
        context.useModel("multimodal-model");
    }
    return body;
}

要点:

  • 必须放在 before 槽:要读客户端原始格式的图片字段,且不同协议字段名不同(OpenAI image_url、Anthropic image、Google inlineData / fileData
  • context.sourceProtocol 分支处理,否则跨协议客户端会漏判
  • context.useModel 做完整路由切换(base_url、协议、凭证一起换)

图片/联网切路由:优先用原生 switch-route(非脚本)

例 1 的 before 槽脚本能按协议分支检测图片,适合跨字段计算 / 复杂判定。但若判定只是「请求里有没有图片块 / 有没有打开联网」这类结构检查,应改用原生 request_payloadswitch-route 规则,不必写脚本:它不读写 body 内容、同协议跨协议皆可、谓词不解引用二进制字节,大请求体的磁盘暂存保持开启,不会在多模态大 body 上 OOM 或被静默跳过。

完整的条件路径写法(含 Anthropic 客户端容易漏的 tool_result 嵌套图片深层路径)、JSON 形态与验证步骤,见 把含图片的请求路由到视觉模型——那是 switch-route 的唯一权威页。只有当判定逻辑超出结构检查能表达的范围时,才回退到例 1 的脚本方式。

例 2:按访问密钥分组设置参数

根据访问密钥分组(context.accessKeyGroup)设置不同的请求参数:

javascript
function transform(body, context) {
    if (context.accessKeyGroup === "premium") {
        body.max_tokens = 8192;
    } else {
        body.max_tokens = 4096;
    }
    return body;
}

挂在 after 槽(request_transform_after),按分组差异化配额。

例 3:注入 System Prompt

javascript
function transform(body, context) {
    if (body.messages.length === 0 || body.messages[0].role !== "system") {
        const systemMsg = { role: "system", content: "You are a helpful assistant." };
        body.messages = [systemMsg, ...body.messages];
    }
    return body;
}

挂在 after 槽。简单的"不存在则注入"逻辑也可以用 request_payloadappend-if-missing 规则(性能更好),脚本适合需要复杂判断的场景。

常见问题

Q:脚本切路由后,原路由的 after 槽还会跑吗? 不会。一旦 before 槽触发了 立即 useModel 切换路由,整套 pipeline 换成目标路由的,原路由的 after 槽不执行。所以原路由和目标路由上的 request_payload 规则要各配一份。

Q:context.useModel 切换的目标模型与当前模型协议不同,能切吗? 能。before 槽支持跨协议切换。但 after 槽的 useModel 只能同协议切换——after 槽拿到的是上游格式 body,跨协议会报错。

Q:脚本跑得太慢? 脚本执行的开销主要来自 JSON 序列化/反序列化。body 越大越慢。建议简单字段操作优先用 request_payload(无序列化开销),避免不必要的 deep_clone / json_encode + json_parse

Q:脚本报 TooManyOperations 超过操作数上限(默认 2000)。优化循环,把 O(n²) 改成 O(n)。SCRIPT_MAX_OPERATIONS 可调(但建议先优化脚本)。

下一步脚本 API 参考 看完整内置函数表;脚本配置 看运行限制与配置;用脚本按 Claude Code plan 模式切换模型 看按会话标记切路由的实战。