BXUP Track progress & test yourself — free
AI at Work · Common Core · ~14 min read
AI AT WORK · COMMON CORE

LLM APIs & Structured Outputs

Every professional now touches the API layer, because anything AI does repeatedly and unattended runs through one. This module covers the anatomy of a call, schema-enforced JSON contracts, tool calling, the failure modes that arrive inside a 200, and the cost arithmetic.

Somewhere between "I use ChatGPT to draft emails" and "I ship AI features" sits a layer every experienced IT professional now touches: the API. It doesn't matter whether your title says developer. QA engineers wire LLM calls into test pipelines. Sysadmins script ticket triage. PMs read API logs to debug an eval failure. Security engineers review what a prompt actually sends. The chat window is where you met the model; the API is where your organization actually uses it — and employer job postings have caught up to that fact.

Key Takeaway:

An LLM behind an API is a metered, probabilistic, seconds-slow remote service that returns text unless you constrain it. The two skills that turn it from a toy into infrastructure are (1) making the call correctly and (2) forcing the output into a JSON contract your code can trust.

Why Every Professional Now Meets the API Layer

Our Phase 1 analysis of 2025–26 job postings found ten expectations that appear across all fourteen IT role families — not just software engineering. Number four on that universal list: LLM APIs plus structured outputs and function calling. It shows up in QA listings ("LLM tooling in CI/CD," "prompt engineering for test automation"), in DevOps listings ("we expect you to use LLMs heavily — runbooks, alert configs, postmortems"), in data engineering listings ("structured outputs" named verbatim alongside vector databases), and in PM interview loops that ask candidates to reason about token costs and failure modes.

The reason is mechanical: anything AI does repeatedly and unattended runs through an API, not a chat tab. A chat session has a human in the loop who tolerates a rambling answer. A nightly job classifying 5,000 support tickets has a json.loads() call that does not. The moment AI moves from "assistant I talk to" to "component in a workflow," three things you never thought about in chat become your problem: the request shape, the output contract, and the bill.

You don't need to become a machine-learning engineer. You need to be able to read an API call, predict what it costs, recognize why it failed, and specify the JSON you want back. That's this module.

The Anatomy of a Chat Completion

Every major provider — Anthropic, OpenAI, Google — converges on the same request shape. Learn it once and you can read all three.

Messages, roles, and the system prompt

A request carries a messages array: alternating turns tagged user and assistant. The model's job is to generate the next assistant turn. Alongside the array rides a system prompt — persistent instructions that frame the whole conversation ("You are a release-notes writer. Be factual and concise."). System instructions carry more weight than user content, which is why production apps put role, rules, and output format there rather than repeating them in every user message.

The critical mental-model shift from chat: the API is stateless. There is no server-side conversation object. If you want turn five to remember turn one, you re-send turns one through four in the messages array on every call. "Memory" in every chat product you've used is just client code re-sending history — and paying for those tokens each time.

Tokens and the context window

Models don't see words; they see tokens — subword chunks averaging roughly ¾ of an English word (code and non-English text tokenize less efficiently). Three numbers govern every call:

  • Input tokenseverything you send: system prompt, full message history, tool definitions, pasted documents.
  • Output tokenseverything the model generates, capped by the max_tokens parameter you set. Hitting the cap truncates the response mid-thought (you'll see a stop reason like max_tokens) — it's a ceiling, not a target.
  • Context windowthe hard limit on input the model can attend to. Current frontier models are large: Anthropic's Claude Opus 4.8 and Sonnet 5 take 1M tokens of input; the budget-tier Claude Haiku 4.5 takes 200K. Large is not free, though — you pay for every input token on every call, so "just paste everything in" is a cost decision, not a convenience.

Every response also returns a usage object reporting exactly how many input and output tokens the call consumed. Log it from day one; it is the raw material for the cost section below.

Calling an API: Two Minimal Examples

Both examples do the same job — summarize a pasted incident report in three bullets — so you can see how little differs between vendors.

Anthropic (Claude)

import anthropic  # pip install anthropic; reads ANTHROPIC_API_KEY from env

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    system="You summarize incident reports for engineers. Max 3 bullets.",
    messages=[
        {"role": "user", "content": f"Summarize this incident:\n{report_text}"}
    ],
)

text = next(b.text for b in response.content if b.type == "text")
print(text)
print(response.usage.input_tokens, response.usage.output_tokens)

OpenAI

from openai import OpenAI  # pip install openai; reads OPENAI_API_KEY from env

client = OpenAI()

response = client.responses.create(
    model="gpt-5.6",
    instructions="You summarize incident reports for engineers. Max 3 bullets.",
    input=f"Summarize this incident:\n{report_text}",
)

print(response.output_text)

Same idea, different spelling: a model ID, an instruction channel, the content, and a text result. Google's Gemini follows the same shape with the google-genai SDK (client.interactions.create(model="gemini-3.6-flash", input=...)). Once you can read one vendor's call, you can read them all — which is exactly why this course stays vendor-neutral.

Note

Tutorials age fast in this space. As of mid-2026, current Anthropic model IDs are plain aliases like claude-sonnet-5, claude-haiku-4-5, and claude-opus-4-8 (no date suffixes), and OpenAI's primary surface is the Responses API — if a blog post shows date-stamped model strings or 2023-era parameters, check the official docs before copying it.

Structured Outputs: Why JSON Contracts Matter

Free-form text is fine when a human reads the answer. Automation needs a contract: if your script expects {"intent": "billing", "urgent": true} and the model returns "This looks like a billing issue, and it seems urgent!", your pipeline is broken in a way that only surfaces at 2 a.m.

The naive fix — "please respond in JSON" in the prompt — works often, which is worse than never: it fails just rarely enough to reach production. The real fix is schema-enforced structured output, where the API itself guarantees the response conforms to a JSON Schema you supply. All three major vendors now offer it; the parameter names differ, the idea doesn't.

Anthropic — pass the schema under output_config.format on messages.create, or use the SDK's messages.parse() helper with a Pydantic model:

from pydantic import BaseModel

class Ticket(BaseModel):
    intent: str          # e.g. "billing", "support", "sales"
    urgent: bool
    summary: str

response = client.messages.parse(
    model="claude-sonnet-5",
    max_tokens=512,
    messages=[{"role": "user", "content": f"Classify this email:\n{email_body}"}],
    output_format=Ticket,
)
ticket = response.parsed_output   # a validated Ticket instance

The raw-schema form is output_config={"format": {"type": "json_schema", "schema": {...}}} — the response text is then guaranteed-valid JSON for that schema.

OpenAI — the same capability is text.format with "type": "json_schema" on the Responses API (or response_format on Chat Completions), plus a strict: true flag; the Python SDK's .parse() helpers accept a Pydantic class directly, exactly like the Anthropic example above.

Gemini — pass response_format with "mime_type": "application/json" and a schema (Pydantic's model_json_schema() output drops straight in) on the interaction call.

Exam Tip

Know the mapping — Anthropic: output_config.format (type json_schema); OpenAI: text.format / response_format with strict: true; Gemini: response_format with an application/json MIME type and schema. Assessments test whether you can name where the schema goes for each vendor.

Schema design basics

Structured output is only as good as the schema. Habits that pay off:

  • Prefer enums over open strings."intent": {"enum": ["billing", "support", "sales", "spam"]} turns a fuzzy classification into a closed decision the rest of your code can switch on.
  • Mark everything required and set additionalProperties: false. Optional fields plus open objects reintroduce the ambiguity you were trying to remove.
  • Add description fields. The model reads them — a one-line description per property is prompt engineering that lives inside the contract.
  • Keep schemas shallow. Deep nesting and recursive structures are unsupported or unreliable; flatten where you can.
  • Validate constraints in code. Numeric ranges and string-length limits are commonly ignored or unsupported by the enforcement layer — enforce them in your own validation step after parsing.

Tool Calling: One Concept, Every Vendor

Structured outputs constrain what the model says. Tool calling (also "function calling") lets the model ask your code to do things. You declare tools — each with a name, a description, and a JSON Schema for its arguments — and instead of answering directly, the model can respond with a structured request: "call get_invoice with {"invoice_id": "INV-4412"}." Your code executes the function, sends the result back as a new message, and the model continues — possibly calling more tools — until it produces a final answer.

Three things to internalize at literacy level:

  1. The model never executes anything. It emits a request; your code runs the function and controls what's allowed. Every safety gate (approval prompts, allowlists, dry-run modes) lives on your side of that line.
  2. The description is the steering wheel. The model decides when to call a tool by reading its description — "Fetch an invoice by ID. Call whenever the user references an invoice number" outperforms "gets invoices."
  3. The loop is the primitive under every agent. Call → model requests tool → execute → return result → repeat. That while-loop, plus memory and planning, is what the industry brands as "agents." We go deep on agents and MCP in module cc-7; for now, recognize the loop when you see it.
Pro Tip

On tool definitions, set the strict/validated mode your vendor offers (Anthropic: strict: true with additionalProperties: false and a required list) so tool arguments are guaranteed to match your schema — and always treat the parsed input as an object; never regex the serialized JSON string, since escaping varies across model versions.

Operational Basics

Temperature and sampling, honestly

Older material presents temperature as the master creativity dial: 0 for "deterministic," 1 for "creative." Two honest corrections:

  • Temperature 0 never guaranteed identical outputsit reduces variance, it doesn't eliminate it, so don't build correctness on it.
  • The newest models are removing the knob entirelyAnthropic's current frontier line (Claude Sonnet 5, Opus 4.7 and later) rejects temperature/top_p/top_k with a 400 error; you steer behavior with prompting and an effort setting (how hard the model thinks) instead.

OpenAI and Gemini still expose temperature on most models, and it remains useful there for genuinely creative tasks — but the direction of travel is clear: design your systems to tolerate output variation via schemas and validation, not to suppress it via sampling parameters.

Remember:

Determinism was never on the menu. If your workflow breaks when wording varies, the fix is a tighter contract (schema, enum, tool call) — not a lower temperature.

Retries, timeouts, and rate limits

An LLM API fails like any remote service, plus a few ways of its own:

  • Rate limits (HTTP 429). Every account has requests-per-minute and tokens-per-minute quotas. The response carries a retry-after header; the official SDKs retry 429s and 5xx errors automatically with exponential backoff (Anthropic's default is 2 retries — configurable). For batch workloads, smooth your request rate rather than blasting and praying.
  • Overload and server errors (5xx/529). Transient; retry with backoff and jitter. For critical paths, keep a fallback model — even a different vendor — behind a feature flag.
  • Client errors (4xx). Your request is malformed — wrong model ID, invalid schema, context overflow. Retrying it just delays the stack trace. Fail fast, log loudly.
  • Timeouts. Completions take seconds; long reasoning-heavy calls can take minutes. SDK default timeouts are generous (~10 minutes for Anthropic's), but your gateway's aren't — for anything long or user-facing, stream the response so tokens flow as generated and connections don't idle out.
  • Content-shaped failures. A truncated response (stop_reason: "max_tokens") and a refusal (stop_reason: "refusal" on current Claude models) both arrive inside an HTTP 200. Check the stop reason on every call; a 200 does not mean "usable answer."
Warning

Never blanket-retry 4xx errors, and never let a retry loop wrap a side-effecting tool call that isn't idempotent — a payment API called from inside a retried LLM turn will fire twice. Retries are for failures that heal themselves: 429, 5xx, and network errors.

The Cost Mental Model

LLM APIs bill per token, input and output priced separately — and output tokens typically cost about five times more than input. That asymmetry drives most cost intuition: a long prompt with a short answer is cheap; a short prompt demanding a 3,000-word report is not.

Anthropic's ladder (as of July 2026) illustrates the tiering pattern every vendor follows:

ModelInput / 1M tokensOutput / 1M tokensRole
Claude Opus 4.8$5.00$25.00Hardest reasoning, agentic work
Claude Sonnet 5$3.00$15.00Workhorse — strong quality per dollar
Claude Haiku 4.5$1.00$5.00High-volume simple tasks

OpenAI and Google publish equivalent ladders (flagship / workhorse / mini-flash tiers) on their pricing pages — the shape is identical even when the numbers move. Four levers cut real-world spend more than model choice alone:

  1. Model tiering. Route the easy 80% (classification, extraction, routing) to the cheap tier; reserve the flagship for the hard 20%. A Haiku-class model classifying tickets at $1/M input is often 5–10× cheaper than defaulting everything to the flagship.
  2. Prompt caching. Vendors discount repeated prompt prefixes heavily — cached input tokens cost around a tenth of the normal price on Anthropic's API. If every call re-sends the same 30-page policy document, caching it is the single biggest saving available.
  3. Batch APIs. Non-urgent volume submitted as an asynchronous batch (results within hours) gets a flat ~50% discount.
  4. Shorter prompts and outputs. Trim boilerplate, cap max_tokens sensibly, and ask for terse formats. Remember the stateless design: conversation history you re-send is input you re-buy every turn.

The habit that makes all four possible: log usage on every call from day one. You cannot tier, cache, or trim what you haven't measured.

Pro Tip

Do the arithmetic before you build. A workflow of 10,000 calls/day averaging 2,000 input + 300 output tokens is 20M input + 3M output tokens daily — about $105/day on a Sonnet-class model versus about $35/day on a Haiku-class one. Two minutes of multiplication beats a surprise invoice.

Free and Cheap Paths to Practice

You do not need a corporate account to build the muscle:

  • Google AI Studio (aistudio.google.com) — a genuinely free tier for the Gemini API: create a key, call gemini-3.6-flash from Python at no cost within rate limits. The lowest-friction way to run every exercise below.
  • Ollama (ollama.com) — run open-weight models (Llama, Mistral, Qwen families) locally with one command; it exposes a local OpenAI-compatible endpoint, so the same Python client code works offline for $0. Slower and weaker than frontier models, but perfect for learning the mechanics — and directly relevant to India services contexts where client data can't leave the building.
  • Small prepaid deposits. Anthropic and OpenAI are pay-as-you-go: $5 of credit runs thousands of exercise-scale calls on their cheap tiers, and both consoles include a browser workbench for testing prompts before writing code.

Exercises

  1. First call. Pick any path above (AI Studio is fastest). Make one API call from Python that sends a system prompt and a user message, then print the response text and the input/output token counts. Rerun the identical request twice — note that wording differs while meaning holds.
  2. Messy text → validated JSON. Take five real, messy inputs (meeting notes, a support email thread, a log excerpt). Define a schema — at least one enum, one boolean, all fields required, additionalProperties: false — and use your vendor's structured-output mechanism to extract records. Validate each result in code (parse it, check the enum values). Add a repair step: on validation failure, retry once with the invalid output and the error message appended to the prompt.
  3. Break it, then read the failure. Deliberately trigger three failures and identify each from the response alone: (a) set max_tokens=20 and confirm the truncation stop reason, (b) use a bogus model ID and observe the 4xx, (c) paste an input large enough to matter and compare the reported usage/cost against a small one.
  4. Cost forecast. Take one recurring task from your own job (triaging tickets, summarizing PRs, drafting status reports). Estimate daily volume and average tokens per call, then compute monthly cost at your vendor's cheap tier and flagship tier. Write three sentences: which tier you'd choose, and which of the four levers you'd pull first.

Key Takeaways

  • The API layer is a universal employer expectation across IT roles — because anything AI does repeatedly and unattended runs through an API, not a chat tab.
  • Every vendor's call has the same anatomy: system prompt + messages array in, text + usage out; the API is stateless, so history is re-sent — and re-billed — every turn.
  • "Please respond in JSON" is a bug waiting to ship; schema-enforced structured outputs (Anthropic output_config.format, OpenAI text.format/response_format, Gemini response_format + schema) are the contract.
  • Tool calling is the model requesting actions your code executes — the loop beneath every agent, with all safety gates on your side of the line.
  • Sampling knobs never bought determinism, and the newest Anthropic models have removed them; engineer for variation with schemas and validation.
  • Retry only what heals itself (429/5xx/network) with backoff; fail fast on 4xx; check stop reasons because failures arrive inside 200s.
  • Cost = input tokens + (pricier) output tokens; the big levers are model tiering, prompt caching, batch APIs, and shorter prompts — all powered by logging usage from day one.

Further Reading

This is the free reading view. Open BXUP to track your progress, run the hands-on labs, and prove it with original, exam-pattern assessments.
© Anvi Innovate · BXUP — Be Exponentially Upskilled · BXUP is an independent learning platform, not affiliated with or endorsed by AWS, Microsoft, Google, NVIDIA, IBM, Salesforce, Databricks, Oracle or Anthropic. All trademarks belong to their respective owners. · bxup.in