ZCode 中的 AI 上下文使用可视化:Context 复合组件体系实战解析
2026/9/23 9:56:08 网站建设 项目流程

ZCode 中的 AI 上下文使用可视化:Context 复合组件体系实战解析

【免费下载链接】ZCodeZ.ai's coding agent harness. Powerful, intelligent, extensible.项目地址: https://gitcode.com/gh_mirrors/zco/ZCode

导读

本文围绕 ZCode 开源仓库中 AI Elements 技能体系的核心组件Context展开,系统讲解如何在一个基于 AI SDK 的 React 应用中展示模型上下文窗口占用率、token 消耗明细(输入 / 输出 / 推理 / 缓存)与实时成本估算。通过阅读本文,你将掌握 Context 复合组件(compound component)的完整 API、React Context 数据流设计、基于Intl.NumberFormat的 token 智能格式化,以及基于tokenlens的成本计算原理,并看到该组件在 ZCode 产品界面中的真实集成方式。

Context是一个用于展示 AI 模型上下文窗口使用情况的复合组件系统:它通过交互式悬停卡片(hover card)呈现上下文窗口占用、token 消耗拆分与成本估算。组件源自 Vercel 的 ai-elements,配套的可运行示例见 .agents/skills/ai-elements/scripts/context.tsx。

安装与前置条件

在项目中使用 Context 组件前,请确认满足 AI Elements 技能体系的环境要求:

  • Node.js 18 及以上
  • 一个安装了AI SDK的 React / Next.js 项目;
  • 已安装shadcn/ui(若未安装,执行安装命令时会自动引入)。

安装 Context 组件最直接的方式是使用 AI Elements 专用 CLI(请根据项目的packageManager选择npxpnpm dlxbunx --bun作为包执行器):

npx ai-elements@latest add context

CLI 会把组件源码直接集成到项目的@/components/ai-elements/目录(或你在 shadcn 配置中指定的组件目录),组件以源码形式存在于项目代码库中,而非隐藏在第三方库内部,因此你可以像使用普通 React 组件一样导入使用,甚至直接打开文件查看实现或做定制修改。

在 ZCode 仓库中,该组件的本地实现已落地于 packages/ui/src/components/ai-elements/context.tsx,其依赖的tokenlens版本为^1.3.1(见 packages/ui/package.json)。

核心特性一览

从参考文档与源码实现可以归纳出 Context 组件的以下能力:

  • 复合组件架构(Compound Component):由根组件与多个子组件灵活组合,按需拼装展示元素;
  • 可视化进度指示:SVG 圆形进度环直观显示上下文使用百分比;
  • Token 明细拆分:输入、输出、推理、缓存四类 token 分别展示;
  • 实时成本估算:借助tokenlens库按模型定价实时计算费用;
  • 智能格式化:token 数量自动按 K / M / B 缩写;
  • 交互式悬停卡片:悬停触发详细信息的 HoverCard 弹层;
  • Context Provider 模式:通过 React Context API 完成干净的数据流传递;
  • TypeScript 支持:所有组件均带完整类型定义;
  • 无障碍设计:正确使用 ARIA 属性与语义化 HTML;
  • 主题自适应:进度指示使用currentColor,随宿主主题自动适配。

Props 全表

以下完整继承自参考文档的 Props 定义,并结合源码 packages/ui/src/components/ai-elements/context.tsx 补充了说明。

<Context />— 根 Provider

Prop类型默认值说明
maxTokensnumber-上下文窗口总大小(token 数),用于计算占用百分比;源码中formatUsagePercent会在maxTokens <= 0时返回 0,避免除零异常
usedTokensnumber-当前已使用的 token 数
usageLanguageModelUsage-来自 AI SDK 的详细 token 用量拆分(input、output、reasoning、cached input tokens),对应ContextSchema中的usage字段
modelIdModelId(即string-模型标识符,用于成本计算,例如"openai:gpt-5"
...propsComponentProps<HoverCard>-其余属性透传给底层 HoverCard 组件

根组件在源码中通过useMemo缓存{ maxTokens, modelId, usage, usedTokens }形成 context 值,并包裹HoverCardcloseDelay={0}openDelay={0},即悬停零延迟开合)。任何子组件在Context之外使用时都会抛出"Context components must be used within Context"错误(见useContextValue的实现)。

<ContextTrigger />— 触发按钮

Prop类型默认值说明
childrenReact.ReactNode-自定义触发元素;未提供时渲染默认按钮(带百分比进度环图标)
loadingbooleanfalseZCode 扩展属性:为true时进度环图标替换为旋转的Loader2加载图标(对应额度自动重置进行中状态,源码注释注明为「正在重置」状态)
...propsComponentProps<Button>-透传给默认按钮元素

默认触发按钮使用variant="ghost"size="icon-md"样式,内部通过HoverCardTrigger asChild包装,以保证无障碍与聚焦行为。

<ContextContent />— 悬停卡片容器

Prop类型默认值说明
classNamestring-附加 CSS 类,通过cn合并
...propsComponentProps<HoverCardContent>-透传给 HoverCardContent 组件

源码中该容器固定宽度!w-64,采用rounded-lgbg-tooltip背景与text-tooltip-foreground前景色,关闭默认阴影、圆环与外框(shadow-none ring-0 outline-0)。

<ContextContentHeader />— 头部

Prop类型默认值说明
childrenReact.ReactNode-自定义头部内容;未提供时渲染百分比、token 数与进度条
actionReact.ReactNode-ZCode 扩展属性:头部右上角可选的行动作区域
progressSegmentsreadonly { className?: string; id: string; percent: number }[]-ZCode 扩展属性:分段进度条配置,与 progress.tsx 的分段渲染能力配合
...propsComponentProps<"div">-透传给头部 div 元素

默认头部渲染 "Context" 标题、分隔线、百分比(保留 1 位小数,如40.0%)、已用 / 总量的完整数字(如40,000 / 128,000),以及一个基于Progress组件的横向进度条(value={usedPercent * 100})。

<ContextContentBody />— 主体

Prop类型默认值说明
childrenReact.ReactNode-主体内容,通常放置各 Usage 拆分组件
...propsComponentProps<"div">-透传给 body div 元素

主体默认使用bg-menu背景与p-3内边距,与头部、底部形成视觉分区。

<ContextContentFooter />— 底部

Prop类型默认值说明
childrenReact.ReactNode-自定义底部内容;未提供且传入modelId时渲染总成本
...propsComponentProps<"div">-透传给 footer div 元素

底部通过border-t border-popover-borderbg-surface形成次级背景。默认渲染 "Total cost" 与格式化后的总费用;未提供modelId时成本为$0.00

Usage 组件(ContextInputUsage/ContextOutputUsage/ContextReasoningUsage/ContextCacheUsage

四个用量组件共享相同的 Props 约定:

Prop类型默认值说明
childrenReact.ReactNode-自定义内容;未提供时渲染对应类型的 token 数与成本
classNamestring-附加 CSS 类
...propsComponentProps<"div">-透传给 div 元素

源码中的行为细节值得注意:

  • 输入(Input):读取usage.inputTokens,成本按{ input: inputTokens, output: 0 }计算;
  • 输出(Output):读取usage.outputTokens,成本按{ input: 0, output: outputTokens }计算;
  • 推理(Reasoning):读取usage.reasoningTokens,成本以{ reasoningTokens }独立计算(推理 token 通常有特殊定价);
  • 缓存(Cache):读取usage.cachedInputTokens,成本以{ cacheReads: cacheTokens, input: 0, output: 0 }计算(缓存读取通常价格更低)。

每个组件在对应 token 数为 0 时返回null(不渲染),token 数未定义时显示占位符;成本文本通过• $X.XX形式附在 token 数之后。

组件架构:复合组件 + React Context

Context 组件采用复合组件(compound component)模式,配合 React Context 在多个展示组件间共享数据,结构分层如下:

  1. <Context>—— 根 Provider,持有全部上下文数据(usedTokensmaxTokensusagemodelId);
  2. <ContextTrigger>—— 交互式触发元素(默认:带百分比进度环的按钮);
  3. <ContextContent>—— 悬停卡片内容容器;
  4. <ContextContentHeader>—— 头部,含进度可视化;
  5. <ContextContentBody>—— 主体,承载用量拆分;
  6. <ContextContentFooter>—— 底部,展示总成本;
  7. Usage 组件—— Input / Output / Reasoning / Cache 四类独立用量展示。

数据流方面,根组件ContextuseMemo构造 context 值并通过ContextContext.Provider下发,所有子组件通过useContextValue()取用;若脱离根组件使用则抛出运行时错误(参见 packages/ui/src/components/ai-elements/context.tsx 中createContextuseContextValue的实现)。底层交互依赖 shadcn/ui 风格的 hover-card.tsx(基于 Radix UI 的HoverCard,含 Portal、对齐与动画)与 progress.tsx(支持分段segments渲染)。

圆形进度环的实现细节

默认触发按钮中的图标是一个纯 SVG 环形进度条(源码ContextIcon):

  • 常量定义:ICON_RADIUS = 10ICON_VIEWBOX = 24ICON_CENTER = 12ICON_STROKE_WIDTH = 4PERCENT_MAX = 100
  • 周长circumference = 2π × 10,根据使用比例usedPercent计算dashOffset = circumference × (1 - usedPercent)
  • 底环opacity="0.25"表示空余容量,进度弧opacity="0.7"transform: rotate(-90deg)使进度从 12 点钟方向起始,strokeLinecap="round"提供圆角端点;
  • 颜色直接使用currentColor,因此自动适配按钮前景色与宿主主题。

Token 智能格式化

组件对 token 数值的格式化遵循Intl.NumberFormat的 compact(紧凑)记法,按数量级自动缩写:

  • < 1,000:显示精确数值,如842
  • 1,000+:追加 K 后缀,如32K
  • 1,000,000+:追加 M 后缀,如1.5M
  • 1,000,000,000+:追加 B 后缀,如2.1B

在 ZCode 实现中,该逻辑被封装为独立的formatCompactTokenNumber工具函数,位于 packages/ui/src/lib/tokenNumberFormat.ts。源码注释明确记录了本地化决策:token 数值应走当前 locale 的 compact 记法(中文环境显示万/亿,英文环境显示 K/M/B),避免此前「为修英文长单位而把所有 locale 强制成 K/M/B」的回归问题;而模型列表的容量 badge(formatModelContextWindowLabel)作为技术规格则固定使用en-US的 K/M/B 展示。数值非有限数(!Number.isFinite)时返回空字符串兜底。

成本计算原理

当传入modelId时,组件通过tokenlens库自动完成成本估算(packages/ui/src/components/ai-elements/context.tsx 中getUsage(...).costUSD?.totalUSD)。成本构成如下:

  • 输入 token:按模型的输入定价计算;
  • 输出 token:按模型的输出定价计算;
  • 推理 token:针对支持推理(reasoning)的模型使用特殊定价;
  • 缓存 token:按缓存输入读取(cache read)的优惠价计算;
  • 总成本:各类 token 成本之和。

成本最终使用Intl.NumberFormatUSD 货币格式输出(如$0.42)。值得说明的是,页脚总成本仅以inputTokensoutputTokens两项调用getUsage,而各 Usage 组件的单项成本分别独立计算,推理与缓存成本在单项明细中体现。

完整可运行示例

参考文档指向的示例脚本 .agents/skills/ai-elements/scripts/context.tsx 演示了完整组合方式——以一个128,000token 的上下文窗口、已用40,000token、openai:gpt-5模型为数据,组合全部 7 类子组件:

"use client"; import { Context, ContextCacheUsage, ContextContent, ContextContentBody, ContextContentFooter, ContextContentHeader, ContextInputUsage, ContextOutputUsage, ContextReasoningUsage, ContextTrigger, } from "@/components/ai-elements/context"; const Example = () => ( <div className="flex items-center justify-center p-8"> <Context maxTokens={128_000} modelId="openai:gpt-5" usage={{ cachedInputTokens: 0, inputTokens: 32_000, outputTokens: 8000, reasoningTokens: 0, totalTokens: 40_000, }} usedTokens={40_000} > <ContextTrigger /> <ContextContent> <ContextContentHeader /> <ContextContentBody> <ContextInputUsage /> <ContextOutputUsage /> <ContextReasoningUsage /> <ContextCacheUsage /> </ContextContentBody> <ContextContentFooter /> </ContextContent> </Context> </div> ); export default Example;

注意:usage的字段名必须与 AI SDK 的LanguageModelUsage类型一致(inputTokensoutputTokensreasoningTokenscachedInputTokenstotalTokens),其中推理与缓存 token 为 0 时,对应 Usage 组件会自动隐藏,不会产生空行。

在 ZCode 产品中的真实应用

Context 组件并非仅供示例使用,它在 ZCode 桌面端聊天输入工具栏中被实际集成:packages/ui/src/chat-input-toolbar/contextUsage.tsx导入了ContextContextContentBodyContextContentContextTrigger等组件,将 Context 窗口占用、Coding Plan 与 Start Plan 额度三段信息聚合在同一个上下文面板中展示(源码头注说明该文件是「context 面板聚合 Context windows、Coding Plan 和 Start Plan 三段紧耦合展示」)。

该集成还展示了两个扩展点:通过loading属性在额度自动重置期间替换进度环图标,以及通过progressSegments传入多段进度条配置(配合 progress.tsx 的分段能力)。这说明 Context 复合组件通过...props透传与可选子节点约定,可以低成本嵌入真实业务面板。

样式与主题集成

组件基于 Tailwind CSS 并遵循宿主设计系统(shadcn/ui 语义 token):

  • 进度指示使用currentColor,自动适配主题与前景色;
  • 悬停卡片宽度与内边距可定制(默认!w-64+p-3);
  • 页脚使用次级背景(bg-surface+ 顶部边框)形成视觉分隔;
  • 主体文本统一使用text-ui-base字号,保持一致性;
  • 次级信息使用 muted 前景色(text-foreground-subtle/text-muted-foreground)。

由于组件代码以源码形式进入你的项目,你可以直接修改 Tailwind 类名来调整外观,例如去掉圆角、更换背景 token 等,无需额外配置。

延伸阅读

  • 组件完整实现:packages/ui/src/components/ai-elements/context.tsx
  • 可运行示例:.agents/skills/ai-elements/scripts/context.tsx
  • Token 格式化工具:packages/ui/src/lib/tokenNumberFormat.ts
  • 底层 UI 基元:hover-card.tsx、progress.tsx
  • 产品内集成案例:packages/ui/src/chat-input-toolbar/contextUsage.tsx
  • 技能体系总览与安装说明:.agents/skills/ai-elements/SKILL.md

【免费下载链接】ZCodeZ.ai's coding agent harness. Powerful, intelligent, extensible.项目地址: https://gitcode.com/gh_mirrors/zco/ZCode

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询