curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageStart",
"data": "开始AI回复..."
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageContent",
"data": "你好!我可以为你做什么?"
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageEnd",
"data": ""
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "custom_event_001",
"channel_id": "user_123",
"channel_type": 1,
"from_uid": "system",
"event": {
"type": "user_status_update",
"timestamp": 1640995200000,
"data": "{\"status\": \"online\", \"last_seen\": 1640995200000}"
}
}'
// 流式文本消息示例
const streamId = `stream_${Date.now()}`;
// 1. 开始流
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageStart',
data: '开始AI回复...'
}
})
});
// 2. 发送内容
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageContent',
data: '你好!我可以为你做什么?'
}
})
});
// 3. 结束流
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageEnd',
data: ''
}
})
});
import requests
import time
# 流式文本消息示例
stream_id = f"stream_{int(time.time() * 1000)}"
base_url = "http://localhost:5001/event"
# 1. 开始流
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageStart",
"data": "开始AI回复..."
}
})
# 2. 发送内容
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageContent",
"data": "你好!我可以为你做什么?"
}
})
# 3. 结束流
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageEnd",
"data": ""
}
})
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Event struct {
Type string `json:"type"`
Data string `json:"data"`
Timestamp int64 `json:"timestamp,omitempty"`
}
type EventRequest struct {
ClientMsgNo string `json:"client_msg_no"`
ChannelID string `json:"channel_id"`
ChannelType int `json:"channel_type"`
FromUID string `json:"from_uid"`
Event Event `json:"event"`
}
func sendEvent(req EventRequest) error {
jsonData, _ := json.Marshal(req)
resp, err := http.Post(
"http://localhost:5001/event",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}
func main() {
streamID := fmt.Sprintf("stream_%d", time.Now().UnixMilli())
// 1. 开始流
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageStart",
Data: "开始AI回复...",
},
})
// 2. 发送内容
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageContent",
Data: "你好!我可以为你做什么?",
},
})
// 3. 结束流
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageEnd",
Data: "",
},
})
}
{
"status": "ok"
}
事件管理
发送事件
发送各种类型的事件到频道,包括流式文本消息和自定义事件
POST
/
event
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageStart",
"data": "开始AI回复..."
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageContent",
"data": "你好!我可以为你做什么?"
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageEnd",
"data": ""
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "custom_event_001",
"channel_id": "user_123",
"channel_type": 1,
"from_uid": "system",
"event": {
"type": "user_status_update",
"timestamp": 1640995200000,
"data": "{\"status\": \"online\", \"last_seen\": 1640995200000}"
}
}'
// 流式文本消息示例
const streamId = `stream_${Date.now()}`;
// 1. 开始流
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageStart',
data: '开始AI回复...'
}
})
});
// 2. 发送内容
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageContent',
data: '你好!我可以为你做什么?'
}
})
});
// 3. 结束流
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageEnd',
data: ''
}
})
});
import requests
import time
# 流式文本消息示例
stream_id = f"stream_{int(time.time() * 1000)}"
base_url = "http://localhost:5001/event"
# 1. 开始流
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageStart",
"data": "开始AI回复..."
}
})
# 2. 发送内容
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageContent",
"data": "你好!我可以为你做什么?"
}
})
# 3. 结束流
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageEnd",
"data": ""
}
})
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Event struct {
Type string `json:"type"`
Data string `json:"data"`
Timestamp int64 `json:"timestamp,omitempty"`
}
type EventRequest struct {
ClientMsgNo string `json:"client_msg_no"`
ChannelID string `json:"channel_id"`
ChannelType int `json:"channel_type"`
FromUID string `json:"from_uid"`
Event Event `json:"event"`
}
func sendEvent(req EventRequest) error {
jsonData, _ := json.Marshal(req)
resp, err := http.Post(
"http://localhost:5001/event",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}
func main() {
streamID := fmt.Sprintf("stream_%d", time.Now().UnixMilli())
// 1. 开始流
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageStart",
Data: "开始AI回复...",
},
})
// 2. 发送内容
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageContent",
Data: "你好!我可以为你做什么?",
},
})
// 3. 结束流
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageEnd",
Data: "",
},
})
}
{
"status": "ok"
}
概述
发送各种类型的事件到频道,包括流式文本消息和自定义事件。支持AG-UI协议事件,用于实时流式通信。查询参数
强制结束频道中现有的流,然后开始新流
0- 不强制结束1- 强制结束现有流
请求体
必传参数
客户端消息编号,必须唯一且不重复。用于标识和跟踪消息/流。对于流式消息,同一流中的所有事件应使用相同的client_msg_no。建议使用UUID格式。
目标频道ID,事件将发送到此频道。对于个人频道,这应该是目标用户ID。对于群组频道,这应该是群组ID。
频道类型
1- 个人频道2- 群组频道
事件对象
显示 event 字段
显示 event 字段
事件类型,支持AG-UI协议事件和自定义事件AG-UI协议事件:
___TextMessageStart- 开始流式文本消息会话___TextMessageContent- 发送流式内容块___TextMessageEnd- 结束流式文本消息会话___ToolCallStart- 开始工具/函数调用事件___ToolCallArgs- 发送工具调用参数___ToolCallEnd- 结束工具调用事件___ToolCallResult- 返回工具执行结果
___ 开头的字符串都被视为自定义事件类型事件ID(可选,某些事件类型会自动生成)
事件时间戳(可选,Unix时间戳,毫秒)
事件数据内容。格式取决于事件类型:文本消息事件:
___TextMessageStart- 初始消息内容或元数据___TextMessageContent- 流式文本块___TextMessageEnd- 最终内容或完成标记
___ToolCallStart- 工具名称或元数据___ToolCallArgs- 函数参数的JSON字符串___ToolCallEnd- 完成状态___ToolCallResult- 执行结果的JSON字符串
可选参数
发送者用户ID。如果未提供或为空,默认为系统UID。用于标识发送事件的用户。
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageStart",
"data": "开始AI回复..."
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageContent",
"data": "你好!我可以为你做什么?"
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "msg_001_stream_start",
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageEnd",
"data": ""
}
}'
curl -X POST "http://localhost:5001/event" \
-H "Content-Type: application/json" \
-d '{
"client_msg_no": "custom_event_001",
"channel_id": "user_123",
"channel_type": 1,
"from_uid": "system",
"event": {
"type": "user_status_update",
"timestamp": 1640995200000,
"data": "{\"status\": \"online\", \"last_seen\": 1640995200000}"
}
}'
// 流式文本消息示例
const streamId = `stream_${Date.now()}`;
// 1. 开始流
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageStart',
data: '开始AI回复...'
}
})
});
// 2. 发送内容
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageContent',
data: '你好!我可以为你做什么?'
}
})
});
// 3. 结束流
await fetch('http://localhost:5001/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_msg_no: streamId,
channel_id: 'group_ai_chat',
channel_type: 2,
from_uid: 'ai_assistant',
event: {
type: '___TextMessageEnd',
data: ''
}
})
});
import requests
import time
# 流式文本消息示例
stream_id = f"stream_{int(time.time() * 1000)}"
base_url = "http://localhost:5001/event"
# 1. 开始流
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageStart",
"data": "开始AI回复..."
}
})
# 2. 发送内容
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageContent",
"data": "你好!我可以为你做什么?"
}
})
# 3. 结束流
requests.post(base_url, json={
"client_msg_no": stream_id,
"channel_id": "group_ai_chat",
"channel_type": 2,
"from_uid": "ai_assistant",
"event": {
"type": "___TextMessageEnd",
"data": ""
}
})
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Event struct {
Type string `json:"type"`
Data string `json:"data"`
Timestamp int64 `json:"timestamp,omitempty"`
}
type EventRequest struct {
ClientMsgNo string `json:"client_msg_no"`
ChannelID string `json:"channel_id"`
ChannelType int `json:"channel_type"`
FromUID string `json:"from_uid"`
Event Event `json:"event"`
}
func sendEvent(req EventRequest) error {
jsonData, _ := json.Marshal(req)
resp, err := http.Post(
"http://localhost:5001/event",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}
func main() {
streamID := fmt.Sprintf("stream_%d", time.Now().UnixMilli())
// 1. 开始流
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageStart",
Data: "开始AI回复...",
},
})
// 2. 发送内容
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageContent",
Data: "你好!我可以为你做什么?",
},
})
// 3. 结束流
sendEvent(EventRequest{
ClientMsgNo: streamID,
ChannelID: "group_ai_chat",
ChannelType: 2,
FromUID: "ai_assistant",
Event: Event{
Type: "___TextMessageEnd",
Data: "",
},
})
}
{
"status": "ok"
}
响应字段
操作状态,成功时返回
"ok"状态码
| 状态码 | 说明 |
|---|---|
| 200 | 事件发送成功 |
| 400 | 请求参数错误或事件数据无效 |
| 500 | 服务器内部错误 |
流式消息机制
流式消息流程
- 开始流:发送
___TextMessageStart事件启动流 - 发送内容:发送多个
___TextMessageContent事件传输消息块 - 结束流:发送
___TextMessageEnd事件关闭流
重要注意事项
- 同一流中的所有事件必须使用相同的
client_msg_no - 除非使用
force=1,否则每个频道只能有一个活跃流 - 对于个人频道,系统会自动处理虚假频道ID生成
- 事件会自动路由到适当的集群节点
事件类型详解
AG-UI协议事件
AG-UI协议事件用于实时流式通信,特别适用于AI应用:| 事件类型 | 用途 | 数据格式 |
|---|---|---|
___TextMessageStart | 启动流式文本消息会话 | 初始内容或元数据 |
___TextMessageContent | 发送内容块 | 文本块内容 |
___TextMessageEnd | 终止流式文本消息会话 | 完成标记 |
___ToolCallStart | 开始工具调用事件 | 工具名称或元数据 |
___ToolCallArgs | 发送工具调用参数 | JSON格式的参数 |
___ToolCallEnd | 结束工具调用事件 | 完成状态 |
___ToolCallResult | 返回工具执行结果 | JSON格式的结果 |
自定义事件
任何不以___ 开头的事件类型都被视为自定义事件,可用于:
- 用户状态更新
- 系统通知
- 业务逻辑事件
- 应用特定的交互
使用场景
AI聊天机器人
# 模拟AI打字效果
curl -X POST "/event" -d '{
"client_msg_no": "ai_response_001",
"channel_id": "user_123",
"channel_type": 1,
"from_uid": "ai_bot",
"event": {
"type": "___TextMessageStart",
"data": "{\"type\":1,\"content\":\"思考中...\"}"
}
}'
# 逐步发送回复内容
curl -X POST "/event" -d '{
"client_msg_no": "ai_response_001",
"channel_id": "user_123",
"channel_type": 1,
"from_uid": "ai_bot",
"event": {
"type": "___TextMessageContent",
"data": "根据您的问题,我建议..."
}
}'
实时协作
# 文档编辑状态
curl -X POST "/event" -d '{
"client_msg_no": "doc_edit_001",
"channel_id": "doc_room_456",
"channel_type": 2,
"from_uid": "user_789",
"event": {
"type": "document_editing",
"data": "{\"action\": \"start_edit\", \"section\": \"paragraph_1\"}"
}
}'
系统通知
# 用户上线通知
curl -X POST "/event" -d '{
"client_msg_no": "status_update_001",
"channel_id": "group_general",
"channel_type": 2,
"from_uid": "system",
"event": {
"type": "user_online",
"timestamp": 1640995200000,
"data": "{\"user_id\": \"user_123\", \"status\": \"online\"}"
}
}'
最佳实践
- 唯一标识:使用UUID格式的
client_msg_no确保唯一性 - 流管理:及时结束不再使用的流,避免资源浪费
- 错误处理:处理流冲突和发送失败的情况
- 权限验证:确保发送者有频道的发送权限
- 数据格式:对于复杂数据使用JSON格式的字符串
- 性能优化:合理控制流式消息的发送频率
错误处理
常见错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 事件类型不能为空 | 未提供event.type | 确保提供有效的事件类型 |
| 频道中已有流正在运行 | 尝试在有活跃流的频道开始新流 | 使用 force=1 或等待现有流结束 |
| 流不存在 | 尝试向不存在的流发送内容 | 检查流是否已正确创建 |
| 流已关闭 | 向已关闭的流发送内容 | 重新开始新的流 |
重试机制
对于临时性错误,建议实现指数退避重试机制:async function sendEventWithRetry(eventData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch('/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(eventData)
});
if (response.ok) return await response.json();
if (response.status >= 400 && response.status < 500) {
// 客户端错误,不重试
throw new Error(`Client error: ${response.status}`);
}
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}
⌘I

