---
title: "Call models through one module · Agent Wranglers"
url: https://agentwranglers.se/playbook/ai-features/deciding-to-use-a-model/model-gateway
updated: 2026-10-20
licence: "All rights reserved"
---

# Call models through one module

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [Deciding to use a model](https://agentwranglers.se/playbook/ai-features/deciding-to-use-a-model)
- Rule: Send every model call through one module of your own. Feature code never imports a provider's SDK directly.
- How: Give the module one function per kind of call, such as `generate` and `embed`. Put the model name, timeouts, retries, logging, cost tracking and fallbacks inside it. Feature code passes a prompt ID, the variables and an output schema. Then a provider change, a new log field or a spending cap is one change in one place. A hosted gateway, such as LiteLLM or a cloud provider's AI gateway, can be the module, as long as all calls go through it.
- Check: A search for provider SDK imports outside the gateway module finds nothing, including the `from google import genai` form. A lint rule or a test runs that search in CI.

Example:

```sh
! grep -rnE "from ['\"](openai|@anthropic-ai/sdk|@google/genai)['\"]|^(from|import) (openai|anthropic|google\.genai)\b|^from google import genai" src/ --include=*.ts --include=*.py | grep -v "^src/ai/gateway"
```

```ts
// src/ai/gateway.ts is the only file that knows the provider.
export async function generate<T>(request: { promptId: string; vars: Record<string, string>; schema: ZodType<T>; userId: string }): Promise<T> {
  const prompt = await loadPrompt(request.promptId);
  return withLimits(request.userId, () => callProvider(prompt.render(request.vars), request.schema));
}
```

```python
# src/ai/gateway.py is the only file that knows the provider.
def generate(prompt_id: str, variables: dict[str, str], schema: type[BaseModel], user_id: str) -> BaseModel:
    prompt = load_prompt(prompt_id)
    return with_limits(user_id, lambda: call_provider(prompt.render(variables), schema))
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers ai features playbook: https://agentwranglers.se/playbook/ai-features/deciding-to-use-a-model/model-gateway`.

- Previous: [Choose the smallest model that passes](https://agentwranglers.se/playbook/ai-features/deciding-to-use-a-model/smallest-passing-model)
- Next: [Design for wrong answers](https://agentwranglers.se/playbook/ai-features/deciding-to-use-a-model/design-for-wrong-answers)
- [Deciding to use a model](https://agentwranglers.se/playbook/ai-features/deciding-to-use-a-model)
