# CopilotKit - The frontend stack for Agent

CopilotKit (opens new window) 是面向 Agent 应用的前端栈。它不只是聊天 UI,更关注 Agent 如何接入应用,比如读取页面上下文、调用前端工具、渲染真实 React 组件,以及在需要时暂停等待用户审批。

可以把 CopilotKit 理解成:把 Agent 接到产品上的一套标准能力,而不是单纯再包一层 Chat 组件。

核心能力如下:

产品能力 说明
Chat UI 可嵌入页面、侧边栏、浮窗的对话界面
Generative UI Agent 调用工具时,在聊天里渲染真实的 React 组件,而不是只吐文本
Shared State 应用状态与 Agent 状态双向同步
Human-in-the-Loop Agent 中途停下来,等人审批、选择、填表后再继续
Frontend Tools Agent 直接调用浏览器里的函数(改 UI、读当前页面、操作本地状态)
Headless UI 不要预置皮肤时,可以定制自己的 UI
Any Agent 后端只要支持 AG-UI,都可以接入

CopilotKit 当前版本 v1.68.1

# 我的应用

我使用 CopilotKit 创建了一个 UI Design Studio Project (opens new window)。效果如下:

使用 Next.js + CopilotKit,实现左侧实时预览登录页,右侧侧边栏开启 agent 对话,agent 可改页面设计。

# 架构

CopilotKit 采用三层结构:FrontendRuntimeAgent,中间用 AG-UI (opens new window) 事件协议连接。更多详情,请参考 Architecture (opens new window)

# 三层职责

Frontend

框架原生 SDK,加上预置聊天组件 CopilotChat / CopilotSidebar / CopilotPopup。可以通过插槽的方式修改内部组件,甚至可以完全定制(Headless UI).

Runtime

挂在应用服务器(Next.js、Express、Hono、Bun、Deno、Workers)上的请求处理程序。可以负责鉴权、工具调用转发、AG-UI 数据流等。

Agent

任意 AG-UI 兼容后端。可以是内置的 BuiltInAgent,也可以是 LangGraph、Mastra、CrewAI、Pydantic AI、Microsoft Agent Framework。它负责跑 prompt、调用工具、发出状态,并把事件流式传回 Runtime。

# 请求过程

一句话概括:用户说话 → 前端 POST 到 Runtime → Runtime 驱动 Agent → 事件经 SSE 流回前端。

如果工具定义在浏览器里,Runtime 会把调用转发到前端,执行完再把结果送回 Agent。

# 集成 CopilotKit

# 手动集成

# 内置模型

CopilotKit 天然支持 OpenAI、Anthropic、Google Gemini、MiniMax。下面以 Next.js + BuiltInAgent 为例,更多详情,请参考 Quickstart (opens new window)

前置条件

  1. 安装依赖
$ npm install @copilotkit/react-core @copilotkit/runtime
1
  1. 配置环境变量
# .env
OPENAI_API_KEY=your_openai_api_key
1
2
  1. 创建 Copilot Runtime(API Route)

app/api/copilotkit/route.ts 里配置 BuiltInAgentCopilotRuntime。模型用内置字符串即可:

import {
  CopilotRuntime,
  createCopilotRuntimeHandler,
} from "@copilotkit/runtime";
import { BuiltInAgent } from "@copilotkit/runtime/v2";
import { NextRequest } from "next/server";

const builtInAgent = new BuiltInAgent({
  model: "openai:gpt-5.4-mini",
});

const runtime = new CopilotRuntime({
  agents: { default: builtInAgent },
});

export const POST = async (req: NextRequest) => {
  const { handleRequest } = createCopilotRuntimeHandler({
    runtime,
    endpoint: "/api/copilotkit",
  });

  return handleRequest(req);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

BuiltInAgent 底层用的是 Vercel AI SDK,内置 openai:anthropic:google:minimax:模型前缀。更多详情,请参考 Model Selection (opens new window)

  1. 配置 CopilotKit Provider

app/layout.tsx 里用 CopilotKit 包裹应用:

import { CopilotKit } from "@copilotkit/react-core/v2";
import "@copilotkit/react-core/v2/styles.css";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <CopilotKit runtimeUrl="/api/copilotkit">
          {children}
        </CopilotKit>
      </body>
    </html>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  1. 添加聊天界面
import { CopilotSidebar } from "@copilotkit/react-core/v2";

export default function Page() {
  return (
    <main>
      <h1>Your App</h1>
      <CopilotSidebar />
    </main>
  );
}
1
2
3
4
5
6
7
8
9
10
  1. 启动
$ npm run dev
1

到这里已经可以对话了。

# 接入其他模型

任何 OpenAI 兼容 API,都可以用 @ai-sdk/openai-compatible@ai-sdk/openaicreateOpenAI({ baseURL }) 包一层,再交给 BuiltInAgent

下面以千问为例说明怎么接入其他模型。更多详情,请参考 Model Selection - Custom Models (AI SDK) (opens new window)

  1. 安装 AI SDK provider
$ npm install @ai-sdk/openai-compatible
1
  1. 配置千问环境变量

阿里云百炼(DashScope)提供 OpenAI 兼容接口。复制 .env.example.env

# 阿里云百炼:https://bailian.console.aliyun.com/
DASHSCOPE_API_KEY=sk-...
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
DASHSCOPE_MODEL=qwen-plus
DASHSCOPE_ENABLE_THINKING=true   # 设为 false 可关闭思考链
1
2
3
4
5
  1. 封装模型
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";

export const QWEN_MODEL_ID = process.env.DASHSCOPE_MODEL;

const dashscope = createOpenAICompatible({
  name: "qwen",
  apiKey: process.env.DASHSCOPE_API_KEY,
  baseURL: process.env.DASHSCOPE_BASE_URL,
  includeUsage: true,
  transformRequestBody: (body) => ({
    ...body,
    enable_thinking: process.env.DASHSCOPE_ENABLE_THINKING !== "false",
    incremental_output: true,
  }),
});

export const qwen = dashscope.chatModel(QWEN_MODEL_ID);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  1. Runtime 里使用千问
import {
  BuiltInAgent,
  CopilotRuntime,
  createCopilotRuntimeHandler,
} from "@copilotkit/runtime/v2";
import { qwen } from "@/lib/qwen";

const agent = new BuiltInAgent({
  model: qwen, // 传入 LanguageModel
  maxSteps: 8,
  tools: agentTools,
  prompt: "...",
});

const runtime = new CopilotRuntime({
  agents: {
    default: agent,
  },
});

const handler = createCopilotRuntimeHandler({
  runtime,
  basePath: "/api/copilotkit",
});

export const GET = handler;
export const POST = handler;
export const OPTIONS = handler;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# CopilotKit CLI

上面是手动集成:自己装依赖、写 Runtime、配 Provider。如果想从零快速搭一个可跑的示例项目,也可以用官方 CLI:

$ npx copilotkit@latest create
1

执行后会进入交互式向导,按提示选择项目名称、Agent 框架、前端模板等,生成一套已经接好 CopilotKit 的脚手架。

  1. 输入项目名称

  2. 选择智能体框架

    Copilotkit 提供了 21 agent framework,供我们选择。下面是这 21 个 agent framework 的简单介绍

分类 选项 简介
LangGraph 系列 🦜 LangGraph (Python) Python 版 LangGraph,官方文档称功能覆盖最全,HITL、checkpoint 支持最成熟
🦜 LangGraph (JavaScript) TS/JS 版 LangGraph,走 AG-UI adapter,纯前端技术栈可用
Claude 系 🔆 Claude Agent SDK (TypeScript) 基于 Anthropic Claude Agent SDK 的 TS 模板
🔆 Claude Agent SDK (Python) 同上的 Python 版,官方标注支持生成式 UI、共享状态、HITL、子 agent、流式输出全特性
其他 Python/TS 框架 🌑 Mastra TypeScript 原生 agent 框架,自带 tools/memory/workflow
🔼 Pydantic AI 基于 Pydantic 的类型化 Python agent 框架
🧬 AWS Strands (Python) AWS Strands agent,Python 版(不经 AgentCore 部署)
Google ADK 相关 🤖 ADK Google Agent Development Kit,Gemini 驱动,经 AG-UI 接入
🔺 Angular + ADK ADK 的 Angular 前端模板(其余大多数模板默认是 React/Next.js)
微软相关 🟦 Microsoft Agent Framework (.NET) MS Agent Framework 的 .NET 实现
🟦 Microsoft Agent Framework (Python) MS Agent Framework 的 Python 实现
协议/生态 🧩 MCP Apps 基于 Model Context Protocol 的 App 集成模板,可把 MCP 工具服务器接入生成式 UI
🤖 A2A Agent-to-Agent 协议模板,用于多 agent 间互通
多 Agent 编排 👥 CrewAI Flows CrewAI 的 Flow(流程编排)模式,比 Crew 更强调确定性步骤控制
🦙 LlamaIndex LlamaIndex workflow 接入 CopilotKit
🧠 Agno 带 tools、state、生成式 UI 示例的轻量 agent 框架
🤖 AG2 支持 chat、tools、HITL 流程的多 agent 框架(原 AutoGen)
AWS AgentCore 部署 ⛅ AgentCore + LangGraph 部署到 AWS Bedrock AgentCore 的 LangGraph 模板,含 CDK 基础设施和一键部署脚本
⛅ AgentCore + Strands 部署到 AWS Bedrock AgentCore 的 Strands 模板,同样含完整部署脚本
生成式 UI 专用 🎨 A2UI Agent-to-UI 模板,agent 直接描述/驱动 UI 结构,适合动态表单类场景
✨ Open Generative UI 专为生成式 UI 优化的模板,配套 useComponent 等 hook,直接渲染真实 React 组件

因为我对 JavaScript 比较熟悉,所以我选择 LangGraph (JavaScript)

  1. 创建 CopilotKit 账号,如果已经有了账号,直接进行验证

  2. 创建或连接一个 Intelligence project

这一步是在问:这套 App 的聊天记录,要存到云端的哪个「项目」里?

可以把它想成 ChatGPT 的历史会话存放处。一个 Intelligence project 就是 CopilotKit 云端的一个小仓库,专门存这套 App 的对话历史(threads)、消息和分析数据。不接的话,聊天只活在当前浏览器里,一刷新就没了;接上之后,关掉页面再打开还能继续聊,换设备也能找回。

刚开始随便新建一个就行。后面如果有正式环境、测试环境,再分开建,免得聊天记录混在一起。更多说明见 Cloud-Hosted Enterprise Intelligence (opens new window)

  1. 选择 Channel,可以先跳过

这一步是在问:要不要把 Agent 接到 Slack、Teams 这类聊天工具里?

Channel 的意思是:用户不用打开你的网页,直接在 Slack / Teams 里跟 Agent 对话。CopilotKit 负责对接这些平台,消息转给你的 Agent,回复再发回对应的频道。刚搭脚手架、只想先在网页里试跑时,这一步可以跳过,以后要用再配。更多说明见 Channels (opens new window)

  1. 设置 OPENAI_API_KEY,如果暂时没有,也可以先跳过。

向导结束后,CLI 会生成项目并安装依赖。进入目录后启动开发服务即可:

$ cd <your-app-name>
$ npm run dev
1
2

之后按提示补上 API Key、按需配置 Channel 或 Intelligence,就可以在浏览器里试对话了。

CLI 适合快速摸清整套结构;真正接到自己的业务里,还是要回到前面的手动集成。

# 组件与 Hook

完整 API 见 References (opens new window),选型可参考 Which Hook for Which Job (opens new window)

# 组件一览

组件 功能
CopilotKit 应用根 Provider,连接 Runtime,提供 Agent 注册表与全局上下文
CopilotChat 开箱即用的完整聊天界面,自动绑定 Agent、管理消息与运行态
CopilotSidebar 侧栏形态聊天,固定面板 + 开关按钮,适合与主内容并排
CopilotPopup 浮窗形态聊天,右下角唤起,不占主布局
CopilotThreadsDrawer 会话抽屉,列出 / 切换 / 重命名 / 归档 / 删除历史对话
CopilotChatMessageView 消息列表,按角色渲染 assistant / user / reasoning 等
CopilotChatAssistantMessage 单条助手消息:Markdown、工具调用、复制 / 重新生成等操作
CopilotChatReasoningMessage 推理消息组件,用于展示模型 thinking/reasoning 的折叠内容
CopilotChatUserMessage 单条用户消息:附件、编辑、多分支回复切换
CopilotChatView 聊天布局核心:消息区 + 输入区 + 建议 + 欢迎屏,支持 slot 定制
CopilotChatInput 输入区:文本、发送、附件、语音转写等

# Hook一览

Hook 功能
useAgent 访问 AG-UI Agent 实例:消息、状态、运行态、事件订阅、主动触发 run
useAgentContext 把应用内的可序列化状态注册为 Agent 上下文(当前页面、选中项等)
useFrontendTool 注册在浏览器执行的前端工具,Agent 可调用并可选 inline 渲染 UI
useHumanInTheLoop 交互式前端工具,Agent 暂停等人操作后再继续(审批、选方案、填表)
useInterrupt 处理 Agent 运行时级中断,用户 resolve / cancel 后恢复或取消
useConfigureSuggestions 配置空会话或特定时机展示的建议胶囊文案
useSuggestions 读取当前可用的建议列表
useCopilotChatConfiguration 读写聊天文案、agentIdthreadId、弹层开关等 UI 配置
useCopilotKit 底层 CopilotKit 实例,用于连接状态、runTool 等进阶控制
useCapabilities 读取 Agent 声明的能力,按能力动态开关 UI 功能
useThreads 管理会话 thread:列表、重命名、归档、删除、分页与实时同步
useRenderTool 为指定工具名(或通配符)注册工具调用的展示 UI
useDefaultRenderTool 为未单独注册 renderer 的工具提供默认展示 UI
useComponent 把 React 组件注册为工具 renderer,Agent 调用时在聊天里渲染该组件
useRenderToolCall Headless 场景下获取工具调用的渲染函数,自行嵌入自定义聊天布局

# Hook 详解

真正把 Agent「接到产品」上的,通常是下面几个 Hook。

# useFrontendTool

useFrontendTool 在浏览器里注册工具。Agent 调用后,handler 在客户端执行,可以直接读写 React 状态、改 UI。

例如我做的登录页设计助手,可以注册两个工具:读当前配置、修改设计。

读配置 getDesignConfig

useFrontendTool({
  name: "getDesignConfig",
  description:
    "Read the current login page design configuration. Call this first to understand the current state before making changes.",
  parameters: z.object({}),
  handler: async () => config, // 返回当前 LoginDesignConfig
});
1
2
3
4
5
6
7

改设计 updateDesign

useFrontendTool({
  name: "updateDesign",
  description:
    "Update login page design properties. Only include the fields you want to change.",
  parameters: z.object({
    brandColor: z.string().optional(),
    backgroundColor: z.string().optional(),
    layout: z.enum(["center", "left", "split"]).optional(),
    // ... 其它可选字段:title、cardStyle、showSocialLogin 等
  }),
  handler: async (patch) => {
    onUpdateDesign(patch); // 更新画布上的登录页预览
    return { success: true, updated: Object.keys(patch) };
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

用户说「改成暗色主题」时,Agent 会先调 getDesignConfig,再调 updateDesign,左侧预览随即变化——这就是前端工具把 Agent 接到产品 UI 的典型路径。

# useComponent

useComponent 让 Agent 通过调用工具的方式,直接在聊天中渲染 React 组件。

参考 Tool-based Generative UI (opens new window)

定义工具:

useComponent({
  name: "render_bar_chart",
  description: "Display a bar chart with labeled numeric values.",
  parameters: barChartPropsSchema,
  render: BarChart,
});
1
2
3
4
5
6

实现效果:

实现流程:

# useRenderTool

useRenderTool 只负责渲染,不注册 handler。工具可以是前端定义的,也可以是服务端定义的。

参考 Tool-based Generative UI (opens new window)

get_weather 为例:按城市展示一张天气卡片。

import { useRenderTool } from "@copilotkit/react-core/v2";
import { z } from "zod";

useRenderTool(
  {
    name: "get_weather",
    parameters: z.object({
      city: z.string().describe("City name"),
      units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
    }),
    render: ({ parameters, status, result }) => {
      if (status === "inProgress" || status === "executing") {
        return <div>正在查询 {parameters.city} 的天气…</div>;
      }
      if (status === "complete" && result) {
        const data = typeof result === "string" ? JSON.parse(result) : result;
        return (
          <div className="my-3 overflow-hidden rounded-2xl border border-sky-100 bg-linear-to-br from-[#e8f4ff] via-white to-[#f0f9ff] p-4 shadow-sm">
            <div className="flex items-start justify-between gap-3">
              <div className="min-w-0">
                <p className="text-[12px] font-medium tracking-wide text-sky-700/80">实时天气</p>
                <h3 className="mt-0.5 truncate text-[17px] font-semibold text-slate-800">
                  {weather.city}
                  {weather.country ? (
                    <span className="ml-1.5 text-[12px] font-normal text-slate-400">{weather.country}</span>
                  ) : null}
                </h3>
              </div>
              <WeatherGlyph icon={weather.icon} />
            </div>

            <div className="mt-3 flex items-end gap-2">
              <span className="text-[40px] font-semibold leading-none tracking-tight text-slate-900">
                {Math.round(weather.temperature)}
                <span className="text-[22px] font-medium">°</span>
              </span>
              <div className="mb-1 space-y-0.5">
                <p className="text-[14px] font-medium text-slate-700">{weather.condition}</p>
                <p className="text-[12px] text-slate-500">
                  体感 {Math.round(weather.apparentTemperature)}° · 今日 {Math.round(weather.low)}° /{" "}
                  {Math.round(weather.high)}°
                </p>
              </div>
            </div>

            <div className="mt-4 grid grid-cols-3 gap-2">
              <Metric label="湿度" value={`${Math.round(weather.humidity)}%`} />
              <Metric label="风速" value={`${Math.round(weather.windSpeed)} km/h`} />
              <Metric label="时区" value={shortTimezone(weather.timezone)} />
            </div>
          </div>
        );
      }
      return null;
    },
  },
  [],
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

渲染效果:

未单独注册 renderer 的工具,可用 name: "*" 通配,或使用 useDefaultRenderTool 做兜底。

# useHumanInTheLoop

useHumanInTheLoop 注册的是等人回复的前端工具。Runtime / Agent 会停在工具调用上;用户操作后通过 respond 把结果送回,Agent 再继续。

useHumanInTheLoop({
  name: "askUserToChoose",
  description:
    "Present design options to the user and wait for them to pick one. " +
    "Use this when choosing a color scheme, layout, or feature to include/exclude.",
  parameters: z.object({
    question: z.string().describe("The question to ask"),
    options: z
      .array(
        z.object({
          label: z.string(),
          value: z.string(),
          description: z.string().optional(),
        }),
      )
      .min(2)
      .max(6),
  }),
  render: ({ status, args, respond }) => (
    <div className="my-3 rounded-lg border bg-white p-4">
      <p className="mb-3 text-[13px] font-medium">{args.question}</p>
      <div className="flex flex-wrap gap-2">
        {(args.options ?? []).map((opt) => (
          <button
            key={opt.value}
            type="button"
            disabled={status !== "executing"}
            onClick={() => respond?.({ chosen: opt.value, label: opt.label })}
          >
            {opt.label}
          </button>
        ))}
      </div>
      {status === "complete" && (
        <p className="mt-2 text-[11px] text-gray-400">✓ 已选择</p>
      )}
    </div>
  ),
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# Runtime

Runtime 是挂在你自己应用服务器上的请求处理程序。常见挂载点是 Next.js 的 /api/copilotkit,也可以是 Express、Hono、Bun、Deno、Cloudflare Workers。

可以把它想成:前端和 Agent 之间的接线盒

前端不直接连 LangGraph / BuiltInAgent;消息先打到 Runtime,再由 Runtime 转给 Agent,并把 Agent 吐出的 AG-UI 事件流回浏览器。API Key、鉴权、前端工具转发,也通常在这一层做。

# 职责

职责 说明
接请求 接收前端的 POST(消息、agentIdthreadId、状态等)
选 Agent 按配置找到对应的 Agent(比如 default),打开一次 AG-UI run
转事件流 把 Agent 的文本、工具调用、状态更新等事件流式回前端
中转前端工具 Agent 要调浏览器里的工具时,Runtime 把调用转给前端,再把结果送回 Agent
可选鉴权 / 持久化 校验身份;需要会话历史时,再接到 Intelligence 等平台

# 核心代码

核心就两样:

  • CopilotRuntime - 加载 Agent

  • createCopilotRuntimeHandler - 把它挂成 HTTP handler

import {
  BuiltInAgent,
  CopilotRuntime,
  createCopilotRuntimeHandler,
} from "@copilotkit/runtime/v2";

const runtime = new CopilotRuntime({
  agents: {
    default: new BuiltInAgent({ model: "openai:gpt-5.4-mini" }),
  },
});

const handler = createCopilotRuntimeHandler({
  runtime,
  basePath: "/api/copilotkit",
});

export const GET = handler;
export const POST = handler;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Agent

Agent 是真正「思考和行动」的那一层:跑 prompt、决定调哪些工具、发出状态,再通过 AG-UI 把事件流回 Runtime。

在 CopilotKit 里,Agent 不绑死某一种框架,只要支持 AG-UI。

一句话:Agent 决定「会什么」;Runtime 决定「怎么接到你的 App」;Frontend 决定「用户看见什么」。

# 常见选择

类型 是什么 适合谁
BuiltInAgent CopilotKit 内置,进程内跑,底层常用 Vercel AI SDK 想最快跑通、逻辑不复杂
LangGraph / Mastra / CrewAI 等 外部 Agent 框架,经 AG-UI adapter 接入 已有编排、多步工作流、团队栈已定
自研 AG-UI Agent 自己实现协议事件流 要完全掌控后端

前面「手动集成」用的就是 BuiltInAgent,和 Runtime 同进程,不用再起一个独立 Agent 服务。

CLI 里选 LangGraph (JavaScript) 等,则是脚手架出外部 Agent + adapter。

# 核心代码

const agent = new BuiltInAgent({
  model: "openai:gpt-5.4-mini", // 或传入自定义 LanguageModel(如千问)
  prompt: "You are a helpful assistant...",
  tools: agentTools,            // 服务端工具
  maxSteps: 8,
});
1
2
3
4
5
6

# AG-UI

AG-UI (opens new window) 全称 Agent–User Interaction Protocol,是一套开放的、基于事件的协议,用来标准化「Agent 后端」和「应用」怎么对话。可以把它想成:Agent 和前端之间的 USB-C

没有它时,每个 Agent 框架(LangGraph、Mastra、CrewAI……)输出格式都不一样,前端要为每种后端单独写对接。有了 AG-UI,后端只要按约定往外发送事件流,前端(比如 CopilotKit)统一监听这些事件:流式文字、工具调用、状态同步、等人审批,都能用同一套语义处理。

所以 CopilotKit 宣传的「Any Agent」——后端只要支持 AG-UI 就能接入——靠的就是这层协议。

# 和 MCP、A2A 的关系

它们不是互相替代,而是各管一段连接:

协议 连谁 一句话
AG-UI Agent ↔ 用户 / 应用 怎么把 Agent 接到界面上:流式回复、工具 UI、共享状态、人工审批
MCP Agent ↔ 工具 / 数据 怎么让 Agent 调用外部能力:文件、数据库、搜索、API
A2A Agent ↔ Agent 怎么让多个 Agent 互相发现、分工、协作

一个完整的 Agent 产品里,常见组合是:对内用 MCP 干活,对外用 AG-UI 对人,需要多 Agent 协作时再上 A2A。

另外别和 A2UI 搞混:A2UI 更偏向「Agent 怎么描述要渲染的 UI」;AG-UI 是「Agent 和前端怎么通信」。两者可以一起用。

# 怎么工作

核心很简单:Agent 跑一次 run,就持续发出一串类型化事件;前端订阅这些事件,按事件类型更新 UI。

传输方式不绑死某一种:常见是 HTTP + SSE,也可以是 WebSocket 等。CopilotKit Runtime 这边,通常就是把 AG-UI 事件流转成前端能消费的 SSE。

一次典型的 run 大致是:

# 常见事件类型

事件都带一个 type,前端靠它判断该怎么渲染。主要几类:

类别 代表事件 作用
生命周期 RUN_STARTEDRUN_FINISHEDRUN_ERROR 一次对话 run 的开始、正常结束、出错
文本消息 TEXT_MESSAGE_START / CONTENT / END 流式打字效果的回复
工具调用 TOOL_CALL_START / ARGS / END Agent 要调工具;前端可据此渲染工具 UI 或执行前端工具
状态同步 STATE_SNAPSHOTSTATE_DELTAMESSAGES_SNAPSHOT 整份状态、增量补丁、消息历史快照
其它 STEP_*CUSTOMRAW 步骤进度、自定义扩展

前端工具、Human-in-the-Loop,本质上也是这条事件流上的约定:Agent 发出工具调用并暂停,人在 UI 里操作完,结果再送回 Agent,run 继续。

# CopilotKit VS Assistant-ui

CopilotKit (opens new window)Assistant-ui (opens new window) 都能构建 AI 对话界面,但关注层次不同:

  • CopilotKit 更关注 Agent 如何接入应用、读取上下文、调用前端工具、执行等待用户响应。
  • Assistant-ui 更关注如何构建精细、可组合的聊天界面。

简单来说,CopilotKit 更像「Agent 应用前端栈」;Assistant-ui 更像「聊天 UI 工具包」。

# 各自优缺点

CopilotKit Assistant-ui
优点 内置 Agent Runtime、前端工具、共享上下文和 Human-in-the-Loop
支持 Chat、Sidebar、Popup 等开箱即用界面
以 AG-UI 解耦前端与 Agent 后端
支持 React、Vue、Angular、React Native 和 Channels
提供高度可组合的 Thread、Message、Composer 等聊天原语
聊天交互细节成熟,便于实现自定义 ChatGPT 风格界面
与 Vercel AI SDK、LangGraph 及自定义 Runtime 集成灵活
UI 代码由项目持有,样式和交互可控性高
缺点 引入 Runtime、Agent 与协议层后整体架构较重
只做普通聊天时可能超出实际需求
高度定制聊天界面需要使用 slots 或 Headless API
部分完整 Threads 能力依赖 Enterprise Intelligence Platform
主要解决聊天 UI,不提供 CopilotKit 那样完整的应用状态协作层
Agent 编排、应用上下文同步和复杂暂停恢复通常需要自行接入
主要面向 React Web,多端覆盖范围较窄
复杂 Agent 产品需要组合其他后端框架和基础设施

# 详细对比

维度 CopilotKit Assistant-ui
产品定位 Agent 应用前端栈 React AI 聊天 UI 工具包
主要目标 让 Agent 读取应用上下文、操作 UI、调用工具并与用户协作 快速构建可定制、体验完整的聊天界面
UI 方式 预置组件、slots 和 Headless API Thread、Message、Composer 等组合原语
Agent 连接 Copilot Runtime + AG-UI Runtime Adapter,可接 AI SDK、LangGraph 或自定义后端
前端工具 useFrontendTool,工具执行和展示均有统一生命周期 支持工具 UI,但具体执行和 Agent 接线更多取决于所用 Runtime
应用上下文 useAgentContext 将页面状态提供给 Agent 通常通过模型上下文或自定义 Runtime 自行传递
Human-in-the-Loop useHumanInTheLoopuseInterrupt 可实现审批和交互式工具,但暂停恢复逻辑通常由后端负责
Generative UI useComponentuseRenderTool 通过工具调用和自定义消息部件渲染 React UI
历史会话 useThreadsCopilotThreadsDrawer;完整托管能力可接 Enterprise Intelligence ThreadList + Assistant Cloud,或自建历史记录 Adapter
多端支持 React、Vue、Angular、React Native、Slack、Teams 主要是 React Web
适合场景 Agent 操作表单、画布、业务状态和审批流程 知识问答、客服聊天、ChatGPT 风格对话产品

# 怎么选

场景 建议
Agent 需要读取或修改当前页面状态 CopilotKit
Agent 需要调用前端工具或等待用户审批 CopilotKit
核心需求是高度定制的 ChatGPT 风格聊天界面 Assistant-ui
有自己的后台服务,只需要完善聊天 UI Assistant-ui
既需要复杂 Agent 能力,也需要高度定制聊天界面 可以组合,但需要自行实现 CopilotKit / AG-UI 与 Assistant-ui Runtime 之间的适配

总结:

如果项目里 Agent 要操作页面状态、调用前端工具、做审批流程,CopilotKit 会更省心;

如果核心只是做一套体验完整的聊天界面,Assistant-ui 会更直接。

# References