You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Today in Switchyard every routing algorithm ends by naming a model and every algorithm carries its own copy of the model catalog.
That suits a route running one strategy against a fixed pair of models. At wider scope it introduces these issues: the same two models are configured four different ways, strategies cannot be combined because each terminates on a model, and selection cannot weigh price or preferences because neither is available where the decision happens.
To successfully unify the existing algorithms there also needs to be a layer that makes a final decision when signals diverge. For instance stage tool signals say X, task classification says Y, and the advisor says Z all at the same time.
In addition, right now switchyard requires customers to categorize models (e.g. efficient/capable) which means they have to make a judgement call on what those definitions mean. Or use an existing configuration we provide that is "blessed". This proposal is a stepping stone (not the final state) towards being able to support an arbitrary pool of models without a need to categorize them explicitly and solves the immediate need of unifying the algorithms.
flowchart LR
subgraph T["Today: every algorithm holds the catalog"]
direction LR
R1[Request] --> A1["Classifier<br/><i>knows sol, luna</i>"]
R1 --> A2["Stage<br/><i>knows sol, luna</i>"]
R1 --> A3["Advisor<br/><i>knows sol, luna</i>"]
A1 --> M1[ModelId]
A2 --> M1
A3 --> M1
M1 --> U1[Upstream]
end
subgraph P["Proposed: one place holds the catalog"]
direction LR
R2[Request] --> S["Signals<br/><i>task, tool loop, review</i>"]
S -->|"needs + confidence"| O["Pool optimizer<br/><i>catalog, cost,<br/>budget, preferences</i>"]
O --> M2[ModelId]
M2 --> U2[Upstream]
end
Loading
Goals
One vocabulary for declaring models. Strategies that combine. A deployment that works from a list of models. Less surface area in the algorithm layer.
Non-Goals
Infrastructure signals in the pool optimizer
Automatic discovery of model capability from providers
A learned or online-optimizing policy
Proposal
Algorithms emit what a request needs. A pool optimizer decides which model provides it.
Three core changes:
1. What an algorithm returns
Today. The capability classifier computes an estimate, compares it to a threshold, and throws the estimate away:
let target = if verdict.p_solve >= threshold {&self.efficient}else{&self.capable};Classification::Scores(vec![Score{ confidence:1.0, target: target.clone()}])
The optimizer takes signals and picks the model. How it settles a disagreement is an open question. Today each algorithm applies its own threshold and selects the top score. This provides a layer that sees every score and can introduce other constraints like cost. Can be extended to take in other preferences from the user.
When more than one model satisfies the need, prefer one the session has already used, since the provider's cache is warm for that prefix.
Composite routing, before and after
Composite routing first use case allowed LLM classifier to set the tier that stage defaults to when the confidence signal is uncertain. Composite needed its own route type, a processor that wrote into the stage algorithms session state, and a runtime API to set and clear that tier.
What this removes: composite as a route type, the processor that sets the fall-open tier, the runtime setter and the session state behind it, and the capable_target and efficient_target pair inside stage. What replaces it is a pool default for the case where no signal is confident:
After this change a working deployment requires a list of models.
Public API. The TOML schema is the affected surface. [pool], type = "auto", and [routes.*.signals] are added. Existing route types and their keys are eventually replaced. [llm_clients.*], [targets.*], route id, and every HTTP endpoint are unchanged. Sequencing and migration come after the shape is agreed.
Docs. The seven routing-algorithm pages collapse to one for the route type and one for the pool.
Proposal co-authored by @ayushag-nv
Background
Today in Switchyard every routing algorithm ends by naming a model and every algorithm carries its own copy of the model catalog.
That suits a route running one strategy against a fixed pair of models. At wider scope it introduces these issues: the same two models are configured four different ways, strategies cannot be combined because each terminates on a model, and selection cannot weigh price or preferences because neither is available where the decision happens.
To successfully unify the existing algorithms there also needs to be a layer that makes a final decision when signals diverge. For instance stage tool signals say X, task classification says Y, and the advisor says Z all at the same time.
In addition, right now switchyard requires customers to categorize models (e.g. efficient/capable) which means they have to make a judgement call on what those definitions mean. Or use an existing configuration we provide that is "blessed". This proposal is a stepping stone (not the final state) towards being able to support an arbitrary pool of models without a need to categorize them explicitly and solves the immediate need of unifying the algorithms.
flowchart LR subgraph T["Today: every algorithm holds the catalog"] direction LR R1[Request] --> A1["Classifier<br/><i>knows sol, luna</i>"] R1 --> A2["Stage<br/><i>knows sol, luna</i>"] R1 --> A3["Advisor<br/><i>knows sol, luna</i>"] A1 --> M1[ModelId] A2 --> M1 A3 --> M1 M1 --> U1[Upstream] end subgraph P["Proposed: one place holds the catalog"] direction LR R2[Request] --> S["Signals<br/><i>task, tool loop, review</i>"] S -->|"needs + confidence"| O["Pool optimizer<br/><i>catalog, cost,<br/>budget, preferences</i>"] O --> M2[ModelId] M2 --> U2[Upstream] endGoals
One vocabulary for declaring models. Strategies that combine. A deployment that works from a list of models. Less surface area in the algorithm layer.
Non-Goals
Proposal
Algorithms emit what a request needs. A pool optimizer decides which model provides it.
Three core changes:
1. What an algorithm returns
Today. The capability classifier computes an estimate, compares it to a threshold, and throws the estimate away:
Proposed. The estimate is the output:
Other algorithms do the same with their own score.
2. What a Score points at
Today:
Proposed:
ModelId is why every algorithm needs the catalog today.
3. What a deployment looks like
Today. The same two models, four times, four vocabularies:
Proposed. Declare the pool once:
The above design can be extended to more than two categories (e.g. beyond capable/efficient) and a model can provide multiple categories.
Strategies become configurable signals on the route:
autoreplaces the existing route types.The optimizer
The optimizer takes signals and picks the model. How it settles a disagreement is an open question. Today each algorithm applies its own threshold and selects the top score. This provides a layer that sees every score and can introduce other constraints like cost. Can be extended to take in other preferences from the user.
Proposed.
When more than one model satisfies the need, prefer one the session has already used, since the provider's cache is warm for that prefix.
Composite routing, before and after
Composite routing first use case allowed LLM classifier to set the tier that stage defaults to when the confidence signal is uncertain. Composite needed its own route type, a processor that wrote into the stage algorithms session state, and a runtime API to set and clear that tier.
Today:
Proposed:
The two signals are declared side by side and the optimizer resolves them. No route type for the pair, no writing into another algorithm's state.
The same shape covers the pattern where stage calls the classifier itself when its own signals are indecisive:
What this removes: composite as a route type, the processor that sets the fall-open tier, the runtime setter and the session state behind it, and the capable_target and efficient_target pair inside stage. What replaces it is a pool default for the case where no signal is confident:
User Experience Impact
After this change a working deployment requires a list of models.
Public API. The TOML schema is the affected surface.
[pool],type = "auto", and[routes.*.signals]are added. Existing route types and their keys are eventually replaced.[llm_clients.*],[targets.*], routeid, and every HTTP endpoint are unchanged. Sequencing and migration come after the shape is agreed.Docs. The seven routing-algorithm pages collapse to one for the route type and one for the pool.