Agent 聊天 API
发送 Agent 消息并接收正文、来源、工具和媒体结果
Chat API 用于向 Agent 发送消息、接收流式响应、管理运行和会话。聊天端点挂载在 /api/v1/agents 下;会话管理端点分别挂载在 /api/v1/conversations 和 /api/v1/agents/conversations 下。
认证
POST /api/v1/agents/{agent_id}/chat 和 /chat/stream 支持 JWT Bearer Token 或 API Key。会话管理和消息版本端点要求认证为会话所有者。
所需作用域:
agent:read- 查看 Agentagent:chat- 与 Agent 聊天conversation:read- 列出和查看会话conversation:delete- 删除会话
Agent 必须已发布。API Key 需要对应权限,并且如果绑定了 Agent,只能访问允许列表中的 ID。Agent 的附件限制、工具迭代上限和模型配额仍然生效。
端点总览
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /api/v1/agents/{agent_id}/public | 获取公开 Agent 基础信息,可选认证 |
| POST | /api/v1/agents/{agent_id}/chat | 非流式聊天 |
| POST | /api/v1/agents/{agent_id}/chat/stream | SSE 流式聊天 |
| POST | /api/v1/agents/{agent_id}/chat/runs | 创建持久运行,立即返回 202 Accepted |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id}/stream?after_sequence=N | 订阅运行事件流(可断点续连) |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/stop | 协作式终止运行 |
| POST | /api/v1/agents/{agent_id}/messages/{message_id}/regenerate | 重新生成 |
| POST | /api/v1/agents/{agent_id}/messages/{message_id}/edit/stream | 编辑用户消息并生成分支 |
| GET | /api/v1/agents/{agent_id}/messages/{message_id}/versions | 查询消息版本 |
| POST | /api/v1/agents/{agent_id}/messages/{message_id}/switch-version | 切换版本 |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id} | 运行状态(所有者范围) |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id}/events?after_sequence=N | 回放 N 之后的事件 |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/inputs | 排队引导/追问(delivery: steer / follow_up / auto) |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/answers | 提交等待中 ask_user 调用的结构化答案 |
| GET | /api/v1/conversations | 列出会话 |
| GET | /api/v1/conversations/{conversation_id} | 获取会话及消息 |
| PATCH | /api/v1/agents/conversations/{conversation_id} | 更新会话标题 |
| DELETE | /api/v1/conversations/{conversation_id} | 删除会话 |
发送消息
向 Agent 发送消息并接收响应。
端点
POST /api/v1/agents/{agent_id}/chat路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
agent_id | string | 是 | Agent UUID |
请求体
{
"message": "营业时间是什么?",
"conversation_id": "conv-123",
"file_urls": [
{
"asset_id": "asset-456",
"url": "https://your-domain.com/api/v1/upload/files/general/2026/09/7f3a1c9d2b10_a1b2c3d4.pdf",
"filename": "7f3a1c9d2b10_a1b2c3d4.pdf",
"size": 1048576,
"mime_type": "application/pdf"
}
],
"variables": {
"customer_tier": "premium"
}
}使用上传响应中的 url、filename、size 和 mime_type 原样提交,不要根据 asset_id 自行拼接 /upload/files/{asset_id}。生成图片或视频的 asset_ref 仅在对应会话或工作流运行范围内有效;受保护媒体 URL 需要带当前 JWT 或 API Key 请求。
请求字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
message | string | 是 | 用户消息(最多 32000 字符) |
images | array | 否 | 视觉图片(asset_id 或 asset_ref、type、url) |
files | array | 否 | 已解析的上传文件(已弃用,使用 file_urls) |
file_urls | array | 否 | 上传响应中的 Asset 元数据(asset_id、filename、url、size、mime_type) |
conversation_id | string | 否 | 会话 UUID(不提供则创建新会话) |
variables | object | 否 | 聊天输入表单的变量值 |
history_override | array | 否 | 覆盖会话历史(用于版本切换/重新生成) |
请求示例
curl -X POST "https://your-domain.com/api/v1/agents/agent-123/chat" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "营业时间是什么?",
"conversation_id": "conv-123"
}'非流式响应
成功 (200 OK):
{
"code": 0,
"data": {
"conversation_id": "conv-123",
"message": {
"id": "msg-456",
"conversation_id": "conv-123",
"role": "assistant",
"content": "我们的营业时间是周一至周五,美国东部时间上午 9 点至下午 5 点。",
"tool_calls": [],
"tool_name": null,
"model_used": "gpt-4",
"token_usage": {
"prompt": 150,
"completion": 25,
"total": 175
},
"duration_ms": 2300,
"rag_context": [
{
"document_id": "doc-789",
"document_name": "营业时间政策",
"chunk_id": "chunk-012",
"content": "营业时间:周一至周五,美东时间上午 9 点至下午 5 点",
"score": 0.95,
"citation_id": "rag_0123456789abcdef"
}
],
"created_at": "2026-02-11T16:00:00Z",
"version_number": 1,
"version_count": 1
},
"usage": {
"prompt": 150,
"completion": 25,
"total": 175
}
},
"msg": "success"
}未执行检索时 rag_context 为 null(例如 RAG 关闭或 Agent 未关联知识库);执行检索但没有上下文时为 []。检索上下文可能包含稳定的 citation_id;引用时使用精确的 [[cite:SOURCE_ID]]。
流式响应
流式响应使用独立端点,POST /chat 上没有 stream 标志。
端点: POST /api/v1/agents/{agent_id}/chat/stream
请求体与非流式的 ChatRequest 相同。响应以 Server-Sent Events (SSE) 发送。
Content-Type: text/event-stream
事件格式:
event: message_start
data: {"conversation_id": "conv-123", "message_id": "msg-456"}
event: content_delta
data: {"delta": "我们的"}
event: content_delta
data: {"delta": "营业时间"}
event: content_delta
data: {"delta": "是"}
event: rag_context
data: {"contexts": [{"document_name": "常见问题", "content": "...", "score": 0.95}]}
event: message_end
data: {"usage": {"prompt_tokens": 150, "completion_tokens": 25, "total_tokens": 175}, "timing": {"first_token_ms": 320, "duration_ms": 2300, "tokens_per_second": 10.9}}详见 SSE 流式事件。
media_result 是成功生成媒体时用于 UI 的事件,不会作为文本回放给模型:
客户端应保留收到的 SSE 事件顺序。检索、压缩、推理、工具、媒体和正文事件可能交错;rag_start 与 rag_context 仅在实际执行检索时发送。
event: media_result
data: {"kind":"media.image","success":true,"images":[{"image":{"url":"/api/v1/upload/files/generated-images/2026/09/9a8b7c6d5e4f_55667788.png","asset_ref":"a1b2","format":"png"}}]}生成图片或视频的受保护 URL 必须使用当前 JWT 或 API Key 获取;客户端应明确展示未认证、无权限、不可用或预览过大状态,不得回退到未认证原始 URL。
持久运行与控制
聊天执行由持久化的 AgentRun 支持,浏览器断开连接不会停止模型循环。/chat 与 /chat/stream 会等待本轮结果;/chat/runs 则把请求落库后立即入队,由 Worker 异步执行,因此连接中断、页面刷新都不会丢失这轮对话。
运行范围的事件在原有 SSE 事件外多一层信封,包含 run_id、sequence、timestamp、round_id、message_id 和 type,因此客户端可以用 after_sequence 精确续读而不重复渲染。
额外的运行事件:
| 事件 | 说明 |
|---|---|
run_start | 运行身份与初始状态 |
run_status | 生命周期转换(queued → running → …);模型调用 ask_user 时进入 waiting,并携带 pending_tool_call_id、pending_tool_name、pending_tool_input |
input_accepted | 排队的引导(steer)或追问(follow-up)已被提交 |
run_end | 每次运行恰好一个终止事件,状态为 completed、stopped、failed 或 interrupted |
| 方法 | 路径 | 用途 |
|---|---|---|
| POST | /api/v1/agents/{agent_id}/chat/runs | 落库并入队一次运行(202 Accepted) |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id}/stream?after_sequence=N | SSE 订阅该运行的事件流(可断点续连) |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id} | 运行状态(所有者范围) |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id}/events?after_sequence=N | 回放已缓冲事件(非流式,适合补齐丢包) |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/inputs | 排队引导/追问/停止(delivery: steer / follow_up / auto) |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/answers | 提交等待中 ask_user 调用的结构化答案 |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/stop | 协作式终止运行 |
创建运行
POST /api/v1/agents/{agent_id}/chat/runs请求体与 POST /api/v1/agents/{agent_id}/chat 完全相同(同一个 ChatRequest),区别是立即返回 202 Accepted,不等助手回复。响应数据是 RunStartOut:
{
"code": 0,
"data": {
"run_id": "8f3b1c9d-2b10-4a1b-9c3d-7f3a1c9d2b10",
"conversation_id": "conv-123",
"user_message_id": "msg-456",
"status": "queued",
"stream_url": "/agents/agent-123/chat/runs/8f3b1c9d-2b10-4a1b-9c3d-7f3a1c9d2b10/stream"
},
"msg": "success"
}| 字段 | 类型 | 说明 |
|---|---|---|
run_id | string | 持久运行 UUID |
conversation_id | string | 会话 UUID(请求未带 conversation_id 时自动创建) |
user_message_id | string | 已落库的用户消息 UUID |
status | string | 入队时的运行状态(见下方状态取值) |
stream_url | string | 该运行 SSE 流的相对路径,不含 /api/v1 前缀 |
stream_url 是相对路径,只带 /agents/...(embed 场景为 /embed/agents/...)。拼接订阅地址时必须自行补上 /api/v1。
订阅运行事件流
GET /api/v1/agents/{agent_id}/chat/runs/{run_id}/stream?after_sequence=N返回 text/event-stream:先回放 sequence 大于 after_sequence(默认 0)的所有缓冲事件,再跟随实时事件直到该运行的终止事件。支持 JWT Bearer Token 或 API Key。
重连语义:客户端记录已处理的最高 sequence,断开后以该值作为 after_sequence 重新请求,即可无重复、无丢失地继续。after_sequence 为负数时按 0 处理。需要非流式补齐时用 GET .../events?after_sequence=N 读取同一批事件。
运行状态取值(RunOut.status / RunStartOut.status):queued、running、stopping、completing、waiting、completed、stopped、failed、interrupted。其中 completed、stopped、failed、interrupted 为终态。
终止运行
POST /api/v1/agents/{agent_id}/chat/runs/{run_id}/stop无请求体。协作式终止处于 queued、running 或 waiting 的运行,返回更新后的 RunOut;随后事件流会收到 status: "stopped" 的终止 run_end。对 waiting 运行(等待 ask_user 答案)执行停止同样有效。
RunOut 字段:id、agent_id、conversation_id、mode、status、source_message_id、canonical_message_id、active_round_id、error_code、error_message、started_at、finished_at,以及等待中的 ask_user 交互(pending_tool_call_id、pending_tool_name、pending_tool_input)。
访问边界:全部运行路由按所有者(API Key 场景按 Agent)限定。运行不存在、或不属于路径中的 {agent_id} → 404(业务码 4000,run_not_found);运行所属会话属于他人 → 403(业务码 1004,access_denied);超级管理员绕过所有权检查。
提交等待中 ask_user 调用的答案:
POST /api/v1/agents/{agent_id}/chat/runs/{run_id}/answers请求体:
{
"tool_call_id": "call-123",
"answers": {
"deployment_target": "云端"
},
"skipped": false
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
tool_call_id | string | 是 | 来自 run_status 等待事件的待处理工具调用 ID |
answers | object | 否 | ID 键控的答案映射;每个值为所选选项或自定义字符串 |
skipped | boolean | 否 | 显式跳过所有问题(发送 { "answers": {}, "skipped": true }) |
运行必须处于 waiting 状态,且 tool_call_id 必须匹配待处理的交互。成功后运行从暂停状态恢复。
当运行活跃时,编辑器可以排队引导(中途)或追问(最终边界),而不是被禁用;停止发送服务器命令并等待终止 run_end 事件。
重新生成
重新生成助手消息。此端点挂载在 agents 路由器下,由 agent_id + message_id 寻址(路径中无 conversation_id)。
端点
POST /api/v1/agents/{agent_id}/messages/{message_id}/regenerate路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
agent_id | string | 是 | Agent UUID |
message_id | string | 是 | 要重新生成的消息 UUID |
请求体
{
"variables": {}
}请求示例
curl -X POST "https://your-domain.com/api/v1/agents/agent-123/messages/msg-002/regenerate" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"variables": {}
}'响应
成功 (200 OK):
{
"code": 0,
"data": {
"conversation_id": "conv-123",
"message": {
"id": "msg-003",
"conversation_id": "conv-123",
"role": "assistant",
"content": "我们的营业时间是周一到周五,美国东部标准时间上午 9:00 到下午 5:00。",
"token_usage": {
"total": 180
},
"created_at": "2026-02-11T16:15:00Z",
"version_number": 2,
"version_count": 2
},
"usage": {
"total": 180
}
},
"msg": "success"
}编辑用户消息并重新生成 (SSE)
编辑用户消息、创建新版本并流式传输重新生成的回复:
POST /api/v1/agents/{agent_id}/messages/{message_id}/edit/stream请求体:
{"content": "你们的节假日营业时间是多少?"}只能编辑用户消息。响应为认证的 SSE 流(text/event-stream),使用聊天流事件格式;最终的 message_end 事件包含 edited_version_number 和 edited_version_count。
消息版本
列出版本
列出消息版本组中的版本。此路由要求认证为会话所有者。
GET /api/v1/agents/{agent_id}/messages/{message_id}/versions200 OK 响应为消息版本对象数组,包含 id、version_number、is_active、content 和 created_at。
切换版本
在同一消息组中激活不同版本。选中消息之后的版本会被停用,因为它们基于之前的分支。
POST /api/v1/agents/{agent_id}/messages/{message_id}/switch-version请求体:
{"version_id": "msg-version-003"}200 OK 响应返回选中的 MessageOut,包含版本信息。认证用户必须拥有该会话。
会话管理
列出会话
GET /api/v1/conversations| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page | integer | 否 | 1 | 页码 |
page_size | integer | 否 | 20 | 每页条数(最多 100) |
team_id | string | 否 | - | 按团队筛选 |
agent_id | string | 否 | - | 按 Agent ID 筛选 |
user_id | string | 否 | - | 按用户筛选(仅管理员/仪表盘访问) |
search | string | 否 | - | 按会话标题模糊匹配(不含消息正文) |
untitled_only | boolean | 否 | false | 仅显示无标题会话(优先于 search,两者同时提供时忽略 search) |
成功 (200 OK):
{
"code": 0,
"data": {
"items": [
{
"id": "conv-123",
"agent_id": "agent-456",
"agent_name": "客服 Agent",
"agent_icon": "🤖",
"title": "营业时间咨询",
"message_count": 5,
"created_at": "2026-02-11T16:00:00Z",
"updated_at": "2026-02-11T16:05:00Z",
"user_id": "user-123",
"user_name": "alice"
}
],
"total": 42,
"page": 1,
"page_size": 20
},
"msg": "success"
}获取会话
GET /api/v1/conversations/{conversation_id}成功 (200 OK):
{
"code": 0,
"data": {
"id": "conv-123",
"agent_id": "agent-456",
"agent_name": "客服 Agent",
"agent_icon": "🤖",
"title": "营业时间咨询",
"variables": {},
"message_count": 5,
"token_usage": 875,
"created_at": "2026-02-11T16:00:00Z",
"updated_at": "2026-02-11T16:05:00Z",
"messages": [
{
"id": "msg-001",
"conversation_id": "conv-123",
"role": "user",
"content": "你们的营业时间是什么?",
"created_at": "2026-02-11T16:00:00Z",
"version_number": 1,
"version_count": 1
},
{
"id": "msg-002",
"conversation_id": "conv-123",
"role": "assistant",
"content": "我们的营业时间是周一至周五,美国东部时间上午 9 点至下午 5 点。",
"tool_calls": [],
"rag_context": [
{
"document_id": "doc-789",
"document_name": "营业时间政策",
"score": 0.95
}
],
"created_at": "2026-02-11T16:00:02Z",
"version_number": 1,
"version_count": 1
}
]
},
"msg": "success"
}获取会话消息(分页 GET /conversations/{id}/messages)尚未实现 / Roadmap。消息内联包含在 GET /api/v1/conversations/{conversation_id} 中。
更新会话
更新会话详情(如重命名)。此端点挂载在 agents 路由器下。
PATCH /api/v1/agents/conversations/{conversation_id}请求体:
{
"title": "更新后的会话标题"
}成功 (200 OK):
{
"code": 0,
"data": {
"id": "conv-123",
"title": "更新后的会话标题",
"updated_at": "2026-02-11T16:10:00Z"
},
"msg": "Conversation updated successfully"
}删除会话
永久删除会话(消息级联删除)。DELETE /api/v1/conversations 挂载在平台会话路由器下,需要 conversation:delete;超级管理员/管理员可删除可访问团队内的任意会话,普通成员只能删除自己的会话(非本人会话返回 404)。
DELETE /api/v1/conversations/{conversation_id}成功 (200 OK):
{
"code": 0,
"data": {
"id": "conv-123"
},
"msg": "Conversation deleted successfully"
}批量删除会话
DELETE /api/v1/conversations?ids=conv-123&ids=conv-456ids 是必填的重复查询参数(list[UUID]),一次删除多个会话;权限规则与单条删除相同,任一目标不可访问即整批拒绝。全部目标都不存在时返回 404(6210)。
curl -X DELETE "https://your-domain.com/api/v1/conversations?ids=conv-123&ids=conv-456" \
-H "Authorization: Bearer YOUR_TOKEN"删除单条消息
平台会话路由器没有按消息删除的端点;删除单条消息请使用 agents 路由器下的用户端点:
DELETE /api/v1/agents/conversations/{conversation_id}/messages/{message_id}该端点需要 conversation:delete,且消息必须属于调用者的会话(详见 Agent API 的 Agent 会话)。
路由能力差异:平台 /api/v1/conversations 只有 GET 列表、GET 详情、DELETE 单条、DELETE 批量。重命名(PATCH)与删除单条消息都只在 agents 路由器下(/api/v1/agents/conversations/...)。此外平台列表的 search 只匹配会话标题,不检索消息正文。
用户范围的会话端点(如
GET /api/v1/agents/conversations/my)详见 会话 API。
错误码
| 代码 | 消息 | 说明 |
|---|---|---|
6200 | Agent not found | Agent 不存在 |
6210 | Conversation not found | 会话不存在 |
6211 | Message not found | 消息不存在 |
4000 | Run not found | 持久运行不存在,或不属于路径中的 Agent |
1004 | Access denied | 运行所属会话属于其他用户 |
3000 | Permission denied | 权限不足 |
1001 | Validation failed | 请求数据无效 |
这些端点没有实现每端点速率限制。没有速率限制中间件。
完整的错误处理和重试策略详见 API 错误与重试。
最佳实践
消息处理
✅ 推荐:
- 保持消息简洁清晰
- 需要时提供上下文
- 使用
conversation_id保持上下文 - 处理流式响应以获得更好的用户体验
- 为失败实现重试逻辑
❌ 避免:
- 发送过长的消息
- 每条消息都创建新会话
- 忽略错误响应
- 跳过错误处理
- 频繁请求 API
会话管理
✅ 推荐:
- 使用描述性会话标题
- 清理旧会话
- 监控会话数量
❌ 避免:
- 创建不必要的会话
- 永久保留所有会话
- 忘记删除测试会话
代码示例
Python
import requests
def chat_with_agent(agent_id, message, conversation_id=None):
"""向 Agent 发送消息。"""
url = f"https://your-domain.com/api/v1/agents/{agent_id}/chat"
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
data = {
"message": message,
"conversation_id": conversation_id
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
if result['code'] == 0:
return result['data']
else:
raise Exception(f"Error: {result['msg']}")
# 用法
response = chat_with_agent(
agent_id="agent-123",
message="你们的营业时间是什么?",
conversation_id="conv-123"
)
print(f"响应: {response['message']['content']}")
print(f"会话 ID: {response['conversation_id']}")JavaScript
async function chatWithAgent(agentId, message, conversationId = null) {
const url = `https://your-domain.com/api/v1/agents/${agentId}/chat`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: message,
conversation_id: conversationId,
}),
});
const result = await response.json();
if (result.code === 0) {
return result.data;
} else {
throw new Error(result.msg);
}
}
// 用法
const response = await chatWithAgent(
'agent-123',
'你们的营业时间是什么?',
'conv-123'
);
console.log('响应:', response.message.content);
console.log('会话 ID:', response.conversation_id);相关文档
这篇文章对你有帮助吗?