A production LLM app is a normal web app plus two layers, orchestration and model access. The model is one dependency, not the system.
- The client renders streamed output and holds the UI session.
- The application API owns auth and business rules, and persists conversation history.
- Orchestration builds each request from retrieval, templates and tool calls, and runs multi-step flows.
- The data layer holds the vector index, documents and application database.
- Model access talks to providers and holds their keys. It runs retries and timeouts, and tracks spend.
- Providers are hosted APIs or self-hosted inference.
Safety checks, evals and telemetry are not a layer. They wrap every call.
These are logical layers, so start in one process. From day one, nothing outside model access imports a provider SDK.
// the only module that imports a provider SDK
export async function complete({ model, messages }) {
return client.messages.create({ model, messages, max_tokens: 1024 });
}
This answer doesn't lend itself to a diagram - it reads best . No credits were charged.
Why there's no diagram: “”
The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓
The diagram below the answer is the concept . Jump to it ↓