← Back to projects

Case study

Quote-Intake Agent

An AI intake agent for a home-services contractor. It reads inbound quote requests, routes them, and drafts replies for a dispatcher to approve, without ever stating a price, promising an arrival time, or missing a gas leak.

TypeScript, Node.js, Claude Opus 5.5 with structured outputs, Zod · View on GitHub

Held-out routes correct
20/20
Held-out safety cases escalated
4/4
Injected model mistakes kept from the customer
232/232
Dev-set routes correct
43/43

The problem

A trades business gets quote requests as run-on texts and emails: “furnace, 15 years old, 14615, faint gas smell.” Someone has to work out what the job is, what's missing, whether it's an emergency, and reply quickly. A language model is good at the reading and the writing. It shouldn't be the last line of defense on what a job costs or whether a customer should leave the house. The business is a fictional Rochester heating, plumbing and electrical company with its own price book, service area and policies.

The design: the model reads and writes, code decides

The agent makes one structured-output call to Claude, then passes the result through guardrails written in plain code before a dispatcher sees the draft.

DecisionMade by
What the customer wants, and drafting the replyClaude, constrained to a JSON schema
Route (safety, urgent, human, decline, ask, estimate)Code: priority order is policy, not judgment
PricesThe price book, inserted by code. The model never writes a dollar figure
What information is still missingThe price book's requirements for each service
HazardsKeyword rules that override the model, plus the model's own flag
ZIPs, phone numbers, photos, equipment ageDiscarded unless they appear in the customer's text
Model refused, errored or returned bad JSONFails closed to a person
SendingA person. Every reply is a draft

How I measured it

What the evals caught

Limits and next steps

Get in touch if you'd like to talk through how I'd build something like this for your team.