Kotlin SDK

ElevenAgents SDK: Android 앱용 맞춤형 대화형 음성 에이전트를 몇 분 만에 배포하세요.

ElevenAgents 작동 방식은 ElevenAgents 개요를 참고하세요.

설치

앱 수준 build.gradle 파일에 다음 종속성을 포함하여 Android 프로젝트에 ElevenLabs SDK를 추가하세요.

build.gradle.kts
dependencies {
// ElevenLabs Agents SDK (Android)
implementation("io.elevenlabs:elevenlabs-android:<latest>")
// Kotlin coroutines, AndroidX, etc., as needed by your app
}

이 SDK를 사용하는 Android 앱 예시는 여기에서 확인할 수 있습니다.

요구 사항

  • Android API 레벨 21(Android 5.0) 이상
  • API 호출을 위한 인터넷 권한
  • 음성 입력을 위한 마이크 권한
  • HTTPS 호출을 위한 네트워크 보안 구성

설정

매니페스트 구성

AndroidManifest.xml에 필요한 권한을 추가하세요.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

런타임 권한

Android 6.0(API 레벨 23) 이상에서는 런타임에 마이크 권한을 요청해야 합니다.

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
private fun requestMicrophonePermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
// Show explanation to the user
showPermissionExplanationDialog()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.RECORD_AUDIO),
MICROPHONE_PERMISSION_REQUEST_CODE
)
}
}
}

사용법

Application 클래스 또는 기본 액티비티에서 ElevenLabs SDK를 초기화하세요.

다음 중 하나로 대화 세션을 시작합니다.

  • 공개 에이전트: agentId 전달
  • 비공개 에이전트: 백엔드에서 프로비저닝한 conversationToken 전달(API 키를 클라이언트에 절대 노출하지 마세요).
import io.elevenlabs.ConversationClient
import io.elevenlabs.ConversationConfig
import io.elevenlabs.ConversationSession
import io.elevenlabs.ClientTool
import io.elevenlabs.ClientToolResult
// Start a public agent session (token generated for you)
val config = ConversationConfig(
agentId = "<your_public_agent_id>", // OR conversationToken = "<token>"
userId = "your-user-id",
// Optional callbacks
onConnect = { conversationId ->
// Called when the conversation is connected and returns the conversation ID. You can access conversationId via session.getId() too
},
onMessage = { source, messageJson ->
// Raw JSON messages from data channel; useful for logging/telemetry
},
onModeChange = { mode ->
// "speaking" | "listening" — drive UI indicators
},
onStatusChange = { status ->
// "connected" | "connecting" | "disconnected"
},
onCanSendFeedbackChange = { canSend ->
// Enable/disable thumbs up/down buttons for feedback reporting
},
onUnhandledClientToolCall = { call ->
// Agent requested a client tool not registered on the device
},
onVadScore = { score ->
// Voice Activity Detection score, range from 0 to 1 where higher values indicate higher confidence of speech
},
onAudioAlignment = { alignment ->
// Character-level timing data for synchronized text display
val chars = alignment["chars"] as? List<*>
val startTimes = alignment["char_start_times_ms"] as? List<*>
val durations = alignment["char_durations_ms"] as? List<*>
Log.d("ExampleApp", "Audio alignment: $chars")
},
// List of client tools the agent can invoke
clientTools = mapOf(
"logMessage" to object : ClientTool {
override suspend fun execute(parameters: Map<String, Any>): ClientToolResult {
val message = parameters["message"] as? String
Log.d("ExampleApp", "[INFO] Client Tool Log: $message")
return ClientToolResult.success("Message logged successfully")
}
}
),
)
// In an Activity context
val session: ConversationSession = ConversationClient.startSession(config, this)

ElevenAgents에는 마이크 액세스가 필요합니다. 특히 런타임 권한이 필요한 Android 6.0 이상에서는 대화가 시작되기 전에 앱 UI에서 권한을 설명하고 요청하는 것이 좋습니다.

서버에서 expects_response=false로 도구를 구성한 경우, 에이전트에 도구 결과를 다시 보내지 않으려면 execute에서 null을 반환하세요.

공개 및 비공개 에이전트

  • 공개 에이전트 (인증 없음): ConversationConfig에서 agentId로 초기화합니다. SDK는 기기에서 API 키 없이 ElevenLabs에 대화 토큰을 요청합니다.
  • 비공개 에이전트 (인증): ConversationConfig에서 conversationToken으로 초기화합니다. 서버는 ElevenLabs API 키를 사용하여 ElevenLabs에 대화 토큰을 요청합니다.
클라이언트에 API 키를 절대 포함하지 마세요. 쉽게 추출되어 악의적으로 사용될 수 있습니다.

클라이언트 도구

에이전트가 기기의 로컬 기능을 호출할 수 있도록 클라이언트 도구를 등록하세요.

val config = ConversationConfig(
agentId = "<public_agent>",
clientTools = mapOf(
"logMessage" to object : io.elevenlabs.ClientTool {
override suspend fun execute(parameters: Map<String, Any>): io.elevenlabs.ClientToolResult? {
val message = parameters["message"] as? String ?: return io.elevenlabs.ClientToolResult.failure("Missing 'message'")
android.util.Log.d("ClientTool", "Log: $message")
return null // No response needed for fire-and-forget tools
}
}
)
)

에이전트가 client_tool_call을 실행하면 SDK는 일치하는 도구를 실행하고 client_tool_result로 응답합니다. 도구가 등록되지 않은 경우 onUnhandledClientToolCall이 호출되고, 응답이 예상되는 경우 에이전트에 실패 결과가 반환됩니다.

콜백 개요

  • onConnect - WebRTC 연결이 설정될 때 호출됩니다. 대화 ID를 반환합니다.
  • onMessage - 새 메시지를 수신할 때 호출됩니다. 사용자 음성의 임시 또는 최종 전사, LLM이 생성한 응답 또는 디버그 메시지일 수 있습니다. 소스("ai" 또는 "user")와 원시 JSON 메시지를 제공합니다.
  • onModeChange - 대화 모드가 변경될 때 호출됩니다. 에이전트가 말하고 있는지("speaking") 또는 듣고 있는지("listening") 표시하는 데 유용합니다.
  • onStatusChange - 대화 상태가 변경될 때 호출됩니다("connected", "connecting", 또는 "disconnected").
  • onCanSendFeedbackChange - 피드백 전송 가능 여부가 변경될 때 호출됩니다. 피드백 버튼을 활성화/비활성화합니다.
  • onUnhandledClientToolCall - 에이전트가 기기에 등록되지 않은 클라이언트 도구를 요청할 때 호출됩니다.
  • onVadScore - 음성 활동 감지 점수가 변경될 때 호출됩니다. 범위는 0에서 1이며, 값이 높을수록 음성에 대한 신뢰도가 높음을 나타냅니다.
  • onAudioAlignment - 에이전트 음성의 문자 수준 타이밍 정보를 제공하는 오디오 정렬 데이터를 수신할 때 호출됩니다.

모든 클라이언트 이벤트가 에이전트에 기본적으로 활성화되어 있는 것은 아닙니다. 콜백을 활성화했지만 이벤트가 수신되지 않는다면 ElevenLabs 에이전트에서 해당 이벤트가 활성화되어 있는지 확인하세요. ElevenLabs 대시보드의 에이전트 설정에서 “Advanced” 탭을 통해 확인할 수 있습니다.

메서드

startSession

startSession 메서드는 WebRTC 연결을 시작하고 마이크를 사용해 ElevenLabs Agents 에이전트와 통신을 시작합니다.

공개 에이전트

공개 에이전트(즉, 인증이 활성화되지 않은 에이전트)의 경우 agentId만 필요합니다. 에이전트 ID는 ElevenLabs UI에서 확인할 수 있습니다.

val session = ConversationClient.startSession(
config = ConversationConfig(
agentId = "your-agent-id"
),
context = this
)
비공개 에이전트

비공개 에이전트의 경우 ElevenLabs API에서 얻은 conversationToken을 전달해야 합니다. 이 토큰을 생성하려면 ElevenLabs API 키가 필요합니다.

conversationToken은 10분 동안 유효합니다.
// Server-side token generation (Node.js example)
app.get("/conversation-token", yourAuthMiddleware, async (req, res) => {
const response = await fetch(
`https://api.elevenlabs.io/v1/convai/conversation/token?agent_id=${process.env.AGENT_ID}`,
{
headers: {
// Requesting a conversation token requires your ElevenLabs API key
// Do NOT expose your API key to the client!
"xi-api-key": process.env.ELEVENLABS_API_KEY,
},
}
);
if (!response.ok) {
return res.status(500).send("Failed to get conversation token");
}
const body = await response.json();
res.send(body.token);
});

그런 다음 토큰을 startSession 메서드에 전달하세요. 비공개 에이전트에는 conversationToken만 필요합니다.

// Get conversation token from your server
val conversationToken = fetchConversationTokenFromServer()
// For private agents, pass in the conversation token
val session = ConversationClient.startSession(
config = ConversationConfig(
conversationToken = conversationToken
),
context = this
)

선택적으로 대화에서 사용자를 식별하기 위한 사용자 ID를 전달할 수 있습니다. 자체 고객 식별자를 사용할 수 있습니다. 이 값은 서버로 전송되는 대화 시작 데이터에 포함됩니다.

val session = ConversationClient.startSession(
config = ConversationConfig(
agentId = "your-agent-id",
userId = "your-user-id"
),
context = this
)

endSession

대화를 수동으로 종료하는 메서드입니다. 연결을 해제하고 대화를 종료합니다.

session.endSession()

sendUserMessage

활성 대화 중 에이전트에 텍스트 메시지를 보냅니다. 에이전트의 응답을 유발합니다.

session.sendUserMessage("Hello, how can you help me?")

sendContextualUpdate

응답을 유발하지 않는 상황별 정보를 에이전트에 전송합니다.

session.sendContextualUpdate(
"User navigated to the profile page. Consider this for next response."
)

sendFeedback

대화 품질에 대한 피드백을 제공합니다. 이는 에이전트 성능을 개선하는 데 도움이 됩니다. 피드백이 허용될 때 onCanSendFeedbackChange를 사용하여 좋아요/싫어요 UI를 활성화하세요.

// Positive feedback
session.sendFeedback(true)
// Negative feedback
session.sendFeedback(false)

sendUserActivity

방해를 방지하기 위해 에이전트에 사용자 활동을 알립니다. 사용자가 앱을 활발히 사용 중이고 에이전트가 말하기를 일시 중지해야 할 때, 예를 들어 사용자가 채팅에 입력 중일 때 유용합니다.

이 신호를 받은 후 에이전트는 약 2초 동안 말하기를 일시 중지합니다.

session.sendUserActivity()

getId

대화 ID를 가져옵니다.

val conversationId = session.getId()
Log.d("Conversation", "Conversation ID: $conversationId")
// e.g., "conv_123"

음소거/음소거 해제

session.toggleMute()
session.setMicMuted(true) // mute
session.setMicMuted(false) // unmute

session.isMuted를 관찰하여 UI 라벨을 “음소거”와 “음소거 해제” 사이에서 업데이트하세요.

속성

status

현재 대화 상태를 가져옵니다.

val status = session.status
Log.d("Conversation", "Current status: $status")
// Values: DISCONNECTED, CONNECTING, CONNECTED

ProGuard / R8

축소/난독화를 사용하는 경우 Gson 모델과 LiveKit이 유지되도록 하세요. 예시 규칙(필요에 따라 조정):

-keep class io.elevenlabs.** { *; }
-keep class io.livekit.** { *; }
-keepattributes *Annotation*

문제 해결

  • 런타임에 마이크 권한이 부여되었는지 확인하세요.
  • 재연결이 멈추면 앱에서 session.endSession()을 호출하고 재연결 전에 새 세션 인스턴스를 시작하는지 확인하세요.
  • 에뮬레이터에서는 오디오 입력/출력 경로가 작동하는지 확인하세요. 실제 기기가 일반적으로 더 안정적으로 작동합니다.

구현 예시

구현 예시는 ElevenLabs Android SDK 리포지토리의 예제 앱을 참조하세요. 이 앱은 다음을 보여 줍니다.

  • 탭 한 번으로 연결/연결 해제
  • 말하기/듣기 표시기
  • UI 활성화/비활성화 기능이 있는 피드백 버튼
  • sendUserActivity()를 통한 입력 표시기
  • 입력란에서 보내는 상황별 및 사용자 메시지
  • 마이크 음소거/음소거 해제 버튼