跳转到内容

上下文注入:应用状态如何成为 Agent 的感知

上下文注入:应用状态如何成为 Agent 的感知

学习目标

理解 CopilotKit 的上下文注入机制:

  • ContextStore 的内部实现
  • useCopilotReadable 如何将 React 状态注入 Agent 上下文
  • 上下文在每次 Agent 运行中的自动附加
  • 上下文数据的 Token 优化策略

前置知识

本章涉及上下文管理与记忆系统的通用原理,建议先阅读:

下文假设你已理解上述概念,直接聚焦 CopilotKit 的上下文注入实现。

项目实践

ContextStore 内部实现

CopilotKitCore 内部的 ContextStore 是一个键值对存储:

ContextStore 结构(伪代码):
{
contexts: Map<description, { description: string, data: JSON }>,
set(description, data) → 设置或更新上下文
delete(description) → 移除上下文
getAll() → Record<description, Context> // 每次 Agent 运行时自动调用
}

关键特性:

  • 键是 description(人类可读的描述文本)
  • 值是任意 JSON 可序列化数据
  • 每次 Agent 运行时,getAll() 返回的上下文自动包含在 RunAgentInput

useCopilotReadable Hook

React 开发者通过 useCopilotReadable 声明式注入组件状态:

useCopilotReadable({
description: "当前页面内容",
value: pageContent
});
useCopilotReadable({
description: "用户选中的商品",
value: selectedProduct,
category: "product" // 可选分类
});

工作原理(源码验证):

  1. Hook 调用 core.getContextStore().set(description, value)
  2. 值变化时自动更新 ContextStore
  3. Agent 运行时获取所有上下文

useMakeCopilotDocumentReadable

针对文档/页面的专用上下文注入:

useMakeCopilotDocumentReadable({
title: document.title,
content: markdownContent,
metadata: { url: window.location.href }
});

useCopilotReadable 的区别:

  • useCopilotReadable:注入任意 JSON 数据
  • useMakeCopilotDocumentReadable:专门用于文档内容(标题、内容、元数据)

上下文在 RunAgentInput 中的结构

每次 Agent 运行时,上下文作为 RunAgentInput 的一部分发送:

RunAgentInput 结构(伪代码):
{
messages: [...], // 聊天消息历史
tools: [...], // 可用工具列表
context: { // 应用上下文
"当前页面内容": "页面文本...",
"用户选中的商品": { name: "商品A", price: 99 }
},
threadId: "...",
state: {...}
}

上下文被注入到 Agent 的系统提示中,使其能够感知当前应用状态。

上下文变更通知

CopilotKitCoreSubscriber 提供 onContextChanged 回调:

core.subscribe({
onContextChanged: ({ context }) => {
// 上下文更新时的响应逻辑
}
});

注意:上下文更新是实时的,但 Agent 只在下次运行时获取最新上下文。

问题与规避

问题规避策略
上下文数据过大导致 Token 膨胀只注入必要数据;使用摘要/压缩策略(如只传页面标题和摘要而非全文)
上下文更新过于频繁useCopilotReadable 内部有节流机制;避免在 value 中放入频繁变化的引用
敏感数据泄露到 Agent避免在 value 中传入 token、密码等;中间件层做数据过滤
上下文描述文本不唯一后注册的覆盖先注册的;建议使用结构化描述(如 “页面:xxx” 而非 “页面”)

设计取舍

声明式 vs 命令式上下文注入

声明式(useCopilotReadable

  • 优势:React 风格,组件自行声明需要暴露的状态
  • 代价:每个组件独立注册,可能导致冗余数据

命令式(core.getContextStore().set() 直接调用)

  • 优势:集中管理,精确控制注入时机
  • 代价:与 React 生命周期解耦,需要手动管理

选择策略:组件级上下文用 Hook,全局上下文用直接调用。

上下文 vs 消息历史

维度上下文消息历史
内容应用状态(页面内容、选中数据等)聊天对话
更新方式实时替换(同一 key 的最新值)追加(不可变历史)
生命周期随组件挂载/卸载变化随线程持久化
用途提供当前状态的”快照”感知提供对话的”历史”感知

参考来源

  • packages/core/src/core/context-store.ts
  • packages/react-core/src/hooks/use-copilot-readable.ts
  • packages/react-core/src/hooks/use-make-copilot-document-readable.ts