Appearance
流式聊天
基本信息
| 项目 | 说明 |
|---|---|
| 接口路径 | POST /v1/chat/stream |
| 响应类型 | text/event-stream(SSE 流) |
| 认证方式 | API Key + 请求签名(认证说明) |
请求体
json
{
"agentId": "agent-uuid",
"conversationId": "conv-uuid",
"text": "你好,请介绍一下你自己",
"language": "zh",
"metadata": {}
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
agentId | string | ✅ | 智能体 ID |
conversationId | string | ✅ | 会话 ID,由 /v1/chat/conversation 接口创建获取 |
text | string | ✅ | 用户发送的消息内容 |
language | string | ✅ | 语言代码,如 zh、en |
metadata | object | ❌ | 扩展字段,可传空对象 {} |
签名示例(字段字典序:agentId、conversationId、language、text):
待签名字符串 = "agentId=agent-uuid&conversationId=conv-uuid&language=zh&text=你好" + apiSecret
X-Signature = sha256(待签名字符串)响应格式(SSE 流)
响应为标准 SSE 格式,每个事件以 data: 开头,事件间以空行分隔。
正常数据帧
data:{"content":"你","id":"dify-message-id"}
data:{"content":"好","id":"dify-message-id"}| 字段 | 类型 | 说明 |
|---|---|---|
content | string | 当前帧的文本片段(增量) |
id | string | 消息 ID,同一条回复各帧一致 |
结束标记
data:[DONE]收到 [DONE] 后紧跟消息保存事件:
data:{"type":"message_saved","messageId":"msg-uuid"}INFO
message_saved 事件中的 messageId 是调用语音播报接口时的必要参数。
错误帧
data:{"error":"Agent config is incomplete or not found, AgentId: xxx"}完整响应示例
data:{"content":"你","id":"abc123"}
data:{"content":"好!有什么可以帮助你的吗?","id":"abc123"}
data:[DONE]
data:{"type":"message_saved","messageId":"msg-uuid-xxx"}错误响应
| HTTP 状态码 | 说明 |
|---|---|
401 | 认证失败(在 SSE 流建立前返回) |
SSE 流建立后的业务错误帧:
| error 内容 | 说明 |
|---|---|
Invalid API key | API Key 无效或已禁用 |
Too many requests, please try again later | 触发频率限制 |
API key usage limit reached | 达到总调用次数上限 |
Agent config is incomplete or not found | 智能体配置缺失 |
客户端示例
javascript
async function chat(apiKey, apiSecret, userId, agentId, conversationId, text) {
const body = { agentId, conversationId, text, language: 'zh' }
const headers = await buildAuthHeaders(apiKey, apiSecret, userId, body)
headers['Accept'] = 'text/event-stream'
const response = await fetch('/v1/chat/stream', {
method: 'POST',
headers,
body: JSON.stringify(body),
})
const reader = response.body.getReader()
const decoder = new TextDecoder()
let fullText = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
const lines = decoder.decode(value).split('\n')
for (const line of lines) {
let data = line.trim()
if (data.startsWith('data:')) data = data.slice(5).trim()
if (!data || data === '[DONE]') continue
try {
const parsed = JSON.parse(data)
if (parsed.error) { console.error('服务端错误:', parsed.error); return }
if (parsed.content) { fullText += parsed.content }
if (parsed.type === 'message_saved') {
console.log('消息已保存,messageId:', parsed.messageId)
// 可在此触发 TTS
}
} catch (_) { /* 跳过非 JSON 行 */ }
}
}
}