综合小项目:用 Python 构建可解释的 AI 模型路由器

举报
时光不写 发表于 2026/10/12 16:51:39 2026/10/12
【摘要】 前面的系列已经介绍了模型调用、提示词、上下文、成本、错误处理、评估和工作流。实际应用中,所有请求都交给同一个模型并不一定合理:简单改写可能不需要高成本模型,复杂分析则可能需要更强的模型。本篇做一个综合小项目:先用确定性的规则判断任务类型,再根据配置选择模型,最后记录路由理由和调用结果。重点不是“自动猜得多聪明”,而是让选择过程可解释、可测试、可替换。 先定义路由边界路由器接收一份任务,任务包...

前面的系列已经介绍了模型调用、提示词、上下文、成本、错误处理、评估和工作流。实际应用中,所有请求都交给同一个模型并不一定合理:简单改写可能不需要高成本模型,复杂分析则可能需要更强的模型。本篇做一个综合小项目:先用确定性的规则判断任务类型,再根据配置选择模型,最后记录路由理由和调用结果。重点不是“自动猜得多聪明”,而是让选择过程可解释、可测试、可替换。

先定义路由边界

路由器接收一份任务,任务包含 kind 和 text 两个字段。kind 只允许 simple、analysis 和 code 三种值,分别代表简单文本处理、分析任务和代码问题。程序根据类型读取环境变量中的模型名:

  • MODEL_SIMPLE:处理短文本改写等低复杂度任务。
  • MODEL_ANALYSIS:处理需要较长上下文的分析任务。
  • MODEL_CODE:处理代码解释或调试问题。

这不是让模型自己决定调用哪个模型,而是把路由规则放在 Python 中。规则越明确,越容易写测试、估算成本,也越容易在出现异常时解释“为什么用了这个模型”。生产系统还可以把规则改成配置文件,加入长度、租户、预算或人工指定的覆盖项。

准备环境变量

在独立虚拟环境中安装官方 Python SDK:

python -m venv .venv
source .venv/bin/activate
python -m pip install openai

然后配置密钥和模型名。下面只是占位符,真实密钥只能通过环境变量提供:

export OPENAI_API_KEY="替换为你的真实密钥"
export MODEL_SIMPLE="替换为可用的轻量模型"
export MODEL_ANALYSIS="替换为可用的分析模型"
export MODEL_CODE="替换为可用的代码模型"

模型名称必须以你实际使用的服务商文档为准,不要因为模型名看起来相似就假定它一定可用。

编写最小路由器

新建 router.py:

import json
import os
import sys
from dataclasses import dataclass

from openai import OpenAI


@dataclass(frozen=True)
class Route:
    model: str
    reason: str


def choose_route(kind: str) -> Route:
    routes = {
        "simple": Route(os.environ["MODEL_SIMPLE"], "简单任务使用轻量模型"),
        "analysis": Route(os.environ["MODEL_ANALYSIS"], "分析任务使用分析模型"),
        "code": Route(os.environ["MODEL_CODE"], "代码任务使用代码模型"),
    }
    try:
        return routes[kind]
    except KeyError as exc:
        allowed = ", ".join(routes)
        raise ValueError(f"kind 必须是:{allowed}") from exc


def load_task(path: str) -> dict:
    with open(path, encoding="utf-8") as file:
        task = json.load(file)
    if not isinstance(task.get("kind"), str):
        raise ValueError("kind 必须是字符串")
    if not isinstance(task.get("text"), str) or not task["text"].strip():
        raise ValueError("text 必须是非空字符串")
    return task


def run(task: dict) -> dict:
    route = choose_route(task["kind"])
    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
    response = client.responses.create(
        model=route.model,
        instructions="用中文回答,直接处理用户任务,不要解释路由过程。",
        input=task["text"],
    )
    return {
        "model": route.model,
        "reason": route.reason,
        "output": response.output_text.strip(),
    }


def main() -> None:
    if len(sys.argv) != 2:
        raise SystemExit("用法:python router.py task.json")
    result = run(load_task(sys.argv[1]))
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()

创建输入文件 task.json:

{
  "kind": "code",
  "text": "解释 Python 中列表推导式的基本写法,并给出一个简短例子。"
}

运行:

python router.py task.json

程序会实际调用所选模型,并输出模型名、路由理由和本次返回的文本。这里不能预先写死模型回答,因为结果取决于你的服务、模型版本和请求状态;可验证的事实是路由函数选择了配置中的对应模型,网络调用成功后才会有 output。

为什么把路由和调用分开

choose_route 是纯函数式的确定性逻辑,不需要网络,也不需要密钥。它可以单独测试:

assert choose_route("simple").reason == "简单任务使用轻量模型"
assert choose_route("code").model == os.environ["MODEL_CODE"]

网络请求只集中在 run 中。这样做有两个好处:第一,路由规则错误不会被 API 异常掩盖;第二,测试时可以替换客户端,避免每次测试都消耗额度。更进一步,可以让 run 接收一个客户端参数,生产环境传入真实客户端,测试环境传入返回固定文本的假客户端。

加上长度与预算保护

类型路由只是第一层规则。用户把一篇很长的文档标成 simple,仍可能造成上下文超限或费用异常。因此,调用前应做输入长度检查,并为每类任务设置预算。例如,先限制字符数:

MAX_CHARS = {"simple": 4000, "analysis": 20000, "code": 12000}


def validate_size(task: dict) -> None:
    limit = MAX_CHARS[task["kind"]]
    if len(task["text"]) > limit:
        raise ValueError(f"输入超过 {limit} 个字符")

这不是精确的 token 计算,中文、代码和不同 tokenizer 的比例都可能不同;它只是一个便宜的第一道保护。涉及严格上下文窗口时,应按实际模型文档和 tokenizer 估算,并在日志中记录输入长度、模型、耗时和错误类型,不要记录密钥或未经脱敏的敏感正文。

常见问题

为什么不直接让模型选择模型? 模型选择本身也要消耗一次调用,而且结果不稳定、难审计。可以把模型建议作为候选信息,但最终选择应受代码规则、预算和权限约束。

模型名称配置错误怎么办? SDK 通常会返回认证、请求或模型不存在等错误。不要无限重试这类配置错误;启动时可以检查必需环境变量是否存在,并把错误写到标准错误。实际项目还应设置请求超时和有限重试。

多个模型的提示词可以完全相同吗? 不一定。不同模型支持的输入格式、参数和能力可能不同。示例使用 Responses API 的共同字段,但接入其他服务时必须查阅其官方文档确认兼容性。

路由后如何证明成本下降? 不能凭一次调用下结论。应准备固定任务集,记录每次的模型、输入输出 token、延迟、错误和质量评分,再与统一使用单一模型的基线比较。模型更便宜不代表总成本更低,如果返工和失败更多,整体成本可能上升。

小结

本项目把模型路由拆成了三个清晰环节:用输入类型确定规则,用环境变量提供模型配置,用独立函数记录选择理由,再由统一调用层取得结果。它没有把模型能力差异包装成绝对结论,也没有伪造 API 输出。继续工程化时,可以加入基于评测集的路由规则、预算熔断、人工覆盖和指标看板,但每一步都应保留可解释的决策记录,并为失败设计明确的降级路径。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。