ZCode 中的 Sources 组件:为 AI 对话响应构建可折叠引用来源展示
【免费下载链接】ZCodeZ.ais coding agent harness. Powerful, intelligent, extensible.项目地址https://gitcode.com/gh_mirrors/zco/ZCode点击查看免费下载导读本文以 ZCode 仓库内置的ai-elements技能中Sources组件的完整参考文档.agents/skills/ai-elements/references/sources.md为核心系统讲解如何在基于 AI SDK 的聊天应用中为模型生成的回答展示来源与引用citations。文章将覆盖Sources、SourcesTrigger、SourcesContent、Source四个组件的安装方式、与 Perplexity 等搜索型模型的端到端接入示例、全部 Props 参数表并结合 ZCode 仓库中的实际实现源码packages/ui/src/components/ai-elements/sources.tsx深入剖析其折叠交互原理与自定义渲染方法帮助你快速在自己的 AI 前端中落地引用来源这一关键可信度功能。什么是 Sources 组件Sources是一个允许用户查看生成回答时所使用来源或引用的 UI 组件。在基于检索增强或联网搜索的 AI 应用中模型会引用多个网页、文档作为回答依据Sources组件将这些来源以可折叠collapsible的形式组织起来默认只显示一个触发按钮例如Used N sources用户点击后展开来源列表每条来源以带图标的超链接形式展示。从 ZCode 仓库的实现看packages/ui/src/components/ai-elements/sources.tsx该组件由四个协作的部分组成底层依赖 radix-ui 的Collapsible原语见 packages/ui/src/components/ui/collapsible.tsx组件职责Sources折叠容器根节点内部渲染Collapsible持有展开/收起状态SourcesTrigger折叠触发器显示来源数量默认文案Used N sources与箭头图标SourcesContent折叠内容区承载来源列表带展开/收起动画Source单个来源链接默认渲染书本图标 标题新标签页打开四个组件均支持通过className与展开的 props 深度定制这与该技能目录.agents/skills/ai-elements/SKILL.md所倡导的尽可能透传原生属性的扩展性原则一致。安装在具备以下前置条件的项目中通过 AI Elements CLI 即可一键安装Sources组件Node.js 18 及以上版本已安装 AI SDK 的 Next.js 项目已安装 shadcn/ui未安装时执行安装命令会自动补装。安装命令npx ai-elementslatest add sources如果你的项目使用 pnpm 或 bun 作为包管理器请使用对应的运行器pnpm dlx ai-elementslatest或bunx --bun ai-elementslatest。CLI 会将组件代码及其依赖写入你项目中 shadcn 配置的组件目录默认位置是/components/ai-elements/因此安装完成后代码中引入路径即为import { Source, Sources, SourcesContent, SourcesTrigger } from /components/ai-elements/sources;组件代码会作为你项目源码的一部分落地而非封装在不可见的库里这意味你可以直接打开组件文件查看实现、按需修改样式与逻辑。若引入时报module not found请检查tsconfig.json中是否配置了/路径别名{ compilerOptions: { baseUrl: ., paths: { /*: [./*] } } }与 AI SDK 集成构建一个联网搜索问答示例参考文档给出了一个完整的实战示例对应的示例源码位于 .agents/skills/ai-elements/scripts/sources.tsx使用 Perplexity Sonar 模型构建一个简单的网页搜索 Agent前端展示每次回复引用的来源。前端组件app/page.tsxuse client; import { useChat } from ai-sdk/react; import { Source, Sources, SourcesContent, SourcesTrigger } from /components/ai-elements/sources; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from /components/ai-elements/prompt-input; import { Conversation, ConversationContent, ConversationScrollButton, } from /components/ai-elements/conversation; import { Message, MessageContent, MessageResponse } from /components/ai-elements/message; import { useState } from react; import { DefaultChatTransport } from ai; const SourceDemo () { const [input, setInput] useState(); const { messages, sendMessage, status } useChat({ transport: new DefaultChatTransport({ api: /api/sources, }), }); const handleSubmit (message: PromptInputMessage) { if (message.text.trim()) { sendMessage({ text: message.text }); setInput(); } }; return ( div classNamemax-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px] div classNameflex flex-col h-full div classNameflex-1 overflow-auto mb-4 Conversation ConversationContent {messages.map((message) ( div key{message.id} {message.role assistant ( Sources SourcesTrigger count{message.parts.filter((part) part.type source-url).length} / {message.parts.map((part, i) { switch (part.type) { case source-url: return ( SourcesContent key{${message.id}-${i}} Source key{${message.id}-${i}} href{part.url} title{part.url} / /SourcesContent ); } })} /Sources )} Message from{message.role} key{message.id} MessageContent {message.parts.map((part, i) { switch (part.type) { case text: return ( MessageResponse key{${message.id}-${i}} {part.text} /MessageResponse ); default: return null; } })} /MessageContent /Message /div ))} /ConversationContent ConversationScrollButton / /Conversation /div PromptInput onSubmit{handleSubmit} classNamemt-4 w-full max-w-2xl mx-auto relative PromptInputTextarea value{input} placeholderAsk a question and search the... onChange{(e) setInput(e.currentTarget.value)} classNamepr-12 / PromptInputSubmit status{status streaming ? streaming : ready} disabled{!input.trim()} classNameabsolute bottom-1 right-1 / /PromptInput /div /div ); }; export default SourceDemo;这段代码的关键逻辑在于通过useChat拿到流式消息后对message.parts中type source-url的 part 逐一映射为Source链接并用SourcesTrigger的count属性展示来源总数文本 part 则交给MessageResponse渲染。折叠容器Sources仅包裹 assistant 消息用户消息不展示来源。后端路由api/chat/route.tsimport { convertToModelMessages, streamText, UIMessage } from ai; import { perplexity } from ai-sdk/perplexity; // Allow streaming responses up to 30 seconds export const maxDuration 30; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } await req.json(); const result streamText({ model: perplexity/sonar, system: You are a helpful assistant. Keep your responses short ( 100 words) unless you are asked for more details. ALWAYS USE SEARCH., messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse({ sendSources: true, }); }后端的关键配置是toUIMessageStreamResponse({ sendSources: true })开启后AI SDK 会把模型返回的引用来源编码为source-url类型的 UI message part前端据此驱动Sources组件渲染。系统提示词中的 ALWAYS USE SEARCH 用于引导 Sonar 模型始终执行搜索从而稳定地产出可展示的来源数据。maxDuration 30允许流式响应最长 30 秒。功能特性Sources组件围绕来源展示场景提供了以下能力可折叠组件用户可按需展开/收起回答所使用的来源或引用列表触发器与内容可定制SourcesTrigger与SourcesContent均可传入自定义子元素或样式支持自定义来源Source组件接受任意href与title可渲染任意来源/引证链接响应式设计布局适配移动端折叠动画与交互在窄屏下同样可用简洁现代的样式基于 Tailwind 与 shadcn/ui 主题体系可通过className无缝接入既有主题。自定义渲染SourcesTrigger与Source均支持 children 覆盖默认内容这为深度定制提供了入口。参考文档提供了自定义示例对应源码 .agents/skills/ai-elements/scripts/sources-custom.tsxuse client; import { Source, Sources, SourcesContent, SourcesTrigger } from /components/ai-elements/sources; import { ChevronDownIcon, ExternalLinkIcon } from lucide-react; const sources [ { href: https://stripe.com/docs/api, title: Stripe API Documentation }, { href: https://docs.github.com/en/rest, title: GitHub REST API }, { href: https://docs.aws.amazon.com/sdk-for-javascript/, title: AWS SDK for JavaScript, }, ]; const Example () ( div style{{ height: 110px }} Sources SourcesTrigger count{sources.length} p classNamefont-mediumUsing {sources.length} citations/p ChevronDownIcon classNamesize-4 / /SourcesTrigger SourcesContent {sources.map((source) ( Source href{source.href} key{source.href} {source.title} ExternalLinkIcon classNamesize-4 / /Source ))} /SourcesContent /Sources /div ); export default Example;与默认渲染相比自定义示例做了两处增强一是触发器文案改为 Using N citations 并显式放置下箭头图标二是每条来源追加ExternalLinkIcon外链图标语义上提示用户点击后将离开当前页面。这正是该组件可像自己写的代码一样自由修改的体现。结合源码看自定义的实现原理在 ZCode 的组件实现中packages/ui/src/components/ai-elements/sources.tsxSourcesTrigger使用{children ?? (...)}的写法传入 children 时完全渲染自定义内容未传入时才回退到默认的 Used {count} sources 文案与ChevronDownIconSource同样用{children ?? (...)}在无 children 时回退到BookIcontitle的默认布局。由此可推断任何自定义内容都是通过 children 覆盖实现的而组件自身仅负责折叠状态与基础 a 标签语义互不干扰。Props 参考以下是四个组件的完整 Props 说明与参考文档一致并结合实现源码补充类型来源。Sources /Prop类型默认值说明...propsReact.HTMLAttributesHTMLDivElement-其余所有 props 透传到根 div实现中Sources实际渲染为 radix-ui 的Collapsible根组件见 packages/ui/src/components/ui/collapsible.tsx因此defaultOpen、open、onOpenChange等折叠控制 props 同样可用。SourcesTrigger /Prop类型默认值说明countnumber必填触发器上展示的来源数量...propsReact.ComponentPropstypeof CollapsibleTrigger-其余 props 透传到 CollapsibleTrigger 组件SourcesContent /Prop类型默认值说明...propsReact.HTMLAttributesHTMLDivElement-其余 props 透传到内容容器实现中SourcesContent渲染为CollapsibleContent内置了data-[state]驱动的展开/收起动画类fade-out、slide-in-from-top 等实际生效样式可参考 packages/ui/src/components/ai-elements/sources.tsx。Source /Prop类型默认值说明...propsReact.AnchorHTMLAttributesHTMLAnchorElement-其余 props 透传到 a 元素Source即一个a锚点元素实现中默认带有target_blank与relnoreferrer保证来源在新标签页打开且不泄露来源页信息href、title等标准链接属性均可用。主题与样式注意事项Sources组件继承 shadcn/ui 的>赞分享【免费下载链接】ZCodeZ.ais coding agent harness. Powerful, intelligent, extensible.项目地址https://gitcode.com/gh_mirrors/zco/ZCode点击查看免费下载相关推荐如何用Ventoy打造终极多系统启动U盘告别反复格式化一U盘装遍所有操作系统如何用Ventoy打造终极多系统启动U盘告别反复格式化一U盘装遍所有操作系统 还在为每次重装系统都要重新制作启动盘而烦恼吗还在因为U盘只能存放一个系统镜像操作系统固件开发工具marimo Accordion 组件详解用 mo.accordion 构建可折叠内容区marimo Accordion 组件详解用 mo.accordion 构建可折叠内容区 导读 本文围绕 marimo 的 mo.accordion 布局组件数据科学前端后端AI 应用推荐开源项目React响应式折叠组件React Collapsible推荐开源项目React响应式折叠组件React Collapsible 在构建动态和交互式的网页应用时处理大量信息展示的高效性和条理性至关重要。今天我创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026最新狡兔二窟实战:3步搞定双活部署避坑指南

2026最新狡兔二窟实战:3步搞定双活部署避坑指南

2026最新狡兔二窟实战:3步搞定双活部署避坑指南 面试被问“高可用架构怎么落地”,很多人只能背概念,代码一写就崩。2026最新的技术栈里,单点故障已是红线,狡兔二窟式的 双活部署…

2026/9/23 7:23:58 阅读更多 →
Flutter路径库在鸿蒙系统的适配实践

Flutter路径库在鸿蒙系统的适配实践

1. 项目背景与核心价值在跨平台开发领域,路径处理一直是基础但极其关键的环节。Flutter生态中的path三方库因其简洁高效的路径操作API被广泛使用,但随着鸿蒙系统的崛起,开发者面临一个现实问题:如何让这套成熟的路径处理逻辑在鸿蒙…

2026/9/23 7:23:58 阅读更多 →
3个误区图解原理:全民英雄紫卡源码级拆解

3个误区图解原理:全民英雄紫卡源码级拆解

3个误区图解原理:全民英雄紫卡源码级拆解 盯着屏幕上的 java.lang.NullPointerException 和满屏红色的…

2026/9/23 7:23:57 阅读更多 →

最新新闻

用ttf2woff2把TTF转WOFF2,字体体积压缩60%实践指南

用ttf2woff2把TTF转WOFF2,字体体积压缩60%实践指南

字体这块的活儿,看着不起眼,真做起来全是细节。最近在给一个老项目做性能优化,翻网络请求记录的时候发现首页字体文件加载得极其缓慢,.ttf 格式,一个文件动辄两三兆,打开 DevTools 的 Network 面板简直惨不…

2026/9/23 8:03:31 阅读更多 →
Ce6-Maleimide:光敏染料与巯基反应的高效偶联技术

Ce6-Maleimide:光敏染料与巯基反应的高效偶联技术

1. Ce6-Maleimide的结构与功能解析Ce6-Maleimide(氯菁6-马来酰亚胺)是一种将光敏分子氯菁6(Chlorin e6, Ce6)与马来酰亚胺(Maleimide)官能团通过共价键连接而成的功能化小分子。这种分子设计巧妙地将两类特…

2026/9/23 8:03:31 阅读更多 →
强电网条件下11电平MMC构网型运行的VSG-环流抑制协同控制策略研究(Simulink仿真实现)

强电网条件下11电平MMC构网型运行的VSG-环流抑制协同控制策略研究(Simulink仿真实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 &#x1f381…

2026/9/23 8:03:31 阅读更多 →
全栈记账系统实战:Vue3+Golang+Uniapp多端开发

全栈记账系统实战:Vue3+Golang+Uniapp多端开发

1. 项目概述与核心思路拆解1.1 为什么我要做这个记账系统记账这件事,本身不新鲜。市面上随手一搜就是一堆记账App,随手记、鲨鱼记账、MoneyWiz,功能一个比一个全,图表一个比一个好看。但我个人记账三年多,始终有一种“…

2026/9/23 8:03:31 阅读更多 →
大数据与机器学习在环境科学建模中的实践应用

大数据与机器学习在环境科学建模中的实践应用

1. 大数据时代下的自然科学建模变革十年前我刚进入环境科学领域时,科研建模还停留在传统统计方法阶段。记得第一次处理气象站数据时,光是处理缺失值就花了两周时间,而建立的线性回归模型解释力还不到40%。如今,深度学习技术已经彻…

2026/9/23 8:03:31 阅读更多 →
2025年AI论文辅助工具全测评与本科生写作指南

2025年AI论文辅助工具全测评与本科生写作指南

1. 项目背景与核心价值作为一名在学术写作领域摸爬滚打多年的老手,我深知本科生撰写毕业论文时的三大痛点:文献检索效率低、写作规范不熟悉、查重降重耗时长。2025年最新一代AI论文辅助平台的出现,正在彻底改变这一局面。这次受导师委托系统测…

2026/9/23 8:02:31 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →