Industry context
HVAC, plumbing, and broader home-services operations.
Case Study
A retrieval-based copilot designed to improve how service reps qualify, price, and book inbound calls under live operational constraints.
The work focused on a recurring operational failure: similar calls were producing different booking outcomes depending on who answered. The system was designed to make changing business rules usable in real time, reduce supervisor dependency, and carry cleaner decisions from intake into scheduling and dispatch.
72% → 92% inbound close rate
HVAC / plumbing intake operations
Shipped as a production CSR workflow

On This Page
Context
Context
In HVAC and plumbing operations, inbound calls are the primary source of revenue. Service reps are responsible for converting those calls into booked jobs while capturing the information needed for scheduling and dispatch. When those decisions are inconsistent, revenue is lost at intake, and the impact carries into scheduling inefficiencies and operational friction.
Industry context
HVAC, plumbing, and broader home-services operations.
Operational setting
Customer intake, booking, dispatch, and routing.
What was at stake
Revenue capture, team coordination, scheduling efficiency, and consistent execution.
Problem
Inbound calls were a major source of revenue, but service reps were not consistently asking the right questions or making the right booking decisions. Important details were often missed during the call, including questions needed to diagnose urgency, qualify the customer, and determine whether the job should be booked immediately. As a result, similar calls could lead to very different outcomes depending on who answered.
Service reps were not consistently asking the questions needed to qualify urgency, job value, and booking fit. As a result, important signals were missed during the call, and high-quality opportunities were not recognized early enough to be converted.
Core booking judgment lived in undocumented habits, supervisor memory, and informal guidance rather than in a consistent process. That made booking quality depend on tenure instead of the workflow itself.
Routine service and pricing questions kept escalating because the workflow did not give reps enough guidance to resolve them during the call. Leadership time was pulled into repetitive support work that should have been handled inside the system.
Weak intake decisions pushed the wrong jobs into the schedule, missed urgency, and left same-day value on the table before dispatch could correct it. That reduced conversion early and created avoidable cleanup for routing and coordination later.
The core problem was not conversation quality alone. It was that critical booking judgment depended on incomplete knowledge, inconsistent habits, and constant escalation. That made revenue capture unreliable and pushed avoidable friction into the rest of the operation.
Challenges
Improving booking decisions required more than better answers. The system had to operate inside a live call workflow, reflect changing business rules, and avoid creating more drag for intake, scheduling, and routing teams.
Key decision logic such as urgency tiers, membership handling, pricing expectations, and service availability existed, but was not consistently defined. Different sources such as the website, supervisors, and service reps often disagreed, which created confusion during intake and led to inconsistent booking decisions.
Promotions and pricing changed frequently, but there was no reliable way to keep the team aligned. Service reps relied on word of mouth or asked supervisors for clarification, which made it difficult to trust the information they were using during live calls.
Reps had to make fast decisions while handling live customer conversations. Introducing new workflows or tools risked slowing them down, and many defaulted to existing habits instead of consistently applying new guidance.
Even when a job was booked, decisions made at intake could negatively affect downstream operations. Assigning the wrong technician or failing to consider routing implications led to inefficient scheduling and increased fuel costs, directly reducing profitability.
Approach
The focus was to fix how booking decisions were made during live calls. Instead of relying on memory, scripts, or supervisor escalation, I led the effort to capture how the business actually qualified leads, prioritized work, and decided when to book. Most of this logic was not documented. It existed as tribal knowledge, which is why reps were asking the wrong questions, escalating basic decisions, and missing booking opportunities.
I led stakeholder interviews to capture how experienced operators actually made intake decisions, including urgency tiers, membership handling, pricing expectations, and booking criteria.
This turned inconsistent, experience-based judgment into defined operating rules.
I translated those rules into focused markdown knowledge documents, each encoding a specific decision framework.
This created a consistent, queryable source of truth instead of fragmented tribal knowledge.
I uploaded the documents into a vector store using the OpenAI Agents SDK, enabling the system to retrieve relevant SOPs dynamically during intake.
This ensured reps could access up-to-date decision logic without relying on memory or supervisor input.
I implemented a chat-based agent that reps could query in real time during calls.
The agent retrieves relevant guidance, answers workflow and pricing questions, and helps reps move toward the correct booking decision without interrupting the flow of the conversation.
System Design
The design goal was to make changing business rules usable during live customer calls. The system had to retrieve current policy in real time, improve booking decisions without slowing the conversation, reduce dependence on memory or supervisor escalation, and stay trustworthy under production conditions.
Asks a pricing, membership, or booking question during a live call.
Next.jsSSE streaming
Chat embedded in the intake workflow — answers stream in so reps can act on partial output.
OpenAI Agents SDK
Governed agent behavior with retrieval enforced for pricing, membership, and policy questions.
Vector storeFile search
Fetches the SOP chunks relevant to the caller's situation.
Markdown SOPs
Stakeholder-derived decision rules: urgency tiers, membership handling, pricing boundaries, booking criteria.
A direct answer plus the next best question or booking action.
PostgreSQL
Reps flag incorrect responses with corrections; reviewed feedback updates the knowledge base.
Framing
Service reps needed support while they were still on the call. The system had to make current business rules retrievable in real time, improve booking decisions without slowing the conversation, reduce dependence on memory or supervisor escalation, and return useful guidance fast enough to keep the rep in flow.
The problem was not where to store knowledge. The problem was making changing, inconsistent business rules usable at the exact moment a rep had to decide whether to book, how to price, and what to ask next. The system needed to support a decision, not just return an answer or expose a document search box.
System Model
The architecture was organized around six responsibilities so operational judgment could move from stakeholder knowledge to usable guidance during intake. Each layer existed because the workflow had to work under live-call constraints, not because the stack needed more moving parts.
The source layer captured the business rules that already governed intake decisions: urgency tiers, membership rules, pricing expectations, booking criteria, and service availability logic. Those rules existed before the product, but they were split across supervisors, service reps, and the public website, and those sources did not always agree.
Why it exists
This layer exists because the business already had real decision logic. The system first had to identify which source reflected operational reality before any automation could be trusted.
Constraint / Tradeoff
Source capture favored how the operation actually worked over what older documentation claimed. That made stakeholder interviews and cross-checking necessary before the rules could be treated as system input.
The extracted rules were translated into focused markdown knowledge documents, with each document encoding a specific decision framework such as same-day qualification, membership handling, pricing boundaries, or booking fit. The goal was not documentation for its own sake. The goal was retrieval-ready knowledge that could be used under intake conditions.
Why it exists
This layer exists because uploading loose notes or transcripts would not produce reliable runtime guidance. The knowledge had to be structured around the decisions reps actually make on calls.
Constraint / Tradeoff
Preparation added authoring discipline up front, but it created a consistent source of truth instead of leaving the system to infer meaning from fragmented tribal knowledge.
The prepared markdown documents were uploaded into a vector store through the OpenAI Agents SDK using its file search tool, which handled chunking and vectorization for retrieval. During intake, retrieval was invoked dynamically by the agent based on the call context, and the system prompt explicitly required retrieval for sensitive categories such as pricing, membership, and policy. That made retrieval part of the control strategy, not an optional lookup path.
Why it exists
This layer existed because reps needed fast access to current policy while the call was in progress, and the system needed a reliable way to ground answers before responding. Retrieval reduced the risk of hallucinated pricing or policy guidance and kept the interaction aligned with current operating rules.
Constraint / Tradeoff
Retrieval is probabilistic, so document structure, file organization, and prompt boundaries mattered. The design traded hard-coded rigidity for a system that could adapt as rules changed without rebuilding application logic, while still enforcing retrieval-first behavior where mistakes would be costly.
The agent was designed as a governed copilot rather than a free-form assistant. It was reactive to CSR input through chat, but proactive in guiding workflow decisions. It used retrieved context plus structured system instructions to answer the rep's question, identify missing context, and suggest the next best question or booking action. Response formats varied by question type, including service issue questions, operational questions, and knowledge-gap cases.
Why it exists
This layer existed because intake decisions depend on workflow judgment. The rep needed help determining what to do next, not only which paragraph to read or which document matched the query.
Constraint / Tradeoff
The reasoning model stayed retrieval-based and prompt-governed instead of becoming a rigid state machine. That preserved flexibility for messy real calls, but it required structured response protocols, safety rules, and output constraints in the system prompt so the agent stayed controlled under varied call conditions.
Service reps interacted with the system through a chat-based copilot embedded in the intake workflow. They could ask customer-specific questions, pricing questions, membership questions, and workflow or booking questions during the live call. The agent returned direct answers, relevant policy context, and suggested next steps or intake questions without requiring the rep to leave the workflow or follow a rigid scripted path.
Why it exists
This layer existed because any tool that slowed the conversation or forced context switching would be ignored during intake. The interface had to fit the pace of the call, not ask reps to stop and navigate a different system.
Constraint / Tradeoff
A chat-based surface is less explicit than a dedicated workflow application, but it was faster to adopt under live-call conditions, easier to fit into current operations, and left room to expand toward scheduling and dispatch support later.
The feedback loop was implemented as part of the production system. Reps could downvote incorrect responses with a dislike button, record what was wrong, and submit the correct answer. That feedback was stored in a PostgreSQL table for review so frontline errors could be used to update the knowledge base and improve system accuracy.
Why it exists
This layer existed because business rules do not stay still and trust depends on correction. A static knowledge base would drift out of date and quickly lose credibility with the team using it.
Constraint / Tradeoff
The system required ongoing review and refinement rather than a one-time setup. That added operational ownership, but it created a direct path from production mistakes to system improvements and supported later scheduling and dispatch extensions.
Why This Design
The architecture was chosen to support live intake decisions under changing business rules and real-time call constraints. Simpler alternatives could store information, but they would not make the right knowledge usable quickly enough, consistently enough, or close enough to the workflow to change booking behavior.
Static scripts
Scripts can standardize a conversation, but they do not adapt well to changing promotions, pricing exceptions, or edge cases. They also do not help a rep decide what to do when the call falls outside the script.
Training alone
Training improves baseline knowledge, but it does not scale judgment under live-call pressure. It also decays quickly when policy changes faster than teams can be retrained.
Disconnected chatbot
A generic chatbot can answer questions, but it does not reliably guide booking decisions if it sits outside the intake workflow or if retrieval is left optional. The product needed governed workflow support, not a separate assistant window.
Manual searchable knowledge base
Searchable documentation helps after the fact, but it is too slow and too dependent on the rep knowing what to search for. That is not enough during a live call where the next question matters immediately.
Constraints And Tradeoffs
The design was shaped by operational constraints, not by a preference for architectural complexity. Each tradeoff came from what had to work during live calls, what had to stay trustworthy under changing policy, and what could realistically be maintained by the business over time.
Business rules were inconsistent across supervisors, reps, and the website, so the system had to reconcile operational reality before it could automate anything.
Promotions and pricing changed monthly, which meant retrieval needed to depend on updateable knowledge rather than hard-coded policy.
Reps operated under time pressure, so guidance had to be useful in seconds and could not slow the call down.
Near-instant feedback was required during live calls, so latency was treated as a product constraint rather than a later optimization.
Pricing, membership, and policy answers could not be hallucinated, so the system prompt enforced retrieval for those categories before the agent responded.
Teams relied on habit and supervisor escalation, which meant the system had to be easier to trust than asking someone nearby.
Scheduling and dispatch integration were future-state, so the current design had to improve intake first while leaving room for routing-aware guidance later.
The guidance had to support judgment without pretending the workflow could be reduced to a single rigid decision tree, which is why prompt-governed behavior was chosen over a brittle hard-coded state machine.
Response streaming was implemented with server-sent events so reps could act on partial output without waiting for the entire answer to complete.
Runtime Behavior
At runtime, the system is simple from the rep's perspective. The complexity stays behind the interface so the call can keep moving and the rep can act on partial guidance as soon as it begins streaming.
Rep asks a live intake question
A rep asks about pricing, membership, service eligibility, or whether a call should be booked now, escalated, or qualified further.
The agent invokes retrieval against the vector store
The agent uses the vector-store-backed file search tool to retrieve the most relevant SOP chunks for that situation, especially when the question touches pricing, membership, or policy.
The agent returns a structured response
The response streams back as a structured answer: a direct answer, clarification if more context is needed, and the next best question or action so the booking decision improves, not just the information lookup.
The rep continues the call without escalating
The rep stays in the conversation, asks the missing follow-up, and makes the booking choice with more confidence and less need for supervisor intervention.
The intake outcome improves downstream execution
A better-qualified booking carries cleaner context forward, which reduces later cleanup for scheduling, dispatch, and routing.
Architecture Summary
What the design enabled
More consistent access to current business rules during live calls.
Less dependence on undocumented supervisor knowledge and rep memory.
Better guidance at the point where booking quality is actually decided.
A knowledge system that can evolve as pricing, promotions, and service rules change.
A foundation for deeper scheduling, dispatch, and routing support later.
What Was Built
The delivery covered the interface CSRs use, the workflow behavior behind it, and the logic needed to keep live guidance grounded in real operating rules.
01
A CSR-facing workspace for live calls, with structured intake, captured context, grounded answers, and visible booking guidance in one place.
02
A call flow that preserves state across intake, qualification, pricing questions, and booking decisions so the conversation does not restart at each step.
03
Retrieval-backed service rules, pricing and warranty boundaries, session memory, and orchestration that turn business policy into usable guidance during the call.
Implementation Detail
Embedded guidance directly into the CSR workflow instead of relying on a separate assistant window.
Surfaced booking and dispatch considerations at the moment the CSR needed them, not after the call.
Connected live call context to policy retrieval and session continuity so recommendations stayed grounded as the conversation evolved.
Structured the system so routing and dispatch implications could be reflected earlier in booking decisions.
Outcomes
After deployment, the inbound close rate rose from 72% to 92% as booking decisions became consistent across reps and shifts. The downstream effects showed up across the intake-to-dispatch workflow.
The inbound close rate improved from 72% to 92% once qualification, pricing, and booking guidance were grounded in the same retrieval-backed rules for every rep.
Booking decisions became more consistent across similar calls because urgency, fit, and policy context were surfaced inside the workflow.
Less of the team's judgment had to live in tribal knowledge or real-time supervision.
Urgent and higher-value work became easier to identify before it disappeared into the general queue.
Booking, dispatch, and routing stayed better aligned because the system carried cleaner operational context forward.
Manual coordination dropped when downstream teams no longer had to reconstruct missing context from intake.
The main value was not that the system answered questions faster. It made the work itself easier to execute with fewer weak handoffs.
What This Demonstrates
This work required identifying the real operational problem quickly, choosing where automation belonged, and translating scattered workflow judgment into a system people could use under live conditions.
01
Ambiguous workflow problems were turned into clearer product boundaries and implementation priorities.
02
Product decisions, system design, and delivery were tied to the same operational objective instead of treated as separate tracks.
03
Execution risk came down because the solution was grounded in how booking, dispatch, and routing actually work.