📝 Markdown as Protocol for Agentic UI
核心创意: 用 Markdown 作为协议,同时传输文本、代码、数据三种内容。流式执行 + mount() 原语,让 AI 代理动态生成 React UI。
🎯 核心理念
Eric Schmidt 预测: "用户界面将在很大程度上消失",AI 代理将按需动态生成 UI。本文探索了这一愿景的实现方式。
📐 协议设计: 三种 Block
| Block 类型 | 语法 | 用途 |
|---|---|---|
| Text | **plain markdown** |
流式输出给用户 |
| Code fence | ```tsx agent.run |
在服务器持久上下文中执行 |
| Data fence | ```json agent.data => "id" |
流式传输数据到 UI |
🔄 反馈循环
console.log = agent 与自己的对话方式
- LLM 生成带代码块的 Markdown
- 文本流给用户,代码在服务器增量执行
- console.* 输出和异常作为新 turn 反馈给 LLM
- 无输出/异常 → 完成,等待新用户查询
⚡ 流式执行
希望语句在生成时就执行,不等完整响应。问题: 没有运行时支持这种流式执行。
解决方案: 构建 bun-streaming-exec,使用 vm.Script + 创意包装。
🖥️ Agentic UI: mount() 原语
```tsx agent.run
mount({
ui: () => Hello from the agent!
});
```
LLM 生成代码 → 服务器执行 → mount() 序列化 React 组件 → 客户端渲染
🔀 四种数据流模式
1. Client → Server (表单)
```tsx agent.run
const form = mount({
outputSchema: z.object({ name: z.string() }),
ui: ({ output }) => (
<Box>
<TextField {...output.name} />
<Button {...output}>Submit</Button>
</Box>
)
});
const { name } = await form.result; // 阻塞直到提交
console.log("user:responded", name);
```
2. Server → Client (实时更新)
```tsx agent.run
const data = new Data({ progress: 0 });
mount({
data,
ui: ({ data }) => <LinearProgress value={data.progress} />
});
data.progress = 40; // UI 立即更新
```
Data 对象是代理,检测变更 → 序列化为 patch → WebSocket 发送到客户端
3. LLM → Client (流式数据)
```tsx agent.run
const movies = new StreamedData("movies-list");
mount({
streamedData: movies,
ui: ({ streamedData }) => <Card>{streamedData?.map(...)}</Card>
});
```
```json agent.data => "movies-list"
[
{ "name": "Blade Runner", "rating": 4.5 }
]
```
4. Client → Server (回调)
```tsx agent.run
const onRefresh = async () => {
data.messages = await loadMessages();
};
mount({
callbacks: { onRefresh },
ui: ({ callbacks }) => <RefreshButton onClick={callbacks.onRefresh} />
});
```
🕳️ Slots 机制
UI 复杂时,用户需等待更久。用 slot 机制: 先挂载骨架,逐步注入重内容。
```tsx agent.run
const shell = mount({
ui: () => (
<Card>
<Slot name="stats" fallback={<Skeleton />} />
<Slot name="blockers" fallback={<Skeleton />} />
</Card>
)
});
shell.mountSlot("stats", ({ data }) => <StatsRow />);
```
🔒 关于安全
Claude Code 和 ChatGPT Code Interpreter 已在执行 LLM 生成的代码。沙箱、权限、静态分析在开发中。Prompt injection 是所有 agent 架构的共同难题。本文探索的是假设安全合理解决后的上层建筑。
💡 为什么有效
每个设计选择都为一个目标优化: LLM 人体工程学
- Markdown + code fences: LLMs 训练时见过数十亿 Markdown
- 语法自然可扩展: 加新 fence header 即可
- console.log 反馈: 代理最熟悉的调试方式
📚 相关标签
Agentic UI Markdown React Protocol Streaming