補全
OpenAI 兼容的 Chat Completions
OpenAI Chat Completions API 的即插即用替代方案。將 OpenAI SDK 指向 Theo,無需改動現有代碼即可繼續使用。
POST
/
api
/
v1
/
chat
/
completions
OpenAI 兼容的 Chat Completions
curl --request POST \
--url https://api.example.com/api/v1/chat/completions \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"messages": [
{}
],
"stream": true,
"temperature": 123,
"conversation_id": "<string>",
"skills": [
"<string>"
],
"metadata": {}
}
'import requests
url = "https://api.example.com/api/v1/chat/completions"
payload = {
"model": "<string>",
"messages": [{}],
"stream": True,
"temperature": 123,
"conversation_id": "<string>",
"skills": ["<string>"],
"metadata": {}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
messages: [{}],
stream: true,
temperature: 123,
conversation_id: '<string>',
skills: ['<string>'],
metadata: {}
})
};
fetch('https://api.example.com/api/v1/chat/completions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/chat/completions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'messages' => [
[
]
],
'stream' => true,
'temperature' => 123,
'conversation_id' => '<string>',
'skills' => [
'<string>'
],
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/chat/completions"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"stream\": true,\n \"temperature\": 123,\n \"conversation_id\": \"<string>\",\n \"skills\": [\n \"<string>\"\n ],\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/chat/completions")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"stream\": true,\n \"temperature\": 123,\n \"conversation_id\": \"<string>\",\n \"skills\": [\n \"<string>\"\n ],\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/chat/completions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"stream\": true,\n \"temperature\": 123,\n \"conversation_id\": \"<string>\",\n \"skills\": [\n \"<string>\"\n ],\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_bodyTheo 在
支持的
傳入任意 Theo 品牌模型 ID。推薦使用
未知的模型字符串會回退到
何時改用
POST /api/v1/chat/completions 上實現了 OpenAI Chat Completions 通信協議。任何使用 OpenAI SDK 的應用都可以將 baseURL 指向 https://www.hitheo.ai/api/v1,換上 Theo API 密鑰即可正常運行——該端點接受相同的 { model, messages, stream, temperature, ... } 結構,並返回相同的 chat.completion / chat.completion.chunk 對象。
響應結構與 OpenAI 完全一致。底層的路由則由 Theo 負責——意圖分類、模型選擇與自動故障轉移。傳入
model: "theo-1-auto" 可讓 Theo 為每個請求選擇最合適的引擎。基礎 URL
請使用規範的www 主機名。OpenAI SDK 會在其後追加 /chat/completions,因此該基礎 URL 最終會解析到真實的 POST /api/v1/chat/completions 路由:
https://www.hitheo.ai/api/v1
務必使用
www 主機名。裸域名 https://hitheo.ai 會以 307 重定向到 www,而大多數 HTTP 客戶端在跨重定向時會剝離 Authorization 頭——請求會以未認證狀態到達,並返回 401。身份驗證
使用標準的 Bearer 令牌請求頭。你的 Theo API 密鑰將替代原來的 OpenAI 密鑰。Authorization: Bearer theo_sk_...
即插即用示例(OpenAI SDK)
import OpenAI from "openai";
const theo = new OpenAI({
apiKey: process.env.THEO_API_KEY,
baseURL: "https://www.hitheo.ai/api/v1",
});
const res = await theo.chat.completions.create({
model: "theo-1-auto",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Write me a haiku about Miami." },
],
});
console.log(res.choices[0].message.content);
from openai import OpenAI
theo = OpenAI(
api_key=os.environ["THEO_API_KEY"],
base_url="https://www.hitheo.ai/api/v1",
)
res = theo.chat.completions.create(
model="theo-1-auto",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Write me a haiku about Miami."},
],
)
print(res.choices[0].message.content)
curl -X POST https://www.hitheo.ai/api/v1/chat/completions \
-H "Authorization: Bearer $THEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "theo-1-auto",
"messages": [
{ "role": "user", "content": "Write me a haiku about Miami." }
]
}'
流式響應
將stream 設為 true,即可接收以 data: [DONE] 結尾的 chat.completion.chunk 對象 SSE 流,行為與 OpenAI 完全一致。
const stream = await theo.chat.completions.create({
model: "theo-1-auto",
messages: [{ role: "user", content: "Stream me a short poem." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
支持的 model 取值
傳入任意 Theo 品牌模型 ID。推薦使用 theo-1-auto,讓 Theo 的意圖分類器為每個請求挑選最合適的引擎;如果你想固定路由,也可以傳入具體的引擎。
| 模型 ID | Theo 模式 | 最適用場景 |
|---|---|---|
theo-1-auto | auto | 讓 Theo 為每條提示選擇合適的引擎 |
theo-1-flash | fast | 快速響應、簡短對話、分類任務 |
theo-1-reason | think | 深度推理、分析、規劃 |
theo-1-code | code | 代碼生成與審查 |
theo-1-create | image | 圖像生成 |
theo-1-motion | video | 視頻生成 |
theo-1-research | research | 帶引用的多步網絡研究 |
theo-1-roast | roast | 不加過濾的幽默與犀利吐槽 |
theo-1-genui | genui | 生成式 UI 組件 |
theo-1-analyze | domain_analysis | 面向業務運營、財務與合規的領域分析 |
theo-1-extract | data_extraction | OCR 與結構化數據提取 |
theo-1-vision | vision | 多模態圖像分析 |
auto,Theo 會像處理其他任何提示一樣為該請求路由。
請求體
請求體沿用標準的 OpenAI Chat Completion 結構。下方未列出的字段仍會被接受,但會被忽略(例如top_p、n、max_tokens、user)。
string
預設值:"theo-1-auto"
一個 Theo 模型 ID。有效取值參見上方表格。
object[]
必填
到目前為止的對話內容。每條消息包含
{ role, content }。支持的角色有:system、user、assistant。tool 消息會被接受但忽略(工具調用狀態由 Theo 內部管理)。最後一條 user 消息會被視為提示。所有 system 消息會被合併為單一的系統提示,覆蓋 Theo 的默認角色設定。此前的 user/assistant 輪次會作為對話上下文注入。boolean
預設值:"false"
當設為
true 時,返回以 data: [DONE] 結尾的 chat.completion.chunk 對象 SSE 流。number
採樣温度(0–2)。
string
Theo 專屬參數。 將此次補全關聯到一個已有的 Theo 對話,使其記憶能夠跨渠道持續保留。省略此參數則發送無狀態請求。
string[]
Theo 專屬參數。 按 slug 為本次請求激活技能。會與用戶已安裝的技能合併。
object
Theo 專屬參數。 附加到審計日誌中的任意鍵值數據。
響應
標準的 OpenAIchat.completion(流式時為 chat.completion.chunk)。Theo 專屬的元數據會以 theo_metadata 擴展字段返回,以避免與現有 OpenAI 客戶端的預期結構衝突。
{
"id": "chatcmpl_...",
"object": "chat.completion",
"created": 1715872800,
"model": "theo-1-flash",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Neon waves on sand..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 38,
"total_tokens": 62
},
"theo_metadata": {
"mode": "auto",
"resolved_mode": "fast",
"tools_used": [],
"artifacts": [],
"engine": "theo-core"
}
}
何時改用 /v1/completions
- 你需要的是單輪提示字符串,而不是消息數組。
- 你想要更豐富的原生 Theo 響應(後續追問、產物、工具調用軌跡),而不是 OpenAI 的結構。
- 你想在每次請求中單獨控制
persona或response_style。
同樣適用按密鑰編排
該端點運行的是與原生端點完全相同的按密鑰編排:無論你為該 API 密鑰配置了什麼——編排器圖譜、模型鎖定、網關護欄、路由工作室偏好設置、模型允許列表,以及上下文窗口保護——都會同樣作用於此處的請求。因此,無論你是通過 OpenAI SDK 還是原生 API 調用,一個你在控制台或通過 MCP 工具配置好的密鑰都會表現一致。護欄可以拒絕請求(422),超出該密鑰允許列表的模型會被拒絕(403),超出體積的請求會返回 400 context_length_exceeded。沒有此類配置的密鑰不受影響——它們仍會按 Theo 的默認設置路由,與以往一致。
錯誤
返回與其他所有 v1 端點相同的錯誤信封:{
"error": {
"message": "Validation failed: messages must contain at least one message.",
"type": "invalid_request_error",
"code": "validation_error"
}
}
| 狀態碼 | 錯誤碼 | 描述 |
|---|---|---|
| 400 | validation_error | messages 缺失、為空或格式錯誤 |
| 400 | empty_prompt | messages 中只包含 system/tool 消息 |
| 400 | context_length_exceeded | 請求體量超出該密鑰所有模型能容納的上限——請在編排器中添加上下文更大的模型,或縮短請求內容 |
| 401 | invalid_api_key | Authorization: Bearer theo_sk_... 缺失或無效 |
| 402 | insufficient_credits | 賬戶餘額不足以完成預扣(pre-flight reservation) |
| 403 | model_not_allowed | 請求解析到的模型不在該密鑰的模型允許列表中 |
| 422 | guardrail_violation | 該密鑰上的網關護欄策略拒絕了此請求 |
| 422 | orchestrator_no_path | 該密鑰的編排器圖譜未能為此請求解析出有效路徑 |
| 404 | not_found | 未找到 conversation_id |
| 429 | rate_limit_exceeded | 請查看 Retry-After |
| 500 | server_error | 內部錯誤 |
這個頁面有幫助嗎?
OpenAI 兼容的 Chat Completions
curl --request POST \
--url https://api.example.com/api/v1/chat/completions \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"messages": [
{}
],
"stream": true,
"temperature": 123,
"conversation_id": "<string>",
"skills": [
"<string>"
],
"metadata": {}
}
'import requests
url = "https://api.example.com/api/v1/chat/completions"
payload = {
"model": "<string>",
"messages": [{}],
"stream": True,
"temperature": 123,
"conversation_id": "<string>",
"skills": ["<string>"],
"metadata": {}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
messages: [{}],
stream: true,
temperature: 123,
conversation_id: '<string>',
skills: ['<string>'],
metadata: {}
})
};
fetch('https://api.example.com/api/v1/chat/completions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/chat/completions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'messages' => [
[
]
],
'stream' => true,
'temperature' => 123,
'conversation_id' => '<string>',
'skills' => [
'<string>'
],
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/chat/completions"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"stream\": true,\n \"temperature\": 123,\n \"conversation_id\": \"<string>\",\n \"skills\": [\n \"<string>\"\n ],\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/chat/completions")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"stream\": true,\n \"temperature\": 123,\n \"conversation_id\": \"<string>\",\n \"skills\": [\n \"<string>\"\n ],\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/chat/completions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"stream\": true,\n \"temperature\": 123,\n \"conversation_id\": \"<string>\",\n \"skills\": [\n \"<string>\"\n ],\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body