Hướng Dẫn Chi Tiết Về Generative UI Cho Các Nhà Phát Triển Trong Năm 2026

Trong bối cảnh công nghệ đang phát triển vũ bão, các AI agent đã đạt được những bước tiến đáng kể trong khả năng lập luận và lập kế hoạch. Tuy nhiên, lớp giao diện người dùng (UI) phần lớn vẫn giữ nguyên, trở thành một nút thắt cổ chai kìm hãm trải nghiệm người dùng. Hầu hết các trải nghiệm với agent vẫn phụ thuộc vào giao diện chat, ngay cả khi nhiệm vụ yêu cầu rõ ràng các biểu mẫu, bản xem trước, điều khiển hoặc phản hồi theo từng bước.

Đây chính là lúc khái niệm [Generative UI](https://www.copilotkit.ai/generative-ui) xuất hiện. Generative UI cho phép các agent tác động đến giao diện người dùng tại thời điểm chạy, giúp UI có thể thay đổi linh hoạt theo sự biến đổi của ngữ cảnh. Điều này thường được thực hiện thông qua các đặc tả UI như A2UI, Open-JSON-UI hoặc MCP Apps.

Bài viết này sẽ đưa bạn khám phá Generative UI, ba mô hình thực tiễn của nó và cách CopilotKit hỗ trợ chúng (sử dụng giao thức AG-UI bên dưới).

Hãy cùng đi sâu vào chi tiết!

[![Image 1: AG-UI connecting all the spec patterns of GenUI](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jbjq0763sbkvy6owrrz.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jbjq0763sbkvy6owrrz.png)

Những Nội Dung Chính Chúng Ta Sẽ Khám Phá

Trong bài viết chuyên sâu này, chúng ta sẽ đi qua các chủ đề quan trọng sau:

  1. Generative UI là gì và tại sao nó lại quan trọng?
  2. Ba Mô Hình Thực Tiễn của Generative UI
    • Static Generative UI (AG-UI)
    • Declarative Generative UI (A2UI và Open-JSON-UI)
    • Open-ended Generative UI (MCP Apps)
  3. Cách AG-UI Kích Hoạt Generative UI Tại Thời Điểm Chạy

Bạn có thể tìm thấy mã nguồn của môi trường thử nghiệm trực tiếp triển khai cả ba cách tiếp cận tại GitHub Repo này.

Generative UI Là Gì?

Generative UI (đôi khi được gọi là GenUI) là một mô hình trong đó các phần của giao diện người dùng được tạo, chọn hoặc kiểm soát bởi một AI agent tại thời điểm chạy, thay vì được các nhà phát triển xác định trước hoàn toàn.

Thay vì mã hóa cứng mọi nút, biểu mẫu hay bảng điều khiển từ đầu, UI được tạo động dựa trên nhu cầu và ngữ cảnh của người dùng. Agent có thể quyết định hiển thị UI nào, cần những đầu vào nào từ người dùng và cách trạng thái nên được cập nhật khi nhiệm vụ tiến triển.

Thay vì chỉ tạo văn bản, agent có thể:

  • Yêu cầu các đầu vào có cấu trúc
  • Kết xuất UI cụ thể cho tác vụ
  • Cập nhật giao diện khi các công cụ chạy và trạng thái thay đổi

Điều này biến UI thành một phần chủ động trong quá trình thực thi của agent, chứ không còn là một lớp vỏ tĩnh xung quanh hộp chat. Frontend không còn phải suy luận ý định từ văn bản nữa.

Generative UI = Đầu ra của LLM → UI tương tác, trực tiếp

Ví dụ điển hình:

  • Một truy vấn du lịch → các thẻ lịch trình + bản đồ + các phần có thể mở rộng
  • Một truy vấn so sánh → các bảng có thể sắp xếp

Trong hệ sinh thái CopilotKit, Generative UI không phải là một sự trừu tượng đơn lẻ. Nó là một tập hợp các mô hình được xây dựng dựa trên các đặc tả UI mang tính tác nhân (như A2UI và MCP Apps) định nghĩa cách các agent giao tiếp các cập nhật UI với các ứng dụng. Bạn có thể tìm hiểu thêm trên website của CopilotKit và tham khảo tài liệu.

Google mô tả Generative UI là một cách để cung cấp cho các mô hình trải nghiệm người dùng phong phú, tùy chỉnh và tương tác, thích ứng với mọi lời nhắc. Nếu bạn quan tâm đến việc đọc thêm, bạn có thể kiểm tra blog nghiên cứu của họ.

Một cái nhìn tổng quan hệ thống cấp cao về triển khai Generative UI (từ Google Research).

[![Image 2: high-level system overview of the generative UI implementation](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9xgo4zdm5we0ckwzade.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9xgo4zdm5we0ckwzade.png)

Nguồn: Google Research

Tại Sao Generative UI Lại Quan Trọng?

Hầu hết các trải nghiệm AI agent ngày nay vẫn giống như các ứng dụng chat. Khi các agent vượt ra ngoài việc trò chuyện và bắt đầu thực hiện các công việc, văn bản đơn thuần trở thành một nút thắt cổ chai.

Các vấn đề phổ biến với các agent chỉ dựa trên văn bản:

  • Việc thực thi công cụ và tiến độ bị ẩn sau các tin nhắn chat.
  • Các đầu vào của người dùng thường mơ hồ, dễ bị hiểu sai và khó xác thực.
  • Các luồng đa bước trở nên khó hiểu, khiến người dùng không tin tưởng vào kết quả.

Với Generative UI, chúng ta có thể:

  • Kết xuất UI cụ thể cho tác vụ chính xác khi cần.
  • Thu thập đầu vào có cấu trúc, được xác thực.
  • Hiển thị tiến độ và kết quả trung gian dưới dạng UI thực tế.
  • Điều chỉnh giao diện khi các kế hoạch phát triển.

Điều này làm cho các hệ thống agent dễ hiểu và dễ hướng dẫn hơn. Thay vì tương tác với một “hộp đen”, người dùng tương tác với một hệ thống hiển thị trạng thái của nó thông qua UI, mang lại sự minh bạch và tin cậy cao hơn.

Ba Mô Hình của Generative UI

Hầu hết các triển khai Generative UI đều nằm trong ba mô hình chính. Điều làm nên sự khác biệt giữa chúng là mức độ kiểm soát nằm ở frontend so với mức độ tự do được trao cho agent.

Dưới đây là ba loại (cùng với các đặc tả ví dụ):

  1. Static Generative UI (kiểm soát cao, tự do thấp) – được truyền qua AG-UI

    Frontend sở hữu UI. Agent chỉ chọn thành phần định nghĩa trước để hiển thị và điền dữ liệu vào đó.
  2. Declarative Generative UI (kiểm soát được chia sẻ) – sử dụng A2UI, Open-JSON-UI

    Agent trả về một đặc tả UI có cấu trúc (thẻ, danh sách, biểu mẫu). Frontend kết xuất nó với các ràng buộc và kiểu dáng riêng.
  3. Open-ended Generative UI (kiểm soát thấp, tự do cao) – được kích hoạt bởi MCP Apps

    Agent trả về một bề mặt UI hoàn chỉnh (thường được nhúng hoặc dạng tự do). Frontend chủ yếu là nơi lưu trữ nó, do đó bạn phải đánh đổi tính nhất quán và an toàn để có được sự linh hoạt.

Nếu bạn muốn xem các mô hình này song song, có một môi trường thử nghiệm trực tiếp hiển thị cả ba, cùng với mã triển khai:

Dưới đây là một đoạn demo ngắn!

Bạn có thể kiểm tra tài liệu và chọn tích hợp bạn đang sử dụng để xem hướng dẫn triển khai chi tiết và ví dụ.

[![Image 3: integration options](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F413kfpmn54kpmx481nt8.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F413kfpmn54kpmx481nt8.png)

Bây giờ, hãy cùng tìm hiểu sâu về từng mô hình và cách triển khai chúng.

✅ Static Generative UI (AG-UI)

Static Generative UI là mô hình bị hạn chế nhất.

Các nhà phát triển xây dựng trước các thành phần UI, và vai trò của agent chỉ giới hạn ở việc quyết định khi nào một thành phần xuất hiện và dữ liệu nào nó nhận được. Bố cục và tương tác hoàn toàn thuộc sở hữu của ứng dụng.

Trong CopilotKit, mô hình này được triển khai bằng cách sử dụng hook `useFrontendTool`, liên kết các thành phần UI được định nghĩa trước với vòng đời của một hành động.

<span style="color: #66d9ef;">// Weather tool - a callable tool that displays weather data in a styled card</span>
<span style="color: #66d9ef;">useFrontendTool({</span>
<span style="color: #66d9ef;">  name: "get_weather",</span>
<span style="color: #66d9ef;">  description: "Get current weather information for a location",</span>
<span style="color: #66d9ef;">  parameters: z.object({ location: z.string().describe("The city or location to get weather for") }),</span>
<span style="color: #66d9ef;">  handler: async ({ location }) => {</span>
<span style="color: #66d9ef;">    await new Promise((r) => setTimeout(r, 500));</span>
<span style="color: #66d9ef;">    return getMockWeather(location);</span>
<span style="color: #66d9ef;">  },</span>
<span style="color: #66d9ef;">  render: ({ status, args, result }) => {</span>
<span style="color: #66d9ef;">    if (status === "inProgress" || status === "executing") {</span>
<span style="color: #66d9ef;">      return <WeatherLoadingState location={args?.location} />;</span>
<span style="color: #66d9ef;">    }</span>
<span style="color: #66d9ef;">    if (status === "complete" && result) {</span>
<span style="color: #66d9ef;">      const data = JSON.parse(result) as WeatherData;</span>
<span style="color: #66d9ef;">      return (</span>
<span style="color: #66d9ef;">        <WeatherCard</span>
<span style="color: #66d9ef;">          location={data.location}</span>
<span style="color: #66d9ef;">          temperature={data.temperature}</span>
<span style="color: #66d9ef;">          conditions={data.conditions}</span>
<span style="color: #66d9ef;">          humidity={data.humidity}</span>
<span style="color: #66d9ef;">          windSpeed={data.windSpeed}</span>
<span style="color: #66d9ef;">        /></span>
<span style="color: #66d9ef;">      );</span>
<span style="color: #66d9ef;">    }</span>
<span style="color: #66d9ef;">    return <>;</span>
<span style="color: #66d9ef;">  },</span>
<span style="color: #66d9ef;">});</span>

Ở đây, hook `useFrontendTool` cho phép ứng dụng đăng ký công cụ `get_weather` và đính kèm một hàm render React được định nghĩa trước vào từng giai đoạn của vòng đời của nó.

[![Image 4: static generative UI output](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futfvm28l3sqrblzuquw2.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futfvm28l3sqrblzuquw2.png)

Agent có thể gọi công cụ và truyền đối số, nhưng nó không bao giờ kiểm soát bố cục hoặc tự tạo ra UI.

Bạn có thể kiểm tra triển khai đầy đủ tại github.com/CopilotKit/generative-ui-playground.

✅ Declarative Generative UI (A2UI và Open-JSON-UI)

Declarative Generative UI nằm giữa các cách tiếp cận tĩnh và hoàn toàn mở.

Thay vì chọn các thành phần được định nghĩa trước, agent trả về một mô tả UI có cấu trúc. Mô tả này định nghĩa các thứ như thẻ, danh sách, biểu mẫu hoặc widget, và frontend sẽ kết xuất chúng.

Hai đặc tả khai báo phổ biến được sử dụng ở đây là:

  1. A2UI → đặc tả Generative UI khai báo từ Google, được mô tả dựa trên JSONL, và các agent có thể sử dụng nó để trả về các widget UI như một phần trong phản hồi của họ.
  2. Open‑JSON‑UI → tiêu chuẩn mở hóa cho lược đồ Generative UI khai báo nội bộ của OpenAI.

Cả hai đều định nghĩa các cách thức có cấu trúc, không phụ thuộc nền tảng để các agent mô tả UI trong JSON.

Hãy cùng tìm hiểu luồng cơ bản để triển khai A2UI.

Thay vì viết A2UI JSON bằng tay, bạn có thể sử dụng A2UI Composer để tạo đặc tả cho bạn. Sao chép đầu ra và dán vào lời nhắc của agent như một mẫu tham chiếu.

[![Image 5: A2UI Composer](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1t1yvtk2r1sixyg26njt.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1t1yvtk2r1sixyg26njt.png)

[![Image 6: A2UI Composer](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1trcbzm894v5eq3vtpk.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1trcbzm894v5eq3vtpk.png)

Trong tệp `prompt_builder.py` của bạn, chọn một mẫu A2UI đại diện (ví dụ: một biểu mẫu hoặc danh sách đơn giản). Đây là những gì agent sẽ học để phát ra:

<span style="color: #f92672;">UI_EXAMPLES</span> <span style="color: #f92672; font-weight: bold;">=</span> <span style="color: #e6db74;">"""</span>
<span style="color: #e6db74;">---BEGIN FORM_EXAMPLE---</span>
<span style="color: #e6db74;">[</span>
<span style="color: #e6db74;">  { "beginRendering": { "surfaceId": "form-surface", "root": "form-column",</span>
<span style="color: #e6db74;">                        "styles": { "primaryColor": "#9B8AFF", "font": "Plus Jakarta Sans" } } },</span>
<span style="color: #e6db74;">  { "surfaceUpdate": {</span>
<span style="color: #e6db74;">      "surfaceId": "form-surface",</span>
<span style="color: #e6db74;">      "components": [</span>
<span style="color: #e6db74;">        { "id": "form-column", "component": { "Column": {</span>
<span style="color: #e6db74;">            "children": { "explicitList": ["form-title", "name-field", "submit-button"] }</span>
<span style="color: #e6db74;">        } } },</span>
<span style="color: #e6db74;">        { "id": "form-title", "component": { "Text": {</span>
<span style="color: #e6db74;">            "usageHint": "h2", "text": { "literalString": "Contact Us" }</span>
<span style="color: #e6db74;">        } } },</span>
<span style="color: #e6db74;">        { "id": "name-field", "component": { "TextField": {</span>
<span style="color: #e6db74;">            "label": { "literalString": "Your Name" },</span>
<span style="color: #e6db74;">            "text": { "path": "name" },</span>
<span style="color: #e6db74;">            "textFieldType": "shortText"</span>
<span style="color: #e6db74;">        } } },</span>
<span style="color: #e6db74;">        { "id": "submit-button", "component": { "Button": {</span>
<span style="color: #e6db74;">            "child": "submit-text", "primary": true,</span>
<span style="color: #e6db74;">            "action": { "name": "submit_form", "context": [</span>
<span style="color: #e6db74;">              { "key": "name", "value": { "path": "name" } }</span>
<span style="color: #e6db74;">            ] }</span>
<span style="color: #e6db74;">        } } },</span>
<span style="color: #e6db74;">        { "id": "submit-text", "component": { "Text": {</span>
<span style="color: #e6db74;">            "text": { "literalString": "Send Message" }</span>
<span style="color: #e6db74;">        } } }</span>
<span style="color: #e6db74;">      ]</span>
<span style="color: #e6db74;">    }</span>
<span style="color: #e6db74;">  },</span>
<span style="color: #e6db74;">  { "dataModelUpdate": {</span>
<span style="color: #e6db74;">      "surfaceId": "form-surface", "path": "/", "contents": [</span>
<span style="color: #e6db74;">        { "key": "name", "valueString": "" }</span>
<span style="color: #e6db74;">      ]</span>
<span style="color: #e6db74;">    }</span>
<span style="color: #e6db74;">  }</span>
<span style="color: #e6db74;">]</span>
<span style="color: #e6db74;">---END FORM_EXAMPLE---</span>
<span style="color: #e6db74;">"""</span>

Khối JSONL này định nghĩa một biểu mẫu “Contact Us” trong A2UI. Bạn cung cấp nó cho agent để nó học cách phát ra ba phong bì tin nhắn mà A2UI mong đợi: `surfaceUpdate` (các thành phần), `dataModelUpdate` (trạng thái), sau đó `beginRendering` (tín hiệu kết xuất).

Sau đó, thêm `UI_EXAMPLES` vào lời nhắc hệ thống mà agent sử dụng:

<span style="color: #66d9ef;">if</span> <span style="color: #f92672;">use_ui</span><span style="color: #f92672; font-weight: bold;">:</span>
<span style="color: #66d9ef;">    instruction = AGENT_INSTRUCTION + get_ui_prompt(self.base_url, UI_EXAMPLES)</span>
<span style="color: #66d9ef;">else</span><span style="color: #f92672; font-weight: bold;">:</span>
<span style="color: #66d9ef;">    instruction = get_text_prompt()</span>

<span style="color: #66d9ef;">return LlmAgent(</span>
<span style="color: #66d9ef;">    model=LiteLlm(model=LITELLM_MODEL),</span>
<span style="color: #66d9ef;">    name="ui_generator_agent",</span>
<span style="color: #66d9ef;">    description="Generates dynamic UI via A2UI declarative JSON.",</span>
<span style="color: #66d9ef;">    instruction=instruction,</span>
<span style="color: #66d9ef;">    tools=[],</span>
<span style="color: #66d9ef;">)</span>

Bằng cách nối `UI_EXAMPLES` (và lược đồ A2UI) vào hướng dẫn của agent, bạn đảm bảo nó sẽ truyền về JSON hợp lệ dựa trên các mẫu của bạn bất cứ khi nào người dùng yêu cầu một UI.

Bước cuối cùng là sử dụng `createA2UIMessageRenderer`, nhận JSON A2UI của agent và chủ đề của bạn, sau đó `renderActivityMessages` yêu cầu CopilotKit sử dụng nó khi kết xuất tin nhắn chat.

<span style="color: #66d9ef;">import { CopilotKitProvider, CopilotSidebar } from "@copilotkitnext/react";</span>
<span style="color: #66d9ef;">import { createA2UIMessageRenderer } from "@copilotkit/a2ui-renderer";</span>
<span style="color: #66d9ef;">import { a2uiTheme } from "../theme";</span>

<span style="color: #66d9ef;">// Instantiate the A2UI renderer once with your theme</span>
<span style="color: #66d9ef;">const A2UIRenderer = createA2UIMessageRenderer({ theme: a2uiTheme });</span>

<span style="color: #66d9ef;">export function A2UIPage({ children }: { children: React.ReactNode }) {</span>
<span style="color: #66d9ef;">  return (</span>
<span style="color: #66d9ef;">    <CopilotKitProvider</span>
<span style="color: #66d9ef;">      runtimeUrl="/api/copilotkit-a2ui"</span>
<span style="color: #66d9ef;">      renderActivityMessages={[A2UIRenderer]}   <span style="color: #66d9ef;">// <-- hook in the A2UI renderer</span>
      showDevConsole={false}
    >
      {children}
      <CopilotSidebar defaultOpen labels={{ modalHeaderTitle: "A2UI Assistant" }} />
    </CopilotKitProvider>
  );
}

[![Image 7: a2ui demo output](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w2t5bbhe0oo0c63vzit.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w2t5bbhe0oo0c63vzit.png)

Kho lưu trữ môi trường thử nghiệm (playground repo) được thiết lập cho A2UI, nhưng mô hình này tương tự đối với Open‑JSON‑UI.

Một agent có thể phản hồi bằng một payload JSON mô tả một “thẻ” UI, và frontend sẽ kết xuất nó.

<span style="color: #66d9ef;">// Example: Agent returns Open-JSON-UI specification</span>
<span style="color: #66d9ef;">{</span>
<span style="color: #66d9ef;">  type: "open-json-ui",</span>
<span style="color: #66d9ef;">  spec: {</span>
<span style="color: #66d9ef;">    components: [</span>
<span style="color: #66d9ef;">      {</span>
<span style="color: #66d9ef;">        type: "card",</span>
<span style="color: #66d9ef;">        properties: {</span>
<span style="color: #66d9ef;">          title: "Data Visualization",</span>
<span style="color: #66d9ef;">          content: {...}</span>
<span style="color: #66d9ef;">        }</span>
<span style="color: #66d9ef;">      }</span>
<span style="color: #66d9ef;">    ]</span>
<span style="color: #66d9ef;">  }</span>
<span style="color: #66d9ef;">}</span>

[![Image 8: Open-JSON-UI output](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfr29hdu1o8sd13vet2z.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfr29hdu1o8sd13vet2z.png)

Bạn có thể kiểm tra tổng quan các đặc tả tại docs.copilotkit.ai/generative-ui/specs/open-json-ui để hiểu cách giao thức AG-UI của CopilotKit hỗ trợ nguyên bản Open-JSON-UI.

Mô hình này là một lựa chọn tốt nếu bạn cần sự linh hoạt hơn so với UI tĩnh, trong khi vẫn giữ ranh giới rõ ràng và kết xuất có thể dự đoán được.

✅ Open-ended Generative UI (MCP Apps)

Open-ended Generative UI là mô hình linh hoạt và mạnh mẽ nhất.

Trong mô hình này, agent trả về toàn bộ một bề mặt UI. Điều này có thể là HTML, một iframe hoặc nội dung dạng tự do khác. Frontend chủ yếu hoạt động như một vùng chứa hiển thị bất cứ thứ gì agent cung cấp.

Cách tiếp cận này thường được sử dụng với MCP Apps, nơi các ứng dụng bên ngoài hiển thị UI riêng của họ có thể được nhúng vào trải nghiệm của agent.

Các công cụ MCP truyền thống trả về văn bản, hình ảnh, tài nguyên hoặc dữ liệu có cấu trúc mà máy chủ hiển thị như một phần của cuộc trò chuyện. MCP Apps mở rộng mô hình này bằng cách cho phép các công cụ khai báo tham chiếu đến một UI tương tác trong mô tả công cụ của chúng mà máy chủ sẽ kết xuất tại chỗ.

[![Image 9: mcp apps](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohm99984zfbh4mj7lnl8.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohm99984zfbh4mj7lnl8.png)

Những đánh đổi là có thật. Việc kết xuất UI tùy ý mang đến các lo ngại về bảo mật và hiệu suất, kiểu dáng không nhất quán và khó khăn hơn trong việc di chuyển bên ngoài web.

Nhưng đối với các công cụ phức tạp và ứng dụng phong phú, mô hình này mở khóa các khả năng không thể thực hiện được chỉ với UI tĩnh hoặc khai báo.

Trong CopilotKit, hỗ trợ MCP Apps được kích hoạt bằng cách đính kèm `MCPAppsMiddleware` vào agent của bạn, cho phép runtime kết nối với một hoặc nhiều máy chủ MCP Apps.

<span style="color: #66d9ef;">// app/api/copilotkit/route.ts</span>
<span style="color: #66d9ef;">import {</span>
<span style="color: #66d9ef;">  CopilotRuntime,</span>
<span style="color: #66d9ef;">  ExperimentalEmptyAdapter,</span>
<span style="color: #66d9ef;">  copilotRuntimeNextJSAppRouterEndpoint,</span>
<span style="color: #66d9ef;">} from "@copilotkit/runtime";</span>
<span style="color: #66d9ef;">import { BuiltInAgent } from "@copilotkit/runtime/v2";</span>
<span style="color: #66d9ef;">import { NextRequest } from "next/server";</span>
<span style="color: #66d9ef;">import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";</span>

<span style="color: #66d9ef;">// 1. Create your agent and add the MCP Apps middleware</span>
<span style="color: #66d9ef;">const agent = new BuiltInAgent({</span>
<span style="color: #66d9ef;">  model: "openai/gpt-4o",</span>
<span style="color: #66d9ef;">  prompt: "You are a helpful assistant.",</span>
<span style="color: #66d9ef;">}).use(</span>
<span style="color: #66d9ef;">   new MCPAppsMiddleware({</span>
<span style="color: #66d9ef;">    mcpServers: [</span>
<span style="color: #66d9ef;">      {</span>
<span style="color: #66d9ef;">        type: "http",</span>
<span style="color: #66d9ef;">        url: "http://localhost:3108/mcp",</span>
<span style="color: #66d9ef;">        serverId: "my-server" <span style="color: #66d9ef;">// Recommended: stable identifier</span>
      },
    ],
  }),
)

<span style="color: #66d9ef;">// 2. Create a service adapter, empty if not relevant</span>
<span style="color: #66d9ef;">const serviceAdapter = new ExperimentalEmptyAdapter();</span>

<span style="color: #66d9ef;">// 3. Create the runtime and add the agent</span>
<span style="color: #66d9ef;">const runtime = new CopilotRuntime({</span>
<span style="color: #66d9ef;">  agents: {</span>
<span style="color: #66d9ef;">    default: agent,</span>
<span style="color: #66d9ef;">  },</span>
<span style="color: #66d9ef;">});</span>

<span style="color: #66d9ef;">// 4. Create the API route</span>
<span style="color: #66d9ef;">export const POST = async (req: NextRequest) => {</span>
<span style="color: #66d9ef;">  const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({</span>
<span style="color: #66d9ef;">    runtime,</span>
<span style="color: #66d9ef;">    serviceAdapter,</span>
<span style="color: #66d9ef;">    endpoint: "/api/copilotkit",</span>
<span style="color: #66d9ef;">  });</span>

<span style="color: #66d9ef;">  return handleRequest(req);</span>
<span style="color: #66d9ef;">};</span>

Bạn có thể tìm thấy GitHub Repo cho việc triển khai mã hoàn chỉnh, và kiểm tra toàn bộ luồng tích hợp trong bài blog này.

Cách AG-UI Kích Hoạt Generative UI Tại Thời Điểm Chạy

Trong tất cả ba mô hình, AG-UI (Agent-User Interaction Protocol) đóng vai trò là lớp tương tác runtime cơ bản trong CopilotKit. Nó cung cấp một kết nối hai chiều giữa agent và ứng dụng, làm cho Generative UI hoạt động.

Điều quan trọng cần lưu ý là AG-UI không phải là một đặc tả UI. Nó là một giao thức sự kiện/trạng thái định nghĩa cách các cập nhật UI, trạng thái agent và tương tác người dùng diễn ra trong khi agent đang hoạt động.

Ở cấp độ cao, AG-UI xử lý:

  • Vòng đời của công cụ (đã bắt đầu → đang truyền → đã hoàn thành / thất bại)
  • Tương tác người dùng (nhấp chuột, gửi biểu mẫu, lựa chọn)
  • Cập nhật trạng thái agent (tiến độ, kết quả một phần, các bước tiếp theo)
  • Phối hợp thời gian thực giữa agent ↔ UI ↔ ứng dụng

Ví dụ, đây là vai trò của giao thức AG-UI trong các mô hình Generative UI:

  • Tĩnh → báo hiệu vòng đời công cụ → frontend kết xuất các thành phần được định nghĩa trước.
  • Khai báo → mang các đặc tả UI + trạng thái → frontend kết xuất UI có cấu trúc.
  • Mở → phối hợp các công cụ + tham chiếu UI → ứng dụng nhúng UI bên ngoài.

Bởi vì AG-UI nằm bên dưới các đặc tả như A2UI, Open-JSON-UI và MCP Apps, CopilotKit có thể hỗ trợ nhiều cách tiếp cận Generative UI mà không khóa bạn vào một cách tiếp cận duy nhất.

[![Image 10: AG-UI as bidirectional runtime interaction layer](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0mkn6anm4f4g8pp4cbl.png)](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0mkn6anm4f4g8pp4cbl.png)

Kết Luận

Trong nhiều trường hợp, nút thắt thực sự nằm ở giao diện giữa agent và người dùng. Generative UI cung cấp một con đường thực tế để tiến lên, và một khi bạn tự xây dựng một trong những mô hình này, bạn sẽ thấy rõ cách tiếp cận nào phù hợp với vấn đề nào.

Hy vọng bạn đã học được điều gì đó có giá trị. Chúc bạn một ngày tốt lành!

Bạn có thể xem các dự án của tôi tại anmolbaranwal.com. Cảm ơn bạn đã đọc! 🥰
Twitter


GitHub


LinkedIn

Đừng quên theo dõi CopilotKit trên Twitter và tham gia cộng đồng các nhà xây dựng agent trên Discord.

Chúc bạn xây dựng thành công!


CopilotKit

Theo Dõi CopilotKit

React UI + cơ sở hạ tầng thanh lịch cho AI Copilots, các agent AI trong ứng dụng, chatbot AI và các Textareas được hỗ trợ bởi AI 🪁

Chỉ mục