Key Features

에이전트 API Endpoint 가이드

에이전트 API Endpoint 가이드

에이전트 API Endpoint 가이드

Agent API 엔드포인트 사용하기

에이전트리아(Agentria)에서 완성한 에이전트를 API로 배포했다면, 외부 서비스에서 이 API 엔드포인트(Endpoint)를 호출해 에이전트와 대화할 수 있습니다. Agent API는 채팅방 생성·조회·삭제, 비동기 채팅, SSE(Server-Sent Events) 스트리밍 채팅을 지원하는 REST API입니다.

이 가이드에서는 각 엔드포인트를 호출하는 방법과, 대화 맥락을 유지하며 실행 결과를 안전하게 받아오는 방법을 안내합니다.

사전 준비


  • 에이전트가 API로 배포되어 있어야 합니다. 아직 배포하지 않았다면 🔗API 배포 가이드를 먼저 진행합니다.

  • API 배포 시 발급받은 엔드포인트 코드(api_endpoint)와 API 키(Key)가 필요합니다.


Base URL과 인증 방식은 모든 엔드포인트에 공통으로 적용됩니다.

Base URL

모든 요청에는 X-API-KEY 헤더가 필요합니다.

API 키가 올바르지 않거나 권한이 없는 경우 403 Forbidden이 반환됩니다. 엔드포인트에 따라 세부 에러 코드가 다를 수 있으므로, 각 단계의 Error Responses 표를 함께 확인합니다.

1단계: 채팅방 관리하기

에이전트와 나눈 대화는 채팅방(Chat Room) 단위로 관리됩니다. 대화 이력을 유지하려면 먼저 채팅방을 만들고, 이후 요청에서 같은 채팅방 ID를 계속 사용합니다.

채팅방 생성

파라미터

타입

설명

api_endpoint

string

에이전트 코드 (릴리즈된 에이전트의 고유 식별자)

헤더

타입

필수

설명

X-API-KEY

string

Yes

API 접근 토큰

{
  "user_ids": [1, 2]
}
{
  "user_ids": [1, 2]
}
{
  "user_ids": [1, 2]
}

필드

타입

필수

설명

user_ids

list[int]

Yes

채팅방에 참여할 사용자 ID 목록 (첫 번째 ID가 생성자)

성공하면 200 OK 상태와 함께 생성된 채팅방 UUID를 응답받습니다.

"e36644fa-0b2e-11f0-b130-143627ec67e9"
"e36644fa-0b2e-11f0-b130-143627ec67e9"
"e36644fa-0b2e-11f0-b130-143627ec67e9"

Status

설명

400 Bad Request

user_ids가 없거나 리스트가 아닌 경우

403 Forbidden

API 키가 유효하지 않거나 에이전트 접근 권한이 없는 경우

curl -X POST "{host}/api/agent/my-agent/rooms" \
  -H "X-API-KEY: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"user_ids": [1]}'
curl -X POST "{host}/api/agent/my-agent/rooms" \
  -H "X-API-KEY: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"user_ids": [1]}'
curl -X POST "{host}/api/agent/my-agent/rooms" \
  -H "X-API-KEY: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"user_ids": [1]}'

채팅방 목록 조회

해당 에이전트 API로 생성된 채팅방 목록을 페이징(Paging) 형식으로 조회합니다.

파라미터

타입

필수

기본값

설명

page_index

int

No

0

페이지 번호 (0부터 시작)

page_size

int

No

10

페이지당 항목 수 (최대 100, 초과 시 100으로 적용)

order_by

list[string]

No

created_time,desc

정렬 기준 (예: created_time,desc)

성공하면 200 OK 상태와 함께 아래 형태로 응답받습니다.

{
  "data": [
    {
      "id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
      "creator_id": 1,
      "properties_json": {},
      "created_time": "2026-01-15T10:30:00",
      "updated_time": "2026-01-15T10:30:00"
    }
  ],
  "page": {
    "page_size": 10,
    "page_number": 0,
    "total_elements": 1,
    "total_pages": 1
  }
}
{
  "data": [
    {
      "id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
      "creator_id": 1,
      "properties_json": {},
      "created_time": "2026-01-15T10:30:00",
      "updated_time": "2026-01-15T10:30:00"
    }
  ],
  "page": {
    "page_size": 10,
    "page_number": 0,
    "total_elements": 1,
    "total_pages": 1
  }
}
{
  "data": [
    {
      "id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
      "creator_id": 1,
      "properties_json": {},
      "created_time": "2026-01-15T10:30:00",
      "updated_time": "2026-01-15T10:30:00"
    }
  ],
  "page": {
    "page_size": 10,
    "page_number": 0,
    "total_elements": 1,
    "total_pages": 1
  }
}

Status

설명

403 Forbidden

API 키가 유효하지 않거나 에이전트 접근 권한이 없는 경우

curl -X GET "{host}/api/agent/my-agent/rooms?page_index=0&page_size=10" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/rooms?page_index=0&page_size=10" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/rooms?page_index=0&page_size=10" \
  -H "X-API-KEY: your-api-key"

채팅방 상세 조회

특정 채팅방의 상세 정보를 조회합니다.

파라미터

타입

설명

api_endpoint

string

에이전트 코드

chat_room_id

UUID

채팅방 ID

성공하면 200 OK 상태와 함께 아래 형태로 응답받습니다. participants_json에서 채팅방에 참여한 사용자와 에이전트 정보를 확인할 수 있습니다.

{
  "id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "participants_json": {
    "users": {
      "1": {
        "id": 1,
        "type": "USER",
        "joined_time": "2026-01-15T10:30:00",
        "name": null
      }
    },
    "agents": {
      "42": {
        "id": 42,
        "type": "AGENT",
        "joined_time": "2026-01-15T10:30:00",
        "name": "My Agent"
      }
    }
  },
  "creator_id": 1,
  "properties_json": {},
  "created_time": "2026-01-15T10:30:00",
  "updated_time": "2026-01-15T10:30:00"
}
{
  "id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "participants_json": {
    "users": {
      "1": {
        "id": 1,
        "type": "USER",
        "joined_time": "2026-01-15T10:30:00",
        "name": null
      }
    },
    "agents": {
      "42": {
        "id": 42,
        "type": "AGENT",
        "joined_time": "2026-01-15T10:30:00",
        "name": "My Agent"
      }
    }
  },
  "creator_id": 1,
  "properties_json": {},
  "created_time": "2026-01-15T10:30:00",
  "updated_time": "2026-01-15T10:30:00"
}
{
  "id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "participants_json": {
    "users": {
      "1": {
        "id": 1,
        "type": "USER",
        "joined_time": "2026-01-15T10:30:00",
        "name": null
      }
    },
    "agents": {
      "42": {
        "id": 42,
        "type": "AGENT",
        "joined_time": "2026-01-15T10:30:00",
        "name": "My Agent"
      }
    }
  },
  "creator_id": 1,
  "properties_json": {},
  "created_time": "2026-01-15T10:30:00",
  "updated_time": "2026-01-15T10:30:00"
}

Status

설명

403 Forbidden

API 키가 유효하지 않거나 채팅방이 존재하지 않는 경우

curl -X GET "{host}/api/agent/my-agent/rooms/e36644fa-0b2e-11f0-b130-143627ec67e9" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/rooms/e36644fa-0b2e-11f0-b130-143627ec67e9" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/rooms/e36644fa-0b2e-11f0-b130-143627ec67e9" \
  -H "X-API-KEY: your-api-key"

채팅방 삭제

성공하면 200 OK 상태와 함께 true(성공) 또는 false(실패)를 응답받습니다.

Status

설명

403 Forbidden

API 키가 유효하지 않거나 에이전트 접근 권한이 없는 경우

curl -X DELETE "{host}/api/agent/my-agent/rooms/e36644fa-0b2e-11f0-b130-143627ec67e9" \
  -H "X-API-KEY: your-api-key"
curl -X DELETE "{host}/api/agent/my-agent/rooms/e36644fa-0b2e-11f0-b130-143627ec67e9" \
  -H "X-API-KEY: your-api-key"
curl -X DELETE "{host}/api/agent/my-agent/rooms/e36644fa-0b2e-11f0-b130-143627ec67e9" \
  -H "X-API-KEY: your-api-key"

2단계: 비동기로 채팅 메시지 보내기

에이전트에게 메시지를 보내고 request_id를 즉시 응답받습니다. 실행 결과는 상태 조회 API(3단계) 또는 콜백(Callback) URL로 받을 수 있습니다.

Path Parameters

파라미터

타입

설명

api_endpoint

string

에이전트 코드

Headers

헤더

타입

필수

설명

X-API-KEY

string

Yes

API 접근 토큰

Request Body (multipart/form-data)

필드

타입

필수

설명

params_json

string (JSON)

Yes

요청 파라미터 (아래 구조 참조)

callback_url

string

No

결과를 POST로 전달받을 콜백 URL

debug

boolean

No

디버그 모드 (기본값: false)

external_request_id

string

No

클라이언트가 발급한 외부 요청 식별자 (최대 128자, ^[A-Za-z0-9_\-\.:]+$). 동일 에이전트 내에서는 고유해야 합니다.

files

file[]

No

업로드할 파일 목록

{
  "input_message": "안녕하세요",
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "input_files": [
    "<https: example.com="" image1.jpg="">",
    "s3://bucket-name/image2.jpg"
  ]
}<

{
  "input_message": "안녕하세요",
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "input_files": [
    "<https: example.com="" image1.jpg="">",
    "s3://bucket-name/image2.jpg"
  ]
}<

{
  "input_message": "안녕하세요",
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "input_files": [
    "<https: example.com="" image1.jpg="">",
    "s3://bucket-name/image2.jpg"
  ]
}<

필드

타입

필수

설명

input_message

string

No

텍스트 메시지

chat_room_id

string (UUID)

No

기존 채팅방 ID (없으면 새로 생성됩니다)

input_files

list[string]

No

파일 URL 목록 (HTTP URL 또는 S3 URI)

chat_room_id를 지정하지 않으면 요청마다 새 채팅방이 자동 생성될 수 있습니다. 대화 맥락을 이어가려면 1단계에서 만든(또는 이전 응답에서 받은) 채팅방 ID를 계속 같은 값으로 전달해야 합니다.

external_request_id는 클라이언트가 요청을 보내기 전에 직접 발급하는 식별자로, 두 가지 역할을 합니다. 첫째, 동일한 external_request_id로 재요청이 오면 서버가 같은 요청으로 판단해 409 Conflict로 거부하므로, 네트워크 재시도 등으로 인한 중복 실행(멱등성, Idempotency 보장)을 방지할 수 있습니다. 둘째, 클라이언트가 요청 시점에 이미 이 식별자를 확보해두는 방식이므로, 서버가 응답으로 request_id를 돌려주기 전부터 이 값으로 해당 요청을 추적·조회할 수 있습니다.

Response

성공하면 200 OK 상태와 함께 요청 ID(문자열)를 응답받습니다.

"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Error Responses

Status

설명

400 Bad Request

external_request_id 형식이 올바르지 않은 경우

401 Unauthorized

인증 실패

404 Not Found

에이전트를 찾을 수 없음

409 Conflict

동일한 external_request_id가 이미 등록된 경우

500 Internal Server Error

서버 내부 오류

요청 예시

# 텍스트만 전송
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "안녕하세요", "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'debug=false'

# 외부 요청 ID 부여
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "주문 처리해줘", "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'callback_url=https://my-service.com/webhook' \
  -F 'external_request_id=order-12345'

# 파일과 함께 전송
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "이 이미지를 분석해줘"}' \
  -F 'callback_url=https://my-service.com/webhook' \
  -F 'files=@/path/to/image.png'
# 텍스트만 전송
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "안녕하세요", "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'debug=false'

# 외부 요청 ID 부여
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "주문 처리해줘", "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'callback_url=https://my-service.com/webhook' \
  -F 'external_request_id=order-12345'

# 파일과 함께 전송
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "이 이미지를 분석해줘"}' \
  -F 'callback_url=https://my-service.com/webhook' \
  -F 'files=@/path/to/image.png'
# 텍스트만 전송
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "안녕하세요", "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'debug=false'

# 외부 요청 ID 부여
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "주문 처리해줘", "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'callback_url=https://my-service.com/webhook' \
  -F 'external_request_id=order-12345'

# 파일과 함께 전송
curl -X POST "{host}/api/agent/my-agent/async" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message": "이 이미지를 분석해줘"}' \
  -F 'callback_url=https://my-service.com/webhook' \
  -F 'files=@/path/to/image.png'

3단계: 요청 상태·결과 조회하기

비동기 채팅 요청의 처리 상태와 결과를 조회합니다.




두 엔드포인트는 동일한 응답을 반환합니다.

Path Parameters

파라미터

타입

설명

api_endpoint

string

에이전트 코드

request_id

string

비동기 요청 ID (/async 응답값)

Response

성공하면 200 OK 상태와 함께 아래 형태의 결과를 응답받습니다.

{
  "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "external_request_id": null,
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "status": "COMPLETED",
  "failure_reason": null,
  "results": {
    "output": "에이전트 응답 내용"
  },
  "artifact_metadata_json": null,
  "request_params_json": "{\"method\":\"POST\",\"client\":\"127.0.0.1\",\"params\":[{\"type\":\"text\",\"text\":\"안녕하세요\"}]}",
  "result_metadata_json": null,
  "requested_time": "2026-01-15T10:30:00",
  "updated_time": "2026-01-15T10:31:00"
}
{
  "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "external_request_id": null,
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "status": "COMPLETED",
  "failure_reason": null,
  "results": {
    "output": "에이전트 응답 내용"
  },
  "artifact_metadata_json": null,
  "request_params_json": "{\"method\":\"POST\",\"client\":\"127.0.0.1\",\"params\":[{\"type\":\"text\",\"text\":\"안녕하세요\"}]}",
  "result_metadata_json": null,
  "requested_time": "2026-01-15T10:30:00",
  "updated_time": "2026-01-15T10:31:00"
}
{
  "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "external_request_id": null,
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "status": "COMPLETED",
  "failure_reason": null,
  "results": {
    "output": "에이전트 응답 내용"
  },
  "artifact_metadata_json": null,
  "request_params_json": "{\"method\":\"POST\",\"client\":\"127.0.0.1\",\"params\":[{\"type\":\"text\",\"text\":\"안녕하세요\"}]}",
  "result_metadata_json": null,
  "requested_time": "2026-01-15T10:30:00",
  "updated_time": "2026-01-15T10:31:00"
}

external_request_id는 요청 시 외부 ID를 부여한 경우에만 값이 채워지며, 그 외에는 null입니다.

status 값

설명

NONE

초기 상태 (처리 대기 중)

PROCESSING

처리 중

COMPLETED

완료

FAILURE

실패 (failure_reason 필드에 사유 포함)

CANCELED

취소됨

요청 예시

curl -X GET "{host}/api/agent/my-agent/a1b2c3d4-e5f6-7890-abcd-ef1234567890/status" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/a1b2c3d4-e5f6-7890-abcd-ef1234567890/status" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/a1b2c3d4-e5f6-7890-abcd-ef1234567890/status" \
  -H "X-API-KEY: your-api-key"

외부 요청 ID로 조회하기

요청 시 external_request_id를 부여했다면, 해당 값으로도 동일한 응답을 조회할 수 있습니다.




Status

설명

400 Bad Request

external_request_id 형식이 올바르지 않음

404 Not Found

해당 외부 ID로 등록된 요청이 없음

curl -X GET "{host}/api/agent/my-agent/external/order-12345/status" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/external/order-12345/status" \
  -H "X-API-KEY: your-api-key"
curl -X GET "{host}/api/agent/my-agent/external/order-12345/status" \
  -H "X-API-KEY: your-api-key"

4단계: SSE로 실시간 채팅 응답 받기

에이전트와 실시간 스트리밍 채팅을 수행합니다. SSE를 통해 에이전트의 응답을 실시간으로 수신합니다.

Path Parameters / Headers

1단계·2단계와 동일하게 api_endpoint 경로 파라미터와 X-API-KEY 헤더가 필요합니다.

Request Body (multipart/form-data)

필드

타입

필수

설명

params_json

string (JSON)

Yes

요청 파라미터 (2단계와 동일한 구조)

debug

boolean

No

디버그 모드 (기본값: false)

external_request_id

string

No

클라이언트가 발급한 외부 요청 식별자. 형식 규칙은 2단계와 동일합니다. SSE 종료 후 이 값으로도 상태·결과를 조회할 수 있습니다.

{
  "input_message": "안녕하세요",
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "input_files": [
    "<https: example.com="" image1.jpg="">"
  ]
}<

{
  "input_message": "안녕하세요",
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "input_files": [
    "<https: example.com="" image1.jpg="">"
  ]
}<

{
  "input_message": "안녕하세요",
  "chat_room_id": "e36644fa-0b2e-11f0-b130-143627ec67e9",
  "input_files": [
    "<https: example.com="" image1.jpg="">"
  ]
}<

Response

응답의 Content-Type은 text/event-stream입니다.

응답 헤더 X-Agent-Request-Id로 요청 ID를 받습니다. 첫 이벤트 수신 전에 연결이 끊기더라도 이 값으로 재조회할 수 있으며, 첫 request_id 이벤트와 동일한 값입니다.

주의: X-Request-Id 헤더는 HTTP 추적용으로 쓰이는 별개의 값이므로 X-Agent-Request-Id와 혼동하지 않도록 주의합니다.

각 이벤트는 표준 EventSource 포맷과 호환되지 않는 자체 정의 SSE 라인 포맷으로 전달됩니다. 빈 줄로 이벤트가 구분됩니다.




event_type 값과 body 형태

Agent API의 SSE는 최초 request_id 메타 이벤트를 제외한 모든 이벤트가 {"ability_node_id", "ability_node_name", "results"} 형태로 한 번 더 감싸진 형태로 직렬화됩니다. Ability API의 SSE(response/error 이벤트의 body가 결과 스키마 그대로 오는 방식)와 다른 부분이므로, 두 API를 함께 연동할 때 특히 주의합니다.

event_type

발생 시점

body 형태

request_id

스트림 시작 직후 (최초, 1회)

plain 문자열(UUID). 감싸는 형태 없이 그대로 전달되며, 스트림 유실 시 결과 재조회용 요청 ID

node

각 노드 실행 종료 시점 (중간 이벤트, 노드 개수만큼 반복)

{"ability_node_id":, "ability_node_name":, "results":<노드 실행 결과 dict>}

response

에이전트 정상 완료 (최종, 1회)

{"ability_node_id":0, "ability_node_name":"final_output", "results":}

error

에이전트 실패 또는 처리 오류 (최종, 1회)

{"ability_node_id":0, "ability_node_name":"final_output", "results":}

최종 이벤트에서는 results 필드 안에 APIResponseSchema가 통째로 한 번 더 들어있다는 점이 중요합니다(3단계의 상태 조회 응답과 같은 구조). 따라서 최종 상태를 판별할 때는 chunk.status가 아니라 chunk.results.status를 확인해야 합니다.

중간 vs 최종 식별


  • event_type == "request_id" → 메타 이벤트(스트림 시작 직후 1회, 요청 ID 전달)

  • chunk.ability_node_id === 0 → 최종 이벤트

  • 또는 chunk.results.statusCOMPLETED·FAILURE이면 최종 이벤트

  • 그 외(위 조건에 해당하지 않는 경우) → 중간 노드 이벤트


스트림 유실 시 결과 재조회

네트워크 유실 등으로 최종 이벤트를 받지 못한 경우, 같은 요청을 재전송하면 에이전트가 재실행되어 대화 이력이 중복되므로 재조회를 사용해야 합니다. 서버는 스트림 단절과 무관하게 실행을 완료하고 결과를 기록합니다.


  • request_id 이벤트(또는 X-Agent-Request-Id 헤더)로 받은 요청 ID로 GET /{api_endpoint}/{request_id}/result를 폴링합니다 (3단계 참고).

  • external_request_id를 부여했다면 GET /{api_endpoint}/external/{external_request_id}/result로도 조회할 수 있습니다 (3단계 참고).


statusCOMPLETED·FAILURE·CANCELED가 될 때까지 폴링합니다. 같은 external_request_id로 재전송하면 409 Conflict로 거부되므로, 외부 ID를 함께 쓰면 실수로 인한 중복 실행도 방지할 수 있습니다.

요청 예시

curl -N -X POST "{host}/api/agent/my-agent/sse" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message":"안녕하세요","chat_room_id":"e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'debug=false'
curl -N -X POST "{host}/api/agent/my-agent/sse" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message":"안녕하세요","chat_room_id":"e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'debug=false'
curl -N -X POST "{host}/api/agent/my-agent/sse" \
  -H "X-API-KEY: your-api-key" \
  -F 'params_json={"input_message":"안녕하세요","chat_room_id":"e36644fa-0b2e-11f0-b130-143627ec67e9"}' \
  -F 'debug=false'
  • N(-no-buffer) 옵션은 필수입니다. 붙이지 않으면 청크가 몰려서 전달됩니다.

실제 응답 예시 (wire)




JavaScript 클라이언트 예시

const formData = new FormData();
formData.append('params_json', JSON.stringify({
  input_message: '안녕하세요',
  chat_room_id: 'e36644fa-0b2e-11f0-b130-143627ec67e9'
}));
formData.append('debug', 'false');

const response = await fetch(`${host}/api/agent/my-agent/sse`, {
  method: 'POST',
  headers: { 'X-API-KEY': 'your-api-key' },
  body: formData
});

// 스트림 유실 시 GET .../{requestId}/result 재조회용. 첫 request_id 이벤트로도 갱신됩니다.
let requestId = response.headers.get('X-Agent-Request-Id');

// 한 번의 read() 가 여러 이벤트를 합쳐서 줄 수 있으므로 line-buffered 파싱이 필요합니다.
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buf = '';
let currentEvent = null;

const chunks = []; // 모든 chunk 누적
let finalChunk = null;

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });

  let nl;
  while ((nl = buf.indexOf('\n')) !== -1) {
    const line = buf.slice(0, nl);
    buf = buf.slice(nl + 1);

    if (line === '') { currentEvent = null; continue; } // 이벤트 경계
    if (line.endsWith(':')) { currentEvent = line.slice(0, -1); continue; }

    // request_id 이벤트의 body는 감싸는 형태 없는 plain UUID 문자열 — JSON.parse 전에 처리
    if (currentEvent === 'request_id') { requestId = line; continue; }

    let body;
    try { body = JSON.parse(line); } catch { continue; }

    chunks.push(body);

    // 중간 vs 최종
    const status = body.results?.status;
    if (body.ability_node_id === 0 || status === 'COMPLETED' || status === 'FAILURE') {
      finalChunk = body; // results 안에 APIResponseSchema
      console.log('[final]', status, finalChunk.results.results);
    } else {
      console.log('[node]', body.ability_node_id, body.ability_node_name, body.results);
    }
  }
}

if (finalChunk?.results?.status === 'FAILURE') {
  console.error('실패:', finalChunk.results.failure_reason);
}

// 최종 chunk 없이 스트림이 끊긴 경우 — 재전송(재실행) 대신 재조회
if (!finalChunk && requestId) {
  const res = await fetch(`${host}/api/agent/my-agent/${requestId}/result`, {
    headers: { 'X-API-KEY': 'your-api-key' }
  });
  const result = await res.json(); // status 가 COMPLETED/FAILURE 가 될 때까지 폴링
}
const formData = new FormData();
formData.append('params_json', JSON.stringify({
  input_message: '안녕하세요',
  chat_room_id: 'e36644fa-0b2e-11f0-b130-143627ec67e9'
}));
formData.append('debug', 'false');

const response = await fetch(`${host}/api/agent/my-agent/sse`, {
  method: 'POST',
  headers: { 'X-API-KEY': 'your-api-key' },
  body: formData
});

// 스트림 유실 시 GET .../{requestId}/result 재조회용. 첫 request_id 이벤트로도 갱신됩니다.
let requestId = response.headers.get('X-Agent-Request-Id');

// 한 번의 read() 가 여러 이벤트를 합쳐서 줄 수 있으므로 line-buffered 파싱이 필요합니다.
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buf = '';
let currentEvent = null;

const chunks = []; // 모든 chunk 누적
let finalChunk = null;

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });

  let nl;
  while ((nl = buf.indexOf('\n')) !== -1) {
    const line = buf.slice(0, nl);
    buf = buf.slice(nl + 1);

    if (line === '') { currentEvent = null; continue; } // 이벤트 경계
    if (line.endsWith(':')) { currentEvent = line.slice(0, -1); continue; }

    // request_id 이벤트의 body는 감싸는 형태 없는 plain UUID 문자열 — JSON.parse 전에 처리
    if (currentEvent === 'request_id') { requestId = line; continue; }

    let body;
    try { body = JSON.parse(line); } catch { continue; }

    chunks.push(body);

    // 중간 vs 최종
    const status = body.results?.status;
    if (body.ability_node_id === 0 || status === 'COMPLETED' || status === 'FAILURE') {
      finalChunk = body; // results 안에 APIResponseSchema
      console.log('[final]', status, finalChunk.results.results);
    } else {
      console.log('[node]', body.ability_node_id, body.ability_node_name, body.results);
    }
  }
}

if (finalChunk?.results?.status === 'FAILURE') {
  console.error('실패:', finalChunk.results.failure_reason);
}

// 최종 chunk 없이 스트림이 끊긴 경우 — 재전송(재실행) 대신 재조회
if (!finalChunk && requestId) {
  const res = await fetch(`${host}/api/agent/my-agent/${requestId}/result`, {
    headers: { 'X-API-KEY': 'your-api-key' }
  });
  const result = await res.json(); // status 가 COMPLETED/FAILURE 가 될 때까지 폴링
}
const formData = new FormData();
formData.append('params_json', JSON.stringify({
  input_message: '안녕하세요',
  chat_room_id: 'e36644fa-0b2e-11f0-b130-143627ec67e9'
}));
formData.append('debug', 'false');

const response = await fetch(`${host}/api/agent/my-agent/sse`, {
  method: 'POST',
  headers: { 'X-API-KEY': 'your-api-key' },
  body: formData
});

// 스트림 유실 시 GET .../{requestId}/result 재조회용. 첫 request_id 이벤트로도 갱신됩니다.
let requestId = response.headers.get('X-Agent-Request-Id');

// 한 번의 read() 가 여러 이벤트를 합쳐서 줄 수 있으므로 line-buffered 파싱이 필요합니다.
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buf = '';
let currentEvent = null;

const chunks = []; // 모든 chunk 누적
let finalChunk = null;

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });

  let nl;
  while ((nl = buf.indexOf('\n')) !== -1) {
    const line = buf.slice(0, nl);
    buf = buf.slice(nl + 1);

    if (line === '') { currentEvent = null; continue; } // 이벤트 경계
    if (line.endsWith(':')) { currentEvent = line.slice(0, -1); continue; }

    // request_id 이벤트의 body는 감싸는 형태 없는 plain UUID 문자열 — JSON.parse 전에 처리
    if (currentEvent === 'request_id') { requestId = line; continue; }

    let body;
    try { body = JSON.parse(line); } catch { continue; }

    chunks.push(body);

    // 중간 vs 최종
    const status = body.results?.status;
    if (body.ability_node_id === 0 || status === 'COMPLETED' || status === 'FAILURE') {
      finalChunk = body; // results 안에 APIResponseSchema
      console.log('[final]', status, finalChunk.results.results);
    } else {
      console.log('[node]', body.ability_node_id, body.ability_node_name, body.results);
    }
  }
}

if (finalChunk?.results?.status === 'FAILURE') {
  console.error('실패:', finalChunk.results.failure_reason);
}

// 최종 chunk 없이 스트림이 끊긴 경우 — 재전송(재실행) 대신 재조회
if (!finalChunk && requestId) {
  const res = await fetch(`${host}/api/agent/my-agent/${requestId}/result`, {
    headers: { 'X-API-KEY': 'your-api-key' }
  });
  const result = await res.json(); // status 가 COMPLETED/FAILURE 가 될 때까지 폴링
}

참고 (Python 클라이언트): httpx.AsyncClient.stream()aiter_lines()와 JSON 파싱으로 한 줄씩 처리하되, node: / response: / error: 접두 라인은 JSON 파싱 오류로 건너뛰면 됩니다. request_id 이벤트의 body(plain UUID)도 JSON이 아니므로 같은 방식으로 건너뛰어지며, 기존 클라이언트의 chunks[-1].get("results", {}).get("status") == "FAILURE" 같은 검사 패턴이 그대로 동작합니다. 재조회용 ID가 필요하면 직전 라인이 request_id:인지 추적하거나 응답 헤더 X-Agent-Request-Id를 사용합니다.

전체 흐름 한눈에 보기

목적에 따라 아래 세 가지 흐름 중 하나를 선택해 사용합니다.

흐름 1: 비동기 방식 (폴링)




흐름 2: 비동기 방식 (콜백)




콜백 페이로드 예시입니다.

// external_request_id를 부여한 요청의 콜백 — 키 포함
{
  "request_id": "a1b2c3d4-...",
  "external_request_id": "order-12345",
  "chat_room_id": "e36644fa-...",
  "status": "COMPLETED",
  "results": { ... },
  "failure_reason": null
}

// external_request_id를 부여하지 않은 요청의 콜백 — 키 자체가 생략됨
{
  "request_id": "a1b2c3d4-...",
  "chat_room_id": "e36644fa-...",
  "status": "COMPLETED",
  "results": { ... },
  "failure_reason": null
}
// external_request_id를 부여한 요청의 콜백 — 키 포함
{
  "request_id": "a1b2c3d4-...",
  "external_request_id": "order-12345",
  "chat_room_id": "e36644fa-...",
  "status": "COMPLETED",
  "results": { ... },
  "failure_reason": null
}

// external_request_id를 부여하지 않은 요청의 콜백 — 키 자체가 생략됨
{
  "request_id": "a1b2c3d4-...",
  "chat_room_id": "e36644fa-...",
  "status": "COMPLETED",
  "results": { ... },
  "failure_reason": null
}
// external_request_id를 부여한 요청의 콜백 — 키 포함
{
  "request_id": "a1b2c3d4-...",
  "external_request_id": "order-12345",
  "chat_room_id": "e36644fa-...",
  "status": "COMPLETED",
  "results": { ... },
  "failure_reason": null
}

// external_request_id를 부여하지 않은 요청의 콜백 — 키 자체가 생략됨
{
  "request_id": "a1b2c3d4-...",
  "chat_room_id": "e36644fa-...",
  "status": "COMPLETED",
  "results": { ... },
  "failure_reason": null
}

외부 ID가 없는 요청은 external_request_id 키 자체를 콜백 페이로드에 포함하지 않습니다. 기존 방식 그대로 유지되므로 이전 연동 코드와도 호환됩니다.

흐름 3: 실시간 스트리밍 방식




참고: chat_room_id를 지정하지 않으면 채팅방이 자동으로 생성될 수 있습니다. 대화 이력을 유지하려면 항상 동일한 chat_room_id를 사용해야 합니다.

다음 단계

Agent API 엔드포인트 사용법을 확인했습니다.

이제 외부 서비스에서 에이전트와 직접 대화하고 실행 결과를 받아올 수 있습니다.


  • 🔗API 배포 가이드에서 엔드포인트와 API 키 발급 절차를 다시 확인할 수 있습니다.


자주 묻는 질문

Agent API란 무엇인가요?

Agent API는 외부 서비스가 에이전트리아의 에이전트와 REST API로 대화할 수 있게 해주는 기능입니다. 채팅방 생성·조회·삭제, 비동기 채팅, SSE 스트리밍 채팅을 지원하며, 모든 요청은 X-API-KEY 헤더로 인증합니다.

Agent API는 언제 사용해야 하나요?

외부 백엔드 서버나 다른 서비스에서 에이전트리아 UI를 거치지 않고 에이전트와 대화하며 응답을 받아야 할 때 사용합니다. 예를 들어 자사 서비스의 채팅 화면에서 에이전트를 호출하거나, 여러 차례에 걸친 대화 맥락을 유지하며 자동화된 응대를 구현하려는 경우에 적합합니다.

Agent API는 Ability API와 어떻게 다른가요?

Ability API가 완성된 워크플로(어빌리티)를 한 번 실행하고 결과를 받는 방식이라면, Agent API는 채팅방 단위로 여러 차례 대화를 주고받으며 맥락을 유지하는 방식입니다. SSE 응답 구조도 달라서, Agent API는 최초 request_id 이벤트를 제외한 모든 이벤트가 {ability_node_id, ability_node_name, results} 형태로 한 번 더 감싸져 있고, 최종 상태는 results.status를 확인해야 합니다.

여러 번 대화해도 대화 맥락이 유지되나요?

같은 chat_room_id를 계속 전달하면 대화 맥락이 유지됩니다. 요청 시 chat_room_id를 지정하지 않으면 새 채팅방이 자동 생성될 수 있으므로, 대화를 이어가려면 이전 응답에서 받은 chat_room_id를 다음 요청에도 동일하게 전달해야 합니다.

실시간 스트리밍(SSE) 도중 연결이 끊기면 어떻게 되나요?

서버는 스트림 연결과 무관하게 에이전트 실행을 계속 완료하고 결과를 기록합니다. 연결이 끊겨 최종 이벤트를 받지 못했다면, 같은 요청을 재전송하지 않고 request_id(또는 external_request_id)로 상태·결과 조회 API를 폴링해 결과를 가져와야 합니다. 같은 요청을 재전송하면 에이전트가 다시 실행되어 대화 이력이 중복될 수 있습니다.