资讯动态

ZCode 中的 AI 推理展示组件 Reasoning:流式思考内容折叠展示的完整实现与接入指南

发布时间:2026/9/23 2:01:06 来源:尧图企业网站定制
【免费下载链接】ZCodeZ.ais coding agent harness. Powerful, intelligent, extensible.项目地址https://gitcode.com/gh_mirrors/zco/ZCode点击查看免费下载导读Reasoning是 ZCode 内嵌的 ai-elements 组件库中用于展示 AI 推理reasoning / thinking内容的可折叠组件其核心能力是流式输出时自动展开显示思考过程输出结束后自动收起并支持手动切换、耗时统计与流式摘要。本文以 reasoning.md 为骨架结合仓库内 reasoning.tsx 的真实实现与 ConversationRowView.tsx 的实际落地用法完整讲解安装方式、AI SDK 前后端接入、组件 Props / Hooks API、以及 ZCode 在流式摘要、自动收起、滚动锁定、i18n 等方面的本地化增强。读完后你将能够把该组件接入任意 AI 聊天界面或直接理解 ZCode 对话时间线中思考块的内部机理。一、组件定位在聊天界面中呈现模型的思考过程1.1 它解决什么问题许多推理模型如 Deepseek R1、启用 extended thinking 的 Claude 等在给出最终答案前会先输出一段思维链文本。若把这段文本直接当作普通消息渲染会占据大量界面空间、打断对话流。Reasoning组件将其封装进一个可折叠面板流式阶段自动展开让用户实时看到模型正在思考输出结束自动收起把界面空间让给正式回答保留手动开关用户随时可点击展开查看完整思考内容。组件文档原句为A collapsible component that displays AI reasoning content, automatically opening during streaming and closing when finished.一个展示 AI 推理内容的可折叠组件流式期间自动打开、结束后自动关闭。1.2 在 ZCode 中的实际地位该组件不是孤立玩具ZCode 的对话时间线v4 会话视图中每一条思考行都由它渲染。在 ConversationRowView.tsx 中ReasoningRowView将ReasoningRow数据映射为Reasoning ReasoningTrigger ReasoningContent组合并显式传入streamingText与durationReasoning classNamew-full isStreaming{streaming} autoCollapseKey{streaming ? null : row.state} {...(durationSeconds ! undefined ? { duration: durationSeconds } : {})} ReasoningTrigger streamingText{row.text} / div>npx ai-elementslatest add reasoning若项目的包管理器是 pnpm 或 bun请替换为对应 runnerpnpm dlx ai-elementslatest add reasoning或bunx --bun ai-elementslatest add reasoning。安装依赖 Node.js 18、Next.js AI SDK 项目以及 shadcn/ui未安装时会自动安装。ZCode 仓库内该组件的源码位于 packages/ui/src/components/ai-elements/reasoning.tsx头部注释标明其派生自 vercel/ai-elements 的packages/elements/src/reasoning.tsxApache-2.0并经 ZCode 本地化改造。仓库还提供了可直接运行的演示脚本 .agents/skills/ai-elements/scripts/reasoning.tsx它用setTimeout模拟 token 流每 25ms 追加 3~4 字符的 chunk驱动isStreaming用于快速预览组件行为。三、与 AI SDK 的完整接入示例3.1 前端合并多段 reasoning part 到单个组件部分模型例如高 reasoning effort 的 GPT 系会返回多个reasoning part而非单个连续流式块。若每个 part 都渲染一个Thinking...指示器界面会非常杂乱。下面的前端组件源自文档的app/page.tsx示例将同一消息内所有type reasoning的 part 合并进一个Reasoning组件use client; import { Reasoning, ReasoningContent, ReasoningTrigger } from /components/ai-elements/reasoning; import { Conversation, ConversationContent, ConversationScrollButton, } from /components/ai-elements/conversation; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from /components/ai-elements/prompt-input; import { Spinner } from /components/ui/spinner; import { Message, MessageContent, MessageResponse } from /components/ai-elements/message; import { useState } from react; import { useChat } from ai-sdk/react; import type { UIMessage } from ai; const MessageParts ({ message, isLastMessage, isStreaming, }: { message: UIMessage; isLastMessage: boolean; isStreaming: boolean; }) { // 将所有 reasoning part 合并到一个块中避免出现多个 Thinking... 指示器 const reasoningParts message.parts.filter((part) part.type reasoning); const reasoningText reasoningParts.map((part) part.text).join(\n\n); const hasReasoning reasoningParts.length 0; // 判断思考是否仍在流式输出最后一条消息的最后 part 是 reasoning 即视为流式中 const lastPart message.parts.at(-1); const isReasoningStreaming isLastMessage isStreaming lastPart?.type reasoning; return ( {hasReasoning ( Reasoning classNamew-full isStreaming{isReasoningStreaming} ReasoningTrigger / ReasoningContent{reasoningText}/ReasoningContent /Reasoning )} {message.parts.map((part, i) { if (part.type text) { return MessageResponse key{${message.id}-${i}}{part.text}/MessageResponse; } return null; })} / ); }; const ReasoningDemo () { const [input, setInput] useState(); const { messages, sendMessage, status } useChat(); const handleSubmit (message: PromptInputMessage) { sendMessage({ text: message.text }); setInput(); }; const isStreaming status streaming; return ( div classNamemax-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px] div classNameflex flex-col h-full Conversation ConversationContent {messages.map((message, index) ( Message from{message.role} key{message.id} MessageContent MessageParts message{message} isLastMessage{index messages.length - 1} isStreaming{isStreaming} / /MessageContent /Message ))} {status submitted Spinner /} /ConversationContent ConversationScrollButton / /Conversation PromptInput onSubmit{handleSubmit} classNamemt-4 w-full max-w-2xl mx-auto relative PromptInputTextarea value{input} placeholderSay something... onChange{(e) setInput(e.currentTarget.value)} classNamepr-12 / PromptInputSubmit status{isStreaming ? streaming : ready} disabled{!input.trim()} classNameabsolute bottom-1 right-1 / /PromptInput /div /div ); }; export default ReasoningDemo;要点拆解reasoningParts过滤出所有part.type reasoning的 part用\n\n拼接为一个文本块isReasoningStreaming判定是否仍在思考中——只有最后一条消息且最后一块是 reasoning且处于 streaming 状态时才为真避免旧消息误触发流式 UI文本 part 依旧通过MessageResponse渲染reasoning part 不再单独渲染实现一个组件容纳全部思考。3.2 后端开启sendReasoning的流式路由后端需要使用 AI SDK 的streamText并调用toUIMessageStreamResponse({ sendReasoning: true })把 reasoning part 一并流式下发import { streamText, UIMessage, convertToModelMessages } from ai; // 允许最长 30 秒的流式响应 export const maxDuration 30; export async function POST(req: Request) { const { model, messages }: { messages: UIMessage[]; model: string } await req.json(); const result streamText({ model: deepseek/deepseek-r1, messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse({ sendReasoning: true, }); }关键点只有开启sendReasoning: true前端UIMessage的parts中才会出现type reasoning的块前端合并逻辑才有数据可用。maxDuration用于放宽流式响应时长上限避免长思考在服务端被截断。四、Reasoning 与 Chain of Thought 如何选择文档明确给出了组件选型建议ZCode 仓库内同时维护了两个组件文档reasoning.md 与 chain-of-thought.md场景推荐组件原因模型输出连续的思考文本块/流Deepseek R1、Claude extended thinking 等Reasoning一段连续文本折叠展示即可模型输出离散的、带标签的步骤搜索查询、工具调用、不同思考阶段ChainOfThought每个步骤有独立状态complete / active / pending、图标与进度需要结构化可视化ChainOfThought还额外支持搜索结果徽标Badge、带标题的图片展示等适合搜索增强型 Agent 的场景。五、特性一览文档列出的核心特性在 ZCode 实现中均可找到对应代码流式开始时自动打开、结束时自动关闭由isStreaming驱动的打开/收起 effect见 reasoning.tsx支持用户手动切换开关onOpenChange交互路径会记录userInteractedRef手动操作后自动收起规则不再覆盖用户选择基于 Radix UI 的平滑动画与过渡底层为Collapsible / CollapsibleContent / CollapsibleTrigger收起动画期间延迟 300ms 卸载内容 DOM 以保留可测量的真实高度带脉冲动画的可视化流式指示器运行态使用文案扫光样式 静态思考语义图标避免长流中旋转 loader 长期占用渲染资源触发器与内容分离的可组合架构ReasoningTrigger/ReasoningContent独立组件 Context 共享状态无障碍支持键盘导航、语义化按钮基于 Radix 的 Collapsible 原语响应式设计适配不同屏幕尺寸与深浅主题无缝集成使用 CSS 变量体系中的foreground-subtlest/foreground-subtle等语义色构建在 shadcn/ui Collapsible 原语之上完整的 TypeScript 类型定义ReasoningProps/ReasoningTriggerProps/ReasoningContentProps均从底层组件类型扩展。六、Props API 详解6.1Reasoning /Prop类型默认值说明isStreamingbooleanfalse是否处于流式思考中。为true时自动打开面板结束后自动收起openboolean-受控的打开状态传入后组件进入受控模式defaultOpenbooleantrue非受控模式下的默认打开状态onOpenChange(open: boolean) void-打开状态变化回调durationnumber-显示耗时秒可从外部控制...propsReact.ComponentPropstypeof Collapsible-其余属性透传给底层 Collapsible注意ZCode 本地化实现将defaultOpen的默认值改为false见 reasoning.tsx并在ReasoningProps上额外增加了autoCollapseKeystring | number | null默认null当该 key 发生变化且用户未手动操作时自动收起面板。这是文档表格之外的 ZCode 增强用于思考输出结束即收起的边界信号。ZCode 实现的内部机制对应 reasoning.tsx打开状态用 Radix 的useControllableState管理open传入即受控、不传即非受控duration同样走useControllableStateisStreaming从false变true时记录startTimeRef Date.now()流式期间每 1 秒用setInterval更新Math.ceil((Date.now() - startTimeRef) / 1000)结束时固化最终秒数为降低渲染开销收起态不启动定时器展开时再按同一开始时间补算shouldRenderContent状态 300ms 延迟卸载REASONING_CONTENT_COLLAPSE_UNMOUNT_DELAY_MS保证 Radix 高度动画在 closed 阶段仍能读到真实内容高度shouldAutoCollapseReasoning工具函数实现autoCollapseKey 变化且用户未交互 → 收起的规则。6.2ReasoningTrigger /Prop类型默认值说明getThinkingMessage(isStreaming: boolean, duration?: number) ReactNode-自定义思考文案接收isStreaming与duration参数...propsReact.ComponentPropstypeof CollapsibleTrigger-其余属性透传给 CollapsibleTriggerZCode 额外增加的streamingText?: stringprop 用于收起态的流式摘要当isStreaming !isOpen时取streamingText最后一行非空文本resolveReasoningStreamingSummary在触发器右侧以单行滚动视口展示最新思考内容配合渐隐 maskgetReasoningSummaryMaskStyle左右各 16px 渐变与ResizeObserver自动推到末尾保证最新 token 永远可见。默认触发器内容由 i18n 文案组装见 en-US.ts 与 zh-CN.ts文案 keyen-USzh-CNchat.reasoning.thinkingThinking正在思考chat.reasoning.thoughtThought思考chat.reasoning.durationFewSecondsa few seconds持续了几秒chat.reasoning.durationSeconds{seconds} seconds持续了 {seconds} 秒UI 上依次渲染BrainIconlucide 大脑图标→ 状态标签流式中显示正在思考完成态显示思考 · 持续了 X 秒→ 可选的流式摘要 →ChevronRightIcon展开时旋转 90° 显示为向下箭头收起时 hover 显示。6.3ReasoningContent /Prop类型默认值说明childrenstring必填要展示的思考文本经 Streamdown 渲染...propsReact.ComponentPropstypeof CollapsibleContent-其余属性透传给 CollapsibleContentZCode 额外增加了variant?: default | nested当思考行嵌套在工具 Group 内时传nested去掉重复的左侧导线与缩进对应 ConversationRowView.tsx 的contentVariant传递。内容区具备滚动锁定跟随能力默认自动跟随底部autoFollowBottomRef true当用户在思考区向上滚动后暂停跟随滚回底部 2px 范围内REASONING_BOTTOM_LOCK_DISTANCE_PX恢复滚动容器顶部/底部有渐隐 maskresolveVerticalScrollMaskState长思考内容的滚动状态一目了然。七、HooksuseReasoning从子组件中访问 Reasoning 的共享上下文const { isStreaming, isOpen, setIsOpen, duration } useReasoning();返回值Prop类型说明isStreamingboolean当前是否处于流式思考isOpenboolean面板是否打开setIsOpen(open: boolean) void设置面板打开状态durationnumber \| undefined思考耗时秒流式中为undefined实现上Reasoning通过ReasoningContext.Provider下发该值见 reasoning.tsxuseReasoning在 Context 缺失时会抛出Reasoning components must be used within Reasoning确保子组件必须包裹在Reasoning内部使用。八、从文档到真实生产代码ZCode 本地化改造清单对照文档与仓库实现可归纳出 ZCode 在原始 ai-elements 组件之上做的关键增强均有源码为证自动收起边界信号autoCollapseKey状态切换如streaming → complete驱动收起且不覆盖用户手动操作shouldAutoCollapseReasoning收起态流式摘要streamingText折叠时也能在触发器上追剧最新思考resolveReasoningStreamingSummary耗时统计与展示流式期间每秒刷新、结束后固化支持外部受控传入durationprop内容延迟卸载300ms 收起动画完成后再卸载 DOM兼顾动画流畅与性能i18n 文案思考状态与耗时文案走 IntlProvider 的中英文案体系嵌套变体与滚动锁定variantnested适配工具组内的层级视觉滚动区自动跟随底部并在手动滚动后让位测试标识触发器与内容分别带TID_CHAT_REASONING_TRIGGER/TID_CHAT_REASONING_CONTENT来自zcode/shared供端到端测试与选择器使用。九、总结与实践建议接入三步走npx ai-elementslatest add reasoning安装 → 后端toUIMessageStreamResponse({ sendReasoning: true })开启思考流 → 前端按part.type reasoning合并渲染进单个Reasoning组件多 part 合并是接入 GPT 系高 reasoning effort 模型时的必做项否则会出现多个重复的Thinking...指示器区分连续思维与离散步骤连续思考文本用Reasoning带状态/图标的步骤式推理用 ChainOfThought复用 ZCode 经验默认收起 收起态流式摘要 状态边界自动收起是长流式对话中兼顾可见性与空间效率的成熟取舍可直接参考 ConversationRowView.tsx 的生产用法。如需查看组件完整源码、演示脚本与配套文档可直接阅读仓库内 reasoning.tsx、.agents/skills/ai-elements/scripts/reasoning.tsx 及 SKILL.md 中的组件库总览。赞分享【免费下载链接】ZCodeZ.ais coding agent harness. Powerful, intelligent, extensible.项目地址https://gitcode.com/gh_mirrors/zco/ZCode点击查看免费下载相关推荐Choco-solver开发者指南贡献代码与扩展约束求解能力Choco solver开发者指南贡献代码与扩展约束求解能力 Choco solver是一款强大的开源Java约束编程库为开发者提供了构建复杂约束求解模型的科学计算人工智能ZCode 中的 AI Elements Sandbox 组件用可折叠容器展示 AI 生成代码与执行输出ZCode 中的 AI Elements Sandbox 组件用可折叠容器展示 AI 生成代码与执行输出 本文围绕 ZCode 仓库内置的 AI ElemenZCode 中的 Sources 组件为 AI 对话响应构建可折叠引用来源展示ZCode 中的 Sources 组件为 AI 对话响应构建可折叠引用来源展示 导读 本文以 ZCode 仓库内置的 ai elements 技能中 Sour创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价