三层解耦架构:Frontend → Runtime → Agent
三层解耦架构:Frontend → Runtime → Agent
学习目标
理解 CopilotKit 的三层架构设计:
- 每层的职责、核心组件和边界
- 为什么需要拆三层而非一体化
- 各层之间如何独立替换和升级
- 请求在三层之间的完整生命周期
前置知识
本章涉及 Agent 核心循环设计的通用原理,建议先阅读:
下文假设你已理解上述概念,直接聚焦 CopilotKit 的三层架构实现。
项目实践
三层架构总览
前端层(Browser)
前端层的核心是 CopilotKitCore——一个纯 TypeScript 的框架无关类,负责:
| 职责 | 实现 |
|---|---|
| Agent 注册 | AgentRegistry 管理多个 AbstractAgent 实例 |
| 工具注册 | 工具注册表,按名称索引,支持 catch-all 通配符 |
| 上下文管理 | ContextStore 键值对存储,每次 Agent 运行自动附加 |
| 事件订阅 | CopilotKitCoreSubscriber 回调接口 |
| 状态管理 | StateManager + ThreadStoreRegistry |
| 远程代理 | ProxiedCopilotRuntimeAgent 将 HTTP 远程 Agent 代理为本地 AbstractAgent |
ProxiedCopilotRuntimeAgent 是关键设计:它继承自 AG-UI 的 HttpAgent,将远程 Agent 封装成本地对象。前端代码无需区分本地 Agent 和远程 Agent——两者都实现 AbstractAgent 接口。
两种运行时模式:
- SSE 模式(默认):通过 HTTP + SSE 与后端通信
- Intelligence 模式:通过 WebSocket 实现持久化线程、实时事件和 Redis 锁
前端通过 ensureRuntimeMode() 在首次请求时自动探测运行时的能力。
运行时层(Server)
运行时层的核心是 CopilotRuntime(及其子类 CopilotSseRuntime / CopilotIntelligenceRuntime),负责:
| 职责 | 实现 |
|---|---|
| HTTP 路由 | Express / Hono / Bun / Elysia 适配器 |
| 端点处理 | run / connect / stop / threads / transcribe / info |
| 中间件管线 | beforeRequestMiddleware + afterRequestMiddleware |
| Agent 解析 | 静态注册或 AgentsFactory 动态工厂 |
| AgentRunner | 管理线程状态、执行 Agent、发射事件流 |
| License 验证 | createLicenseChecker 服务侧验证 |
| 遥测 | @copilotkit/license-verifier 集成的遥测客户端 |
HTTP 端点(以 Express 为例):
| 端点 | 方法 | 说明 |
|---|---|---|
/agent/{agentId}/run | POST | 启动 Agent 运行,返回 SSE 事件流 |
/agent/{agentId}/connect | POST | 连接到已有 Agent 运行 |
/agent/{agentId}/stop/{threadId} | POST | 停止 Agent 运行 |
/threads | GET/POST | 线程管理 |
/info | GET | 运行时信息(模式、能力等) |
单端点传输下,所有操作统一 POST 到 /api/copilotkit,通过 body 中的 method 字段区分:"agent/run"、"agent/connect"、"agent/stop"、"info"。
Agent 层
Agent 层通过 AbstractAgent 抽象接入多种后端:
| 后端 | 包/类 | 说明 |
|---|---|---|
| LangGraph | @ag-ui/langgraph | 图状态机 Agent,支持中断和恢复 |
| OpenAI | OpenAIAdapter | 直接调用 OpenAI Chat Completion API |
| Anthropic | AnthropicAdapter | 直接调用 Anthropic Messages API |
| Google GenAI | GoogleGenAIAdapter | 直接调用 Google Gemini API |
| Groq | GroqAdapter | 通过 Groq API 调用 |
| Bedrock | BedrockAdapter | 通过 AWS Bedrock 调用 |
| LangChain | LangChainAdapter | 通过 Vercel AI SDK 接入任意 LangChain 模型 |
| BuiltIn | BuiltInAgent | 内置 Agent,基于 Vercel AI SDK |
| Custom | 用户自定义 | 实现 CopilotServiceAdapter 接口 |
CopilotRuntime 的 Agent 配置支持三种方式:
- 静态注册(开发环境常见):
const runtime = new CopilotSseRuntime({ agents: { default: new LangGraphAgent({ ... }) }});- Promise 异步注册:
const runtime = new CopilotSseRuntime({ agents: loadAgentsAsync()});- 工厂函数(多租户场景):
const runtime = new CopilotSseRuntime({ agents: ({ request }) => { const tenantId = request.headers.get("x-tenant-id"); return { default: createAgentForTenant(tenantId) }; }});请求生命周期(源码验证)
完整请求流:
- 前端初始化:
CopilotKitCore创建 → 注册工具/上下文 →ProxiedCopilotRuntimeAgent连接到运行时 - 用户发送消息:消息添加到 Agent → 调用
runAgent() - HTTP 请求:POST 发送到运行时,携带
RunAgentInput(消息、工具、上下文、threadId) - 中间件执行:
beforeRequestMiddleware处理请求(认证、日志等) - Agent 解析:根据
agentId查找或动态创建 Agent - AgentRunner 执行:Runner 管理线程状态,执行 Agent
- SSE 流回前端:Agent 发射 AG-UI 事件 → 运行时编码为 SSE → 前端解码
- 前端工具执行:Agent 调用前端工具 → Core 查找 handler → 浏览器执行 → 结果回传
- 中间件后置:
afterRequestMiddleware从 SSE 流解析 messages → 审计日志 - UI 更新:Core 更新消息存储 → React 重新渲染
问题与规避
| 问题 | 规避策略 |
|---|---|
| Runtime 成为单点瓶颈 | 多实例部署 + 粘性会话(同一 threadId 路由到同一实例);Intelligence 模式通过 Redis 共享锁 |
前端 ProxiedAgent 与后端 Agent 状态不一致 | syncDelegate() 在每次操作前同步状态(messages、state、threadId) |
| Agent 工厂每次创建新实例的开销 | 在工厂内部实现 Agent 缓存(按 tenantId 等 key 缓存) |
| SSE 流在长时间运行中被代理缓冲 | 响应头设置 X-Accel-Buffering: no;使用单端点模式减少代理层 |
设计取舍
三层 vs 一体化
CopilotKit 选择三层而非一体化(如 Dify 将 UI、运行时、Agent 耦合在一起):
三层优势:
- 前端拥有完整的 UI 自定义能力(不局限于框架提供的组件)
- 运行时独立部署,可做认证、审计、限流等横切关注点
- Agent 后端可随意替换,前端和运行时不需要改动
三层代价:
- 增加了一层网络通信(前端 ↔ 运行时)
- 调试需要追踪三层的事件流
- 部署复杂度更高(需要分别维护前端和运行时服务)
前端 Agent 代理 vs 直接远程调用
ProxiedCopilotRuntimeAgent 将远程 Agent 代理为本地对象:
优势:
- 前端代码透明使用,不关心 Agent 是本地还是远程
- 状态同步自动处理(messages、state、threadId)
- 支持 Intelligence 模式的 WebSocket 长连接
代价:
- 增加了代理层的复杂度(路由、传输协商、错误处理)
runtimeAgentIdvsagentId的区分容易混淆(subscriber 用前者,注册用后者)
参考来源
- CopilotKit 架构文档
packages/core/src/core/core.ts(CopilotKitCore 实现)packages/runtime/src/v2/runtime/core/runtime.ts(CopilotRuntime 实现)