一个智能对话代理是如何工作的
OpenClaw 的 6 个阶段:从 WhatsApp 接收的消息到代理的响应。防止幻觉、会话成本和技术选择。
Equipe OpenClaw · Time de Engenharia & Produto
A Equipe OpenClaw é formada por engenheiros, designers e especialistas em IA dedicados a construir a melhor plataforma de agentes conversacionais para negócios brasileiros. Combinamos expertise…
什么是 OpenClaw 的 AI 语音助手架构
AI 语音助手是如何工作的?本文将打开 OpenClaw 的黑盒子:从客户端发送的消息到助手回复的文本。将会很技术性。值得一读的是,如果你正在设计产品架构,想购买解决方案,或者想了解后台发生了什么。
TL;DR: 每个回合都经过 6 个阶段 — 1. 吞吐量,2. 解决上下文,3. 选择技能,4. 决定下一步行动,5. 执行带有 guard-rails,6. 持久化内存。整个循环在 Cloudflare Edge 上运行,耗时 <秒,没有固定的服务器。
为什么架构很重要
看起来很好的语音助手demo,但在生产环境中却会崩溃。通常会有 4 个问题:
- 高延迟 — 客户端等待 8 秒的回复,会导致会话死亡。
- 失控的幻觉 — 语音助手会发明价格、时间、政策等。
- 上下文丢失 — 客户端在 2 天后回复,语音助手会“忘记”所有内容。
- 高昂的成本 — 每个长会话都会填满提示,导致大量 token 支付。
这 4 个问题都是架构选择,而不是模型限制。OpenClaw 是为了避免这 4 个问题而设计的。了解它的秘密是看一个回合的循环。
回合循环 (6 个阶段)
假设客户端刚刚发送了消息 "我想在周六早上预约"。发生在 "接收" 和助手回复之间的事件是什么?
阶段 1 — 吞吐量 (边缘工人,<ms)
WhatsApp 的消息通过 Meta 的 webhook 直接到达 Cloudflare Worker 在最接近的地理位置(PoP)。在巴西,这意味着是 São Paulo 或 Rio,网络延迟 <0ms。
工人做了三件事:
- 验证 webhook 的签名 (HMAC 对 WABA 的秘密)。
- 识别租户 通过接收者的电话号码(多租户通过
to_number)。 - 标准化 payload — 音频变成转录,图像变成描述,位置变成
{lat,lng}, 文本保持不变。
阶段 1 结束时,你会得到一个 {tenant_id, conversation_id, user_message} 对象,准备好下一个阶段。
阶段 2 — 解决上下文 (D1 + KV,~80ms)
助手需要 3 个上下文片段才能决定下一步:
- 会话历史:助手需要了解会话的上下文,以便做出明智的决定。
- 用户信息:助手需要了解用户的信息,以便提供个性化的服务。
- 系统状态:助手需要了解系统的状态,以便做出合适的决定。
在阶段 2 中,助手会使用 D1 和 KV 来解决上下文。D1 是一个用于存储和管理会话历史的数据库,KV 是一个用于存储和管理用户信息和系统状态的键值对存储。
阶段 2 结束时,助手会有一个包含会话历史、用户信息和系统状态的对象,准备好下一个阶段。
阶段 3 — 选择技能 (D2,~20ms)
助手需要选择一个技能来处理用户的请求。技能是指助手可以执行的特定任务,例如回答问题、提供建议或完成任务。
在阶段 3 中,助手会使用 D2 来选择技能。D2 是一个用于存储和管理技能的数据库。
阶段 3 结束时,助手会有一个包含选择的技能的对象,准备好下一个阶段。
阶段 4 — 决定下一步行动 (D3,~10ms)
助手需要决定下一步行动。下一步行动可能包括执行技能、提供反馈或等待用户的回复。
在阶段 4 中,助手会使用 D3 来决定下一步行动。D3 是一个用于存储和管理决策的数据库。
阶段 4 结束时,助手会有一个包含决定的下一步行动的对象,准备好下一个阶段。
阶段 5 — 执行带有 guard-rails (D4,~5ms)
助手需要执行选择的技能。执行技能可能包括访问外部系统、处理数据或提供反馈。
在阶段 5 中,助手会使用 D4 来执行带有 guard-rails 的技能。D4 是一个用于存储和管理技能执行的数据库。
阶段 5 结束时,助手会有一个包含执行结果的对象,准备好下一个阶段。
阶段 6 — 持久化内存 (D5,~2ms)
助手需要持久化内存。持久化内存包括存储会话历史、用户信息和系统状态。
在阶段 6 中,助手会使用 D5 来持久化内存。D5 是一个用于存储和管理持久化数据的数据库。
阶段 6 结束时,助手会有一个包含持久化数据的对象,准备好下一个阶段。
整个循环在 Cloudflare Edge 上运行,耗时 <秒,没有固定的服务器。
- 最近的历史 (最后 N 个相关的对话轮次).
- 长期记忆 (客户的偏好、购买历史、笔记).
- 代理状态 (角色、启用的技能、规则).
所有这些信息都来自 D1 (Cloudflare 的分布式 SQLite). D1 替代传统的 Postgres/Mongo - 无需维护服务器,仅从 worker 开始即可在几毫秒内访问,多租户通过 tenant_id.
关键点: 我们 不载入整个对话 到提示中。OpenClaw 的 Memory Manager v2 (如我们的 内部文档 中所述) 只选择当前轮次的相关轮次 (最后 N + N 个高语义相关性轮次).
阶段 3 — 技能选择 (策略引擎,~20ms)
每个代理都有一个可用的 技能集 - 可以调用的功能。例如: consultar_calendario、criar_evento、gerar_link_pagamento、consultar_pedido、chamar_humano.
给定消息 "quero marcar pra sábado de manhã",策略引擎筛选:
- 与 检测到的意图 兼容的技能。
- 对于 对话当前阶段 允许的技能 (不是所有技能都始终可用).
- 该 租户启用的技能 (仅当租户已集成时才会出现日历).
最终您将获得一个小技能子集,传递给模型 - 不是 50 个技能,而是 4 个技能。这样可以显著减少模型调用错误技能的机会。
阶段 4 — 决策 (LLM 调用,400-1200ms)
现在模型进入。OpenClaw 进行一次调用到边缘 LLM (Anthropic Claude、OpenAI GPT、Google Gemini - 可以通过租户配置):
- 系统提示 = 代理角色 + 规则 + 可用技能。
- 历史 = 阶段 2 中选择的轮次。
- 用户消息 = 当前轮次的消息。
模型响应 两种情况之一:
- 最终响应 (直接传递给客户端的文本).
- 工具调用 (要求执行特定技能的请求).
在 "quero marcar pra sábado de manhã" 的例子中,模型通常返回:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变,~100-500ms)
技能 不 在模型中运行。它在我们的代码中运行,代码:
{
"tool": "consultar_calendario",
"args": { "date_range": "2026-04-19 06:00 to 12:00" }
}
阶段 5 — 执行 (可变
- 验证参数 (date_range 格式正确吗? 是否符合租户规则?).
- 检查权限 (该代理是否有权查询该日历?).
- 执行调用 (在这种情况下使用 Google Calendar API).
- 返回结构化结果 给模型。
为什么这样重要? 因为 模型永远不会制造结果。如果日历返回 [10h, 11h],那么就是这样传递给下一次调用。如果技能失败,模型知道失败了。没有风险让代理“发明”自己有 9 点钟时间,而实际上没有。
对于涉及敏感信息(价格、期限、客户姓名)的案例,管道强制 tool call — 不允许模型从自己的“知识”中回答。这 消除了商业代理中最常见的幻觉类别。
阶段 6 — 回答和持久性 (~50ms)
有了技能结果,模型做了第二次调用 — 现在是为了形成最终回复给客户。例如:
"我有星期六 10 点和 11 点。您喜欢哪一个?"
与此同时,工作者:
- 发送 回复通过 WhatsApp API。
- 持久化 完整的轮次(用户 + 代理 + 工具调用 + 持续时间)在 D1。
- 更新长期记忆 如果轮次产生了新事实(例如“客户喜欢星期六”)。
- 发出可观察性事件 (延迟指标、令牌成本、扩展率)。
所有这些都在并行运行。持久化 不会阻塞 发送回复 — 客户不等待 D1。
防止幻觉的防御
在生产中,幻觉的代理很快就会失去信任。OpenClaw 有 4 条防御线:
- 强制事实来源。事实数据(价格、时间、姓名) 始终 来自技能,而不是模型自己。
- 双重验证敏感数据。预订在确认客户之前不会持久化。付款在释放访问之前不会确认。
- 明确的否定规则。每个代理的角色包括“永远不要发明 X、Y、Z” — 模型遵守。
- 人工fallback。当没有技能覆盖问题时,代理会说
"让我们检查一下团队"并打开一个票 — 不会扔掉。
在过去 6 个月的审计中(手动检查的真实对话),事实幻觉率低于 0.3% 的轮次 — 大多数情况都是由于配置(租户忘记启用相关技能),而不是模型错误。
Arquitetura好的设计是不可见的,直到你查看账单。假设每个轮次都进行1-2次LLM调用+D1查找,一个完整对话(10-15轮次)的典型成本如下:
- 10轮次:LLM调用+D1查找的总成本约为$0.60-$0.80
- 15轮次:LLM调用+D1查找的总成本约为$0.90-$1.20
Equipe OpenClaw
发布于 2026年5月31日