内容
# Volante
[](https://github.com/ribato22/volante/actions/workflows/ci.yml)
[](https://github.com/ribato22/volante/blob/main/LICENSE)
[](pyproject.toml)
[](https://pypi.org/project/volante/)
[](https://registry.modelcontextprotocol.io)
[](https://github.com/astral-sh/ruff)
**透明、用户拥有的模型路由器和编排控制平面(alpha版本)。** 一个 *supervisor* 模型将目标分解为任务DAG,*路由* 每个子任务跨用户显式配置的模型,运行它们一次或在代理工具循环中,并 *合成* 最终答案。 硬能力优先;可解释的元数据和质量证据对合格模型进行排名。 Volante在本地运行,保留用户的库存、策略、凭证和决策记录。
选择质量是基于证据的预测,而不是通用赢家的声明。 Volante目前不提供已发布的代表性跨提供商基准测试或自动得分校准。 不使用编排框架构建(无LangChain / CrewAI / LiteLLM)。
> 一个 *volante* 引导游戏:深潜的中场球员读取整个场地并将球送到最有价值的地方——然后拿回来。 一个心智,多名球员。
---
## 亮点
- **Supervisor + 可解释路由。** 一个LLM计划一个经过验证的非循环任务DAG;路由器评估每个配置的模型,拒绝硬能力不匹配,评估合格集,记录完整的决策跟踪。 可选的评估导出质量配置文件用证据替换粗粒度元数据。 `quality`、`local`、`cheap`和`cash_protect_quota`是不同的路由目标。
- **用户拥有,跨提供商控制平面。** `AnthropicProvider`和通用`OpenAICompatProvider`与Anthropic、Google AI Studio(Gemini)、Groq、OpenRouter、DeepSeek、Moonshot(Kimi)、本地Ollama以及其他OpenAI兼容端点通信。 库存和凭证保留在用户的环境中。
- **范围提供商故障转移。** 模型/部署、提供商身份验证/端点、耗尽重试和超时失败被记录,可以将工作转移到下一个排名的合格候选者,包括规划器/合成器故障转移。 格式错误或语义无效的请求仍然快速失败,而不是在提供商之间广播请求。
- **混合一次性/代理。** 任务作为单个调用运行 *或* 作为模型↔工具循环(在Docker隔离的沙箱中运行`run_python`,当有守护进程可用时保留,当没有时由主机托管 `fetch_url` / `read_file`)。
- **共享上下文。** 一个仅追加的 *blackboard* 携带来源;每个任务都获得一个作用域限定、预算限制的仅依赖项工件投影。
- **流式传输 everywhere。** 通过supervisor、worker和synthesizer进行实时token流式传输,每个任务都有并行worker和合作早期停止的标签。
- **可选Web UI。** 一个小型FastAPI + SSE应用程序在浏览器中流式传输运行(计划 → 按任务划分的worker输出 → 合成 → 结果);与真实提供商或无密钥演示一起运行。
- **成本和诚实。** `CostMeter`统计每个模型的用法和成本,并在提供商返回用法时传播一个 *estimated* 标志。
- **防伪评估。** 一个3臂评估(基准 vs. 编排 vs. 单代理)带有打分器,在 **进程 + 文件系统隔离** 下运行不受信任的解决方案代码,因此模型无法伪造通过的分数。
- **测试。** 800+测试,默认情况下无需网络(`FakeProvider` + 本地子进程),`ruff`-clean。
## 架构
```mermaid
flowchart TD
goal(["goal"]) --> S["Supervisor<br/>计划 → 验证任务DAG<br/>(非循环 · 类型 · 一次完成 | 代理)"]
S --> R["路由器<br/>最佳预测拟合每个任务<br/>(硬约束 → 可解释得分)"]
R --> P
subgraph wave["wave 执行 · asyncio 并发 · 快速失败"]
direction TB
P["投影器<br/>作用域限定、预算限制的请求<br/>(系统 + 任务 + 依赖项)"]
P --> W["工作器<br/>一次性"]
P --> AW["代理工作器<br/>模型↔工具循环<br/>(run_python · fetch_url · read_file)"]
end
W --> BB[("黑板<br/>仅追加 · 来源 · 最新胜者")]
AW --> BB
BB --> SY["合成器<br/>合并工件 → 最终答案"]
SY --> result(["结果<br/>+ CostMeter 总计 · 用量 · 持续时间"])
classDef io stroke:#8b5cf6,stroke-width:2px;
classDef store stroke:#f59e0b,stroke-width:2px;
class goal,result io;
class BB store;
```
<details>
<summary>文本版本(在任何地方渲染,例如PyPI或终端)</summary>
```text
┌──────────────┐
目标 ──────────► │ Supervisor │ 计划 → 验证任务DAG(非循环,类型,一次完成|代理)
└──────┬───────┘
▼
┌──────────────┐ 每个任务:硬能力过滤,然后排名配置的证据
│ 路由器 │ 预测拟合
└──────┬───────┘
▼
┌───────────── wave 执行(异步,并发,快速失败) ─────────────┐
│ ┌───────────┐ 作用域限定、预算限制的请求(系统 + 任务 + 依赖项) │
│ │ 投影器 │──────────────────────────────────────────────────────────► │
│ └───────────┘ │
│ ▼ ▼ │
│ ┌─────────┐ 一次完成 ┌───────────────┐ 模型↔工具循环 │
│ │ 工作器 │ │ 代理工作器 │ (run_python 沙箱, │
│ └────┬────┘ └───────┬───────┘ fetch_url,read_file) │
│ └──────────────┬──────────────────┘ │
└───────────────────────┼───────────────────────────────────────────────────┘
▼
┌──────────────────────┐ 仅追加,来源 最新胜者
│ 黑板 │◄──────────────────────────────────────
└──────────┬───────────┘
▼
┌──────────────┐
│ 合成器 │ 合并工件 → 最终答案
└──────┬───────┘
▼
结果 (+ CostMeter 总计,用量,持续时间)
```
</details>
| 组件 | 文件 | 责任 |
|---|---|---|
| Supervisor | `src/volante/supervisor.py` | 分解目标 → 验证任务DAG |
| 路由器 | `src/volante/router.py` | 整个库存 → 合理解的候选者 → 可解释的排名 |
| 投影器 | `src/volante/projector.py` | 作用域限定、预算限制的请求来自黑板工件 |
| 工作器 | `src/volante/worker.py` | 一次完成模型调用 |
| 代理工作器 | `src/volante/agent.py` | 模型↔工具循环,带有每轮记录 |
| 黑板 | `src/volante/blackboard.py` | 仅追加的共享状态,带有来源 |
| 合成器 | `src/volante/synthesizer.py` | 工件 → 最终答案 |
| 运行时 | `src/volante/runtime.py` | 编排:计划 → 波浪 → 合成(流式,快速失败) |
| 提供者 | `src/volante/providers/` | Anthropic + OpenAI兼容适配器(完整/流/工具) |
| 工具 | `src/volante/tools/` | 沙箱 / DockerSandbox,run_python,fetch_url,read_file |
| 评估 | `eval/` | 7个目标(5个小测验 + 2个多部分),3臂比较,防伪打分器 |
## 快速开始
需要 **Python 3.11+** 和 [`uv`](https://docs.astral.sh/uv/)。
```bash
git clone https://github.com/ribato22/volante
cd volante
uv sync --dev # 安装依赖 + 开发工具
uv run pytest # 800+ 测试,无网络
uv run ruff check . # 检查代码风格
# 使用FakeProvider演示查看:无需API密钥:
uv run python examples/fake_provider.py
```
然后至少配置一个真实提供者(参见 [提供者](#providers))并运行演示:
```bash
cp .env.example .env # 填写一个提供者,然后 `set -a; . .env; set +a`
uv run python demo.py # 显示检测到的提供者
uv run python demo.py orchestrate # 完整的supervisor → 工作器 → 合成,实时流式传输
uv run python demo.py agentic # 一个跨提供者的代理编码任务(run_python循环)
uv run python demo.py eval # 3臂评估套件
```
### 示例输出
`demo.py orchestrate`实时流式传输每个阶段,然后打印结果(示意性):
```text
编排演示 — 规划器/合成模型=openai/gpt-4o-mini
(规划 + 工作器 + 合成实时流式传输)
[haiku] 线程运行为一个 - / 任务在并行时间中盛开, / 联结收集所有。
状态:成功
最终:
线程运行为一个 -
任务在并行时间中盛开,
连接收集所有。
成本:$0.001834
```
`demo.py eval`打印3臂表格(`format_report`)。以下是它在最后一次完整运行的实际输出 - **编排失败**:
```text
目标 胜者 基线 编排 代理
--------------------------------------------------
slugify 基线 1.00 1.00 0.48
roman 基线 1.00 0.80 0.70
calc 基线 0.99 0.86 0.27
csv_stats 基线 1.00 0.84 0.88
json_flatten 基线 1.00 0.80 0.70
textkit 基线 1.00 1.00 0.42
ledger 基线 1.00 1.00 0.88
toolbelt 基线 1.00 1.00 0.70
debug_gauntlet 编排 0.93 0.97 0.63
--------------------------------------------------
胜者:基线=8 编排=1 代理=0 平局=0
总计:基线 $0.029908 编排 $0.218879 代理 $0.135432
判决: 基线
```
`openai/gpt-4o-mini`,9个目标 x 3臂 x k=5 = 135次真实运行对抗Docker沙箱。编排 **7.3倍** 基线,耗时 **4.7倍**,除了1个目标外所有目标都失败。 这些数字来自`results-nudge2.json`,这是运行写入的自描述工件(模型,k,每个目标的得分,成本)。
重现它 - 这需要您的密钥并且 **花费真实货币**:
```bash
uv run python -m eval.run --k 5 --json results.json
```
**阅读这个判决并理解其限制。** 基线在9个目标中的7个上获得满分1.00,因此在这套测试中没有提升空间:运行建立的是 *"编排对一个模型已经可以在单个回合中解决的任务没有帮助"* - 比声称的陈述要窄得多。 一个编排胜利,`debug_gauntlet`,是唯一一个编写答案更容易通过 **运行** 代码而不是阅读它的目标,它的优势是单个目标上0.04的k=5 - 方向性证明,而不是证明。 代理臂仍然失败了45次运行中的3次。 所有这些都是一项模型在一个小型编程任务类别上的表现;编排是否适用于更强的模型,更大的任务或确实超过一个上下文窗口的工作 **未测量,该项目不做声明。**
基准测试最有用的输出不是分数。 它发现了三个真正的引擎错误 - 代理循环中的确定性活锁,一个评估臂因正确答案而失败的模型,以及一个阻止守卫在第二次警告后放弃,但第二个警告恢复了运行 - 修复这些错误将代理终端失败率从79%降至7%。 它还驳斥了作者的两个假设(更广泛的目标将打破天花板效应;提高迭代上限将有所帮助)。 那就是这个套件的作用。
## 用法
Volante提供了三个接口:一个命令行 **CLI** (主要入口点),一个可选的 **Web UI**,和一个可导入的 **库**。 所有这些都需要至少一个配置的提供者 - 参见 [提供者](#providers) - 或者(仅限Web UI)回落到无密钥演示。
### CLI(主要)
```bash
uv run volante "写一个关于并发性的俳句,然后解释比喻"
```
`volante`实时流式传输计划,每个并行工作器的输出(按任务标记),合成和结果,然后打印摘要。 标志(`volante --help`):
| 标志 | 描述 |
|---|---|
| `--prefer {quality,cash_protect_quota,local,cheap}` | 路由目标。 `quality`(默认)根据预测任务拟合度进行排名;`cash_protect_quota`保留订阅配额;`local`优先考虑合格的本地模型;`cheap`优先考虑配置的经济成本 |
| `--provider NAME` / `-P NAME` | 将规划器/合成基线限制为此提供者 |
| `--model ID` | 覆盖规划器/合成 `model_id` |
| `--list-models` | 打印完整的配置/检测到的路由库存并退出;与 `--json` 结合使用以获取机器可读的输出 |
| `--usage` | 打印最近的使用账单(`~/.volante/usage.jsonl`)- 包括通过MCP委派运行的运行;与 `--json` 结合使用 |
| `--json` | 以一行可解析的JSON打印运行摘要;禁用流式传输 |
| `--no-stream` | 禁用计划/工作器/合成文本的实时流式传输 |
| `--version` | 打印安装的版本并退出 |
退出代码:`0` 成功,`1` 运行失败,`2` 配置错误(例如未配置提供者),`130` Ctrl-C(打印已流式的部分输出 - 从不原始跟踪)。
摘要报告 `billed_usd`(实际花费)vs. `credit_usd`(订阅/计划API等效值,不是现金),物理 `subscription_calls`,和每个任务的路由跟踪。 JSON模式还包括每个合格/拒绝的候选者,分数组件,所选模型和实际执行的模型。
### Web UI
```bash
uv sync --extra ui
uv run python -m webui # 然后打开 http://127.0.0.1:8000
```
一个小型FastAPI + Server-Sent-Events 应用程序在浏览器中实时流式传输运行 - 计划,每个并行工作器的输出(按任务标记),合成和最终结果与成本和模型路由一起。 它使用您的配置提供者运行,或者如果没有设置任何提供者,则使用内置的 `FakeProvider` 演示(不需要API密钥)。 此功能是 **源代码checkout 功能` - `webui/` 不会在构建的轮子/PyPI 包中发布。
`VOLANTE_UI_HOST` / `VOLANTE_UI_PORT` 覆盖绑定地址。 除非设置了 `VOLANTE_UI_AUTH_TOKEN`,否则Volante拒绝非回环主机; `VOLANTE_UI_ALLOWED_HOSTS` 设置客户端将使用的主机名逗号分隔列表。`VOLANTE_UI_MAX_GOAL_CHARS` (默认 `20000`)和 `VOLANTE_UI_MAX_CONCURRENT_RUNS` (默认 `2`)限制输入和并发度。该页面仅使用 `textContent` 通过注入插入所有模型输出(从不原始 HTML),因此流式文本无法注入标记。 `/usage` 页面(从标头链接)显示使用账单低于。
### 监控使用情况
每次从 CLI、Web UI 和 **MCP 服务器** 运行,都会将一行 JSON 日志追加到使用情况账单中 - 默认情况下为 `~/.volante/usage.jsonl`(`VOLANTE_USAGE_LOG` 重新定位,留空则禁用)- 以监控 IDE 代理通过 MCP 将目标委派给 Volante:
```bash
uv run volante --usage # 最近的运行 + 总计,新鲜度优先
uv run volante --usage --json # 相同,但作为一个 JSON 对象
```
Web UI `/usage` 仪表板读取相同的使用账单(摘要图块 + 最新运行表)。设置 `VOLANTE_LOG=debug` (或 `info`/`warning`/`error`),在 stderr 上引发引擎诊断 - 用于 MCP 服务器在客户端服务器输出面板中显示(例如 VS Code 的 **输出** → Volante MCP 服务器);它默认情况下保持沉默,从不写入 stdout。
### 库
```python
import asyncio
import volante
async def main() -> None:
registry, providers, model_id = volante.build_providers_from_env()
factory = await volante.make_verified_runtime_factory(
registry, providers, model_id
)
runtime = factory()
result = await runtime.aexecute("your goal")
print(result.status, result.billed_usd, result.credit_usd, result.cost_estimated)
asyncio.run(main())
```
一个 `Runtime` 是 **单次使用** 的:它运行一个目标,其会计核算,路由跟踪和规划器都是每个运行的。再次调用 `factory()` 以获取每个目标(在同一个或重叠的 `aexecute` 上调用同一个实例将被拒绝并引发 `RuntimeError`,而不是静默地混淆两个运行的数字)。读取 `result.cost_estimated` 以及金额 - 它是 `True`,当提供者报告没有标记计数,至少有一个调用的费用不是由提供者报告,而是根据配置的费率推断出来的。
顶级 `volante` 包重新导出公共库 API(`Runtime`、`Registry`、`Router`、`RoutingDecision`、`ModelQualityProfile`、库存帮助器、`build_providers_from_env`、`make_verified_runtime_factory`、`RunResult`、`ModelInfo`、`Task`、`LLMProvider`、`ProviderError` - 参见 `volante.__all__`)因此您不需要深入到子模块中。
参见 [`examples/`](examples/) 中的可运行脚本 - 包括 [`examples/fake_provider.py`](examples/fake_provider.py),它根本不需要 API 密钥。有关分步游览,请参阅 demo 脚本:`uv run python demo.py orchestrate|agentic|eval`(逐步解释见 [快速开始](#quickstart))。
# 原始完成;`append` 会破坏严格的 JSON 规划,因此除非你知道原因,否则请保持未设置。
export CODEX_ENABLED=1 CODEX_TIER=3 # 需要 `codex login`
uv run volante "你的目标"
```
> ⚠️ **订阅运行是无现金的,但会消耗您的交互式 Claude Code / Codex 配额** —
> 与您的交互式编码会话使用的同一个池。大量编排运行可能会触发速率限制暂停。
> 默认的 `quality` 目标优先考虑每个任务中预测的最高拟合度,
> 这可能会倾向于订阅模式。传递 `--prefer cash_protect_quota` 以缓解这种情况 —
> 它会将批量/简单工作发送到更便宜的本地/免费层模型,并仅为困难任务保留订阅模型。
> 建议使用卡付费、免费层或本地模型作为 **planner**:订阅 CLI 忽略
> `temperature`,因此 Volante 重试规划并进行自我纠正,并可以在实时解析计划检查后将 `claude -p` 作为 planner 放在后面(只有当它明显发出有效的计划 JSON 时才会规划)。
>
> 这驱动了 **官方无头 CLI**(`claude -p`,`codex exec`),您已经登录到这些 CLI —
> 绝不会是 claude.ai / ChatGPT 网页应用。抓取这些网页应用未实现(这会违反他们的服务条款)。
### 在您的 IDE(VSCode)& MCP 中
Volante 是一个 CLI,因此它已经在任何编辑器的集成终端中工作(`uv run volante …"`)。对于 VSCode,有两个额外的便利:
**1. 一键任务。** 仓库附带了 [`.vscode/tasks.json`](.vscode/tasks.json)。打开
*终端 → 运行任务…* (或按 `⌘/Ctrl+Shift+B`)并选择:
| 任务 | 它执行的操作 |
|------|--------------|
| **Volante:运行目标** | 提示输入目标并编排它(流式传输计划 → 工作程序 → 合成)。 |
| **Volante:Web UI** | 在 <http://127.0.0.1:8000> 提供实时 Web UI。 |
| **Volante:MCP 服务器(stdio)** | 为 AI 代理集成运行 MCP 服务器(如下)。 |
| **Volante:测试 / 校验** | 对项目进行 `pytest` / `ruff`。 |
**2. MCP 服务器 — 让 AI 在您的编辑器中调用 Volante。** Volante 附带了一个
[MCP](https://modelcontextprotocol.io) 服务器([`volante_mcp/`](volante_mcp/)),暴露一个工具,
`volante_run(goal, prefer?)`,它计划 → 路由 → 运行 → 合成并返回最终答案
以及诚实的现金/计划信用页脚。任何具有 MCP 能力的助手(Claude Code、Cursor、VS Code
Copilot *代理模式*、Windsurf)都可以将整个目标委托给 Volante。
无需克隆即可安装(推荐),或从源代码检出:
```bash
# 无克隆 — uv 按需获取已发布的包 + `mcp` 额外内容:
uvx --from "volante[mcp]==0.3.1" volante-mcp
# 或安装它并运行控制台脚本:
pip install "volante[mcp]==0.3.1" # 然后:
volante-mcp
# 或从源代码检出:
uv sync --extra mcp && uv run --extra mcp python -m volante_mcp
```
用您的客户端注册它。 **Claude Code** — 一个命令:
```bash
claude mcp add volante -- uvx --from "volante[mcp]==0.3.1" volante-mcp
```
**Cursor / VS Code / Windsurf** — 添加到客户端的 MCP 配置(例如 `.cursor/mcp.json`,或
VS Code 的 `.vscode/mcp.json` 在 `"servers"` 键下):
```jsonc
{
"mcpServers": {
"volante": {
"command": "uvx",
"args": ["--from", "volante[mcp]==0.3.1", "volante-mcp"]
}
}
}
```
服务器读取环境中的提供程序,与 CLI 相同(包括
`CLAUDE_CODE_ENABLED` / `CODEX_ENABLED`),因此请至少配置一个提供程序 —
它 **不会** 恢复到演示。完整的品牌 VSCode *扩展* 故意 **不** 随附;
CLI、任务和 MCP 服务器涵盖相同的范围。
**在官方 MCP 注册表中。** Volante 发布到
[官方 MCP 注册表](https://registry.modelcontextprotocol.io) 作为 `io.github.ribato22/volante`
(一个验证的 [`server.json`](server.json) 清单和一个 `publish-mcp.yml` GitHub Actions 工作流
,该工作流通过 OIDC 在每个版本发布时重新发布)。诸如 [mcp.so](https://mcp.so)、
[PulseMCP](https://www.pulsemcp.com) 和 [Glama](https://glama.ai) 等目录都从中索引。
**作为 Claude Code 插件。** 该仓库还兼作插件市场 — 一个命令将 MCP 服务器和 `/volante:run` 斜杠命令连接到 Claude Code:
```text
/plugin marketplace add ribato22/volante
/plugin install volante@volante
```
需要 [`uv`](https://docs.astral.sh/uv/) 在您的 PATH 上(插件使用
`uvx` 启动服务器)。请参阅 [`plugins/volante/`](plugins/volante/)。
**其他 MCP 客户端(Codex、Cursor、Windsurf、Gemini CLI、Cline)。** 这些客户端没有插件市场 —
它们通过配置使用 MCP 服务器。将它们指向相同的启动命令:
- **OpenAI Codex CLI** — `codex mcp add volante -- uvx --from "volante[mcp]==0.3.1" volante-mcp`
(在 `~/.codex/config.toml` 中写入一个 `[mcp_servers.volante]` 块;使用重复的
`--env KEY=VALUE` 添加提供程序)。
- **Gemini CLI** — `gemini mcp add volante uvx -- --from "volante[mcp]==0.3.1" volante-mcp`
(需要 `--` 因为 Volante 的第一个参数是 `--from`)。
- **Cursor / Windsurf / Cline / Roo** — 将标准 `mcpServers` 条目添加到客户端的 MCP
配置(`~/.cursor/mcp.json`,`~/.codeium/windsurf/mcp_config.json`,或 Cline 设置):
```json
{ "mcpServers": { "volante": {
"command": "uvx",
"args": ["--from", "volante[mcp]==0.3.1", "volante-mcp"],
"env": { "CLAUDE_CODE_ENABLED": "1", "ANTHROPIC_API_KEY": "sk-ant-..." }
} } }
```
在每个客户端的 `env` 块中设置您的提供程序(`CLAUDE_CODE_ENABLED`、`CODEX_ENABLED`、
`ANTHROPIC_API_KEY`、`OPENAI_COMPAT_*`)。
**Claude Desktop & Smithery — MCPB 捆绑包。** 一个 MCPB 捆绑包
[release](https://github.com/ribato22/volante/releases) 作为 `volante-<version>.mcpb` 附加到每个
[版本](https://github.com/ribato22/volante/releases)。 **在 Claude
Desktop 中打开它** 以实现一键安装(它显示一个提供者配置 UI)。或将其发布到
[Smithery](https://smithery.ai) 作为 *本地* 服务器 — 因为 Volante 是 stdio(不是托管的 HTTPS
端点),因此使用 CLI 捆绑包路径,而不是“发布 URL” Web 表单:
```bash
# 从版本中下载 volante-<version>.mcpb,然后(需要 Smithery API 密钥):
npx -y @smithery/cli mcp publish ./volante-<version>.mcpb -n <your-namespace>/volante
```
该捆绑包封装了 `uvx --from "volante[mcp]==0.3.1" volante-mcp`,因此它在本地运行,您的
订阅 CLI + API 密钥像往常一样工作(需要 `uv` 在 PATH 上)。
## 提供者
为任意子集设置环境变量。每个已配置的模型都成为用户模型清单的一部分,被路由器考虑;
**Anthropic > OpenAI-compat > Kimi > Ollama** 优先级仅选择默认计划器/合成器。
请参阅 [`.env.example`](https://github.com/ribato22/volante/blob/main/.env.example) 获取完整列表。
| 提供者 | 环境变量 | 访问权限 |
|---|---|---|
| **Anthropic** (Claude) | `ANTHROPIC_API_KEY` | 付费 API (`console.anthropic.com`) |
| **通用 OpenAI 兼容** | `OPENAI_COMPAT_BASE_URL`、`OPENAI_COMPAT_MODEL` (+`_KEY`/`_NAME`/`_CONTEXT`/…) | 任何 OpenAI 兼容端点 |
| **Moonshot / Kimi** | `MOONSHOT_API_KEY` | 付费 API |
| **Ollama** | `OLLAMA_BASE_URL` | **本地且免费** |
### 模型清单和质量证据
Volante 绝不会猜测帐户拥有的远程模型。提供者目录和授权 API 不一致,可能需要额外权限,
并且不能证明模型当前可用。相反,路由清单是明确且可审计的:
```bash
# 以逗号分隔的列表;单数形式保持向后兼容。
export ANTHROPIC_MODELS=claude-opus-4-8,claude-sonnet-4-5
export ANTHROPIC_NAMES=anthropic/opus,anthropic/sonnet
export MOONSHOT_MODELS=kimi-k3,kimi-k2.6
export OLLAMA_MODELS=qwen2.5-coder:14b,llama3.2
export CLAUDE_CODE_MODELS=opus,sonnet
export CODEX_MODELS=gpt-5-codex,gpt-5-codex-mini
uv run volante --list-models
uv run volante --list-models --json
```
`*_NAMES` 是可选的,必填时必须包含每个线缆模型的一个规范 ID。
所有已配置的模型都已注册;不会静默添加默认种子。清单命令是
离线的:“已配置/检测到”并不声称具有实时资格、配额或服务可用性。
在执行时,显式模型/部署未找到或模型访问拒绝仅标记该候选不可用。
通用身份验证或端点故障会标记提供者不可用。Volante 记录任一回退事件,
并可以尝试下一个排名模型;格式错误或语义无效的请求仍然会快速失败,
而不是盲目调用每个提供者。
没有测量证据,`quality` 故意成为基于声明的优势、
层、上下文/输出裕度以及任务难度进行的 **预测**。Volante 不会填充该预测:
一个表示相同事物关于每个合格模型的评分组件(当没有模型声明特殊优势时为 `task_fit`,
当没有配置配置文件时为 `reliability`)赋予 **零权重**,
其份额重新分配给实际具有信息的组件。路由跟踪会命名它所删除的组件,
因此基于层级的排名会像那样读取,而不是隐藏在 45 点的“任务适应性”常数后面。
两个杠杆可以重新打开这些组件。
**1. 声明模型实际上擅长什么。** 除了任务类型的必需优势
(`coding` 表示 `code`,`reasoning` 表示其他),这些可选标签提高了 `task_fit`,
并让同一层级的同行排名分开:
| 任务类型 | 提高适应性的可选优势标签 |
|---|---|
| `code` | `software_engineering`、`debugging`、`instruction_following` |
| `research` | `research`、`grounding`、`long_context` |
| `write` | `writing`、`creativity`、`instruction_following` |
| `analyze` | `analysis`、`math`、`long_context` |
使用 `*_STRENGTHS` 环境变量(例如
`ANTHROPIC_STRENGTHS=coding,reasoning,software_engineering,debugging`)
或在覆盖文件中按模型设置它们。这些是 **您** 的声明,而不是供应商声称 Volante 内置的内容。
**2. 从您拥有的测量结果中校准。** 将您实际观察到的分数转换为严格的配置文件 —
无需提供者调用,因此无需花费:
```bash
# measurements.json — 每个观察到的运行一个条目;null 表示“没有可用的内容”:
# {"anthropic/opus": {"code": [1.0, 0.8], "write": [0.9]},
```
# "ollama/qwen": {"code": [0.4, null]}}
}
uv run volante --calibrate measurements.json --calibrate-out quality-profiles.json
export VOLANTE_QUALITY_PROFILES_FILE=$PWD/quality-profiles.json
`--calibrate` 会对每种任务类型取平均值。只有当**所有任务类型都测量过**时,它才会发出 `overall_score`,因为路由器会将该字段应用于所有任务类型,包括您从未触及的任务类型。这样可以防止您的编码证据被视为研究能力。部分覆盖时会省略该字段,路由器会回退到粗略的声明层级,并在跟踪中说明,而不是引用从未查看过的配置文件。当覆盖**完整**时,它会对每种类型的平均值进行宏平均,因此不平衡的样本(30 次 `code` 运行,1 次 `write` 运行)描述的是模型,而不是您的采样。
`confidence` 跟随**最弱的采样**任务类型,并且上限为 `1.0` — 路由器对每种任务类型都应用一个置信度,因此不相关的运行不得用作单个观测值的参考。因此置信度不会因为无关的运行而显得过于自信。 `reliability_score` 仅在您记录了 `null` 运行次数时才会发出:从低分数推导出它会使可靠性组件成为质量组件的副本。模型 ID 必须存在于您配置的库存中(加载器是严格的),并且输出会替换先前的配置,而不是合并。因此,请为所有关心的模型校准 **单个文件**。
**这些测量值来自哪里。** `eval/calibrate_models.py` 运行评估套件的基准测试臂 —— 一次一个模型,一次一个调用,无需编排 —— 跨多个模型,并为您写入测量文件。它会花费实际的资金(`models x goals x k` 次调用):
```bash
uv run python -m eval.calibrate_models --models gpt-4.1-nano,gpt-4o-mini,gpt-4.1 --k 3
uv run volante --calibrate measurements.json --calibrate-out quality-profiles.json
```
`measurements.json` 和 `quality-profiles.json` 是实际运行的示例(2026-07-29,81 次调用)。请将其视为有效的示例,而不是默认值。它们描述了三个 OpenAI 模型,您可能没有这些模型,路由器只会加载您指向的配置文件。
**测量结果的作用。** 三个 OpenAI 模型在 `code` 上产生了干净的单调梯度 —— `gpt-4.1-nano` 为 0.951,`gpt-4o-mini` 为 0.990,`gpt-4.1` 为 1.000 —— 这与路由器已经使用的层级顺序一致,因此在同一家族内进行校准确认了启发式方法,而不是推翻它。测量**第二个家族**改变了局面:
| 模型 | `code` | `analyze` |
|---|---|---|
| `openai/gpt-4.1` | 1.000 | 0.417 |
| `openai/gpt-4o-mini` | 0.990 | **0.167** |
| `openai/gpt-4.1-nano` | 0.951 | 0.183 |
| `glm/glm-4.5-flash` | **0.704** | 0.389 |
`glm-4.5-flash` 在 `code` 上排名**最后**,在分析上排名**第二**;`gpt-4o-mini` 在 `code` 上几乎最佳,在分析上排名**最差**。这是真正的排名交换 —— 在一项任务类型上 0.29 的反向变化,在另一项任务类型上 0.22 的正向变化 —— 相对于 0.016 的家族内波动,这是纯粹的噪声。不同实验室的模型具有真正互补的优势,这是在任务路由上建立假设的基础。以前从未在此测试过。
加载这些证据并排除最强的模型后,路由器选择 **`gpt-4o-mini` 用于 `code` 和 `glm-4.5-flash` 用于 `analyze`** —— 根据测量结果而不是层级常量选择不同模型用于不同工作。当最强的模型可用时,它仍然赢得两者,因为它在两者上都真正是最好的;排名交换反映在它下面的所有内容中,这就是成本或配额目标实际选择的内容。
关于信任您自己的配置文件之前需要知道的两个限制:
- **套件饱和。** `gpt-4.1` 得分 27/27 完美,因此无法测量更高的分数,梯度被压缩到顶部 5%。在 `k=1` 时,**最弱**的模型碰巧得分为 1.000;只有 `k=3` 才能区分它们。请在 `k>=3` 时进行校准,并期望一个任务集让所有模型都通过,从而告诉您几乎没有什么信息。
- **一种任务类型占据所有四个。** 套件中的每个目标都是编码任务,因此仅限 `code` 的运行仅测量 `code`。以前会泄漏:`overall_score` 源自已测量的内容,然后应用于每种任务类型,因此编码证据会无声无息地成为研究声明。现在不会了;通用声明现在需要完整的覆盖。效果在分数中可见:加载仅限 `code` 的配置文件时,`research` 的排名与没有配置文件时相同,而 `code` 会发生变化。 `eval/tasks_text.py` 为其他类型添加了目标。
配置文件格式与您可以手动编写的格式相同:
```json
{
"anthropic/opus": {
"task_scores": {"code": 0.96, "research": 0.94, "write": 0.91, "analyze": 0.95},
"overall_score": 0.95,
"reliability_score": 0.98,
"confidence": 0.9,
"source": "team-eval-2026-07"
},
"ollama/qwen2.5-coder:14b": {
"task_scores": {"code": 0.78},
"overall_score": 0.70,
"reliability_score": 0.86,
"is_local": true,
"confidence": 0.8,
"source": "team-eval-2026-07"
}
}
```
将该严格的 JSON 保存在源代码控制之外,并设置 `VOLANTE_QUALITY_PROFILES_FILE=/absolute/path/to/quality-profiles.json`。分数归一化为 `0..1`;支持的任务键是 `code`、`research`、`write` 和 `analyze`。未知的模型 ID、字段、JSON 键、无效/非有限分数和凭证样额外字段都会关闭。决策跟踪记录了证据源和警告,而不是声称经验上普遍的赢家。
存储库中包含一个 3 臂评估框架,但 Volante 尚未发布代表性的跨提供商经验基准测试结果或自动校准质量配置文件。请将配置的分数视为用户拥有的证据,并针对您自己的任务分布进行验证,并在模型或端点更改时重新校准它们。
多个家族的设置共享提供程序级别的默认值。当同一个家族中的两个模型具有不同的硬件能力、限制、价格或层级时,请在第二个严格的 JSON 文件中按规范的模型 ID 声明:
```json
{
"anthropic/haiku": {
"strengths": ["reasoning"],
"context_window": 200000,
"max_output_tokens": 64000,
"supports_tools": true,
"cost_per_1k_in": 0.001,
"cost_per_1k_out": 0.005,
"tier": 2
},
"anthropic/opus": {
"strengths": ["coding", "reasoning", "long_context"],
"context_window": 1000000,
"max_output_tokens": 128000,
"supports_tools": true,
"cost_per_1k_in": 0.005,
"cost_per_1k_out": 0.025,
"tier": 4
}
}
```
设置 `VOLANTE_MODEL_OVERRIDES_FILE=/absolute/path/to/model-overrides.json`。覆盖项可以包含上面显示的七个字段之一;模型 ID 必须已经存在于配置的库存中。质量配置文件携带软的、基于评估的证据,而模型覆盖项携带用于资格、投影、路由和计费的硬/经济元数据。两个文件都不接受秘密。
还明确了 Agentic 工具的可用性。`run_python` 仅在可用的隔离沙箱中提供(参见[安全](#security--limitations-honest));设置 `VOLANTE_FETCH_ALLOWLIST=example.com,docs.python.org` 以启用 `fetch_url`,并设置 `VOLANTE_READ_ROOT=/absolute/path/to/trusted/files` 以启用 `read_file`。主管为每个 Agentic 任务声明 `required_tools`,当这些工具未启用或从未实际调用时,Volante 会拒绝计划或执行。主机名允许列表不能防御 DNS 绑定/私有解析攻击,`VOLANTE_READ_ROOT` 应指向一个受信任的树,而不具有对抗性并发符号链接更改。
> **订阅 CLI 代理是可选的,它们会消耗您的交互配额。** 抓取 claude.ai / ChatGPT 不会构建(ToS,脆弱,存在封禁风险)。相反,Volante 可以驱动您已经登录的**官方无头 CLI** —— Claude Code (`claude -p`) 和 Codex (`codex exec`) —— 无需 API 密钥。此功能**默认关闭**(`CLAUDE_CODE_ENABLED=1` / `CODEX_ENABLED=1` 加上已安装的 CLI),并且**永远不会**被评估使用。诚实声明:`claude -p` 和 `codex exec` 目前会占用与聊天应用**相同的交互池**(不是单独的/计量的桶),因此完整的编排运行 —— 尤其是 3 臂评估 —— 可能会烧毁您的 Claude Code / Codex 额度并触发中间暂停。Volante 报告 `credit_usd`(消耗的订阅价值)与 `billed_usd`(现金)分别计费,与仅限硬/高层任务到订阅(批量工作转到本地/免费层级),并在每次运行中限制物理订阅调用次数(`VOLANTE_MAX_SUBSCRIPTION_CALLS`,默认为 16,包括订阅计划器兼容性预飞行、规划、重试、工作人员/代理回合和合成)。在默认的 `quality` 目标下,任何符合条件的订阅模型都可能被选中;硬任务保留行为仅适用于 `--prefer cash_protect_quota`。
**免费、高智力选项** —— Google AI Studio(Gemini Flash),通过通用插槽:
```bash
export OPENAI_COMPAT_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
export OPENAI_COMPAT_KEY=<ai-studio-key> # aistudio.google.com/apikey
export OPENAI_COMPAT_MODEL=gemini-flash-latest # pick a current model from the endpoint's /models
export OPENAI_COMPAT_NAME=google/gemini-flash
uv run python demo.py orchestrate
```
通用插槽默认为上下文 128k,输出 8k,工具支持**关闭**,费用 0。设置 `OPENAI_COMPAT_TOOLS=true` 仅在确认函数调用支持后,并设置提供程序的实际成本/层级/优势;Volante 注册 `ModelInfo` 以便路由和计费使用声明的元数据,而不是隐藏的种子。
**一次多个提供商/模型** —— 添加 `OPENAI_COMPAT_2_*`、`OPENAI_COMPAT_3_*` 等(每个都有自己的 `model_id` / 定价 / 上下文),或使用 Anthropic、Moonshot、Ollama、Claude Code 和 Codex 的复数模型列表。插槽可以指向不同的提供商或同一兼容端点的多个模型。例如,配置 Gemini 加 Groq,以便主管计划在 Gemini 上运行,而 Groq 模型运行并行工作线程。请参阅 [`.env.example`](https://github.com/ribato22/volante/blob/main/.env.example)。
## 评估
`demo.py eval` 运行一个 **3 臂** 比较,涵盖 5 个综合编码目标:**基准测试**(一个强大的模型,一次性),**编排**(完整的引擎)和 **agentic-single**(一个模型 + 一个 `run_python` 循环,无分解)。每个目标由一个隐藏的参考测试得分。
评估器在**进程 + 文件系统隔离**的保护下运行模型的生成的 `solution.py`:一个受信任的运行程序在单独的进程中驱动不可信的解决方案,从未看到预期的输出(基于身份验证的 RPC),因此解决方案必须实际计算正确的答案 —— 它不能伪造通过的分数。
一起阅读判决和评估框架发出的警告:
- `WARNING: some costs are estimated …` —— 提供者返回了没有使用情况;成本比较是软的。
- `WARNING: agentic arm failed N run(s) …` —— `0.0` 可能是基础设施/提供者故障,而不是能力。
- `WARNING: goal(s) […] produced NO trusted result …` —— 参考运行程序本身已损坏;这些分数是评估框架的产物,而不是真正的零。
## 安全与局限性(诚实)
Volante 是 **alpha 软件**;其隔离保证有意为范围限定,并有文档记录。
- **默认情况下代码执行是安全的,并且会失败关闭。** 如果没有设置 `VOLANTE_SANDBOX`,Volante 会探测正在运行的 Docker 守护进程:如果有响应,`run_python` 会在容器中执行(`--network none`,只读根目录,删除功能,cgroup 限制)。如果没有响应,`run_python` **不会提供** —— 计划程序会告知它无法执行代码 —— 而不是静默地用您的文件和网络运行模型编写的代码。子进程 `Sandbox` 保护**事故**,而不是**对手**(主机网络和磁盘保持可达),因此它现在是一个明确的选项:`VOLANTE_SANDBOX=subprocess`,每次启动时都会打印警告。未知的 `VOLANTE_SANDBOX` 值被拒绝,而不是静默地降级。
- **外部工具是主机中介的。** `fetch_url`(主机名允许列表,无重定向,边界正文)和 `read_file`(解析路径根目录检查,边界读取)在受信任的编排器中运行,以便沙盒代码保持网络隔离。允许列表不会破坏 DNS 绑定/私有地址解析,并且根目录检查对于对抗性符号链接交换不是竞争安全的;请使用受信任的域和受信任的本地树。提示注入仅在 Docker 下保持。
- **评估计分是防伪的,尽力而为的 POSIX。** 进程 + 文件系统隔离阻止了解决方案伪造分数;调用 `setsid()` 的解决方案仍然可以逃避 `killpg` 组(时钟超时仍然限制运行时间)。它是进程隔离,而不是任意敌对代码的安全沙箱。
- **永远不要在模型上下文中放置秘密。** 将允许列表和读取文件根目录视为明确的暴露控制,而不是通用对抗性安全沙箱。
## 项目布局
```text
src/volante/ # 引擎(可导入包:`volante`)
providers/ # Anthropic + OpenAI 兼容适配器,FakeProvider
tools/ # Sandbox,DockerSandbox,run_python,fetch_url,read_file
eval/ # 目标,3 臂框架,防伪记分器,运行程序
examples/ # 小的可运行库 API 脚本(包括无密钥 FakeProvider 演示)
webui/ # 可选的 FastAPI + SSE Web UI(uv run python -m webui)
tests/ # 800+ 测试(单元测试 + 可选集成测试)
docs/ # 内部设计/构建记录 — 参见 docs/README.md;不是用户文档
demo.py # 端到端演示(orchestrate | agentic | eval)
```
## 开发
- **测试驱动,默认零网络。** `uv run pytest` 使用 `FakeProvider` 和本地子进程;集成测试标记为 `integration`,默认情况下跳过(`uv run pytest -m integration` 启用)。
- **Lint:** `uv run ruff check .`(行长度 100;`E,F,I,UP,B`)。
- 欢迎贡献 - 参见 [CONTRIBUTING.md](https://github.com/ribato22/volante/blob/main/CONTRIBUTING.md) 和我们的 [行为准则](https://github.com/ribato22/volante/blob/main/CODE_OF_CONDUCT.md)。安全报告: [SECURITY.md](https://github.com/ribato22/volante/blob/main/SECURITY.md)。发布说明: [CHANGELOG.md](https://github.com/ribato22/volante/blob/main/CHANGELOG.md)。
## 项目状态与非目标
Volante 是一个 **alpha,透明,用户拥有的模型路由器和编排控制平面**。它今天可以通过其 CLI、库、Web UI 和 MCP 服务器用于用户明确配置的库存和提供商。是 **不是** 一个托管的模型网关、自动发现服务或保证其预测的经验上最优的接口。接口仍然可以进化。
生产使用时,请验证 Volante 的路由是否针对代表性的工作负载,供应和维护您自己的质量证据,选择文档中记录的隔离模式,并保留应用程序级别的恢复路径。框架实现是故意的:主管、路由器、投影和黑板行为保持可检查,而不是隐藏在 LangChain、LiteLLM 或 CrewAI 抽象后面。
## 路线图
- 发布代表性的跨提供商 3 臂基准测试结果,并解释编排是否优于单个模型。
- 从代表性的用户评估中自动校准特定任务的质量配置文件。
- 异步生成器/背压流 API。
- Ollama 工具调用 / 流集成覆盖。
## 许可证
[MIT](https://github.com/ribato22/volante/blob/main/LICENSE) © 2026 ribato。
<!-- MCP 注册表所有权标记(证明此 PyPI 包与服务器名称匹配)。 -->
<!-- mappers映射。)
<!-- mcp-name: io.github.ribato22/volante -->
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器