Files
wehub-resource-sync 1443d3fdf9
Ruff Format Check / Ruff Format & Lint (push) Failing after 7m39s
Deploy VitePress site to Pages / build (push) Failing after 9m11s
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:26 +08:00

193 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API Key 外部集成
Yuxi 平台提供了 API Key 认证机制,允许外部系统在无需用户登录的情况下调用智能体对话接口。本文档详细介绍 API Key 的使用方法、接口调用方式以及安全注意事项。
## API Key 概述
API Key 是一种用于身份验证的密钥字符串,外部系统可以通过它在请求头中携带凭据来访问 Yuxi 的对话接口。与传统的用户名密码登录方式相比,API Key 更加适合用于系统间的自动化调用场景。Yuxi 的 API Key 以 `yxkey_` 为前缀,长度为 54 个字符,采用 SHA-256 哈希存储,确保密钥本身不会在数据库中明文保存。系统会记录每个 API Key 的最后使用时间,方便管理员追踪使用情况。
## 创建 API Key
登录系统后,进入 API Key 管理界面,可以创建新的密钥。创建时需要为 API Key 设置一个名称,用于标识其用途,例如"外部客服系统"或"数据同步服务"。创建的 API Key 会自动绑定到当前登录用户,绑定后的 API Key 在调用接口时会以该用户的身份执行操作。API Key 还支持设置过期时间,过期后该密钥将自动失效。
需要特别注意的是,创建 API Key 时返回的完整密钥(secret)只会显示一次,务必在创建时将其安全保存。如果遗失,需要通过"重新生成"功能生成新的密钥,原有的密钥将立即失效。
管理接口同样走通用认证:
- `GET /api/user/apikey/`:列出当前用户可见的 API Key
- `POST /api/user/apikey/`:创建 API Key
- `PUT /api/user/apikey/{api_key_id}`:更新名称、状态或过期时间
- `POST /api/user/apikey/{api_key_id}/regenerate`:重新生成密钥
- `DELETE /api/user/apikey/{api_key_id}`:删除密钥
## 确定 API 访问地址
Yuxi 后端服务绑定在 `0.0.0.0:5050`,不会自动探测或对外宣告本机 IP。实际访问地址取决于部署环境:
- **本地开发**`http://localhost:5050`
- **生产部署(Nginx 反向代理)**:**强烈建议使用 HTTPS**,即 `https://<服务器域名>`443 端口)。由于 API Key 会在请求头中以明文形式传输,使用 HTTP(80 端口)会导致密钥在网络传输过程中被窃听或篡改,必须避免
完整的 API 交互流程可参考自动生成的 Swagger 文档:`{base_url}/docs`
## 接口调用方式
> **关于 `agent_id` / `agent_slug` 的说明**:创建会话线程时仍使用 `agent_id` 绑定目标 Agent;创建运行任务时使用 `agent_slug` 快照本次运行目标。二者的取值都是智能体的 **slug**(如 `default-chatbot`),不是数据库自增 ID 或 `agent_config_id`。
外部系统通过 HTTP 请求调用 Yuxi 接口时,需要在请求头中携带 API Key:
```http
Authorization: Bearer yxkey_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
当前智能体对话采用 run + SSE 流程:
1. 创建对话线程:`POST /api/chat/thread`
2. 创建运行任务:`POST /api/agent/runs`
3. 订阅事件流:`GET /api/agent/runs/{run_id}/events`
`POST /api/agent/runs` 请求体必填 `query``agent_slug``thread_id`,可选字段包括 `meta``image_content``resume``created_by_run_id`。接口返回 `run_id``thread_id``status``request_id``stream_url`
以下是一个典型的 Python 调用示例:
```python
import json
import requests
base_url = "https://your-yuxi-server" # 生产环境务必使用 HTTPS;本地开发可改为 http://localhost:5050
headers = {
"Authorization": "Bearer yxkey_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
}
thread_resp = requests.post(
f"{base_url}/api/chat/thread",
headers=headers,
json={
"agent_id": "default-chatbot",
"title": "外部系统会话",
"metadata": {},
},
)
thread_resp.raise_for_status()
thread_id = thread_resp.json()["id"]
run_resp = requests.post(
f"{base_url}/api/agent/runs",
headers=headers,
json={
"query": "你好,请介绍一下你自己",
"agent_slug": "default-chatbot",
"thread_id": thread_id,
"meta": {"request_id": "external-request-001"},
},
)
run_resp.raise_for_status()
run = run_resp.json()
with requests.get(f"{base_url}{run['stream_url']}", headers=headers, stream=True) as response:
response.raise_for_status()
event_type = None
data_lines = []
for line in response.iter_lines(decode_unicode=True):
if line is None:
continue
if line.startswith(":"):
continue
if line == "":
if event_type and data_lines:
payload = json.loads("\n".join(data_lines))
print(event_type, payload)
if event_type == "end":
break
event_type = None
data_lines = []
continue
if line.startswith("event:"):
event_type = line.removeprefix("event:").strip()
elif line.startswith("data:"):
data_lines.append(line.removeprefix("data:").strip())
```
如果已经有会话线程,可以复用已有 `thread_id` 直接创建 run
```json
{
"query": "继续上一轮话题",
"agent_slug": "default-chatbot",
"thread_id": "existing-thread-id",
"meta": {}
}
```
### 读取运行结果
如果不需要逐事件消费 SSE,可以在 run 终态后直接拉取最终结果:
```http
GET /api/agent/runs/{run_id}/result
```
返回结构包含运行状态、最终 assistant 输出、Langfuse trace id 和错误信息。该接口只读,不会再次触发 run。对外部系统只关心「最终答案」、不需要展示中间过程的场景,比订阅 SSE 更简单。
### 外部系统调用入口
除通用 `/api/agent/runs` 之外,Yuxi 还提供专为外部系统设计的 `agent-invocation` 路由,复用同一套 AgentRun 队列与结果读取能力:
| 接口 | 用途 | 关键字段 |
|------|------|----------|
| `POST /api/agent-invocation/agent-call/runs` | 外部系统调用 Agent`async_mode=true` 时立即返回 `run_id`,否则阻塞到 run 终态返回结果 | `agent_slug``messages``thread_id``request_id``model_spec``async_mode` |
| `POST /api/agent-invocation/agent-call/runs/result` | 读取 agent-call run 的 OpenAI 兼容结果结构 | `run_id`、可选 `agent_slug` |
| `POST /api/agent-invocation/eval/runs` | 运行一次评估样例,阻塞到 run 终态后返回最终输出与可选轨迹摘要 | `query``agent_slug``evaluation``include_trajectory_summary` |
agent-call 的 `messages[].content` 兼容 OpenAI 风格的 `text`/`image_url` 多模态数组:纯文本数组不会触发 422,图片输入会保留原始 LangChain 多模态消息供 worker 恢复。出于安全考虑,**不允许通过 `agent_call_meta.context` 覆盖 Agent 运行上下文**;运行时模型覆盖只允许走独立 `model_spec` 字段。Agent Eval 通常通过 `yuxi agent eval` CLI 触发,详见[智能体评估](../agents/agent-evaluation.md)。
## 响应格式
运行事件流采用 Server-Sent Events 格式,响应头为 `text/event-stream`。每个事件包含:
- `event`:事件类型,可能是模型输出、工具调用、子智能体输出等语义事件,也可能是 `error` 或终止事件 `end`
- `data`JSON 编码的事件 envelope,包含 `run_id``thread_id`、事件载荷等字段
- `id`Redis Stream 序号,可作为断线重连游标
服务端还会定期发送以 `:` 开头的 heartbeat 注释,客户端应忽略。断线重连时,可以在请求头中传 `Last-Event-ID`,或在 query 参数中传 `after_seq`,服务端会从该序号后继续回放事件。
事件流默认返回完整载荷,便于排查 LangGraph/Langfuse 运行细节。如果只需要渲染消息、工具调用、工具结果、Agent state 和终止状态,可以在订阅地址追加 `?verbose=false`。精简模式会保留 SSE `event/data/id`、data 中的 `run_id/thread_id/request_id/payload` 以及客户端消费所需字段;同一 data 内的 `request_id` 会外提为单个字段。精简模式还会跳过 `metadata` 和空 `yuxi.agent_state`,并去掉每个 chunk 中重复的 `meta``metadata``thread_id``response`、空 `namespace` 和图片 base64 等调试字段。
每次创建 run 都会返回 `request_id`,可用于日志追踪和问题排查。如果需要在多轮对话中使用同一个会话,请复用 `thread_id`,系统会将同一线程的消息串联起来形成连贯的对话上下文。
## 认证方式
Yuxi 的 API 接口统一支持两种认证方式:
1. **API Key 认证**:使用 `Authorization: Bearer <api_key>` 格式,其中 API Key 必须以 `yxkey_` 前缀开头
2. **JWT Token 认证**:使用 `Authorization: Bearer <jwt_token>` 格式
系统根据 token 的前缀自动判断认证方式。以 `yxkey_` 开头的 token 被视为 API Key,其他 token 则作为 JWT Token 处理。这种设计使得同一个接口可以同时支持外部系统(使用 API Key)和内部前端应用(使用用户登录态)调用。
## 安全注意事项
**传输层安全**:API Key 在请求头中以明文形式传输,**生产环境必须通过 HTTPS(443 端口)调用**,避免在公网上以 HTTP 明文传输造成密钥泄露。建议在 Nginx 反向代理层启用 TLS 并强制 HTTP 重定向到 HTTPS。
保管好 API Key 密钥是最重要的安全原则。由于 API Key 一旦泄露就可能被滥用,建议不要将密钥硬编码在代码中,而是通过环境变量或配置中心来管理。如果怀疑密钥泄露,应立即在管理界面禁用该 API Key 并重新生成。启用密钥过期功能是一种良好的安全实践,可以设置较短的有效期并定期轮换。
在生产环境中,建议为不同的外部系统创建独立的 API Key,这样可以在某个密钥泄露时快速定位问题并限制影响范围。同时,建议在管理界面定期查看 API Key 的使用记录,检查是否存在异常调用情况。
关于权限控制,API Key 的权限等同于其绑定的用户在系统中的角色。如果 API Key 绑定到特定用户,则该用户的所有权限都会体现在 API Key 的操作中,因此务必妥善保管。
## 常见问题
**Q: API Key 认证失败返回什么错误?**
A: 认证失败时返回 401 Unauthorized 错误,错误信息为"无效的凭证"。请检查请求头中 `Authorization` 字段的格式是否正确,是否包含完整的密钥,且密钥必须以 `yxkey_` 开头。
**Q: 可以同时使用 API Key 和 JWT Token 吗?**
A: 不可以。系统根据 token 前缀自动判断认证方式。以 `yxkey_` 开头的 token 使用 API Key 认证,其他 token 使用 JWT 认证。
**Q: API Key 是否有调用频率限制?**
A: 目前没有单独的频率限制,但 API Key 的行为等同于其绑定的用户身份,因此会受到用户角色相关的一些限制。
**Q: 对话返回的内容是乱码怎么办?**
A: 确保客户端正确处理了 UTF-8 编码。流式响应中可能包含中文字符,需要使用正确的编码方式解析。如果在终端显示乱码,可以检查终端的编码设置。