Lesson 12 Cost, Latency & Evals Across Frameworks
Theme:
Lesson 12 · Slide 1

Lesson 12 — Cost, Latency & Evals

Operating agents in production: knowing what you spend, what you wait for, and whether the answer is right.

Agents Module 6 Operations MCP Bridge

Lesson 12 · Slide 2

Three pillars of operating an agent

Lesson 12 · Slide 3

Cost — what actually drives the bill

Lesson 12 · Slide 4

Token accounting in code

total_in = total_out = total_cost = 0.0
for event in agent.stream(question):
    if event.type == "message_stop":
        total_in += event.usage.input_tokens
        total_out += event.usage.output_tokens
        total_cost += event.usage.cost_usd     # if the SDK provides it

Each framework exposes usage differently — Claude SDK on the streaming event, OpenAI SDK on Runner.run_result.usage, LangGraph via callbacks, CrewAI by aggregating its sub-agents. The L11 eval harness abstracts this.

Lesson 12 · Slide 5

Cost caps you should always have

Per-task cap

e.g., max_cost_usd=0.50 — kills a runaway agent before it explodes the bill.

Per-user-per-hour cap

Your application's responsibility, not the SDK's. Implement at the API edge.

Lesson 12 · Slide 6

Latency — what your user actually waits for

Lesson 12 · Slide 7

Latency budgeting

A useful frame

budget = max_turns × per_turn_latency × (1 + tool_serial_factor)

For the L04 sweet-spot agent: 6 turns × 2.5s/turn × 1.2 ≈ 18s.

If your UX needs <10s, cut max_turns or use a smaller model — don't change frameworks; that's not where the latency lives.

Lesson 12 · Slide 8

Streaming makes latency feel different

Lesson 12 · Slide 9

Evals — beyond “did it crash?”

Lesson 12 · Slide 10

A minimum eval rig

def eval_one(question: str, expected_bullets_substring: list[str]) -> dict:
    out = run_research_agent(question)
    bullets = out["report"].get("bullets", [])
    hits = sum(
        1 for substr in expected_bullets_substring
        if any(substr.lower() in b.lower() for b in bullets)
    )
    return {"q": question, "score": hits / len(expected_bullets_substring),
            "cost": out["cost_usd"], "latency_s": out["turns"]}

Substring-based scoring is crude but reproducible. Good first eval — replace with LLM-as-judge if you need precision.

Lesson 12 · Slide 11

MCP-bridge sidebar — what it is

Lesson 12 · Slide 12

MCP-bridge sidebar — the demo

# Launch the stub server as a subprocess; connect via stdio.
from mcp.client.stdio import stdio_client, StdioServerParameters
async def demo():
    params = StdioServerParameters(
        command="python", args=["-m", "agents._eval.mcp_stub.server"]
    )
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as sess:
            await sess.initialize()
            result = await sess.call_tool(
                "pkb_search", {"query": "BIG TCP"}
            )
            print(result.content[0].text)

This is the client side; the server side is the stub we ship in agents/_eval/mcp_stub/server.py.

Lesson 12 · Slide 13

What the sidebar does NOT cover

Out of scope here (covered by the Creating MCP Servers course)

  • Authentication / authorization on MCP tools.
  • Network transports (HTTP, WebSocket) beyond stdio.
  • Hosting MCP servers in production.
  • The full set of MCP primitives (resources, prompts, sampling) — we only use tools.
Lesson 12 · Slide 14

Recap & what's next

Coming up: Lesson 13 — where agents are going in 2026. Theory + slides + homework only.
1 / ?