API 调用指导
VeyraOS 为每个智能体实例提供两个对外接口:
- OpenAI 兼容接口(本页主体):
/v1/chat/completions等,用标准 OpenAI SDK 即可直接调用, 流式与非流式都兼容。 - 完整能力接口(VES):
/v1/runs系列,返回平台统一事件流 VES,除正文外还带工具调用、 思考过程与任务取消。门户界面走这个接口,同样对外开放——需要完整过程或中途取消时用它 (见下文「完整能力接口」)。
两个接口用同一把 API Key。你可以在智能体工作台「版本」页签的 HTTP API 卡片(或实例详情页 「API Keys」页签)创建 sk- 风格 API Key。
准备工作
- 已部署一个智能体实例(状态为
RUNNING) - 在智能体工作台「版本」页签的 HTTP API 卡片单击生成(或实例详情页「API Keys」tab)创建一个 API Key,复制明文 key 妥善保存(创建后不再显示)
基础调用
Endpoint
POST http://<服务器IP>:30080/v1/chat/completions
Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
<服务器IP>:30080为 admin 门户地址,nginx 已反代/v1/*到 gateway。用
sk-API Key 调用时,请求路由到的智能体由 Key 本身决定,无需额外请求头。 若改用平台 JWT(Authorization: Bearer <JWT>)调用/v1/*,需同时带X-Agent-ID(智能体 ID)与X-Engine-Type(智能体引擎标识,见智能体详情); 缺少引擎标识或取值不支持时返回400。
curl 示例
curl -X POST http://190.92.230.115:30080/v1/chat/completions \
-H "Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "hermes-default",
"messages": [
{"role": "user", "content": "你好,介绍一下自己"}
],
"stream": false
}'响应(非流式):
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"model": "hermes-default",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "你好!我是..."},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 12, "completion_tokens": 30, "total_tokens": 42}
}流式响应(OpenAI chunk)
"stream": true 时返回标准 OpenAI chunk 流(data: {"choices":[{"delta":{...}}]},以 data: [DONE] 收尾),与 OpenAI SDK 及各类 OpenAI 兼容工具直接兼容。
curl -N -X POST http://190.92.230.115:30080/v1/chat/completions \
-H "Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "hermes-default",
"messages": [{"role": "user", "content": "写一首短诗"}],
"stream": true
}'data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"春"}}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"眠"}}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":30,"total_tokens":42}}
data: [DONE]本接口只保证正文与用量的 OpenAI 兼容:工具调用过程、思考过程、任务取消等不在此接口输出, 需要时请用下方的「完整能力接口」。
Python 示例(非流式)
from openai import OpenAI
client = OpenAI(
base_url="http://190.92.230.115:30080/v1",
api_key="sk-xxxxxxxxxxxxxxxxxxxx",
)
resp = client.chat.completions.create(
model="hermes-default",
messages=[{"role": "user", "content": "你好"}],
stream=False,
)
print(resp.choices[0].message.content)Node.js SDK 示例(非流式)
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://190.92.230.115:30080/v1",
apiKey: "sk-xxxxxxxxxxxxxxxxxxxx",
});
const resp = await client.chat.completions.create({
model: "hermes-default",
messages: [{ role: "user", content: "你好" }],
});
console.log(resp.choices[0].message.content);Python 示例(流式)
from openai import OpenAI
client = OpenAI(
base_url="http://190.92.230.115:30080/v1",
api_key="sk-xxxxxxxxxxxxxxxxxxxx",
)
stream = client.chat.completions.create(
model="hermes-default",
messages=[{"role": "user", "content": "写一首短诗"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)完整能力接口(VES)
POST /v1/runs 返回平台统一事件流 VES(Veyra Event Stream):每条 data: 行是一个 JSON 帧, 以帧内 type 字段区分,同一轮内 seq 递增,run.completed / run.failed / run.cancelled 一定在最后。除正文外,这里还有工具调用、思考过程、用量与任务取消。
curl -N -X POST http://190.92.230.115:30080/v1/runs \
-H "Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"input": "写一首短诗",
"session_id": "my-session-1",
"model": "hermes-default"
}'请求体:
| 字段 | 必填 | 说明 |
|---|---|---|
input | 是 | 本轮用户输入 |
session_id | 否 | 会话标识;同一会话的多轮传相同值(首次可留空或自定义) |
conversation_history | 否 | 历史轮 [{role, content}],role 取 user / assistant |
attachments | 否 | 附件列表(与 /v1/chat/completions 同格式) |
model | 否 | 模型名(不传用实例默认) |
响应(节选):
data: {"type":"run.started","run_id":"run_xxx","seq":1}
data: {"type":"message.started","run_id":"run_xxx","message_id":"...","seq":2}
data: {"type":"message.delta","run_id":"run_xxx","message_id":"...","delta":"春","seq":3}
data: {"type":"message.completed","run_id":"run_xxx","message_id":"...","seq":8}
data: {"type":"usage.updated","run_id":"run_xxx","usage":{"prompt_tokens":12,"completion_tokens":30},"seq":9}
data: {"type":"run.completed","run_id":"run_xxx","seq":10}主要帧类型:
帧 type | 含义 |
|---|---|
run.started / run.completed / run.failed / run.cancelled | 本轮对话的开始与终止(终止帧必为最后一帧) |
message.started / message.delta / message.completed | 回复正文(delta 为增量文本) |
reasoning.delta / reasoning.completed | 模型的思考过程(引擎支持时才有;Dify 型智能体也会输出) |
tool.started / tool.progress / tool.completed / tool.failed | 工具调用生命周期(引擎支持时才有) |
step.started / step.completed | 处理步骤的进度(如工作流型智能体的节点执行;status 为 waiting 表示该步骤在等待人工处理) |
interaction.requested / interaction.resolved | 需要用户确认的交互(如命令审批) |
usage.updated | 用量统计 |
platform.* | 平台保留命名空间(如长时间无输出时的心跳提示) |
客户端解析时忽略未知
type。type以x.开头的是引擎扩展帧,同样可安全忽略。
任务状态与取消
| 操作 | 请求 | 说明 |
|---|---|---|
| 查状态 | GET /v1/runs/{run_id} | 返回 {"run_id":"...","status":"running"},status 取 running / completed / failed / cancelled |
| 取消任务 | POST /v1/runs/{run_id}/cancel | 受理返回 202;任务已结束时幂等返回 200 与原状态 |
取消会同时停止引擎侧执行,流内随即以 run.cancelled 收尾。客户端直接断开连接也视同取消。
事件续接(
GET /v1/runs/{run_id}/events)与交互应答(POST /v1/runs/{run_id}/approval) 目前仅部分引擎支持;不支持时返回404与稳定的错误码(replay_not_supported/interaction_not_supported),不会静默失败。
Python 示例(按 VES 帧解析)
import json
import requests
resp = requests.post(
"http://190.92.230.115:30080/v1/runs",
headers={"Authorization": "Bearer sk-xxxxxxxxxxxxxxxxxxxx"},
json={
"input": "写一首短诗",
"session_id": "my-session-1",
"model": "hermes-default",
},
stream=True,
)
for line in resp.iter_lines():
if not line or not line.startswith(b"data: "):
continue
frame = json.loads(line[len(b"data: "):])
if frame["type"] == "message.delta":
print(frame["delta"], end="", flush=True)
elif frame["type"] in ("run.completed", "run.failed", "run.cancelled"):
break引擎差异
不同引擎类型的智能体,调用行为略有差异:
| 引擎 | model 字段 | 备注 |
|---|---|---|
| Hermes | hermes-default 或自定义 | 走 Profile 默认 Pod |
| Dify-Chat | 任意(仅占位) | 走 Dify chat-messages API |
| Dify-Workflow | 任意 | 走 Dify workflows/run API |
| Dify-Agent | 任意 | Dify 平台限制,必须 stream: true |
| Dify 全部类型 | 不生效 | 实际使用的模型由 Dify 平台上的应用编排决定——可能经本平台网关调用,也可能由 Dify 直连模型服务(工作台绑定面板可查看该应用的模型通道) |
| DeepSeek | 模型组(如 deepseek-chat) | 走 DeepSeek Harness 引擎,模型经统一模型网关 |
- 两个接口(
/v1/chat/completions与/v1/runs)对各引擎都可用,引擎差异由平台消化。- 运行续接(
GET /v1/runs/{id}/events)与交互应答(POST /v1/runs/{id}/approval)目前仅 Hermes 支持;其余引擎在这些端点上返回404(运行状态查询与取消对全部引擎可用)。- API Key 决定路由:
sk-Key 绑定单个智能体实例,model字段不会切换实例。
会话管理
OpenAI 兼容 API 支持会话 CRUD:
# 创建会话
curl -X POST http://190.92.230.115:30080/v1/sessions \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{"title": "我的会话"}'
# 列出会话
curl http://190.92.230.115:30080/v1/sessions \
-H "Authorization: Bearer sk-xxx"
# 列出会话消息
curl http://190.92.230.115:30080/v1/sessions/<session_id>/messages \
-H "Authorization: Bearer sk-xxx"文件管理
# 列出文件
curl http://190.92.230.115:30080/v1/files \
-H "Authorization: Bearer sk-xxx"外部应用接入
本节与上文「Dify 外接应用绑定」是两套不同机制:本节讲的是把平台能力开放给第三方应用(
external_app_id+ 外部用户 ID 绑定);Dify 外接是平台对接你自管的 Dify 实例,二者互不影响。
第三方应用可使用绑定外部应用的 API Key 接入,让每位终端用户拥有独立的会话与上下文:
- 管理员创建外部应用:
POST /api/manager/external-apps(管理 API,JWT 鉴权)。 - 为智能体实例创建 API Key 时指定该外部应用(请求体带
external_app_id)。 - 为平台终端用户建立与外部用户 ID 的绑定:
POST /api/manager/end-users/{终端用户ID}/external-user-bindings(同一外部应用下,一个外部用户 ID 对应一位终端用户)。 - 应用服务端每次请求携带
X-External-User-Id头:
curl -X POST http://190.92.230.115:30080/v1/chat/completions \
-H "Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx" \
-H "X-External-User-Id: app-user-123" \
-H "Content-Type: application/json" \
-d '{ ... }'说明:
- 携带已绑定的外部用户 ID 时,请求自动路由到对应终端用户的独立上下文,不同终端用户互不混淆。
- 未携带
X-External-User-Id头时,与普通 API Key 行为一致(使用实例默认上下文)。 - 携带了未绑定的外部用户 ID 会返回 401,请先完成第 3 步绑定。
API Key 必须只保留在应用服务端
X-External-User-Id 头本身不含签名,网关依据 API Key 信任该头。绑定外部应用的 API Key 只能由你的服务端持有并发起调用,不得下发到浏览器、App 等客户端——否则任一终端用户篡改该头即可冒充其他用户,访问其会话与数据。客户端请一律经由你自己的服务端中转调用。
常见错误
| HTTP | 原因 | 处理 |
|---|---|---|
| 401 | API Key 无效 / 已删除 / 外部用户 ID 未绑定 | 重新创建 Key;注意删除后最长 60s 内可能仍生效;外部接入先完成用户绑定 |
| 400 | 请求体格式错误 | 检查 messages 字段是否合法 |
| 503 | 引擎 Pod 未就绪 | 在实例详情页确认状态为 RUNNING |
| 502 | 网关无法连接引擎 | 检查实例是否已部署、Pod 是否健康 |
安全建议
- 不要把 API Key 提交到代码仓库,使用环境变量或密钥管理服务
- 每个场景独立 Key:生产/测试/开发各用不同 Key,方便撤销与追踪
- 定期轮换:删除旧 Key 创建新 Key,60s 内切换
- 设置用量告警:在监控中心配置异常告警,发现异常调用及时处理
管理 API:级联删除智能体
删除智能体定义走 Manager 管理 API(JWT 鉴权,非 sk- Key):
# 预览删除影响:列出定义下全部实例
curl http://190.92.230.115:30080/api/manager/agent-definitions/<definition_id>/instances \
-H "Authorization: Bearer <JWT>"
# 级联删除:定义与其全部实例一并删除,实例数据(含归档)不可恢复
curl -X DELETE "http://190.92.230.115:30080/api/manager/agent-definitions/<definition_id>?cascade=true" \
-H "Authorization: Bearer <JWT>"- 不传
cascade(默认false)时,若仍有实例引用该定义则返回409,删除被拒绝。 cascade=true时逐实例删除;部分实例失败返回409,detail中含失败清单,已删成功的实例不回滚,重试即可续删。- 全部成功返回
204。
管理 API:查看实例部署产物
每次部署都会记录一份该实例的最终引擎消费配置(环境变量全集 + 模型/技能/MCP 清单 + 知识库绑定),可用于审计「这次部署到底给引擎喂了什么」:
curl http://190.92.230.115:30080/api/manager/agent-instances/<instance_id>/prepared-config \
-H "Authorization: Bearer <JWT>"- 实例尚未部署过时返回
404。 - 响应中的敏感环境变量值已掩码(仅末 4 位可见,如
***1234)。 - 重新部署时若配置无变化会自动跳过引擎重启。
管理 API 认证
管理 API(/api/manager/*)使用 JWT 鉴权,与智能体调用的 sk- API Key 相互独立。JWT 分两类,token 的 aud claim 标记所属账号体系,两类 token 不可跨体系使用:
- 管理台账号:
POST /api/manager/auth/login(另支持邮箱/手机号密码、短信验证码登录与「一键演示」/api/manager/auth/demo-login)→ tokenaud="admin" - 终端用户账号:
POST /api/manager/auth/enduser/login(另支持/api/manager/auth/enduser/login-by-contact、/api/manager/auth/enduser/login-by-sms-code、/api/manager/auth/enduser/demo-login)→ tokenaud="enduser"
管理 API 的完整端点清单见 API 参考(Swagger UI 自动生成),此处不重复罗列。
SaaS 运营操作(ops 门户)
客户 SaaS 运营操作(客户状态管理、对公到账确认、通知/支付通道配置等)已随 #480 迁至 account 运营接口(/api/account/ops/*,门户 JWT 鉴权 + 平台员工 scope 门禁)。运营人员 使用 ops 门户操作;权限由平台员工绑定(platform_staff scopes)授予。
SaaS 账号登录
门户用户登录走 Account 认证 API(无需 Bearer 头;返回的 access_token / refresh_token 用于门户自助接口):
# 手机号 / 邮箱 + 密码登录
curl -X POST http://<account-host>/api/account/auth/login \
-H "Content-Type: application/json" \
-d '{"contact_type": "email", "contact": "user@example.com", "password": "<密码>"}'
# 账号名 + 密码登录(平台开启账号名登录后可用;账号名在「账号中心 → 账号安全」设置)
curl -X POST http://<account-host>/api/account/auth/login \
-H "Content-Type: application/json" \
-d '{"contact_type": "account", "contact": "alice", "password": "<密码>"}'contact_type取值:email/phone/account(账号名)。账号名规则:小写字母开头,可含数字、_、-,长度 3–32 位。- 验证码登录(
POST /api/account/auth/login-or-register):contact_type为email(或平台开启手机能力后的phone)+code,仅登录已注册的联系方式;未注册返回404 contact_not_registered(请改走注册接口)。注册统一走POST /api/account/register(个人)/POST /api/account/register/organization(企业)/POST /api/account/register/invite(凭邀请码入组),username/password均为必填。 - 登录响应的
user对象携带username字段(未设置账号名时为null)。 - 失败(密码错误 / 账号不存在 / 账号名登录未开启)统一返回
401 invalid_credentials;连续失败 2 次后要求图形验证码(400 captcha_required),连续失败 5 次锁定 15 分钟(423 account_locked)。 - 设置账号名:登录后调用
POST /api/account/username/set(仅未设置时可用,请求体{"username": "alice"};被占用返回409 username_taken)。
API 参考文档
完整的 Manager 管理 API(智能体定义/实例管理/用户/角色等)请查看 API 参考(Swagger UI 自动生成)。