17.1 Canvas 概念

生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~180k tokens,输出 ~5k tokens(本节)


在前面的章节中,我们已经看到 OpenClaw 的 Agent 如何通过文字回复与用户交互、如何通过 Bash 工具执行命令、如何通过浏览器控制工具操纵网页。但这些交互方式都有一个共同的局限——Agent 的输出本质上是文本流。当 Agent 需要向用户展示一张动态图表、一个交互式表单、甚至一个完整的小程序时,纯文本就力不从心了。

Canvas 系统正是为了解决这个问题而设计的。它为 Agent 提供了一个可视化工作区——一块可以渲染 HTML/CSS/JavaScript 的画布,Agent 可以向其中推送任意 Web 内容,用户可以在其中进行交互操作。


17.1.1 什么是 Canvas:Agent 驱动的可视化工作区

基本概念

Canvas 的核心思想很简单:给 Agent 一块 WebView,让它可以自由渲染内容

在传统的聊天式 AI 交互中,Agent 的输出被限制在消息流里——文字、代码块、Markdown 表格。而 Canvas 提供了一个独立的渲染表面(rendering surface),Agent 可以:

  1. 推送 HTML 页面——Agent 生成 HTML/CSS/JS 文件,Canvas 服务器托管并渲染

  2. 注入 JavaScript——通过 canvas.eval 在运行中的页面执行任意 JS 代码

  3. 截取快照——通过 canvas.snapshot 获取当前渲染结果的截图

  4. 控制显隐——通过 canvas.present / canvas.hide 控制 Canvas 的可见性

这种设计使得 Agent 从一个"只会打字的助手"升级为"能操纵屏幕的助手"。

架构定位

Canvas 在 OpenClaw 的整体架构中处于节点(Node)子系统的一部分。回顾第 1 章的架构图:

Canvas 的数据流是这样的:

  1. Agent 调用 canvas 工具(如 canvas.present

  2. 工具实现通过 Gateway 的 node.invoke 发送命令到目标节点

  3. 目标节点(iOS/Android/macOS 原生应用)在本地 WebView 中执行命令

  4. WebView 从 Canvas Host 服务器拉取 HTML 内容并渲染

衍生解释——WebView:WebView 是原生应用中嵌入的浏览器组件。在 iOS 上是 WKWebView(基于 WebKit 引擎),在 Android 上是 android.webkit.WebView(基于 Chromium),在 macOS 上同样是 WKWebView。它允许原生应用在界面中嵌入一个完整的网页渲染器,能执行 HTML/CSS/JavaScript。OpenClaw 利用 WebView 作为 Canvas 的渲染表面,这样 Agent 就可以通过 Web 技术来构建任意 UI。

Canvas Host:静态文件服务器

Canvas 的内容需要一个 HTTP 服务器来托管。OpenClaw 在 src/canvas-host/server.ts 中实现了这个服务器,称为 Canvas Host。它的职责很单纯:

职责
说明

静态文件服务

~/.openclaw/canvas/ 目录提供 HTML/CSS/JS/图片等文件

路径安全

防止路径遍历攻击(../ 不允许跳出根目录)

Live Reload

文件变更时通过 WebSocket 通知客户端自动刷新

A2UI 托管

同时托管 A2UI 渲染器的资源文件

Agent 的工作流程是:

  1. 将 HTML 文件写入 ~/.openclaw/canvas/ 目录

  2. 调用 canvas.present 让目标节点的 WebView 加载该文件

  3. Canvas Host 提供文件服务,WebView 渲染内容

  4. 文件变更时,Live Reload 自动刷新 WebView

这种"文件系统即 API"的设计非常简洁——Agent 不需要学习任何特殊的渲染协议,只需要会写 HTML 就可以驱动 Canvas。

Canvas 与浏览器控制的区别

读者可能会问:第 16 章的浏览器控制不是也能操纵网页吗?Canvas 和它有什么区别?

维度
浏览器控制(第 16 章)
Canvas

控制对象

用户的桌面浏览器(Chrome/Edge/Brave)

嵌入在原生应用中的 WebView

内容来源

任意互联网网页

Agent 自己生成的 HTML

使用场景

网页自动化、爬虫、表单填写

Agent 驱动的可视化展示

协议

CDP / Playwright

Gateway node.invoke

平台

仅桌面(需要安装 Chrome)

macOS / iOS / Android

简言之:浏览器控制是"操纵别人的网页",Canvas 是"渲染自己的网页"。


17.1.2 A2UI(Agent-to-UI):AI Agent 直接操纵用户界面

从 HTML 推送到结构化 UI

Canvas 的基础模式——Agent 写 HTML,WebView 渲染——已经很强大了。但它有一个问题:每次 UI 更新都需要重写整个 HTML 文件。如果 Agent 只想在屏幕上追加一行文字、更新一个进度条,它不得不重新生成完整的 HTML 并触发页面刷新。

A2UI(Agent-to-UI)解决了这个问题。它是 OpenClaw 提出的一套结构化 UI 协议,允许 Agent 通过 JSONL(JSON Lines)命令流来增量地操纵用户界面。

衍生解释——A2UI:A2UI 是 Agent-to-UI 的缩写,是 OpenClaw 原创的概念。它指的是 AI Agent 可以直接向用户推送结构化的 UI 描述(而非纯 HTML),由一个专用的渲染器(A2UI Renderer)解释并呈现为可交互的界面。可以把它理解为"AI 主导的前端渲染"——Agent 不仅能回复文字,还能展示按钮、表单、图表等交互式界面元素。

衍生解释——JSONL(JSON Lines):JSONL 是一种文本格式,每行一个 JSON 对象,行与行之间用换行符分隔。相比普通 JSON 数组,JSONL 的优势是支持流式处理——不需要等待整个数据完成,每读到一行就能解析一个对象。这对于 Agent 逐步构建 UI 非常合适:Agent 可以一条一条地发送 UI 指令,渲染器收到一条就执行一条。

A2UI 的工作方式

A2UI 的核心流程:

  1. Agent 调用 canvas 工具的 a2ui_push 动作,附带 JSONL 数据

  2. 命令通过 Gateway 转发到目标节点

  3. 节点的 WebView 中运行着 A2UI 宿主页面(index.html

  4. 宿主页面中的 <openclaw-a2ui-host> 自定义元素接收 JSONL 并渲染

双向通信:用户动作回传

A2UI 不仅仅是单向推送。当用户在 A2UI 渲染的界面上点击按钮或提交表单时,用户的操作可以回传给 Agent

这通过一个跨平台的"动作桥"(Action Bridge)实现。injectCanvasLiveReload() 函数会向每个 Canvas 页面注入一段 JavaScript,提供全局函数 window.openclawSendUserAction()

三个平台的消息路径:

平台
API
原理

iOS

window.webkit.messageHandlers.openclawCanvasA2UIAction.postMessage()

WKWebView 的 WKScriptMessageHandler 机制,允许 JS 向 Swift 发送消息

Android

window.openclawCanvasA2UIAction.postMessage()

Android WebView 的 @JavascriptInterface 注解,将 Java/Kotlin 对象暴露为 JS 全局对象

macOS

与 iOS 相同(WKWebView

macOS 上的 WKWebView 与 iOS 共享相同的 WebKit API

衍生解释——JavaScript Bridge(JS 桥):在原生应用的 WebView 中,JavaScript 代码运行在一个沙箱环境中,默认无法访问原生功能(如摄像头、文件系统、通知等)。JS 桥是一种让 JavaScript 和原生代码互相调用的机制。在 iOS 上,Swift 通过 WKScriptMessageHandler 监听 JS 发来的消息;在 Android 上,Kotlin/Java 通过 @JavascriptInterface 注解将方法暴露给 JS。OpenClaw 利用这个机制实现了 A2UI 的用户动作回传。

A2UI 宿主页面

A2UI 的渲染发生在一个专用的宿主页面中(src/canvas-host/a2ui/index.html)。这个页面的结构包括三个层次:

元素
用途

底层画布

<canvas id="openclaw-canvas">

供低级 2D 绘图使用,自动适配设备像素比(DPR)

状态覆盖层

#openclaw-status

显示调试状态信息(默认隐藏,可通过 ?debugStatus=1 启用)

A2UI 渲染层

<openclaw-a2ui-host>

承载 A2UI 渲染器输出的自定义元素,是用户看到的主要内容

宿主页面还暴露了一个全局 API window.__openclaw

平台自适应

A2UI 宿主页面通过 CSS 自定义属性和平台检测实现了跨平台适配:

这些自定义属性对应移动设备的安全区域(Safe Area),原生应用在加载 WebView 时会将实际的安全区域值注入这些属性,确保 A2UI 内容不会被刘海屏、底部手势条等遮挡。

平台检测在页面加载时执行:

Android 平台会使用更高不透明度的渐变背景,以适配 OLED 屏幕的显示特性:

Canvas 与 A2UI 的关系

最后,厘清 Canvas 和 A2UI 的关系:

Canvas 是底层基础设施(WebView + 静态文件服务),A2UI 是基于 Canvas 的高级抽象(结构化 UI 协议)。Agent 可以根据需要选择:

  • 需要完全自定义的 UI → 使用 Canvas 基础模式,直接推送 HTML

  • 需要快速构建标准化界面 → 使用 A2UI 模式,发送 JSONL 命令


本节小结

  1. Canvas 是 OpenClaw 的可视化工作区,让 Agent 从"只会打字"升级为"能渲染界面"

  2. Canvas 的核心是一个静态文件服务器(Canvas Host),Agent 将 HTML 文件写入指定目录,由 WebView 加载渲染

  3. Canvas 通过 Gateway 的 node.invoke 机制将命令转发到原生应用节点,节点在本地 WebView 中执行

  4. A2UI(Agent-to-UI)是基于 Canvas 的高级协议,通过 JSONL 命令流实现增量式 UI 更新

  5. A2UI 通过跨平台动作桥(JS Bridge)实现双向通信——iOS 用 WKScriptMessageHandler,Android 用 @JavascriptInterface

  6. A2UI 宿主页面包含三个层次:底层 Canvas 画布、状态覆盖层、A2UI 渲染层

  7. 平台自适应通过 CSS 自定义属性和 data-platform 数据集实现,Android 有特定的高对比度样式

Last updated