Claude Architect WorkshopPDFEPUBlearnwithparam.comkaas.team

Professional, lesson 12

Tracing

One run id, one span per call

The Lumen support agent logs every full prompt with the customer's name and email, and no id ties a run's calls together. When a wrong answer is reported, nobody can find the run, and the log holds data it should not. This is the order status agent at Lumen Supply, an online electronics shop. You will read a log that leaks and cannot find its run, then fix two functions in one file. The fix is a run id, one span per call, and hashed personal fields.

I doWatch the failure and its fix.

One wrong answer, twenty minutes to find the run

The agent answers where an order is. It calls two tools, one for the order and one for its shipping. Each call can leave a record in the log.

Three things go wrong, in this order. Full prompts are logged with personal data, so the log is a leak. No run id ties the calls of one run together, so a bad answer cannot be found. And alerts fire on single errors, not on a number derived from the spans.

What a call leaves in the log.Callmodel or toolredacthash personal dataspanrun id, name, fieldsMetricsp95, cost, alertsboth rules are written in trace.pyWhat a call leaves in the log.Callmodel or toolredacthash personal dataspanrun id, name, fieldsMetricsp95, cost, alertsboth rules are written in trace.py

One run, one id, five spans

A customer says the order shows delivered and nothing arrived. The agent calls the order tool, then the shipping tool, and the shipping tool times out. The log holds 5 spans, and every one carries the run id.

A hook on each tool call starts a clock before it and reads it after, so a tool span's time is measured, not typed in.

Open the Log card to read them. Each span has a name, and the tool spans have a time and a status. The order result shows the customer's fields as hashed tags, not as text.

  1. CallerSigned in as Dana Lee <dana.lee@example.com>. My order O-1004 says delivered but nothing…
    Show the result
    Signed in as Dana Lee <dana.lee@example.com>.
    
    My order O-1004 says delivered but nothing arrived. Where is it really?
  2. Agentcalls: get_order, get_shipping, get_shipping, get_shipping
    Show the result
    get_order, get_shipping, get_shipping, get_shipping
  3. Log7 spans; 7 carry the run id
    Show the result
    {"run_id": "run-3cfa9b1e", "name": "request"}
    {"run_id": "run-3cfa9b1e", "name": "model", "turns": 5, "cost_usd": 0.0004824450000000001}
    {"run_id": "run-3cfa9b1e", "name": "get_order", "tool": "get_order", "ms": 152, "status": "ok", "result": "{\"order_id\": \"O-1004\", \"item\": \"router\", \"status\": \"shipped\", \"name\": \"name#7f0f4eba\", \"email\": \"email#398efa8e\", \"phone\": \"phone#f5430c8c\", \"address\": \"address#b01dc2ed\"}"}
    {"run_id": "run-3cfa9b1e", "name": "get_shipping", "tool": "get_shipping", "ms": 165, "status": "error", "error": "carrier_timeout", "result": "{\"order_id\": \"O-1004\", \"error\": {\"category\": \"carrier_timeout\", \"retryable\": true}}"}
    {"run_id": "run-3cfa9b1e", "name": "get_shipping", "tool": "get_shipping", "ms": 162, "status": "error", "error": "carrier_timeout", "result": "{\"order_id\": \"O-1004\", \"error\": {\"category\": \"carrier_timeout\", \"retryable\": true}}"}
    {"run_id": "run-3cfa9b1e", "name": "get_shipping", "tool": "get_shipping", "ms": 161, "status": "error", "error": "carrier_timeout", "result": "{\"order_id\": \"O-1004\", \"error\": {\"category\": \"carrier_timeout\", \"retryable\": true}}"}
    {"run_id": "run-3cfa9b1e", "name": "answer"}
  4. Runbook7 spans found for run-3cfa9b1e
    Show the result
    7 spans found for run-3cfa9b1e
    first bad tool span: get_shipping: carrier_timeout
    last model call: 5 turns

The run was found, and the log holds no personal data.

Span and redact, written as code

Two functions hold the design. The file shown is the starting one. The span function should write one record per call, with the run id, the name and only the allowed fields.

The redact function should hash personal data before it is written. The same value should always give the same tag, so a reader can still tell that two spans are about one customer.

starter/trace.py
1"""EDIT THIS FILE. The log has two planted defects.21. span(): writes every field, prompt and email included, with no run id.32. redact(): returns the text untouched.45Run `./workshop check tracing` until it is green, then6`./workshop watch tracing`.7"""89from kit.api import Json101112def span(run_id: str, name: str, data: Json) -> Json:13 """One log record for one call. The start keeps it all and no id."""14 return {"name": name, **data}151617def redact(text: str) -> str:18 """Hide personal data in text. The start hides nothing."""19 return text

Is logging every full prompt the safest way to debug?

A teammate says the log should keep every full prompt, because more detail can only help when a run goes wrong.

Predict: Is logging every full prompt the safest way to debug?

  1. ANo, it leaks data and finds no run.
  2. BYes, more detail helps.
Show the answer

A. Structured spans with a run id find the run. Redaction keeps personal data out of the store, so the detail that helps is kept and the detail that harms is not.

Full prompts and no run id

This is a real Claude Haiku 5.5 run, recorded once and replayed here. The customer gave an email, a phone number and an address in the message. The starting log wrote the whole prompt, and no span carries a run id.

Open the Log card. The first line holds priya.nair@example.com in clear text, and a search for the run id finds 0 spans. A log that cannot find the run and holds the email is both useless and a leak.

  1. CallerSigned in as Priya Nair <priya.nair@example.com>. I am Priya Nair…
    Show the result
    Signed in as Priya Nair <priya.nair@example.com>.
    
    I am Priya Nair, priya.nair@example.com, phone 555-0163, at 88 Ash Lane. Where is order O-1006?
  2. Agentcalls: get_order, get_shipping
    Show the result
    get_order, get_shipping
  3. Log5 spans; 0 carry the run id
    Show the result
    {"name": "request", "prompt": "Signed in as Priya Nair <priya.nair@example.com>.\n\nI am Priya Nair, priya.nair@example.com, phone 555-0163, at 88 Ash Lane. Where is order O-1006?"}
    {"name": "model", "turns": 3, "cost_usd": 0.0002721}
    {"name": "get_order", "tool": "get_order", "ms": 150, "result": "{\"order_id\": \"O-1006\", \"item\": \"desk lamp\", \"status\": \"shipped\", \"name\": \"Priya Nair\", \"email\": \"priya.nair@example.com\", \"phone\": \"555-0163\", \"address\": \"88 Ash Lane\"}", "status": "ok"}
    {"name": "get_shipping", "tool": "get_shipping", "ms": 192, "result": "{\"order_id\": \"O-1006\", \"status\": \"in transit\", \"carrier\": \"Parcelly\"}", "status": "ok"}
    {"name": "answer", "reply": "Order O-1006 (desk lamp) has shipped and is in transit with Parcelly. It's on its way to 88 Ash Lane. The carrier status doesn't include a tracking number or delivery date.", "chars": 172}
  4. Runbookrun not found
    Show the result
    run not found
    no spans
    no spans

The log failed: the log holds the customer's email and name, and no span carries a run id.

Structured spans with a run id

span keeps the run id and only the fields in its allow-list. The prompt and the reply are not in it, so they are never written. redact hashes the six personal fields, emails and phone numbers in what remains.

If a log store that holds personal data leaks, that is a breach to report, and two years of prompts is two years of exposure. Hashing before the write keeps the readable value out of the store. The hash is stable, so the same customer keeps the same tag, and the log still counts as personal data.

What the agent calls and what the log keeps.CallerAgentLogrequesttool callsone span per callrun id foundanswer
trace.pygreen lines are what the fix adds
1"""One record per call, tied to its run, with personal data hashed."""23import hashlib4import re56from kit.api import Json78ALLOWED = ("tool", "ms", "status", "error", "turns", "cost_usd", "result")9PERSONAL = "name|email|phone|address|card_last4|birth_date"10FIELD = re.compile(rf'"({PERSONAL})":\s*"([^"]*)"')11EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+")12PHONE = re.compile(r"\b\d{3}-\d{4}\b")131415def tag(kind: str, value: str) -> str:16 """A stable stand-in: the same value always gives the same tag."""17 digest = hashlib.sha256(value.encode()).hexdigest()[:8]1819 return f"{kind}#{digest}"202122def redact(text: str) -> str:23 """Hash the personal fields, emails and phone numbers in text."""24 text = FIELD.sub(lambda m: f'"{m[1]}": "{tag(m[1], m[2])}"', text)25 text = EMAIL.sub(lambda m: tag("email", m[0]), text)2627 return PHONE.sub(lambda m: tag("phone", m[0]), text)282930def span(run_id: str, name: str, data: Json) -> Json:31 """One record: the run id, the name and only the allowed fields."""32 kept = {k: data[k] for k in ALLOWED if k in data}33 clean = {34 k: redact(v) if isinstance(v, str) else v for k, v in kept.items()35 }3637 return {"run_id": run_id, "name": name, **clean}
We doChange one setting at a time and predict.

The same input now ends well

Use the switch to run the same case with raw prompts and then with structured spans. The card marked "This is where the runs split" shows what the log held.

The raw log found 0 spans for its run id and held the email. The structured log found 5 spans and held only hashed tags. The model's answer was the same kind in both runs, so the fix is in the log.

This part is interactive in the lab: run ./workshop watch tracing.

Try it: logging and case

Change one setting at a time. Pick a case, then switch between raw prompts and structured spans. Every combination is a recorded run, so this works with no internet.

In the slow case, the hook measured the shipping tool at 4,213 ms. That is one of 2 timed spans, so p95 latency for the run is 4,213 ms against a limit of 2,000 ms, and the alert fires. A mean would hide a tail like that, which is why the alert reads p95 from the spans.

This part is interactive in the lab: run ./workshop watch tracing.

Triage from a trace

The runbook has three checks in order: find the run by its id, read the tool spans for errors or slow calls, then read the last model call. Each check has an owner.

Here the second check finds get_shipping with a carrier timeout, so the fix starts in that tool and not in the prompt. A fault in a tool span is not cured by rewording the prompt. The same spans show the path an agent took, which is the only record of a path that code did not fix in advance.

app/runbook.py
1"""The triage runbook: three checks in order, and who owns each one."""23from kit.api import Json45SLOW_MS = 20006CHECKS = (7 ("Find the run by its id", "on-call engineer"),8 ("Read the tool spans for an error or a slow call", "on-call engineer"),9 ("Read the last model call", "agent owner"),10)111213def first_bad(spans: list[Json]) -> str:14 """The first tool span with an error or a slow call, or none."""15 for s in spans:16 if s.get("status") == "error":17 return f"{s['name']}: {s.get('error', 'error')}"1819 if int(s.get("ms", 0)) > SLOW_MS and "tool" in s:20 return f"{s['name']}: {s['ms']} ms"2122 return "none"232425def triage(spans: list[Json], run_id: str) -> list[str]:26 """Run the three checks on a log and say what each one found."""27 mine = [s for s in spans if s.get("run_id") == run_id]28 tools = [s for s in mine if "tool" in s]29 last = next((s for s in reversed(mine) if s["name"] == "model"), None)3031 return [32 f"{len(mine)} spans found for {run_id}" if mine else "run not found",33 f"first bad tool span: {first_bad(tools)}" if mine else "no spans",34 f"last model call: {last['turns']} turns" if last else "no spans",35 ]
  1. CallerSigned in as Dana Lee <dana.lee@example.com>. My order O-1004 says delivered but nothing…
    Show the result
    Signed in as Dana Lee <dana.lee@example.com>.
    
    My order O-1004 says delivered but nothing arrived. Where is it really?
  2. Agentcalls: get_order, get_shipping, get_shipping, get_shipping
    Show the result
    get_order, get_shipping, get_shipping, get_shipping
  3. Log7 spans; 7 carry the run id
    Show the result
    {"run_id": "run-3cfa9b1e", "name": "request"}
    {"run_id": "run-3cfa9b1e", "name": "model", "turns": 5, "cost_usd": 0.0004824450000000001}
    {"run_id": "run-3cfa9b1e", "name": "get_order", "tool": "get_order", "ms": 152, "status": "ok", "result": "{\"order_id\": \"O-1004\", \"item\": \"router\", \"status\": \"shipped\", \"name\": \"name#7f0f4eba\", \"email\": \"email#398efa8e\", \"phone\": \"phone#f5430c8c\", \"address\": \"address#b01dc2ed\"}"}
    {"run_id": "run-3cfa9b1e", "name": "get_shipping", "tool": "get_shipping", "ms": 165, "status": "error", "error": "carrier_timeout", "result": "{\"order_id\": \"O-1004\", \"error\": {\"category\": \"carrier_timeout\", \"retryable\": true}}"}
    {"run_id": "run-3cfa9b1e", "name": "get_shipping", "tool": "get_shipping", "ms": 162, "status": "error", "error": "carrier_timeout", "result": "{\"order_id\": \"O-1004\", \"error\": {\"category\": \"carrier_timeout\", \"retryable\": true}}"}
    {"run_id": "run-3cfa9b1e", "name": "get_shipping", "tool": "get_shipping", "ms": 161, "status": "error", "error": "carrier_timeout", "result": "{\"order_id\": \"O-1004\", \"error\": {\"category\": \"carrier_timeout\", \"retryable\": true}}"}
    {"run_id": "run-3cfa9b1e", "name": "answer"}
  4. Runbook7 spans found for run-3cfa9b1e
    Show the result
    7 spans found for run-3cfa9b1e
    first bad tool span: get_shipping: carrier_timeout
    last model call: 5 turns

The run was found, and the log holds no personal data.

Keep the trace useful

Derived metrics come from the spans, and this slow run shows one. Alert on p95 latency and on the error rate over a window, not on every error. A cost per run that rises while traffic is flat points at a step that grew.

A trace belongs to its feature. Review the metrics on a schedule, so drift shows up in days. When a feature is retired, retire its span writing and delete the old spans with it.

  1. CallerSigned in as Omar Reyes <omar.reyes@example.com>. Where is my order O-1005?
    Show the result
    Signed in as Omar Reyes <omar.reyes@example.com>.
    
    Where is my order O-1005?
  2. Agentcalls: get_order, get_shipping
    Show the result
    get_order, get_shipping
  3. Log5 spans; 5 carry the run id
    Show the result
    {"run_id": "run-39bfcff7", "name": "request"}
    {"run_id": "run-39bfcff7", "name": "model", "turns": 3, "cost_usd": 0.000185495}
    {"run_id": "run-39bfcff7", "name": "get_order", "tool": "get_order", "ms": 160, "status": "ok", "result": "{\"order_id\": \"O-1005\", \"item\": \"USB keyboard\", \"status\": \"shipped\", \"name\": \"name#030569dc\", \"email\": \"email#28f34466\", \"phone\": \"phone#fdd91029\", \"address\": \"address#07b02b54\"}"}
    {"run_id": "run-39bfcff7", "name": "get_shipping", "tool": "get_shipping", "ms": 4213, "status": "ok", "result": "{\"order_id\": \"O-1005\", \"status\": \"in transit\", \"carrier\": \"Parcelly\"}"}
    {"run_id": "run-39bfcff7", "name": "answer"}
  4. Runbook5 spans found for run-39bfcff7
    Show the result
    5 spans found for run-39bfcff7
    first bad tool span: get_shipping: 4213 ms
    last model call: 3 turns

The run was found, and the slow call raised the alert.

You doFix the starting code, then test yourself.

You do: tie each span to its run and hide personal data

Copy the starting code and open work/tracing/trace.py. span() writes every field, the prompt and email included, with no run id. redact() returns the text untouched.

Terminal
./workshop start tracing
./workshop check tracing
./workshop watch tracing

The checks want no email or personal value in a span, a run id on every span and no prompt or reply. The same value always gets the same tag, other text is left alone, and a slow call still raises the alert.

Check your understanding

Answer each question, then read why every option is right or wrong. The wrong options are the mistakes engineers make on the job.

1. A customer reports a wrong answer from the support agent and gives the time and the order number. The log holds 12,000 prompt lines from that hour, and none carries an id that ties a run's calls together. The on-call engineer has 20 minutes before the next escalation. What should the team add first?

  1. AA run id on every span, made once per run and passed to each call.
  2. BA longer retention period for the prompt lines, so nothing is lost.
  3. CSearch by order number for now, and add run ids when the log grows.
  4. DA second copy of each prompt line in another store.
Show the answer

Answer: A

  • A Correct. One id per run lets the engineer pull every span of that run in one query, whatever else is in the hour.
  • B Keeping the lines longer keeps the same 12,000 lines with no way to group them into one run.
  • C An order number can sit in many runs, and waiting means the same 20 minutes on the next report.
  • D A copy of a line with no run id is still a line with no run id.

2. An agent run writes one giant log line at the end, holding the prompt, every tool result and the reply. A slow run took 9 seconds, and finding which call was slow meant reading a 40 KB line by hand. The team wants the slow call to show up at once. What should it change?

  1. AWrite the line sooner in the run, so the log is fresher.
  2. BPrint the same 40 KB line with line breaks for readability.
  3. CWrite one span per model or tool call, each with its own timing.
  4. DAdd a flag to the line that says the run was slow.
Show the answer

Answer: C

  • A A fresher line is still one line, so the slow call stays hidden inside it.
  • B Line breaks make a debug print easier to read. A trace is a set of records that can be queried by call.
  • C Correct. With one span and one timing per call, the slow call is the span with the largest number.
  • D A flag says that a run was slow and not which call was, so the search goes on by hand.

3. A log store keeps every prompt for two years. A privacy review finds customer emails and phone numbers in 3,400 of the lines. The team may keep the logs for debugging but must stop holding those values in clear text. What is the right change?

  1. ARestrict the log store to two engineers and keep writing the same lines.
  2. BDelete the logs older than one year and keep the newer ones as they are.
  3. CAdd a banner to the log viewer that warns readers about personal data.
  4. DRedact the personal fields before a span is written, with a stable hash.
Show the answer

Answer: D

  • A Fewer readers still leaves the data in the store, and a breach of the store exposes it.
  • B The newer logs still hold the values, and the next year of lines will too.
  • C A warning is text for a person. It removes nothing from the store.
  • D Correct. Hashing before the write means the store never holds the value, and the same value keeps the same tag.

4. A design review lists the fields every span in the order status agent must carry. The team wants any span to be found in one query and read without opening the prompt. Select two fields that every span needs.

  1. AThe run id that ties it to its run.
  2. BThe full prompt, in case a reader needs it.
  3. CThe name of the call and its duration.
  4. DThe customer's email, to find their runs.
Show the answer

Answer: A, C

  • A Correct. Without the run id, a span cannot be grouped with the others from the same run.
  • B The prompt holds personal data and is large. A span keeps only the fields it needs.
  • C Correct. The name and the duration say which call it was and how long it took.
  • D An email in a span is personal data. The run id finds the run without it.

5. An alert pages the on-call engineer on every tool error, and the agent logs about 60 of them a day, mostly short carrier timeouts that retry and succeed. The team now ignores the pages. The goal is fewer pages that still catch a real outage. What fits?

  1. AMute the alert at night, when fewer customers are online.
  2. BSend each error to a chat channel as well as the page.
  3. CPage only when the error rate over a 10-minute window crosses a limit.
  4. DRaise the retry count so fewer errors are logged.
Show the answer

Answer: C

  • A Muting at night removes the page when an outage starts at night, and the day noise stays.
  • B A second channel carries the same 60 messages, so it adds noise and fixes nothing.
  • C Correct. A rate over a window comes from the spans, and it fires when errors climb, not when one call retries.
  • D More retries hide the errors in the log while the outage goes on.

6. After a release, the mean latency of the agent is flat at 1.1 seconds, yet customers say some answers take 10 seconds. The spans show 5 percent of tool calls now take over 8 seconds. The team needs an alert that would have caught this. Which metric should it read from the spans?

  1. AThe p95 latency of the spans, with a limit.
  2. BThe count of runs per hour.
  3. CThe mean latency, with a tighter limit.
  4. DThe size of the log files.
Show the answer

Answer: A

  • A Correct. One call in twenty being slow moves p95 while the mean barely moves, and p95 comes from the span timings.
  • B A run count says how busy the agent is. It says nothing about how long a call took.
  • C The mean stays near 1.1 seconds whatever limit is set, because most calls are fast.
  • D Log size grows with traffic and says nothing about how long a call took.

7. Cost per run rose 40 percent this week, from 0.005 to 0.007 dollars, while traffic stayed flat at 2,000 runs a day. Nothing in the error alerts changed. The team wants to know which step got more expensive. What should it do?

  1. AAsk the model provider for last week's invoice.
  2. BCut the answer length in the prompt and watch the total.
  3. CSwitch to a cheaper model for every call.
  4. DDerive cost per run from the model spans and compare steps week on week.
Show the answer

Answer: D

  • A An invoice gives a total for the week. It cannot say which step of which run changed.
  • B A guess changes one thing and may miss the step that grew, such as a third model turn.
  • C A cheaper model may fail the task, and the cost of the step that grew would stay hidden.
  • D Correct. Each model span carries its own cost, so a sum per run and a comparison by step find the change.

8. An on-call setup for the agent needs alerts that read from the spans and say something about users, not only about servers. The team has room for two. Select two metrics that come from the spans.

  1. ACPU use of the host.
  2. Bp95 latency per step.
  3. CThe number of engineers on call.
  4. DCost per run.
Show the answer

Answer: B, D

  • A CPU use is read from the host, not from a span, and it can be high with every answer fast.
  • B Correct. Each span has a duration and a name, so p95 per step is a query over the spans.
  • C Staffing is a rota, not a measure of how the agent ran.
  • D Correct. The model spans carry cost, so a sum per run is a query over the spans.

9. An on-call engineer receives a report that the agent told a customer the wrong thing at 14:05. There is no runbook, and the engineer starts by reading raw log text for the whole hour. Twenty minutes pass with no cause found. What order of checks should the team write down?

  1. AEdit the prompt, then test, then read the log.
  2. BFind the run by its id, then read the tool spans, then the last model call.
  3. CRestart the agent, then read the log if the fault returns.
  4. DRead the whole hour of logs from the first line.
Show the answer

Answer: B

  • A Editing first changes the prompt before anyone knows the fault is in it.
  • B Correct. The id finds the run, the tool spans show where a call failed, and the last model call shows what was said.
  • C A restart clears state and may remove the evidence, and the fault can return.
  • D A whole hour holds many runs, and the first line is unlikely to be the one that matters.

10. A wrong answer is reported, and the engineer on call starts to rewrite the system prompt. The run's spans show the get_shipping tool returned a carrier timeout, and the model then guessed a status from the order alone. The engineer has spent 30 minutes on the prompt. What should have come first?

  1. AAsk the customer for a screenshot of the answer.
  2. BSwitch the agent to a larger model before changing anything else.
  3. CFind the failing span and fix or handle that tool error.
  4. DAdd a line to the prompt that says to be accurate.
Show the answer

Answer: C

  • A A screenshot shows the answer, and the spans already hold the cause.
  • B A larger model given no shipping data would still have to guess.
  • C Correct. The fault is in a tool span, so the fix starts there, and the prompt may need no change at all.
  • D A line about accuracy cannot supply data a failed tool did not return.

11. Two engineers debug the same incident on Monday and each finds half the cause. Their notes are in two chat threads, and on Tuesday a third engineer repeats both checks. The team wants the next incident to start from shared steps. What should it keep?

  1. AA runbook with a first check, the next checks and an owner for each step.
  2. BA longer chat history, pinned for everyone to read.
  3. CA rota that puts the most senior engineer on every incident.
  4. DA weekly meeting to go over last week's incidents.
Show the answer

Answer: A

  • A Correct. The steps run in the same order each time, and an owner for each step stops two people doing the same check.
  • B A pinned thread holds the notes of one incident and gives no order of checks for the next one.
  • C One senior engineer is a single point of failure, and the steps stay in that person's head.
  • D A review helps the team learn, and it does not tell the engineer on call what to do at 02:00.

12. A platform review checks a triage runbook for the agent before it goes to the whole on-call rota. The runbook must work for an engineer who has never seen the agent. Select two parts the runbook must have.

  1. AThe first check to run, with what a good result looks like.
  2. BThe customer's email, so the engineer can call them.
  3. CA rule that hashing the customer's fields is optional when in a hurry.
  4. DThe owner of each step, so an engineer knows who to ask.
Show the answer

Answer: A, D

  • A Correct. A first check with a known good result tells the engineer at once whether to go on or stop.
  • B The runbook works from the run id. An email in it would be personal data in a document.
  • C Hashing is not optional, and a rush is when a leak is most likely.
  • D Correct. A named owner for each step means a stuck engineer knows who to ask.

13. A team chose a fixed workflow for an order status feature, then found that the next step depends on what each tool returns. The spans of 50 runs show the path branches in four different ways. The team wants to decide whether an agent fits better. What should it use?

  1. AA vote among the engineers on which design feels cleaner.
  2. BThe prompt length as a measure of how complex the task is.
  3. CThe number of tools the feature holds as a proxy for branching.
  4. DThe spans, to count how often and where the path branches.
Show the answer

Answer: D

  • A A vote gives a preference. The spans hold 50 runs of evidence about the path.
  • B A long prompt can drive a fixed path, and a short one can drive a branching path.
  • C Two tools can branch many ways, and ten can run in a fixed order.
  • D Correct. The spans show each call in order, so the branch points can be counted where they happen.

14. An agent chooses its own tools, so the path it takes cannot be predicted from the code. A customer disputes an answer, and the team must show what the agent did step by step. Only a trace can answer that. What must be true of the trace?

  1. AIt was switched on after the dispute, for the next run.
  2. BIt holds only the final reply, to keep the log small.
  3. CEvery model and tool call is a span under the run id, so the path can be replayed.
  4. DIt holds the prompts in clear text, so the wording is exact.
Show the answer

Answer: C

  • A A trace switched on after the dispute has nothing about the run in question.
  • B A final reply says what was answered and not how, so the path is lost.
  • C Correct. With one span per call under one id, the path can be read in order, however the agent chose it.
  • D Clear text adds personal data and is not needed to show the path.

15. The order status agent has run in production for six months, and its spans are stored and never read. Last week a slow tool went unnoticed for 9 days until a customer complained. The team wants to catch drift sooner. What should it schedule?

  1. AA regular review of the span metrics, such as p95 latency and cost per run.
  2. BA yearly rewrite of the system prompt from scratch.
  3. CA larger log store, so spans can be kept for longer.
  4. DA rule that any engineer may mute alerts they find noisy.
Show the answer

Answer: A

  • A Correct. A review of the derived metrics on a schedule shows a slow tool in days, before a customer does.
  • B A rewrite changes the prompt and leaves a slow tool where it was.
  • C Keeping more spans that nobody reads adds cost and does not show drift.
  • D Muting alerts hides drift. It does not look for it.

16. A feature that used the agent was retired in March, yet its code still writes 15,000 spans a day. The log store grows by 2 GB a week, and nobody reads those spans. The team wants to stop paying for them. What is the right move?

  1. ACompress the old spans and leave the writer running.
  2. BRaise the alert limit so the feature stops showing up.
  3. CSample one span in ten and keep writing the rest.
  4. DRemove the span writing together with the feature, and delete its old spans.
Show the answer

Answer: D

  • A Compression shrinks the cost and leaves a writer for a feature nobody uses.
  • B An alert limit has nothing to do with storage, so the growth goes on.
  • C Sampling keeps writing spans for a retired feature, at a tenth of the cost.
  • D Correct. Logging belongs to the feature, and when the feature is retired the writer and its old spans go too.

Play: predict the output

This redact step hides phone numbers by their shape.

python
PHONE = re.compile(r"\b\d{3}-\d{4}\b")
redact("Call me on 020 7946 0958 after six.")

Predict: Does the phone number reach the log?

  1. AYes. The pattern wants three digits, a dash and four digits, so it misses this one.
  2. BNo. The pattern finds the digits and replaces them.
Show the answer

A. A pattern catches only the formats someone thought of. Keep spans to an allowlist of fields, so free text never reaches the log, and test redaction on real samples.

References

Conclusions

  • Give every span the run id, a name and only the fields it needs, so a run is found in one query.
  • Hash personal data before it is written, with a stable tag, and drop the prompt.
  • Alert on a metric derived from the spans, and triage from the run id to the failing span.

You can now make an agent's log find its run and keep personal data out of it.

Run id

One id shared by every span of one run

Span

One structured record for one model or tool call

Redaction

Hashing personal data before it is written

p95 latency

The time that 95 percent of calls beat

Runbook

The ordered checks for an incident, each with an owner