콘텐츠로 이동

채팅

채팅은 대화를 바탕으로 텍스트를 생성합니다. Sakuranbo AI에는 채팅 엔드포인트가 두 개 있습니다. 두 엔드포인트는 같은 모델을 실행하고 같은 방식으로 과금하며, 요청과 응답의 형식만 다릅니다.

  • POST /v1/chat/completions 엔드포인트는 OpenAI Chat Completions API와 호환됩니다.
  • POST /v1/messages 엔드포인트는 Anthropic Messages API와 호환됩니다.

두 엔드포인트 모두 Authorization: Bearer로 보내는 API 키가 필요합니다. 인증을 참고하세요. POST /v1/messages 엔드포인트는 Anthropic SDK가 키를 담아 보내는 x-api-key 헤더로 보낸 키도 받습니다.

이 페이지의 예시에서 사용하는 모델은 sakuranbo/cherrytext-1.0-flash입니다. 텍스트 모델을 찾으려면 task=chat으로 GET /v1/models 엔드포인트를 호출하세요. 모델 API를 참고하세요. 텍스트 모델이 아닌 모델을 지정하면 404와 model_not_found가 반환됩니다.

OpenAI와 Anthropic의 공식 SDK를 사용할 수 있습니다. SDK가 Sakuranbo AI를 가리키도록 설정하고 Sakuranbo AI API 키를 지정하세요. OpenAI SDK는 /v1을 포함한 기본 URL을 기대합니다. Anthropic SDK는 /v1/messages를 스스로 덧붙이므로 기본 URL에 /v1을 포함하지 않습니다.

TypeScript용 OpenAI SDK:

import OpenAI from "openai";
const apiKey = process.env.SAKURANBO_API_KEY;
if (!apiKey) throw new Error("Set the SAKURANBO_API_KEY environment variable.");
const client = new OpenAI({
baseURL: "https://api.sakuranbo.ai/v1",
apiKey,
});
const completion = await client.chat.completions.create({
model: "sakuranbo/cherrytext-1.0-flash",
messages: [
{
role: "system",
content: "You are a concise assistant."
},
{
role: "user",
content: "Summarize the benefits of prepaid API credits in two lines."
}
],
max_tokens: 2048
});
console.log(completion.choices[0]?.message.content);

Python용 OpenAI SDK:

import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.sakuranbo.ai/v1",
api_key=os.environ["SAKURANBO_API_KEY"],
)
completion = client.chat.completions.create(
model="sakuranbo/cherrytext-1.0-flash",
messages=[
{
"role": "system",
"content": "You are a concise assistant.",
},
{
"role": "user",
"content": "Summarize the benefits of prepaid API credits in two lines.",
},
],
max_tokens=2048,
)
print(completion.choices[0].message.content)

TypeScript용 Anthropic SDK:

import Anthropic from "@anthropic-ai/sdk";
const apiKey = process.env.SAKURANBO_API_KEY;
if (!apiKey) throw new Error("Set the SAKURANBO_API_KEY environment variable.");
// Pass the key as authToken too, so the SDK does not send ANTHROPIC_AUTH_TOKEN from the environment.
const client = new Anthropic({
baseURL: "https://api.sakuranbo.ai",
apiKey,
authToken: apiKey,
});
const message = await client.messages.create({
model: "sakuranbo/cherrytext-1.0-flash",
max_tokens: 2048,
system: "You are a concise assistant.",
messages: [
{
role: "user",
content: "Summarize the benefits of prepaid API credits in two lines."
}
]
});
console.log(message.content);

Python용 Anthropic SDK:

import os
import anthropic
api_key = os.environ["SAKURANBO_API_KEY"]
# Pass the key as auth_token too, so the SDK does not send ANTHROPIC_AUTH_TOKEN from the environment.
client = anthropic.Anthropic(
base_url="https://api.sakuranbo.ai",
api_key=api_key,
auth_token=api_key,
)
message = client.messages.create(
model="sakuranbo/cherrytext-1.0-flash",
max_tokens=2048,
system="You are a concise assistant.",
messages=[
{
"role": "user",
"content": "Summarize the benefits of prepaid API credits in two lines.",
},
],
)
print(message.content)

API는 서버에서 호출하세요. API 키를 브라우저에서 실행되는 코드에 넣지 마세요.

POST /v1/chat/completions 엔드포인트는 messages 목록을 받아 모델의 다음 메시지를 반환합니다.

터미널 창
curl -X POST "https://api.sakuranbo.ai/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAKURANBO_API_KEY" \
-d '{
"model": "sakuranbo/cherrytext-1.0-flash",
"messages": [
{
"role": "system",
"content": "You are a concise assistant."
},
{
"role": "user",
"content": "Summarize the benefits of prepaid API credits in two lines."
}
],
"max_tokens": 2048
}'

생성된 메시지는 choices[0].message에 있고, usage에는 토큰 수와 비용이 들어 있습니다. 사용량과 비용을 참고하세요.

이름타입필수기본값제약
modelstring예
messagesobject[]예1개 이상
max_tokensinteger아니요
max_completion_tokensinteger아니요
temperaturenumber아니요0~2
top_pnumber아니요0~1
stopstring | string[]아니요string[]: 최대 4개
seedinteger아니요1 이상
userstring아니요최대 512자
toolsobject[]아니요최대 128개
tool_choicestring | object아니요string: 다음 중 하나: none, auto, required
response_formatobject아니요
nnumber아니요다음 중 하나: 1
streamboolean아니요
stream_optionsobject | null아니요

파라미터의 범위와 기본값은 모델마다 다릅니다. 이 표는 예시 모델의 것입니다.

이름타입필수기본값제약설명
messagesobject[]예OpenAI Chat Completions 형식의 대화 메시지.
max_tokensinteger아니요40961~131,072추론에 사용되는 토큰을 포함한 최대 생성 토큰 수. 값이 너무 작으면 답변을 쓰기 전에 응답이 잘릴 수 있습니다. 잔액 홀드는 이 값으로 계산됩니다.
temperaturenumber아니요10~2샘플링 온도.
streamboolean아니요false토큰을 Server-Sent Events로 스트리밍합니다.

max_tokens가 범위를 벗어나면 400과 invalid_request가 반환됩니다. error.details.minimum과 error.details.maximum에 허용 범위가 담깁니다. 요청에 max_tokens와 max_completion_tokens가 모두 있으면 max_completion_tokens를 사용합니다.

함수 도구(tools와 tool_choice)와 response_format을 지원합니다. 도구 호출은 choices[0].message.tool_calls로 돌아옵니다.

메시지에는 텍스트만 담을 수 있습니다. 이미지처럼 다른 유형의 콘텐츠 파트는 400을 반환하며, error.param이 해당 파트를 가리킵니다. 필드 표에 없는 파라미터도 400을 반환하며, error.param은 그 파라미터의 이름입니다.

assistant 메시지에 텍스트도 tool_calls 항목도 없거나 content 배열이 비어 있으면 400을 반환합니다. 추론 도중 출력이 끊기면 텍스트도 도구 호출도 없는 응답이 올 수 있으므로, 그런 응답은 대화 기록에 넣지 말고 max_tokens를 늘려서 다시 요청하세요.

POST /v1/messages 엔드포인트는 Anthropic Messages API 형식의 대화를 받습니다.

터미널 창
curl -X POST "https://api.sakuranbo.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAKURANBO_API_KEY" \
-d '{
"model": "sakuranbo/cherrytext-1.0-flash",
"max_tokens": 2048,
"system": "You are a concise assistant.",
"messages": [
{
"role": "user",
"content": "Summarize the benefits of prepaid API credits in two lines."
}
]
}'
이름타입필수기본값제약
modelstring예
messagesobject[]예1개 이상
systemstring | object[]아니요
max_tokensinteger예
temperaturenumber아니요0~1
top_pnumber아니요0~1
stop_sequencesstring[]아니요최대 4개
streamboolean아니요
toolsobject[]아니요최대 128개
tool_choiceobject아니요

OpenAI 형식과 다른 점은 다음과 같습니다.

  • max_tokens는 필수입니다.
  • system은 최상위 필드입니다. 역할이 system인 메시지는 400을 반환합니다.
  • temperature의 허용 범위는 Anthropic API를 따르므로 POST /v1/chat/completions 엔드포인트의 범위와 다릅니다.
  • anthropic-version 헤더는 필요하지 않습니다. SDK가 보내더라도 서버는 무시합니다.
  • 메시지에는 텍스트와 도구 블록만 담을 수 있습니다. image 블록은 400을 반환합니다. top_k나 thinking처럼 필드 표에 없는 파라미터도 400을 반환합니다.
  • assistant 메시지에는 비어 있지 않은 문자열 content, 또는 text나 tool_use 블록이 있는 content 배열이 필요합니다. 추론 도중 출력이 끊겨 content가 빈 배열로 온 응답을 대화 기록에 넣으면 400을 반환하므로, max_tokens를 늘려서 다시 요청하세요.
  • 모든 오류 본문은 Anthropic 형식을 따릅니다. type은 error이고, 자세한 내용은 error에 들어 있으며, request_id는 최상위 필드입니다. 401, 404, 405도 마찬가지입니다.

stream을 true로 설정하면 응답을 server-sent events로 받습니다. 첫 토큰은 모델이 만들어 내는 즉시 도착합니다.

터미널 창
curl -N -X POST "https://api.sakuranbo.ai/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAKURANBO_API_KEY" \
-d '{
"model": "sakuranbo/cherrytext-1.0-flash",
"messages": [
{
"role": "system",
"content": "You are a concise assistant."
},
{
"role": "user",
"content": "Summarize the benefits of prepaid API credits in two lines."
}
],
"max_tokens": 2048,
"stream": true,
"stream_options": {
"include_usage": true
}
}'

OpenAI 형식에서는 각 이벤트가 chat.completion.chunk 객체를 담은 data: 줄이며, choices[].delta에 새 텍스트가 들어 있습니다. 스트림은 data: [DONE]으로 끝납니다. 비용이 담긴 usage 객체는 choices 배열이 빈 마지막 청크로 도착하며, stream_options.include_usage를 true로 설정한 경우에만 도착합니다.

Anthropic 형식에서는 각 이벤트에 event: 줄과 data: 줄이 있습니다. 이벤트는 다음 순서로 도착합니다.

  1. message_start
  2. 콘텐츠 블록마다 content_block_start, 하나 이상의 content_block_delta 이벤트, content_block_stop
  3. stop_reason과 비용을 포함한 usage가 들어 있는 message_delta
  4. message_stop

Anthropic SDK는 자신이 아는 필드만으로 최종 메시지를 구성하므로 usage.cost는 최종 메시지에 들어 있지 않습니다. 비용을 읽으려면 message_delta 이벤트의 usage를 읽으세요.

스트림이 시작되기 전의 실패(인증 오류나 검증 오류 등)는 HTTP 상태와 함께 일반 JSON 오류를 반환합니다. 스트림이 시작된 뒤의 실패는 상태를 바꿀 수 없으므로 상태는 200으로 유지됩니다. OpenAI 형식에서는 스트림이 error 객체가 담긴 data: 줄을 보낸 다음 data: [DONE]을 보냅니다. Anthropic 형식에서는 event: error 이벤트를 보내며 message_stop은 보내지 않습니다.

스트리밍이 아닌 응답은 비용을 두 곳에, 토큰 수를 usage에 담아 보고합니다.

  • usage.cost에는 micro USD 단위의 금액이 amount_micro_usd로, 십진수 문자열 금액이 amount_usd로 들어 있습니다.
  • X-Usage-Cost-Usd 헤더에 같은 USD 문자열이 들어 있습니다.
  • usage에는 토큰 수가 들어 있습니다. OpenAI 형식에서는 prompt_tokens, completion_tokens, total_tokens, prompt_tokens_details.cached_tokens이고, Anthropic 형식에서는 input_tokens, output_tokens, cache_read_input_tokens입니다. input_tokens에는 캐시된 토큰이 포함되지 않습니다.

스트리밍 응답에는 X-Usage-Cost-Usd 헤더가 없습니다. 대신 마지막 usage 객체에서 비용을 읽으세요.

요청을 실행하기 전에 Sakuranbo AI는 잔액에서 일정 금액을 확보합니다. 확보 금액은 입력의 크기와 max_tokens로 예상합니다. 요청이 끝나면 실제 토큰 수로 청구액을 계산하고, 확보했던 금액의 나머지는 잔액으로 돌아옵니다. 출력을 하나도 생성하기 전에 모델 쪽에서 실패한 요청은 과금되지 않습니다.

  • 확보 금액은 max_tokens를 사용해 계산하므로, 실제 비용은 잔액으로 충분하더라도 요청이 402로 거부될 수 있습니다. max_tokens는 필요한 길이로 설정하세요.
  • 모델이 출력을 생성하기 시작한 뒤 스트림이 끊기면, 스트림이 오류로 끝나더라도 요청은 과금됩니다. 출력에는 추론 출력이 포함되며, 이용자에게 도달했는지와 관계없이 과금됩니다. Anthropic 형식은 추론 출력을 반환하지 않으므로, 텍스트를 하나도 받지 못했더라도 과금될 수 있습니다. 최종 토큰 수가 도착하지 않았다면 청구액을 추정해 계산합니다. 입력은 확보에 사용한 상한으로, 출력은 추론 출력과 도구 호출을 포함해 이미 생성된 출력의 크기로 계산하므로 청구액이 실제 사용량보다 높을 수 있습니다. 확보한 금액을 넘지는 않습니다.
  • 스트림이 끝나기 전에 연결을 닫아도 요청은 끝까지 실행되며, 생성된 출력 전체가 과금됩니다.
  • 채팅 요청은 Idempotency-Key를 사용하지 않습니다. 재시도한 요청은 새 요청이며 다시 과금됩니다.

가격은 모델 카탈로그의 모델 페이지와 요금 페이지에서 확인하거나, 요청을 실행하기 전에 POST /v1/estimate 엔드포인트로 계산할 수 있습니다. 비용 계산 API를 참고하세요. 잔액을 확인하려면 잔액과 API 키 사용 한도를 참고하세요.

코드HTTP 상태유형설명
invalid_request400invalid_request_error요청 형식이 올바르지 않거나 값이 허용 범위를 벗어났습니다. 유효한 값을 알 수 있는 경우 details.allowed에 담깁니다.
unauthorized401authentication_errorAPI 키가 없거나, 형식이 올바르지 않거나, 존재하지 않거나, 폐기되었거나, 만료되었습니다. 응답은 그중 어느 경우인지 알려 주지 않습니다.
balance_insufficient402insufficient_balance사용 가능한 잔액이 이 요청에 확보해야 하는 금액보다 적습니다. error.details.limit_source는 balance입니다.
key_limit_exceeded402insufficient_balance이 요청을 실행하면 API 키가 사용 한도를 넘게 됩니다. error.details.limit_source는 key이고, error.details.resets_at에 카운터가 다시 시작되는 시각이 담깁니다.
account_suspended403permission_error계정이 정지되어 이미지, 영상, 채팅 요청이 거부됩니다. 지원팀에 문의하세요. 잔액, 입금, API 키, 작업은 계속 사용할 수 있습니다.
model_not_found404not_found_error카탈로그에 없는 모델 ID입니다. 채팅 엔드포인트는 텍스트 모델이 아닌 모델에도 이 코드를 반환합니다.
payload_too_large413invalid_request_error요청 본문이 허용 크기를 초과했습니다. error.details.max_bytes가 허용 크기입니다.
rate_limited429rate_limit_error모델 제공업체가 요청을 제한하고 있습니다. POST /v1/reports는 같은 주소에서 신고가 너무 많이 들어올 때도 이 코드를 반환합니다. Retry-After 헤더에 표시된 시간이 지난 뒤 다시 시도하세요.
upstream_error502upstream_error업스트림 제공사가 오류를 반환했습니다.
upstream_unavailable503overloaded_error업스트림 제공사의 용량이 일시적으로 부족합니다. 잠시 후 다시 시도하세요.

POST /v1/messages 엔드포인트는 같은 코드와 HTTP 상태를 Anthropic 오류 형식으로 반환합니다. error.type은 Anthropic API를 따르므로 유형 열과 다를 수 있습니다. balance_insufficient와 key_limit_exceeded는 billing_error, payload_too_large는 request_too_large, content_policy_violation은 invalid_request_error, upstream_error는 api_error입니다. 분기에는 error.type이 아니라 error.code를 사용하세요.

429나 503 응답을 받으면 Retry-After 헤더에 표시된 초만큼 기다린 뒤 다시 시도하세요. 402 응답에는 balance 또는 key인 error.details.limit_source가 있습니다. 잔액과 API 키 사용 한도를 참고하세요. 전체 코드 목록은 오류를 참고하세요.