Skip to content
LangSmith 文档版本 跟随上游 源快照 b1366675 更新于 2026-10-18

追踪 LiveKit 应用

NOTE

此集成处于 beta 阶段,因此其 API 可能会发生变化。

使用 LangSmith LiveKit 集成追踪 LiveKit Agents 语音 agent,包括其转录和音频录制。有关高层约定,请参阅语音追踪基础。

NOTE

此设置需要 langsmith[livekit]>=0.11.2 和 livekit-agents>=1.6。LiveKit Agents 1.7 及更高版本需要 langsmith[livekit]>=0.12.4。

每个对话都会显示为一条 LangSmith 追踪,包含其流水线事件、延迟和 token 指标。

安装

安装该集成以及你的 agent 使用的 LiveKit 插件:

bash
pip install "langsmith[livekit]" "livekit-agents[openai,silero,turn-detector]"
bash
uv add "langsmith[livekit]" "livekit-agents[openai,silero,turn-detector]"

设置环境变量

该集成会从环境中读取你的 LangSmith 凭据,并通过 OpenTelemetry 为你导出到 LangSmith:

bash
LANGSMITH_API_KEY=<your-langsmith-api-key>
LANGSMITH_TRACING=true
LANGSMITH_PROJECT=<your-desired-langsmith-project>
LIVEKIT_URL=<your-livekit-url>
LIVEKIT_API_KEY=<your-livekit-api-key>
LIVEKIT_API_SECRET=<your-livekit-api-secret>
OPENAI_API_KEY=<your-openai-api-key>

设置追踪

在创建 AgentServer 之前调用一次 configure_livekit。

python
from langsmith.integrations.livekit import configure_livekit
from livekit import agents
from livekit.agents import Agent, AgentServer, AgentSession

# Enable tracing before creating agents.
configure_livekit()

server = AgentServer()

@server.rtc_session()
async def my_agent(ctx: agents.JobContext):
    session = AgentSession(
        stt="openai/gpt-4o-mini-transcribe",
        llm="openai/gpt-4o-mini",
        tts="openai/tts-1:alloy",
    )
    await session.start(
        room=ctx.room,
        agent=Agent(instructions="You are a helpful assistant."),
        record={"audio": True},
    )

configure_livekit() 默认使用 LiveKit 会话录制。record="&quot;audio&quot;: True" 选项告诉 LiveKit 创建录制。

此设置适用于 STT/LLM/TTS 级联和语音到语音(实时)模型。实时模型需要额外调用一次来捕获用户转录。有关更多信息,请参阅使用实时模型。

使用你自己的 tracer provider

如果你的应用已经管理 OpenTelemetry TracerProvider,请将 LangSmith processor 添加到该 provider,并将其注册到 LiveKit:

python
from langsmith.integrations.livekit import LiveKitLangSmithSpanProcessor
from livekit.agents import telemetry
from opentelemetry.sdk.trace import TracerProvider

provider = TracerProvider()  # your own provider
processor = LiveKitLangSmithSpanProcessor()
provider.add_span_processor(processor)
telemetry.set_tracer_provider(provider)

将对话分组到线程

要将对话的运行分组到 LangSmith 线程,请在会话处理程序中调用 set_thread_id。为每个活动会话使用唯一 ID:

python
from langsmith.integrations.livekit import configure_livekit, set_thread_id

configure_livekit()

@server.rtc_session()
async def my_agent(ctx: agents.JobContext):
    thread_id = ctx.job.id  # or any id that identifies the conversation
    set_thread_id(thread_id)
    ...

使用实时模型

对于语音到语音(实时)模型,在创建 AgentSession 后调用 instrument_session 以捕获用户转录。将相同的线程 ID 传给 set_thread_id 和 instrument_session:

python
from langsmith.integrations.livekit import configure_livekit, set_thread_id
from livekit.plugins import openai as lk_openai

processor = configure_livekit()

@server.rtc_session()
async def my_agent(ctx: agents.JobContext):
    thread_id = ctx.job.id  # or any id that identifies the conversation
    set_thread_id(thread_id)

    session = AgentSession(llm=lk_openai.realtime.RealtimeModel(voice="marin"))
    processor.instrument_session(session, thread_id)  # capture the user transcript

    await session.start(
        room=ctx.room,
        agent=Agent(instructions="You are a helpful assistant."),
        record={"audio": True},
    )

仅对实时模型调用 instrument_session。STT/LLM/TTS 级联已经捕获用户转录,因此在那里调用它会把每个用户轮次记录两次。

录制对话音频

默认情况下,集成使用 LiveKit 的会话录制。如果你改为录制到外部存储,请使用 Egress 模式。

使用 LiveKit 的会话录制进行录制

开启 LiveKit 的会话录制。

python
from langsmith.integrations.livekit import configure_livekit
from livekit import agents
from livekit.agents import Agent, AgentServer, AgentSession

configure_livekit()

server = AgentServer()

@server.rtc_session()
async def my_agent(ctx: agents.JobContext):
    session = AgentSession(...)
    await session.start(
        room=ctx.room,
        agent=Agent(instructions="You are a helpful assistant."),
        record={"audio": True},
    )

默认情况下,如果存在 LiveKit 录制,LangSmith 集成会捕获该录制。

NOTE

在 console 模式下,还要在命令行传入 --record(python agent.py console --record)。否则 LiveKit 会创建录制器但从不启动它,因此没有可附加的文件。录制反映的是播放给客户端的内容,因此打断会显示为截断。

使用 Egress 进行录制

当你希望将录制保存在自己的对象存储中或需要视频时,请使用 LiveKit Egress。Egress 录制交付需要线程 ID。为 Egress 配置集成,然后在 Egress 文件可用后调用 complete_recording:

python
import asyncio
import os
import time

from langsmith.integrations.livekit import configure_livekit, set_thread_id
from livekit import agents, api
from livekit.agents import Agent, AgentServer, AgentSession

RECORDING_BUCKET = os.environ["RECORDING_BUCKET"]

processor = configure_livekit(
    recording_mode="egress",
    recording_timeout_seconds=180,
)
server = AgentServer()

async def wait_for_egress(
    lkapi: api.LiveKitAPI,
    egress_id: str,
    timeout_seconds: float = 120,
) -> api.EgressInfo:
    deadline = time.monotonic() + timeout_seconds
    failed_statuses = {
        api.EgressStatus.EGRESS_FAILED,
        api.EgressStatus.EGRESS_ABORTED,
        api.EgressStatus.EGRESS_LIMIT_REACHED,
    }
    while time.monotonic() < deadline:
        response = await lkapi.egress.list_egress(
            api.ListEgressRequest(egress_id=egress_id)
        )
        if response.items:
            info = response.items[0]
            if info.status == api.EgressStatus.EGRESS_COMPLETE:
                return info
            if info.status in failed_statuses:
                raise RuntimeError(f"Egress failed with status {info.status}")
        await asyncio.sleep(1)
    raise TimeoutError(f"Egress {egress_id} did not complete in time")

@server.rtc_session()
async def my_agent(ctx: agents.JobContext):
    thread_id = ctx.job.id  # unique per session; ctx.room.name is "console" in console mode
    set_thread_id(thread_id)  # routes the Egress recording to this trace
    key = f"recordings/{thread_id}.ogg"

    # Start an audio-only room-composite egress to your storage.
    lkapi = api.LiveKitAPI()  # reads LIVEKIT_URL / LIVEKIT_API_KEY / LIVEKIT_API_SECRET
    egress = await lkapi.egress.start_room_composite_egress(
        api.RoomCompositeEgressRequest(
            room_name=ctx.room.name,
            audio_only=True,
            file_outputs=[
                api.EncodedFileOutput(
                    file_type=api.EncodedFileType.OGG,
                    filepath=key,
                    s3=api.S3Upload(
                        bucket=RECORDING_BUCKET,
                        region=os.environ["AWS_REGION"],
                        access_key=os.environ["AWS_ACCESS_KEY_ID"],
                        secret=os.environ["AWS_SECRET_ACCESS_KEY"],
                    ),
                )
            ],
        )
    )

    async def attach_recording():
        try:
            info = await wait_for_egress(lkapi, egress.egress_id)  # poll until EGRESS_COMPLETE
            audio = download_from_storage(RECORDING_BUCKET, key)  # your storage client
            processor.complete_recording(
                thread_id,
                data=audio,
                # EgressInfo.started_at is a Unix timestamp in nanoseconds. This is
                # when the egress worker began recording, which is what aligns the
                # audio start with the trace.
                started_at=info.started_at / 1e9,
            )
        except Exception:
            processor.complete_recording(thread_id, data=None)

    ctx.add_shutdown_callback(attach_recording)

    session = AgentSession(...)
    await session.start(room=ctx.room, agent=Agent(instructions="..."))

download_from_storage 代表你的存储客户端的下载操作。默认附件名和 MIME 类型为 recording.ogg 和 audio/ogg。如果你的 Egress 输出使用其他格式,请在 complete_recording 中设置 name 或 mime_type。

NOTE

始终调用 complete_recording,包括失败时使用 data=None。否则,集成会等待 recording_timeout_seconds(默认 30 秒)后导出不带音频的追踪。使用 complete_recording 捕获 Egress 录制需要设置 thread_id。

后续步骤


BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。