消息与对话
消息是用户与 AI 交互的载体。用户发送消息,AI 流式返回回复,支持 Markdown 渲染、代码高亮、思考过程展示、工具调用卡片——整个过程实时可见。
| 类型 | 说明 | 渲染方式 |
|---|---|---|
| 💬 用户消息 | 用户输入的内容 | 纯文本 |
| 📝 AI 回复 | AI 生成的文本 | Markdown + 代码高亮 |
| 🧠 思考过程 | AI 的推理过程 | 可折叠,Markdown 渲染 |
| ⚙️ 工具调用 | AI 请求执行的工具 | 输入/输出卡片 |
| 📄 压缩摘要 | 上下文压缩后的摘要(summary) | Markdown 渲染 |
| 📃 纯文本 | 未格式化的文本内容(text) | 纯文本 |
| 🔧 工具消息 | 独立的工具角色消息(tool role) | 输入/输出卡片 |
| 📩 用户消息 | 用户输入的内容,含场景注入(user_message) | 纯文本 + 场景标签 |
| 📜 系统提示词 | 持久化系统级指令(prompt) | 不直接渲染 |
| ℹ️ 系统消息 | 系统通知 | 纯文本 |
MessageRole 共 4 种:
user、assistant、system、toolContentType 共 9 种:text、markdown、summary、thinking、toolcall_input、toolcall_output、user_message、error、prompt
消息发送流程
Section titled “消息发送流程”消息采用本地优先策略:先存本地立即显示,后台异步同步。用户发消息后零等待即可看到消息出现在界面上。
发送失败处理
Section titled “发送失败处理”| 同步状态 | 用户看到的行为 |
|---|---|
pending | 消息显示发送中动画 |
synced | 消息正常显示 |
failed | 消息显示失败标记 + 🔄 重试按钮 |
💡 重试使用相同的
client_id,服务端幂等去重,不会产生重复消息。
Turn 状态机
Section titled “Turn 状态机”每次 AI 处理构成一个 Turn,它有明确的生命周期:
| 状态 | 含义 | 用户看到的行为 |
|---|---|---|
Pending | 等待执行 | 消息显示”处理中” |
Running | 正在执行 | AI 流式输出,工具卡片闪烁 |
Interrupted | 等待工具执行 | 工具卡片显示”执行中” |
Completed | 正常完成 | AI 回复完整显示 |
Failed | 执行失败 | 错误提示 |
Cancelled | 用户取消 | 已停止标记 |
Merged | 合并到其他轮次 | 不单独展示 |
AI 的回复逐字流式到达,用户无需等待完整回复:
流式消息通过 双频道 传输:
| 频道 | 用途 | 特性 |
|---|---|---|
| Topic 频道 | 首条 chunk + 最终完整消息 | 持久化,支持离线恢复 |
| Live 频道 | 中间 chunk | 非持久化,低延迟,可容忍丢失 |
💡 最终完整消息通过 Topic 频道推送,即使中间 chunk 丢失,最终也能收到完整内容。
停止 Turn
Section titled “停止 Turn”用户可随时停止正在执行的 Turn:
AI Thinking 展示
Section titled “AI Thinking 展示”AI 的推理过程默认折叠,用户可选择展开查看:
| 特性 | 说明 |
|---|---|
| 默认折叠 | 节省界面空间 |
| 点击展开 | 查看完整推理过程 |
| 流式动画 | 生成时有脉冲动画效果 |
| Markdown 渲染 | 支持格式化显示 |
工具调用卡片
Section titled “工具调用卡片”每次 RTC 工具调用以卡片形式展示,包含输入和输出两部分:
| 特性 | 说明 |
|---|---|
| 分区展示 | 输入参数和输出结果独立展示 |
| JSON 格式化 | 参数和结果自动美化 |
| 状态指示 | 运行中(🟠 橙色脉冲)/ 完成(🟢 绿色) |
| 复制按钮 | 一键复制输入/输出内容 |

| 特性 | 说明 |
|---|---|
| 📊 排序 | 按发送时间升序(最早的在上) |
| 📑 分页 | 游标分页,从服务端加载历史消息 |
| 📜 自动滚动 | 新消息到达时自动滚动到底部 |
| 🔔 离开提示 | 用户滚动离开底部时显示”↓ 新消息”按钮 |
| 场景 | 处理方式 |
|---|---|
| 发送失败 | 标记 failed,显示重试按钮 |
| 幂等保证 | 使用 client_id 去重,重试不产生重复消息 |
| RTC 失败 | 指数退避重试(1s → 2s → 4s → … → 30s 封顶) |
user_message 内容类型
Section titled “user_message 内容类型”user_message 是第 7 种 ContentType,用于支持 场景注入——在用户消息中嵌入结构化上下文,服务端将其解析后以系统提示词的形式注入 LLM。
{ "type": "user_message", "data": { "text": "请帮我创建一个任务", "scenarios": [ { "filepath": "/scenarios/create-task.md", "title": "Create and Complete a Task", "file_content": "# Create Task\n\n..." } ], "files": [] }}| 字段 | 类型 | 说明 |
|---|---|---|
text | string | 消息文本内容 |
scenarios | ScenarioRef[] | 场景列表(可选),包含完整文件内容 |
files | FileAttachment[] | 文件附件列表(可选) |
ScenarioRef 结构
Section titled “ScenarioRef 结构”| 字段 | 类型 | 说明 |
|---|---|---|
filepath | string | 场景文件路径 |
title | string | 场景标题 |
file_content | string | 场景文件完整内容(Markdown 格式) |
FileAttachment 结构
Section titled “FileAttachment 结构”| 字段 | 类型 | 说明 |
|---|---|---|
fileid | string | 文件唯一标识(内容标识符) |
mimetype | string | MIME 类型(如 image/png、application/pdf) |
extra | object | 扩展字段(如 name、size) |
File ID 格式规范:
File ID 是文件内容的唯一标识符,格式为 {md5}.{ext}:
{md5}:32 个十六进制字符(小写a-f或数字0-9)的文件内容 MD5 哈希值{ext}:1-10 个字母数字字符的文件扩展名(如txt、jpg、pdf)
示例:
- ✅ 正确:
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.txt - ✅ 正确:
b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7.jpg - ❌ 错误:
user-550e8400.../a1b2c3d4...txt(不应包含用户前缀) - ❌ 错误:
myfile.txt(MD5 格式错误)
💡 File ID vs File Key:File ID 是客户端使用的内容标识符(
{md5}.{ext}),服务端在存储时会构造完整的 S3 Key:user-{userId}/{fileid}。客户端只需传递 File ID,服务端会自动添加用户前缀进行验证和存储。
💡 注入机制:服务端从
UserMessageContent.Scenarios提取场景,以<scenarios>XML 标签注入系统消息。最终消息顺序为:[system] Attachments→[system] Scenarios→[system] Command prompts→[conversation history]。
用户可以在消息中附加图片和文本文件,Agent 能够识别图片内容(视觉理解)和读取文本内容,从而基于附件信息进行推理和回答。
| 操作方式 | 说明 |
|---|---|
| 附件按钮 | 点击输入区域工具栏的附件图标,打开文件选择对话框(接受 image/*、text/*) |
| 粘贴上传 | 使用 Ctrl+V / Cmd+V 粘贴剪贴板中的图片或文件 |
| 文件预览 | 点击已附加的文件缩略图,打开全屏预览模态框(图片支持缩放查看,文本文件显示内容) |
| 上传重试 | 文件上传失败时,点击重试图标手动重新上传(文件保留在内存中,无需重新选择) |
上传流程:文件先在本地缓存(生成 File ID),立即显示缩略图预览,然后后台上传至对象存储。上传失败时会显示错误状态和重试按钮,用户可手动重试或继续发送消息(允许带失败附件发送)。
支持的文件类型
Section titled “支持的文件类型”| 类别 | MIME 类型 | 最大大小 | 处理方式 |
|---|---|---|---|
| 图片(支持) | JPEG、PNG、BMP、TIFF | 原始 20MB / base64 5MB | 自动缩放至 2000x2000,多级 JPEG 压缩 |
| 图片(不支持) | WebP、GIF | - | 当前不支持,请转换为 JPEG 或 PNG |
| 文本 | text/* | 256KB | UTF-8 校验,超长截断 |
图片处理流程
Section titled “图片处理流程”- 读取:从对象存储读取原始数据(限制 20MB)
- 检测:通过 magic bytes 检测真实 MIME 类型
- 解码:自动应用 EXIF 方向校正
- 快速路径:若已满足尺寸要求,直接返回
- 缩放:使用 Lanczos 算法缩放至 2000×2000 边界框内
- 压缩:依次尝试 JPEG 质量 80→60→40→20,直到 base64 编码后 ≤ 5MB
- 兜底:若仍超限,缩小至 400×400 并以最低质量输出
- 注入:以 base64 格式嵌入 LLM 请求的
imagecontent part
文本处理流程
Section titled “文本处理流程”- 读取:从对象存储读取文本数据(限制 256KB)
- 校验:验证文件内容为合法 UTF-8 编码
- 截断:若超过 256KB,在 UTF-8 字符边界处安全截断,并附加截断提示
- 包裹:使用 XML 标签包裹:
<file_content name="文件名" type="MIME 类型">内容</file_content> - 追加:将包裹后的文本追加到用户消息的 Content 字段
| 条件 | 说明 |
|---|---|
| 所有文件上传完成 | 存在上传中(loading)或失败(error)的文件时,发送按钮禁用 |
| 上传失败处理 | 失败的文件可重试,或删除后重新上传 |
💡 文件附件在消息发送时随
user_message一同提交,服务端并行加载所有文件以提升多文件场景的响应速度。当用户连续发送多条带图片的消息时,服务端会将相邻的同角色消息的MultiContent(图片内容)合并,确保所有图片都被 LLM 识别。
Token 用量显示
Section titled “Token 用量显示”前端通过 rtc-token-usage Web Component 在输入区域工具栏实时展示 Token 消耗和成本信息。
| 显示项 | 数据来源 | 说明 |
|---|---|---|
| 圆环进度 | compression_progress | 当前上下文占压缩阈值的百分比 |
| 总 Token | total_tokens | 累计消耗的总 Token 数 |
| 总成本 | total_cost_usd | 累计成本(美元) |
| 输入/输出 | total_input_tokens / total_output_tokens | 分类 Token 统计 |
| 缓存命中率 | cached_read / input | 缓存读取占总输入的比例(上限 99%) |
| 预估下轮 | estimated_next_round_tokens | 基于 EWMA 的下一轮 Token 预估 |
| 压缩倒计时 | rounds_until_compression | 距离下次自动压缩的轮次数 |
协议字段映射
Section titled “协议字段映射”后端推送的 session.updated 事件中的 snake_case 字段会映射为前端 camelCase 属性:
| 协议字段(snake_case) | 前端属性(camelCase) | 说明 |
|---|---|---|
current_context_tokens | currentContextTokens | 当前上下文 Token 数 |
estimated_next_round_tokens | estimatedNextRoundTokens | 预估下轮 Token 数(圆环进度分子) |
compression_threshold | compressionThreshold | 压缩触发阈值(圆环进度分母) |
compression_progress | compressionProgress | 压缩进度(0-100) |
rounds_until_compression | roundsUntilCompression | 距压缩轮次数 |
total_tokens | totalTokens | 累计总 Token |
total_cost_usd | totalCostUsd | 累计成本 |
圆环进度与颜色阈值
Section titled “圆环进度与颜色阈值”圆环进度计算公式:estimatedNext / compressionThreshold * 100%
| 进度范围 | 颜色 | 含义 |
|---|---|---|
| < 50% | 🔵 蓝色 | 上下文充裕 |
| 50% - 70% | 🟡 黄色 | 接近压缩阈值 |
| > 70% | 🔴 红色 | 即将触发压缩 |
💡 当
roundsUntilCompression在 0-3 轮时,tooltip 底部显示 “X 轮后压缩 (Y%)” 提示;小于等于 1 轮时升级为警告色。
- 会话管理 — 了解消息所在的会话容器
- Remote Tool Calling — 了解工具调用卡片的背后机制
- 实时通信 — 了解流式消息的双频道架构