> ## Documentation Index
> Fetch the complete documentation index at: https://docs.acedata.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# AI Chat v2 API 연동 설명

> AI Dialogue API guide - Ace Data Cloud

AI Chat v2 API(`/aichat2/conversations`)는 새로운 세대의 대화 인터페이스로, [AI Chat API](https://platform.acedata.cloud/documents/aichat-conversations)의 전면 업그레이드 버전입니다. v1의 간결하고 다중 회차 대화를 호스팅하는 기반 위에 다음과 같은 기능이 확장되었습니다:

* **다중 모드 사용자 입력**: 구조화된 `message` 필드를 통해 텍스트 + 이미지 + 파일 블록을 직접 전달할 수 있으며, `references`를 통해 간접적으로 첨부할 필요가 없습니다.
* **Agent화 도구 호출**: 내장된 네트워크 검색, 웹 스크래핑, 파일 읽기 등의 도구 세트를 제공하며, 사용자가 권한을 부여한 MCP 서버(Google Drive, Notion, Slack, GitHub 등)를 장착할 수 있습니다. 모델은 한 번의 요청으로 다중 회차 도구를 자율적으로 호출하여 복잡한 작업을 수행할 수 있습니다.
* **구조화된 스트리밍 이벤트**: `accept: text/event-stream` 또는 `application/x-ndjson`을 통해 토큰별 `text_delta`, `tool_use`, `tool_result`, `thinking`, `citation`, `card`, `artifact` 등의 이벤트를 받아 프론트엔드에서 해당 유형에 따라 별도로 렌더링할 수 있습니다.
* **중단 가능 / 복구 가능**: 모델이 사용자에게 추가 정보를 요청할 때 `ask_user_question` 이벤트를 발송하고 일시 중지하며, 다음 호출 시 `tool_results`를 통해 답변을 다시 입력하면 계속 진행할 수 있습니다.
* **새로운 CRUD 동작**: 동일한 엔드포인트에서 `action` 필드를 통해 `retrieve` / `retrieve_batch` / `update` / `delete`를 수행할 수 있으며, 추가적인 세션 관리 API가 필요하지 않습니다.
* **지속적으로 업데이트되는 모델 목록**: 기본적으로 GPT-5.4, Claude Opus 4.8, Claude Sonnet 4.6, Gemini 3.1 Pro, GLM 5.1, DeepSeek V4, Kimi K3 등 현대 모델에 접속할 수 있습니다.

또한 요청 본문 수준에서 **v1과 완전히 하위 호환**됩니다: `model` + `question`( + 선택적 `stateful` / `id` / `references` / `preset`)만 전달하면 v1과 동등한 `{answer, id}` JSON 응답을 받을 수 있으므로 `/aichat/conversations`에서 마이그레이션할 때 클라이언트를 다시 작성할 필요 없이 경로만 `/aichat2/conversations`로 변경하면 됩니다.

> 현재 `/aichat/conversations`를 사용 중이라면, 구형 인터페이스는 여전히 서비스가 유지되며, 자신의 속도에 맞춰 마이그레이션할 수 있습니다.

## 신청 절차

AI Chat v2 API를 사용하려면 먼저 [Ace Data Cloud 콘솔](https://platform.acedata.cloud/console/applications)에서 API 토큰을 받아야 합니다. 이를 백업용으로 보관하십시오.

![](https://cdn.acedata.cloud/5hmkdg.jpg)

로그인 또는 등록하지 않은 경우 자동으로 로그인 페이지로 리디렉션되어 등록 및 로그인을 초대합니다. 완료 후 현재 페이지로 자동으로 돌아옵니다.

**하나의 API 토큰으로 플랫폼의 모든 서비스를 호출할 수 있으며, 각 서비스에 대해 별도로 신청할 필요가 없습니다.** 최초 신청 시 무료 크레딧이 제공되어 무료로 체험할 수 있으며, 크레딧이 부족할 경우 [콘솔](https://platform.acedata.cloud/console/coin)에서 일반 잔액을 충전할 수 있습니다.

> 📘 전체 문서: [AI Chat v2 API →](https://platform.acedata.cloud/documents/aichat2-conversations)

## 기본 사용

가장 간단한 사용법은 v1과 완전히 동일합니다: `model` + `question`을 전달하여 `{answer, id}`를 얻습니다.

CURL 예시:

```shell theme={null}
curl -X POST 'https://api.acedata.cloud/aichat2/conversations' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.4",
    "question": "AceDataCloud에 대해 한 문장으로 소개해 주세요."
  }'
```

반환 결과:

```json theme={null}
{
  "answer": "AceDataCloud는 주류 AI 모델과 다중 모드 서비스를 통합한 API 플랫폼으로, 개발자는 하나의 키로 GPT, Claude, Gemini, Midjourney, Suno, Veo 등 여러 서비스를 호출할 수 있습니다.",
  "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44"
}
```

Python 예시:

```python theme={null}
import requests

url = "https://api.acedata.cloud/aichat2/conversations"

headers = {
    "accept": "application/json",
    "authorization": "Bearer {token}",
    "content-type": "application/json",
}

payload = {
    "model": "gpt-5.4",
    "question": "AceDataCloud에 대해 한 문장으로 소개해 주세요.",
}

response = requests.post(url, json=payload, headers=headers)
print(response.json())
```

사용 가능한 `model` 값은 오른쪽의 Try 패널 드롭다운에서 직접 확인할 수 있으며, 일반적으로 사용되는 카테고리는 다음과 같습니다:

* OpenAI: `gpt-5.4-mini`, `gpt-5.4-nano`, `gpt-5.2-pro`, `gpt-5.1-all`, `gpt-5-all`, `gpt-4.1`, `gpt-4o`, `gpt-4o-image`, `o3`, `o4-mini` 등
* Anthropic: `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-opus-4-5-20251101`, `claude-sonnet-4-6`, `claude-sonnet-4-5-20250929`, `claude-haiku-4-5-20251001` 등
* Google: `gemini-3.1-pro`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-image-preview`, `gemini-3-pro-preview`, `gemini-2.5-flash-lite` 등
* xAI: `grok-4` 등
* DeepSeek: `deepseek-v4-flash`, `deepseek-v3.2-exp`, `deepseek-r1-0528` 등
* Moonshot: `kimi-k3`, `kimi-k2.6`, `kimi-k2.5` 등
* Zhipu: `glm-5.1`, `glm-5`, `glm-5-turbo`, `glm-4.7`, `glm-4.5v` 등

구체적인 요금 규칙은 서비스 페이지의 Pricing 카드에서 확인할 수 있습니다.

## 다중 회차 대화

v1과 마찬가지로 `stateful: true`를 전달하여 세션 저장을 활성화하면 API가 `id`를 반환합니다. 이후 요청 시 `id`를 함께 전달하면 대화를 계속할 수 있으며, 메시지 기록을 직접 관리할 필요가 없습니다.

첫 번째 요청:

```shell theme={null}
curl -X POST 'https://api.acedata.cloud/aichat2/conversations' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.4",
    "stateful": true,
    "question": "숫자 하나를 기억해 주세요: 42."
  }'
```

반환:

```json theme={null}
{
  "answer": "좋아요, 42를 기억했습니다. 이 숫자로 무엇을 할까요?",
  "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44"
}
```

두 번째 요청, 동일한 `id`를 포함하여:

```shell theme={null}
curl -X POST 'https://api.acedata.cloud/aichat2/conversations' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.4",
    "stateful": true,
    "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44",
    "question": "방금 당신에게 기억하라고 한 숫자는 무엇인가요?"
  }'
```

```json theme={null}
{
  "answer": "당신이 기억하라고 한 숫자는 42입니다.",
  "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44"
}
```

> `stateful`의 기본값은 `true`이며, 생략하거나 명시적으로 `true`를 전달하는 것과 같습니다. 서버가 이 대화 세션을 저장하지 않기를 원한다면, 명시적으로 `stateful: false`로 설정할 수 있습니다.

## 스트리밍 응답

v2는 두 가지 스트리밍 형식을 지원하며, `accept` 헤더에 따라 선택합니다:

| 장면                      | `accept`               | 데이터 형태                                       |
| ----------------------- | ---------------------- | -------------------------------------------- |
| 웹 프론트엔드 / EventSource   | `text/event-stream`    | `data: {json}\n\n`, 마지막 줄 `data: [DONE]\n\n` |
| 서버 / CLI / Node 스트리밍 파싱 | `application/x-ndjson` | 각 줄마다 하나의 JSON 객체                            |
| 스트리밍 필요 없음              | `application/json`（기본） | 한 번에 `{answer, id}` 반환                       |

### NDJSON 예시

```python theme={null}
import json
import requests

url = "https://api.acedata.cloud/aichat2/conversations"

headers = {
    "accept": "application/x-ndjson",
    "authorization": "Bearer {token}",
    "content-type": "application/json",
}

payload = {
    "model": "gpt-5.4",
    "stateful": True,
    "question": "세 문장으로 항저우를 소개해 주세요.",
}

with requests.post(url, json=payload, headers=headers, stream=True) as resp:
    answer = ""
    for line in resp.iter_lines():
        if not line:
            continue
        event = json.loads(line)
        if event.get("type") == "text_delta":
            # v1과의 호환성: 증분 조각은 delta_answer 필드를 통해 제공
            answer += event["content"]
            print(event["delta_answer"], end="", flush=True)
        elif event.get("type") == "done":
            print()
            print("usage =", event.get("usage"))
```

NDJSON의 각 줄은 구조화된 이벤트이며, 가장 일반적인 것은 `text_delta`입니다:

```json theme={null}
{"type":"text_delta","content":"항","delta_answer":"항","id":"f2f4b3e8-..."}
{"type":"text_delta","content":"저","delta_answer":"저","id":"f2f4b3e8-..."}
{"type":"text_delta","content":"우","delta_answer":"우","id":"f2f4b3e8-..."}
...
{"type":"done","conversation_id":"f2f4b3e8-...","usage":{"prompt_tokens":21,"completion_tokens":58,"total_tokens":79},"terminal_reason":"natural_stop"}
```

### SSE 예시

브라우저 측에서 `EventSource`는 사용자 정의 요청 본문을 지원하지 않으므로, `fetch` + 수동으로 `\n\n`로 분할하여 파싱하는 것을 권장합니다:

```javascript theme={null}
const resp = await fetch("https://api.acedata.cloud/aichat2/conversations", {
  method: "POST",
  headers: {
    accept: "text/event-stream",
    authorization: "Bearer {token}",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    model: "gpt-5.4",
    stateful: true,
    question: "세 문장으로 항저우를 소개해 주세요.",
  }),
});

const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });
  const blocks = buffer.split("\n\n");
  buffer = blocks.pop() ?? "";
  for (const block of blocks) {
    const dataLine = block.split("\n").find((l) => l.startsWith("data: "));
    if (!dataLine) continue;
    const payload = dataLine.slice(6);
    if (payload === "[DONE]") return;
    const event = JSON.parse(payload);
    if (event.type === "text_delta") process.stdout.write(event.content);
  }
}
```

### 스트리밍 이벤트 유형

| `type`              | 의미                                                                                                              |
| ------------------- | --------------------------------------------------------------------------------------------------------------- |
| `text_delta`        | 도우미의 응답 증분 텍스트 조각. `content`는 추가된 내용; v1과의 호환성을 위해 동일한 이벤트는 `delta_answer`(즉, `content`와 동일)와 `id`를 포함합니다.      |
| `thinking`          | 모델의 사고 과정(선택한 모델이 reasoning을 노출할 때만 발생).                                                                        |
| `tool_use`          | 모델이 도구를 호출하기로 결정했으며, 이벤트는 `tool_id`, `tool_name`, `input`을 포함합니다.                                               |
| `tool_result`       | 도구 실행 결과, 이전 `tool_use`와 `tool_id`로 쌍을 이루며, `is_error`는 실패 여부를 나타냅니다.                                           |
| `card`              | 도구에서 생성된 구조화된 카드(예: 이미지, 링크 미리보기), 직접 렌더링하기에 적합합니다.                                                             |
| `citation`          | 해당 텍스트 조각의 출처 URL을 보충하는 데 사용됩니다.                                                                                |
| `ask_user_question` | 모델이 사용자에게 추가 정보를 요청할 때 발생하며, 대화는 `awaiting_user_input` 상태로 전환됩니다.                                               |
| `artifact`          | 모델이 생성한 독립적인 산출물(예: 코드 블록, 문서)으로, 저장하거나 다운로드할 수 있습니다.                                                           |
| `system_message`    | 시스템 알림 메시지(사용자와 도우미 간의 내용이 아님), UI 알림에만 사용됩니다.                                                                  |
| `compact`           | 내부 컨텍스트가 압축된 이벤트로, 특별한 처리가 필요 없습니다.                                                                             |
| `error`             | 이 라운드에서 오류가 발생했으며, `message`는 오류 내용을 설명합니다.                                                                     |
| `done`              | 스트리밍 응답이 종료되었으며, `usage`(포함된 `prompt_tokens` / `completion_tokens` / `total_tokens`)와 `terminal_reason`을 포함합니다. |

최종 답변만을 걱정하는 클라이언트는 모든 `text_delta`의 `content`를 연결하면 `application/json` 모드에서의 `answer`와 동일합니다.

## 다중 모드 입력

사용자 입력에 이미지나 파일이 포함된 경우, `question` 대신 `message`(배열)를 전달합니다. 각 배열 요소는 하나의 콘텐츠 블록입니다:

```json theme={null}
{
  "model": "gpt-5.4",
  "stateful": true,
  "message": [
    { "type": "text", "text": "이 이미지에는 고양이가 몇 마리 있나요?" },
    { "type": "image_url", "image_url": { "url": "https://cdn.acedata.cloud/cats.jpg" } }
  ]
}
```

지원되는 블록 유형:

* `text` — 일반 텍스트, 필수 `text` 필드.
* `image_url` — 이미지, 필수 `image_url.url`.
* `file_url` — 파일(PDF, CSV, TXT 등), 필수 `file_url.url`.

### v1 `references`와의 관계

구형 클라이언트와의 호환성을 위해, v2는 여전히 `references: ["https://...", ...]` 필드를 인식합니다:

* URL 접미사는 `jpg / jpeg / png / gif / bmp / webp / svg / heic / heif`인 경우, 자동으로 `image_url` 블록으로 변환됩니다;
* 다른 확장자는 `file_url` 블록으로 변환됩니다;
* 만약 `question`이 함께 제공되면, 이를 `text` 블록으로 앞에 배치합니다.

따라서 v1에서 마이그레이션을 원하지만 요청 본체를 변경하고 싶지 않다면, 경로를 `/aichat2/conversations`로 변경하면 됩니다. 원래의 `references` 사용법은 그대로 작동합니다.

더 세밀한 제어가 필요하다면 (예: 여러 이미지를 텍스트 사이에 배치하거나 순서가 중요한 경우) `message` 배열을 직접 사용하세요.

## 도구 호출 및 MCP

v2의 핵심 강화점은 모델이 도구를 자율적으로 호출하여 다단계 작업을 수행할 수 있다는 것입니다. **이는 기본적으로 활성화되어 있으며**, 클라이언트가 요청에 추가 구성을 할 필요가 없습니다. 일반적인 시나리오는 다음과 같습니다:

* 사용자가 "최근 상하이에 어떤 새로운 전시가 있는지 검색해줘"라고 질문하면 → 모델이 내장 웹 검색을 호출하여 → 결과를 정리하여 답변합니다.
* 사용자가 "이 PDF를 읽고 요약을 작성해줘"라고 질문하면 → 모델이 file\_read를 호출하여 → 요약을 작성합니다.
* 사용자가 [Connections](https://platform.acedata.cloud/connections)에서 Google Drive / GitHub / Notion 등을 권한 부여한 경우 → 모델이 해당 MCP 도구를 호출하여 데이터를 읽고 쓸 수 있습니다.

NDJSON / SSE 스트림에서 도구 호출은 `tool_use` 및 `tool_result` 두 가지 이벤트로 표시됩니다. 예를 들어:

```json theme={null}
{"type":"tool_use","tool_id":"toolu_01ABCDEF","tool_name":"web_search","input":{"query":"상하이 2026 봄 전시"},"id":"f2f4b3e8-..."}
{"type":"tool_result","tool_id":"toolu_01ABCDEF","output":"...","is_error":false,"id":"f2f4b3e8-..."}
{"type":"text_delta","content":"현재","delta_answer":"현재","id":"f2f4b3e8-..."}
{"type":"text_delta","content":"상하이","delta_answer":"상하이","id":"f2f4b3e8-..."}
...
```

프론트엔드에서 도구 호출 세부정보를 표시하고 싶지 않다면, `tool_use` / `tool_result` / `card` / `citation` 이 이벤트를 무시하면 됩니다. 모델의 최종 출력은 여전히 `text_delta`를 통해 전달됩니다.

`max_turns`는 이번 요청에서 모델이 도구를 최대 몇 번 호출할 수 있는지를 제한할 수 있으며, 기본 한도는 플랫폼에서 결정합니다. 이를 작게 설정하면 (예: `max_turns: 1`) 단일 응답을 강제하고 도구 호출을 허용하지 않습니다.

## 비동기 실행 및 무인 승인

알림 Webhook, CI/CD, 모니터링 시스템 또는 기타 백그라운드 작업에서 호출이 발생하는 경우, `async: true`를 설정하여 인터페이스가 즉시 작업 ID를 반환하고 백그라운드에서 계속 실행되도록 할 수 있습니다:

```json theme={null}
{
  "model": "gpt-5.5",
  "async": true,
  "question": "내 서비스가 경고를 발생시켰습니다. 개인 WeChat으로 'AceDataCloud 팀'의 WeChat 그룹에 알림을 보내주세요……"
}
```

반환 예시:

```json theme={null}
{
  "task_id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44",
  "conversation_id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44",
  "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44",
  "status": "queued"
}
```

이후 `action: retrieve` + `id`를 사용하여 세션 결과를 조회할 수 있습니다. 또한 `callback_url`을 제공하면, 작업이 완료된 후 플랫폼이 `{ status, answer, usage, error }`를 POST하여 귀하의 콜백 주소로 전송합니다. `callback_url`은 `http` / `https`를 사용해야 하며, `localhost` 또는 개인 IP 리터럴 주소를 직접 입력할 수 없습니다.

백그라운드 작업은 일반적으로 사람이 확인할 수 없습니다. 특정 Skill 또는 MCP Server가 무인 모드에서 전송, 게시, 쓰기 등의 작업을 수행하도록 하려면 요청 본체에 명시적으로 사전 승인 목록을 전달해야 합니다:

```json theme={null}
{
  "model": "gpt-5.5",
  "async": true,
  "allowed_skills": ["acedatacloud/personal-wechat"],
  "allowed_mcp_servers": [],
  "question": "내 서비스가 경고를 발생시켰습니다. 개인 WeChat으로 'AceDataCloud 팀'의 WeChat 그룹에 알림을 보내주세요……"
}
```

`allowed_skills`의 값은 연결된 Skill의 슬러그입니다; `allowed_mcp_servers`의 값은 연결된 MCP Server의 슬러그입니다. 사전 승인 목록에 포함되지 않은 Skill / MCP Server는 무인 모드에서 여전히 미리보기, dry-run 또는 쓰기 작업을 거부할 수 있습니다.

더 세밀한 제어가 필요하다면, 동등한 `unattended_policy` 객체를 사용할 수도 있습니다:

```json theme={null}
{
  "unattended_policy": {
    "allowed_skills": ["acedatacloud/personal-wechat"],
    "allowed_mcp_servers": [],
    "expires_at": 1790000000
  }
}
```

사전 승인은 이 두 목록 자체를 의미합니다: 목록이 비어 있으면 어떤 능력도 승인되지 않으며, 추가 스위치 필드가 필요하지 않습니다.

주의: 사전 승인은 "이번 요청에서 이러한 능력이 무인 모드에서 인적 확인을 건너뛰도록 허용됩니다"를 나타냅니다. 특정 Skill은 여전히 `--unattended-confirm` 또는 해당 보안 메커니즘을 지원해야 합니다; 그렇지 않으면 계속해서 dry-run을 수행하며 직접 쓰기 작업을 실행하지 않습니다.

## 일시 중지된 대화 복구

일부 도구는 모델이 "사용자에게 재질문"하도록 하며, 이때 모델은 `ask_user_question` 이벤트를 발송하고 대화는 `awaiting_user_input` 상태로 동결됩니다:

```json theme={null}
{
  "type": "ask_user_question",
  "tool_id": "toolu_01XYZW",
  "tool_name": "ask_user_question",
  "question": "생성할 보고서는 중국어로 할까요, 영어로 할까요?",
  "options": ["중국어", "영어"],
  "id": "f2f4b3e8-..."
}
```

프론트엔드에서 이 이벤트를 카드로 렌더링하여 사용자가 답변을 선택하게 한 후, 동일한 `id`로 다음 요청을 시작하고 답변을 `tool_results`를 통해 다시 채워 넣습니다:

```shell theme={null}
curl -X POST 'https://api.acedata.cloud/aichat2/conversations' \
  -H 'accept: text/event-stream' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.4",
    "stateful": true,
    "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44",
    "tool_results": [
      {
        "tool_use_id": "toolu_01XYZW",
        "output": "중국어"
      }
    ]
  }'
```

요청 본체의 `tool_use_id`는 **반드시** 일시 중지 시의 `tool_id`와 완전히 일치해야 하며, 일치하지 않으면 400 오류가 반환됩니다. 요청에 `tool_results`가 동시에 존재하는 경우, `question` / `message` / `references`는 모두 무시됩니다.

사용자가 이 문제를 포기하기로 결정하면, 새로운 `question` / `message`를 직접 전달하면 됩니다. 플랫폼은 자동으로 일시 중지된 도구 호출을 "사용자가 건너뜀"으로 표시합니다.

## 세션 관리 (CRUD)

v2는 동일한 엔드포인트에서 `action` 필드를 통해 경량 세션 관리를 제공하며, 별도의 API를 열 필요가 없습니다.

### `action: retrieve` —— 세션 가져오기

```shell theme={null}
curl -X POST 'https://api.acedata.cloud/aichat2/conversations' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "action": "retrieve",
    "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44"
  }'
```

완전한 대화 문서 반환(포함 `messages` 이력, `model`, `title`, `tools_used` 등).

### `action: retrieve_batch` —— 대화 요약 목록

```json theme={null}
{
  "action": "retrieve_batch",
  "model_group": "chatgpt",
  "limit": 20,
  "offset": 0
}
```

`{ items: [...], total }` 반환. **요약에는 `messages`가 포함되지 않음**, 사이드바 목록에 적합; 사용자가 특정 대화를 클릭하면, `action: retrieve`를 사용하여 그 대화의 전체 메시지를 개별적으로 가져옴.

선택적 필터링 매개변수: `user_id`, `application_id`, `model_group`, `model`.

### `action: update` —— 제목 변경 또는 이력 재작성

```json theme={null}
{
  "action": "update",
  "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44",
  "title": "항저우 여행 계획"
}
```

`messages`도 전달할 수 있지만, 서버는 엄격한 스키마 검증을 수행함(반드시 접힌 형태의 `ToolUseContent`이어야 하며, 그렇지 않으면 400을 반환). 일반적으로 `title` 변경에만 사용하는 것이 좋음.

### `action: delete` —— 대화 삭제

```json theme={null}
{
  "action": "delete",
  "id": "f2f4b3e8-0c0a-4d3a-aaa2-7ff80c0a1c44"
}
```

`{ id, success: true }` 반환. 삭제 후에는 복구할 수 없으니, 확인 후 호출할 것.

## v1에서 부드럽게 마이그레이션

이미 [`/aichat/conversations`](https://platform.acedata.cloud/documents/aichat-conversations)를 사용 중이라면, v2로 마이그레이션할 때 코드 변경이 거의 필요하지 않음:

1. URL을 `https://api.acedata.cloud/aichat/conversations`에서 `https://api.acedata.cloud/aichat2/conversations`로 변경.
2. 이전에 v1 모델 이름(예: `gpt-3.5`, `gpt-4-browsing` 등)을 사용했다면, v2로 전환할 때 최신 모델(예: `gpt-5.4`, `claude-opus-4-8`, `gemini-3.1-pro` 등)로 업그레이드하는 것이 좋음.
3. NDJSON 스트림의 필드는 하위 호환성을 유지: 각 `text_delta` 이벤트는 여전히 `delta_answer`와 `id`를 포함하므로, 원래 행 단위로 `delta_answer`를 파싱하던 클라이언트는 변경할 필요 없음.

마이그레이션 후 필요에 따라 v2의 새로운 기능(다중 모드 `message`, SSE, 도구 호출, `action` CRUD)을 활성화할 수 있으며, 원하는 속도로 진행하면 됨.

## 오류 처리

오류 응답은 통일되어 있음:

```json theme={null}
{
  "error": {
    "code": "chat_error",
    "message": "상류 LLM이 오류를 반환했습니다"
  },
  "trace_id": "2cf86e86-22a4-46e1-ac2f-032c0f2a4e89"
}
```

일반적인 오류:

* `400 bad_request`: 필수 필드 누락, `tool_use_id` 불일치, `messages` 스키마 불법 등.
* `401 invalid_token`: `authorization` 헤더가 올바르지 않음.
* `404 not_found`: `action: retrieve / update / delete` 시 `id`에 해당하는 대화가 존재하지 않음.
* `429 too_many_requests`: 속도 제한이 발생함.
* `500 chat_error`: 상류 LLM 오류 또는 이번 라운드 `completion_tokens=0`(소비되지 않은 것으로 처리, 요금 부과되지 않음).

스트리밍 응답에서 오류는 `{"type":"error","message":"..."}` 이벤트로 발송되며, 그 직후 스트림이 종료됨.

## 결론

AI Chat v2 API는 v1과의 하위 호환성을 유지하면서 대화를 "단일/다중 회답"에서 "에이전트화된 관찰 가능한 대화"로 업그레이드함: 다중 모드 입력, 도구 호출, 일시 중지/재개 가능, 스트리밍 구조화된 이벤트, 내장 CRUD. 새로운 통합은 직접 v2를 사용하는 것이 좋으며, 기존 v1 통합은 단계적으로 부드럽게 마이그레이션할 수 있음. 질문이 있으면 언제든지 기술 지원 팀에 문의하십시오.
