Predictable Like a Good API Should Be
LLM-powered voice bots have a dirty secret: you never know exactly what they'll say next.
For a demo, that's fine. Impressive, even. The model improvises, it sounds natural, it says something unexpectedly clever, and everyone in the room is delighted. The demo gets booked.
Then the regulated industry customer asks: "Can we see the audit trail for what the bot said on each call?" And the answer is: "We have a recording." And they say: "Can we verify that the bot followed our disclosure script?" And the answer starts to get complicated.
The Auditability Gap
Prompt-based voice bots have an architectural auditability problem. If your bot's behavior is encoded as prose instructions to a language model, then what the bot actually does on any given call is the intersection of: your instructions, the model's training, the specific words the user happened to say, and whatever stochastic decisions the model made during generation.
You cannot point to your codebase and say "the bot will always do X before hanging up." You can point to a prompt that says "always do X before hanging up" and hope the model complies. In practice, for most tasks and most models, it does. But "in practice, usually" is not a compliance posture you can take to a regulator.
This isn't a hypothetical problem. In financial services, consumer lending regulations require specific disclosures at specific points in a conversation. In healthcare, informed consent processes have legally mandated steps. In insurance, claim acknowledgments have required language. None of these are compatible with "the LLM will probably say the right thing."
The Checklist as an Audit Log
Guava's checklist architecture inverts this relationship. Instead of instructions that the model interprets, the checklist is a structured execution plan that Guava steps through deterministically.
Here's a loan application intake bot:
import guava
from my_lending_platform import save_application, check_eligibilityclass LoanIntakeBot(guava.CallController): def __init__(self, campaign_id: str): super().__init__() self.campaign_id = campaign_id
self.set_persona( organization_name="Meridian Lending", agent_name="Jordan", ) self.set_task( objective="Collect a complete loan application from the caller", checklist=[ guava.Say( "Before we begin, I want to let you know that this call may be " "recorded for quality and compliance purposes. By continuing, " "you consent to this recording." ), guava.Field( key="consent_confirmed", field_type="boolean", description="Confirm the caller consents to continue", ), guava.Field( key="full_name", field_type="text", description="Caller's full legal name", ), guava.Field( key="ssn_last_four", field_type="digits", description="Last four digits of Social Security Number", digit_count=4, ), guava.Field( key="annual_income", field_type="currency", description="Caller's stated annual income before taxes", ), guava.Field( key="loan_purpose", field_type="enum", description="Purpose of the requested loan", choices=["Home improvement", "Debt consolidation", "Auto purchase", "Other"], ), guava.Field( key="loan_amount", field_type="currency", description="Requested loan amount", ), guava.Say( "Thank you. I'm required to inform you that submitting this " "application does not guarantee approval, and a hard credit inquiry " "may be performed as part of the review process." ), "Summarize the application details and confirm the caller wants to submit.", guava.Field( key="submission_confirmed", field_type="boolean", description="Caller confirms they want to submit the application", ), ], on_complete=self.submit_application, )
def submit_application(self, result): if result.get("submission_confirmed"): save_application(result, campaign_id=self.campaign_id) self.end_call() ```
Notice what's auditable here. The two guava.Say(...) items — the consent disclosure and the credit inquiry notice — are guaranteed to be communicated. Not "probably communicated" or "communicated unless the user interrupted." They are items in a structured execution plan that Guava will complete before moving to the next step.
Typed Fields, Typed Data
The other half of predictability is the output. When a Field completes, Guava returns a value in the declared type — currency returns a Decimal, digits returns a validated string, boolean returns True or False. The on_complete handler receives a typed dictionary.
This matters because when you call save_application(result, ...), you're not parsing free-form LLM output. You're working with structured data that Guava extracted and validated. If the user said "around forty thousand dollars," annual_income is Decimal("40000.00"). If they said "fifty to sixty thousand," Guava asks a clarifying question before populating the field.
What This Buys You
Predictable voice AI is not about removing the LLM. The LLM is doing enormous work in Guava — managing conversation state, reformulating questions naturally, handling interruptions, recovering from misunderstandings. We're not constraining it out of existence.
What we're doing is giving the LLM a job description instead of a general mandate. Its job is to execute the checklist, naturally and conversationally. What it is not authorized to do is skip steps, invent disclosures, or complete the call without hitting on_complete.
For teams building in regulated industries, this is the difference between a voice bot that can be deployed and one that can't. For teams building anywhere, it's the difference between a system you can reason about and one you can only observe.