Architecting an Agent Around a Model-Agnostic Gateway
Production agents age poorly when every node imports a vendor SDK and hardcodes a model string.
Search across all documentation pages
Production agents age poorly when every node imports a vendor SDK and hardcodes a model string.
A model-agnostic gateway pattern flips that: agent logic owns goals, tools, memory, and stop rules; a thin client owns base URL, credentials, model ids, and fallbacks.
OpenRouter is a common gateway implementation (one OpenAI-compatible API over many models), but the architecture works with any compatible router or your own adapter.
An agent has at least four separable parts:
Only the fourth part should talk to OpenRouter (or OpenAI, Anthropic, Ollama, and so on).
Teams often invert that: tools and goals stay vague, while gpt-... strings and vendor clients appear in six modules.
That inversion fails when prices change, a provider browns out, or you need a cheaper model for triage steps.
A gateway is the component that accepts a stable request shape (messages, tools, model_ref, timeouts) and returns a stable response shape (content, tool_calls, usage, raw).
OpenRouter fits this role because it already normalizes many upstream APIs behind https://openrouter.ai/api/v1 (verify endpoint and headers at build).
Your job is not to re-implement OpenRouter inside every agent.
Your job is to ensure business logic never bypasses the gateway interface.
User goal / event
|
Agent host (loop, tools, stops, memory)
|
Gateway client (model_ref -> model id, retries, logging)
|
OpenRouter (or Ollama / direct provider)
|
Upstream model providersAt minimum, isolate:
model_ref (logical name: planner, extractor, default) mapped to a concrete model slugbase_urlThe agent graph should call complete(messages, tools, model_ref) once per decision.
It should not import a vendor SDK inside each node.
| Concern | Lives in | Changes when |
|---|---|---|
| Tool schemas and allowlists | Code + versioned schemas | Product behavior changes |
| Stop conditions, budgets | Code | Reliability policy changes |
| Default model per env | Config / secrets | Ops or cost policy |
| Per-step model map | Config | Eval results or pricing |
| Fallback order | Config | Outages or quality gates |
Hardcoding anthropic/claude-... inside a planner node couples product code to a SKU.
Mapping model_ref="planner" to that slug in config keeps the node portable.
Not every model behind a gateway supports the same features equally.
Maintain a small matrix for the models you allow: tool calling quality, structured JSON, vision, context length, streaming, and cost tier.
Route only models that satisfy the step's required capabilities.
A gateway that can call 300+ models is not a license to send tool-heavy agent turns to a free chat model that mangles function calls.
The gateway is the natural place for:
model_ref, resolved model id, and providerAgent nodes then log phase labels (plan, act, observe) without re-implementing HTTP policy.
OpenRouter provides unified auth, model slugs, provider routing, and many operational knobs.
Your architecture still owns:
Do not treat "we use OpenRouter" as the design doc.
Treat "agent host + gateway client + registry" as the design, with OpenRouter as the first backend.
Production systems often need more than one transport:
A model-agnostic client can dispatch by backend field in the registry without changing the agent loop.
See Building a Self-Hosted Fallback Layer: Ollama + OpenRouter.
LangChain, CrewAI, LlamaIndex, and similar stacks can all target OpenRouter via OpenAI-compatible base URLs or LiteLLM-style model strings.
Keep framework model construction in one factory module.
If every agent class builds its own ChatOpenAI(...), you have not actually centralized the gateway.
| Approach | Strength | Weakness | Best fit |
|---|---|---|---|
| Direct vendor SDK in each node | Fast prototype | Hard to swap or A/B | Throwaway demos |
| Single OpenRouter client, hardcoded models | One auth surface | Still rigid per step | Small single-agent apps |
| Gateway + model registry + model_ref | Portable, testable routing | Small abstraction cost | Production agents |
| Full multi-backend router | Local + cloud + policy | More ops complexity | Hybrid / enterprise |
The gateway is also a control point for secrets and egress.
API keys stay in the client layer; tools never receive raw provider credentials.
Prefer scoped keys and spend caps on OpenRouter (and elsewhere) so a runaway loop cannot burn unbounded credits.
cheap, strong) pay for themselves the first time you cut cost or fail over.A thin client and config layer that turns logical model requests from your agent into concrete HTTP calls, so orchestration never hardcodes a provider.
No.
OpenRouter is a strong default multi-model gateway; the same pattern works with LiteLLM, a custom reverse proxy, or a single-provider client behind an interface.
In a versioned registry or config map keyed by model_ref and environment, not as string literals inside tool nodes.
Define tools once in a JSON-schema style your host understands, and let the gateway send OpenAI-compatible tools payloads (or adapt only inside the client if a backend differs).
Usually no.
Planners, extractors, and classifiers often need different tiers; the gateway should resolve per-step model_ref values.
Construct framework chat models through one factory that reads the registry.
Do not let each CrewAI agent or LangGraph node invent its own endpoint configuration.
At least: request id, model_ref, resolved model id, latency, token usage, cost if available, HTTP status, and retry count - never full secrets or unnecessary PII.
Fallbacks are gateway policy: on failure or 429, try the next model or backend.
The agent loop should see either a successful completion or a typed failure after the chain exhausts.
Short-lived spikes and eval harnesses comparing specific SKUs.
Even then, prefer CLI flags or env vars over literals in library code.
It can reduce blast radius with fallbacks, but you must still surface degraded mode, partial failure, or "try again" when the whole chain fails.
Unit-test the loop with a fake gateway; integration-test the real gateway with a tiny model; eval quality per registered model on a fixed suite.
Introduce a single client module with base_url + api_key + model from config, point it at OpenRouter or OpenAI, then replace scattered SDK calls with that client.
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026