Loading... ## GenUI / A2UI 最近,GenUI 和 A2UI 更新到了 0.9.0 版本,也带来了不少的变化。 ### A2UI 协议 A2UI 是一个通用的、与具体实现无关的 Agent-to-UI 协议。它定义了一套标准,让 AI Agent 可以通过结构化描述来生成动态 UI——注意,A2UI **不生成代码**,而是生成对 UI 结构的 JSON 描述,由客户端框架(如 GenUI)负责解析和渲染。 **核心设计思想:** UI 不是静态预定义的,而是由 AI 在运行时根据用户意图实时构建的。 ```mermaid flowchart LR A([用户输入]) --> B[Agent 理解任务] B --> C[基于规范生成\nA2UI 描述] C --> D[客户端按 Catalog\n渲染组件] D --> E[用户与组件交互] E --> F[状态回传给 Agent] F --> A style A fill:#2563EB,color:#fff,stroke:none style B fill:#3B82F6,color:#fff,stroke:none style C fill:#6366F1,color:#fff,stroke:none style D fill:#8B5CF6,color:#fff,stroke:none style E fill:#A855F7,color:#fff,stroke:none style F fill:#EC4899,color:#fff,stroke:none ``` ### 直接生成代码 vs A2UI <div class="flex-column"><div class="flex-block" style="flex:auto"> ```mermaid flowchart TB CG1([用户输入]) --> CG2["LLM 生成 UI 代码"] CG2 --> CG3["执行 eval -- 安全风险"] CG3 --> CG4["渲染结果 -- 难以预测"] style CG1 fill:#6B7280,color:#fff,stroke:none style CG2 fill:#EF4444,color:#fff,stroke:none style CG3 fill:#DC2626,color:#fff,stroke:none style CG4 fill:#B91C1C,color:#fff,stroke:none ``` </div><div class="flex-block" style="flex:auto"> ```mermaid flowchart TB AG1([用户输入]) --> AG2["LLM 生成 A2UI JSON 描述"] AG2 --> AG3["客户端解析 JSON,限 Catalog 组件"] AG3 --> AG4["Flutter 渲染,可预测可流式"] style AG1 fill:#2563EB,color:#fff,stroke:none style AG2 fill:#6366F1,color:#fff,stroke:none style AG3 fill:#8B5CF6,color:#fff,stroke:none style AG4 fill:#059669,color:#fff,stroke:none ``` </div></div> | | 直接生成代码 | A2UI | | -------- | ---------------------------- | ----------------------------- | | LLM 输出 | 可执行代码(Flutter / HTML) | 结构化 JSON 描述 | | 执行方式 | eval / 动态编译 | 客户端解析,调用预定义 Widget | | 安全性 | 任意代码可被执行 | 沙箱化,只能用 Catalog 内组件 | | 可预测性 | 输出随机,难以 debug | Schema 约束,结构可验证 | | 流式渲染 | 需代码完整才能执行 | 逐块解析,边生成边渲染 | | 跨平台 | 依赖运行时和语言 | 协议与平台无关 | | 组件控制 | LLM 可生成任意 UI | 开发者通过 Catalog 定义边界 | --- ### A2UI 从 v0.8 到 v0.9 #### 1. 设计哲学转变 | | v0.8 | v0.9 | | ----------- | ------------------------- | ------------------------------------------------------ | | 设计核心 | 优化 LLM 的结构化输出生成 | **Prompt-first**,优先考虑如何嵌入系统提示词 | | Schema 形态 | 单一整体 Schema | 模块化,分离 common types / server-to-client / catalog | | LLM 友好性 | 较复杂 | 更符合 LLM 自然理解 JSON 的方式 | v0.9 的核心哲学是:**Schema 应该能直接嵌入 LLM 的 system prompt**,对 token 友好,同时与 LLM 生成 JSON 的自然习惯保持一致。 --- #### 2. 消息类型重命名 | v0.8 | v0.9 | 说明 | | ----------------- | ------------------ | --------------------------- | | `beginRendering` | `createSurface` | 现在必须显式指定`catalogId` | | `surfaceUpdate` | `updateComponents` | | | `dataModelUpdate` | `updateDataModel` | | | `userAction` | `action` | | **`createSurface` 新增变化:** - 必须指定 `catalogId`(明确使用哪个组件目录) - 使用 `theme` 替代 `styles` 来控制样式 - 根组件通过 ID 标识,而非显式声明 --- #### 3. 组件结构扁平化 **v0.8(动态 key 包裹):** ```json { "Text": { "value": "Hello World" } } ``` **v0.9(discriminator 属性):** ```json { "component": "Text", "value": "Hello World" } ``` 这一变化让 LLM 的生成更自然,避免了生成"以组件名为 key 的对象"这种对 LLM 来说反直觉的结构。 --- #### 4. 数据模型简化 **v0.8(键值对数组):** ```json [ { "key": "name", "valueString": "Alice" }, { "key": "age", "valueInt": 25 } ] ``` **v0.9(标准 JSON 对象):** ```json { "name": "Alice", "age": 25 } ``` --- #### 5. 数据绑定统一 - 统一使用 `path`(JSON Pointer 语法),消除了 v0.8 中 `dataBinding` / `path` 混用的歧义 - 新增 `formatString` 函数,支持 `${expression}` 内插语法: ``` formatString("你好,${/user/name},你有 ${/notifications/count} 条消息") ``` --- #### 6. 组件级变化速览 | 组件 | v0.8 | v0.9 | | -------------- | ---------------------------- | --------------------------------------- | | Button 上下文 | 键值对数组 | 标准 JSON 对象 | | Button 样式 | `primary: true/false` | `variant: "primary" / "borderless"` | | TextField 类型 | `textFieldType` | `variant`,验证改用 `checks` | | 多选组件 | `MultipleChoice` | `ChoicePicker`(variant 控制单选/多选) | | Slider | `minValue` / `maxValue` | `min` / `max` | | 布局对齐 | `distribution` / `alignment` | `justify` / `align` | --- #### 7. 显式数据同步 & 错误自校正 **数据同步:** 新增 `sendDataModel` flag,客户端可主动向 Agent 同步当前数据模型状态,实现真正的双向数据流。 **错误自校正(`ValidationFailed`):** 当 LLM 生成内容违反 Schema 时,服务端返回结构化错误: ```json { "type": "ValidationFailed", "path": "/components/0/value", "message": "expected string, got number" } ``` 这为 LLM 提供了精确的 generate → validate → retry 反馈闭环。 --- #### 8. 辅助规则文件 v0.9 新增了 `basic_catalog_rules.txt`,用纯自然语言描述那些难以用 JSON Schema 表达的约束规则,直接面向 LLM 友好的形式补充 Schema 的表达局限。 --- ### GenUI GenUI 是 Flutter 对 A2UI 的一个实现,将 Agent 生成的结构化描述实时渲染为 Flutter Widget。 #### 核心包结构 | 包 | 职责 | | --------------------- | -------------------------------------- | | `genui` | 核心框架,实现生成式 UI 的主要逻辑 | | `genui_a2a` | A2UI 协议连接器,对接自定义 Agent 后端 | | `genai_primitives` | 与技术无关的 AI 应用基础数据结构 | | `json_schema_builder` | JSON Schema 验证与定义系统 | #### 五大核心组件 1. **`Conversation`** — 主入口,编排整个生成式 UI 流程 2. **`Catalog`** — 定义 AI 可用的 Widget 词汇表(名称、Schema、builder 函数) 3. **`DataModel`** — 可观察的中心化状态存储,驱动响应式 UI 4. **`SurfaceController`** — 运行时引擎,管理 UI 生命周期和状态更新 5. **`A2uiTransportAdapter`** — 桥接外部 LLM 服务到框架内部 #### 消息处理流程 ``` 用户输入 → conversation.sendRequest() → A2uiTransportAdapter 调用 LLM,流式返回 chunks → A2uiParserTransformer 解析文本为 GenerationEvent → SurfaceController 处理 A2UI 消息: createSurface / updateComponents / updateDataModel / deleteSurface → Surface Widget 自动响应状态变化,重建 UI → 用户交互触发新的 AI 请求,形成对话循环 ``` #### 基本使用模式 ```dart // 1. 定义组件目录 final catalog = Catalog( id: 'my_catalog', components: [ ComponentDef( name: 'Text', schema: textSchema, builder: (props, _) => Text(props['value']), ), // ...更多组件 ], ); // 2. 组装框架 final controller = SurfaceController(catalogs: [catalog]); final transport = A2uiTransportAdapter(onSend: myLlmCall); final conversation = Conversation(controller, transport); // 3. 渲染 Surface Surface(controller: controller) ``` --- #### Catalog 与自定义组件 **BasicCatalog 不是 A2UI 协议的一部分。** A2UI 只规定消息结构(`createSurface` / `updateComponents` 等),组件集合完全由 Catalog 决定。GenUI 提供了 18 个 `BasicCatalogItems` 作为参考实现,实际使用时要替换为自己定义的 Catalog。 | 层 | 定义方 | 可替换? | | ---------------------------- | -------------- | ------------------------------ | | 消息结构(createSurface 等) | A2UI 协议规范 | 不可,这是协议本身 | | Basic Catalog 18 个组件 | GenUI 参考实现 | 可完全替换或扩展 | | 自定义组件 | 开发者自定义 | 只需 Schema + Builder + Prompt | `createSurface` 里的 `catalogId`(URI)就是切换 Catalog 的开关,指向哪个 URI,LLM 就按哪套组件词汇表生成。 **自定义组件三步走:** **① 定义 Schema**(告诉 LLM 这个组件有哪些属性) ```dart final orderCardSchema = S.object( properties: { 'title': S.string(description: '卡片标题', isRequired: true), 'status': S.string(enumValues: ['pending', 'done', 'error']), 'amount': S.number(description: '金额(元)'), }, ); ``` **② 实现 Widget Builder**(把 LLM 输出的 JSON 渲染成 Flutter Widget) ```dart Widget orderCardBuilder(CatalogItemContext ctx, Widget? child) { final title = ctx.json['title'] as String; final status = ctx.json['status'] as String? ?? 'pending'; final amount = ctx.json['amount'] as num?; return Card( child: ListTile( title: Text(title), subtitle: Text('¥${amount ?? '--'}'), trailing: Chip(label: Text(status)), ), ); } ``` **③ 注册进 Catalog,挂载到 SurfaceController** ```dart final myCatalog = Catalog( id: 'https://your-domain.com/catalog/v1.json', // 与 createSurface.catalogId 对应 items: [ CatalogItem( name: 'OrderCard', // LLM 用 "component": "OrderCard" 来引用 schema: orderCardSchema, widgetBuilder: orderCardBuilder, ), ...BasicCatalogItems.asCatalog().items, // 可选:混入官方组件 ], ); final controller = SurfaceController(catalogs: [myCatalog]); ``` **④ 同步到系统 Prompt**(LLM 只知道你告诉它的) ``` | OrderCard | title(必填)| status: pending/done/error; amount | ``` 这正是 A2UI v0.9 "prompt-first" 哲学的体现——Schema 的消费者是 LLM,而不是运行时验证器。 **完整流转:** ``` 开发者写 Schema + Builder → 注册进 Catalog(catalogId = 自定义 URI) → 把组件说明写进 system prompt ↓ 用户提问 → LLM 读 system prompt,知道可用哪些组件及其属性 → LLM 输出文本流,内嵌 A2UI JSON: {"version":"v0.9","createSurface":{"surfaceId":"s1","catalogId":"<自定义 URI>"}} {"version":"v0.9","updateComponents":{"surfaceId":"s1","components":[ {"id":"root","component":"OrderCard","title":"SmartHub Pro","status":"pending","amount":699} ]}} → A2uiParserTransformer 从文本流中提取 JSON 块 → SurfaceController 根据 catalogId 找到对应 Catalog → 用 "component":"OrderCard" 匹配到 CatalogItem → 调用 orderCardBuilder(ctx) 渲染 Flutter Widget → Surface Widget 展示在聊天气泡中 ↓ 用户点击 Button → 触发 action event,重新走用户提问流程 ``` --- ## GenKit for Dart GenKit 是 Google 推出的 **AI SDK**,定位为 LLM 框架和 AI Agent 工具包,Dart 则是 GenKit 的一种实现。 ### 核心特性 - **类型安全**:为调用 Genkit Flow 提供类型安全的客户端库 - **流式支持**:支持实时流式响应 - **多模型支持**:通过插件机制接入多个 AI 提供商 - **Agent 工作流**:支持工具调用(Tool Calling)和 Agentic 工作流 - **MCP 支持**:内置 Model Context Protocol 集成 ### 主要包 | 包 | 用途 | | --------------------- | ----------------------------------------- | | `genkit` | 核心客户端库 | | `genkit_google_genai` | Google AI(Gemini)集成 | | `genkit_anthropic` | Anthropic / Claude 集成 | | `genkit_openai` | OpenAI 集成 | | `genkit_chrome` | Chrome Prompt API(Gemini Nano 本地推理) | | `genkit_mcp` | Model Context Protocol 支持 | | `genkit_shelf` | HTTP 服务端集成 | | `genkit_firebase_ai` | Firebase AI 插件 | | `schemantic` | 类型安全的数据类生成工具 | ### 典型使用示例 ```dart import 'package:genkit/genkit.dart'; import 'package:genkit_google_genai/genkit_google_genai.dart'; final ai = Genkit(plugins: [googleAI()]); // 文本生成 final response = await ai.generate( model: gemini15Flash, prompt: '用一句话介绍 Flutter', ); // 流式输出 await for (final chunk in ai.generateStream( model: gemini15Flash, prompt: '写一首关于 Dart 的诗', )) { print(chunk.text); } // 结构化输出 final result = await ai.generate( model: gemini15Flash, prompt: '提取用户信息', output: OutputConfig(schema: userSchema), ); ``` ### 与 Flutter 集成 GenKit Dart 同时支持纯 Dart 服务端和 Flutter 客户端应用,可以与 GenUI 配合,构建完整的 AI 驱动应用:后端通过 GenKit 调用 LLM、遵循 A2UI 协议生成 UI 描述,前端通过 GenUI 实时渲染为 Flutter Widget。 --- ## Flutter / Dart Agent Skills ### 什么是 Agent Skills? Agent Skills 是一组**专为 AI Agent 设计的指令集**,由 Flutter 团队和 Dart 团队分别维护。Skills 的核心价值是:赋予 AI Agent 特定领域的专业知识和可重复的工作流,让 Agent 在完成开发任务时更少出错、更符合最佳实践。 Skills 与 MCP 是互补关系: - **MCP** 给 Agent 提供工具(能做什么) - **Skills** 教 Agent 如何正确使用这些工具(怎么做) ### 安装方式 ```bash # 安装 Flutter Skills npx skills add flutter/skills --skill '*' --agent universal # 安装 Dart Skills npx skills add dart-lang/skills --skill '*' --agent universal # 更新 npx skills update ``` ### Flutter Skills(11 个) 覆盖 Flutter 应用开发的核心场景: | 分类 | Skills | | -------- | ----------------------------------- | | 测试 | 集成测试、Widget 测试、Preview 测试 | | 架构 | 分层应用设计、响应式布局 | | 路由 | GoRouter 声明式路由 | | 国际化 | 多语言支持配置 | | 数据处理 | JSON 序列化、HTTP 请求 | | 布局 | 响应式设计、错误修复 | ### Dart Skills(10 个) 覆盖 Dart 开发的通用工作流: | 分类 | Skills | | -------- | ---------------------------------- | | 测试 | 单元测试编写、Mock 生成 | | CLI 开发 | 命令行应用结构、参数解析 | | 代码质量 | 静态分析、模式匹配、自动修复 | | 错误管理 | 运行时错误检测与解决 | | 依赖管理 | 包冲突解决 | | 覆盖率 | 测试覆盖率收集与报告 | | 迁移 | 升级到现代包(如`package:checks`) | ### 使用示例 在配置好 Skills 后,直接用自然语言驱动 Agent 完成任务: ``` "帮我为 UserRepository 写单元测试,并生成相应的 Mock" "用 GoRouter 重构当前项目的路由层" "分析项目的静态分析警告并自动修复" ``` --- ``` ## Flutter / Dart MCP Dart 官方提供了一个实验性的 MCP Server —— **dart_mcp_server**,将 Dart/Flutter 开发工具链直接暴露给 AI Agent,让 Agent 可以像开发者一样操作项目。 ### 核心能力 | 分类 | 工具 | |---|---| | 代码分析 | 项目错误分析、LSP hover 信息、符号解析 | | 代码质量 | 格式化(dart format)、自动修复(dart fix)| | 应用管理 | 连接 Dart Tooling Daemon、Flutter hot reload / hot restart | | UI 调试 | Widget Inspector 集成、获取运行时错误 | | 项目管理 | 创建项目、pub 依赖管理 | | 包搜索 | pub.dev 搜索、package URI 读取 | | 测试 | 运行测试、Flutter Driver 命令 | ### 接入配置 **VS Code + Copilot**(最简单):在用户设置中添加: ```json "dart.mcpServer": true ``` **Cursor**:在 `.cursor/mcp.json` 中配置: ```json { "mcpServers": { "dart": { "command": "dart", "args": ["mcp-server"] } } } ``` **Gemini CLI**:在 `.gemini/settings.json` 中配置,参数相同。 ### 与运行中的 App 联动 应用以 **debug / profile 模式**启动时会自动注册到 Dart Tooling Daemon(DTD),MCP Server 通过 DTD 与 App 通信,实现: - 实时 hot reload - 获取 Widget 树和运行时错误 - 执行 Flutter 命令 ### 与 Agent Skills 的分工 - **MCP Server** — 给 Agent 提供**工具**(能做什么):分析、reload、运行测试… - **Agent Skills** — 教 Agent **方法论**(怎么做):按最佳实践完成具体开发任务 两者配合使用,才能让 Agent 既有能力又有正确的工作流。 © 允许规范转载 打赏 赞赏作者 微信 赞