Skip to content

Pydantic AI vs LiveKit Agents

LiveKit Agents is a voice-agent framework built on LiveKit’s WebRTC transport: rooms, SIP telephony, turn detection, noise cancellation, mid-call handoffs, and plugins for STT, LLM and TTS vendors, with a cascaded pipeline as the default. Pydantic AI’s realtime support is a speech-to-speech agent loop on five providers behind one API, and it is the same typed Agent that runs as text, in a web chat or behind your API: the call uses the same tools, dependencies and capabilities, becomes ordinary message history you can hand to a text agent for structured output, and is traced end to end in Logfire. You bring the transport; with LiveKit, the transport is the product.

Pydantic AI is one part of a stack: the Harness SDK for capabilities and complete agents, Pydantic Evals for evaluation, Pydantic Graph for graph-based workflows, Pydantic Logfire for observability, and Pydantic itself for validation. The tables below cover the whole of it.

Framework

LiveKit AgentsPydantic AI and Harness SDK
LanguagePython (also Node)Python
LicenseApache-2.0MIT
Model providersMany (plugins)Many
ExtensibilityPipeline nodes (stt_node, llm_node, …)Capabilities and toolsets; 90+ with the Harness SDK
HarnessesBuild your ownBuilt-in Coder and Researcher, or compose your own
ObservabilityOpenTelemetryOpenTelemetry, including Pydantic Logfire
Enterprise supportWith a LiveKit Cloud planFor the framework itself, no platform required
Durable executionNoNine integrations
InterfacesWebRTC rooms, telephony, text sessionsCLI, web chat, AG-UI, Vercel AI, ACP (experimental), GitHub Agentic Workflows
Realtime voiceSpeech-to-speech and cascaded STT + LLM + TTSSpeech-to-speech, five providers
EvalsYesPydantic Evals
Image generationNoImage Generation

Realtime, side by side

Our realtime support means speech-to-speech models: one persistent connection, audio in and audio out, on the five providers below. LiveKit also runs a cascaded pipeline you compose from plugins; we don’t build one in, though ElevenLabs Agents and Azure AI Voice Live’s cascade models run hosted ones. If you are choosing a voice stack, these are the rows that decide it:

LiveKit AgentsPydantic AI
Speech-to-speech providersPlugins for several providersFive behind one API: OpenAI, Azure OpenAI, Gemini Live, xAI, ElevenLabs
Cascaded STT + LLM + TTSYes, the default; dozens of STT and TTS pluginsHosted only, via ElevenLabs Agents or Azure AI Voice Live; otherwise compose it yourself around a text agent
Audio transportWebRTC rooms via LiveKit server or CloudYours: browser WebRTC sideband or WebSocket relay
TelephonySIP in and out, DTMF, transfers; numbers on CloudBridge a provider such as Twilio
Turn detectionSilero VAD, own turn-detector model, adaptive interruptionProvider turn detection, barge-in, push-to-talk
Noise cancellationKrisp and ai-coustics plugins; enhanced models on CloudProvider-side only
Hand off to another agent mid-callYes, context carried overNo; delegate from a tool instead
Tools mid-call@function_tool, MCPThe same tools, toolsets and dependencies as a text agent
Capabilities mid-callNo equivalentCapabilities and hooks, with documented limits
After the callsession.history, SessionReport JSONAgent.run() on the call’s history for structured output or follow-up; a LiveKit call’s history converts too
ObservabilityOpenTelemetry; Insights on CloudOpenTelemetry: session, turn and tool spans, usage attributed per response
Evalspytest framework with an LLM judge; simulations on CloudPydantic Evals on the text hand-off; nothing realtime-specific yet
DeploymentAgent server, dispatch, jobs; Cloud or self-hostYour process, your backend; Hosting the backend covers long-lived sessions, routing, and draining
The same agent without voiceText-only sessions, still a room and a serverrun(), CLI, web chat, AG-UI, Vercel AI

Handing a LiveKit call to Pydantic AI

If you keep LiveKit’s cascaded pipeline for the call, you can still use a Pydantic AI agent afterwards for structured output or follow-up. LiveKit records the call as a ChatContext in AgentSession.history, not as Pydantic AI message history, so convert its items to ModelRequests and ModelResponses first:

from livekit.agents import AgentSession, llm
from pydantic import BaseModel

from pydantic_ai import (
    Agent,
    ModelMessage,
    ModelRequest,
    ModelResponse,
    TextPart,
    ToolCallPart,
    ToolReturnPart,
    UserPromptPart,
)


def to_model_messages(chat_ctx: llm.ChatContext) -> list[ModelMessage]:
    messages: list[ModelMessage] = []
    for item in chat_ctx.items:
        if isinstance(item, llm.ChatMessage):
            text = item.text_content  # the transcript; images and audio are dropped
            if not text or item.role in ('system', 'developer'):
                continue  # the LiveKit agent's instructions; the text agent has its own
            if item.role == 'user':
                messages.append(ModelRequest(parts=[UserPromptPart(text)]))
            else:
                if item.interrupted:
                    text += ' [Interrupted]'
                messages.append(ModelResponse(parts=[TextPart(text)]))
        elif isinstance(item, llm.FunctionCall):
            part = ToolCallPart(item.name, item.arguments, item.call_id)
            messages.append(ModelResponse(parts=[part]))
        elif isinstance(item, llm.FunctionCallOutput):
            outcome = 'failed' if item.is_error else 'success'
            part = ToolReturnPart(item.name, item.output, item.call_id, outcome=outcome)
            messages.append(ModelRequest(parts=[part]))
    return messages


class CallSummary(BaseModel):
    summary: str
    follow_up_needed: bool


notetaker = Agent('openai:gpt-6.1-sol', output_type=CallSummary)


async def summarize_call(session: AgentSession) -> CallSummary:
    result = await notetaker.run(
        'Summarize the call.', message_history=to_model_messages(session.history)
    )
    return result.output

Pydantic AI merges consecutive requests or responses, such as a spoken reply followed by a tool call, before sending the history to the model. Agent handoffs and configuration updates in the LiveKit history have no Pydantic AI equivalent and are skipped.

Last checked: 2026-10-26

Sources