AI: LLMs, providers, the platform's AI and your own
How a language model reads and writes tokens and what each call costs, how the provider APIs differ and how one catalog hides them, how the platform's AI and your own key share the work and in what order, and how cost, caching, streaming and structured output are done safely - step by step, with pictures.
In short
A large language model (LLM) reads text as tokens and writes the most likely next ones, one at a time. {{brand}} does not train models; it calls them over plain HTTP, from five kinds of provider, through one small layer with just two clients. Two kinds of key can answer: the platform's AI, which {{brand}} pays for, and your own key - or your company's - which you pay the vendor for directly. Every call is checked, budgeted before it is made, and streamed back while it is written.
After this lesson you can Explain tokens, the context window and temperature, and price a model call by hand; talk to OpenAI, Anthropic and a local Ollama server with plain HTTP; design a bring-your-own-key system with a clear order of whose key answers; and reserve, cache, stream and structure model answers safely.
Words you need
- LLM A large language model: a neural network trained on huge amounts of text to predict the next token. It keeps no memory between calls.
- Token The unit a model reads and writes: a piece of a word, about 4 characters of English. Limits, speed and prices are all counted in tokens.
- Context window Everything the model can see in one call: the rules, the history, the material, the question and the answer it writes.
- Temperature How much randomness goes into choosing each next token. Near 0 the answer is almost repeatable; higher values make it more varied.
- Provider API The HTTP interface a vendor offers, such as OpenAI's chat completions or Anthropic's messages.
- OpenAI-compatible server Any server that copies OpenAI's API - Ollama, vLLM, LM Studio, OpenRouter - so one client can talk to all of them.
- Provider catalog A table of what differs between vendors - address, key header, default model - so a new vendor is data, not code.
- Platform key The AI account {{brand}} pays for. It is budgeted per workspace, and its safe answers may be reused for others.
- Bring your own key (BYOK) A person or a company connects its own vendor account. The vendor bills them; {{brand}} only counts fair use.
- Budget reservation Setting aside the most a call could cost before making it, then replacing that with the real cost.
- Server-sent events (SSE) A web standard for streaming text from a server to a browser over one ordinary HTTP response.
- Structured output Making a model answer in JSON that matches a schema, so code can read it safely.
How an LLM answers, in practice
You do not need the mathematics to use a model well. You need five facts: it reads tokens, it sees only one window, it writes one token at a time, randomness is a dial, and you pay for every token in both directions.
- 1. Tokenize The text is cut into tokens by the model's tokenizer. The prompt The login redirect is becomes four tokens; a rare word is split into several pieces, so a long word can cost three or four tokens by itself.
- 2. Read the whole window Rules, earlier turns, material and the question are read together in one pass. The model is stateless: anything it should remember must be sent again on every call.
- 3. Score every next token For every possible next token the model computes a score. After The login redirect is it might be: broken 48%, slow 22%, missing 9%, and a long tail of others.
- 4. Pick one At temperature 0 the code always takes the top score (broken). At temperature 1 it samples, so slow is chosen about one time in five. A higher temperature flattens the scores; a lower one sharpens them. The chosen token is added to the text.
- 5. Repeat until it stops The loop runs until the model writes an end token, hits max output tokens, or meets a stop sequence. A cut by the limit is reported with the finish reason length.
- 6. Report usage The response says how many input and output tokens were used - exactly the numbers you are billed for.
Reasoning models are different Newer reasoning models think in hidden tokens before they answer - you pay for those too - and some accept no temperature except their default. A robust client sends a temperature only when it may, and when a provider refuses one it asks once more without it.
Limits and failure modes
A model call can fail loudly, or succeed and still be wrong. Both are predictable. Know the limits before you design around a model.
- Context window The most a model can read and write in one call, input plus output - for example 128,000 tokens. Go over it and the call fails, or old turns must be dropped.
- Roles Each message has a role: system sets the rules, user asks, assistant holds the model's earlier replies. The model is stateless, so all of them are sent again on every call.
- Hallucination The model writes plausible text, not checked facts. Ground it in retrieved material and tell it to say when the material does not cover the question.
- Vendor prompt caching Some vendors bill a long repeated prefix at a discount. Put the stable part first - rules and big material - and the changing question last.
- Vendor rate limits Vendors cap requests and tokens per minute and answer 429 beyond it. Retry with a growing, randomized wait.
- Tool calling The model returns a request to call a function you described; your code runs it and sends the result back. The model never runs anything itself. See /help/technology/ai-agents-mcp.
- Latency Two times matter: the time to the first token and the time to the last. Streaming improves the first one; a smaller model improves both.
- Count first Add up the system rules, the history, the material and the maximum answer. Do it before the limit is hit, because cost grows with every token as well.
- Keep what must stay The rules and the newest turns always stay. They are what the answer depends on most.
- Shrink the old part Drop the oldest turns, or replace them with a short summary written by a small model.
- Retrieve instead of pasting For large material, send only the few relevant pieces found by search. This also lowers the cost.
What a call costs - a worked example
The formula is always the same: input tokens x input price + output tokens x output price. Prices are quoted per million tokens, so $0.15 per million is $0.00000015 per token. The prices below are examples for illustration; real ones change often, so look them up on the vendor's page.
- Model choice is the biggest cost lever. Light work - summaries, short answers, explanations - goes to a small model; generation and design to a strong one. {{brand}} gives every AI feature a tier for exactly this reason.
- Input dominates when a model answers from your data: thousands of tokens of material for a few hundred tokens of answer. Send less, better material.
- History is sent again on every turn, so a long chat costs more with each question. Cap the number of earlier turns you send.
- Output costs more per token, largely because it is written one token at a time, each step running the whole model, while input is read in one parallel pass. Vendors also set the ratio commercially.
- A reused answer costs nothing at all - the cheapest call is the one you never make.
Provider APIs: two dialects of one idea
Every vendor offers the same idea - send a list of messages, get text and token counts back - but the details on the wire differ. Two formats cover almost the whole market: OpenAI's chat completions, which most other vendors and open-source servers copied, and Anthropic's messages.
- Azure AI Foundry speaks OpenAI's format at your own resource's address, with an api-key header - so it needs no client of its own, only a different row.
- Ollama, vLLM and LM Studio run open models on your own hardware behind an OpenAI-compatible API; OpenRouter is a hosted gateway to many vendors behind the same API.
- Kimi (Moonshot AI) is one more hosted OpenAI-compatible API: in a catalog it is a single row with its address and default model filled in.
The provider catalog: differences as data
The classic design is the adapter pattern: the rest of the code talks to one small interface - complete a request, or stream it - and one adapter exists per wire format. Everything else that differs between vendors lives in a catalog of rows: the default address, the path, how the key is presented, the default model, the name of the max-tokens field and whether an address is required. {{brand}} has five provider rows and two adapters.
- Look up the row The provider's row gives its default address, path, key scheme, default model and wire format.
- Check the settings A required address must be there and be absolute, and a model must be named when the row has no default.
- Build the HTTP client Base address = endpoint + path, and the key goes into the header the row names. Addresses typed by users are untrusted input, so calls to them are made through a hardened client (protecting a server from such calls is a lesson of its own).
- Pick the adapter Chat completions or messages - two classes, whatever the number of vendors.
- Wrap it Retries, a generous timeout, the policy check, usage recording and the budget sit around every call, the same for every vendor.
No built-in list of models Vendors release models faster than anyone updates a dropdown, and a stale list stops people using the model they pay for. The model is a free-text field with a sensible default, and the catalog never lists models.
The options in the market
- One vendor's SDK Use the official OpenAI or Anthropic library directly.; Fastest start; A vendor's newest features arrive first; Locked to one vendor's shapes; A second vendor means a second code path everywhere
- An abstraction library Semantic Kernel, LangChain or Microsoft.Extensions.AI put one interface over many vendors.; Many providers out of the box; Agents, memory and tool helpers included; A large dependency to keep up with; Hides the HTTP details you need for exact cost, retries and streaming
- An LLM gateway LiteLLM or OpenRouter sit between you and the vendors and speak one API.; One API, many models; Central keys, logs and fallbacks; One more service to run or pay for; Customer text passes through one more party
- Thin own clients + a provider catalog Two small HTTP clients - chat completions and messages - and one row per vendor.; Covers every vendor and any OpenAI-compatible server, a local one too; Full control of retries, streaming, token counts and network safety; No vendor SDK to upgrade; The team parses each format itself; A vendor's newest feature needs code before it can be used
- Self-hosted only Run open models with Ollama or vLLM and never call a vendor.; Text never leaves your network; No per-token bill; Needs GPUs and people to run them; Smaller open models answer worse
- Platform key only The product pays for every call.; Works for everyone with no setup; One place to control quality and safety; Every free user's question is the company's bill; Customers with strict data rules cannot use it
- Bring your own key only Nothing works until a key is added.; Costs the company nothing; Customers keep their own vendor contracts; A blank feature on the first day; Every user must understand API keys
- Both, in a fixed order Own keys first, the platform's AI as the fallback, within a budget.; Works out of the box, within a budget; Anyone can move to their own vendor, model and bill at any time; An organization decides whose key may read its data; An order to define, test and explain on every screen; Two cost paths: a money budget for the platform key, fair use for own keys
What {{brand}} chose, and why
{{brand}} writes its own two clients on plain HTTP and keeps the vendor differences in a catalog. It also runs two AIs side by side: the platform's, which it pays for and budgets, and yours, which you pay for. The reasons:
- Two wire formats cover the market. OpenAI's format is the de facto standard and only Anthropic really differs. Kimi was added as one row of data - no new class.
- Exact control where money and safety live. Token counts, retries, streaming, early stops and the network guard are code the team reads and tests; an SDK would hide some of them.
- Private installations. The platform AI can point at any OpenAI-compatible server inside a company's own network, so no text leaves it.
- Cost must stay bounded. The platform's key is metered against a budget, and heavy users can move to their own key, so the product never promises more AI than it can pay for.
- Data stays where its owner wants it. A company can keep its AI on its own vendor contract, on the platform's AI alone, or limited to EU-only processing.
The trade-off accepted When a vendor ships a new API feature, {{brand}} can use it only after someone writes the code for it. In exchange there is no SDK upgrade treadmill, and every vendor behaves the same inside the product - the same retries, the same budget, the same checks.
When another option is right: a product built around agents with memory and many tools gains from a framework; a company running dozens of models for many teams gains from a gateway; a product whose data may never leave the building should self-host.
Bring your own key: the design
In a multi-tenant product three parties can own the AI account: the platform (the operator), a tenant (an organization) and a user. All of them do the same work through the same code. Only who pays, what is limited and what may be reused differ.
- Stored encrypted on the server Works on every device and in background work. Cost: the server now holds a secret, so encryption, key management and never sending it back to the browser all matter.
- Kept in the browser for the session Nothing is stored, so nothing can leak from a database. Cost: a reload forgets it and background work cannot use it.
- Shared by an organization administrator One contract for every member, easy to audit. Cost: the organization carries all its members' usage.
Every AI call - a question, a report summary, a drafted card - asks one resolver whose key answers. It walks the same order every time and stops at the first that may answer:
- 1. The tenant's AI policy If the tenant switched AI off, or keeps this feature's data away from AI, nothing answers and nothing is sent.
- 2. Exceptions that skip own keys Some work is pinned to the platform, for example features whose safety was measured on specific models. A tenant that requires EU-only processing is answered only by an EU-only option, which a personal key cannot promise.
- 3. The person's own key Where the policy lets personal keys answer, the person's own key comes first.
- 4. The tenant's key Next comes the tenant's shared key, if its plan includes one and its choice of keys uses it.
- 5. The platform's key Last, the platform's own AI - only for a verified person, only for the kinds of work the plan allows there, and with the model suited to the work.
- 6. Nobody answers The screen says the true reason and the next step - for example add your own key, or confirm your email - never a vague error.
Checked twice: defense in depth The resolver decides, and then a gate that every model call must pass checks the same rules again just before the request leaves. A new feature that forgot to ask the resolver still cannot send a tenant's data with a key the tenant ruled out. Rules enforced in one choke point cannot be skipped by accident.
Why answers from your own key are never shared
In any multi-tenant product that caches model answers, only answers the operator's own model wrote should be kept for other people. An answer written with a person's own key, or with an organization's key, is shown to the person who asked and then forgotten. The main reason is an attack called cache poisoning.
- An own key can point anywhere An OpenAI-compatible key comes with an address the person chooses - it could be a server they wrote themselves.
- That server can answer anything It returns text that looks like a normal answer, perhaps with a link to a look-alike sign-in page.
- A shared cache would spread it If that answer were stored under the question, the next person - in another company - asking the same thing would get it, shown as {{brand}}'s own answer.
- So the rule is simple Only text the platform's own model wrote may be reused. Everything else is served to its asker alone.
- Privacy: an answer from a company's own key was produced under that company's contract, from its data. It is theirs, not material for strangers.
- Honest billing: a reused answer costs nothing. Reusing another customer's paid answer would quietly hand their spend to someone else.
- Defence in depth: even the platform's own answers have their links checked before they are kept, so this rule is one barrier among several, not the only one.
Policy at one choke point
A multi-tenant AI product usually lets each tenant's administrators decide what AI may do with their data. The policy is enforced at the one place every model call passes, whatever made the call - a question, a summary or a draft.
- Switch AI off for the whole tenant: nothing is retrieved and no model is called.
- Keep some data sources away from AI, so their records are never read for an answer.
- Mask personal details, such as email addresses and phone numbers, before text leaves for a vendor.
- Pin a region, so only a processor in that region answers.
- Choose whose key may answer: members' own keys, the tenant's shared key, or the platform's.
One choke point Policies written as checks inside each feature always leak somewhere. Put them where every call must pass - the same place that records usage and holds the budget - and a new feature obeys them on its first day.
Cost control: reserve the maximum before the call
The danger with AI cost is not one expensive call; it is many calls at once. Ten questions arrive together, each checks that the budget has room, each sees room, and together they overspend. The fix is the one airlines use for seats: reserve first, settle later.
- 1. Work out the worst case Over-count on purpose: assume the worst, for example one token per byte of text (a byte-level tokenizer never produces more tokens than bytes), then add every output token the call allows.
- 2. Price it Use the model's price from a price table. When a price is missing, fall back to a deliberately high one, so a missing price never makes AI free.
- 3. Reserve atomically Take that amount from the workspace's budget in one atomic step - a serializable transaction or a single conditional UPDATE. If it does not fit, refuse: the model is never called.
- 4. Call the model Only now does the request leave.
- 5. Settle Replace the reservation with the real cost from the provider's token counts. A failed call gives the whole reservation back.
- 6. A stream that stops early Charge the counts the provider reported, filling any gap with an estimate from the text written so far.
Count money in micro-dollars Store money as integers of a millionth of a dollar. A price per million tokens is then exactly the micro-dollars of one token, sums never drift the way floating point does, and the rounding rule - always up - is written down in one place.
Caching answers safely
An answer that already exists costs nothing. The hard part is reusing it only when it would be the same answer for this person. {{brand}} always runs retrieval first - cheap database work, done with the asker's own permissions - and skips only the model call.
- Normalize the question Lower case, no sentence punctuation, single spaces: What is a board? and what is a board are one question - but C# and C stay different.
- Retrieve as the asker Run the permission-checked retrieval exactly as for a fresh answer.
- Hash the question with what was retrieved Hash the question together with exactly what was retrieved and anything else that changes the answer: who may see it and the prompt version.
- Look up, or answer and store A hit is served marked as reused and costs nothing; a miss asks the model and stores the answer only if it may be kept.
Why hashing the retrieved pieces is the trick If a card is added or edited, or the asker loses access to one, their retrieval returns different pieces, so the key changes and the old answer is simply never found. Permissions are enforced by the key itself - nothing has to remember to clear the cache.
Streaming with server-sent events
A long answer takes many seconds to write. Streaming sends it piece by piece, so the reader starts at once. Vendors stream to {{brand}} with server-sent events, and {{brand}} streams to the browser the same way: one ordinary POST request whose response stays open and carries events.
- Check everything first Validation, the organization, the plan, the budget and the policy run before the stream opens, so a refusal is an ordinary error response with a status code.
- Open the stream Content-Type text/event-stream, no caching, and response buffering switched off - in the server and in any proxy in front of it - so pieces are not held back.
- Relay the vendor's pieces Each piece the model writes is checked, written as a token event and flushed at once.
- Hold back what could still change Hold back anything that could still change, such as a half-written link, until it is complete.
- Finish with a complete event The finished answer comes last and replaces what was shown, so a correction made at the end is what the reader keeps.
- Stop means stop Closing the request cancels the vendor call. What was written is charged; nothing half-written is kept for anyone.
Why not the browser's EventSource? The built-in EventSource makes only GET requests and cannot send a body or custom headers. A question with its history needs a POST, so the page reads the stream with fetch and a small parser - which must cope with an event cut in half between two network chunks.
- Wait for the whole answer Simplest code; Easy to retry; The reader stares at a spinner for many seconds
- WebSocket or SignalR Two-way, one connection for many messages; A long-lived connection outside the normal request pipeline - every security check must be rebuilt for it; Stopping one answer needs a protocol of its own
- Server-sent events over the asking request One normal request: sign-in, the organization check, rate limits and CSRF protection all apply; Closing it stops the model and the cost; Plain text, easy to watch with curl; One-way only - which is all an answer needs; Proxies must be told not to buffer
Structured output: JSON you can trust
Some features need data, not prose: a list of acceptance criteria, a drafted vacancy, a set of design changes. Asking politely for JSON works most of the time - and breaks in production. There are four techniques, from weakest to strongest, and {{brand}} uses the vendor's native one on each wire format.
- Ask in the prompt Reply with JSON like ...; Works on every model; Models wrap it in prose or code fences; Fields go missing or change type
- JSON mode response_format: json_object; Always valid JSON; Any JSON - not necessarily your shape
- A strict JSON Schema response_format with a json_schema and strict: true, on OpenAI-compatible servers. Used on OpenAI-compatible servers.; The vendor enforces your exact shape; No parsing surprises; Every property must be required and no extra properties allowed; Many compatible servers refuse it
- A forced tool call Offer one tool whose input is your schema and require the model to call it - used with Anthropic. Used on Anthropic messages.; Works where response_format does not exist; The answer arrives as a parsed JSON object; A gateway without tool support refuses it; The tool input is still worth validating
With the forced tool call, the answer comes back as a content block of type tool_use whose input is the JSON object. With response_format, the message content itself is the JSON text.
- Ask with the schema As response_format on chat completions, as a forced tool on messages.
- Survive a refusal A server that answers 400 or 422 naming the schema or tool fields is asked once more without it - any other refusal is a real error.
- Cut the object out Take the text from the first opening brace to the last closing brace, so code fences or a sentence around it do not matter.
- Read each field leniently A field of the wrong type reads as missing, not as a failed answer.
- Validate against your own rules Drop lines that are too long, duplicates, or things the record already has. The model proposes; the code decides.
Never stream a structured answer Half a JSON object is worth nothing. A request with a schema is answered whole, even when the caller asked for a stream.
Try it yourself: a model on your own computer
You can try every idea in this lesson for free on your own computer with Ollama, which serves open models behind an OpenAI-compatible API.
- Install Ollama Download it from ollama.com, then run ollama pull llama3.2 to fetch a small model.
- Call it like OpenAI POST to http://localhost:11434/v1/chat/completions with the same body you would send OpenAI.
- Read the usage Find usage.prompt_tokens and usage.completion_tokens in the reply and price the call with the example prices above (script below).
- Stream it Add "stream": true and watch the data: lines arrive, ending with data: [DONE] (script below).
- Ask for JSON Add a response_format with a json_schema and parse the answer (script below) - then write the fallback for a server that refuses it.
- Turn the dial Ask the same question five times at temperature 0 and five times at 1, and compare the answers (script below).
- Check yourself You are done when you can explain why the 5 answers at temperature 0 match and the 5 at 1 do not.
On Windows PowerShell and cmd, the quotes in the curl command above break; use the Node script below instead. It needs Node 18 or newer: save it as try.mjs and run node try.mjs.
Common mistakes
- Sending everything because it fits: you pay for every token on every call, and models answer worse from noise. Send the few pieces that matter.
- Checking the budget, then calling: ten parallel calls all see room and overspend together. Reserve the worst case atomically first, settle afterwards.
- Caching by question text alone: the next person gets an answer built from records they may not see. Key by exactly what their own retrieval returned.
- Sharing answers made with customers' keys: a key can point at any server, and its output must never reach other customers.
- Retrying everything: a 400 or 401 fails again and only delays the message. Retry 429, timeouts and gateway errors, with backoff and jitter.
- Parsing a model's JSON strictly: models add fences and prose. Use the native schema mechanism, cut the object out, read fields leniently, then validate.
Interview questions
- What is the context window, and what do you do when a conversation outgrows it? It is the maximum of input plus output tokens per call. When history grows past it, trim older turns, summarize them, or retrieve only the relevant pieces; cost also rises with every extra token, so do it before the limit.
- How do you reduce hallucinations in an answer from your own data? Retrieve the relevant material, tell the model to answer only from it and to say when it does not cover the question, and show citations the reader can check.
- Why do output tokens cost more than input tokens? Input is read in one parallel pass, while output is generated one token at a time, each step running the whole model. That is one reason output costs more per token, though vendors also set the ratio commercially.
- How do you avoid vendor lock-in with LLMs? Put one small interface in front of every call and keep vendor differences in a catalog of data. OpenAI's chat completions and Anthropic's messages cover almost every vendor, and any OpenAI-compatible server - a local one included - works through the first.
- How would you design bring-your-own-key in a multi-tenant product? One resolver with a fixed order - organization policy, the person's key, the organization's key, the platform's key - re-checked at a gate every call passes. Keep the cost paths apart: a money budget for the platform key, fair use for own keys.
- Why never cache answers made with a customer's own key? Its endpoint can be any server the customer controls, so caching its output for others opens a cache-poisoning hole. It is also their private output, paid for under their contract.
- How do you stop parallel AI calls from overspending a budget? Reserve the worst-case cost atomically before calling - an over-estimate of the input plus the maximum output - and refuse when it does not fit. Then settle to the real token counts, and give the reservation back if the call fails.
- How do you cache LLM answers without leaking across permissions? Retrieve with the asker's permissions first and hash exactly the retrieved pieces into the key, together with the workspace and the prompt version. Any data or permission change produces a different key.
- Why server-sent events rather than WebSockets for streaming answers? SSE rides on one ordinary HTTP request, so authentication, rate limits and CSRF protection already apply, and closing it stops the model and the cost. Answers flow one way, so a two-way socket adds risk without benefit.
- How do you get reliable JSON out of a model? Use the vendor's native mechanism - a strict JSON schema or a forced tool call - and ask once more without it when a server refuses. Then cut out the object, read fields leniently and validate them in code.
Related
- /help/technology/ai-chunking
- /help/technology/ai-safety
- /help/technology/ai-agents-mcp