Skip to content

    Forward Deployed Engineer

    How an LLM Application Works: One Request in Code

    Trace one LLM request in code: the messages, the call, the validation and the token cost, and learn when plain code should answer instead of a model.

    By Published 10 min read

    Share

    What you'll learn: what actually happens when your code "calls an LLM": two messages go out, text and token counts come back, and everything else (checking the reply, filtering what the user may see, deciding whether to call a model at all) is ordinary code that you write. You trace one request, count the calls in the capstone, price them with placeholder prices and write a lookup that needs no model.

    At a glance

    Figure 1. The capstone application, end to end

    End-to-end architecture of the Product Discovery Copilot capstoneClient app to API gateway (request); API gateway to Orchestrator (run); Orchestrator to Model gateway (prompt); Model gateway to LLM provider (call); Orchestrator to Tool server (tool call); Orchestrator to Retriever (query); Tool server to Document store (read); Retriever to Document store (read)CAPSTONE SERVICEClient app: React pageClient appReact pageAPI gateway: FastAPI, tokenAPI gatewayFastAPI, tokenOrchestrator: run_discoveryOrchestratorrun_discoveryModel gateway: provider interfaceModel gatewayproviderinterfaceLLM provider: mock by defaultLLM providermock by defaultTool server: 3 read-only toolsTool server3 read-only toolsRetriever: BM25 keywordRetrieverBM25 keywordDocument store: catalog, documentsDocument storecatalog,documentsrequestrunpromptcalltool callqueryreadread

    How to read this: the model sits behind one interface at the edge of the system; every other box is ordinary code that your tests can run without it.

    • One model call is messages in, text plus token counts out. Nothing more.
    • The model proposes; code validates, filters and decides what the user sees.
    • The pumps request in the capstone makes 9 model calls, not 1, and the bill grows with the calls.
    • If the answer sits in a record, a lookup is cheaper, faster and identical every time.
    • Input and output tokens have separate prices: you pay for each.

    Scenario

    Composite scenario, not a real company. Lumen Industrial Supply, a fictional distributor, is piloting a copilot for its sales engineers.

    Two kinds of questions arrive: "What is the ingress protection rating of the LUM-VS-100?", which has one answer in the product record, and "monitor vibration on 40 pumps in a humid plant, budget around 30k, must work with our existing OPC UA setup", which needs search, checks and judgment. The lead asks: does every question need a model, and what does one request cost? All figures are illustrative.

    What you will be able to do

    • Trace one LLM request in code: the messages built, the call made, the reply validated, the tokens recorded.
    • Say which steps of the capstone belong to the model and which to code.
    • Compute the cost of a request from token counts and placeholder prices, and count the calls a workflow makes.
    • Decide when a lookup should replace a model call, and write one.

    Prerequisites

    You should be able to read Python and run pytest: see Testing with pytest. For the theory of gateways, routing, tokens and context windows, read Models and routing; this lesson adds only the view from the code.

    Core ideas

    One request, in code

    Predict first. The capstone's extract_messages builds the first call for the pumps request. How many messages does it send, and how many model calls does the whole request make end to end (extract, plan, compose)?

    Answer

    Two messages (one system, one user) for that first call. The whole request makes 9 model calls: 1 to extract requirements, 7 to plan (six tool calls plus the final "stop" decision) and 1 to compose. A request that looks like one call is often many, and that is where cost surprises come from.

    Figure 2. Anatomy of one request

    sequenceDiagram accTitle: Anatomy of one LLM request accDescr: The caller sends the customer text to the prompt builder, which returns a system message and a user message. The caller sends both to a metered provider, which forwards them to the model. The model returns reply text and token counts. The metered provider records the tokens and returns a completion. The caller validates the text against a schema and gets either typed requirements or an error. participant C as Caller code participant P as Prompt builder participant M as Metered provider participant L as Model participant V as Validator C->>P: customer text P-->>C: system message and user message C->>M: messages and a JSON schema M->>L: request L-->>M: reply text and token counts M-->>C: completion, tokens recorded C->>V: reply text V-->>C: typed requirements or an error

    How to read this: the model is one participant out of five, and four of them are code you own and can test.

    The prompt builder is a plain function. The instructions go in the system message; the customer's text goes in the user message, untouched.

    Verified: capstone/fde-product-discovery-copilot/app/llm/prompts.py

    def extract_messages(request: str) -> list[Message]:
        system = (
            f"TASK: {TASK_EXTRACT}\n"
            "Turn a customer request for industrial equipment into JSON requirements. "
            "Use only what the request says; leave a field empty when it is not mentioned. "
            "Return JSON only. Never invent a product."
        )
        return [Message("system", system), Message("user", request)]

    A real provider's HTTP API has the same shape. As of 2026-11-02 the Anthropic Messages API requires a model id, a list of messages and max_tokens (a ceiling on generated tokens, not a target), and takes the system prompt in a separate system parameter. Its example responses carry a usage object with input and output token counts.

    What the model owns and what code owns

    Step in the capstone Done by Why
    Turn free text into Requirements model (the mock here) language is the input
    Find SKUs named in the text code (Catalog.mentions) exact match, and it must respect who may see what
    Search the catalog, read specs, check protocols code (tools) the data is structured and exact
    Choose the next tool call model (the mock here) open-ended, but bounded by max steps and a time limit
    Retrieve evidence, filter by visibility code (retriever) access control is never the model's job
    Write the "why" text model (the mock here) language is the output
    Keep only real SKUs with real citations code (_validated) the model's output is a proposal

    The model handles language at the two ends; code handles everything that must be exact, allowed or auditable. The mock is a rule-based stand-in that makes the course runnable offline; a real model behaves less predictably.

    When deterministic code beats a model

    Question to ask If yes, prefer code
    Is the answer one field in a record you own? Look it up.
    Must the same input always give the same output? Code is repeatable; a model is not.
    Must you prove where the answer came from? A record is a source; a model sentence is not.
    Is a wrong answer costly and easy to avoid? Do not add a chance of error.
    Does the request need language understanding or judgment? Use the model, then check its output.

    Decision exercise. Many Lumen questions look like "What is the X of LUM-...?". Options: (A) send every question through the full pipeline; (B) answer single-product field lookups from the record and send the rest to the model; (C) replace the pipeline with keyword rules. Choose one and justify it in three sentences.

    Model answer

    Choose B. A lookup is exact, free of token cost, identical on every run and cites the record. Option A pays for calls that add a chance of error, and an old document can contradict the record (the capstone's superseded datasheet lists IP65 where the current record says IP67). Option C loses the cases that need language: "40 pumps in a humid plant" has no field to match. Do not use B if the record is not kept in sync with the datasheets: fix data ownership first.

    At the customer: a sponsor asks "is this AI?" about a lookup. A good answer: the model interprets language, a lookup returns a stored fact, and mixing them gives reliability and a predictable bill.

    Cost: tokens in, tokens out, calls

    A provider bills input tokens and output tokens at two different prices, which you read from its published price list. One call costs input tokens times the input price plus output tokens times the output price; a workflow multiplies that by its number of calls.

    The capstone's UsageMeter prices each call with Settings.input_price_per_mtok and output_price_per_mtok. Both are placeholders (1.0 and 5.0 EUR per million tokens): fill in your provider's published prices before you quote a number.

    Cost of the pumps request in placeholder cost units (interactive when JavaScript is on)
    Cost per request (units)0.004272
    Cost per 1,000 requests (units)4.272

    The start values give 0.004272 units per request and 4.272 per 1,000 requests. Change priceOut to 1 to see how much of the bill output carries; cachedShare shows what caching would do (the capstone does not use it).

    Worked example

    Assumptions: the mock provider (token counts are the capstone's estimate of 1 word = 1.3 tokens, rounded up, not a real tokenizer); placeholder prices of 1.0 and 5.0 EUR per million input and output tokens; the pumps request as a public user. Numbers come from running the code in lessons/M2-L1.

    Call group Calls What it does
    Extract 1 77 input and 32 output tokens
    Plan 7 six tool steps plus the final decision
    Compose 1 writes one recommendation per candidate
    Total 9 2,792 input and 296 output tokens

    Cost: (2,792 x 1.0 + 296 x 5.0) / 1,000,000 = 4,272 / 1,000,000 = 0.004272 EUR, so 4.27 EUR per 1,000 requests. Output tokens are 1,480 of 4,272 cost units, 34.6 percent of the bill, although they are only 9.6 percent of the tokens.

    Of the 36 golden questions, 3 (q13, q14 and q17) are single-product field lookups that answer_without_model answers with zero calls, 8.3 percent of the set. The same author wrote the set and tuned the pipeline, so treat 3 of 36 as an illustration, not your customer's traffic mix.

    Build it

    The lesson code is lessons/M2-L1/m2_l1_anatomy.py, with tests in test_m2_l1_anatomy.py. First, the trace: build the messages, call through the metered provider, validate, read the meter.

    Verified: capstone/fde-product-discovery-copilot/lessons/M2-L1/m2_l1_anatomy.py

    def trace_one_request(text: str, provider: LLMProvider, settings: Settings) -> RequestTrace:
        """Build the messages, make the call, validate the reply, and read the meter."""
        meter = UsageMeter(settings)
        llm = MeteredProvider(provider, meter)
        messages = extract_messages(text)
        requirements = complete_structured(llm, messages, Requirements)
        usage = meter.snapshot()
        return RequestTrace(
            roles=[m.role for m in messages],
            input_tokens=usage.input_tokens,
            output_tokens=usage.output_tokens,
            llm_calls=usage.llm_calls,
            cost_eur=usage.estimated_cost_eur,
            requirements=requirements,
        )

    Second, the lookup. It returns None when it cannot answer, which means "send it to the model". It resolves the SKU with catalog.mentions, which ignores products the caller may not see, so a public user asking about a partner-only SKU falls through to the normal path.

    Verified: capstone/fde-product-discovery-copilot/lessons/M2-L1/m2_l1_anatomy.py

    def answer_without_model(text: str, catalog: Catalog, visibilities: Collection[str]) -> str | None:
        """Answer 'what is <field> of <one SKU>' from the product record. None means: use the model."""
        low = text.lower()
        skus = catalog.mentions(text, visibilities)
        fields = {field for word, field in FIELD_WORDS.items() if word in low}
        if len(skus) != 1 or len(fields) != 1:
            return None
        product = catalog.products[skus[0]]
        field = fields.pop()
        value = getattr(product, field, None) if field in ("ip_rating", "protocols") else product.specs.get(field)
        if value in (None, []):
            return None
        shown = ", ".join(value) if isinstance(value, list) else value
        return f"{product.sku}: {field} = {shown}"

    Third, a test that counts calls per task, so an added call fails loudly instead of showing up on the invoice.

    Verified: capstone/fde-product-discovery-copilot/lessons/M2-L1/test_m2_l1_anatomy.py

    def test_the_whole_pumps_request_makes_nine_calls(services: Services) -> None:
        counting = CountingProvider(MockProvider())
        svc = Services(services.settings, services.catalog, services.store, counting)
        usage = run_discovery(PUMPS, PUBLIC, svc).response.usage
        assert counting.by_task == {"extract_requirements": 1, "plan_next_step": 7, "compose_answer": 1}
        assert (usage.llm_calls, usage.input_tokens, usage.output_tokens) == (9, 2792, 296)
        assert usage.estimated_cost_eur == pytest.approx((2792 * 1.0 + 296 * 5.0) / 1_000_000)

    Run the lesson tests:

    ./.venv/Scripts/python -m pytest lessons/M2-L1 -q

    Exercise

    Extend answer_without_model so that "What is the price of the LUM-VS-100?" is answered from the record, and the answer says the price is illustrative.

    Acceptance criteria:

    • A new test shows the price question returns an answer that contains the word "illustrative".
    • The golden-question test still finds exactly q13, q14 and q17, or you update it and explain why in a comment.
    • q33 ("What is the partner price for the LUM-VS-900?") still returns None for a public user.

    Done when the lesson tests pass and you can say why q33 falls through.

    Hint 1: where does the price live?

    In app/models.py, price_eur is a field of the product itself, not an entry in specs, like ip_rating. How does the existing code handle ip_rating?

    Hint 2: the shape of the change

    Map "price" to price_eur in FIELD_WORDS and add price_eur to the tuple on the getattr line. Include the label "illustrative price". Then run q33 with {"public"} and look at what catalog.mentions returns for LUM-VS-900.

    Common mistakes

    • Treating the model as the application: no validation, no filtering, no limit on calls. Its output is a proposal.
    • Counting one call per user request. A tool loop makes many, and each repeats the instructions and history as input.
    • Reading only one price. Input and output tokens are priced separately.
    • Using a model for a stored fact. It adds cost and a chance of a wrong or stale answer for no gain.

    Knowledge check

    1. What does one LLM call consist of, from your code's point of view?

    Messages go in (a system message with instructions and a user message with the data); reply text plus input and output token counts come back. Parsing, checking the reply and deciding what happens next is your code.

    2. The pumps request makes 9 calls. Name the three groups and why the plan group is the largest.

    Extract (1), plan (7) and compose (1). The plan group is largest because the workflow asks the model for the next step after every tool result: six tool steps plus one final decision. Each call's input carries the observations so far.

    3. A request uses 1,000 input and 200 output tokens at placeholder prices of 1.0 and 5.0 per million. What does it cost, and what share is output?

    (1,000 x 1.0 + 200 x 5.0) / 1,000,000 = 2,000 / 1,000,000 = 0.002 units. Output is 1,000 of the 2,000 cost units: 50 percent of the bill from 16.7 percent of the tokens. When the output price is higher, shorter replies can matter more than a shorter prompt.

    4. When would you not use a lookup for "What is the IP rating of LUM-VS-100"?

    When the record is not kept in step with the datasheets, because the lookup then returns a stale answer with full confidence, or when the customer wants a document quotation, which a record cannot give. Fix data ownership first, or route through retrieval with citations.

    5. Why does the lookup use `catalog.mentions` with the caller's visibilities instead of searching the whole catalog?

    A product the caller may not see must behave as if it does not exist. mentions ignores it, so a public user asking about a partner-only SKU goes down the normal path, where the same filters apply. Filtering after the lookup, or not at all, would leak partner-only data.

    You can now

    • Trace a request from customer text to validated output and name each participant.
    • Say which steps of the capstone are model work and which are code work.
    • Price a request from token counts and placeholder prices, and count calls with a test.
    • Write a lookup that falls through to the model when it cannot answer.

    Further reading

    Last verified: 2026-11-02

    Next

    Prompts and untrusted input

    Ask about this article

    Get answers grounded in this post. AI-generated — based on this article, and may be imperfect.

    Scaled AI Weekly

    Enjoyed this? Get more like it every Monday.

    Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.

    Get new articles by email

    Free. We email a confirmation link first, and you can unsubscribe from any email.

    Join engineers building production AI systems

    Comments