AI 음성 에이전트
대시보드 에이전트
코드 없이 대시보드에서 AI 음성 에이전트를 만드는 방법. 실행 주체·설정 반영 시점·사용 가능한 도구·키패드 입력 처리를 설명합니다.
대시보드 에이전트
한국AI통신에서 AI 음성 에이전트를 만드는 방법은 두 가지입니다.
| 대시보드 에이전트 | Voice Agent SDK | |
|---|---|---|
| 만드는 방법 | 대시보드에서 설정 | Python 코드 작성 |
| 실행 | 한국AI통신이 실행 | 직접 서버에서 상시 실행 |
| 도구 | 기본 도구 + MCP 연결 | 코드로 자유롭게 정의 |
| 적합한 경우 | 예약 접수·안내·상담 연결 | 자체 시스템과 깊게 연동 |
이 문서는 대시보드 에이전트 를 다룹니다.
누가 실행하나요
한국AI통신이 실행합니다. 전화가 걸려 오면 저장된 설정으로 에이전트 세션이 시작되고, 통화가 끝나면 정리됩니다. 별도로 서버를 띄우거나 프로그램을 상시 실행할 필요가 없습니다.
SDK 문서의 agent.serve() 는 에이전트를 직접 호스팅할 때 쓰는 방법입니다. 대시보드에서 만든
에이전트에는 필요하지 않습니다.
설정은 언제 반영되나요
다음 통화부터 적용됩니다. 진행 중인 통화에는 영향을 주지 않습니다.
프롬프트·음성·모델을 바꾸고 저장한 뒤 곧바로 전화를 걸면 새 설정으로 응답합니다.
사용할 수 있는 도구
에이전트 상세 → 도구 탭에서 확인할 수 있습니다.
| 도구 | 설명 | 켜는 곳 |
|---|---|---|
| 통화 종료 | 대화를 마치고 전화를 끊습니다 | 항상 켜짐 |
| DTMF 전송 | 상대방 ARS 에 키패드 신호를 보냅니다 | 항상 켜짐 |
| 지식 검색 | 등록한 문서에서 답을 찾습니다 | 「지식」 탭 |
| 통화 전환 | 담당자에게 연결합니다 | 「도구」 탭 → 통화 전환 |
| 외부 도구 | 직접 운영하는 MCP 서버의 도구를 호출합니다 | 「도구」 탭 → 외부 도구 연결 |
자체 서버의 함수를 통화 중에 호출하려면 외부 도구 연결(MCP) 을 사용하세요. SDK 의
@agent.tool 에 해당하는 기능을 대시보드에서 직접 정의할 수는 없습니다.
발신자의 키패드 입력 받기
전화 음질에서는 숫자 음성 인식이 자주 틀립니다. 연락처·주문번호처럼 정확해야 하는 값은 키패드로 받는 편이 안전합니다.
발신자가 누른 키는 별도 설정 없이도 에이전트에게 전달됩니다. 다만 언제 전달할지는 정해 두는 편이 정확합니다 — 에이전트 상세 → 대화 탭 → 「통화 흐름」 카드의 「키패드 입력 설정」입니다.
| 설정 | 언제 전달되나 | 쓰는 곳 |
|---|---|---|
| 종료 키 | 그 키를 누르는 즉시 | 대부분. 자리수가 매번 달라도 됩니다 |
| 자리수 | 그만큼 눌리는 즉시 | 받을 자리수가 항상 같을 때 |
| 켜지 않음 | 누르기를 멈추고 잠시 뒤 | 자리수를 모르고 안내도 어려울 때 |
둘을 같이 켜면 먼저 오는 쪽이 전달합니다.
종료 키 (권장)
# 또는 * 를 고릅니다. 발신자가 그 키를 누르면 그때까지 누른 값이 전달되고, 이 키
자체는 값에 포함되지 않습니다.
1234# → 1234
900101# → 900101자리수와 무관하게 정확합니다. 한 통화에서 차량번호 4자리도 받고 생년월일 6자리도 받는 구성이라면 이것만 켜면 됩니다.
시스템 프롬프트에는 안내 문장을 넣어 주십시오.
연락처는 음성으로 받지 말고 키패드로 받으세요.
"연락처를 누르시고 마지막에 우물정자를 눌러 주세요" 라고 안내하십시오.자리수 고정
받을 자리수가 매번 같을 때만 채우십시오. 비워 두면 자리수로는 확정하지 않습니다.
자리수 4로 정해 둔 경우
1234 → 1234 (네 번째 키에서 바로)
12 → 12 (멈추면 잠시 뒤)정한 자리수보다 적게 누르고 멈추는 것은 문제가 없습니다. 그래서 "1번 요금 안내, 2번 예약" 같은 한 자리 메뉴 선택과 같이 써도 됩니다.
정한 자리수보다 많이 누르면 남는 입력은 다음 묶음으로 넘어갑니다. 4자리로 정해 둔 상태에서
생년월일 6자리를 누르면 900101 이 9001 + 01 로 나뉘어 전달됩니다. 오류로 처리되지 않고 값만
달라집니다. 한 통화에서 받는 자리수가 일정하지 않다면 자리수를 비우고 종료 키만 쓰십시오.
설정을 켜지 않을 때
입력이 잠시 끊길 때까지 기다렸다가 전달합니다. 발신자가 천천히 누르면 나누어 도착할 수 있으므로, 프롬프트에 모아서 확인하라고 지시해 두십시오.
이 경우 「다 모일 때까지 기다리라」는 지시가 필요합니다. 이 문장이 없으면 에이전트가 중간에 끼어들어 "현재까지 010이 입력되었습니다" 같은 응답을 반복할 수 있습니다.
키패드 입력이 들어오면 숫자를 모아 두었다가, 11자리가 모이면
"눌러 주신 번호는 010-1234-5678 맞으실까요?" 처럼 전체 번호를 복창하십시오.
11자리가 안 모였으면 아무 말도 하지 말고 기다리십시오.발신자가 말이 없을 때
전화를 받고도 아무 말이 없는 경우를 위해 무응답 처리 를 켤 수 있습니다. 에이전트 상세 → 대화 탭 → 「통화 흐름」 카드입니다.
| 항목 | 범위 |
|---|---|
| 조용할 때 기다리는 시간 | 3 ~ 120초 |
| 다시 여쭤보는 횟수 | 0 ~ 5회 |
| 다시 여쭤볼 때 쓸 말 | 문구 입력 |
설정한 시간만큼 양쪽 다 말이 없으면 에이전트가 대화 상태를 보고 판단합니다. 접수가 남아 있으면 다시 여쭙고, 이미 마무리된 대화라면 통화를 종료합니다.
마무리 인사 뒤 전화가 끊기지 않는다면 이 기능을 켜 보세요. 인사만 하고 통화가 남아 있는 상태를 정리해 줍니다.
첫 인사 전 대기
발신 통화에서 상대가 받은 뒤 첫 인사를 시작하기 전에 기다릴 시간을 정할 수 있습니다. 에이전트 상세 →
대화 탭 → 「통화 흐름」 카드의 「첫 인사 전 대기」에서 정하거나, API 의 beginMessageDelayMs 로
설정합니다.
| 항목 | 값 |
|---|---|
| 범위 | 0 ~ 5,000ms |
| 기본값 | 0(바로 인사) |
| 적용 대상 | 「에이전트가 먼저 인사하기」를 켠 에이전트의 발신 통화 |
수신 통화에는 적용되지 않습니다.
통화 시간 제한
통화가 너무 길어지지 않게 최대 통화 시간 을 정할 수 있습니다. 에이전트 상세 → 대화 탭 →
「통화 흐름」 카드에서 「최대 통화 시간 제한」을 켜거나, API 의 maxDurationSeconds 로 설정합니다.
| 항목 | 값 |
|---|---|
| 범위 | 10 ~ 7,200초 |
| 기본값 | 꺼짐 |
| 계측 시작 | 수신: 받은 순간 · 발신: 상대가 받은 순간 |
시간이 되면 대화 중이어도 통화를 끊습니다. 끊기 전에 안내 멘트는 나가지 않으므로, 마무리 안내가 필요하면 프롬프트에 통화를 N초 안에 마치라는 지시를 함께 적어 두십시오.
이 제한은 에이전트와 나누는 대화에만 걸립니다. 담당자에게 전환된 뒤의 통화에는 적용되지 않습니다.
이 제한으로 끊긴 통화는 통화 상세의 종료 사유가 「에이전트 최대 통화 시간 도달」로 표시됩니다.
끼어들기와 발화 감지
에이전트가 말하는 도중 발신자가 말하면 안내를 멈추고 듣습니다(끼어들기). 누가 「발신자가 말했다」를 판단하느냐가 모드에 따라 다릅니다.
| 구성 | 기본 판단 주체 | 조절 항목 |
|---|---|---|
| 실시간 모델(모델 음성·외부 TTS) | 실시간 모델 서버 | 없음 |
| STT + 텍스트 모델(파이프라인) | 한국AI통신 음성 감지(VAD) | 「대화 흐름」 카드 |
| GPT-Live(전이중) | GPT-Live 모델 자신 | 없음 |
| ElevenLabs Realtime | ElevenLabs 서버 | 없음 |
GPT-Live 는 듣는 동시에 말하는 전이중(full duplex) 모델이라, 발신자가 말을 얹어도 곧바로 멈추지 않고 모델이 스스로 멈출지 이어 갈지 판단합니다. 짧은 맞장구("네", "음")처럼 끼어들 뜻이 아닌 말에는 말을 이어 갈 수 있습니다. 아래 「한국AI통신에서 발화 감지」는 GPT-Live 에서는 쓰지 않습니다.
실시간 모델의 서버 측 감지는 지연이 가장 짧지만 민감도를 조절할 수 없고, 전화 회선의 작은 잡음에도 안내가 끊겼다가 처음부터 다시 시작될 수 있습니다. 이 증상이 있으면 에이전트 상세 → 모델 · 음성 탭 → 「대화 흐름」 카드에서 「한국AI통신에서 발화 감지」 를 켜십시오. 켜면 실시간 모델에서도 한국AI통신이 음성 감지로 발화와 끼어들기를 판단하고, 아래 항목을 조절할 수 있습니다.
| 항목 | 뜻 |
|---|---|
| 끼어들기 허용 | 끄면 에이전트가 말하는 동안 발신자 음성으로 안내를 멈추지 않습니다 |
| 끼어들기 최소 길이 | 이보다 짧은 소리는 끼어들기로 보지 않습니다(기본 0.5초) |
| 감지 민감도 · 최소 발화 길이 | 음성으로 인식할 문턱. 잡음이 많으면 민감도를 올리십시오 |
| 발화 끝 최소·최대 대기 | 발신자 말이 끝났다고 판단하기까지 기다리는 시간 |
첫 인사는 끝까지 말하기 — 발신 통화에서 상대가 받자마자 하는 "여보세요"에 첫 인사가 끊기지 않게 합니다. 대화 탭 → 「통화 흐름」 카드의 「에이전트가 먼저 인사하기」 아래에 있으며, 「한국AI통신에서 발화 감지」가 켜져 있거나 파이프라인 구성일 때 동작합니다.
실시간 모델에서는 인사 중에 들린 상대의 말("네", "여보세요")을 버리지 않습니다. 인사가 끝나면 그 말에 이어서 응답하므로 상대가 같은 말을 되풀이하지 않아도 됩니다. 끼어들기 허용을 끈 경우에도 같은 방식으로, 에이전트가 말을 마친 뒤 그동안 들린 말에 응답합니다.
전화 회선 잡음이 문제라면 실시간 모델 카드의 고급 설정에서 입력 노이즈 감소 를 far_field 로
두는 것도 함께 시도해 보십시오. 모델이 듣는 오디오의 잡음을 줄입니다.
통화 전환
담당자별로 **매주 연결 가능 시간(한국시간)**을 켜고 요일과 시간을 지정할 수 있습니다. 시작 시각은 포함하고 종료 시각은 포함하지 않습니다. 선택하지 않은 요일과 제외 날짜에는 그 담당자에게 연결하지 않습니다. 공휴일은 자동 추가되지 않으며, 기존에 지정한 전체 연결 기간도 함께 적용됩니다. 시간 밖에서는 전환을 시작하지 않고 AI 상담을 계속합니다.
담당자에게 연결하려면 도구 탭 → 통화 전환에서 대상을 등록합니다. 에이전트에게는 등록한 이름만 보이고 번호는 노출되지 않습니다.
전환 안내(웜 트랜스퍼)를 켜면 담당자가 전화를 받은 직후, 발신자에게는 들리지 않는 한 문장을 먼저 들려줍니다. 문구에는 두 가지 변수를 쓸 수 있습니다.
| 변수 | 채워지는 값 |
|---|---|
{발신번호} | 걸려 온 번호 |
{사유} | 에이전트가 통화에서 파악한 문의 유형 |
예: {발신번호} 고객님, {사유} 문의입니다
안내 문구 전체를 에이전트가 작성하지는 않습니다. 고정 문구에 {사유} 만 채워집니다. 전환 결과를
시스템에서 받으려면 전환 웹훅을 사용하세요.
대기 시간과 대기 중 소리
연결되는 동안 발신자에게 들리는 소리와, 담당자를 기다리는 시간을 같은 화면에서 정합니다.
| 설정 | 값 | 기본 |
|---|---|---|
| 대기 시간 | 10~60초 | 30초 |
| 연결되는 동안 발신자에게 | 대기 음악 · 통화 연결음 · 무음 | 대기 음악 |
정한 시간 안에 담당자가 받지 않으면 전환이 실패하고 발신자의 통화도 종료됩니다. 에이전트가 다시 이어받지는 않습니다. 담당자가 통화 중이거나 전화를 거절하면 대기 시간을 채우지 않고 그 시점에 바로 종료됩니다.
「무음」은 발신자가 통화가 끊긴 것으로 오해하기 쉽습니다. 대기가 몇 초 이상 이어지는 구성이라면 대기 음악이나 통화 연결음을 권합니다.
통화 중 전사·키패드 받기
통화가 이어지는 동안 양쪽이 하는 말과 상대가 누른 키를 실시간으로 받을 수 있습니다. 에이전트마다 받을 이벤트를 고르며, 기본값은 아무것도 고르지 않은 꺼짐입니다. 추가 요금은 없습니다.
에이전트 상세 → 대화 탭 → 「통화 중 이벤트」 카드에서 고르거나, REST 의
PATCH /agents/{agentId} 에 liveEvents.events 를 보냅니다.
{ "liveEvents": { "events": ["transcript.final", "transcript.partial", "dtmf.received"] } }| 고르는 이벤트 | 콘솔 항목 | 뜻 |
|---|---|---|
transcript.final | 확정된 말 | 한 발화의 확정 텍스트 |
transcript.partial | 말하는 도중의 텍스트 | 말이 끝나기 전의 누적 텍스트 |
dtmf.received | 누른 키 | 상대가 누른 키 하나 |
dtmf.sent | AI가 보낸 키 | AI가 통화 연결로 전송한 키 하나 |
- 하나라도 고르면
stream.started·stream.ended가 함께 옵니다. - 수정할 때는 보낸 목록으로 통째로 바뀝니다. 빈 목록이나
null을 보내면 꺼집니다. - 설정은 다음 통화부터 반영됩니다.
받는 방법
| 방법 | REST | 필요한 권한 |
|---|---|---|
| 스트림(SSE) | GET /calls/{callId}/live-events/stream | read:transcripts |
| 목록(페이지) | GET /calls/{callId}/live-events | read:transcripts |
curl -N https://api.claw-ops.com/v1/accounts/$ACCOUNT_ID/calls/$CALL_ID/live-events/stream \
-H "Authorization: Bearer $CLAWOPS_API_KEY"- 스트림은 통화가 끝나면
stream.ended를 보낸 뒤 닫힙니다. - 연결이 끊기면 마지막으로 받은
id를Last-Event-ID헤더에 넣어 다시 연결합니다. 그 뒤 이벤트부터 이어서 옵니다. - 이벤트가 없는 동안에는 15초마다 ping 주석(
: ping)이 옵니다. - 목록은
?after={id}&limit=로 이어서 받고,hasMore가false면 끝입니다.
이벤트
모양은 통화 이벤트와 같은 { id, event, timestamp, detail } 입니다.
event | detail | 뜻 |
|---|---|---|
stream.started | 없음 | 이벤트 기록이 시작됐습니다 |
transcript.partial | utteranceId, role, text | 말하는 도중의 텍스트(지금까지 누적) |
transcript.final | utteranceId, role, text | 한 발화의 확정 텍스트 |
dtmf.received | digit | 상대가 누른 키 하나 |
dtmf.sent | digit | AI가 통화 연결로 전송한 키 하나. 상대 ARS 수신 확인은 아님 |
stream.ended | reason | 마지막 이벤트 |
role은user(상대방) 또는agent(에이전트)입니다. 수신·발신 통화 모두 같습니다.transcript.partial의text는 그 발화의 지금까지 누적 문장입니다. 같은utteranceId의 표시를 통째로 바꾸십시오.transcript.final이 오면 같은utteranceId의 표시를 확정 텍스트로 바꾸십시오. 말이 끊긴 발화는 마지막 조각보다 짧을 수 있습니다.dtmf.received는 키를 누를 때마다 하나씩, 누른 값 그대로 옵니다.stream.ended의reason은completed(통화 종료),runner_lost(종료 기록 없이 끊김),no_events(이 통화에는 이벤트가 없음) 중 하나입니다.
id: 18341
event: transcript.final
data: {"id":"18341","event":"transcript.final","timestamp":"2026-10-21T06:50:59.300Z","detail":{"utteranceId":"u3","role":"agent","text":"평일 오전 9시부터 오후 6시까지입니다."}}모드별 차이
에이전트 말의 조각은 모든 모드에서 말하기 시작하면 바로 옵니다. 상대방 말의 조각은 모드에 따라 다릅니다.
| 구성 | 상대방 말의 transcript.partial |
|---|---|
| 실시간 모델(모델 음성·외부 TTS) | 받아쓰기 모델에 따라 다릅니다(아래) |
| STT + 텍스트 모델(파이프라인) | 오지 않습니다(확정만 옵니다) |
| GPT-Live | 말하는 도중에 옵니다 |
| Grok Voice | 말하는 도중에 옵니다 |
| ElevenLabs Realtime | 오지 않습니다(확정만 옵니다) |
상대방 말 받아쓰기 모델(실시간 모델)
실시간 모델은 상대방 말을 별도 모델로 받아씁니다. 이 텍스트가 role: "user" 전사와 대화 기록에 쓰입니다.
모델이 대화를 알아듣는 방식은 바뀌지 않습니다.
모델은 모델 · 음성 탭 → 실시간 모델 카드의 고급 설정, 또는 API 의 llm.input_transcription_model 로 고릅니다.
언어는 에이전트 언어(language)를 따릅니다.
| 모델 | 상대방 말의 transcript.partial | 받는 힌트 |
|---|---|---|
gpt-4o-mini-transcribe(기본) | 말이 끝난 뒤 확정과 거의 함께 | 힌트 문장(input_transcription_prompt) |
gpt-4o-transcribe | 말이 끝난 뒤 확정과 거의 함께 | 힌트 문장 |
whisper-1 | 확정과 함께 | 힌트 문장 |
gpt-transcribe | 말이 끝난 뒤 확정과 거의 함께 | 단어 힌트(input_transcription_keywords) |
gpt-live-transcribe | 말하는 도중 | 단어 힌트 |
gpt-realtime-whisper | 말하는 도중 | 지연(input_transcription_delay) |
- 힌트 문장은 1,024자까지 받습니다.
- 단어 힌트는 쉼표나 줄바꿈으로 구분하며, 최대 100개·각 50자까지 받습니다.
- 고른 모델이 받지 않는 힌트를 함께 보내면 API 가
400을 돌려줍니다. - 받아쓰기 요금은 고른 모델에 따라 달라지며, 에이전트 화면의 1분 가격에 포함됩니다.
{
"llm": {
"provider": "openai-realtime",
"model": "gpt-realtime-2.1",
"voice": "marin",
"input_transcription_model": "gpt-live-transcribe",
"input_transcription_keywords": "상담원 연결, 샵 버튼"
}
}보관
| 이벤트 | 보관 기간 |
|---|---|
transcript.partial | 1일 |
| 그 밖의 이벤트 | 30일 |
통화 기록에서 확인하기
에이전트 통화의 통화 기록 → 통화 상세 에는 「이번 통화의 요청」과 아래 이벤트가 표시됩니다. 「이번 통화의 요청」은 그 통화에 실린 CallContext 의 지시와 변수이며, 30일 동안 보관합니다. 이벤트는 통화 이벤트 조회 API 로도 내려갑니다.
| 이벤트 | detail | 뜻 |
|---|---|---|
managed_agent.max_duration_reached | limitS | 최대 통화 시간이 되어 통화를 끊었습니다 |
managed_agent.first_audio_timeout | timeoutMs | 착신에서 첫 인사 음성을 기다리다 그대로 받았습니다 |
agent.setup_aborted_caller_termination | 없음 | 에이전트가 준비되기 전에 상대가 끊었습니다 |
agent.bridge_join_failed | 없음 | 에이전트 음성을 통화에 연결하지 못했습니다 |
managed_agent.mcp_connected | connectionName, toolCount | 외부 도구를 준비했습니다 |
managed_agent.mcp_connection_failed | connectionName, errorCode | 외부 도구를 준비하지 못했습니다 |
managed_agent.mcp_tool_called | connectionName, toolName, durationMs, isError | 외부 도구를 호출했습니다. 인자와 결과는 남기지 않습니다 |
API·MCP 로 관리하기
에이전트 목록·조회·수정은 REST API 와 MCP 도구로도 할 수 있습니다. 여기서 얻은 에이전트 ID 를
발신 요청의 AgentId 에 넣으면 그 에이전트로 전화를 겁니다.
| 작업 | REST | MCP 도구 | 필요한 권한 |
|---|---|---|---|
| 목록 | GET /agents | list_agents | read:agents |
| 조회 | GET /agents/{agentId} | get_agent | read:agents |
| 수정 | PATCH /agents/{agentId} | update_agent | write:agents |
list_agents 는 목록 요약만 돌려줍니다(프롬프트는 앞부분만). 프롬프트 전문과 실행 설정은
get_agent 로 조회하십시오.
update_agent 로 바꿀 수 있는 항목은 이름·프롬프트(instructions)·먼저 인사하기(greeting)·
최대 통화 시간(maxDurationSeconds, null 이면 제한 없음)·첫 인사 전 대기(beginMessageDelayMs)·모델·음성입니다. 지정한 항목만 바뀌고, 바뀐 설정은 다음 통화부터 반영됩니다. 그 밖의 실행 설정은
대시보드나 REST 의 configuration 으로 바꾸십시오.
기존에 연결된 앱은 재연결해야 이 도구가 보입니다. 권한은 연결할 때 확정되므로, 이 도구가
추가되기 전에 연결한 앱은 목록에서 받지 못합니다(에러가 아니라 도구가 없는 상태로 동작합니다).
update_agent 는 쓰기 권한이라 연결할 때 write:agents 를 함께 허용해야 합니다.