> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # 실시간 음성 실시간 음성은 Mastra Agent를 사용자가 브라우저나 전화를 통해 대화할 수 있는 실시간 통화로 전환합니다. Mastra는 그것을 기반으로 합니다.[LiveKit](https://livekit.io), 실시간 오디오 및 비디오를 위한 오픈 소스 WebRTC 플랫폼입니다. 그만큼[`@mastra/livekit`](https://mastra.zisheng.pro/ko/reference/voice/livekit) package connects Mastra agents to the [LiveKit Agents framework](https://docs.livekit.io/agents/): LiveKit은 음성 활동 감지, 음성-텍스트 스트리밍, 의미론적 전환 감지, 바지인 및 텍스트-음성 변환과 같은 오디오 루프를 소유합니다. Mastra Agent는 자체 Model, Tool 및 Memory를 사용하여 모든 응답을 생성합니다. 대기 시간이 짧고 중단 가능한 음성 대화가 필요한 경우 실시간 음성을 사용하세요. LiveKit을 사용하지 않는 공급자 기반 음성 음성 변환은 다음을 참조하세요.[Speech to Speech](https://mastra.zisheng.pro/ko/guides/voice/speech-to-speech). ## 빠른 시작 이 단계는 빈 프로젝트에서 대화할 수 있는 음성 Agent로 이동합니다. 음성 세션에는 여기에서 설정하는 두 가지 이동 부분이 있습니다. 즉, 액세스 토큰을 전달하는 Mastra 서버의 API 경로와 오디오 파이프라인을 실행하고 매 턴마다 Agent를 호출하는 별도의 작업자 프로세스입니다. 1. 음성 활동 감지 및 회전 감지를 위해 LiveKit 플러그인과 함께 통합 패키지를 설치합니다. **npm**: ```bash npm install @mastra/livekit @livekit/agents @livekit/agents-plugin-silero @livekit/agents-plugin-livekit ``` **pnpm**: ```bash pnpm add @mastra/livekit @livekit/agents @livekit/agents-plugin-silero @livekit/agents-plugin-livekit ``` **Yarn**: ```bash yarn add @mastra/livekit @livekit/agents @livekit/agents-plugin-silero @livekit/agents-plugin-livekit ``` **Bun**: ```bash bun add @mastra/livekit @livekit/agents @livekit/agents-plugin-silero @livekit/agents-plugin-livekit ``` 2. LiveKit 자격 증명을 내부에 설정하세요.`.env` file. Create a free project on [LiveKit Cloud](https://cloud.livekit.io), or run a local server with [`livekit-server --dev`](https://docs.livekit.io/home/self-hosting/local/): ```bash LIVEKIT_URL=wss://your-project.livekit.cloud LIVEKIT_API_KEY=your-api-key LIVEKIT_API_SECRET=your-api-secret ``` 3. Mastra 인스턴스에 음성 Agent를 추가하고 연결 경로를 노출하세요. 그만큼`liveKitConnectionRoute()` helper adds a `POST /voice/livekit/connection-details` 엔드포인트는 LiveKit 토큰을 발급하고 Agent를 방으로 디스패치합니다: ```typescript import { Mastra } from '@mastra/core/mastra' import { Agent } from '@mastra/core/agent' import { liveKitConnectionRoute } from '@mastra/livekit' const supportAgent = new Agent({ id: 'support', name: 'Support', instructions: 'You are a friendly phone support agent. Keep replies short and conversational.', model: 'openai/gpt-5-mini', }) export const mastra = new Mastra({ agents: { support: supportAgent }, server: { apiRoutes: [liveKitConnectionRoute({ agentName: 'mastra-voice' })], }, }) ``` 4. 작업자를 생성합니다. 별도의 프로세스로 실행되고 LiveKit 세션에 응답하며 매 턴마다 Agent에 전화를 겁니다. 작업자 API는`@mastra/livekit/worker` 진입점을 사용하므로 Mastra 서버가 LiveKit Agents 런타임을 로드하지 않습니다. 이 예제에서는 음성 텍스트 변환과 텍스트 음성 변환에 LiveKit Inference Model 문자열을 사용하므로 Provider 플러그인이 필요하지 않습니다: ```typescript import { fileURLToPath } from 'node:url' import { createLiveKitWorker, runLiveKitWorker } from '@mastra/livekit/worker' import { mastra } from './index' export default createLiveKitWorker({ mastra, agent: 'support', stt: 'deepgram/nova-3', tts: 'cartesia/sonic-3', turnDetection: 'multilingual', greeting: 'Hi! How can I help you today?', }) if (process.argv[1] === fileURLToPath(import.meta.url)) { runLiveKitWorker({ entry: import.meta.url, agentName: 'mastra-voice' }) } ``` 그만큼`agent` 옵션은 각 세션에 응답할 Mastra Agent를 선택합니다. 표시된 것처럼 고정 키를 전달하거나, 다음을 사용하려면 생략하세요: `agentId` 를 디스패치 메타데이터에서 가져오므로 하나의 워커가 Mastra 인스턴스의 모든 Agent를 처리할 수 있습니다. 5. 회전 감지 및 음성 활동 감지 Model을 한 번 다운로드하세요. 그런 다음 한 터미널에서는 작업자를 실행하고 다른 터미널에서는 Mastra 서버를 실행합니다. ```bash npx livekit-agents download-files npx tsx src/mastra/voice-worker.ts dev ``` **npm**: ```bash npm run dev ``` **pnpm**: ```bash pnpm run dev ``` **Yarn**: ```bash yarn dev ``` **Bun**: ```bash bun run dev ``` 작업자는 LiveKit 서버에 등록하고 세션을 기다립니다.`mastra dev` serves the connection route. 6. 대리인과 상담하세요. 호스팅을 엽니다.[LiveKit Agents Playground](https://agents-playground.livekit.io) 를 프로젝트에 연결하여 프런트엔드를 구축하지 않고도 통화를 시작하세요. 대신 자신의 앱을 연결하려면 토큰에 대한 연결 경로를 호출하세요.`POST /voice/livekit/connection-details` accepts optional `agentId`, `threadId`, and `resourceId` fields in the request body and returns: ```json { "serverUrl": "wss://your-project.livekit.cloud", "roomName": "mastra-voice-a1b2c3d4", "participantName": "user-1", "participantToken": "eyJhbGci..." } ``` 이 응답은 LiveKit의 프런트엔드 스타터에서 사용하는 계약과 일치하므로 앱은 다음에서 빌드됩니다.[agent-starter-react](https://github.com/livekit-examples/agent-starter-react) or the [LiveKit React components](https://docs.livekit.io/reference/components/react/) work without changes. ## 회전 감지 및 방해 LiveKit은 사용자가 말하기를 마친 시점과 Agent가 중단된 시점을 결정합니다. 기본값은 잘 작동합니다. 그들을 조정`turnHandling`: ```typescript export default createLiveKitWorker({ mastra, agent: 'support', stt: 'deepgram/nova-3', tts: 'cartesia/sonic-3', turnDetection: 'multilingual', turnHandling: { endpointing: { mode: 'dynamic', minDelay: 300, maxDelay: 3000 }, interruption: { minDuration: 500, resumeFalseInterruption: true }, }, }) ``` - `turnDetection: 'multilingual'`: LiveKit의 의미론적 턴 종료 Model을 CPU에서 로컬로 실행합니다. 사용자가 생각을 중단하는 것을 방지하기 위해 실시간 기록을 읽습니다. 사용`'vad'` or `'stt'` for silence-based endpointing instead. - `endpointing`: 사용자가 말하기를 멈춘 후 Agent가 기다리는 시간을 제한합니다. - `interruption`: 참여를 제어합니다. 사용자가 Agent를 통해 말하면 LiveKit은 재생을 중지하고 진행 중인 Mastra 스트림을 취소하므로 토큰 생성도 중지됩니다. - `preemptiveGeneration`: 사용자가 완료하는 동안 Mastra Agent의 응답을 시작하여 첫 번째 토큰까지의 시간을 숨깁니다. 작업자는 기본적으로 이를 비활성화합니다. 각 선점 시도는 중간 기록에서 Mastra Agent를 실행하고, 모든 실행은 스레드에서 메시지를 복제하는 사용자 메시지를 유지합니다. 다음을 사용하여 다시 활성화하세요.`preemptiveGeneration: { enabled: true }` 정확한 스레드 기록보다 지연 시간이 더 중요하다면 사용합니다. 참조[LiveKit turn detection docs](https://docs.livekit.io/agents/logic/turns/) for all options. ## 통화별 음성 및 전사 최상위 수준`stt` and `tts` 옵션은 모든 호출에 적용됩니다. 호출별로 선택하거나 테넌트마다 하나의 음성 또는 언어를 지정하려면 `configuration.stt` and `configuration.tts` 리졸버를 대신 설정하세요. 각 리졸버는 디스패치 메타데이터, 요청 컨텍스트, 룸 이름, 작업 컨텍스트와 함께 호출마다 한 번 실행되며, 일치하는 최상위 옵션에서 허용하는 값을 반환합니다. 이 값은 플러그인 인스턴스 또는 추론 Model 문자열입니다. 다음을 반환하세요: `undefined` to fall back to the top-level option. 다음 예에서는 각 테넌트에게 고유한 텍스트 음성 변환 음성을 제공합니다.`tenant` entry in the dispatch metadata: ```typescript import * as cartesia from '@livekit/agents-plugin-cartesia' // One voice id per tenant, resolved from the dispatch metadata on each call. const tenantVoices: Record = { meridian: 'your-cartesia-voice-id-1', coastal: 'your-cartesia-voice-id-2', } // The resolver runs during call setup, so cache plugin instances across calls. const ttsByVoice = new Map() export default createLiveKitWorker({ mastra, agent: 'support', stt: 'deepgram/nova-3', tts: 'cartesia/sonic-3', configuration: { tts: ({ requestContext }) => { const voice = tenantVoices[requestContext?.tenant as string] if (!voice) return undefined // fall back to the top-level `tts` let tts = ttsByVoice.get(voice) if (!tts) { tts = new cartesia.TTS({ voice }) ttsByVoice.set(voice, tts) } return tts }, }, }) ``` `configuration.stt`호출별 전사와 동일한 방식으로 작동합니다(예: 테넌트별 다른 전사 Model 또는 언어). 인사말에는 일치하는 통화별 형식이 있습니다.`configuration.greeting.text` 동일한 호출 컨텍스트를 받는 리졸버를 허용하므로, 하나의 워커가 각 테넌트에 맞는 고유한 문구로 대화를 시작할 수 있습니다. ## Memory와 스레드 확인된 Mastra Agent에 Memory가 구성되어 있으면 각 호출은 하나의 Memory 스레드가 됩니다. - `thread`기본값은`threadId` 디스패치 메타데이터에서 가져오고, 그다음에는 룸 이름에서 가져옵니다. - `resource`기본값은`resourceId` 디스패치 메타데이터에서 가져오고, 그다음에는 스레드에서 가져옵니다. 호출이 올바른 사용자 아래에 그룹화되도록 여기에 최종 사용자의 ID를 보내세요. Mastra Studio는 Agent ID를 전송하며, 이는 사이드바에서 스레드를 나열하는 방식과 일치합니다. - 스레드가 아직 존재하지 않으면 작업자는 메타데이터를 사용하여 "음성 통화"라는 제목으로 스레드를 생성합니다.`{ source: 'livekit' }`, 음성 인사말은 첫 번째 어시스턴트 메시지로 저장되므로 스레드가 전체 통화 기록으로 표시됩니다(비활성화하려면 `persistGreeting: false`). 각 차례에서는 새로운 사용자 입력만 보냅니다. Mastra Memory는 역사, 의미 기억 및 작업 기억을 제공합니다. 전달하여 기존 스레드에 세션을 고정합니다.`threadId` 를 연결 요청 본문에 지정할 수 있으며, 이는 텍스트 대화를 음성으로 이어갈 때 유용합니다. Studio에서 열린 채팅으로 통화를 시작하면 통화가 해당 스레드에 연결되고, 각 대화가 끝날 때마다 대화 기록이 채팅에 채워집니다. 사용자가 Agent를 중단하면 진행 중인 생성이 중단되고 해당 턴의 어떤 것도 그 순간 지속되지 않습니다. LiveKit은 사용자가 실제로 들은 부분을 녹취록에 보관하고, 다음 차례에 작업자는 들리는 부분만 다시 보내 스레드가 호출과 일치하도록 다시 채웁니다. 중단 후 바로 전화를 끊은 사용자는 마지막 부분을 녹음하지 않은 채 남겨둡니다. 보다[interrupted turns](https://mastra.zisheng.pro/ko/reference/voice/livekit) for the details and a reconciliation recipe. ## Tool이 실행되는 동안 말하기 느린 Tool이 실행되는 동안 음성 대화는 자동으로 진행될 수 없습니다. 사용`toolFeedback` 를 사용하여 Mastra Agent가 Tool 호출을 시작할 때 짧은 문구를 말하게 할 수 있습니다: ```typescript export default createLiveKitWorker({ mastra, agent: 'support', stt: 'deepgram/nova-3', tts: 'cartesia/sonic-3', toolFeedback: ({ toolName }) => toolName === 'searchOrders' ? 'Let me look that up.' : undefined, }) ``` 해당 문구는 응답의 일부로 말하고 성적표에 기록됩니다. ## Workflow를 사용하여 응답 생성 기본적으로 작업자는 Mastra Agent를 사용하여 각 응답을 생성합니다. 턴별로 다단계 로직을 실행하려면(예: 의도 분류, 라우팅, Tool을 순서대로 호출한 후 응답 작성) Mastra를 사용하여 응답을 생성하세요.[workflow](https://mastra.zisheng.pro/ko/docs/workflows/overview) instead. Set `workflow` in place of `agent`. LiveKit은 여전히 ​​오디오 루프를 소유하고 턴당 한 번씩 Mastra를 호출하므로 Workflow는 턴마다 완료될 때까지 실행됩니다. Workflow는 일시 중지하거나 재개할 수 없으며 턴 간에 대화 상태가 전달되지 않습니다. 성적표를 다음을 통해 전달하세요.`workflowInput` so the workflow stays stateless: ```typescript import { createLiveKitWorker, chatContextToMessages } from '@mastra/livekit/worker' import { mastra } from './index' export default createLiveKitWorker({ mastra, workflow: 'phoneConversation', workflowInput: ({ chatCtx }) => ({ history: chatContextToMessages(chatCtx) }), replyStep: 'generateResponse', stt: 'deepgram/nova-3', tts: 'cartesia/sonic-3', turnDetection: 'multilingual', }) ``` Workflow는 텍스트가 아닌 구조화된 단계 이벤트를 스트리밍합니다. 생성된 토큰을 말하기 위해 응답 단계는 Agent의 텍스트를 단계로 파이프합니다.`writer`: ```typescript const generateResponse = createStep({ id: 'generateResponse', // input and output schemas omitted execute: async ({ inputData, mastra, writer, abortSignal }) => { const stream = await mastra.getAgent('voice').stream(inputData.history, { abortSignal }) await stream.textStream.pipeTo(writer) return { assistantMessage: await stream.text } }, }) ``` - `replyStep`: 음성 출력을 한 단계로 제한합니다. 그것에 쓰는 모든 단계를 말하는 것을 생략하십시오.`writer`. - `resultText`: 텍스트를 스트리밍하는 단계가 없을 때 최종 실행 결과에서 응답을 파생하는 대체입니다. 스트리밍을 통해`writer` gives lower time-to-first-token, so prefer it. - `abortSignal`: 단계를 앞으로`abortSignal` into `agent.stream()` 를 사용하면 끼어들기 시 생성이 즉시 중지됩니다. 사용자가 끼어들면 워커가 실행을 취소합니다. - `generate`: 완전한 제어를 위해서는 다음을 전달하십시오.`generate` 함수를 대신 사용하세요. 턴을 텍스트 스트림으로 변환하는 어떤 응답 생성기든 사용할 수 있습니다. Workflow를 사용하면 작업자가 지속되지 않고 Agent의 방식대로 자동으로 전환됩니다.`stream()` 가 수행합니다. Workflow 내부에 대화 기록을 유지하거나, LiveKit 대화 기록을 정보의 기준으로 유지하고 각 턴마다 전달하세요. ## Mastra를 LLM 구성 요소로 사용 `createLiveKitWorker()`귀하를 위해 LiveKit 세션을 소유합니다. 세션을 직접 소유하려면 다음을 사용하세요.[`MastraLLM`](https://mastra.zisheng.pro/ko/reference/voice/livekit) 를 대신 사용하세요. Mastra Agent를 `llm` slot of your own `voice.AgentSession`에 배치하는 표준 LiveKit LLM 플러그인입니다. Mastra 앱, Agent 루프, Tool, Memory, Observability는 Mastra 서버에서 실행되며, 워커는 HTTP를 통해 이에 접근합니다. 워커 프로세스에는 Mastra 앱, 데이터베이스 또는 Model Provider 키가 필요하지 않습니다. ```typescript import { fileURLToPath } from 'node:url' import { defineAgent, voice } from '@livekit/agents' import * as silero from '@livekit/agents-plugin-silero' import { MastraLLM } from '@mastra/livekit/plugin' import { runLiveKitWorker } from '@mastra/livekit/worker' export default defineAgent({ entry: async ctx => { await ctx.connect() const session = new voice.AgentSession({ llm: new MastraLLM({ remote: { baseUrl: process.env.MASTRA_URL!, agentId: 'support' }, memory: { thread: ctx.room.name!, resource: 'user-7' }, }), stt: 'deepgram/nova-3', tts: 'cartesia/sonic-3', vad: await silero.VAD.load(), // Required with `memory`: LiveKit enables preemptive generation by default. turnHandling: { preemptiveGeneration: { enabled: false } }, }) await session.start({ // These instructions never reach the Mastra agent; its own instructions apply. agent: new voice.Agent({ instructions: 'Replies come from the Mastra agent.' }), room: ctx.room, }) session.say('Hi! How can I help you today?') }, }) if (process.argv[1] === fileURLToPath(import.meta.url)) { runLiveKitWorker({ entry: import.meta.url, agentName: 'mastra-voice' }) } ``` 두 경로 모두 아래에서 동일한 응답 파이프라인을 공유합니다. 세션을 소유할 사람을 선택하세요. | | `createLiveKitWorker()` | `MastraLLM` | | -------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | 세션 소유권 | 워커 헬퍼가 다음을 구성하고 관리함: `AgentSession` | 코드에서 세션을 구성하며 모든 LiveKit 옵션과 훅을 직접 관리함 | | Mastra 앱 실행 위치 | 워커 프로세스 내부 | HTTP를 통해 접근하는 Mastra 서버(또는 다음을 통한 인프로세스 방식: `agent`) | | 워커 프로세스 요구 사항 | Mastra 앱, 스토리지 및 Model Provider 키 | LiveKit SDK와 서버에 대한 네트워크 액세스만 필요 | | 기본 제공 편의 기능 | 인사말, 동의 게이팅, Agent 주도 통화 종료, 스레드 부트스트랩, Observability 롤업 | 다음을 사용하여 필요한 기능을 다시 구현: [session helpers](https://mastra.zisheng.pro/ko/reference/voice/livekit) | | 적합한 용도 | 작동하는 음성 Agent를 가장 빠르게 구현하는 경로, Studio 음성 모드 | 기존 LiveKit 앱 및 세션에 대한 완전한 제어 | Tool은 Mastra Agent에 유지되고 서버에서 실행됩니다. 세션에 전달된 LiveKit 측 Tool은 무시됩니다. Tool 활동은 다음을 통해 작업자에게 도달합니다.`toolFeedback` (spoken filler), `onToolCall` (fires as each tool call starts), and `onTurnComplete` (텍스트, Tool 호출 및 토큰 사용량과 함께 각 응답 후 실행됨). Agent 주도 통화 종료는 몇 줄이면 구현할 수 있습니다. 다음을 함께 사용하세요: `onToolCall` with [`runEndCall()`](https://mastra.zisheng.pro/ko/reference/voice/livekit). > **경고:** 결합하지 마십시오`memory` option with LiveKit's `preemptiveGeneration`, 직접 구성한 세션에서는 LiveKit이 이를 기본적으로 활성화합니다. LiveKit이 폐기하기 전에 완료된 추측성 턴은 사용자 메시지와 실제로 음성 출력되지 않은 응답을 스레드에 유지합니다. 다음을 설정하세요: `turnHandling: { preemptiveGeneration: { enabled: false } }`, or run without `memory` and pass the full transcript each turn. `MastraLLM`또한 진행 중인 Mastra도 허용합니다.`agent` 인스턴스, 두 번째 배포 없이 세션 소유권 확보 또는 사용자 지정 `generate` 함수입니다. 원격 전송 기능은 다음으로도 독립적으로 제공됩니다: [`createRemoteAgentReplyGenerator()`](https://mastra.zisheng.pro/ko/reference/voice/livekit), which also plugs into `createLiveKitWorker`'s `generate` 옵션을 사용하여 모든 기능이 포함된 워커를 원격 서버에 연결해 실행할 수 있습니다. ## 서버에서 시작된 세션 사용`dispatchVoiceSession()` 를 사용하여 자체 코드에서 룸에 음성 Agent를 추가할 수 있습니다. 예를 들어 기존 룸에 참여시키거나 아웃바운드 [SIP call](https://docs.livekit.io/sip/): ```typescript import { dispatchVoiceSession } from '@mastra/livekit' await dispatchVoiceSession({ roomName: 'support-call-42', agentName: 'mastra-voice', metadata: { agentId: 'support', threadId: 'thread-42', resourceId: 'user-7' }, }) ``` ## Observability Mastra 인스턴스에[observability](https://mastra.zisheng.pro/ko/docs/observability/overview) 가 구성되어 있으면 워커가 각 호출을 추적합니다. 호출마다 하나의 `voice call` span을 열고 모든 항목을 그 아래에 중첩합니다: - 매 턴의 Mastra Agent는 Model 생성, Tool 호출 및 Memory 작업을 통해 텍스트 채팅이 기록하는 것과 똑같이 실행됩니다. - 각 LiveKit 파이프라인 지표에 대한 하위 범위: 음성-텍스트, 텍스트-음성, 발화 끝(회전 감지), 음성 활동 감지 및 Model의 첫 번째 토큰 시간. 이는 텍스트 추적으로 표시할 수 없는 대기 시간 및 오디오 측정값을 전달합니다. - 세션이 종료될 때 범위에 기록되는 Model별 사용량 롤업(전체 호출에 대한 토큰, 문자 및 오디오 합계)입니다. 작업자는 별도의 프로세스이므로 서버와 작업자 모두의 동시 쓰기를 허용하는 백엔드의 저장소를 가리킵니다. SQLite 지원[LibSQL](https://mastra.zisheng.pro/ko/reference/storage/libsql) 는 작동합니다. 단일 작성자 스토어는 작동하지 않습니다. Trace, Memory 및 스레드는 하나의 스토어를 공유할 수 있습니다: ```typescript import { Mastra } from '@mastra/core/mastra' import { LibSQLStore } from '@mastra/libsql' import { Observability, MastraStorageExporter } from '@mastra/observability' export const mastra = new Mastra({ storage: new LibSQLStore({ id: 'voice-agent-storage', url: 'file:./voice-agent.db' }), observability: new Observability({ configs: { default: { serviceName: 'voice-agent', exporters: [new MastraStorageExporter()], }, }, }), }) ``` 추적은 기본적으로 켜져 있습니다. 통과하다`observability: false` to `createLiveKitWorker` to turn it off. ## 전개 작업자는 Mastra 서버와 별도의 프로세스이므로`mastra build` needs to emit it as its own entry. Add it to [`bundler.entries`](https://mastra.zisheng.pro/ko/reference/configuration): ```typescript import { Mastra } from '@mastra/core' export const mastra = new Mastra({ bundler: { entries: { 'voice-worker': './voice-worker.ts' }, // Keep LiveKit's native modules out of the bundle. `mastra build` only applies // this default when you set no other bundler options, so set it explicitly here. externals: true, }, }) ``` `mastra build`이제 두 프로세스를 모두 작성합니다.`.mastra/output`, sharing one `package.json` and one dependency install: ```text .mastra/output/ index.mjs # Mastra server voice-worker.mjs # LiveKit worker ``` 해당 디렉터리를 단일 아티팩트로 배포하고 자체 명령을 사용하여 각 프로세스를 시작합니다. ```bash node .mastra/output/index.mjs # server node .mastra/output/voice-worker.mjs start # worker ``` 작업자는 서버와 동일한 환경 변수가 필요하며,`LIVEKIT_URL`, `LIVEKIT_API_KEY`, and `LIVEKIT_API_SECRET`. 크기 조정, 정상적인 종료 및 호스팅에 대한 LiveKit의 지침은 변경되지 않고 적용됩니다. 보다[Deploying agents](https://docs.livekit.io/agents/ops/deployment/). 워커는 LiveKit에 아웃바운드로 연결되므로 인바운드 포트가 필요하지 않습니다. ## 작동 원리 LiveKit 음성 세션에는 다음 세 가지 부분이 포함됩니다. 1. Mastra 서버는 LiveKit 액세스 토큰을 발행하고 Agent를 방으로 파견합니다. 디스패치는 Mastra Agent ID, Memory 스레드 및 리소스와 같은 메타데이터를 전달합니다. 2. LiveKit Agent 작업자(별도의 장기 실행 프로세스)가 작업을 수신하고 오디오 파이프라인을 실행합니다. 오디오는 WebRTC를 통해 브라우저와 작업자 간에 흐르며 결코 Mastra HTTP 서버를 통과하지 않습니다. 3. 사용자가 차례를 마칠 때마다 직원은 마스트라 Agent에게 전화를 겁니다.`stream()` 를 새 입력으로 실행하고 스트리밍된 텍스트를 음성으로 출력합니다. 사용자가 끼어들면 LiveKit이 스트림을 취소하고 Mastra가 생성을 중지합니다. 대화 기록은 Mastra Memory에 저장되므로 음성 세션과 문자 채팅이 하나의 스레드를 공유할 수 있습니다. ## 관련된 - [`@mastra/livekit`참조](https://mastra.zisheng.pro/ko/reference/voice/livekit) - [음성 대 음성](https://mastra.zisheng.pro/ko/guides/voice/speech-to-speech) - [Agent Memory](https://mastra.zisheng.pro/ko/docs/memory/overview) - [LiveKit Agent 문서](https://docs.livekit.io/agents/)