# router **Repository Path**: ariacompute/router ## Basic Information - **Project Name**: router - **Description**: aria router - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-28 - **Last Updated**: 2026-11-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
# router **Aria Compute 推理网关** 一个 OpenAI 兼容的 HTTP 网关,内置**三种并列决策器**——
**semantic**(YAML v0.3 信号 → 决策)、轻量 **builtin agent**
(进程内固定工具 + 限 turns)、以及 **afm-d**(经 aria-engine 的 System One Choice)
——共享 providers、硬约束与转发。 [English](./README.md) · **简体中文** · [文档](./AGENTS.md) · [发布说明](./releasenotes_cn.md) [![][release-shield]][release-link] [![][rust-shield]][rust-link] [![][license-shield]][license-link] [![][lastcommit-shield]][lastcommit-link]
[![][routers-shield]][routers-link] [![][sdk-shield]][sdk-link] [![][coverage-shield]][coverage-link] [![][dashboard-shield]][dashboard-link]
Table of contents #### TOC **上手** - [✨ 功能](#-功能) - [🚀 快速开始](#-快速开始) - [🧰 命令行](#-命令行) - [🧪 用户视角 E2E 测试](#-用户视角-e2e-测试) - [🔧 配置](#-配置) **部署与服务** - [🛳 Release 资产](#-release-资产) - [🔌 OpenAI API](#-openai-api) - [🔐 API 密钥与成本](#-api-密钥与成本) - [🌐 Dashboard](#-dashboard) **内部机制** - [🧭 三种决策器](#-三种决策器) - [🔗 ContextHold](#-contexthold) - [🧩 SDK 绑定](#-sdk-绑定) - [📊 Bench](#-bench) - [⚖️ 特性对比](#-特性对比) **信任与治理** - [🔏 信任库安全](#-信任库安全) - [🔨 开发](#-开发) - [📚 文档](#-文档) - [📝 许可证](#-许可证) - [🤝 工程约定](#-工程约定)
## ✨ 功能 aria-router 为 OpenAI 兼容网关回答一个问题:*这条请求该由哪个模型回答,又受哪些约束?* 答案绝不是写死的单一目标。入口名映射到三条决策路径之一;硬约束在排名之前剪枝;任何落选路径都回落到失败关闭的决策。 - 🔀 **三种并列决策器** —— `semantic`(信号→决策)、`agent`(进程内 builtin 工具循环)、`afm-d`(System One Choice)。一次请求不会串跑其中多种。 - 🔒 **排名前先硬约束剪枝** —— location / auth / modality / tools 先剪枝;Compute 只进排名;无合格路径 → fail closed。 - 🧠 **AFM-D System One Choice** —— 模糊请求打到 `POST {endpoint}/v1/systemone`(aria-engine);低分保护与失败关闭回落保证决策安全。 - 🪶 **轻量 builtin agent** —— 进程内固定工具 + 有限 `max_turns`,`submit_route` → 类型化 `RouteDecision`;无 subprocess harness。 - 🔌 **OpenAI 兼容 HTTP** —— 数据面(`/v1/chat/completions`、`/v1/models`)+ 管理面(health、validate、replay、providers、topology、playground、dashboard)。 - 🔑 **多租户鉴权与计费** —— API key、OAuth、Users,以及六因子成本视图;实名 provider 模型 bypass recipe,直打后端。 - 🧩 **原生 C ABI + 八语言 SDK** —— `ariacompute-router-ffi` / `libaria-router_ffi`,含 Rust、Python、Go、TypeScript、React Native、Flutter、Swift、Kotlin 封装。 - 📊 **可观测与证据** —— 能力感知降级、ContextHold 前缀复用、显式重判边界、离线策略一致性报告。 - 🖥 **生产级 Dashboard** —— 单色、扁平、可访问的 Vite React SPA(无 Grafana、无 ML wizard)。
[![][back-to-top]](#readme-top)
## 🚀 快速开始 ```bash # 写入 ~/.ariacompute/router.yml(semantic-gateway / agent-gateway / afm-d-gateway) # 以及 ~/.ariacompute/router-cli.yml(upgrade_url,供 `aria-router upgrade`)。 # 交互:template → models(base_url、api_key_env 变量名、gateway API key、 # 三档 provider_model_id;agent 另有 endpoint/model/fallback; # afm-d 另有 System One endpoint/fallback)→ admin → upgrade_url。 # CI:--template + --admin-user + --admin-password 跳过 models 提示(用 gateway 默认)。 cargo run -p aria-router -- setup cargo run -p aria-router -- setup --status # 从 GitHub/Gitee Releases 更新 CLI + libaria-router_ffi(需先 setup 写 upgrade_url) cargo run -p aria-router -- upgrade cargo run -p aria-router -- upgrade 0.1.0 # 校验(setup 后默认路径,或传 --config) cargo run -p aria-router -- validate # 服务 — 数据面来自 YAML listeners(示例均为 127.0.0.1:8899); # 管理面默认 127.0.0.1:8080。setup 后可省略 --config。 # 离线 CI / 演示(无需 GATEWAY_API_KEY):显式 --config *-tiny.yaml cargo run -p aria-router -- serve \ --config config/examples/semantic-tiny.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 ``` `--bind` 是 **数据面**(`POST /v1/chat/completions`、`GET /v1/models`)。`--mgmt-bind` 是 **管理面**(`/health`、validate、replay、providers、config、topology、playground chat,以及运维 Dashboard)。一次请求不会串跑 semantic、agent、afm-d 中的多种。实名 provider **bypass** recipe,直打该后端。 ### 服务示例 ```bash # 若要让 --mgmt-bind 避开 engine 的 8080,请勿与 aria-engine 同端口。 # 日常 semantic 黄金路径(ariacompute/semantic-auto → local/general) cargo run -p aria-router -- serve \ --config config/examples/semantic-tiny.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # Semantic catalog(ariacompute/semantic-auto + ariacompute/semantic-catalog;catalog chat → Unsupported) cargo run -p aria-router -- serve \ --config config/examples/semantic.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # Stateful semantic(retention sticky + stores.memory / semantic_cache / replay;无需 ML 权重) cargo run -p aria-router -- serve \ --config config/examples/semantic-stateful.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # 日常 agent 黄金路径(ariacompute/agent-auto;builtin tool-loop) cargo run -p aria-router -- serve \ --config config/examples/agent-tiny.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # Agent catalog(ariacompute/agent-auto + ariacompute/agent-catalog;catalog chat → Unsupported) cargo run -p aria-router -- serve \ --config config/examples/agent.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # 日常 AFM-D 黄金路径(ariacompute/afm-d-auto;无 endpoint → first-eligible) cargo run -p aria-router -- serve \ --config config/examples/afm-d-tiny.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # AFM-D catalog(ariacompute/afm-d-auto + ariacompute/afm-d-catalog) cargo run -p aria-router -- serve \ --config config/examples/afm-d.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # Aria Gateway 后端(先 export GATEWAY_API_KEY)。与 setup 默认拓扑相同。 # providers.models[].tier 标注 small/mid/large;provider_model_id 为可替换上游 id。 export GATEWAY_API_KEY=… cargo run -p aria-router -- serve \ --config config/examples/semantic-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 export GATEWAY_API_KEY=… cargo run -p aria-router -- serve \ --config config/examples/agent-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # AFM-D gateway(另需 DECISION_MODEL_URL 上的 aria-engine,默认 :8010 encoder) export GATEWAY_API_KEY=… cargo run -p aria-router -- serve \ --config config/examples/afm-d-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 ```
[![][back-to-top]](#readme-top)
## 🧰 命令行 `aria-router` 二进制有四条子命令: | 命令 | 主要参数 | 用途 | |------|----------|------| | `setup` | `--template` · `--admin-user` · `--admin-password` · `--base-url` · `--api-key-env` · `--api-key` · `--model-small` · `--model-mid` · `--model-large` · `--agent-endpoint` · `--agent-model` · `--agent-fallback` · `--afm-d-endpoint` · `--afm-d-fallback` · `--upgrade-url` | 写 `~/.ariacompute/router.yml` + `router-cli.yml` | | `validate` | `--config` | 校验 YAML 策略(setup 后默认路径) | | `serve` | `--config` · `--bind` · `--mgmt-bind` · `--no-dashboard` | 启动数据面 + 管理面 | | `upgrade [version]` | — | 从 GitHub/Gitee Releases 拉取 CLI + `libaria-router_ffi`(需 `upgrade_url`) | | `--version` | — | 打印版本 | `setup` 为交互式:template → models(`base_url`、`api_key_env` 变量名、gateway API key、三档 `provider_model_id`;agent 另有 `endpoint`/`model`/`fallback`;afm-d 另有 System One `endpoint`/`fallback`)→ admin → `upgrade_url`。API key 写入 `router.yml` 的 `backend_refs.api_key`;serve 默认加载该文件(无明文 key 时回退 `$GATEWAY_API_KEY` / `--api-key-env`)。逻辑名 `ariacompute/ariamodel-{small,mid,large}` 固定;只换上游 provider_model_id。CI:`--template` + `--admin-user` + `--admin-password` 跳过 models 提示(用 gateway 默认)。
[![][back-to-top]](#readme-top)
## 🧪 用户视角 E2E 测试 [`scripts/run-user-e2e.sh`](scripts/run-user-e2e.sh) 是一套从**用户视角**验证 router 的黑盒测试,并把每条用例映射到 `task.md` 的任务编号。**默认**只探测一个**已运行**的实例(数据面 + 管理面),不会对该实例执行编译、安装、启动、停止或升级。两个可选模式提供隔离的额外覆盖:`--with-fixtures` 用临时 YAML fixture 启动短生命周期的**本地**实例(仅使用现成二进制,独立 `ARIA_COMPUTE_HOME` 与回环端口,退出时停止),`--with-local` 执行静态 / bench / UI 审计等离线命令。两个模式都不会触碰默认实例。 ```bash # 默认数据面 :8899 / 管理面 :8090 ./scripts/run-user-e2e.sh # 显式 URL + 管理员凭据(走登录/密钥旅程) ./scripts/run-user-e2e.sh \ --data-url http://127.0.0.1:8899 --mgmt-url http://127.0.0.1:8090 \ --admin-user admin --admin-password '…' # 对生产实例安全:跳过所有写请求 ./scripts/run-user-e2e.sh --read-only # 任务编号覆盖(含隔离 fixture 场景) ./scripts/run-user-e2e.sh --list ./scripts/run-user-e2e.sh --self-test ./scripts/run-user-e2e.sh --with-local --with-fixtures ./scripts/run-user-e2e.sh --task-focus T90,T91,T92 --with-fixtures ``` 要获得最广覆盖,用单个实例同时启用三种决策器,并打开所有可选模式。保留默认云端上游(`https://tokenhub.tencentmaas.com`)时必须设置 `GATEWAY_API_KEY`(YAML 中的 `api_key_env` 指向它);使用无需鉴权的本地 stub 时可省略。`GATEWAY_BASE_URL` 可覆盖三个云端上游,`LOCAL_BASE_URL` / `LOCAL_MODEL_ID` 配置 `local/general` bypass 模型(默认 `127.0.0.1:8011`): ```bash # 终端 1 —— 自行启动实例(套件本身不会编译/启动/停止它) # 默认云端上游必需;使用无需鉴权的本地 stub 时可省略。 export GATEWAY_API_KEY=… # 可选:把云端 provider 与 bypass 模型都指向本地 OpenAI 兼容 stub。 # export GATEWAY_BASE_URL=http://127.0.0.1:8011 # export LOCAL_BASE_URL=http://127.0.0.1:8011 cargo run -p aria-router -- serve \ --config config/examples/triad-gateway.yaml \ --bind 127.0.0.1:8899 --mgmt-bind 127.0.0.1:8090 # 终端 2 —— 全量覆盖运行 ./scripts/run-user-e2e.sh \ --data-url http://127.0.0.1:8899 --mgmt-url http://127.0.0.1:8090 \ --admin-user admin --admin-password '…' \ --with-local --with-fixtures --allow-mutating \ --out-dir out/full ```
[![][back-to-top]](#readme-top)
## 🔧 配置 路由策略为 YAML v0.3(`--config`)。密钥用 `${VAR}` / `${VAR:-default}` 展开。`entrypoint.router` 必须等于 `recipe.router`。Semantic recipe 禁止 `agent:` / `afm-d:`;agent recipe 禁止 `signals` / `decisions` / `afm-d:`;afm-d recipe 禁止 `routing` / `agent:`。未知顶层键 → `validate` 失败。未实现的 YAML 能力返回 `Unsupported`(禁止静默空实现)。**无**顶层 `extensions`,不做 pi / deepseek-harness 子进程。 | 块 | 含义 | |----|------| | `listeners` | 数据面绑定(`address` + `port`;`--bind` 默认值) | | `providers` | `defaults.default_model` + 具名模型 / `backend_refs` | | `entrypoints` | 虚拟模型名 → `router: semantic\|agent\|afm-d` + `recipe` | | `recipes` | Semantic 的 `routing.*`、agent 的 `agent.*`、或 afm-d 的 `afm-d.*`(System One endpoint / 可选 `track` / timeout / fallback) | | `global` | 鉴权 / keys / users 路径(可选) | ### 示例策略 | 文件 | 用途 | |------|------| | [`semantic-tiny.yaml`](config/examples/semantic-tiny.yaml) | 日常 semantic 黄金路径 — `ariacompute/semantic-auto`;keyword 启发式 → `local/general`;可选 retention;无 ML 权重即可 `validate` + `serve` | | [`semantic.yaml`](config/examples/semantic.yaml) | Semantic catalog — 黄金 `ariacompute/semantic-auto` + `ariacompute/semantic-catalog`(learned signal + 未实现 algorithm → chat `Unsupported`,除非 `--features ml`);演示优先 tiny | | [`semantic-gateway.yaml`](config/examples/semantic-gateway.yaml) | Semantic + Aria Gateway — 三档 `ariamodel-{small,mid,large}`(`tier` + 可换 `provider_model_id`);**setup `--template semantic` 默认**;需 `GATEWAY_API_KEY` | | [`semantic-stateful.yaml`](config/examples/semantic-stateful.yaml) | Retention sticky + `stores.memory` / `semantic_cache` / replay | | [`agent-tiny.yaml`](config/examples/agent-tiny.yaml) | 日常 agent 黄金路径 — `ariacompute/agent-auto`;进程内 builtin tool-loop(无 `endpoint` → first-eligible);演示 / CI | | [`agent.yaml`](config/examples/agent.yaml) | Agent catalog — 对称 `semantic.yaml`:黄金 `ariacompute/agent-auto` + `ariacompute/agent-catalog`(故意 `Unsupported`);演示优先 tiny / gateway | | [`agent-gateway.yaml`](config/examples/agent-gateway.yaml) | Agent + Aria Gateway — 同上三档(`tier` + 可换上游);**setup `--template agent` 默认**;需 `GATEWAY_API_KEY` | | [`afm-d-tiny.yaml`](config/examples/afm-d-tiny.yaml) | 日常 AFM-D 黄金路径 — `ariacompute/afm-d-auto`;无 `endpoint` → first-eligible;演示 / CI | | [`afm-d.yaml`](config/examples/afm-d.yaml) | AFM-D catalog — 对称 `agent.yaml`:黄金 `ariacompute/afm-d-auto` + `ariacompute/afm-d-catalog`;演示优先 tiny / gateway | | [`afm-d-gateway.yaml`](config/examples/afm-d-gateway.yaml) | AFM-D + Aria Gateway — System One Choice 三档;**setup `--template afm-d`**;需 `GATEWAY_API_KEY` + `DECISION_MODEL_URL` 上的 aria-engine | 校验任一示例: ```bash cargo run -p aria-router -- validate --config config/examples/semantic-tiny.yaml cargo run -p aria-router -- validate --config config/examples/semantic.yaml cargo run -p aria-router -- validate --config config/examples/semantic-gateway.yaml cargo run -p aria-router -- validate --config config/examples/semantic-stateful.yaml cargo run -p aria-router -- validate --config config/examples/agent-tiny.yaml cargo run -p aria-router -- validate --config config/examples/agent.yaml cargo run -p aria-router -- validate --config config/examples/agent-gateway.yaml cargo run -p aria-router -- validate --config config/examples/afm-d-tiny.yaml cargo run -p aria-router -- validate --config config/examples/afm-d.yaml cargo run -p aria-router -- validate --config config/examples/afm-d-gateway.yaml ```
[![][back-to-top]](#readme-top)
## 🛳 Release 资产 每次 GitHub Release,[`.github/workflows/release.yml`](.github/workflows/release.yml) 上传与 `aria-router` CLI 并列的平台包: | 资产 | 内容 | |------|------| | `aria-router__linux_x86_64.tar.gz` | `aria-router` | | `aria-router__linux_arm64.tar.gz` | `aria-router` | | `aria-router__macos.tar.gz` | `aria-router` | | `aria-router__windows_x86_64.zip` | `aria-router.exe` | | `libaria-router_ffi__.tar.gz` | `libaria-router_ffi.so` / `.dylib` / `aria-router_ffi.dll` | ```bash # 示例:Linux x86_64 tar -xzf aria-router_0.1.0_linux_x86_64.tar.gz chmod +x aria-router ./aria-router --version # 或:aria-router upgrade(setup 后;替换 CLI 并把 FFI 装到 ~/.ariacompute/lib/) ``` 创建 **GitHub Release** — 语言包发布为 **fail-pass**,不阻塞 CLI / FFI 资产。版本号 = tag 去掉前缀 `v`。
[![][back-to-top]](#readme-top)
## 🔌 OpenAI API 假设数据面 `http://127.0.0.1:8899`、管理面 `http://127.0.0.1:8090`: ```bash # 列出入口名 + provider 名 curl -s http://127.0.0.1:8899/v1/models | jq . # Semantic 入口(semantic-tiny.yaml 的 keyword recipe) curl -s http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -d '{ "model": "ariacompute/semantic-auto", "messages":[{"role":"user","content":"please explain rust"}], "max_tokens": 32 }' | jq . # Agent 入口(agent-tiny.yaml) curl -s http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -d '{ "model": "ariacompute/agent-auto", "messages":[{"role":"user","content":"Hello"}], "max_tokens": 32 }' | jq . # AFM-D 入口(afm-d-tiny.yaml;无 endpoint → first-eligible) curl -s http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -d '{ "model": "ariacompute/afm-d-auto", "messages":[{"role":"user","content":"Hello"}], "max_tokens": 32 }' | jq . # Chat(SSE) curl -sN http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -d '{ "model": "ariacompute/semantic-auto", "messages":[{"role":"user","content":"please explain rust"}], "stream": true }' # 实名 bypass curl -s http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -d '{ "model": "local/general", "messages":[{"role":"user","content":"Hello"}] }' | jq . # 路由响应头(layer = semantic | agent | afm-d | bypass) curl -sD - -o /dev/null http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -d '{"model":"ariacompute/semantic-auto","messages":[{"role":"user","content":"please explain rust"}]}' \ | grep -i x-aria-router # 管理面 curl -s http://127.0.0.1:8090/health | jq . curl -s -X POST http://127.0.0.1:8090/v1/router/validate | jq . curl -s 'http://127.0.0.1:8090/v1/router/replay?n=20' | jq . curl -s http://127.0.0.1:8090/v1/router/overview | jq . curl -s http://127.0.0.1:8090/v1/router/providers | jq . curl -s http://127.0.0.1:8090/v1/router/topology | jq . curl -s http://127.0.0.1:8090/v1/router/config | jq . ``` 响应头:`x-aria-router-layer`、`x-aria-router-decision`、`x-aria-router-model`,以及 `x-aria-router-redecision`(显式跨请求边界:`new-user-message` / `context-compaction` / `tool-continuation` / `same-turn` / `unknown`)。若设置了 retention emit,还会有:`x-aria-router-retention-keep-current-model`、`x-aria-router-retention-ttl-turns`、`x-aria-router-retention-drop`、`x-aria-router-retention-prefer-prefix`。
[![][back-to-top]](#readme-top)
## 🔐 API 密钥与成本 1. Dashboard → **API 密钥** → 生成(`sk-aria_…` 只显示一次),或 `POST /v1/router/keys`。 2. setup 默认写入 `global.require_api_key: true`(chat 与 `PUT /v1/router/providers` 须 Bearer)。可在 YAML 改为 `false` 开放数据面。 3. 客户端与 `aria-engine` 使用 Bearer `sk-aria_…` 或 `sk-bf-…`(`router_api_key` / `--router-api-key`)。 4. **Cost** 页 / `GET /v1/router/cost` 展示六因子、`by_local_user` / `by_serve_user` / `by_key`(YAML `pricing`)。 5. OAuth:Dashboard → Account 配置 `sk-bf-…`(关联 / 粘贴 / 展示)。 ```bash curl -s http://127.0.0.1:8899/v1/chat/completions \ -H 'content-type: application/json' \ -H 'Authorization: Bearer sk-aria_…' \ -d '{"model":"local/general","messages":[{"role":"user","content":"Hi"}],"max_tokens":16}' ``` 硬约束(location / auth / modality / tools)在排名 **之前** 剪枝。Compute 只进排名。无合格路径 → fail closed。
[![][back-to-top]](#readme-top)
## 🌐 Dashboard 管理面在存在 `dashboard/dist` 时托管 Vite React SPA,地址为 `http://{mgmt}/`。完成 `aria-router setup` 后先 **Login**(本地用户名/密码): | 段落标题(与 CLI 同名) | 页面 | |------------------------|------| | **Local (router Dashboard)** | Login / Register · API 密钥(`sk-aria_…`)· Users(admin) | | **OAuth (Aria Compute)** | Account — 已关联用户、`sk-bf-…` 展示/粘贴/OAuth | | **Routing** | Config · Topology · Providers · Replay · **Playground**(多轮聊天、SSE、路由 Header;不做 MCP/Claw)· Cost · Cost by Competence · **Model Performance** · **Trust Tiers** | Cost 分 **Local users** 与 **OAuth users**。构建: ```bash npm --prefix dashboard ci npm --prefix dashboard run build cargo run -p aria-router -- serve \ --config config/examples/semantic-tiny.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # 打开 http://127.0.0.1:8090/ ``` `--no-dashboard` 只提供 JSON API(仍可用 curl 管理 keys/cost)。无 Grafana、ML wizard;默认绑 `127.0.0.1`。 **设计契约与 UI 回归审计**:Dashboard 为单色 / 扁平 / 直角 / AA / ≥12px,动效仅 transform/opacity,使用本地字体栈(无 web-font CDN)。设计契约见 [`PRODUCT.md`](PRODUCT.md)。UI 护栏测试:`npm --prefix dashboard run test`。 ### 本地渲染检查(重跑) `scripts/audit-ui.sh` 以五种模式运行 impeccable 风格审计:`--static`(CSS + `index.html` 主规则)、`--dom`(15 路由 × 深浅双主题 jsdom 渲染)、`--url`(实时页面 + Chrome + impeccable 二进制)、`--browser`(同 `--url`,但缺浏览器即硬失败)、`--list-rules`(打印规则 id + 页面矩阵)。无法运行的模式记为 `skipped`,绝不伪造成功。 ```bash npm --prefix dashboard ci npm --prefix dashboard run build npm --prefix dashboard run test ./scripts/audit-ui.sh --list-rules ./scripts/audit-ui.sh --static ./scripts/audit-ui.sh --dom # 在有 Chrome 与 impeccable 二进制的机器上: IMPECCABLE_BROWSER=/usr/bin/google-chrome ./scripts/audit-ui.sh --url ```
[![][back-to-top]](#readme-top)
## 🧭 三种决策器 每个入口名精确映射到一种决策器;一次请求不会串跑多种。硬约束(location / auth / modality / tools)在排名 **之前** 剪枝,任何通过排名的合格路径都会产出类型化的 `RouteDecision`。无合格路径时,网关失败关闭。 | 决策器 | Recipe 块 | 行为 | |--------|-----------|------| | `semantic` | `routing.*` | 信号 → 投影 → 布尔决策 → algorithm / looper。keyword 启发式无需 ML 权重;learned signal + 未实现 algorithm 除非 `--features ml` 否则返回 `Unsupported`。 | | `agent` | `agent.*` | 进程内 `BuiltinAgent` 工具循环,固定工具 + 有限 `max_turns`;`submit_route` 产出类型化 `RouteDecision`。无 `endpoint` → first-eligible 后端。 | | `afm-d` | `afm-d.*` | 合格候选 → System One Choice → `POST {endpoint}/v1/systemone` → 类型化 `RouteDecision`。实名模型 bypass recipe,直打该后端。低分保护 + 失败关闭回落保证决策安全。 | 数据面暴露 `x-aria-router-layer`(`semantic` | `agent` | `afm-d` | `bypass`)、`x-aria-router-decision`、`x-aria-router-model` 与 `x-aria-router-redecision`,使每个重判边界都可观测。完整决策契约见 [AGENTS.md](./AGENTS.md)。
[![][back-to-top]](#readme-top)
## 🔗 ContextHold 同一用户轮次内的 tool / assistant 往返保持已选模型;只在自然边界(用户新消息或上下文压缩)再重新决策。混用便宜模型与主力模型时,KV Cache / 前缀复用仍然划算。 - semantic / agent / afm-d 配方上,**`prefix_reuse` 缺省为 `true`**(显式 `false` 关闭)。同一**显式 session**、同一**用户消息条数**内,复用冻结的 `RouteDecision`。 - **用户新消息**(turn 计数上升)→ 全新决策。 - **压缩**(消息列表变短,或 system 提示词 / `tools` 指纹变化)→ 清除该 session 的 DecisionCache 与 sticky,再重新路由。 - **Sticky TTL**(`stores.memory`)**仅在用户消息条数上升时**递减——不会在每一次工具调用的 HTTP 请求上扣减。同一模型再次 pin **不会**刷新 TTL;换模型才重新记满 TTL。 - **afm-d / agent sticky**:当 `global.stores.memory.enabled` 与 `prefix_reuse` 均开启时,路由成功后 pin 所选模型;后续用户轮上若仍通过硬约束则短路(跳过 System One / builtin agent),reason 为 `sticky:…`。semantic 仍由 decision 的 `emits.retention.keep_current_model` 在 algorithm 选型之后驱动 sticky。 - **仅显式 session**:ContextHold 只认 `x-aria-session` 或 body `session`。自动生成的 `req_*` id 仅用于成本记账——不冻结决策、不写 sticky。 请发送显式 session,并带上**累积的对话历史**(或至少让用户消息条数递增),以驱动 turn 键与 TTL。只发最后一条消息的客户端会一直保持 `turn_of == 1`,sticky TTL 不会前进。未提供显式 session 时,路由粘性等价于「每次请求都重新决策」。 ### 行为一览 ```text 带显式 session 的请求 │ ▼ 已压缩? ──是──► 清除 DecisionCache + sticky ──► 重新路由 │ 否 ▼ 若用户轮计数上升则 tick sticky TTL │ ▼ 同 (session, turn) 命中缓存? ──是──► 复用冻结模型 │ 否 ▼ afm-d/agent sticky 仍 eligible? ──是──► 短路 │ 否 ▼ 跑 semantic / agent / afm-d → pin(若适用) ``` ### 配置示意 ```yaml recipes: - name: mom router: semantic routing: strategy: priority prefix_reuse: true # 省略时默认 true # … - name: agent-default router: agent agent: prefix_reuse: true # … - name: afm-d-default router: afm-d afm-d: prefix_reuse: true # … global: stores: memory: enabled: true max_sessions: 4096 default_ttl_turns: 2 ``` semantic 跨轮 sticky 仍需要 decision emit,例如: ```yaml emits: - kind: retention retention: ttl_turns: 2 keep_current_model: true ``` 参见 [`semantic-stateful.yaml`](config/examples/semantic-stateful.yaml) 与各 `*-gateway.yaml` 示例(已写 `prefix_reuse: true`)。
[![][back-to-top]](#readme-top)
## 🧩 SDK 绑定 C ABI(`ariacompute-router-ffi` / `libaria-router_ffi`)加 `bindings/` 薄封装。**不要**与 `libaria_ffi` / `ariacompute-engine` 混用。 | Binding | 路径 | 包 | |---------|------|-----| | Rust | `bindings/rust` | crates.io `ariacompute-router`(原生;不 dlopen) | | Python | `bindings/python` | PyPI `ariacompute-router`(`aria_router`) | | Go | `bindings/go` | `github.com/ariacompute/router/bindings/go`(cgo;build tag `aria_router_ffi`) | | TypeScript | `bindings/typescript` | npm `@ariacompute/router-ts` | | React Native | `bindings/react-native` | npm `@ariacompute/router-rn` | | Flutter | `bindings/flutter` | pub.dev `aria_router` | | Swift | `bindings/swift` | CocoaPods / SPM `AriaComputeRouter` | | Kotlin | `bindings/kotlin` | Maven `com.ariacompute:router` | C 头文件:[`ffi/include/aria_router.h`](ffi/include/aria_router.h) — `aria_router_init`(进程内加载 YAML;`NULL`/空串 → `~/.ariacompute/router.yml`)、`aria_router_connect`(HTTP 连已运行的 `serve`)、`aria_router_setup`(仅内存 `base_url` / `token`;`NULL` 保持不变、空串清除)、`aria_router_complete` / `_stream`、`aria_router_models`、`aria_router_last_route`、`aria_router_destroy`、`aria_router_last_error`。 `aria_router_complete_stream` 当前是**整块单次回调**(一次携带完整响应体),不是逐 SSE chunk。`aria_router_last_route` 返回 `RouteDecision` JSON 及 `headers` 扩展对象(白名单 `x-aria-router-*`,含 `x-aria-router-redecision`;不暴露 `authorization` / cookie)。`connect` 句柄的 `models` 代理 `GET /v1/models`,`last_route` 暴露最近一次 `complete` 捕获的响应头;失败显式报错,不返回空结果。 动态库顺序:`ARIA_ROUTER_FFI_LIB` → 包内捆绑路径 → `~/.ariacompute/lib/`。实例 `setup` 仅内存 `base_url` / `token`,**禁止**写 `router.yml`。无路径的 `init` 使用 `aria-router setup` 写入的默认 `router.yml`(gateway 模板 serve 前需 `export GATEWAY_API_KEY`)。离线 binding CI 使用 [`bindings/testdata/fast-response.yaml`](bindings/testdata/fast-response.yaml)(固定回复,无需 upstream)。`init` 进程内跑 semantic 与轻量 builtin agent(固定工具 + `max_turns`);无 subprocess harness。Rust 原生绑定不 dlopen,Go 走 cgo `-L… -laria_router_ffi`,二者均不使用该查找顺序。 ```bash cargo test -p ariacompute-router-ffi -p ariacompute-router ./scripts/run-binding-tests.sh # 宿主矩阵(Rust / Python / Go / TS / RN / Flutter / Kotlin;Swift 需工具链可用时手工 swift test) ``` C ABI 变更必须同步 [`bindings/testdata/cases.json`](bindings/testdata/cases.json) 与宿主测。 ### 示例 进程内 `init` + `complete` **不需要** Dashboard API key。`connect` 到开启 `require_api_key` 的已运行 `serve` 仍需 `setup(token=…)`。实例 `setup` 仅写内存。 八语言 SDK 统一暴露 `setup` / `setup_status`(或 `setupStatus` / `SetupStatus`)/ `setup_clear`、`complete`、`complete_stream`(或 `completeStream` / `CompleteStream`)、`models`、`last_route`(或 `lastRoute` / `LastRoute`)、`close` + `destroy`。`complete_stream` 交付一次完整响应体,`last_route()["headers"]` 携带白名单决策响应头。例如: ```python r.setup(token="sk-...") print(r.setup_status()) chunks = [] out = r.complete_stream([{"role": "user", "content": "hi"}], callback=chunks.append) print(out, chunks[0][:80]) print(r.last_route()["headers"]) ``` **Python**(需 `ARIA_ROUTER_FFI_LIB` 或捆绑/缓存的 `libaria-router_ffi`): ```bash pip install ariacompute-router ``` ```python from aria_router import Router # aria-router setup 后:加载 ~/.ariacompute/router.yml r = Router().init() print(r.models()) print(r.complete( [{"role": "user", "content": "hi"}], {"model": "ariacompute/semantic-auto"}, )) print(r.last_route()) r.close() # 或连接已运行的 serve(开启 require_api_key 时需 token): r = Router().connect("http://127.0.0.1:8899") r.setup(base_url="http://127.0.0.1:8899", token="") ``` **Rust**(`ariacompute-router` — 原生 API,不 dlopen `libaria-router_ffi`): ```bash cargo add ariacompute-router ``` ```rust use ariacompute_router::{Router, SetupUpdates}; use serde_json::json; fn main() -> Result<(), Box> { let mut r = Router::new(); // 空路径 → ~/.ariacompute/router.yml(需先 aria-router setup) r.init("")?; println!("{}", r.models()?); println!( "{}", r.complete( json!([{"role": "user", "content": "hi"}]), json!({"model": "ariacompute/semantic-auto"}), )? ); println!("{}", r.last_route()); // 或连接已运行的 serve(开启 require_api_key 时需 token): r.connect("http://127.0.0.1:8899"); r.setup(&SetupUpdates { base_url: Some("http://127.0.0.1:8899".into()), token: Some("".into()), })?; Ok(()) } ``` **Go**(cgo + `libaria-router_ffi`;build tag `aria_router_ffi`): ```bash go get github.com/ariacompute/router/bindings/go ``` ```go package main import ( "fmt" "log" aria "github.com/ariacompute/router/bindings/go" ) func main() { r := aria.NewRouter() // 空路径 → ~/.ariacompute/router.yml(需先 aria-router setup) if err := r.Init(""); err != nil { log.Fatal(err) } defer r.Close() models, err := r.Models() if err != nil { log.Fatal(err) } fmt.Println(models) out, err := r.Complete( []map[string]string{{"role": "user", "content": "hi"}}, map[string]string{"model": "ariacompute/semantic-auto"}, ) if err != nil { log.Fatal(err) } fmt.Println(out) route, err := r.LastRoute() if err != nil { log.Fatal(err) } fmt.Println(route) // 或连接已运行的 serve(开启 require_api_key 时需 token): _ = r.Connect("http://127.0.0.1:8899") r.Setup("http://127.0.0.1:8899", "") } ``` **TypeScript**(`@ariacompute/router-ts`): ```bash npm install @ariacompute/router-ts ``` ```ts import { Router } from "@ariacompute/router-ts"; // aria-router setup 后:加载 ~/.ariacompute/router.yml const r = new Router().init(); console.log(r.models()); console.log( r.complete([{ role: "user", content: "hi" }], { model: "ariacompute/semantic-auto", }), ); console.log(r.lastRoute()); r.close(); // 或连接已运行的 serve(开启 require_api_key 时需 token): const c = new Router().connect("http://127.0.0.1:8899"); c.setup({ base_url: "http://127.0.0.1:8899", token: "" }); ``` **React Native**(`@ariacompute/router-rn`): ```bash npm install @ariacompute/router-rn ``` ```js const { Router } = require("@ariacompute/router-rn"); const r = new Router().init(); console.log(r.models()); console.log( r.complete([{ role: "user", content: "hi" }], { model: "ariacompute/semantic-auto", }), ); console.log(r.lastRoute()); r.close(); // 或连接已运行的 serve(开启 require_api_key 时需 token): const c = new Router().connect("http://127.0.0.1:8899"); c.setup({ base_url: "http://127.0.0.1:8899", token: "" }); ``` **Flutter**(`ariacompute_router`): ```bash flutter pub add ariacompute_router ``` ```dart import 'package:ariacompute_router/ariacompute_router.dart'; void main() { // aria-router setup 后:加载 ~/.ariacompute/router.yml final r = AriaRouter()..init(); print(r.models()); print(r.complete( [ {'role': 'user', 'content': 'hi'} ], {'model': 'ariacompute/semantic-auto'}, )); print(r.lastRoute()); r.close(); // 或连接已运行的 serve(开启 require_api_key 时需 token): final c = AriaRouter()..connect('http://127.0.0.1:8899'); c.setup(baseUrl: 'http://127.0.0.1:8899', token: ''); } ``` **Swift**(dlopen `libaria-router_ffi`;SPM / CocoaPods `AriaComputeRouter`): ```bash pod 'AriaComputeRouter' ``` ```swift import AriaComputeRouter import Foundation do { // load(nil) → ~/.ariacompute/router.yml(Swift 关键字;对应 aria_router_init) let r = try Router().load(nil) print(try r.models()) print(try r.complete( messages: [["role": "user", "content": "hi"]], options: ["model": "ariacompute/semantic-auto"] )) print(try r.lastRoute()) r.close() // 或连接已运行的 serve(开启 require_api_key 时需 token): let c = try Router().connect("http://127.0.0.1:8899") c.setup(baseUrl: "http://127.0.0.1:8899", token: "") } catch { fputs("\(error)\n", stderr) } ``` **Kotlin**(JNA + `libaria-router_ffi`;Maven `com.ariacompute:router`): ```kotlin implementation("com.ariacompute:router:+") ``` ```kotlin import com.ariacompute.router.Router fun main() { // aria-router setup 后:加载 ~/.ariacompute/router.yml Router().init().use { r -> println(r.models()) println( r.complete( listOf(mapOf("role" to "user", "content" to "hi")), mapOf("model" to "ariacompute/semantic-auto"), ), ) println(r.lastRoute()) } // 或连接已运行的 serve(开启 require_api_key 时需 token): Router().connect("http://127.0.0.1:8899").use { c -> c.setup(baseUrl = "http://127.0.0.1:8899", token = "") } } ```
[![][back-to-top]](#readme-top)
## 📊 Bench [`bench/`](bench/) 下 Python ≥3.10 **report-only** 评测(标准库;对齐 `engine/bench`)。**不**拉起 `aria-router`、[vLLM Semantic Router](https://github.com/vllm-project/semantic-router) 或 provider——需自行 serve 后把 `--router` / `--pool` 指到 OpenAI 兼容 URL。报告恒含 `ci_fail: false`。 | 子命令 | 用途 | |--------|------| | `routing` | ADR-040 矩阵 + always / oracle / domain / knn / **多 live router** ladder | | `routing-accuracy` | **仅 Router API** 的 label 准确率(选路 vs `expected_model`;无需 `--pool`) | | `build-routing-eval` | 生成 `routing_gateway_eval.json`(≥200 模板;可选并入 MMLU/DRACO) | | `research` | DRACO 形 JSONL + rubric,对比 always_X 与各 router | | `compare` | MCQ **accuracy + E2E latency + tokens**(对齐 VSR 公开 bench 叙事) | | `policy-consistency` | 离线重算 4 种确定性策略(cheapest / strongest / expected-label / by-config-expected),输入为已保存的决策记录——无需 live router;report-only,恒含 `ci_fail: false` | | `list-corpus` | 打印内置 tiny 语料 | | `download-draco` / `download-mmlu` | 可选 HF 拉取(失败 skip) | `--router` 可重复 `NAME=URL`(裸 URL → `aria_router`)。配合 `--entrypoint` / `--pick-header` / `--pick-map`。 并排对标建议端口:**aria-router `:8899`**、**vLLM SR `:8890`**、共享 backend `:8000` / `:9001+`。 routing / research 的质量模式(`--quality`):`label`、`overlap`、`judge`(需 `--judge-url`)。 两条常用 track(同一套 `routing` / `compare` CLI,测的对象不同): | Track | 实际打谁 | 主要 flags | 测什么 | |-------|----------|------------|--------| | 上游仅 pool | **直接** chat TokenHub(与 Track B 同一三档) | `--pool` + `--model-id` + `--api-key` + `--prices`;**无** `--router` | `glm-5.3-flash` / `glm-5.3` / `deepseek-v4-pro` 后端质量 / 成本阶梯(不启本地 router) | | 多 router ladder | 经 **live router** chat,再(可选)共享 pool | `--router` + `--entrypoint` / `--pick-header`,外加 `--pool` 做 always/oracle 基线 | 选路质量(aria-router vs vLLM SR 等)在 ADR-040 / MCQ 上的表现 | 可选中间步:本地 serve `semantic-gateway` / `agent-gateway` / `afm-d-gateway`,在仅 pool track 上追加 `--router aria_router=…`(及 `--pick-map`),使选路经 router 再进同一上游 pool。 下方片段:**A** = 上游仅 pool;**B** = semantic-auto vs vLLM SR;**C** = agent-auto vs vLLM SR;**D** = afm-d-auto vs vLLM SR;**E** = routing-accuracy(三决策器共用 eval 语料,仅 API)。 ```bash python -m unittest discover -s bench/tests -t . # --- Track A:上游仅 pool(可不启本地 router)--- # 与 Track B semantic routing 同一 TokenHub 三档;corpus expected_model = 上游名。 export GATEWAY_BASE=https://tokenhub.tencentmaas.com export GATEWAY_API_KEY=your-api-key # ADR-040 ladder:直接 chat pool(always_* / oracle / domain / knn;无 --router)。 # --quality label 按 corpus expected_model 打分;写出 out/gateway_routing.{json,md}。 python -m bench routing \ --pool small=$GATEWAY_BASE --pool mid=$GATEWAY_BASE --pool large=$GATEWAY_BASE \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --quality label \ --corpus bench/corpus/routing_gateway.json \ --report ./out/gateway_routing.json # MCQ accuracy + E2E latency + tokens:同一 pool 上跑 mmlu_tiny(仅 always_*)。 python -m bench compare \ --pool small=$GATEWAY_BASE --pool mid=$GATEWAY_BASE --pool large=$GATEWAY_BASE \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --corpus bench/corpus/mmlu_tiny.jsonl \ --report ./out/gateway_compare.json ``` ```bash # --- Track B: semantic ladder (aria-router vs vLLM Semantic Router) --- # 需本地 aria-router(:8899)、vLLM SR(:8890)以及 pool 后端(:9001+ / :8000)。 # 自行启动 router(见 bench/vllm-sr/README.md)。下方 aria-router 配置三选一 #(semantic XOR agent XOR afm-d,同一 --bind)。--router = live 选路质量;--pool = always/oracle 基线。 export GATEWAY_BASE=https://tokenhub.tencentmaas.com export GATEWAY_API_KEY=your-api-key # aria-router 数据面 :8899 — semantic keyword 路由 → Gateway ariamodel-{small,mid,large}。 # Bench 使用 --entrypoint ariacompute/semantic-auto。 aria-router serve \ --config config/examples/semantic-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # 上一段的替代:builtin agent 路由(同端口,勿同时跑)。 # bench 改用 --entrypoint ariacompute/agent-auto(替代 semantic-auto)。 # aria-router serve \ # --config config/examples/agent-gateway.yaml \ # --bind 127.0.0.1:8899 \ # --mgmt-bind 127.0.0.1:8090 # vLLM Semantic Router 数据面 :8890 — **keyword 基线**(冻结;不对齐 aria advanced)。 # 建议先 validate:vllm-sr validate --config bench/vllm-sr/config-gateway.yaml # Bench 使用 --entrypoint vllm_sr=auto。 vllm-sr validate --config bench/vllm-sr/config-gateway.yaml vllm-sr serve --config bench/vllm-sr/config-gateway.yaml # vllm-sr status # vllm-sr stop # Live-router ADR-040 ladder(非对称 §6.6):aria = advanced mom;vllm_sr = keyword baseline。 # 优先 hard corpus + --prices,用成本与陷阱事实题拉开差距。 python -m bench routing \ --router aria_router=http://127.0.0.1:8899 \ --router vllm_sr=http://127.0.0.1:8890 \ --entrypoint aria_router=ariacompute/semantic-auto \ --entrypoint vllm_sr=auto \ --pick-header aria_router=x-aria-router-model \ --pick-header vllm_sr=x-vsr-selected-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --pool small=https://tokenhub.tencentmaas.com \ --pool mid=https://tokenhub.tencentmaas.com \ --pool large=https://tokenhub.tencentmaas.com \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --quality label \ --corpus bench/corpus/routing_gateway_hard.json \ --timeout 300 \ --report ./out/vs_vsr_routing.json # MCQ compare:经各 live router(accuracy / latency / tokens / cost)对比 Gateway 三档 always_*。 # 公平延迟:先重启 aria 以清空进程内 response-cache(否则 p50≈ms 多为缓存命中)。 # 重建/重启后,共享 reqwest Client(§6.7)在 compare 多题间复用到 TokenHub 的 TLS。 # (在 aria serve 终端)Ctrl-C,再带 GATEWAY_API_KEY 重新执行同一条 `aria-router serve …`。 python -m bench compare \ --router aria_router=http://127.0.0.1:8899 \ --router vllm_sr=http://127.0.0.1:8890 \ --entrypoint aria_router=ariacompute/semantic-auto \ --entrypoint vllm_sr=auto \ --pick-header aria_router=x-aria-router-model \ --pick-header vllm_sr=x-vsr-selected-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --pool small=https://tokenhub.tencentmaas.com \ --pool mid=https://tokenhub.tencentmaas.com \ --pool large=https://tokenhub.tencentmaas.com \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --corpus bench/corpus/mmlu_tiny.jsonl \ --timeout 300 \ --report ./out/vs_vsr_compare.json ``` ```bash # --- Track C: agent ladder (aria-router vs vLLM Semantic Router) --- export GATEWAY_BASE=https://tokenhub.tencentmaas.com export GATEWAY_API_KEY=your-api-key # 若 semantic-gateway 在跑,先停掉,再: aria-router serve \ --config config/examples/agent-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # vllm-sr keyword 基线仍在 :8890(config-gateway.yaml)。 python -m bench routing \ --router aria_router=http://127.0.0.1:8899 \ --router vllm_sr=http://127.0.0.1:8890 \ --entrypoint aria_router=ariacompute/agent-auto \ --entrypoint vllm_sr=auto \ --pick-header aria_router=x-aria-router-model \ --pick-header vllm_sr=x-vsr-selected-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --pool small=https://tokenhub.tencentmaas.com \ --pool mid=https://tokenhub.tencentmaas.com \ --pool large=https://tokenhub.tencentmaas.com \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --quality label \ --corpus bench/corpus/routing_gateway_hard.json \ --timeout 300 \ --report ./out/agent_vs_vsr_routing.json python -m bench compare \ --router aria_router=http://127.0.0.1:8899 \ --router vllm_sr=http://127.0.0.1:8890 \ --entrypoint aria_router=ariacompute/agent-auto \ --entrypoint vllm_sr=auto \ --pick-header aria_router=x-aria-router-model \ --pick-header vllm_sr=x-vsr-selected-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --pool small=https://tokenhub.tencentmaas.com \ --pool mid=https://tokenhub.tencentmaas.com \ --pool large=https://tokenhub.tencentmaas.com \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --corpus bench/corpus/mmlu_tiny.jsonl \ --timeout 300 \ --report ./out/agent_vs_vsr_compare.json ``` ```bash # --- Track D:AFM-D ladder(aria-router vs vLLM Semantic Router)--- # aria = System One Choice(afm-d-auto);vllm_sr = keyword 基线(auto)。 export GATEWAY_BASE=https://tokenhub.tencentmaas.com export GATEWAY_API_KEY=your-api-key # afm-d 所需 Encoder System One(afm-d-gateway 默认 track: encoder @ :8010): # aria-engine serve --track encoder --bind 127.0.0.1:8010 # Decoder 轨用 :8011(`--track decoder`);若指向 Decoder 则设 afm-d.track: decoder。 export DECISION_MODEL_URL=http://127.0.0.1:8010 # 若 :8899 上已有 semantic/agent gateway,先停掉,再: aria-router serve \ --config config/examples/afm-d-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # vllm-sr keyword 基线仍在 :8890(config-gateway.yaml)。 python -m bench routing \ --router aria_router=http://127.0.0.1:8899 \ --router vllm_sr=http://127.0.0.1:8890 \ --entrypoint aria_router=ariacompute/afm-d-auto \ --entrypoint vllm_sr=auto \ --pick-header aria_router=x-aria-router-model \ --pick-header vllm_sr=x-vsr-selected-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --pool small=https://tokenhub.tencentmaas.com \ --pool mid=https://tokenhub.tencentmaas.com \ --pool large=https://tokenhub.tencentmaas.com \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --quality label \ --corpus bench/corpus/routing_gateway_hard.json \ --timeout 300 \ --report ./out/afmd_vs_vsr_routing.json python -m bench compare \ --router aria_router=http://127.0.0.1:8899 \ --router vllm_sr=http://127.0.0.1:8890 \ --entrypoint aria_router=ariacompute/afm-d-auto \ --entrypoint vllm_sr=auto \ --pick-header aria_router=x-aria-router-model \ --pick-header vllm_sr=x-vsr-selected-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --pool small=https://tokenhub.tencentmaas.com \ --pool mid=https://tokenhub.tencentmaas.com \ --pool large=https://tokenhub.tencentmaas.com \ --model-id small=glm-5.3-flash \ --model-id mid=glm-5.3 \ --model-id large=deepseek-v4-pro \ --api-key small=$GATEWAY_API_KEY --api-key mid=$GATEWAY_API_KEY --api-key large=$GATEWAY_API_KEY \ --prices bench/prices/ariamodel.json \ --corpus bench/corpus/mmlu_tiny.jsonl \ --timeout 300 \ --report ./out/afmd_vs_vsr_compare.json ``` ```bash # --- Track E:routing-accuracy(仅 Router API;≥200 金标)--- # 度量选路是否命中 expected_model — 无 --pool / 无 TokenHub 矩阵。 # 用 triad-gateway 一次挂起三个 entrypoint(或脚本 --start-router)。 # AFM-D 需 System One:aria-engine serve --track encoder --bind 127.0.0.1:8010 # GATEWAY_API_KEY 必须在 *serve* 进程环境里(TokenHub)。不要把它当作客户端 # Authorization 发给 :8899(triad-gateway 的 require_api_key: false)。 export GATEWAY_API_KEY=your-api-key export DECISION_MODEL_URL=http://127.0.0.1:8010 aria-router serve \ --config config/examples/triad-gateway.yaml \ --bind 127.0.0.1:8899 \ --mgmt-bind 127.0.0.1:8090 # 一键:semantic → agent → afm-d;写出 out/acc_{semantic,agent,afmd}.json + acc_summary.json # (本 shell 不必设 GATEWAY_API_KEY;若开启 require_api_key 再用 ROUTER_API_KEY) ./scripts/run-routing-accuracy.sh # 或:./scripts/run-routing-accuracy.sh --start-router # 决策模型未起时跳过 AFM-D:./scripts/run-routing-accuracy.sh --skip-afmd # 单决策器: python -m bench routing-accuracy \ --router http://127.0.0.1:8899 \ --entrypoint ariacompute/semantic-auto \ --pick-header x-aria-router-model \ --pick-map ariacompute/ariamodel-small=glm-5.3-flash \ --pick-map ariacompute/ariamodel-mid=glm-5.3 \ --pick-map ariacompute/ariamodel-large=deepseek-v4-pro \ --corpus bench/corpus/routing_gateway_eval.json \ --report ./out/acc_semantic.json # 重建 eval 语料(模板;可选本地合并 MMLU/DRACO — 勿提交全量 dump): python -m bench build-routing-eval ``` 详见 [`bench/corpus/README.md`](bench/corpus/README.md) 与 [`bench/vllm-sr/`](bench/vllm-sr/)(外部 `vllm-sr` 配置与 validate/serve)。
[![][back-to-top]](#readme-top)
## ⚖️ 特性对比 | 维度 | Router (aria-router) | HiRoute | vLLM Semantic Router | |------|:---:|:---:|:---:| | OpenAI 兼容 HTTP 网关(服务端) | ✅ | ❌ | ❌ | | 三种并列决策器(semantic / agent / afm-d) | ✅ | ❌ | ❌ | | 语义路由(信号 → 决策) | ✅ | ✅ | ✅ | | 硬约束剪枝(location/auth/modality/tools,决策前) | ✅ | ❌ | ❌ | | 能力感知降级(competence-aware 经济降档) | ✅ | ✅ | ❌ | | 有界故障转移 / fail closed(不静默改行为) | ✅ | ✅ | ❌ | | 执行证据留存(任务/模型/工具/输出/能力 结构化证据链) | ✅ | ✅ | ❌ | | 长周期 Agent 编排 / 委托 | ✅ | ✅ | ❌ | | 决策模型扩展 API(外置决策服务) | ✅ | ✅ | ❌ | | 多租户 / 鉴权 / 计费(API key·OAuth·Users·六因子成本) | ✅ | ❌ | ❌ | | 成本·能力可观测(按 tier 成本归因 + Dashboard) | ✅ | △ | ❌ | | 显式重判边界可观测(`x-aria-router-redecision`) | ✅ | ❌ | ❌ | | 离线策略一致性报告(用留存记录重算,无需 router) | ✅ | ❌ | ❌ | | 上下文前缀复用(同 turn 冻结决策) | ✅ | ✅ | ❌ | | 集成面(C ABI + 八语言 SDK / 部署形态) | ✅ | △ | △ | | 生产级服务端定位(多租户·管控·可运维) | ✅ | ❌ | ❌ | 图例:✅ 完整支持 · △ 部分/受限 · ❌ 不支持。 **结论**:Router 在保持「硬约束 + fail closed + 三决策器隔离」的前提下,补齐了 HiRoute 的 competence-aware 软降级、结构化执行证据、可插拔决策扩展与长周期委托,并以生产级 OpenAI 兼容网关 + 多租户计费 + C ABI / 八语言 SDK 的组合,覆盖 vLLM SR 之外的服务端全栈需求。
[![][back-to-top]](#readme-top)
## 🔏 信任库安全 2026-10 的 eMudhra(emSign)中间 CA 私钥泄露事件在二进制层面兜底:`aria-router` / `ariacompute-router-ffi` 通过 `reqwest` + `rustls-tls` 进行 provider API 调用与 `bin` 的 `upgrade` GitHub/Gitee Release 下载,其信任库是编译进二进制的 **`webpki-roots`**,已在 `http/Cargo.toml` 钉 `>=1.0.10`(`Cargo.lock` 经 `cargo update -p webpki-roots --precise 1.0.10` 由 1.0.9 → 1.0.10)。1.0.10+ 移除受泄露的 emSign 根。二进制**不**走系统 bundle,故锁升级是决定性修复。 Dashboard 是由 Rust 二进制托管的静态 Vite React SPA,**无运行时信任库**,自身不做出向 TLS。构建期 `npm install` 走主机 `ca-certificates`,但那只是构建环境。脚本 `scripts/check-emudhra.sh` 离线扫描系统或镜像 CA bundle 中已知根/中间证书的 SHA-256 指纹(退出码 `0` 干净、`1` 命中、`2` 无法读取)。 ```bash scripts/check-emudhra.sh /etc/ssl/certs/ca-certificates.crt ```
[![][back-to-top]](#readme-top)
## 🔨 开发 | 目标 | 作用 | |------|------| | `cargo test` | 跑工作区测试 | | `cargo clippy --workspace --all-targets -- -D warnings` | Lint,拒绝警告 | | `./scripts/coverage.sh` | 100% 行覆盖门禁(llvm-cov) | | `./scripts/run-binding-tests.sh` | 宿主矩阵(Rust / Python / Go / TS / RN setup) | | `cargo build --release -p aria-router -p ariacompute-router-ffi` | 构建 CLI + FFI | 运维 Dashboard 另有护栏测试与 impeccable 风格审计(在仓库根目录执行): ```bash npm --prefix dashboard ci npm --prefix dashboard run build npm --prefix dashboard run test # 样式 token + 15 路由 × 深浅双主题 jsdom 快照 ./scripts/audit-ui.sh --static # CSS / index.html 静态规则 ./scripts/audit-ui.sh --dom # 全部路由 × 双主题(jsdom) ./scripts/audit-ui.sh --url # Chrome 页面加载(无浏览器时 skip) ```
[![][back-to-top]](#readme-top)
## 📚 文档 详细的工程上下文位于仓库根目录: | 文档 | 覆盖内容 | |------|----------| | [AGENTS.md](./AGENTS.md) | Agent 工程上下文入口与目录索引 | | [requirements.md](./requirements.md) | 需求规格(功能边界 / 异常 / 验收,人审后编码) | | [task.md](./task.md) | 实施清单 | | [PRODUCT.md](./PRODUCT.md) | Dashboard 设计契约(单色 / 扁平 / 直角 / AA / ≥12px) | | [releasenotes_cn.md](./releasenotes_cn.md) | 发布说明 |
[![][back-to-top]](#readme-top)
## 📝 许可证 MIT.
[![][back-to-top]](#readme-top)
## 🤝 工程约定 本仓库遵循 Harness Engineering: - [`AGENTS.md`](./AGENTS.md):Agent 工程上下文入口与目录索引 - [`requirements.md`](./requirements.md):需求规格(功能边界 / 异常 / 验收,人审后编码) - [`task.md`](./task.md):实施清单
[![][back-to-top]](#readme-top)
---
Copyright © 2026 [ariacompute][org].
This project is [MIT](./LICENSE) licensed.
[org]: https://github.com/ariacompute [release-shield]: https://img.shields.io/github/v/release/ariacompute/router?style=flat-square&labelColor=black&color=555 [release-link]: https://github.com/ariacompute/router/releases [rust-shield]: https://img.shields.io/github/rust/cargo/v/ariacompute-router?style=flat-square&labelColor=black&color=555 [rust-link]: ./Cargo.toml [license-shield]: https://img.shields.io/github/license/ariacompute/router?style=flat-square&labelColor=black&color=555 [license-link]: ./LICENSE [lastcommit-shield]: https://img.shields.io/github/last-commit/ariacompute/router?style=flat-square&labelColor=black&color=555 [lastcommit-link]: https://github.com/ariacompute/router/commits [routers-shield]: https://img.shields.io/badge/routers-3_parallel-555?style=flat-square&labelColor=black [routers-link]: #-三种决策器 [sdk-shield]: https://img.shields.io/badge/SDK-8_languages-555?style=flat-square&labelColor=black [sdk-link]: #-sdk-绑定 [coverage-shield]: https://img.shields.io/badge/coverage-100%25-555?style=flat-square&labelColor=black [coverage-link]: ./scripts/coverage.sh [dashboard-shield]: https://img.shields.io/badge/dashboard-monochrome_SPA-555?style=flat-square&labelColor=black [dashboard-link]: #-dashboard [back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square