Chapter DCapstone: support bot with RAG + toolsPage 4 of 8

Capstone: support bot with RAG + tools

Prove behavior with deterministic tests

Build a support API that retrieves versioned policy, reads live order state through a scoped tool, and returns a cited answer or human escalation as an operable release, not a slide-deck example.

~18 minValidation

1Try it yourself

Playground

Support bot: RAG + tool

Retrieve policy text, optionally fetch live order status, then answer with citations.

User: Can I refund order #8821 on my annual plan?

  1. Retrieve FAQ chunk
  2. Call order lookup tool
  3. Generate cited reply

Before you start

Why this matters

Before changing code, write the single production outcome this chapter must prove and the signal that would stop you. For this lab, the service boundary is SupportRequest(user_id, message) produces Answer(text, citations, order_facts, escalation) with every claim attributable to policy or tool output. Record one request identifier you can follow from ingress through the final decision. If you cannot name the owner of the stop decision, the rollout is not yet controlled.

The source architecture is retrieve policy, call a live-data tool, produce a cited reply, and escalate on no-match, anger, or fraud. This chapter turns that compact lesson into implementation evidence. The running scenario is a support API that retrieves versioned policy, reads live order state through a scoped tool, and returns a cited answer or human escalation. You will keep the same scenario across all eight chapters so setup decisions, tests, telemetry, and rollback controls accumulate into one coherent system rather than eight disconnected exercises.

2Learn the idea

Read

Build a layered test suite

Start with pure unit tests for deterministic decisions: schema checks, bucketing or routing, threshold comparisons, and redaction. Use fixed clocks and seeded identifiers. Then add contract tests against every fake dependency and one sandbox integration. Finally, run an end-to-end fixture through the public endpoint and assert the durable record and telemetry event, not just the HTTP response.

Turn the declared boundary into test cases. A valid request produces SupportRequest(user_id, message) produces Answer(text, citations, order_facts, escalation) with every claim attributable to policy or tool output. Missing required fields return a stable client error. Unknown schema versions are quarantined or rejected. Authorization failure occurs before external calls. A repeated identifier cannot duplicate effects. A timeout returns the documented degraded response. Every branch carries the revision and request ID.

Read

Test the decision metrics

For AI quality, keep a versioned JSONL golden set with input, permitted facts, forbidden claims, and expected disposition. Grade citations or fact support deterministically where possible; use a model grader only with a pinned grader prompt and periodic human calibration. Report confidence intervals and case-level failures, not one blended score. The release metric is task resolution, citation correctness, tool authorization failures, escalation precision, p95 latency, and cost per resolved conversation.

Add an adversarial set specifically for missing policy, stale chunks, tool timeout, prompt injection in retrieved text, order ownership mismatch, and a model inventing an irreversible action. Each fixture needs a short explanation of the production incident it prevents. This stops the suite becoming a pile of examples nobody trusts. When a real incident occurs, first add the smallest reproducing fixture, then fix the implementation.

Read

Encode gates

CI should reject schema drift, unsafe configuration, failed deterministic tests, and quality regression beyond the declared tolerance. A flaky quality check is not permission to ignore failures. Quarantine it with an owner and deadline while preserving a stable blocking subset. Print revisions, seed, and dataset digest so any failure can be reproduced locally.

Create a rollout-gate function that accepts observed metrics and returns promote, hold, or rollback plus reasons. Test boundary values: exactly at threshold, one sample below minimum, stale metrics, and missing guardrails. Missing or stale evidence must return hold. This small function prevents a deployment script from silently interpreting policy differently from the runbook.

Read

Review the evidence

Have another person run the acceptance command without verbal guidance. They should be able to locate the failed fixture, identify its owning component, and explain whether it blocks shipment. Save a concise test report containing counts, failures, dataset digest, and environment. Tests become release evidence only when their inputs and meaning are reviewable.

Read

Run a reproducible contract probe

Store a fixture with the local test harness so the grounded support workflow decision is reviewable rather than hidden in a mock. Pinning the revision and thresholds prevents a later environment change from silently changing what “pass” means.

capstone_support_bot_contract:
  conversation_id: conv_test_104
  user_id: user_fixture_9
  order_id: order_fixture_21
  policy_version: returns-2026-06
  expected_disposition: human_escalation
  forbidden_action: issue_refund

Run the same fixture unchanged and with one guardrail deliberately violated. The expected transcript makes the gate repeatable by a teammate who was not present when it was authored.

$ python3 -m pytest -q -k "capstone_support_bot and contract"
2 passed in 0.41s
$ CONTRACT_REVISION=support-bot-v4 python3 -m pytest -q -k "rejects_stale_evidence"
1 passed in 0.18s

Expected output is a stable pass count plus support-bot-v4 in the report. If another revision appears, inspect fixture loading and environment precedence before changing thresholds. If stale evidence promotes instead of holding, stop: the gate is unsafe even if quality checks pass. Preserve the seed and failing fixture so the result can be reproduced without production traffic.

Checking tutor…

Continue learning · glossary & guides