LLM Routing $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#llm-routing">LLM 路由
With the rapid proliferation of large language models (LLMs) — each optimized for different strengths, style, or latency/cost profile — routing has become an essential technique to operationalize the use of different models. Plano provides three distinct routing approaches to meet different use cases: Model-based routing, Alias-based routing, and Preference-aligned routing. This enables optimal performance, cost efficiency, and response quality by matching requests with the most suitable model from your available LLM fleet.大语言模型(LLM)越来越多。有的擅长逻辑,有的擅长文采,有的快,有的省钱。怎么选模型,成了个事。Plano 提供三种路由方式:基于模型路由、基于别名路由、基于偏好路由。按需匹配,性能、成本、质量,都能兼顾。
Note注意
For details on supported model providers, configuration options, and client libraries, see LLM Providers.模型提供商、配置项、客户端库,详见“LLM Providers”。
Routing Methods $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#routing-methods" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#routing-methods'">路由方法
Model-based routing $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#model-based-routing" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#model-based-routing'">基于模型路由
Direct routing allows you to specify exact provider and model combinations using the format provider/model-name:直接路由,写死提供商和模型名,格式为 provider/model-name:
Use provider-specific names like
openai/gpt-5.2oranthropic/claude-sonnet-4-5用具体的名,比如 openai/gpt-5.2 或 anthropic/claude-sonnet-4-5。Provides full control and transparency over which model handles each request哪个请求走哪个模型,清清楚楚,完全可控。
Ideal for production workloads where you want predictable routing behavior生产环境用这个,稳。
Configuration $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#configuration">配置
Configure your LLM providers with specific provider/model names:配置 LLM 提供商,填好 provider/model 名:
listeners:
egress_traffic:
address: 0.0.0.0
port: 12000
message_format: openai
timeout: 30s
llm_providers:
- model: openai/gpt-5.2
access_key: $OPENAI_API_KEY
default: true
- model: openai/gpt-5
access_key: $OPENAI_API_KEY
- model: anthropic/claude-sonnet-4-5
access_key: $ANTHROPIC_API_KEY
Client usage $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#client-usage">客户端用法
Clients specify exact models:客户端指定模型:
# Direct provider/model specification
response = client.chat.completions.create(
model="openai/gpt-5.2",
messages=[{"role": "user", "content": "Hello!"}]
)
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4-5",
messages=[{"role": "user", "content": "Write a story"}]
)
Alias-based routing $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#alias-based-routing" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#alias-based-routing'">基于别名路由
Alias-based routing lets you create semantic model names that decouple your application from specific providers:起个语义化的别名,应用层不用管底下换了哪个提供商:
Use meaningful names like
fast-model,reasoning-model, orplano.summarize.v1(see Model Aliases)起名要直观,比如 fast-model、reasoning-model 或 plano.summarize.v1(参考 Model Aliases)。Maps semantic names to underlying provider models for easier experimentation and provider switching别名映射到具体模型。换模型方便,做实验也快。
Ideal for applications that want abstraction from specific model names while maintaining control想解耦又想可控,用这个。
Configuration $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#id3">
Configure semantic aliases that map to underlying models:配置别名,映射到模型:
listeners:
egress_traffic:
address: 0.0.0.0
port: 12000
message_format: openai
timeout: 30s
llm_providers:
- model: openai/gpt-5.2
access_key: $OPENAI_API_KEY
- model: openai/gpt-5
access_key: $OPENAI_API_KEY
- model: anthropic/claude-sonnet-4-5
access_key: $ANTHROPIC_API_KEY
model_aliases:
# Model aliases - friendly names that map to actual provider names
fast-model:
target: gpt-5.2
reasoning-model:
target: gpt-5
creative-model:
target: claude-sonnet-4-5
Client usage $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#id4">
Clients use semantic names:客户端用别名:
# Using semantic aliases
response = client.chat.completions.create(
model="fast-model", # Routes to best available fast model
messages=[{"role": "user", "content": "Quick summary please"}]
)
response = client.chat.completions.create(
model="reasoning-model", # Routes to best reasoning model
messages=[{"role": "user", "content": "Solve this complex problem"}]
)
Preference-aligned routing (Plano-Orchestrator) $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#preference-aligned-routing-plano-orchestrator" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#preference-aligned-routing-plano-orchestrator'">基于偏好路由 (Plano-Orchestrator)
Preference-aligned routing uses the Plano-Orchestrator model to pick the best LLM based on domain, action, and your configured preferences instead of hard-coding a model.不用写死模型。Plano-Orchestrator 根据领域、动作和偏好,自动挑一个最合适的。
Domain: High-level topic of the request (e.g., legal, healthcare, programming).领域:请求的主题(如法律、医疗、编程)。
Action: What the user wants to do (e.g., summarize, generate code, translate).动作:用户想干什么(如总结、写代码、翻译)。
Routing preferences: Your mapping from (domain, action) to preferred models.路由偏好:领域加动作,对应你喜欢的模型。
Plano-Orchestrator analyzes each prompt to infer domain and action, then applies your preferences to select a model. This decouples routing policy (how to choose) from model assignment (what to run), making routing transparent, controllable, and easy to extend as you add or swap models.Plano-Orchestrator 拆解提示词,推断领域和动作,再按偏好选模型。路由策略和模型分配分开,透明、可控,加模型也容易。
Configuration $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#id5">
To configure preference-aligned dynamic routing, declare a top-level routing_preferences list and attach an ordered models candidate pool to each route. Starting in v0.4.0, routing_preferences lives at the root of the config (not inline under model_providers), which lets multiple models serve the same route — the first entry in models is primary, the rest are fallbacks that the client tries on 429/5xx errors.配置动态路由,在根目录声明 routing_preferences 列表,给每个路由挂上候选模型池。v0.4.0 起,配置移到根节点。一个路由可以配多个模型,第一个是主选,后面是备选。遇 429 或 5xx 错误,自动切备选。
version: v0.4.0
listeners:
- name: egress_traffic
type: model
address: 0.0.0.0
port: 12000
timeout: 30s
model_providers:
- model: openai/gpt-5.2
access_key: $OPENAI_API_KEY
default: true
- model: openai/gpt-5
access_key: $OPENAI_API_KEY
- model: anthropic/claude-sonnet-4-5
access_key: $ANTHROPIC_API_KEY
routing_preferences:
- name: code understanding
description: understand and explain existing code snippets, functions, or libraries
models:
- openai/gpt-5
- anthropic/claude-sonnet-4-5
- name: complex reasoning
description: deep analysis, mathematical problem solving, and logical reasoning
models:
- openai/gpt-5
- name: creative writing
description: creative content generation, storytelling, and writing assistance
models:
- anthropic/claude-sonnet-4-5
- name: code generation
description: generating new code snippets, functions, or boilerplate based on user prompts
models:
- anthropic/claude-sonnet-4-5
- openai/gpt-5
Note
Configs still using the v0.3.0 inline style (routing_preferences nested under each model_provider) are auto-migrated to this top-level shape by the Plano CLI at compile time, with a deprecation warning. Update your config to the form above to silence the warning.v0.3.0 的旧配置会自动迁移,但会报警告。改到新格式,警告就没了。
Client usage $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#id6">
Clients can let the router decide or still specify aliases:客户端可以交给路由选,也可以自己指定别名:
# Let Plano-Orchestrator choose based on content
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Write a creative story about space exploration"}]
# No model specified - router will analyze and choose claude-sonnet-4-5
)
Cost- and latency-aware selection $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#cost-and-latency-aware-selection" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#cost-and-latency-aware-selection'">成本与延迟感知
When a route lists more than one candidate model, you can let Plano reorder that
candidate pool using live cost or latency data instead of relying solely on the
order you wrote them in. This is controlled per route with selection_policy and
backed by one or more model_metrics_sources.路由有多个候选模型时,Plano 能根据实时成本或延迟数据重排模型,不用死守配置顺序。用 selection_policy 控制,配合 model_metrics_sources 使用。
This is useful when several models are equally capable for a route and you want Plano to always reach for the cheapest (or fastest) option first, with the others kept as fallbacks.几个模型能力差不多,用这个,让 Plano 优先选最便宜或最快的,剩下的做备选。
Selection policy $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#selection-policy" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#selection-policy'">选择策略
Attach an optional selection_policy to any entry in routing_preferences:在 routing_preferences 的条目里加 selection_policy:
routing_preferences:
- name: code review
description: reviewing, analyzing, and suggesting improvements to existing code
models:
- anthropic/claude-sonnet-4-5
- groq/llama-3.3-70b-versatile
selection_policy:
prefer: cheapest # cheapest | fastest | none
prefer accepts:prefer 参数:
cheapest— order candidates by total price (input + output rate) ascending, using acostmetrics source.cheapest:按总价(输入+输出)升序排,需配置成本指标源。fastest— order candidates by observed latency ascending, using alatencymetrics source.fastest:按观测延迟升序排,需配置延迟指标源。none(default) — keep the order you declared; no reordering.none(默认):按声明顺序,不重排。
Models that have no data in the selected source are ranked last, in their original order, so routing always degrades gracefully rather than dropping a candidate.没数据的模型排在最后,按原顺序。保证路由不出错,只是降级。
Configuring the pricing source $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#configuring-the-pricing-source" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#configuring-the-pricing-source'">配置定价源
cheapest routing needs a price catalog. Plano’s default pricing provider is
DigitalOcean — its GenAI model catalog is public (no API key, no signup), so cost data
is available out of the box and is what planoai obs uses if you don’t configure
anything. The pricing source is fully swappable: point Plano at models.dev,
or at any endpoint that exposes a supported pricing structure.cheapest 路由需要价格目录。默认用 DigitalOcean,GenAI 模型目录公开,不用 API Key,不用注册,开箱即用。定价源可换,指向 models.dev 或其他支持的接口都行。
The provider field selects which response schema Plano expects (and therefore how it
parses the catalog); the optional url lets you override the endpoint — for example to
use a mirror, a cached copy, or an internal catalog service that returns the same shape.provider 字段决定解析格式;url 字段可覆盖默认地址,用来接镜像、缓存或内部服务。
|
Default catalog URL |
Key format |
Expected structure |
|---|---|---|---|
|
DigitalOcean GenAI model catalog |
|
|
|
|
|
|
Because the source is selected per provider, switching is a one-line change. To stay
on the default DigitalOcean catalog you can omit model_metrics_sources entirely for
planoai obs, or declare it explicitly for routing:按提供商选源,改一行就行。用默认 DigitalOcean 目录,planoai obs 不用配 model_metrics_sources,路由则需显式声明:
model_metrics_sources:
- type: cost
provider: digitalocean # default; uses the public DO GenAI catalog
To switch to models.dev — an open, community-maintained catalog covering a broad range of
providers and models — change the provider (and optionally url):换成 models.dev(社区维护的开源目录),改 provider 和 url:
model_metrics_sources:
- type: cost
provider: models.dev # models.dev | digitalocean
url: https://models.dev/api.json # optional; defaults per provider
refresh_interval: 3600 # optional, seconds; refetch on this interval
model_aliases: # optional; see below
openai/gpt-oss-120b: openai/gpt-4o
To use your own endpoint, pick the provider whose structure your endpoint matches and
override url — Plano parses the response with that provider’s schema:用自己的接口,选个结构匹配的 provider,覆盖 url 就行:
model_metrics_sources:
- type: cost
provider: digitalocean # selects the DO response schema
url: https://catalog.internal.example.com/pricing
Note
The cost metric used for ranking is the sum of the input and output per-million-token rates — a relative signal for ordering candidates, not a per-request bill. For actual per-request cost, see the observability console below.成本指标是每百万 token 的输入输出价之和,用来做排序参考,不是单次请求账单。单次请求成本看下面的可观测性控制台。
Matching catalog keys to your models $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#matching-catalog-keys-to-your-models" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#matching-catalog-keys-to-your-models'">匹配目录键与模型名
The router looks up each candidate model by the exact name you use in
routing_preferences (e.g. anthropic/claude-sonnet-4-5). models.dev keys models as
creator/model, which lines up with Plano’s provider/model naming, so most models
match automatically.路由按 routing_preferences 里的名查候选模型。models.dev 用 creator/model 格式,跟 Plano 的 provider/model 对应,大部分能自动匹配。
When a catalog key does not match your model name — for example a version skew, or an
open-weight model you serve under a different provider — use model_aliases to map the
catalog key to the Plano model name used in your routing preferences:对不上时,用 model_aliases 把目录键映射到 Plano 模型名:
model_metrics_sources:
- type: cost
provider: models.dev
model_aliases:
# catalog key : plano model name
openai/gpt-oss-120b: openai/gpt-4o
Latency source $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#latency-source" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#latency-source'">延迟源
fastest routing reads observed latency from a Prometheus instance. Provide the query
that returns a per-model latency value (lower is faster), labelled by model_name:fastest 路由从 Prometheus 读延迟。写个查询语句,返回各模型的延迟值(越低越快),打上 model_name 标签:
model_metrics_sources:
- type: latency
provider: prometheus
url: http://prometheus:9090
query: avg by (model_name) (rate(plano_llm_latency_seconds_sum[5m]))
refresh_interval: 60
You can declare both a cost and a latency source at the same time; each route
picks whichever it needs based on its selection_policy.成本源和延迟源可以同时配,路由按 selection_policy 选着用。
Cost in the observability console $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#cost-in-the-observability-console" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#cost-in-the-observability-console'">可观测性控制台的成本
planoai obs displays a per-request USD cost column derived from the same pricing
catalog. By default it reads the cost source from your config (the first
type: cost entry under model_metrics_sources); you can also override it on the
command line:planoai obs 显示单次请求的美元成本,来自定价目录。默认读配置里的第一个成本源,也可以在命令行覆盖:
# Use the cost source from ./config.yaml (default)
planoai obs
# Or override the provider / endpoint explicitly
planoai obs --pricing-provider models.dev
planoai obs --pricing-url https://models.dev/api.json
If no source is configured and no override is given, planoai obs falls back to the
DigitalOcean catalog so the cost column still populates out of the box.没配置源也没覆盖,默认走 DigitalOcean 目录,保证有数。
Plano-Orchestrator $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#id7" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#id7'">Plano-Orchestrator
Plano-Orchestrator is a preference-based routing model specifically designed to address the limitations of traditional LLM routing. It delivers production-ready performance with low latency and high accuracy while solving key routing challenges.Plano-Orchestrator 是基于偏好的路由模型,解决传统路由的局限。它性能好、延迟低、精度高,专为生产环境设计。
Addressing Traditional Routing Limitations:解决传统路由局限:
Human Preference Alignment Unlike benchmark-driven approaches, Plano-Orchestrator learns to match queries with human preferences by using domain-action mappings that capture subjective evaluation criteria, ensuring routing decisions align with real-world user needs.对齐人类偏好:不靠跑分,靠领域-动作映射。捕捉主观评价标准,决策更贴合真实需求。
Flexible Model Integration The system supports seamlessly adding new models for routing without requiring retraining or architectural modifications, enabling dynamic adaptation to evolving model landscapes.灵活集成:加新模型不用重训,也不用改架构,适应模型迭代。
Preference-Encoded Routing Provides a practical mechanism to encode user preferences through domain-action mappings, offering transparent and controllable routing decisions that can be customized for specific use cases.偏好编码路由:通过领域-动作映射编码偏好,决策透明可控,针对场景定制。
To support effective routing, Plano-Orchestrator introduces two key concepts:Plano-Orchestrator 引入两个概念:
Domain – the high-level thematic category or subject matter of a request (e.g., legal, healthcare, programming).领域:请求的主题(如法律、医疗、编程)。
Action – the specific type of operation the user wants performed (e.g., summarization, code generation, booking appointment, translation).动作:具体操作(如总结、写代码、预约、翻译)。
Both domain and action configs are associated with preferred models or model variants. At inference time, Plano-Orchestrator analyzes the incoming prompt to infer its domain and action using semantic similarity, task indicators, and contextual cues. It then applies the user-defined routing preferences to select the model best suited to handle the request.领域和动作都绑定模型。推理时,Plano-Orchestrator 分析提示词,靠语义相似度、任务标识和上下文推断领域和动作,再按配置选模型。
In summary, Plano-Orchestrator demonstrates:总结一下,Plano-Orchestrator 的特点:
Structured Preference Routing: Aligns prompt request with model strengths using explicit domain–action mappings.结构化偏好路由:用显式的领域-动作映射,让模型强项对齐请求。
Transparent and Controllable: Makes routing decisions transparent and configurable, empowering users to customize system behavior.透明可控:决策过程透明,行为可配。
Flexible and Adaptive: Supports evolving user needs, model updates, and new domains/actions without retraining the router.灵活自适应:无需重训,支持新需求、新模型、新领域。
Production-Ready Performance: Optimized for low-latency, high-throughput applications in multi-model environments.生产级性能:针对多模型环境下的低延迟、高吞吐优化。
Self-hosting Plano-Orchestrator $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#self-hosting-plano-orchestrator" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#self-hosting-plano-orchestrator'">自托管 Plano-Orchestrator
By default, Plano uses a hosted Plano-Orchestrator endpoint. To run Plano-Orchestrator locally, you can serve the model yourself using either Ollama or vLLM.默认用托管端点。想本地跑,可以用 Ollama 或 vLLM。
Using Ollama (recommended for local development) $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#using-ollama-recommended-for-local-development" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#using-ollama-recommended-for-local-development'">用 Ollama(推荐本地开发)
Install Ollama安装 Ollama
Download and install from ollama.ai.去 ollama.ai 下载安装。
Pull and serve the routing model拉取并运行路由模型
ollama pull hf.co/katanemo/Arch-Router-1.5B.gguf:Q4_K_M ollama serveThis downloads the quantized GGUF model from HuggingFace and starts serving on
http://localhost:11434.从 HuggingFace 下载 GGUF 量化模型,在 http://localhost:11434 启动。Configure Plano to use local routing model配置 Plano 使用本地路由模型
version: v0.4.0 overrides: llm_routing_model: plano/hf.co/katanemo/Arch-Router-1.5B.gguf:Q4_K_M model_providers: - model: plano/hf.co/katanemo/Arch-Router-1.5B.gguf:Q4_K_M base_url: http://localhost:11434 - model: openai/gpt-5.2 access_key: $OPENAI_API_KEY default: true - model: anthropic/claude-sonnet-4-5 access_key: $ANTHROPIC_API_KEY routing_preferences: - name: creative writing description: creative content generation, storytelling, and writing assistance models: - anthropic/claude-sonnet-4-5Verify the model is running验证模型运行状态
curl http://localhost:11434/v1/modelsYou should see
Arch-Router-1.5Blisted in the response.响应里能看到 Arch-Router-1.5B。
Using vLLM (recommended for production / EC2) $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#using-vllm-recommended-for-production-ec2" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#using-vllm-recommended-for-production-ec2'">用 vLLM(推荐生产/EC2)
vLLM provides higher throughput and GPU optimizations suitable for production deployments.vLLM 吞吐更高,有 GPU 优化,适合生产。
Install vLLM安装 vLLM
pip install vllmDownload the model weights下载模型权重
The GGUF weights are downloaded automatically from HuggingFace on first use. To pre-download:首次使用会自动从 HuggingFace 下载 GGUF。想预下载:
pip install huggingface_hub huggingface-cli download katanemo/Arch-Router-1.5B.ggufStart the vLLM server启动 vLLM 服务
After downloading, find the GGUF file and Jinja template in the HuggingFace cache:下载后,在 HuggingFace 缓存里找 GGUF 文件和 Jinja 模板:
# Find the downloaded files SNAPSHOT_DIR=$(ls -d ~/.cache/huggingface/hub/models--katanemo--Arch-Router-1.5B.gguf/snapshots/*/ | head -1) vllm serve ${SNAPSHOT_DIR}Arch-Router-1.5B-Q4_K_M.gguf \ --host 0.0.0.0 \ --port 10000 \ --load-format gguf \ --chat-template ${SNAPSHOT_DIR}template.jinja \ --tokenizer katanemo/Arch-Router-1.5B \ --served-model-name Plano-Orchestrator \ --gpu-memory-utilization 0.3 \ --tensor-parallel-size 1 \ --enable-prefix-cachingConfigure Plano to use the vLLM endpoint配置 Plano 使用 vLLM 端点
version: v0.4.0 overrides: llm_routing_model: plano/Plano-Orchestrator model_providers: - model: plano/Plano-Orchestrator base_url: http://<your-server-ip>:10000 - model: openai/gpt-5.2 access_key: $OPENAI_API_KEY default: true - model: anthropic/claude-sonnet-4-5 access_key: $ANTHROPIC_API_KEY routing_preferences: - name: creative writing description: creative content generation, storytelling, and writing assistance models: - anthropic/claude-sonnet-4-5Verify the server is running验证服务运行状态
curl http://localhost:10000/health curl http://localhost:10000/v1/models
Using vLLM on Kubernetes (GPU nodes) $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#using-vllm-on-kubernetes-gpu-nodes" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#using-vllm-on-kubernetes-gpu-nodes'">在 Kubernetes 上用 vLLM (GPU 节点)
For teams running Kubernetes, Plano-Orchestrator and Plano can be deployed as in-cluster services.
The demos/llm_routing/model_routing_service/ directory includes ready-to-use manifests:Plano-Orchestrator 和 Plano 可作为集群内服务部署。demos/llm_routing/model_routing_service/ 目录下有清单文件:
vllm-deployment.yaml— Plano-Orchestrator served by vLLM, with an init container to download the model from HuggingFacevllm-deployment.yaml:vLLM 运行 Plano-Orchestrator,带 init 容器下载模型。plano-deployment.yaml— Plano proxy configured to use the in-cluster Plano-Orchestratorplano-deployment.yaml:Plano 代理,指向集群内 Orchestrator。config_k8s.yaml— Plano config withllm_routing_modelpointing athttp://plano-orchestrator:10000instead of the default hosted endpointconfig_k8s.yaml:Plano 配置,llm_routing_model 指向 http://plano-orchestrator:10000。
Key things to know before deploying:部署前须知:
GPU nodes commonly have a
nvidia.com/gpu:NoScheduletaint — thevllm-deployment.yamlincludes a matching toleration. Thenvidia.com/gpu: "1"resource request is sufficient for scheduling in most clusters; anodeSelectoris optional and commented out in the manifest for cases where you need to pin to a specific GPU node pool.GPU 节点常有 nvidia.com/gpu:NoSchedule 污点,vllm-deployment.yaml 里加了容忍度。nvidia.com/gpu: "1" 资源请求够用,nodeSelector 可选,清单里已注释。Model download takes ~1 minute; vLLM loads the model in ~1-2 minutes after that. The
livenessProbehas a 180-secondinitialDelaySecondsto avoid premature restarts.下载模型约 1 分钟,vLLM 加载约 1-2 分钟。livenessProbe 的 initialDelaySeconds 设为 180 秒,防过早重启。The Plano config ConfigMap must use
--from-file=plano_config.yaml=config_k8s.yamlwithsubPathin the Deployment — omittingsubPathcauses Kubernetes to mount a directory instead of a file.ConfigMap 挂载需用 --from-file=plano_config.yaml=config_k8s.yaml 并指定 subPath,否则会挂载成目录。
For the canonical Plano Kubernetes deployment (ConfigMap, Secrets, Deployment YAML), see Deployment. For full step-by-step commands specific to this demo, see the demo README.标准 Kubernetes 部署详见 Deployment,具体步骤看 demo README。
Model Affinity $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#model-affinity" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#model-affinity'">模型亲和性
In agentic loops — where a single user request triggers multiple LLM calls through tool use — Plano’s router classifies each turn independently. Because successive prompts differ in intent (tool selection looks like code generation, reasoning about results looks like analysis), the router may select different models mid-session. This causes behavioral inconsistency and invalidates provider-side KV caches, increasing both latency and cost.在 Agent 循环中,一个请求触发多次 LLM 调用。每次意图不同(工具选择像写代码,结果分析像分析师),路由可能中途换模型,导致行为不一致,KV 缓存失效,增加延迟和成本。
Model affinity pins the routing decision for the duration of a session. Send an X-Model-Affinity header with any string identifier (typically a UUID). The first request routes normally and caches the result. All subsequent requests with the same affinity ID skip routing and reuse the cached model.模型亲和性把路由决策锁定在会话期间。带上 X-Model-Affinity 请求头(填 UUID)。首次请求路由后缓存结果,后续请求带上同一个 ID,跳过路由,复用模型。
import uuid
from openai import OpenAI
client = OpenAI(base_url="http://localhost:12000/v1", api_key="EMPTY")
affinity_id = str(uuid.uuid4())
# Every call in the loop uses the same header
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
extra_headers={"X-Model-Affinity": affinity_id},
)
Without the header, routing runs fresh on every request — no behavior change for existing clients.不带请求头,每次都重新路由,不影响现有客户端。
Configuration:配置:
routing:
session_ttl_seconds: 600 # How long affinity lasts (default: 10 min)
session_max_entries: 10000 # Max cached sessions (upper limit: 10000)
To start a new routing decision (e.g., when the agent’s task changes), generate a new affinity ID.想重新路由(如任务变了),生成个新 ID 就行。
Session Cache Backends $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#session-cache-backends" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#session-cache-backends'">会话缓存后端
By default, Plano stores session affinity state in an in-process LRU cache. This works well for single-instance deployments, but sessions are not shared across replicas — each instance has its own independent cache.默认用进程内 LRU 缓存。单实例没问题,多实例不共享。
For deployments with multiple Plano replicas (Kubernetes, Docker Compose with scale, or any load-balanced setup), use Redis as the session cache backend. All replicas connect to the same Redis instance, so an affinity decision made by one replica is honoured by every other replica in the pool.多实例(K8s、Docker Compose 等)用 Redis 做后端。实例连同一个 Redis,决策全局有效。
In-memory (default)内存(默认)
No configuration required. Sessions live only for the lifetime of the process and are lost on restart.不用配,随进程销毁。
routing:
session_ttl_seconds: 600 # How long affinity lasts (default: 10 min)
session_max_entries: 10000 # LRU capacity (upper limit: 10000)
RedisRedis
Requires a reachable Redis instance. The url field supports standard Redis URI syntax, including authentication (redis://:password@host:6379) and TLS (rediss://host:6380). Redis handles TTL expiry natively, so no periodic cleanup is needed.需连接 Redis。url 支持标准 URI,含认证和 TLS。Redis 自带 TTL,不用清理。
routing:
session_ttl_seconds: 600
session_cache:
type: redis
url: redis://localhost:6379
Note
When using Redis in a multi-tenant environment, construct the X-Model-Affinity header value to include a tenant identifier, for example {tenant_id}:{session_id}. Plano stores each key under the internal namespace plano:affinity:{key}, so tenant-scoped values avoid cross-tenant collisions without any additional configuration.多租户环境,X-Model-Affinity 头加个租户 ID,如 {tenant_id}:{session_id}。Plano 存为 plano:affinity:{key},自动隔离,不用多配。
Example: Kubernetes multi-replica deployment示例:K8s 多实例部署
Deploy a Redis instance alongside your Plano pods and point all replicas at it:部署 Redis,所有实例连上去:
routing:
session_ttl_seconds: 600
session_cache:
type: redis
url: redis://redis.plano.svc.cluster.local:6379
With this configuration, any replica that first receives a request for affinity ID abc-123 caches the routing decision in Redis. Subsequent requests for abc-123 — regardless of which replica they land on — retrieve the same pinned model.无论哪个实例先收到 abc-123,决策都进 Redis。后续请求 abc-123,不管落到哪个实例,都用同一个模型。
Combining Routing Methods $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#combining-routing-methods" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#combining-routing-methods'">混合路由方法
You can combine static model selection with dynamic routing preferences for maximum flexibility:静态模型选择和动态偏好路由可以混用:
version: v0.4.0
model_providers:
- model: openai/gpt-5.2
access_key: $OPENAI_API_KEY
default: true
- model: openai/gpt-5
access_key: $OPENAI_API_KEY
- model: anthropic/claude-sonnet-4-5
access_key: $ANTHROPIC_API_KEY
routing_preferences:
- name: complex_reasoning
description: deep analysis and complex problem solving
models:
- openai/gpt-5
- anthropic/claude-sonnet-4-5
- name: creative_tasks
description: creative writing and content generation
models:
- anthropic/claude-sonnet-4-5
- openai/gpt-5
model_aliases:
# Model aliases - friendly names that map to actual provider names
fast-model:
target: gpt-5.2
reasoning-model:
target: gpt-5
# Aliases that can also participate in dynamic routing
creative-model:
target: claude-sonnet-4-5
This configuration allows clients to:客户端可以:
Use direct model selection:
model="fast-model"指定模型:model="fast-model"Let the router decide: No model specified, router analyzes content交给路由:不指定模型,让路由分析内容。
Example Use Cases $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#example-use-cases" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#example-use-cases'">用例示例
Here are common scenarios where Plano-Orchestrator excels:Plano-Orchestrator 适用场景:
Coding Tasks: Distinguish between code generation requests (“write a Python function”), debugging needs (“fix this error”), and code optimization (“make this faster”), routing each to appropriately specialized models.代码任务:区分写代码、修 Bug、优化代码,分配给对应模型。
Content Processing Workflows: Classify requests as summarization (“summarize this document”), translation (“translate to Spanish”), or analysis (“what are the key themes”), enabling targeted model selection.内容处理:区分总结、翻译、分析,精准选模型。
Multi-Domain Applications: Accurately identify whether requests fall into legal, healthcare, technical, or general domains, even when the subject matter isn’t explicitly stated in the prompt.多领域应用:自动识别法律、医疗、技术或通用领域,提示词里没写也能认出来。
Conversational Routing: Track conversation context to identify when topics shift between domains or when the type of assistance needed changes mid-conversation.对话路由:跟踪上下文,对话中途换话题或换任务,路由也能跟上。
Best practices $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#best-practices" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#best-practices'">最佳实践
💡Consistent Naming: Route names should align with their descriptions.💡 命名一致:路由名要和描述对得上。
❌ Bad:
` {"name": "math", "description": "handle solving quadratic equations"} `❌ 差:{"name": "math", "description": "handle solving quadratic equations"}✅ Good:
` {"name": "quadratic_equation", "description": "solving quadratic equations"} `✅ 好:{"name": "quadratic_equation", "description": "solving quadratic equations"}
💡 Clear Usage Description: Make your route names and descriptions specific, unambiguous, and minimizing overlap between routes. The Router performs better when it can clearly distinguish between different types of requests.💡 描述清晰:路由名和描述要具体,别重叠。区分度越高,路由越准。
❌ Bad:
` {"name": "math", "description": "anything closely related to mathematics"} `❌ 差:{"name": "math", "description": "anything closely related to mathematics"}✅ Good:
` {"name": "math", "description": "solving, explaining math problems, concepts"} `✅ 好:{"name": "math", "description": "solving, explaining math problems, concepts"}
💡Nouns Descriptor: Preference-based routers perform better with noun-centric descriptors, as they offer more stable and semantically rich signals for matching.💡 名词描述:用名词描述路由,语义更稳,匹配更准。
💡Domain Inclusion: for best user experience, you should always include a domain route. This helps the router fall back to domain when action is not confidently inferred.💡 包含领域:一定要配个领域路由。动作推断不准时,兜底用。
Unsupported Features $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#unsupported-features" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#unsupported-features'">不支持的特性
The following features are not supported by the Plano-Orchestrator routing model:Plano-Orchestrator 不支持:
Multi-modality: The model is not trained to process raw image or audio inputs. It can handle textual queries about these modalities (e.g., “generate an image of a cat”), but cannot interpret encoded multimedia data directly.多模态:没训过图像或音频输入。能处理关于这些模态的文本查询(如“画只猫”),但不能直接解析多媒体数据。
Function calling: Plano-Orchestrator is designed for semantic preference matching, not exact intent classification or tool execution. For structured function invocation, use models in the Plano Function Calling collection instead.函数调用:这是做语义偏好匹配的,不是做意图分类或工具执行的。结构化函数调用请用 Plano Function Calling 集合。
System prompt dependency: Plano-Orchestrator routes based solely on the user’s conversation history. It does not use or rely on system prompts for routing decisions.系统提示词依赖:只看对话历史,不看系统提示词。