miniature-lifeguard-87511
07/11/2025, 10:38 AMtall-airline-16756
07/11/2025, 10:38 AMtall-airline-16756
07/11/2025, 10:39 AMSurveyData
) to hold user responses and state.
2. Create a sequence of specialized agents: For each data point (such as name, email, etc.), make a corresponding agent using @function_tool
decorators to collect input and record responses. Each agent can prompt the user for specific data and transition to the next step.
3. Store collected data: After data collection, you can store responses in memory, write to a CSV file, or save to a database (e.g., SQLite), depending on your persistence requirements.
4. Session management: Use session.userdata
to store and pass the data structure as the user progresses through the stages.
You can implement robust flows by chaining multiple agents, validating user input within your function tools, and providing completion summaries at the end of the process. This approach is flexible and adaptable for collecting any type of user information through your LiveKit agent workflow.
If you need a code example or have specific requirements (e.g., voice vs. text, storage backend), please specify for more detailed guidance.
Sources: complex-agents/nutrition-assistant/README.mdminiature-lifeguard-87511
07/11/2025, 11:00 AMtall-airline-16756
07/11/2025, 11:02 AMsession.say("The patient ID is 12345.")
.
3. Listening for what's needed: When the pharmacist asks, "What details do you need?", your bot will be all set to smoothly move to the next step.
4. Gathering info together: Your bot will have friendly agents ready to collect details like: All these answers get neatly stored in a ConversationData
structure.
◦ What are the active prescriptions?
◦ What are the inactive prescriptions?
◦ What are the insurance details?
1. Wrapping up with a smile: After collecting all the info, the bot will confirm everything with the pharmacist and cheerfully say: "Thanks so much! Hope you have a great day!" before ending the call.
We'll use LiveKit's smart agent state management to keep track of each stage, with @function_tool
decorators making sure everything flows smoothly. This setup works great for both flexible conversations and more structured interactions. You can easily store the collected info in session memory, a file, or a database.
This approach is super flexible—if you want more details on things like understanding natural language, setting up phone systems, or handling data storage, just give me a shout, and I'll be happy to help!
Sources: agent.py | examples/voice_agents/restaurant_agent.py | Agents telephony integration | LiveKit Docs | Company directory phone assistant | LiveKit Docs | flows/simple_flow.pyminiature-lifeguard-87511
07/11/2025, 11:56 AMBVCTelephony
for best results
noise_cancellation=noise_cancellation.BVC(),
),
)
await ctx.connect()
await session.generate_reply(
instructions="Greet the user and offer your assistance."
)
if name == "__main__":
agents.cli.run_app(agents.WorkerOptions(entrypoint_fnc=entrypoint))tall-airline-16756
07/11/2025, 11:57 AMfrom dotenv import load_dotenv
from dataclasses import dataclass, field
from typing import Dict, Optional
from livekit import agents
from livekit.agents import AgentSession, Agent, RoomInputOptions
from livekit.plugins import (
openai,
cartesia,
deepgram,
noise_cancellation,
silero,
)
from livekit.plugins.turn_detector.multilingual import MultilingualModel
load_dotenv()
@dataclass
class PharmacistSessionData:
patient_id: Optional[str] = "12345"
patient_name: str = "Alex"
responses: Dict[str, str] = field(default_factory=dict)
stage: int = 0
class PharmacistBot(Agent):
def __init__(self):
super().__init__(instructions="You are an assistant running a pharmacist info collection flow.")
self.questions = [
"What are the active prescriptions?",
"What are the inactive prescriptions?",
"What are the insurance details?"
]
async def on_enter(self):
s = self.session.userdata
if s.stage == 0:
await self.session.say(f"I would like to collect some information regarding a patient named {s.patient_name}.")
elif s.stage == 1:
await self.session.say(f"The patient ID is {s.patient_id}.")
elif 2 <= s.stage < 6:
await self.session.say(self.questions[s.stage - 2])
elif s.stage == 6:
summary = f"Active prescriptions: {s.responses.get('active', '[not provided]')}\n"
summary += f"Inactive prescriptions: {s.responses.get('inactive', '[not provided]')}\n"
summary += f"Insurance details: {s.responses.get('insurance', '[not provided]')}\n"
await self.session.say(f"To confirm, here's what I have collected:\n{summary}Does this look correct?")
elif s.stage == 7:
await self.session.say("Thank you, have a good day!")
await self.session.aclose()
async def on_user_message(self, message: str):
s = self.session.userdata
if s.stage == 0 and "patient id" in message.lower():
s.stage = 1
await self.on_enter()
elif s.stage == 1 and "what details" in message.lower():
s.stage = 2
await self.on_enter()
elif s.stage == 2:
s.responses['active'] = message
s.stage = 3
await self.on_enter()
elif s.stage == 3:
s.responses['inactive'] = message
s.stage = 4
await self.on_enter()
elif s.stage == 4:
s.responses['insurance'] = message
s.stage = 5
await self.on_enter()
elif s.stage == 5:
if "yes" in message.lower():
s.stage = 6
await self.on_enter()
else:
await self.session.say("Please clarify or provide corrections.")
else:
await self.session.say("Could you please clarify?")
async def entrypoint(ctx: agents.JobContext):
session = AgentSession(
stt=deepgram.STT(model="nova-3", language="multi"),
llm=openai.LLM(model="gpt-4o-mini"),
tts=cartesia.TTS(model="sonic-2", voice="f786b574-daa5-4673-aa0c-cbe3e8534c02"),
vad=silero.VAD.load(),
turn_detection=MultilingualModel(),
userdata=PharmacistSessionData(),
)
await session.start(
room=ctx.room,
agent=PharmacistBot(),
room_input_options=RoomInputOptions(
noise_cancellation=noise_cancellation.BVC(),
),
)
await ctx.connect()
if __name__ == "__main__":
agents.cli.run_app(agents.WorkerOptions(entrypoint_fnc=entrypoint))
I've crafted this code to make patient info gathering super smooth! You can totally customize the stage transitions and field names to fit exactly what you need. Think of it like having a friendly chat that makes collecting important details feel natural and easy. 😊
Sources: Workflows | LiveKit Docs | complex-agents/personal_shopper/README.mdminiature-lifeguard-87511
07/11/2025, 12:02 PMtall-airline-16756
07/11/2025, 12:03 PMMultilingualModel()
to make sure we catch the full context of what you're saying, without cutting you off mid-sentence.
• Keeping things smooth: We'll only update our conversation stage after carefully understanding your response. No more rushing ahead!
• Give you breathing room: If it seems like we're interrupting, we'll adjust the settings to allow for more natural pauses in our chat.
The goal is to make our conversation feel as natural as talking with a friend—taking turns, listening carefully, and moving forward together.
Sources: AI voice agents | LiveKit Docs | How does end-of-utterance detection work in conversations? | Voice Assistants | livekit/livekit_composite | DeepWiki | Handling RAG Delays in Voice Agents | LiveKit Docs | flows/multi_stage_flow.py | VoicePipelineAgent | LiveKit Docs | Speech & Audio Processing | livekit/livekit_composite | DeepWiki | LiveKit turn detector plugin | LiveKit Docs | Turn detection and interruptions | LiveKit Docs | Turn detection and interruptions | LiveKit Docsminiature-lifeguard-87511
07/11/2025, 12:04 PMtall-airline-16756
07/11/2025, 12:06 PM