不要向你的代理喂入 HTML
Source: Dev.to
请提供您希望翻译的完整文本内容,我将为您翻译成简体中文并保留原始的格式、Markdown 语法以及技术术语。谢谢!
TL;DR — 给 AI 一个白盒,而不是黑盒
大多数 AI 代理通过 黑盒 方法与网页应用交互:读取 DOM 转储或截图,然后猜测该点击什么。HTML 从未为机器设计。从 AI 的视角来看,DOM 只是噪声,业务逻辑仅隐约埋藏其中。
本文主张 白盒 方法:公开一个 语义状态层,直接揭示应用的结构、规则、状态以及有效的转移。这并不是要取代 UI;而是要在传统用户界面旁提供一个 智能接口 (II)。

1. 黑盒:AI 与网页应用的现状
以下是大多数团队今天向网页应用“添加 AI”的方式:
- 使用 LangChain、AutoGPT 或浏览器自动化
- 驱动 Playwright 或 Puppeteer
- 将 DOM 或截图导入模型
- 希望它能自行判断点击哪个位置
这就是 黑盒 方法。代理只能看到渲染后的表面,必须推断所有其他信息。
DOM Dump 有什么问题?
<div class="product-name">
<label>Product Name</label>
<input type="text" name="name" />
<span class="error">This field is required.</span>
</div>
从代理的视角来看:
| 问题 | 影响 |
|---|---|
| 令牌浪费 | 90 % 的令牌都是类名和包装器 |
| 缺失约束 | 它是必填吗?最大长度是多少? |
| 无依赖 | 此字段是否依赖其他字段? |
| 无因果关系 | 提交按钮被禁用——但为什么? |
代理被迫 猜测。一次 CSS 重构会导致一切失效。布局的改变会让模型困惑。逻辑从未被暴露——只有它的视觉投影。
信号 90 %。
2. 白盒:暴露应用的大脑
另一种方式是 白盒 协议。与直接返回 HTML 不同,引擎会暴露一个 语义快照 —— 一个结构化的、描述应用内部状态的表示,供代理直接读取。
{
"topology": {
"viewId": "product-create",
"mode": "create",
"sections": [
{ "id": "basic", "title": "Basic Info", "fields": ["name", "productType"] },
{ "id": "shipping", "title": "Shipping", "fields": ["shippingWeight"] }
]
},
"state": {
"form": { "isValid": false, "isDirty": false },
"fields": {
"name": {
"value": "",
"meta": { "valid": false, "hidden": false, "disabled": false, "errors": ["Required"] }
},
"productType": {
"value": "PHYSICAL",
"meta": { "valid": true, "hidden": false, "disabled": false, "errors": [] }
},
"shippingWeight": {
"value": null,
"meta": { "valid": true, "hidden": false, "disabled": false, "errors": [] }
}
}
},
"constraints": {
"name": { "required": true, "minLength": 2, "maxLength": 100 },
"shippingWeight": { "min": 0, "max": 2000, "dependsOn": ["productType"] }
},
"interactions": [
{ "id": "updateField:name", "intent": "updateField", "target": "name", "available": true },
{ "id": "updateField:productType", "intent": "updateField", "target": "productType", "available": true },
{ "id": "submit", "intent": "submit", "available": false, "reason": "Name is required" }
]
}
现在代理拥有:
- Topology – 屏幕结构、分区、字段层级
- State – 每个字段的当前值、有效性、可见性、错误信息
- Constraints – 必填、最小/最大值、依赖关系
- Interactions – 可执行的操作以及 为何 某些操作被阻止
无需猜测,无需推断。代理直接读取应用的大脑。
3. 实际案例:“我在哪里选择周?”
🎮 实际操作演示: Manifesto Playground – 尝试更改字段值,实时观察语义状态的更新。
场景
User: “我看到一个日期选择器,但我在哪里选择哪一周?”
AI Chatbot: “只有在将频率设置为‘Weekly’时,周选择器才会出现。现在它被设置为‘Daily’。需要我帮你改成吗?”
为实现此功能,AI 需要了解:
- 一个名为
weekSelector的字段存在且当前被隐藏 - 当
frequency === 'WEEKLY'时它会变为可见 - 当前
frequency的值是'DAILY'
仅靠 DOM‑方式无法可靠提供这些信息,但语义快照可以:
{
"fields": {
"frequency": {
"value": "DAILY",
"meta": { "hidden": false }
},
"weekSelector": {
"value": null,
"meta": { "hidden": true },
"visibleWhen": "frequency === 'WEEKLY'"
}
}
}
AI 读取此快照后 知道——无需推断——字段被隐藏的确切原因以及什么条件会让它出现。
4. 协议循环
Manifesto 在引擎和 AI 代理之间实现了一个持续的反馈循环:
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ [Context Injection] → [Reasoning] → [Action Dispatch] → [Delta] │
│ ▲ │ │
│ └─────────────── Continuous Snapshots ────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
逐步说明
- 上下文注入 – 引擎导出包含拓扑、状态、约束和交互的语义快照。
- 推理 – 代理根据快照规划下一步操作。
- 动作分发 – 代理调用抽象意图(例如
updateField、submit、reset、validate),而不是原始 DOM 事件。 - 增量反馈 – 引擎返回实际的变化,而不仅仅是“成功”。差异显示因果关系(例如,“我修改了 X,导致 Y 隐藏”。)
- 循环使用更新后的快照重复进行,使代理获得可预测、结构化的反馈,而不是“点击并期待”。
5. The API: Exploration and Execution
Manifesto 通过 @manifesto-io/ai 暴露此协议。
Exploration Mode – “What can I do here?”
import { createInteroperabilitySession } from '@manifesto-io/ai'
const session = createInteroperabilitySession({
runtime, // FormRuntime instance
viewSchema, // View definition
entitySchema, // Entity definition
})
// Get the current semantic snapshot
const snapshot = session.snapshot()
// snapshot.interactions tells the agent:
// - submit: available = false, reason = "Name is required"
从这里,代理可以查询可用的交互、更新字段、提交表单,并接收增量差异,所有这些都由白盒语义表示驱动。