API Docs
FlameBOX 연결부터 첫 API 호출까지.
Quickstart
FlameAI는 FlameBox(설치형 로컬 추론 머신)과 API Gateway를 조합해 동작합니다. 아래 6단계를 순서대로 따라가면 첫 API 호출까지 끝낼 수 있습니다.
Windows — PowerShell에서 실행 (또는 설치파일 .exe를 내려받아 실행)
irm https://flameai.im/install.ps1 | iex
Linux — 터미널에서 실행
curl -fsSL https://flameai.im/install.sh | sh
- Windows: FlameBox를 처음 실행하면 인증 화면이 바로 열립니다.
- Linux: 터미널에서
flamebox up을 처음 실행하면https://flameai.im/registration/{token}형태의 인증 URL이 출력됩니다.
flamebox up을 한 번 더 실행해야 등록이 완료되어 내 계정에 등록되고 My AI Console에 나타납니다.
/mypage/flamebox)를 클릭해 상세 페이지로 들어간 뒤, Models 탭에서 사용할 AI 모델을 내려받습니다.구성 및 연결
외부 클라이언트의 요청이 실제 추론 결과로 돌아오기까지 거치는 경로는 다음과 같습니다.
[외부 클라이언트] │ HTTPS + Bearer(Secret Key) ▼ [API Gateway] api-N.flameai.im ← 로드밸런싱용 물리 노드 풀, API 경로로 계정 식별 │ FlameBox로 연결 하여 요청 전달 ▼ [FlameBox] 사용자 PC/서버에 설치된 추론 머신(Inference Machine) │ GPU/CPU 자원으로 다수의 Cortex(추론 인스턴스)를 관리 ▼ [Cortex] FlameBox 안에서 실행 중인 추론 인스턴스(Inference Instance, 모델 1개 상주)
- 하나의 계정에 여러 FlameBox를 등록할 수 있습니다 — 각 Cortex는 자신이 생성된 FlameBox에만 속하므로, 그 FlameBox가 온라인 상태일 때만 호출할 수 있습니다.
- FlameBox 연결이 끊기면 그 안의 Cortex 호출은 모두 실패합니다 — 다시 연결되면 자동으로 호출 가능한 상태로 돌아옵니다.
Inference Structure
FlameBox와 Cortex는 서로 다른 층의 개념입니다 — FlameBox는 추론 머신(Inference Machine), Cortex는 그 머신 위에서 실행되는 추론 인스턴스(Inference Instance)입니다.
| 구성요소 | 역할 |
|---|---|
| FlameBox Inference Machine | PC/서버에 설치되는 프로그램 자체. FlameAI 서버와의 상시 연결 유지, 모델 다운로드/보관, 그 안에서 여러 Cortex를 띄우고 관리하는 역할을 합니다. |
| Cortex Inference Instance | FlameBox 하나 위에서 실행되는 추론 인스턴스. 모델 파일을 GPU/CPU 메모리에 로드한 상태로 대기하며, API 호출을 받아 실제 추론을 수행합니다. 자세한 설명은 Inference API 섹션 참고. |
Available models
FlameBox가 다운로드해 Cortex로 띄울 수 있는 모델 목록과 각 모델의 사양은 모델 목록 페이지에서 확인할 수 있습니다.
HTTP Endpoint 열기
FlameAI 에 가입하면 API 경로와 Secret Key가 계정당 자동으로 하나 발급됩니다 — 별도로 "발급 신청"을 할 필요가 없습니다.
API 경로, base url, secret key 3가지를 확인합니다. Secret Key는 기본적으로 마스킹되어 있으며 "보기" 토글로 확인할 수 있습니다.FlameBox 추가
운영체제에 맞는 방법으로 FlameBox를 설치합니다(자세한 설치 옵션은 다운로드 페이지 참고). 새 머신에 설치 후 아래 인증 과정을 거치면 그 머신의 FlameBox가 자동으로 계정에 추가됩니다 — 이 과정을 반복해 여러 대의 FlameBox를 등록할 수 있습니다.
Windows — PowerShell에서 실행 (또는 설치파일 .exe를 내려받아 실행)
irm https://flameai.im/install.ps1 | iex
Linux — 터미널에서 실행
curl -fsSL https://flameai.im/install.sh | sh
flamebox up을 처음 실행하면 https://flameai.im/registration/{token} 형태의 인증 URL이 출력됩니다.flamebox up을 한 번 더 실행해야 등록이 완료됩니다. 등록이 끝나면 해당 FlameBox가 로그인한 계정에 등록되고, My AI Console의 FlameBox 목록에서 바로 확인할 수 있습니다.Model 다운로드
모델은 계정 단위가 아니라 FlameBox 단위로 다운로드됩니다 — 같은 계정이라도 FlameBox마다 보유한 모델이 다를 수 있습니다.
추론 인스턴스(Cortex) 생성
다운로드된 모델을 실제로 호출 가능한 상태로 띄우려면 Cortex를 생성해야 합니다.
cortexId가 해당 FlameBox 상세 페이지(/mypage/flamebox)의 Cortex 탭에 나타납니다 — 이 값을 API 호출의 {cortexId} 자리에 사용합니다.Cortex 구조와 특성
Cortex는 LLM 모델을 GPU/CPU 메모리에 로드하여 인스턴스화한 추론 실행 단위입니다. 모델 파일(.gguf)을 매 요청마다 다시 불러오지 않고 메모리에 상주시킨 상태로 대기하며, 요청이 들어오면 즉시 추론을 수행합니다. 이 구조 덕분에 다음과 같은 이점이 있습니다.
- 즉시 응답 — 모델이 이미 메모리에 로드되어 있어, 요청 시점에 모델을 새로 불러오는 지연(콜드 스타트) 없이 바로 추론을 시작합니다.
- 효율적인 멀티턴 대화 — KV Cache가 유지되므로 전체 대화 히스토리를 매번 다시 보낼 필요 없이 마지막 메시지만 전송해도 대화가 이어집니다(자세한 내용은 아래 "Stateful 동작 방식" 참고).
- 대화가 길어져도 일정한 추론 속도 — Stateless 방식은 대화가 쌓일수록 매번 전체 히스토리를 다시 처리해야 해서 추론 시간도 함께 길어지지만, Cortex는 이전 턴의 KV Cache를 그대로 재사용해 새 메시지만큼만 처리하면 되므로 대화 길이와 무관하게 추론 속도가 일정하게 유지됩니다.
- 용도별 독립 운용 — 하나의 FlameBox 안에 여러 Cortex를 동시에 띄워, 코딩용/일반 대화용처럼 목적에 맞는 모델을 나눠 운용할 수 있습니다.
다만 모델이 메모리에 상주하며 대화 컨텍스트를 유지하는 구조이다 보니, 다음과 같은 제약도 함께 따릅니다.
- Cortex별 단일 스레드 추론 — 같은 Cortex 안에서는 GPU/CPU 자원을 독점적으로 사용하므로 동시 추론이 불가능합니다. 서로 다른 Cortex끼리는 자원이 허용하는 한 동시에 추론할 수 있습니다.
- KV Cache 공유 불가 — 대화 컨텍스트는 하나의 점유자에게만 귀속됩니다.
- 단일 점유 리소스 — 한 번에 하나의 클라이언트만 사용할 수 있습니다.
# 하나의 FlameBox에 여러 Cortex를 생성해 분산 운용할 수 있습니다
[Cortex Client]
│ REST API
▼
[FlameBox]
├─ Cortex (7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a) ← 모델 로드, KV Cache, 대화 컨텍스트 보유
├─ Cortex (a13d5e67-8f2b-4c91-b3d4-1e9f7a6c5b02)
└─ Cortex (c48e2f91-3a7d-4b56-9c1e-8d2f6a4b7e03)
Stateful 동작 방식
Cortex는 내부에 KV Cache를 보유하며 Stateful 방식으로 동작합니다. 추론 완료 후에도 대화의 KV Cache가 메모리에 유지되므로, 다음 요청 시 이전 대화 전체를 다시 전송할 필요 없이 마지막 메시지만 전송해도 컨텍스트가 이어집니다.
# Stateless 방식 (일반적인 OpenAI 호환 서버) 1번 요청: [user: "안녕"] 2번 요청: [user: "안녕", assistant: "안녕하세요", user: "이름이 뭐야?"] ← 전체 히스토리 재전송 # Stateful 방식 — FlameBox Cortex 1번 요청: [user: "안녕"] → KV Cache 유지 2번 요청: [user: "이름이 뭐야?"] → 마지막 메시지만 전송
/reset을 직접 호출해야 초기화됩니다. 새로 점유한 클라이언트가 이전과 무관한 새 대화를 시작하려면, 먼저 /reset으로 컨텍스트를 비운 뒤 대화를 시작하는 것을 권장합니다.점유(Occupancy) 모델
클라이언트는 conversationId를 통해 Cortex를 선점하며, 점유 중인 Cortex에는 동일한 conversationId를 가진 클라이언트만 요청할 수 있습니다.
- 적은 리소스로 멀티 대화 지원 — Cortex 하나만으로도 여러
conversationId를 필요에 따라 전환해가며 운용할 수 있어, 대화마다 별도 Cortex를 띄우지 않아도 됩니다(단, 전환 시 컨텍스트 재구축은 클라이언트가 대화 히스토리를 다시 전송하는 방식으로 직접 구현해야 합니다). - Cortex Pool 라우팅 키로 활용 —
conversationId를 애플리케이션의 Cortex 배정 기준으로 사용하면, 여러 Cortex를 운용할 때 "이 대화가 어느 Cortex에 있는지"를 추적/관리하는 키로 쓸 수 있습니다. - 컨텍스트 오염 방지 — 점유 중인 Cortex에 다른
conversationId로 요청이 들어오면 즉시cortex_occupied에러로 차단되어, 서로 다른 대화의 메시지가 섞이는 문제를 막습니다.
점유 충돌 시 클라이언트 대응 전략
| 전략 | 설명 |
|---|---|
| 재시도 대기 | 현재 점유자가 해제할 때까지 기다린 후 재점유 |
| 강제 재점유 | /switch-conversation로 점유를 빼앗은 후 대화 히스토리로 컨텍스트 재구축 |
| 포기 | 에러를 사용자에게 전달하고 다른 Cortex 탐색 |
일반적인 사용 흐름
GET /{my_base_path}/cortexes — 사용 가능한 Cortex 확인 (내 Cortex 목록 참고)POST /{my_base_path}/cortex/{cortexId}/switch-conversation — conversationId로 Cortex 선점POST /{my_base_path}/cortex/{cortexId}/reset — 새 대화이므로 컨텍스트를 비웁니다.POST /{my_base_path}/cortex/{cortexId}/messages — 대화 히스토리 전체 + 새 메시지 전송 (SSE Stream)GET /{my_base_path}/cortex/{cortexId}/status — 컨텍스트 사용량 모니터링POST /{my_base_path}/cortex/{cortexId}/stop — 필요 시 추론 중단POST /{my_base_path}/cortex/{cortexId}/switch-conversation — 다른 conversationId로 전환하거나 ""로 점유 해제나의 API 호출 주소
FlameAI 에 가입하게 되면 나만의 API 호출을 위한 API 경로가 발급됩니다. 이 경로를 아래 형식의 URL에 넣어 API Gateway를 통해 호출합니다.
https://api-N.flameai.im/{my_base_path}/cortex/{cortexId}/{action}
예시: https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/messages
- api-N: 로드밸런싱용 물리 노드 식별자이며 API Gateway 노드의 이름입니다.
- my_base_path(API 경로): My AI Console(/mypage/settings)에서 확인 가능한 나만의 고유 경로입니다.
- 인증:
Authorization: Bearer {Secret Key}헤더 필수 (Secret Key도/mypage/settings에서 확인) - 버전:
X-API-Version헤더로 지정(생략 시 기본값1) — URL에는 버전을 넣지 않습니다.
인증 (Bearer Token)
API Gateway를 통해 호출할 때는 모든 요청에 Bearer Token을 포함해야 합니다.
POST /Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/messages HTTP/1.1 Host: api-3.flameai.im Content-Type: application/json Authorization: Bearer fai_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx X-API-Version: 1
/mypage/settings)에서 확인/재발급할 수 있습니다.공통 요청 규칙
모든 요청에 다음 규칙이 공통으로 적용됩니다.
- Body가 있는 요청(
POST등)은Content-Type: application/json헤더가 필수입니다. - Body는 UTF-8로 인코딩된 JSON이어야 합니다.
X-API-Version헤더로 API 버전을 지정합니다(선택, 생략 시 기본값1) — URL에는 버전을 넣지 않습니다.- 인증(Bearer Token) 방식은 위 "인증 (Bearer Token)" 섹션을 참고하세요.
Content-Type: application/json X-API-Version: 1 (선택, 생략 시 기본값 1)
공통 응답 규칙
- 성공 응답은 HTTP 200과 JSON 본문을 반환합니다.
- 에러 응답은 HTTP 에러 상태 코드와 함께, 아래 "에러 응답 포맷"의 JSON을 반환합니다.
성공 응답
- 일반(비스트리밍) 응답은
Content-Type: application/json으로 반환합니다. - SSE Stream 응답은
Content-Type: text/event-stream으로 반환합니다. - HTTP status가
200이면 정상 응답입니다. 응답이 JSON 포맷일 때는 JSON에error필드가 없으면 정상 응답으로 판단할 수 있습니다.
성공 응답 포맷 (비스트림)
Content-Type: application/json
{
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"conversationId": "chat-abc123",
"message": {
"id": "msg-1714000000001",
"role": "assistant",
"content": [
{ "type": "text", "text": "안녕하세요" }
],
"usage": { "input_tokens": 12, "output_tokens": 2, "elapsed_ms": 80 }
}
}
성공 응답 포맷 (스트림)
Content-Type: text/event-stream
event: message.completed
data: {"cortexId":"7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a","conversationId":"chat-abc123","message":{"id":"msg-1714000000001","role":"assistant","content":[{"type":"text","text":"안녕하세요"}],"usage":{"input_tokens":12,"output_tokens":2,"elapsed_ms":80}}}
data: [DONE]
message.created/message.delta/message.block_done/message.completed)는 대화 요청 엔드포인트 문서를 참고하세요.에러 응답
- 에러 응답은 항상
Content-Type: application/json으로 단일 패킷으로 반환합니다. - 응답 JSON에는
error필드가 항상 포함되어 있습니다. - HTTP status는 항상
200이 아닌 값으로 반환됩니다.
에러 응답 포맷
{
"error": {
"code": "에러코드",
"message": "상세 메시지",
"httpStatus": 404
}
}
| HTTP | 상황 |
|---|---|
| 400 | bad request — 파라미터 오류, JSON 파싱 실패 |
| 401 | unauthorized — 인증 실패 |
| 403 | forbidden — 인증은 되었으나 리소스 접근 권한 없음 |
| 404 | not found — URL 또는 리소스를 찾을 수 없음 |
| 409 | conflict — 점유 충돌, 추론 중 등 상태 불일치 |
| 500 | internal error — 서버 내부 오류 |
| 503 | service unavailable — FlameBox가 오프라인이거나 통신할 수 없음 |
에러 코드
에러가 발생했다는 사실은 HTTP 상태 코드만으로도 알 수 있지만, 정확히 어떤 상황인지는 응답 Body에 담긴 에러 코드로 구분해야 합니다. 이 에러 코드는 문자열 형태이며, 아래와 같습니다.
에러는 발생 지점에 따라 두 종류로 나뉩니다 — API Gateway 자체에서 즉시 반환되는 에러와, 요청이 FlameBox까지 전달된 뒤 FlameBox가 반환하는 에러입니다.
API Gateway 에러 (FlameBox 도달 전)
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | URL 경로 형식 오류(허용되지 않는 문자 포함), JSON 형식 오류, 요청 본문 50MB 초과 |
| bearer_not_found | 401 | Authorization 헤더 누락 또는 형식 오류 |
| bearer_invalid | 401 | API 경로가 존재하지 않거나 Secret Key가 일치하지 않음 |
| cortexbox_offline | 503 | 대상 FlameBox가 오프라인 상태 |
| flamebox_io_error | 503 | FlameBox와의 통신 오류 |
FlameBox 에러 (요청이 전달된 뒤 발생)
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | JSON 파싱 실패 또는 파라미터 오류 |
| unsupported_cortex_type | 400 | Cortex 종류에 맞지 않는 요청 (예: 이미지 생성 Cortex에 messages, LLM Cortex에 imageGenerate, 판정 전용 Cortex에 messages) |
| cortex_not_found | 404 | 없는 cortexId |
| file_not_found | 404 | Cortex 파일 저장소에 없는 파일 |
| not_found | 404 | 엔드포인트를 찾을 수 없음 |
| cortex_occupied | 409 | 다른 conversationId가 Cortex를 점유 중 |
| cortex_not_running | 409 | 모델이 로드되지 않은 상태에서 reset/tokenize 요청 |
| cortex_inferring | 409 | 해당 Cortex가 추론(생성) 중 |
| internal_error | 500 | 서버 내부 오류 (모델 로드 실패 포함) |
대화 요청
대화 메시지를 전송하고 AI 응답을 받습니다. SSE 스트리밍과 동기 방식을 모두 지원합니다.
Request Body
{
"conversationId": "chat-550e8400",
"tools": [],
"options": {
"stream": true,
"think": 1,
"cortex_reset": false
},
"messages": [
{ "role": "system", "content": "당신은 유용한 AI 어시스턴트입니다." },
{ "role": "user", "content": "3 더하기 3은?" }
]
}
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
conversationId | string | 예 | 구현자의 APP 내 대화 세션(Chat Session) ID를 그대로 사용해도 됩니다. 최초 대화 시 이 값으로 점유가 자동 발생하며, 이후 요청은 현재 점유 중인 conversationId와 일치해야 함 |
tools | array | 아니오 | 모델이 호출할 수 있는 도구(tool) 정의 배열. 실행은 클라이언트가 합니다 — 아래 "Tool 호출" 참고 |
options.stream | boolean | 아니오 | true면 SSE 스트리밍, false면 동기 응답 (기본값: false) |
options.think | int | 아니오 | 생각(thinking) 강도 — 0 즉답, 1 자동(기본값), 2 생각 강제. 모델마다 해석이 다릅니다(아래 표). false/true도 받으며 각각 0/1로 처리됩니다 |
options.cortex_reset | boolean | 아니오 | true면 기존 컨텍스트를 버리고 이번 messages로 새로 구성한 뒤 추론합니다. 다른 conversationId가 점유 중이어도 이 요청의 conversationId로 점유가 넘어옵니다 (기본값: false) |
options.apply_sampling | boolean | 아니오 | true면 함께 보낸 생성 설정 값(temperature 등)을 적용하고 다음 요청에도 유지 — 아래 "생성 설정 바꾸기" 참고 |
messages | array | 예 | 전달할 메시지 배열(1개 이상). 각 요소는 role과 content(문자열 또는 블록 배열) |
messages의 role
| role | 의미 |
|---|---|
system | 모델의 최상위 동작 규칙 (역할, 말투, 정책 등) |
developer | 개발자가 넣는 앱/에이전트 지침 |
user | 사용자 입력. 파일 첨부(image/document 블록)와 도구 실행 결과(tool_result 블록)도 여기에 넣습니다 |
assistant | 모델의 이전 응답 (대화 히스토리 재전송, few-shot 예시) |
tool | 도구 실행 결과를 문자열로 돌려줄 때 |
options.think 모델별 동작
| 모델 | 0 | 1 (기본) | 2 |
|---|---|---|---|
| Qwen 3 / Qwen 3.5 | 생각 없이 즉답 | 모델이 스스로 판단 | 항상 생각한 뒤 답변 |
| Gemma 4 | 생각 끔 | 생각 켬 | 생각 켬 (1과 같음 — 켜고 끄기 두 단계뿐) |
| GPT-OSS | 얕게 생각 | 보통 | 깊게 생각 (생각을 아예 끌 수는 없음) |
think: 0이어도 thinking 블록이 올 수 있습니다. thinking 블록의 signature는 항상 빈 문자열입니다.파일 첨부 — 이미지·문서
먼저 Cortex 파일 API로 파일을 올린 뒤, 응답의 file 값을 user 메시지의 content 배열에 블록으로 넣습니다. 블록은 놓인 순서대로 모델에 들어갑니다.
{ "role": "user", "content": [
{ "type": "image", "source": { "type": "file", "file": "files/upload-20261016-101500-a1b2.jpg" } },
{ "type": "document", "source": { "type": "file", "file": "files/upload-20261016-101512-c3d4.txt" } },
{ "type": "text", "text": "사진과 문서 내용을 비교해서 설명해줘" }
] }
| 블록 | 규칙 |
|---|---|
image | 이미지를 이해하는 모델(비전 모델)의 Cortex에서만 사용할 수 있습니다 — 상태 보기의 capabilities.inputs에 "type": "image"가 있는지 확인하세요. PNG·JPEG만 가능(webp 불가), 요청당 최대 4장. 이미지 1장이 수백~천여 토큰을 차지하며 usage.input_tokens에 포함됩니다. 이미지는 대화 컨텍스트에 남아 다음 요청에서 "아까 사진에서…"처럼 이어 물을 수 있습니다(cortex_reset: true면 지워짐) |
document | 텍스트 파일(txt/md/csv/json, UTF-8, 최대 256KB). 본문이 그 자리에 텍스트로 들어가며, 컨텍스트를 그만큼 차지합니다 |
"source": { "type": "file" }로 가리켜야 합니다 — base64·URL 방식은 지원하지 않습니다. 텍스트에 <__media__> 문자열을 직접 쓰면 bad_request가 됩니다.생성 설정 바꾸기 (apply_sampling)
options에 "apply_sampling": true와 바꿀 값을 함께 보내면 이번 요청부터 적용되고 다음 요청에도 유지됩니다. 대화 내용은 그대로 이어집니다.
{ "conversationId": "chat-abc123",
"options": { "stream": true, "apply_sampling": true, "temperature": 0.3, "top_p": 0.9, "max_tokens": 1024 },
"messages": [ { "role": "user", "content": "조금 더 정확하게 다시 설명해줘" } ] }
| 키 | 범위 | 설명 |
|---|---|---|
temperature | 0 ~ 2 | 0이면 항상 가장 확률 높은 토큰 |
top_p | 0 ~ 1 | 1이면 끔 |
top_k | 0 ~ | 0이면 끔 |
min_p | 0 ~ 1 | 0이면 끔 |
seed | -1 ~ 4294967294 | -1이면 무작위 |
repeat_penalty | 1.0 ~ 2.0 | 1.0이면 끔 |
max_tokens | 1 ~ 컨텍스트 크기 | 응답 최대 토큰 수 |
apply_sampling이 없거나false면 위 값을 보내도 무시됩니다.- 보낸 키만 바뀌고, 빠진 키는 마지막으로 적용한 값을 유지합니다.
cortex_reset: true, conversationId 변경, 모델 언로드 때 Cortex 기본 설정으로 돌아갑니다.- 지금 적용 중인 값은 응답
usage.sampling과 상태 보기의sampling으로 확인합니다. - 고정
seed로 같은 결과를 재현하려면 요청마다apply_sampling: true와seed를 다시 보냅니다. - 범위를 벗어나면
bad_request(400)이고 아무 값도 바뀌지 않습니다.
Tool 호출
모델이 도구를 쓰기로 하면 응답 content에 tool_use 블록이 옵니다. 클라이언트가 그 도구를 실행한 뒤, 결과를 tool_result 블록으로 다시 보내면 모델이 이어서 답합니다.
# 1) 도구 정의와 함께 요청 { "conversationId": "chat-001", "tools": [ { "name": "bash", "description": "Execute a bash command.", "parameters": { "type": "object", "properties": { "cmd": { "type": "string" } }, "required": ["cmd"] } } ], "messages": [ { "role": "user", "content": "현재 디렉터리 파일 목록 보여줘." } ] } # 2) 응답 — tool_use 블록 "content": [ { "type": "tool_use", "id": "call_001", "raw": "<모델이 출력한 tool call 원문>" } ] # 3) 실행 결과를 tool_result 블록으로 전송 { "conversationId": "chat-001", "messages": [ { "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "call_001", "content": "total 48\ndrwxr-xr-x ..." } ] } ] } # 4) 응답 — 최종 text 블록
raw에는 모델이 출력한 도구 호출 원문이 그대로 담깁니다. 형식은 모델마다 다르므로(예: Qwen 3은 JSON, Qwen 3.5는 XML) 클라이언트가 직접 파싱합니다.tool_result의tool_use_id에는 받은tool_use.id값을 넣어야 짝이 맞습니다.- Cortex가 대화를 기억하므로, 같은 conversationId라면 3단계에서 앞의 대화를 다시 보내지 않아도 됩니다.
Response — stream: false
{
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"conversationId": "chat-abc123",
"message": {
"id": "msg-1714000000001",
"role": "assistant",
"content": [
{ "type": "thinking", "thinking": "3 더하기 3을 계산해보면 6이다.", "signature": "" },
{ "type": "text", "text": "6입니다." }
],
"usage": {
"input_tokens": 42, "output_tokens": 10, "elapsed_ms": 320, "prefill_ms": 85,
"ctx_used": 52, "ctx_size": 10000, "stop_reason": "eot"
}
}
}
| 필드 | 설명 |
|---|---|
content | 블록 배열 — thinking(생각 과정) → text(답변) → tool_use(도구 호출) 순 |
usage.input_tokens | 이번 요청의 입력 토큰 수 |
usage.output_tokens | 생성한 토큰 수 (모든 블록 합계) |
usage.prefill_ms | 입력(프롬프트)을 처리하는 데 걸린 시간(ms) |
usage.elapsed_ms | 입력 처리 후 생성이 끝나기까지 걸린 시간(ms) — prefill_ms는 포함하지 않음 |
usage.ctx_used | 생성이 끝난 시점에 컨텍스트에 쌓인 토큰 수 (대화를 이어가면 누적) |
usage.ctx_size | 컨텍스트 최대 토큰 수 |
usage.stop_reason | 끝난 이유 — eot 정상 종료, n_predict 최대 생성 길이 도달, hardcap 서버 안전 상한(8192 토큰) 도달, abort 중지 요청, decode_error 생성 중 오류 |
usage.sampling | 이번 생성에 적용된 생성 설정 값 (temperature 등) |
SSE Stream 응답 포맷
Content-Type: text/event-stream
event: message.created
data: {"cortexId":"7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a","conversationId":"chat-abc123","message_id":"msg-1714000000001"}
event: message.delta
data: {"type":"text","delta_index":0,"delta":"안녕"}
event: message.delta
data: {"type":"text","delta_index":1,"delta":"하세요"}
event: message.block_done
data: {"type":"text","token_count":2,"elapsed_ms":80}
event: message.completed
data: {"cortexId":"7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a","conversationId":"chat-abc123","message":{"id":"msg-1714000000001","role":"assistant","content":[{"type":"text","text":"안녕하세요"}],"usage":{"input_tokens":12,"output_tokens":2,"elapsed_ms":80}}}
data: [DONE]
| 이벤트 | 설명 |
|---|---|
message.created | 스트림 시작 (1회) |
message.delta | thinking/text 블록의 텍스트 조각 (여러 번). delta_index는 스트림 전체의 조각 순번 |
message.block_done | 블록 하나 완료 (블록마다 1회). tool_use 블록은 delta 없이 이 이벤트로만 오며 id, raw가 함께 옵니다 |
message.completed | 전체 완료 — 완성된 message 객체 포함 (1회) |
data: [DONE] | 스트림 종료 표시 (JSON 아님) |
event: message.block_done
data: {"type":"tool_use","id":"call_001","raw":"<모델이 출력한 tool call 원문>","token_count":12,"elapsed_ms":150}
message.completed 이벤트의 data: 한 줄에 완성된 message 객체(content 블록 전체 + usage)가 이미 다 들어있습니다 — 델타를 직접 누적하지 않고 이 마지막 이벤트만 파싱해도 됩니다.Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | messages/conversationId 누락, 생성 설정 값이 범위를 벗어남, image 블록 규칙 위반(이미지를 받지 않는 Cortex, PNG/JPEG 아님, 장수 초과, 컨텍스트 초과 등) |
| unsupported_cortex_type | 400 | LLM이 아닌 Cortex(이미지 생성·판정 전용)에 요청 |
| cortex_not_found | 404 | 없는 cortexId |
| file_not_found | 404 | image/document 블록이 가리키는 파일이 없음 |
| cortex_occupied | 409 | 다른 conversationId가 점유 중 (cortex_reset: false) |
| cortex_inferring | 409 | 이미 추론 중 |
| internal_error | 500 | 모델 로드 실패 등 서버 내부 오류 |
상태 보기
Cortex의 현재 점유 상태와 Context 토큰 사용량을 반환합니다. 추론 중에도 조회 가능합니다.
Response — 200 OK
{
"cortexId": "b47778cd-24d9-4912-830c-6745e1253cc5",
"status": "idle",
"conversationId": "conv_mtwfir2fyi0o",
"last_response_id": "msg-1789099310429",
"capabilities": { "api": "messages", "outputs": ["text"],
"inputs": [ { "type": "image", "max": 4, "mime": ["image/png", "image/jpeg"] } ] },
"sampling": { "temperature": 0.7, "top_p": 0.9, "top_k": 40, "min_p": 0.05, "seed": -1, "repeat_penalty": 1.0, "max_tokens": 2048 },
"context_size": 4096,
"context_used": 621,
"context_remain": 3475,
"context_used_pct": 15,
"kv_cache_bytes": 91578517,
"totalOutputTokens": 722,
"sessionOutputTokens": 722,
"currentOutputTokens": 722,
"lastOutputTokens": 722
}
| 필드 | 타입 | 설명 |
|---|---|---|
status | string | idle | busy(추론 진행/중단 처리 중) |
conversationId | string|null | 현재 점유 중인 conversationId. 점유자가 없으면 null — idle/busy 여부와 무관하게 유지됨(점유는 별도 상태) |
last_response_id | string|null | 가장 최근에 완료된 응답의 ID. 아직 없으면 null |
capabilities | object | 이 Cortex가 쓰는 API와 받을 수 있는 파일 — 아래 표 참고. 모델이 로드되지 않아도 정확한 값이 옵니다 |
sampling | object | (LLM, 모델이 로드된 경우) 현재 적용 중인 생성 설정. 대화 요청의 apply_sampling으로 바꾼 값 포함 |
context_size | int | 모델 최대 컨텍스트 토큰 수 (모델이 로드되지 않았으면 0) |
context_used | int | 현재 KV Cache에 사용된 토큰 수 |
context_remain | int | 남은 컨텍스트 토큰 수 |
context_used_pct | int | 컨텍스트 사용 비율(%) |
kv_cache_bytes | int | KV Cache가 차지하는 메모리 크기(byte) |
totalOutputTokens | int | 세션(모델 로드) 이후 누적 생성된 전체 출력 토큰 수 |
sessionOutputTokens | int | 마지막 /reset 이후 누적 생성된 출력 토큰 수 |
currentOutputTokens | int | 가장 최근 생성의 출력 토큰 수 — 진행 중이면 실시간으로 증가하고, 완료 후에는 다음 생성이 시작되기 전까지 그 값을 유지 |
lastOutputTokens | int | 가장 최근에 완료된 생성의 출력 토큰 수 |
capabilities
Cortex마다 어떤 API로 호출하는지, 어떤 파일을 첨부할 수 있는지 알려줍니다. 화면에서 첨부 버튼을 보여줄지 정할 때 이 값을 쓰면 됩니다.
| 필드 | 설명 |
|---|---|
api | 생성에 쓰는 API — messages(LLM) | choice(판정 전용 모델) | imageGenerate(이미지 생성) |
outputs | 결과 종류 — text | choice | image |
inputs | 텍스트 외에 첨부할 수 있는 파일 목록. 비어 있으면 파일 첨부 불가 |
inputs[].type | 파일 종류 — 현재 image |
inputs[].role | (이미지 생성만) reference = ref_images로 넣는 참조 이미지 |
inputs[].max | 요청 하나에 넣을 수 있는 최대 개수 |
inputs[].mime | 받는 파일 형식 (업로드 Content-Type과 같은 값) |
// LLM (비전 모델) — messages 에 이미지 첨부 가능 { "api": "messages", "outputs": ["text"], "inputs": [ { "type": "image", "max": 4, "mime": ["image/png", "image/jpeg"] } ] } // LLM (텍스트 전용) { "api": "messages", "outputs": ["text"], "inputs": [] } // 판정 전용 모델 { "api": "choice", "outputs": ["choice"], "inputs": [] } // 이미지 생성 (편집 가능) { "api": "imageGenerate", "outputs": ["image"], "inputs": [ { "type": "image", "role": "reference", "max": 4, "mime": ["image/png", "image/jpeg", "image/webp"] } ] }
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| cortex_not_found | 404 | 없는 cortexId |
추론 중지
진행 중인 추론(대화 생성, 이미지 생성)을 즉시 중단합니다. 추론 중이면 1초 이내에 중단되고 SSE Stream이 종료됩니다. 점유 중인 conversationId와 달라도 중단할 수 있습니다.
Request Body
{ "conversationId": "chat-550e8400" } // 생략 가능
Response — 200 OK
{
"ok": true,
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"message": "inference stopped"
}
"message": "already stopped"로 성공 응답합니다 — 여러 번 호출해도 안전합니다.Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| cortex_not_found | 404 | 없는 cortexId |
모델 언로드
로드된 모델을 메모리에서 내려 GPU/메모리를 비웁니다. Cortex 자체는 남아 있으며, 다음 messages/choice/imageGenerate 요청 때 자동으로 다시 로드됩니다. Body는 필요하지 않습니다.
Response — 200 OK
{
"ok": true,
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"message": "unloaded"
}
"message": "already unloaded"로 성공 처리됩니다(idempotent). 추론 중이었다면 먼저 중단시키고, 추론이 실제로 끝날 때까지 최대 5초 기다린 뒤 언로드합니다.Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| cortex_not_found | 404 | 없는 cortexId |
| cortex_inferring | 409 | 중단을 요청했지만 5초 안에 추론이 끝나지 않음 — 언로드하지 않았으니 잠시 후 다시 시도 |
컨텍스트 초기화
Cortex의 KV Cache(대화 컨텍스트)를 초기화합니다. 이후 요청 시 대화 히스토리 전체를 다시 전송해야 합니다. Body는 필요하지 않습니다.
Response — 200 OK
{
"ok": true,
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"message": "context reset"
}
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| cortex_not_found | 404 | 없는 cortexId |
| unsupported_cortex_type | 400 | LLM이 아닌 Cortex(이미지 생성·판정 전용)에 요청 |
| cortex_not_running | 409 | 모델이 로드되지 않음 |
| cortex_inferring | 409 | 추론 중 |
대화 세션 전환
대화 세션(conversationId)으로 Cortex를 선점합니다. 이미 다른 클라이언트가 점유 중인 Cortex를 강제로 빼앗거나, 점유를 해제하는 데도 사용합니다.
/switch-conversation는 점유 전환을 허용합니다. 점유 중 다른 클라이언트의 탈취를 방지하려면 상위 레이어(API 프록시 등)에서 접근 제어를 수행해야 합니다.동작 규칙
| 상황 | 동작 |
|---|---|
| Cortex가 idle 상태 | conversationId를 등록하고 즉시 점유 성공 |
| 동일한 conversationId로 재요청 | 점유 유지 (no-op) |
| 다른 conversationId로 요청 | 기존 점유를 해제하고 새 conversationId로 전환 (강제 탈취) |
conversationId를 ""로 요청 | 점유 해제 (idle 상태로 전환) |
Request Body
{
"conversationId": "chat-550e8400" // 빈 문자열 ""이면 점유 해제
}
Response — 200 OK
{
"ok": true,
"message": "conversationId changed to chat-550e8400"
}
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | JSON 파싱 실패 |
| unsupported_cortex_type | 400 | LLM이 아닌 Cortex(이미지 생성·판정 전용)에 요청 |
| cortex_not_found | 404 | 없는 cortexId |
선택지 판정
주어진 선택지(choices) 중 query에 가장 맞는 것을 판정합니다. 텍스트를 생성하지 않고 한 번의 계산으로 끝나서 빠르며, 결과를 선택지별 확률로 돌려줍니다. 문의 분류, 의도 파악, 정책 위반 판정처럼 "정해진 보기 중 하나를 고르는" 작업에 씁니다.
- 일반 LLM Cortex와 판정 전용 모델(예: Laya) Cortex 모두 같은 요청 형식을 씁니다.
cortexId만 바꾸면 두 방식을 비교할 수 있습니다 — 응답의method가llm_label(LLM) 또는laya(판정 전용 모델)로 옵니다. - conversationId(점유)를 확인하지도 바꾸지도 않으며, LLM Cortex에서 진행 중인 대화 컨텍스트에도 영향을 주지 않습니다. 언로드된 Cortex는 자동으로 로드됩니다.
Request Body
{
"instruction": "다음 고객 문의의 유형을 고르세요.",
"query": "어제 주문한 상품을 취소하고 돈을 돌려받고 싶습니다.",
"choices": ["환불", "배송조회", "단순문의", "스팸"],
"temperature": 1.0,
"debias": false
}
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
instruction | string | 아니오 | 판정 질문. 생략하거나 빈 문자열이면 "Choose the option that best fits the query." |
query | string | object | array | 예 | 판단 대상. 문자열이 아니면 JSON 텍스트로 넣습니다. 업로드한 텍스트 파일을 document 블록(또는 text/document 블록 배열)으로 줄 수도 있습니다 — image 블록은 지원하지 않음 |
choices | string[] | 예 | 선택지. LLM Cortex는 2 ~ 26개, 판정 전용 모델은 2 ~ 255개. 빈 문자열/중복 불가 |
temperature | number | 아니오 | 확률 분포 온도, 0보다 커야 함. LLM Cortex 기본값 1.0, 판정 전용 모델은 생략 시 모델에 내장된 보정 온도 사용(생략 권장) |
debias | bool | 아니오 | LLM Cortex 전용 — 선택지 순서를 뒤집어 한 번 더 계산해 평균(위치 편향 보정, 비용 2배). 기본 false. 판정 전용 모델은 무시 |
Response — 200 OK
{
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"method": "llm_label",
"best_choice": "환불",
"confidence": 0.9845,
"probabilities": { "환불": 0.9845, "배송조회": 0.0112, "단순문의": 0.0041, "스팸": 0.0002 },
"usage": { "input_tokens": 98, "elapsed_ms": 41, "passes": 1 }
}
| 필드 | 설명 |
|---|---|
method | 계산 방식 — llm_label(LLM Cortex) 또는 laya(판정 전용 모델) |
best_choice | 확률이 가장 높은 선택지 (동률이면 앞의 것) |
confidence | best_choice의 확률 (0 ~ 1) |
probabilities | 선택지 → 확률 (요청 choices 순서 유지, 합계 1) |
truncated | 판정 전용 모델만 — 질문/선택지가 길어 모델 입력 한도에 맞춰 잘렸으면 true |
usage.input_tokens | 평가한 입력 토큰 수 (debias면 두 번의 합) |
usage.elapsed_ms | 판정 소요 시간(ms) |
usage.passes | 계산 횟수 (1, debias면 2) |
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | JSON 오류, query/choices 누락, 선택지 개수 위반, 빈/중복 선택지, instruction이 문자열이 아님, temperature <= 0, debias가 bool이 아님 |
| unsupported_cortex_type | 400 | 이미지 생성 Cortex에 요청 |
| cortex_not_found | 404 | 없는 cortexId |
| cortex_inferring | 409 | 이미 추론/판정 중 |
| internal_error | 500 | 모델 로드 실패, 입력이 모델 한도 초과 등 |
/choice만 처리합니다 — messages, switch-conversation, reset은 unsupported_cortex_type(400)으로 거절됩니다.이미지 생성
이미지 생성 모델(예: Qwen Image, FLUX) Cortex로 이미지를 만들거나 편집합니다. 생성된 이미지는 그 Cortex의 파일 저장소에 저장되고, 응답의 files에 files/gen-….png 형태로 옵니다. 이 값을 /{my_base_path}/cortex/{cortexId}/ 뒤에 붙이면 다운로드 주소가 됩니다(아래 "Cortex 파일" 참고).
Request Body
{
"prompt": "a lovely cat holding a sign says 'flamebox'",
"negative_prompt": "blurry",
"width": 1024, "height": 1024,
"steps": 20, "cfg_scale": 6.0, "seed": -1,
"sampler": "euler", "count": 1, "stream": false
}
| 파라미터 | 필수 | 설명 |
|---|---|---|
prompt | 예 | 그릴 내용 |
negative_prompt | 아니오 | 피하고 싶은 내용 |
width, height | 아니오 | 이미지 크기 — 모델이 정한 배수(Qwen Image 2.1은 32의 배수). 생략 시 모델/Cortex 기본값 |
steps, cfg_scale, sampler, scheduler, count | 아니오 | 생략 시 기본값. 최댓값은 Cortex 설정(limits)을 넘을 수 없음 |
seed | 아니오 | -1이면 무작위 (응답에 실제 사용한 seed가 옴 — 같은 결과를 다시 얻을 때 사용) |
ref_images | 아니오 | 편집용 참조 이미지 배열 — "files/<이름>" 문자열 또는 image 블록. 먼저 "Cortex 파일" API로 업로드합니다. 아래 "이미지 편집" 참고 |
stream | 아니오 | true면 SSE로 진행률을 받음. 기본 false |
모르는 파라미터를 보내면 bad_request(400)입니다.
Response — stream: false (생성이 끝나면 응답)
{
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"files": ["files/gen-20261006-195252-3294.png"],
"seed": 7, "width": 1024, "height": 1024, "steps": 20,
"elapsed_ms": 78000, "method": "sd.cpp"
}
생성 중에 /stop으로 중지되면 { "cortexId": "…", "status": "cancelled" }가 옵니다.
Response — stream: true (SSE, 마지막 이벤트가 result / error / cancelled)
event: generation.queued data: {"cortexId": "..."} (다른 생성이 진행 중일 때만)
event: generation.progress data: {"cortexId": "...", "step": 3, "steps": 20, "elapsed_ms": 4100}
event: generation.result data: {"cortexId": "...", "files": ["files/gen-….png"], "seed": 12345, ...}
stream: true를 권장합니다. 한 PC에서 이미지 생성은 한 번에 하나씩 처리되며, 대기 중인 요청은 generation.queued를 먼저 받습니다.이미지 편집 — 참조 이미지(ref_images)
업로드한 사진이나 앞 생성 결과를 ref_images로 주고, prompt에 바꿀 내용을 적으면 그 이미지를 고친 결과를 만듭니다.
{
"prompt": "Change only the background to a snowy mountain. Keep the same man, face, clothes and pose.",
"ref_images": ["files/upload-20261016-101500-a1b2.jpg"],
"width": 832, "height": 1248, "seed": 42
}
| 항목 | 규칙 |
|---|---|
| 사용 가능한 Cortex | 상태 보기의 capabilities.inputs에 { "type": "image", "role": "reference" }가 있는 Cortex만. 없으면 bad_request(400) |
| 형식 | PNG, JPEG, webp |
| 여러 장 | 배열 순서대로 모델에 들어갑니다(최대 4장). 프롬프트에서 역할을 지정하세요 — 예: "Use the face of the man in the first image and put him into the scene of the second image" |
| 연속 편집 | 응답의 files/gen-….png를 다음 요청의 ref_images로 넣습니다. 이미지 모델은 이전 요청을 기억하지 않으므로 매번 참조 이미지와 바꿀 내용을 함께 보냅니다. 편집을 거듭할수록 화질이 조금씩 흐려지므로 원본 사진을 함께 넣으면(2장) 인물 유지에 도움이 됩니다 |
| 출력 크기 | width/height를 생략하면 Cortex 기본 크기로 나와 원본과 비율이 달라질 수 있습니다 — 참조 이미지 비율에 맞춘 크기(모델 배수)를 주는 것을 권장합니다(예: 540×810 → 832×1248) |
| 프롬프트 | 바꿀 것은 Change only …, 유지할 것은 Keep the same …으로 함께 적으면 바뀌는 범위가 좁아집니다 |
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | 입력 오류(필수값 누락, 크기 배수 위반, 상한 초과, 모르는 파라미터, 참조 이미지를 받지 않는 Cortex, 장수 초과, 읽을 수 없는 이미지 등) |
| unsupported_cortex_type | 400 | 이미지 생성 Cortex가 아님 |
| file_not_found | 404 | ref_images에 없는 파일 이름 |
| cortex_inferring | 409 | 이미 생성 중 |
| internal_error | 500 | 모델 로드 실패 등 |
Cortex 파일
Cortex마다 파일 저장소가 있습니다. 생성 결과(gen-…)를 내려받거나, 생성에 쓸 입력 파일(예: 편집용 참조 이미지)을 올립니다. 모델 종류나 로드 여부와 상관없이 모든 Cortex에서 동작합니다.
| 메서드 | 경로 | 설명 |
|---|---|---|
| POST | /{my_base_path}/cortex/{cortexId}/files | 업로드 — Body는 파일 바이트 그대로, Content-Type으로 형식 지정(최대 50MB). 응답 { "cortexId", "file": "files/upload-….png", "size", "mime" } |
| GET | /{my_base_path}/cortex/{cortexId}/files | 목록 — { "cortexId", "files": [ { "name", "size", "mime", "createdAt" } ] } (이름순) |
| GET | /{my_base_path}/cortex/{cortexId}/files/{name} | 다운로드 — 파일 바이트 그대로(Content-Type = 파일 형식) |
| POST | /{my_base_path}/cortex/{cortexId}/files/{name} | 다운로드 — GET과 같음 |
| DELETE | /{my_base_path}/cortex/{cortexId}/files/{name} | 삭제 — { "ok": true, "cortexId", "file" } |
- 업로드 파일 이름은 서버가 정합니다:
upload-<yyyyMMdd-HHmmss>-<hex>.<ext>. 생성 결과는gen-…입니다. - API가 주고받는 파일은
files/<이름>형식입니다. 이 값을 그대로 대화 요청의image/document블록, 이미지 생성의ref_images에 넣습니다(<이름>만 써도 됩니다). - 허용 형식(
Content-Type):image/png,image/jpeg,image/webp,audio/wav,video/webm,video/mp4,text/plain,application/json— 그 외는bad_request(400). 단, 대화 요청의image블록은 PNG/JPEG만 받습니다. - 파일 이름 규칙: 영문·숫자·
.·_·-만, 128자 이하,.으로 시작하거나..포함 불가. - 다운로드는
Authorization헤더가 필요하므로, 브라우저<img src>에 주소를 바로 넣을 수는 없습니다 — 서버에서 받아 전달하거나 Blob으로 받아서 표시하세요.
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | 허용되지 않는 형식, 파일 이름 규칙 위반, 50MB 초과 |
| file_not_found | 404 | 없는 파일 |
| cortex_not_found | 404 | 없는 cortexId |
# 이미지 생성 → 결과 다운로드 → 삭제 curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/{cortexId}/imageGenerate \ -H "Authorization: Bearer YOUR_SECRET_KEY" -H "Content-Type: application/json" \ -d '{ "prompt": "a lovely cat holding a sign says flamebox", "width": 1024, "height": 1024 }' curl -s https://api-3.flameai.im/Nx7bQ2mZ/cortex/{cortexId}/files/gen-20261006-195252-3294.png \ -H "Authorization: Bearer YOUR_SECRET_KEY" -o result.png curl -s -X DELETE https://api-3.flameai.im/Nx7bQ2mZ/cortex/{cortexId}/files/gen-20261006-195252-3294.png \ -H "Authorization: Bearer YOUR_SECRET_KEY" # 편집용 참조 이미지 업로드 curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/{cortexId}/files \ -H "Authorization: Bearer YOUR_SECRET_KEY" -H "Content-Type: image/png" --data-binary @input.png
토큰 세기
문자열을 이 Cortex 모델의 토크나이저로 나눠 토큰 id 배열과 토큰 수를 돌려줍니다. 토큰 수는 모델마다 다르므로, 보낼 프롬프트가 컨텍스트에 들어가는지 미리 확인할 때 씁니다. LLM과 판정 전용 모델 Cortex에서 쓸 수 있습니다.
Request Body
{
"text": "안녕하세요. 오늘 날씨가 좋네요.",
"options": { "autoLoad": false }
}
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
text | string | 예 | 토큰화할 문자열 |
options.autoLoad | boolean | 아니오 | true면 모델이 로드되지 않은 경우 먼저 로드한 뒤 토큰화합니다. 기본값 false |
Response — 200 OK
{
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"tokens": [148924, 154982, 88005, 13],
"count": 4
}
Errors
| 코드 | HTTP | 상황 |
|---|---|---|
| bad_request | 400 | text 누락 또는 JSON 파싱 실패 |
| unsupported_cortex_type | 400 | 이미지 생성 Cortex에 요청 |
| cortex_not_found | 404 | 없는 cortexId |
| cortex_not_running | 409 | 모델이 로드되지 않았고 options.autoLoad가 false |
| internal_error | 500 | 모델 로드 실패 등 |
curl 테스트 예시
아래 예시의 Nx7bQ2mZ(my_base_path)는 My AI Console(/mypage/settings)에서 확인한 실제 값으로, 7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a은 실제 등록된 cortexId로 교체하세요.
Cortex 선점
curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/switch-conversation \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversationId": "chat-test-001" }' | python3 -m json.tool
대화 요청 (SSE 스트리밍)
curl -s -N -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/messages \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversationId": "chat-test-001", "options": { "stream": true, "think": 1 }, "messages": [ { "role": "user", "content": "안녕하세요. 간단히 자기소개 해줘." } ] }'
이미지 질문 (비전 모델 Cortex)
# 1) 이미지 업로드 → 응답의 "file" 값을 확인 curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/files \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: image/jpeg" --data-binary @photo.jpg # 2) 그 파일을 image 블록으로 넣어 질문 curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/messages \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversationId": "chat-img-001", "options": { "stream": false, "think": 0 }, "messages": [ { "role": "user", "content": [ { "type": "image", "source": { "type": "file", "file": "files/upload-20261016-101500-a1b2.jpg" } }, { "type": "text", "text": "이 사진에 무엇이 있는지 설명해줘" } ] } ] }' | python3 -m json.tool
컨텍스트 재구성 (cortex_reset)
curl -s -N -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/messages \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversationId": "chat-test-001", "options": { "stream": true, "cortex_reset": true }, "messages": [ { "role": "user", "content": "파이썬이란 무엇인가?" }, { "role": "assistant", "content": "파이썬은 범용 프로그래밍 언어입니다." }, { "role": "user", "content": "그렇다면 파이썬의 장점은?" } ] }'
상태 조회
curl -s https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/status \
-H "Authorization: Bearer YOUR_SECRET_KEY" | python3 -m json.tool
추론 중단
curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/stop \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversationId": "chat-test-001" }' | python3 -m json.tool
점유 해제
curl -s -X POST https://api-3.flameai.im/Nx7bQ2mZ/cortex/7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a/switch-conversation \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversationId": "" }' | python3 -m json.tool
다른 API와의 차이
Claude(Anthropic) API나 OpenAI API를 써 본 개발자가 헷갈리기 쉬운 차이점입니다.
| 항목 | FlameAI | Claude API | OpenAI API |
|---|---|---|---|
| 대화 상태 | Stateful — Cortex가 대화를 기억, conversationId로 점유 | Stateless — 매번 전체 대화 전송 | Stateless — 매번 전체 대화 전송 |
| 스트리밍 지정 | options.stream | 최상위 stream | 최상위 stream |
| 응답 구조 | 단일 message 객체 (usage는 그 안에) | 단일 message | choices[0].message, 최상위 usage |
| SSE 이벤트 | message.created / delta / block_done / completed | content_block_start / content_block_delta 등 | choices[0].delta.content |
| 종료 이유 | usage.stop_reason (eot, n_predict 등) | stop_reason (end_turn 등) | finish_reason |
| 도구 호출 | tool_use 블록, 호출 내용은 원문 그대로 raw (클라이언트가 파싱) | tool_use 블록, 파싱된 input | tool_calls 배열 |
| 도구 결과 | user 메시지의 tool_result 블록 (role: "tool" + 문자열도 허용) | user 메시지의 tool_result 블록 | role: "tool" + tool_call_id |
| thinking 서명 | signature는 항상 빈 문자열 | 서명 값을 다시 보내야 함 | - |
| 모델명 | 응답에 없음 (Cortex가 모델을 정함) | model 필드 | model 필드 |
| 처리 시간 | elapsed_ms, prefill_ms 제공 | 없음 | 없음 |
WORKSPACE
WORKSPACE는 사용자에게 제공되는 공간으로, FlameAI 가입 시 자동으로 생성됩니다. 각 WORKSPACE에는 연결되는 가상의 my_base_path(API 경로)가 주어지며, 이 경로를 통해 사용자가 관리하는 Cortex 등을 API로 핸들링할 수 있습니다.
내 Cortex 목록
이 계정이 가진 Cortex 전체 목록을 조회합니다. FlameBox 자신의 /v1/cortexes(FlameBox 1대 단위)와 달리, 이 엔드포인트는 API Gateway 자신이 응답을 만듭니다 — 한 계정이 여러 FlameBox에 걸쳐 있을 수 있어서, FlameBox 하나가 답할 수 있는 질문이 아니기 때문입니다.
Response — 200 OK
{
"cortexes": [
{
"cortexId": "7f3c9a12-4e6b-4d8f-9a21-6b5e8c1f2d3a",
"name": "코딩 어시스턴트",
"status": "ONLINE",
"flameboxId": "fb-abc123",
"flameboxName": "내 데스크탑"
}
]
}
| 필드 | 타입 | 설명 |
|---|---|---|
cortexId | string | Cortex 식별자 |
name | string | Cortex 이름(비어있으면 cortexId로 대체) |
status | string | ONLINE | OFFLINE — 이 Cortex가 속한 FlameBox의 온라인 여부(Cortex 자체의 idle/busy 여부가 아님) |
flameboxId | string | 이 Cortex가 속한 FlameBox 식별자 |
flameboxName | string | 그 FlameBox의 이름 |
curl 테스트 예시
아래 예시의 Nx7bQ2mZ(my_base_path)는 My AI Console(/mypage/settings)에서 확인한 실제 값으로 교체하세요.
내 Cortex 목록 조회
curl -s https://api-3.flameai.im/Nx7bQ2mZ/cortexes \
-H "Authorization: Bearer YOUR_SECRET_KEY" | python3 -m json.tool