Kakao i Agent::AI Service Agent::채널 연결 및 통신

페이지 이동경로

채널 연결 및 통신

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 연결을 생성해야 합니다.

연결 프로세스

  1. 다음의 채널 연결 요청을 통해 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 전송 옵션

  2. 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}--
     }
    

  3. Service Agent가 응답(Instruction)을 받으면 위의 Event 채널 스트림을 닫습니다.

  4. 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 TimeoutServer-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는 다음의 작업을 수행합니다.

  1. Service Agent는 새로운 연결을 열고, 이를 통해 새로운 요청을 라우팅합니다.

  2. 열려있는 모든 요청을 처리하고, 해당 스트림이 정상적으로 닫힌 후에 이전 연결을 닫습니다.

  3. 연결이 해제되기 전에 설정된 모든 스트림 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}}

채널 통신 Request Protocol
파라미터 설명
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}

채널 통신 Request Header
파라미터 설명
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}

채널 통신 Response Header
필드 설명
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
    }
  }
}

이 문서가 만족스러운 이유를 알려주세요.
이 문서에 아쉬운 점을 알려주세요.
평가해주셔서 감사합니다.

더 자세한 의견은 contact.dkt@kakaocorp.com 으로 제보해주세요.