Single Prompt drifting at 9 custom functions. Is a thin Conversation Flow the right move for a booking agent?

Hi all, I’m building an outbound booking agent for UK estate agencies. It calls back web enquiries, verifies the property address, offers appointment slots from a real calendar, books, and sends an SMS confirmation. It’s a Single Prompt agent right now, about 2.5k tokens with 9 custom functions. All the actual logic is server side, the functions return facts and the agent’s job is to speak them.

I read the recent Single Prompt vs Conversational Agent thread and it matches my experience. I’m past the “1,000 words or 5+ functions” point people mention in there, and I’m seeing exactly the drift that gets described: the model calling a write tool off the wrong kind of user input.

Concrete example from testing last night. The caller says “I’m pretty sure you already booked me in” (they weren’t). That’s a mistaken belief the agent should correct, not a booking request. Instead it called book_appointment and created a real appointment at a time the caller never picked. I’ve been patching this kind of thing in tool descriptions, and yesterday I hit the 1024 character limit on descriptions while trying to squeeze the consent rules in. At that point it feels like I’m fighting the architecture instead of building.

What I’m considering is a thin Conversation Flow: around 15 nodes, topology only, all logic stays in my backend. Fixed nodes for the address read back and the booking confirmation, free dialogue nodes everywhere the conversation needs to sound human. Before I commit I have four questions for anyone running Conversation Flow in production:

  1. Does tools.response_variables reliably interpolate into static text node speech? I’ve confirmed the field exists at schema level but the docs don’t cover rendering into node speech. This matters a lot for me, a scripted confirmation that can only speak values my server returned is the main reason to switch.

  2. What’s the current status of the static text getting skipped bug (#3394)? A confirmation node that silently doesn’t speak would recreate the exact problem I’m trying to get away from.

  3. What latency difference are people actually seeing between flow and single prompt with function heavy agents? I’m at roughly 500-800ms LLM p50 today and can’t afford much regression on a live phone call.

  4. How are you consent gating state changing tools? Is a dedicated confirmation node before the booking function the reliable pattern, rather than ever longer tool descriptions? And any multi tenant gotchas with one shared flow plus dynamic variables set at dial time?

I’ve ruled out Flex Mode for this since the docs say it compiles the flow back into a single prompt, which loses the runtime guarantees I’d be switching for in the first place.

Would appreciate any production experiences, especially from anyone who migrated a booking type agent and can say what broke.

Hello @Raul

Response variables from Function, Code, or MCP nodes are stored as dynamic variables using the {{variable_name}} syntax. These variables can be referenced in prompts and begin messages. A reliable approach is to use a Function Node with wait_for_result: on, followed by a Conversation Node that references {{your_variable}} in its prompt to communicate the function’s result to the user. For appointment booking, the recommended pattern is to use a Conversation Node to collect and verbally confirm the user’s details before transitioning to a book_appointment Function Node. Since the Function Node executes deterministically when the flow reaches it, the booking only occurs after the user has confirmed the details. It’s also recommended to avoid attaching too many tools to a single subagent node, as increasing the number of available tools makes it more likely that the LLM selects the wrong one. For multi-tenant implementations, dynamic variables set at dial time using retell_llm_dynamic_variables are fully supported and can also be used in function URLs, such as https://api.example.com/{{tenant_id}``}/book. The overall flow is: Conversation Node (confirm details) → Function Node (book_appointment with wait_for_result: on) → Conversation Node (announce the result using {{booking_ref}}).

Thanks Shah, that’s really helpful, especially the confirmation node before the function node. That solves the exact consent problem I posted about.

Two things you didn’t touch on that would settle this for me:

  1. Is the static text never spoken issue still around, or is setting interruption sensitivity to 0 on those nodes the recommended workaround? This is the one I mean: Conversation node's static_text instruction never spoken — else edge fires ~3s after node entry And related, if a caller talks over a sensitivity 0 node, does their speech still come through as a turn afterwards? I need an opt out shouted over the opening disclosure to still be heard.

  2. Roughly what latency difference should I expect per turn moving from single prompt to a flow with the same functions? I’m at about 500-800ms LLM p50 today and a phone call doesn’t leave much headroom.