Appearance
发送消息
ChatFlow 对话接口。ChatFlow 将用户输入、会话上下文和业务变量传入应用绑定的工作流,按画布节点执行,并把回复节点或结束节点的输出作为对话回复。
接口支持 SSE 流式响应和阻塞式响应。工作流执行到问答节点或输入节点时,还可以通过 HITL 中断等待用户响应,再从中断位置恢复执行。
- 接口路径:
POST /v1/openapi/chat/send-messages
INFO
此接口与 Agent、AgentLite 和 TextCompletion 共用同一路径,由 app_id 对应的应用类型分发到 ChatFlow 执行链路。
ChatFlow 能力范围
| 能力 | ChatFlow |
|---|---|
多轮对话(conversation_id) | ✓ |
业务变量输入(input) | ✓ |
| 图片 / 视频输入 | ✓ |
| 工作流画布与节点编排 | ✓ |
| 问答 / 输入节点人工介入(HITL) | ✓ |
| SSE 断连重连 | 取决于应用是否开启重连 |
| 应用级模型、提示词与工具配置 | — |
| 沙盒、Skill、Sub-agent | — |
ChatFlow 的模型、提示词、知识库和外部调用能力均配置在工作流节点中,不使用应用级 select_model_id。工作流节点由画布按固定拓扑调度,不会像 Agent 一样自主选择应用工具。
请求头
| 参数名 | 必填 | 说明 |
|---|---|---|
| Content-Type | 是 | application/json |
| Authorization | 是 | 鉴权凭证,格式 Bearer sk_xxx |
发起对话
action 为空或为 chat 时发起一轮对话。
json
{
"app_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"user_id": "u_12345",
"username": "张三",
"conversation_id": "",
"query": "我想预约明天下午的门诊",
"files": [
{
"type": "image",
"url": "https://example.com/report.png"
}
],
"input": {
"department": "心内科"
},
"response_mode": "streaming",
"with_tts": false,
"tts_format": "pcm"
}| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_id | string(uuid) | 是 | ChatFlow 应用 ID |
| user_id | string | 是 | 业务方用户标识;同一应用内用于隔离会话与工作流变量 |
| username | string | 否 | 用户名称,用于会话记录和工作流运行时变量 |
| conversation_id | string(uuid) | 否 | 会话 ID;为空时创建新会话,后续传回可续接同一会话 |
| query | string | 是 | 本轮用户输入 |
| files | array | 否 | 附件列表,每项包含 type 和公网可访问的完整 url;type 支持 image、video |
| input | object | 否 | 业务变量,key 使用 ChatFlow 开始节点的变量名称,value 须符合对应数据结构 |
| response_mode | string | 否 | streaming(默认)或 blocking |
| with_tts | bool | 否 | 是否开启语音播报,仅 streaming 生效,默认 false |
| tts_format | string | 否 | 语音格式:pcm(默认)、mp3、wav |
变量输入
ChatFlow 开始节点与 Agent、Workflow 使用同一套变量配置规则。input 只提交本次运行值,不提交显示名称、控件或默认值状态;完整定义见变量协议。
运行时内置变量
服务端会把请求和会话信息转换为下列 ChatFlow 运行时变量。调用方不需要放入 input,同名业务变量也不会覆盖这些值。
| 变量 | 说明 |
|---|---|
USER_INPUT / sys.query | 本轮 query |
APP_ID / WORKSPACE_ID | 当前应用和工作空间 ID |
USER_ID / USERNAME / USER_NAME | 当前用户标识和名称 |
CONVERSATION_ID / CONVERSATION_NAME | 当前会话 ID 和名称 |
INPUT_FILES | 附件对象数组,每项包含 type、url |
INPUT_FILE_URLS / INPUT_FILE | 全部附件 URL / 第一个附件 URL |
INPUT_IMAGES / INPUT_IMAGE | 全部图片 URL / 第一张图片 URL |
INPUT_VIDEOS / INPUT_VIDEO | 全部视频 URL / 第一个视频 URL |
ChatFlow 会加载当前会话的候选历史消息,各 LLM 节点再按节点自身配置的对话历史轮数消费。
阻塞模式响应
当 response_mode=blocking 时,服务端等待 ChatFlow 执行完成后一次性返回 JSON。
json
{
"code": 200,
"message": "success",
"data": {
"conversation_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"message_id": "01965de1-1920-7fe4-aa38-2e6836c46f23",
"task_id": "01965de1-1920-7fe4-aa38-2e6836c46f24",
"status": "completed",
"duration": 1500,
"output": {
"content": "已为您进入预约信息确认流程。",
"finish_reason": "completed",
"tokens": 0
}
}
}TIP
如果画布包含问答节点或输入节点,建议使用 streaming,以便客户端接收 interrupt 事件并取得恢复执行所需的信息。
流式模式响应
当 response_mode=streaming 或未传时,接口返回 SSE 事件流。
SSE 响应头
text
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no事件格式
text
id: 42
event: node.started
data: {"event":"node.started","id":"...","conversation_id":"...","message_id":"...","task_id":"...","seq":42,"timestamp":"2026-07-23T10:00:00+08:00","data":{}}除 ping 外,事件对象包含以下公共字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| event | string | 事件类型 |
| id | string(uuid) | 事件唯一 ID |
| conversation_id | string(uuid) | 会话 ID |
| message_id | string(uuid) | 消息 ID |
| task_id | string(uuid) | 任务 ID,可用于停止或重连 |
| seq | uint64 | 事件序号,同时写入 SSE id 行 |
| timestamp | string | RFC 3339 格式的事件时间 |
| data | object | 当前事件的数据 |
执行生命周期事件
ChatFlow 会发送通用执行生命周期事件:
| 事件 | 说明 |
|---|---|
start | 对话执行开始;新会话的 ID 可从事件中取得 |
completed | 对话执行完成,data.content 为完整回复 |
failed | 执行失败,data.error 为错误描述 |
cancelled | 任务被停止或工作流被取消 |
token.usage | 当前累计的 Token 用量与耗时 |
ping | 收到 start 后每 5 秒发送的心跳 |
json
{
"event": "start",
"id": "01965de1-1920-7fe4-aa38-2e6836c46f25",
"conversation_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"message_id": "01965de1-1920-7fe4-aa38-2e6836c46f23",
"task_id": "01965de1-1920-7fe4-aa38-2e6836c46f24",
"seq": 1,
"timestamp": "2026-07-23T10:00:00+08:00",
"data": {
"conversation_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"app_id": "01965de1-1920-7fe4-aa38-2e6836c46f22"
}
}工作流事件
workflow.started
工作流开始执行。
json
{
"event": "workflow.started",
"data": {
"workflow_run_id": "01965de1-1920-7fe4-aa38-2e6836c46f30"
}
}workflow.finished
工作流成功、失败或取消。
json
{
"event": "workflow.finished",
"data": {
"workflow_run_id": "01965de1-1920-7fe4-aa38-2e6836c46f30",
"status": "succeeded",
"elapsed_time": 1.26,
"total_tokens": 168,
"total_steps": 4
}
}| 字段 | 类型 | 说明 |
|---|---|---|
| workflow_run_id | string(uuid) | 工作流执行 ID |
| status | string | succeeded、failed 或 cancelled |
| outputs | object | 工作流输出(如有) |
| error | string | 失败原因(如有) |
| elapsed_time | number | 执行耗时,单位秒 |
| total_tokens | int | 工作流累计 Token 数 |
| total_steps | int | 已开始执行的节点数 |
node.started
节点开始执行。
json
{
"event": "node.started",
"data": {
"node_id": "llm_1",
"node_type": "LLM",
"title": "生成预约回复",
"inputs": {
"department": "心内科"
}
}
}node.finished
节点执行结束。
json
{
"event": "node.finished",
"data": {
"node_id": "llm_1",
"node_type": "LLM",
"title": "生成预约回复",
"status": "succeeded",
"outputs": {
"output": "已为您进入预约信息确认流程。"
},
"elapsed_time": 0.86,
"input_tokens": 120,
"output_tokens": 48
}
}| 字段 | 类型 | 说明 |
|---|---|---|
| node_id | string | 节点 ID |
| node_type | string | 节点类型 |
| title | string | 节点标题 |
| status | string | succeeded 或 failed |
| outputs | object | 节点输出 |
| error | string | 节点错误信息(如有) |
| elapsed_time | number | 节点耗时,单位秒 |
| input_tokens | int | 节点输入 Token 数 |
| output_tokens | int | 节点输出 Token 数 |
每个节点还会同步产生 tool.start 和 tool.result,便于使用统一的消息明细组件展示节点入参、结果、耗时和 Token 用量。节点事件用于观察工作流生命周期,工具事件用于统一展示执行明细。
回复事件
只有回复节点和结束节点会产生面向用户的 chunk。工作流内部节点的中间输出不会直接作为聊天内容返回。
json
{
"event": "chunk",
"data": {
"content": "已为您进入预约信息确认流程。"
}
}执行完成前还会发送 token.usage:
json
{
"event": "token.usage",
"data": {
"usage": {
"prompt_tokens": 120,
"completion_tokens": 48,
"total_tokens": 168,
"first_token_duration": 0,
"duration": 1260
}
}
}人工介入与恢复
当问答节点或输入节点等待用户操作时,当前 SSE 流发送 interrupt 后结束。
json
{
"event": "interrupt",
"data": {
"checkpoint_id": "01965de1-1920-7fe4-aa38-2e6836c46f30",
"interrupts": [
{
"interrupt_id": "01965de1-1920-7fe4-aa38-2e6836c46f31",
"payload": {
"type": "choice",
"title": "选择就诊时段",
"description": "请选择一个时段",
"options": [
{"value": "14:00", "label": "14:00"},
{"value": "15:00", "label": "15:00"}
],
"required": true
}
}
]
}
}payload.type 主要有:
| 类型 | 来源节点 | 响应格式 |
|---|---|---|
text_input | 普通问答节点 | {"text": "用户输入"} |
choice | 选项问答节点 | {"choice": "选项值"} |
form_input | 输入节点 | {"form_data": {"字段名": "字段值"}} |
使用事件中的 checkpoint_id 和 interrupt_id 发起恢复请求。ChatFlow 单次只恢复一个中断事件,因此 responses 只能包含一个键值对。
json
{
"app_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"user_id": "u_12345",
"conversation_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"action": "resume",
"checkpoint_id": "01965de1-1920-7fe4-aa38-2e6836c46f30",
"responses": {
"01965de1-1920-7fe4-aa38-2e6836c46f31": {
"choice": "14:00"
}
},
"response_mode": "streaming"
}恢复成功后会建立新的事件流,并从中断节点继续执行。
断连重连
应用开启重连后,客户端可以从最后收到的事件序号继续订阅,不会重新执行 ChatFlow。
json
{
"app_id": "01965de1-1920-7fe4-aa38-2e6836c46f22",
"user_id": "u_12345",
"action": "reconnect",
"task_id": "01965de1-1920-7fe4-aa38-2e6836c46f24",
"last_event_id": "42"
}推荐通过标准请求头传递游标:
text
Last-Event-ID: 42| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_id | string(uuid) | 是 | 原任务所属 ChatFlow 应用 ID |
| user_id | string | 是 | 业务方用户标识 |
| action | string | 是 | 固定为 reconnect |
| task_id | string(uuid) | 是 | 原 start 事件中的任务 ID |
| last_event_id | string | 否 | 最后收到的事件序号;请求头和 Body 同时存在时请求头优先 |
reconnect 仅支持 streaming。如果任务不存在或事件已过期,请改用消息管理查询最终结果。
典型事件顺序
普通执行:
text
start
workflow.started
node.started
tool.start
node.finished
tool.result
chunk
workflow.finished
token.usage
completed发生人工介入:
text
原事件流:start → workflow.started → node.started → tool.start → interrupt
恢复请求:action=resume
新事件流:node.finished → tool.result → ... → workflow.finished → token.usage → completed