ClouisleClouisle

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 - 查看 Agent
  • agent: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/streamSSE 流式聊天
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_idstring是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 请求。

请求字段

字段类型必填说明
messagestring是用户消息(最多 32000 字符)
imagesarray否视觉图片(asset_id 或 asset_ref、type、url)
filesarray否已解析的上传文件(已弃用,使用 file_urls)
file_urlsarray否上传响应中的 Asset 元数据(asset_id、filename、url、size、mime_type)
conversation_idstring否会话 UUID(不提供则创建新会话)
variablesobject否聊天输入表单的变量值
history_overridearray否覆盖会话历史(用于版本切换/重新生成)

请求示例

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=NSSE 订阅该运行的事件流(可断点续连)
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_idstring持久运行 UUID
conversation_idstring会话 UUID(请求未带 conversation_id 时自动创建)
user_message_idstring已落库的用户消息 UUID
statusstring入队时的运行状态(见下方状态取值)
stream_urlstring该运行 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_idstring是来自 run_status 等待事件的待处理工具调用 ID
answersobject否ID 键控的答案映射;每个值为所选选项或自定义字符串
skippedboolean否显式跳过所有问题(发送 { "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_idstring是Agent UUID
message_idstring是要重新生成的消息 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}/versions

200 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
参数类型必填默认值说明
pageinteger否1页码
page_sizeinteger否20每页条数(最多 100)
team_idstring否-按团队筛选
agent_idstring否-按 Agent ID 筛选
user_idstring否-按用户筛选(仅管理员/仪表盘访问)
searchstring否-按会话标题模糊匹配(不含消息正文)
untitled_onlyboolean否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-456

ids 是必填的重复查询参数(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。

错误码

代码消息说明
6200Agent not foundAgent 不存在
6210Conversation not found会话不存在
6211Message not found消息不存在
4000Run not found持久运行不存在,或不属于路径中的 Agent
1004Access denied运行所属会话属于其他用户
3000Permission denied权限不足
1001Validation 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);

相关文档

这篇文章对你有帮助吗?

本页目录