Eleven ideas, one per screen. This is the layer Claude Code and every other app sits on. Each slide is a thing to point at while you explain. Take the silences.
Four moves: make the call, make it reliable, extend its reach, then compose the pieces into systems.
You send a model, an optional system line, and the whole message list. It replies once. There's no memory. To continue, you append the reply and send it all again.
A "multi-turn conversation" is just this loop run by hand: the model holds nothing between calls, so the growing messages[] list is the memory. Same key, same shape, whatever language you call from.
Key conceptMinimum request = model + messages + max_tokens in the body, API key in the headers. Keep the key in an env var / .env, never hardcoded. → teacher notes (incl. web-app: key stays server-side).
You don't change the model to change the behaviour. You turn these.
The system prompt does the heavy lifting. It's where the role and rules live. Temperature trades reliability for variety; streaming is about feel; structured output is how you get data a program can actually use.
Key conceptFor clean JSON with no prose to strip, use forced tool use (tool_choice): define a tool whose schema is the shape you want, read back the validated object. → teacher notes (prefill+stop-sequences is the lighter, flat-JSON alternative).
An eval is a test suite for prompts: a set of cases, run automatically, graded, scored. Change the prompt, re-run, watch the number move.
Two ways to grade: code-based for anything exact (is it valid JSON? does it contain the answer?), model-based for judgement (is this tactful? is it on-topic?): you ask another Claude call to score it against a rubric.
Key conceptThe eval loop: build test cases → Claude generates responses → grade them → score → refine and re-run. The step after generation is grading; model-based grading uses another AI to judge. → teacher notes.
What's a "model grader"? The model-based half: another Claude call that scores an output against a rubric. The go-to when "right" is a judgement (tone, relevance, helpfulness) that code can't check exactly.
How far do you trust it? Write a clear rubric, have it return a one-line reason with the score, and check it against human marks on a sample before you lean on it across hundreds of cases.
When the output is wrong, you rarely need a bigger model. You need a clearer prompt. Reach for these in order.
Examples (few-shot) move quality the most: a couple of worked input→output pairs teach format and edge cases that paragraphs of instruction can't. XML tags matter because Claude is trained to respect them: <document>…</document> reads cleaner than quotes.
Claude can't run anything. It can only ask. You describe the tools; it replies "call this, with these arguments"; you run it and hand back the result; it continues.
The loop can repeat. Claude can call several tools across several turns before it answers. This single mechanism is what every agent is built on: the model proposes, your environment executes, the result comes back.
So a tool is a special Anthropic endpoint? No. There's one Messages endpoint. A tool is a plain function in your own code; Claude only ever returns a request to call it (name + arguments) and waits for your result.
Is it a config file that sets Claude's behaviour? No. A tool is your code, plus a declaration (name, description, input schema) that tells Claude the function is available, not how it should behave.
Most tools are yours to implement. A few ship with the API. You switch them on and Anthropic runs them server-side.
The text editor and code execution tools are exactly what powers Claude Code and the analysis features. The Files API lets a request reference uploaded files (PDFs, datasets) without re-sending them every call.
Key conceptThe code execution tool's main limit: it runs Python in an isolated sandbox with no network access. The Files API is the upload-once / reference-many store that also moves inputs in and outputs (charts) back out. → teacher notes.
You can't fit a whole knowledge base in one prompt. So you index it once, then retrieve only the few chunks each question needs and paste them in.
Embeddings catch meaning ("car" finds "vehicle"); BM25 catches exact terms (an error code, a part number). A multi-index pipeline runs both and merges the hits. That's what production RAG actually does.
Four capabilities ride on the request you already know: two change what goes in, two change what comes out.
Extended thinking gives the model room to work through hard problems before committing to an answer. Citations turn "trust me" into "here's the passage", the backbone of any answer a business has to stand behind.
Key conceptPDF vs image: a PDF is read as text and images (a document block, supports citations); an image is vision-only. PDFs cost more per page but give the richer, citable understanding. → teacher notes.
Most prompts start with the same big block: a system prompt, tool definitions, a document. Cache that prefix and later calls read it instead of re-paying for it.
The rule: only an exact, unchanged prefix is reused, so put everything stable first and the variable part last. Cache lifetimes are short (minutes), so it pays off across a burst of related calls, the heart of any responsive, repeated-context app.
Key conceptCaching needs two things: mark the block cache_control: ephemeral and clear the minimum length (~1,024 tokens on Sonnet 4.x, ~4,096 on Opus 4.5+). Under the minimum it silently runs uncached, with no error. → teacher notes.
Without it, every app wires up every integration by hand. With it, a server exposes its capabilities once and any client can connect.
A server publishes three things (tools, resources, prompts) and the inspector lets you test it before wiring it to a client. Build the integration once; plug it into Claude Code, your own client, or anyone else's.
Exposing document contents? That's a resource: read-only data Claude can pull in. Actions it performs are tools; pre-tested instructions (like a formatter) are prompts.
Defining a tool in Python? Easiest way is the @mcp.tool() decorator (FastMCP). The function's name, docstring and type hints become the tool, no schema by hand.
How do client and server talk in dev? Almost always stdio: the client runs the server as a subprocess over stdin/stdout. No ports, no auth. HTTP is for remote.
Why three primitives, not one? Different owners. Model picks tools, the app loads resources, the user invokes prompts, so each is offered the right way.
Both chain LLM calls. The difference is control: in a workflow you wire the steps; in an agent the model chooses them as it goes.
Choose by predictability. If you can draw the steps in advance, a workflow is cheaper and more reliable. If the path depends on what's found along the way, you need an agent. Claude Code is one. Most production systems mix both.
Want it to handle the unexpected? Give the agent a few general tools and let it pick, not one narrow tool per case you predicted. General tools recombine into paths you never scripted.
One long prompt it keeps half-ignoring? Chain it. Split the rules across a few small steps so each call holds less, and check the output between them.
A stateless request is the unit. Evals and prompting make it reliable; tools, RAG and the model's own capabilities give it reach; MCP and the workflow-vs-agent choice are how you build something real.
tutto.one/praxis · daniel@tutto.one