How to Build AI Applications That Ship to Production
Building AI applications means connecting a model API to your product logic, handling the parts that make demos different from production — streaming, retries, tool calls, usage tracking — and shipping something that doesn't fall over when a real user sends an unexpected input. It's less about picking the "smartest" model and more about the plumbing around it.
This guide walks through the practical decisions you'll make when building an AI application from scratch: how to structure the request layer, when to use streaming, how tool use changes your architecture, and where teams commonly get stuck (auth, rate limits, and cost visibility).
Start with the request layer, not the prompt
It's tempting to spend the first week tuning prompts. Don't. The thing that determines whether your AI application survives contact with real users is the request layer — the code that sends messages to the model, handles errors, retries, and streams tokens back to your UI.
A minimal request layer needs to handle:
- Authentication — an API key, stored server-side, never shipped to the client
- Timeouts and retries — network calls fail; your app shouldn't
- Streaming — most chat-style UIs feel broken without token-by-token output
- Structured responses — if you're using tool calls, you need to parse them reliably
- Usage tracking — so you know what a feature actually costs before you ship it to everyone
If you already have Claude access through a Pro or Team plan and want an HTTPS endpoint without building this layer yourself, that's what SubToAPI does — it turns your existing access into application API keys (sub_live_...) with streaming, tool use, and usage metadata built in. You can check the quickstart to see the request shape before deciding whether to build it yourself.
Architecture patterns for AI applications
Most AI applications fall into one of three shapes:
1. Single-turn transformation — input goes in, structured output comes out. Summarization, classification, data extraction. These are the easiest to build and the easiest to test, because you can assert on output shape.
2. Multi-turn conversation — a chat interface with memory. You're managing a message history, trimming it to fit context limits, and usually streaming responses. This is where most consumer-facing AI products live.
3. Agentic / tool-using — the model decides to call functions (search a database, hit an API, run code) and you execute those calls and feed results back. This is the hardest to build reliably because failure modes multiply: the model can call the wrong tool, pass malformed arguments, or loop.
Pick the simplest pattern that solves your problem. A lot of "AI agent" projects would work fine — and ship faster — as single-turn transformations with a good prompt and a validation step.
Example: a single-turn request
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 512,
"messages": [
{"role": "user", "content": "Summarize this ticket in one sentence: ..."}
]
}'
This is the whole pattern for a huge class of useful features: ticket summarization, tag suggestion, sentiment classification. No agent loop needed. Full request/response fields are in the messages docs.
Streaming: don't bolt it on later
If your application has any kind of chat or generation UI, build with streaming from day one. Retrofitting streaming onto a request/response app usually means rewriting your state management, because you go from "one response object" to "a sequence of partial updates you accumulate."
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 1024,
stream: true,
messages: [{ role: "user", content: "Draft a release note for..." }],
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
process.stdout.write(decoder.decode(value));
}
Details on event types and how to parse the stream are in the streaming docs.
Tool use changes the shape of your app
Once your AI application needs to look something up, take an action, or query a database mid-conversation, you're building a tool-use loop. The model returns a tool call request instead of text, your code executes it, and you send the result back as part of the conversation. This loop is the core of most "agent" products.
The engineering challenges here are less about the model and more about your own systems:
- Idempotency — if the model calls a tool twice (retries, duplicate reasoning), does your action fire twice?
- Validation — the model can pass arguments that don't match your schema; validate before executing.
- Timeouts — a tool call that hangs blocks the whole conversation turn.
- Observability — log every tool call and its arguments; this is where debugging actually happens.
The tools documentation covers the request format for defining tools and handling tool-call responses if you're building this on SubToAPI.
Cost and access are part of the architecture
Two things quietly kill AI application projects that otherwise work fine technically: cost surprises and access friction. A feature that costs €0.02 per call feels free until it's called 200,000 times a month. Track usage per feature, not just per app, from the start — it's much cheaper to add a token budget check now than to explain a bill later.
Access friction shows up on teams: five engineers need to call the model, but only one person has an account with billing set up. If you're evaluating how to get from "I have Claude access" to "my team has API keys with usage visibility," pricing covers the plan options, and you can start on Solo for individual projects or move to Team/Scale plans with per-seat keys once more than one person is building against the same account. Signup is at /signup if you want to try the request layer before wiring it into your app.
A reasonable build order
- Ship the single-turn version of your feature first, without streaming or tools.
- Add streaming once the UI needs it — not before.
- Add tool use only when the task genuinely requires the model to take actions, not just produce text.
- Add usage tracking and rate limiting before you add more users, not after.
- Move auth/keys to a shared team setup once more than one person needs access.
questions
Do I need to fine-tune a model to build an AI application? No. Most production AI applications use a general-purpose model with good prompting, structured outputs, and sometimes retrieval. Fine-tuning is a late optimization, not a starting point.
What's the difference between building a chatbot and an AI agent? A chatbot manages conversation and memory but produces text. An agent adds tool use — the model can trigger actions in your systems, which requires validation, idempotency, and error handling on your side.
How do I control API costs while building an AI application? Track usage per feature during development, set max token limits per request, and test with cheaper/faster models before switching to larger ones for production traffic.