Voice and chat agents are increasingly used for workflows that aren't open-ended: qualify a lead, run patient intake, gather booking details, confirm a service request, follow up with a survey. The goal is not to have a freeform conversation; it's a structured record you can act on at the end of every call.
Prompt-only agents struggle with this use case. To reliably collect a defined dataset and submit the result somewhere deterministic, developers usually end up stitching together tool calls for structured extraction, end-of-call detection, and result delivery.
Guided data collection flows are now a first-class pattern with LiveKit Agents, and there are two ways to build one:
- In code, using Tasks and TaskGroups in the Agents SDKs.
- In your browser, using Data collection mode in Agent Builder.
Both paths produce the same kind of agent: one with a defined objective that keeps the conversation on track, captures the user's responses, and yields control when the work is done. Agent Builder compiles down to the same Tasks and TaskGroups primitives the SDKs expose, so picking one path now doesn't lock you out of the other later.
Path 1: Tasks and TaskGroups in the Agents SDKs
AgentTask is the primitive for structured conversational work in the Python and TypeScript Agents SDKs. A task is a focused, reusable unit that takes control of the session, completes a specific objective, and returns a typed result to the agent that started it. Tasks have full support for tools, just like an agent.
Here is a simple task that asks for recording consent and returns a boolean:
1from livekit.agents import AgentTask, function_tool23class CollectConsent(AgentTask[bool]):4def __init__(self, chat_ctx=None):5super().__init__(6instructions="""7Ask for recording consent and get a clear yes or no answer.8Be polite and professional.9""",10chat_ctx=chat_ctx,11)1213async def on_enter(self) -> None:14await self.session.generate_reply(15instructions="""16Briefly introduce yourself, then ask for permission to record17the call for quality assurance and training purposes.18Make it clear that they can decline.19"""20)2122@function_tool23async def consent_given(self) -> None:24"""Use this when the user gives consent to record."""25self.complete(True)2627@function_tool28async def consent_denied(self) -> None:29"""Use this when the user denies consent to record."""30self.complete(False)
An agent runs the task by awaiting it, and uses the returned value to decide what to do next:
1from livekit.agents import Agent23class CustomerServiceAgent(Agent):4def __init__(self):5super().__init__(6instructions="You are a friendly customer service representative."7)89async def on_enter(self) -> None:10if await CollectConsent(chat_ctx=self.chat_ctx):11await self.session.generate_reply(12instructions="Offer your assistance to the user."13)14else:15await self.session.generate_reply(16instructions="Inform the user that you cannot proceed."17)
For multi-step flows, the framework provides TaskGroup, an ordered sequence of tasks that share conversation context, support backtracking to earlier steps, and return all their results together when the group finishes:
1from livekit.agents.beta.workflows import TaskGroup23task_group = TaskGroup(chat_ctx=self.chat_ctx)45task_group.add(6lambda: IntroTask(),7id="intro_task",8description="Collects name and introduction",9)10task_group.add(11lambda: CommuteTask(),12id="commute_task",13description="Asks about commute flexibility",14)1516results = await task_group17task_results = results.task_results18# {19# "intro_task": IntroResults(name="...", intro="..."),20# "commute_task": CommuteResults(can_commute=True, commute_method="subway"),21# }
TaskGroups handle the messy parts of real conversations. If a user wants to correct an earlier answer mid-flow, the group can regress to that task while keeping the rest of the context intact. When the group finishes, its conversation is summarized and passed back to the controlling agent so the session continues naturally.
For common patterns, the framework also includes prebuilt tasks like GetEmailTask, GetAddressTask, GetDtmfTask, and WarmTransferTask, tuned for noisy voice transcription and the formats they collect. Drop them into a TaskGroup alongside your own tasks for reliable collection without writing the field-handling logic yourself.
Use Tasks and TaskGroups when you want fine-grained control, need to reuse the same collection step across multiple agents, or are composing structured collection into a larger code-first agent.
Path 2: Data collection mode in Agent Builder
Data collection mode in Agent Builder is a browser-based experience for the same use case. Instead of scripting questions or wiring up flowcharts, you declare fields: pieces of information that the agent needs to gather before the session ends. Fields can map to a one-turn answer or take a full sub-conversation. Fields can return scalars, nested objects, or arrays. An attendees field, for example, can yield an array of attendee records, each with their own sub-fields.
Based on these inputs, Agent Builder composes the underlying TaskGroups for you. You focus more on the outcome of the conversation and less on the nitty-gritty details of how your agent asks questions.
How it works
When you create a new agent, you pick a conversation type: Open ended or Data collection. The choice changes the Agent Builder layout and defaults, but the agent underneath is the same; you can still export, deploy, and extend it the same way.

After selecting Data collection mode, you can either start from scratch or pick from a prebuilt template (patient intake, lead qualification, or customer feedback). Each template comes with suggested fields that you can edit, reorder, or replace to meet your needs.

The Agent Builder UI maps directly to the behavior the agent will follow: an overall instructions layer, an optional welcome step, your ordered list of fields, and an ending step that handles result delivery and session termination. Authoring the agent feels like walking through the conversation.
Result delivery is part of the feature
A data collection agent is only useful if the output can leave the conversation in a structured way. At the end of the flow, Agent Builder submits a structured payload to the configured endpoint. A representative response looks like this:
1{2"body": {3"job_id": "AJ_qsV4cAeZCDPF",4"room_id": "RM_hNJarY6HwLaY",5"room": "p_1m03vlvq2ym:ab_542mhzi1w12:preview-ysuY",6"started_at": "2026-03-24T00:19:44.514403Z",7"ended_at": "2026-03-24T00:21:02.729760Z",8"summary": "The caller followed up with a customer one week after service...",9"results": {10"customer_identification": {11"customer_full_name": "John Doe",12"service_order_number": "334"13},14"service_type": {15"service_type": "plumbing"16}17}18}19}
The results object is what you build against. Map it to your intake form, CRM, database, or whatever downstream system owns the data.

You can also generate a call summary if you want one, but your integration shouldn't depend on parsing it. Once the submission succeeds, the session ends automatically. No end-call tool wiring or custom cleanup is required.
Preview your agent directly in Agent Builder so you can iterate on models and voices used, field sequencing, and your structured data output before deploying to LiveKit Cloud.
Choose a path to get started
Structured data collection is now a first-class pattern in LiveKit, in code or in the browser. You declare the fields you need, the agent handles how to gather them, and LiveKit Agents handles end-of-call detection, retries, and result delivery. Whichever path you start on, you end every session with a predictable, structured record:
- Start in Agent Builder when you want a fast visual loop, a templated starting point, or a way to iterate in the browser before writing any code.
- Start in code when you want fine-grained control, need to reuse the same collection step across multiple agents, or are composing structured collection into a larger code-first agent.
You can also switch later. Agent Builder agents compile down to Tasks and TaskGroups so exporting to code is easy.
Start building today with Agent Builder or Tasks and TaskGroups in the Agents SDKs and share feedback or questions in our community forums.