外观
Chat Completions
创建对话补全,是壹通最核心的 OpenAI 兼容接口。支持流式(SSE)、非流式、多模态内容、函数调用与工具调用。
- 方法:
POST /v1/chat/completions - 鉴权:必须使用 API Key(
agent = "api",即sk-开头的 Key)
请求体
对应结构体 RelayForm(manager/types.go):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | ✅ | 模型标识,如 gpt-3.5-turbo |
messages | Message[] | ✅ | 对话消息数组 |
stream | bool | ❌ | 是否流式返回,默认 false |
max_tokens | int | ❌ | 最大生成 token 数 |
temperature | float32 | ❌ | 采样温度 |
top_p | float32 | ❌ | 核采样 |
top_k | int | ❌ | Top-K 采样 |
presence_penalty | float32 | ❌ | 存在惩罚 |
frequency_penalty | float32 | ❌ | 频率惩罚 |
repetition_penalty | float32 | ❌ | 重复惩罚 |
tools | FunctionTools | ❌ | 工具定义(见 公共类型) |
tool_choice | any | ❌ | 工具选择策略 |
official | bool | ❌ | 是否为官方计费(内部使用,见下方说明) |
消息结构(Message)
| 字段 | 类型 | 说明 |
|---|---|---|
role | string | system / user / assistant / tool / function |
content | string | MessageContent[] | 文本内容,或多模态内容数组 |
name | string | 可选,消息来源名称 |
function_call | FunctionCall | 仅 function 角色 |
tool_call_id | string | 仅 tool 角色 |
tool_calls | ToolCalls | 仅 assistant 角色 |
多模态内容(MessageContent)
当 content 为数组时,每项结构如下:
json
{
"type": "text",
"text": "这是什么?",
"image_url": null
}| 字段 | 类型 | 说明 |
|---|---|---|
type | string | 内容类型,如 text / image_url |
text | string | 文本(type = "text" 时) |
image_url | object | 图片(type = "image_url" 时),含 url 与可选 detail |
模型特殊后缀
| 写法 | 效果 |
|---|---|
web- 前缀(如 web-gpt-3.5-turbo) | 开启联网搜索,前缀会被剥离后路由 |
-official 后缀(如 gpt-4o-official) | 官方计费模式,响应中返回 quota 字段,不扣用户额度 |
非流式响应
响应示例
json
{
"id": "chatcmpl-9a1b2c3d",
"object": "chat.completion",
"created": 1700000000,
"model": "gpt-3.5-turbo",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你好!我是壹通提供的 AI 助手。",
"tool_calls": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 18,
"total_tokens": 30
},
"quota": 0.00012
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 本次补全 ID,前缀 chatcmpl- |
object | string | 固定为 "chat.completion" |
created | int64 | 时间戳 |
model | string | 实际使用的模型 |
choices | Choice[] | 候选结果 |
choices[].index | int | 序号 |
choices[].message | globals.Message | 助手消息 |
choices[].finish_reason | string | "stop" 或 "tool_calls" |
usage | Usage | token 用量 |
quota | float32 | 本次消耗额度(仅 -official 模式返回) |
非流式请求示例
bash
curl https://app.1in2.top/api/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-your-api-key-here" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{ "role": "system", "content": "你是一个乐于助人的助手。" },
{ "role": "user", "content": "用一句话介绍你自己" }
],
"temperature": 0.7,
"max_tokens": 200
}'python
from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key-here",
base_url="https://app.1in2.top/api/v1",
)
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "你是一个乐于助人的助手。"},
{"role": "user", "content": "用一句话介绍你自己"},
],
)
print(completion.choices[0].message.content)流式响应(SSE)
设置 stream: true 后,服务端以 text/event-stream 返回,每个事件为一行 data: <json>,结束标记为 data: [DONE]。
data: {"id":"chatcmpl-9a1b2c3d","object":"chat.completion.chunk",...}
data: {"id":"chatcmpl-9a1b2c3d","object":"chat.completion.chunk",...}
data: [DONE]流式块结构(RelayStreamResponse)
json
{
"id": "chatcmpl-9a1b2c3d",
"object": "chat.completion.chunk",
"created": 1700000000,
"model": "gpt-3.5-turbo",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"content": "你好",
"tool_calls": null
},
"finish_reason": null
}
],
"usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 },
"quota": null,
"error": null
}关键字段:
object:流式时固定为"chat.completion.chunk";choices[].delta:增量内容,content为本次新增文本;choices[].finish_reason:传输过程中为null,最后一个块为"stop"(或"tool_calls");error:发生错误时非空,见 错误处理。
流式请求示例
bash
curl -N https://app.1in2.top/api/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-your-api-key-here" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [ { "role": "user", "content": "讲一个笑话" } ],
"stream": true
}'python
from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key-here",
base_url="https://app.1in2.top/api/v1",
)
stream = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "讲一个笑话"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)函数调用与工具调用
壹通支持 OpenAI 风格的 function calling。使用 tools 声明工具,模型返回的 assistant 消息会携带 tool_calls。
请求示例(工具调用)
bash
curl https://app.1in2.top/api/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-your-api-key-here" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{ "role": "user", "content": "北京今天天气怎么样?" }
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名" }
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto"
}'响应(工具调用被触发)
此时 finish_reason 为 "tool_calls",message.tool_calls 包含调用信息:
json
{
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"index": 0,
"type": "function",
"id": "call_abc123",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"北京\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
}将工具执行结果以 role = "tool" 回传,携带对应的 tool_call_id,即可继续多轮对话:
json
{
"model": "gpt-3.5-turbo",
"messages": [
{ "role": "user", "content": "北京今天天气怎么样?" },
{
"role": "assistant",
"content": "",
"tool_calls": [
{
"index": 0,
"type": "function",
"id": "call_abc123",
"function": { "name": "get_weather", "arguments": "{\"city\":\"北京\"}" }
}
]
},
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": "{\"temperature\": \"18°C\", \"condition\": \"晴\"}"
}
]
}多模态请求示例(图片输入)
json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "这张图片里有什么?" },
{
"type": "image_url",
"image_url": { "url": "https://example.com/cat.png", "detail": "auto" }
}
]
}
]
}常见错误
| 错误类型 | 触发场景 |
|---|---|
access_denied_error | 中继被关闭(CloseRelay) |
authentication_error | 未携带 Key 或非 api 身份 |
invalid_request_error | 请求体非法或缺少 model / messages |
access_denied_error | 模型不在 API Key 白名单 |
quota_exceeded_error | 额度不足或套餐不可用 |
