I’m seeing an agent call tools out of order. Setup...
# ask-ai
d
I’m seeing an agent call tools out of order. Setup: LiveKit Agents Python, inference.LLM (OpenAI + Gemini fallback), tools: get_instructions_tool, transfer_to_live_agent. Issue: When user says “I want to speak to a human,” the model calls get_instructions_tool then immediately calls transfer_to_live_agent in the same turn, before collecting call reason/name/phone whereas it's clearly instructed to follow these steps
t
Thanks for reaching out, Tejas. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I hear you: your agent is calling
get_instructions_tool
and then immediately
transfer_to_live_agent
in the same turn, skipping the required data-collection steps (call reason / name / phone). I’ll walk through why that happens and give actionable fixes you can apply. Why this happens • The model can decide to call multiple tools in a single turn when the LLM integration allows parallel tool calls. If
parallel_tool_calls
is enabled, the model may try to invoke both tools concurrently instead of following your intended sequence. • LLMs sometimes attempt a best-effort handoff if a transfer tool is available, so without protections the model can jump to
transfer_to_live_agent
even when required fields are missing. Practical fixes you can apply 1. Disable parallel tool calls (if configurable) ◦ Turn off
parallel_tool_calls
for your OpenAI/Gemini integration so the model is constrained to one tool call per turn. This prevents simultaneous invocations and makes ordering more predictable. ◦ If you cannot disable it globally, disable it for the agent profile or request pipeline that handles handoffs. 1. Make
transfer_to_live_agent
require preconditions ◦ Have the
transfer_to_live_agent
tool check session state (
userdata
or
RunContext
) before performing the transfer. ◦ If required fields (call reason, name, phone) are missing, return a structured response that: ▪︎ Explains which fields are missing, and ▪︎ Prompts the user to provide them (do not perform the transfer). ◦ Only execute the actual transfer when all required data are present. 1. Track collection with session state ◦ Use
userdata
(or the session context mechanism you already use) to store flags like
has_name
,
has_phone
,
call_reason_collected
. ◦ Tools and the agent’s instruction template should read/write these flags so both model and tools share the same truth about progress. 1. Encapsulate collection in a Task ◦ Create a
CollectUserInfoTask
or similar
AgentTask
that owns the flow of asking for and validating name/phone/reason. A task takes control of the session until its goal is achieved, which forces step-by-step completion before the handoff is allowed. ◦ Only allow the
transfer_to_live_agent
to be callable after the task marks completion. 1. Make tool responses explicit and structured ◦ Return deterministic, short outputs from
get_instructions_tool
(e.g., JSON or a labeled response) so the LLM can’t infer that a transfer should happen immediately. ◦ Example:
get_instructions_tool
returns {"instructions_collected": true, "next":"ask_for_name"} — this reduces ambiguity and improves the model’s decision-making. Quick checklist to implement 1. Check and disable
parallel_tool_calls
in your LLM plugin/configuration. 2. Add precondition checks inside
transfer_to_live_agent
. 3. Persist collected fields in session state and read them before transfer. 4. Optionally move the collection to an
AgentTask
that must complete first. 5. Make tools return structured outputs to reduce ambiguity. If you’d like, share: • The tool definitions (code for
get_instructions_tool
and
transfer_to_live_agent
), and • The agent prompt/instruction template or relevant config (including whether
parallel_tool_calls
is enabled). With those I can point out exactly where to add the checks or provide a concrete code example for the transfer precondition and task implementation. Sources: Together AI LLM plugin guide | LiveKit Documentation | Agents and handoffs | LiveKit Documentation | Tasks and task groups | LiveKit Documentation