채널 연결 및 통신
Service Agent가 카카오 i 서버로 요청(Event)을 보내기 위해서는 HTTP/2 연결을 통해 Event 채널 연결 및 채널 통신을 진행해야 합니다. 채널 연결은 Service Agent가 카카오 i 서버로부터 명령(Instruction)을 받기 위해 HTTP/2 연결을 설정하는 작업이며, 채널 통신은 HTTP/2 연결을 통해 Service Agent와 카카오 i 서버가 요청(Event 메시지)과 응답(Instruction 메시지)을 주고받는 작업을 의미합니다. Service Agent Interaction을 위한 인터페이스 별 자세한 설명은 Service Agent Interface를 참고하시기 바랍니다.
그림채널 연결 및 통신
안내
채널을 구성하기 위해서는 먼저 HTTP/2, JSON, 멀티파트(Multipart)를 숙지해야 합니다.
채널 연결
Service Agent는 디바이스 전원이 켜지면 카카오 i 서버와 단일 HTTP/2 연결을 생성해야 합니다.
연결 프로세스
-
다음의 채널 연결 요청을 통해 Down Channel을 설정합니다. 요청이 성공했을 경우에는 Down Channel이 생성되며, Down Channel은 Half-closed(단방향 통신) 상태를 유지합니다. heartbeat 옵션에 따라 Down Channel로 heartbeat Instruction을 keepalive 목적으로 전송합니다.
안내
요청은 Service Agent가 카카오 i 서버와 연결되는 10초 이내에 진행됩니다.코드예제채널 연결 생성
:method = {verb} :scheme = https :path = /{API version}/instructions?heartbeat={on or off} authorization = Bearer {access token} kakaoi-agent = {kakaoi agent} kakaoi-user = {kakao developers 앱의 app user id} x-anchor = {unique device id} content-type = multipart/form-data; boundary={boundary term}
표downchannel stream Query Parameters
파라미터 타입 필수 여부 설명 heartbeat String 선택
{on or off}
: downchannel 연결 후 keepalive 목적의 heartbeat Instruction 전송 옵션 -
Service Agent 구성 요소의 상태를 카카오 i 서버와 동기화하기 위해서는 연결된 Down Channel에서 POST 요청을 하여 SynchronizeState Event를 전송합니다.
주의
새로운 Channel 연결을 요청하지 말고, 반드시 기존 연결된 채널에서 해당 작업을 수행해야 합니다.코드예제SynchronizeState Event 전송
{ :method = {verb} :scheme = https :path = /{API version}/instructions authorization = Bearer {access token} kakaoi-agent = {kakaoi agent} kakaoi-user = {kakao developers 앱의 app user id} x-anchor = {unique device id} content-type = multipart/form-data; boundary={boundary term} { "service": { "capabilities": [{...}, {...}, {...}] }, "state": [, , ,], "event": { "header": { "type": "{STRING}", "messageId": "{STRING}" }, "body": { } } } --{boundary term}-- }
-
Service Agent가 응답(Instruction)을 받으면 위의 Event 채널 스트림을 닫습니다.
-
Service Agent가 카카오 i 서버로 Event 메시지를 전송하고, 카카오 i 서버로부터 Instruction 메시지를 정상적으로 수신하는지 확인합니다.
- Service Agent와 카카오 i 서버의 HTTP2 연결은 10개의 동시 스트림만 지원합니다.
- 여기에는 Event 스트림, Down Channel, Ping이 포함됩니다.
- Service Agent와 카카오 i 서버의 연결 수명 동안 카카오 i 서버와 Service Agent 간 열린 상태로 유지되어야 하는 Down Channel 스트림이 필요하므로 읽기 timeout은 최소 60분으로 설정합니다.
HTTP/2 연결 실패 시
HTTP/2 연결이 실패한 경우에는 Ping and Timeout과 Server-initiated Disconnects 동작이 진행됩니다.
Ping and Timeout
Service Agent는 다음 작업 중 하나를 선택하여 수행한 뒤, 실패한 Ping에서의 연결을 닫고 새 연결을 즉시 생성합니다.
- 연결이 유휴(idle) 상태일 때, 카카오 i 서버에 Ping 프레임을 3분마다 전송합니다.
- 연결이 유휴(idle) 상태일 때, 3분마다
/ping
에 GET 요청을 진행합니다. (:path =/ping
)
Server-initiated Disconnects
카카오 i 서버가 Service Agent와 연결 해제를 시작하면 Service Agent는 다음의 작업을 수행합니다.
Service Agent는 새로운 연결을 열고, 이를 통해 새로운 요청을 라우팅합니다.
열려있는 모든 요청을 처리하고, 해당 스트림이 정상적으로 닫힌 후에 이전 연결을 닫습니다.
연결이 해제되기 전에 설정된 모든 스트림 URL에 대한 연결을 유지합니다.
- 서버에서 시작된 연결 끊기가 발생하기 전에 재생되는 스트림은 바이트를 사용할 수 있는 한 계속 재생해야 합니다.
채널 통신
Service Agent와 카카오 i 서버 간 연결 설정이 완료되면, Service Agent는 HTTP/2로 인코딩된 Multipart 메시지를 사용하여 카카오 i 서버와 통신합니다. Multipart 메시지의 경우의 <The First Part>는 JSON 형식의 Event로 구성되며, 마이크에서 캡처한 오디오 파일이 있을 경우에는 <The Second Part>에 구성됩니다.
Service Agent와 카카오 i 서버 간 통신은 Service Agent가 카카오 i 서버로 전송하는 Event 메시지와 카카오 i 서버가 Service Agent로 전송하는 Instruction 메시지를 통해 수행됩니다.
그림채널 통신
Request
Service Agent와 카카오 i 서버 간 채널 통신에 필요한 Request Protocol과 Request Header는 다음과 같습니다.
Request Protocol
코드예제채널 통신 Request Protocol
:method = {{verb}}
:scheme = https
:path = /{API version}/{{events or instructions}}
파라미터 | 설명 |
---|---|
method | - POST: 모든 Event는 Events path를 통해 카카오 i 서버로 전송 - GET: Instruction Path를 사용하여 Down Channel을 설정 |
scheme | 카카오 i 서버에 접근하기 위한 구성은 https 로 고정 |
path | - /v1/events : Event- /v1/instructions : Instruction |
Request Header
코드예제채널 통신 Request Header
authorization = Bearer {access token}
kakaoi-agent = {kakaoi agent}
kakaoi-user = {kakao developers 앱의 app user id}
x-anchor = {unique device id}
content-type = multipart/form-data; boundary={boundary term}
파라미터 | 설명 |
---|---|
authorization | Bearer {access token} KAuth(카카오 로그인 사용 시) |
kakaoi-agent | KVS/{버전} ({OS}; {플랫폼}; {제품정보}; AIID ${AIID}) {앱패키지}/{버전문자}/{버전코드} SDK/{버전} 카카오 i 에이전트 ex) KVS/1.0 (Linux; Android 25 7.1.1; SM-N950N/ NMF26X; AIID 1abcdefgh) com.kakao.i.connect/1.3.0/130 SDK/1.1.0 |
kakaoi-user | AU {kakao developers 앱의 app user id} 헤이카카오 사용자 구분값 ex) AU 1234567890 |
x-anchor | {HEX(SHA256(unique device ID))} 기기별 유일한 식별값의 SHA 256 Hex값 전달 |
content-type | content-type = multipart/form-data; boundary={boundary term} 본문의 포함된 데이터를 설명하며 이를 통해 카카오 i 서버는 요청을 적절하게 처리함 - content-Type은 항상 multipart/form-data 값으로 설정 |
Multipart Messages
Multipart 메시지 요청 시에 필요한 Header는 다음과 같습니다.
표Multipart Messages Request Header헤더 | 설명 |
---|---|
content-disposition | form-data; name="metadata" |
content-type | application/json; charset=UTF-8 |
Binary Audio 첨부 시
Binary Audio 첨부 시에 필요한 Header는 다음과 같습니다.
표Binary Audio Request Header헤더 | 설명 |
---|---|
content-disposition | form-data; name="audio" |
content-type | application/octet-stream |
JSON Content
각 Event에는 고유의 Header와 Body가 존재하며, 카카오 i 서버로 전송되는 모든 JSON 형식 Event는 service
, state
, event
, body
로 구성됩니다. Header에서 name
스페이스와 값은 인터페이스와 Event를 식별하며, messageId
는 클라이언트가 각 요청과 함께 전달되는 고유한 식별자입니다.
안내
Binary Audio를 첨부할 경우에는Recognize Event를 사용합니다.
코드예제JSON Content
{
:method = POST
:scheme = https
:path = /{API version}/events
authorization = Bearer {{access token}}
kakaoi-agent = {{kakaoi agent}}
kakaoi-user = {{kakao developers 앱의 app user id}}
x-anchor = {{unique device id}}
content-type = multipart/form-data; boundary={{boundary term}}
{
"service": {
"capabilities": [{...}, {...}, {...}]
},
"state": [, , ,],
"event": {
"header": {
"type": "{STRING}",
"messageId": "{STRING}"
},
"body": {
}
}
}
--{boundary term}--
}
Response
Service Agent는 카카오 i 서버로부터 응답(Instruction 메시지)을 수신하며, 응답 유형은 다음과 같습니다.
표응답 유형유형 | 설명 |
---|---|
Multipart 메시지 | 하나 이상의 Instruction 메시지와 필요시에 관련된 Binary audio 파일로 구성 |
예외 | Error Code와 설명이 포함되며, Multipart 메시지는 아님 |
Response Header
코드예제채널 통신 Response Header
authorization = Bearer {access token}
kakaoi-agent = {kakaoi agent}
kakaoi-user = {kakao developers 앱의 app user id}
x-anchor = {unique device id}
content-type = multipart/form-data; boundary={boundary term}
필드 | 설명 |
---|---|
authorization | Bearer {access token} KAuth(카카오 로그인 사용 시) |
kakaoi-agent | KVS/{버전} ({OS}; {플랫폼}; {제품정보}; AIID ${AIID}) {앱패키지}/{버전문자}/{버전코드} SDK/{버전} 카카오 i 에이전트 ex) KVS/1.0 (Linux; Android 25 7.1.1; SM-N950N/ NMF26X; AIID 1abcdefgh) com.kakao.i.connect/1.3.0/130 SDK/1.1.0 |
kakaoi-user | AU {kakao developers 앱의 app user id} 헤이카카오 사용자 구분값 ex) AU 1234567890 |
x-anchor | {HEX(SHA256(unique device ID))} 기기별 유일한 식별값의 SHA256 HEX값 전달 |
content-type | content-type = multipart/form-data; boundary={boundary term} 본문의 포함된 데이터를 설명하며 이를 통해 카카오 i 서버는 요청을 적절하게 처리함 - content-Type은 항상 multipart/form-data 값으로 받아야 함 |
Error Code
오류 상황을 구분하는 코드와 그 설명은 다음과 같습니다.
표오류 코드 값코드 | 설명 |
---|---|
400 | API 요청 파라미터 정보가 유효하지 않을 때 발생 |
401 | 인증 토큰이 만료되었을 때 주로 발생 |
481 | 버전 업그레이드가 필요한 경우 발생 |
482 | 미승인 약관이 존재할 경우 발생 |
483 | 미등록된 사용자일 경우 발생 |
485 | 미등록된 애플리케이션일 경우 발생 |
500 | 카카오 i 서버 내부 오류일 경우 발생 |
503 | 서비스 점검 중일 경우 발생 |
안내
오류 발생 시 해결 방안은 Troubleshooting 문서를 참고하시기 바랍니다.
표 | 오류 코드 값 이외에 클라이언트에서 확인되는 서버 오류는 아래 표 | 서버 오류 메시지를 참고하여 예외 상황 처리를 부탁드립니다.
표서버 오류 메시지오류 메시지 | 설명 |
---|---|
StreamResetException | KVS와의 연결 오류 - Down Channel 재연결 또는 재 로그인 필요 |
Exception | 아래와 같은 경우에 Exception 발생 - Response Body의 content-type이 multipart/form-data 가 아닌 경우- Multipart Header의 content-type이 application/json 또는 application/octet-stream 이 아닌 경우 |
코드예제정상 동작인 경우(ex. Template.Render)
{
"instruction": {
"header": {
"type": "Template.Render",
"messageId": "067cdc16-a9ea-44f5-96e3-00f978e7f7cf",
"dialogRequestId": "18e639b7-8d43-47bd-bc4f-d9f545321b13"
},
"body": {
"type": "KEYWORD_TEXT",
"data": {
"subtitle": {
"thumbnail": {}
},
"source": {
"thumbnail": {}
},
"button2": {
"thumbnail": {},
"action": {}
},
"background": {
"thumbnail": {}
},
"multimedia": {
"thumbnail": {}
},
"meta": {},
"content": {
"primaryText": {
"plainText": "오후 6:36",
"styledText": "오후 6:36",
"thumbnail": {}
},
"secondaryText": {
"thumbnail": {}
},
"paragraph": {
"thumbnail": {}
}
},
"title": {
"plainText": "현재 시각",
"styledText": "현재 시각",
"thumbnail": {}
},
"ttl": 300000,
"button1": {
"thumbnail": {},
"action": {}
},
"quickReplies": [
{
"plainText": "내일 일정 알려줘",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EB%82%B4%EC%9D%BC+%EC%9D%BC%EC%A0%95+%EC%95%8C%EB%A0%A4%EC%A4%98%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "내일 일정 알려줘"
},
{
"plainText": "밤에 듣기 좋은 음악 추천",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EB%B0%A4%EC%97%90+%EB%93%A3%EA%B8%B0+%EC%A2%8B%EC%9D%80+%EC%9D%8C%EC%95%85+%EC%B6%94%EC%B2%9C%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "밤에 듣기 좋은 음악 추천"
},
{
"plainText": "수면동화 들려줘",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EC%88%98%EB%A9%B4%EB%8F%99%ED%99%94+%EB%93%A4%EB%A0%A4%EC%A4%98%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "수면동화 들려줘"
},
{
"plainText": "내일 날씨 알려줘",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EB%82%B4%EC%9D%BC+%EB%82%A0%EC%94%A8+%EC%95%8C%EB%A0%A4%EC%A4%98%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "내일 날씨 알려줘"
},
{
"plainText": "내일 미세먼지 알려줘",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EB%82%B4%EC%9D%BC+%EB%AF%B8%EC%84%B8%EB%A8%BC%EC%A7%80+%EC%95%8C%EB%A0%A4%EC%A4%98%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "내일 미세먼지 알려줘"
},
{
"plainText": "이 시각 주요 뉴스 알려줘",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EC%9D%B4+%EC%8B%9C%EA%B0%81+%EC%A3%BC%EC%9A%94+%EB%89%B4%EC%8A%A4+%EC%95%8C%EB%A0%A4%EC%A4%98%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "이 시각 주요 뉴스 알려줘"
},
{
"plainText": "야식 주문해줘",
"thumbnail": {},
"action": {
"url": "kakaoi://instruction?body=%7B%22utterance%22%3A%22%EC%95%BC%EC%8B%9D+%EC%A3%BC%EB%AC%B8%ED%95%B4%EC%A4%98%22%2C%22token%22%3A%22kakao%2F59549ce09418c2575f9ba80c%2Fd41d8cd98f00b204e9800998ecf8427e%22%7D&type=Recognizer.RequestText"
},
"styledText": "야식 주문해줘"
}
],
"utterance": "지금 몇 시야"
},
"token": "kakao/59549ce09418c2575f9ba80c/d41d8cd98f00b204e9800998ecf8427e",
"ttl": 300000
},
"meta": {
"topic": "calendar",
"botId": "59549ce09418c2575f9ba80c",
"botName": "시간_AIU연동",
"intentId": "59549cf99418c2575f9ba80f",
"intentName": "informTime",
"ts": 1620293814936
}
}
}