普通视图

发现新文章,点击刷新页面。
昨天以前首页

阿里夸克发布了两款 AI 眼镜,他们说行业的「iPhone 时刻」还没到

作者 刘学文
2025年11月28日 17:54

3799 元起,阿里巴巴集团旗下的夸克 AI 眼镜 S1 正式发布,这个价格并不便宜。这和之前阿里巴巴做硬件的思路并不一致,譬如此前阿里巴巴旗下的天猫精灵智能音箱,以及天猫魔盒电视盒子,都是以极低的价格切入市场,然后试图在硬件后端的软件和服务上赚钱。

3799 元起的夸克 AI 眼镜 S1,1899 元起的夸克 AI 眼镜 G1,没有明显的那种硬件亏本,大量出货,然后服务赚钱的互联网公司思路,而是看起来属于「硬件的归硬件,AI 的归 AI」。

第一代夸克 AI 眼镜,足够好,更好的方向在哪里?

当然,消费者侧的感受,和夸克这边的感受未必一致,比如说,阿里智能终端业务的负责人宋刚就说:

我们依托于当前的产业链能够做出这样极致的产品,已经是行业的天花板。

这是发布会后采访里,阿里巴巴这边划的第一个重点,言下之意就是,3799 元不便宜,但以目前行业的情况,是物有所值的。他还有补充:

今天国内 AI 眼镜的规模还不足以支撑产业链当前的投入。我刚才说了光机、光波导人家投了十来年才找到一个机会能够发展,这个阶段确实是需要投入的方式来做,但是我们认为它到一定的规模之后,一定是能够把价格降下来的。行业的量达到一定水准,百万级以上和千万级,成本肯定是能够持续下降的,这个是硬件的规律。

这也意味着,3799 元起的价格不便宜,但在没有起量的情况下,也未必赚钱,甚至在算产业链账单的情况,也可能是亏本的。

夸克 AI 眼镜 S1 的硬件规格是这样的:高通骁龙 AR1 加恒玄 BES2800 双芯片方案,双光机双目显示,国内首创合像距可调,亮度可达 4000nits,二维衍射波导方案及高折射率镜片加镀膜工艺,五个麦克风阵列加骨传导;0.6 秒极速抓拍,Super Raw 暗光增强技术,3K 视频录制,超分超帧后可输出 4K 视频;定制研发小型化扬声器,镜腿仅 7.5 毫米宽。

相比于手机,AI 眼镜是一个更需要做「取舍」的产品,受制于产品形态,产品经理和工程师很难在寸土寸金的眼镜里埋入大量的元器件以及大容量的电池。

功能,性能,重量和续航之间矛盾重重。

初代 Meta Ray-Ban 眼镜的成功,很大程度上是因为它在做减法的上相当成功,首先它是一个合格的,不突兀的眼镜,然后它是一个还可以的拍摄眼镜,以及稍微有点用的 AI 眼镜,因为拍摄和 AI 功能增加的重量和元器件不会有明显的负面体验,所以它成功了。

夸克 AI 眼镜 S1 在此之上,做了非常谨慎的加法,也是最重要的加法:加了 JBD 0.15cc 级蜂鸟 Mini Ⅱ 微型光机做单色 AR 显示。

做这个加法的前提是,蜂鸟 Mini Ⅱ 微型光机足够小足够轻,不会对眼镜的形态和重量造成明显地负面影响,小型化是夸克做 AI 眼镜的核心要义。

这也是未来夸克 AI 眼镜迭代的方向,宋刚说:

因为 AI 眼镜这个品类,它有多余的空间,我们认为会让给外观,未来是不是可以做无框的?我认为在小型化之后还是会有这样的机会,现在的瓶颈更多的还是在材料、芯片,当前芯片的尺寸还是比较大的,针对 AI 眼镜的方向。我认为未来行业还在做更小尺寸的芯片,让我们的外观可以再往小型化走,是这样的影响。

当然也有人会问,为什么不做彩色显示,为什么不做沉浸式显示?宋刚回答说:

在 AI 眼镜出现之前,AR 或者是 VR 它已经发展了十几年的时间,为什么他们一直处在量没有那么大的飞跃,或者中间某个阶段有增长过,但又掉下来了,这个时候可以看到,某种程度上,它还是只能让人戴 20 分钟、30 分钟的定义。

 

另外一个就是它的沉浸感,我认为 AR 本身的定义不应该是沉浸式的,它应该是虚实结合的,它不能够脱离现实去做,所以在目前的技术上不是不做,而是我们能不能做得更好。我认为现在的彩色光机还没有到做出让人能够随时戴出去的状态。

 

当然我们也已经在预研了,我们会是行业最早推出更小型化、更高亮度,体验更好彩色光机的产品,但是这个肯定需要时间的。

两个信息:一是阿里巴巴认为现在 AI 眼镜的路线还是不能盲目做加法,眼镜太大太厚太重太突兀没法全天佩戴就不是成功的产品定义,二是阿里巴巴认为彩色显示会是正确的方向,未来会有成熟产品出来。

这就涉及到会后采访里媒体们不断问及的一个关键词:iPhone 时刻。

行业的「iPhone 时刻」还没到,但路标很明确

因为采访里提到「iPhone 时刻」的频率过高,所以我们不用纠结是否真的有这么一个真实的概念,只需要把这个概念理解为「硬件产品在某一个阶段,达成了创新性,实用性和成本相对经济」的三者平衡,而不是某一个时刻产品魔法般的惊艳世界享誉全球畅销海内外了。

基于这个理解,我们可以看一看夸克是如何阐释 AI 眼镜这个领域的「iPhone 时刻」的。

宋刚说:

我们都在期待眼镜的 iPhone 时刻什么时候到来?我们看过去 iPhone 时刻到来的时候,它其实是在管道流量的渠道下,2G 到3G 的转变,3G 到 4G 的转变过程中产生的,它做对了一件事情就是人机交互的变化。

 

AI 眼镜这代的革命实际上是 AI 驱动的人机交互的革命,我们认为这一代人机交互革命的中心就是 AI 眼镜为主要时代的场景,我们认为这个时代已经到来了,只是说它还缺少一些生态的支持,还有就是能不能有一些 AI 本身的发展能不能更好地服务于人,主动式的 AI 服务。

 

我们认为它就是下一代的个人移动入口,它就是个人人机交互变革的中心,也是 AI 的入口,它是未来最有机会挑战手机的设备,这件事情在阿里的战略里面它就是一个非常重要的角色。

乔布斯复述的「真正认真写软件的人应该自己做硬件」这句话用在这里非常合适。

阿里巴巴是一个好的软件公司吗?在 AI 时代之前恐怕不算是,无论是天猫淘宝或是飞猪等等等软件的用户量还是基于平台优势,而非软件本身的体验。

但是在 AI 浪潮把所有公司都拉回创业的统一起跑线之后,无论是 Qwen 开源大模型,还是夸克应用的转变,都让阿里巴巴拥有了聊「真正认真写软件的人应该自己做硬件」这句话的本钱,阿里有体验很好的 AI 大模型和应用了。

当然,苹果做 iPhone 的水到渠成,是因为苹果是大众意义上的硬件公司,这个认知摆在苹果是一家操作系统公司之前。阿里巴巴的给大众的认知是什么呢?电商,云计算,大模型等等标签要先于硬件。

但宋刚还是认为,阿里是可以做好硬件的:

做硬件本身和阿里没有本质矛盾,只是说公司想不想做好这件事情,我刚才说了阿里的战略已经转移了,它不存在做不好。

更关键的是,宋刚认为,时代站在 AI 眼镜这边:

人机交互的革命,眼镜肯定是主角过去 OS 的生态其实是 App 生态,这些生态未来也会往 AI OS 转变,以及当前的 App 会往 Agent 化的改造。

 

过去可能要自己下载 App,去打开它去查找、使用,这样的过程,在眼镜上一句话就完成了。它实际上更有利于眼镜的场景,这是技术发展的主方向。

 

AI OS,未来会催生硬件行业非常大的变革,包括手机,我们今天看到的这些设备都会发生变革。眼镜其实是在这个里面的人机交互核心,围绕眼镜可能未来还会有一些介质。今天还需要唤醒千问,明天不用唤醒它,按一下直接说了,再结合眼动,这样的操控也是比较好的场景,眼睛看着一个东西,按一下直接问,这样的操控也是比较顺的。

 

未来这样的发展脉络还是比较清晰的,再有是 AI 对于海量数据的处理能力会是过去设备不具备的,过去的智能化更多的靠人工做的智能,AI 来了之后它推动了技术的革命,实际上是对于海量数据处理的能力。像眼镜,我们说它未来可能搭载更多的传感器,对于人的理解和对于环境的理解会更加深入,基于海量数据的处理之后,它能够更加主动地来服务人。我认为 AI 眼镜就是这种最核心的设备。

而关于那个「iPhone 时刻」最确切的回答,来自于阿里巴巴智能终端产品负责人晋显,他说:

从大的方向上,显示技术一定会去做突破的,并不是产品需要,而是产业链需要,因为大家老提 iPhone 时刻,但是大家往往忘了,iPhone 时刻,如果它出一个 9999 元的 iPhone,它的时刻还能来吗?如果它出一个五六百克的 iPhone,它的 iPhone 时刻还能够带来吗?如果戴不到头上的眼镜,其实 iPhone 时刻今天看不到。所以有些显示方案确实我们也在做预研,会在全彩方案,iPhone 时刻到来的时候再把它推出来。

对了,当我们说「iPhone 时刻」的时候,是指开天辟地的初代 iPhone,还是真正惊艳的 iPhone 4,亦或是带上苹果步入巅峰的 iPhone 6 系列呢?

或许只有 iPhone 时代,没有 iPhone 时刻。

AI 眼镜亦是如此,我们步入了历史,但历史的年轮要很久之后才能被看到。

稳中向好。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


夸克 AI 眼镜体验:超细镜腿没负担,还能给出手机旗舰级画质

作者 Lin
2025年11月28日 17:15

「看起来很普通」,这句话对智能眼镜来说却是很高的评价,而这正是夸克 AI 眼镜最亮眼的地方。

就在昨天,阿里旗下的夸克正式发布了 S1 和 G1 两个系列共六款 AI 眼镜,起步价分别为 3799 元和 1899 元。我体验的是带显示的旗舰款 S1,而它给我的第一印象是:这可能是目前最接近普通眼镜的智能眼镜。

更细的镜腿、更小的光机

智能眼镜的痛点一直是镜腿的宽度。不同于市面上其它智能眼镜「宽腿粗框」的外形,夸克 AI 眼镜最独特的地方就是超细镜腿——从侧面看,它的镜腿只有 7.5mm 宽,是全球同类产品中最窄的,戴起来就和普通的眼镜框没有什么区别。

为了把镜腿做得更细,眼镜的电池被安排在了镜腿尾部,左右腿各一个。调整眼镜重心的同时,右侧的电池还被巧妙地设计成了可插拔的「换电」功能,日常使用中能够快速地延长续航时间。

超细镜腿压缩了显示光机的空间,但夸克还是通过定制方案实现了双目双光机,亮度最高可达 4000nits,实测在户外确实清晰可见。比较特别的是合像距可调节功能,可以在手机 App 中自定义不同功能界面的「显示距离」。

系统也为不同功能设定了不同的默认距离,例如需要和人面对面交流的「翻译」界面就设定在 2m,需要留意路况的「导航」就设定在 9m,不仅能降低眼球的压力,也能保障出行安全。

手机同款影像处理能力,表现超预期

说实话,我对于这款眼镜的画质预期并不高,目前的智能眼镜囿于体积和功耗限制,很难做到显示和拍摄两头都强。但实际用下来,它有挺多亮眼的表现。

光线充足的情况下能实现快速抓拍,日间的画质表现稳定,夜景照片经过和手机上类似的 RAW 域处理后也能获得低噪且色彩还原度很高的画质。

除了能直出 1080P 和 3K 两种分辨率的视频以外,防抖效果也很让我惊喜,骑行画面没有大幅度起伏,也没有防抖处理的残影。值得一提的是,配套 App 内为视频提供「AI 超分」、「AI 插帧」和「防抖」的后处理功能,最高能将视频提升至 4K@60fps 的规格。在硬件已经使出浑身解数以后,通过软件优化,也不失为一种好思路。

阿里亲生的眼镜,打通内部生态

同样属于 AI 方面的功能还有眼镜里搭载的阿里千问闭源模型,借助五麦克风阵列和骨传导技术,夸克 AI 眼镜能在嘈杂环境里准确拾音并很快地给出响应,除了常规的语音问答和调节眼镜本身的显示和声音以外,还能直接在眼镜端发起导航,或者拍照搜同款识别价格。

由于同属阿里系,夸克 AI 眼镜与淘宝、支付宝、高德等应用的整合较为深入。眼镜内的「识价」功能可以直接识别商品并显示淘宝同款价格,手机端使用高德地图发起导航能直接在眼镜中投屏显示,支付宝的「看一下支付」也终于是迎来了第一方设备的支持。

除此之外还整合了高德打车、飞猪旅行、阿里商旅、航班/高铁管家中的行程信息,直接通过眼镜画面进行实时通知。眼镜内的听歌功能打通了网易云及 QQ 音乐的会员曲库,还能在眼睛前直接显示滚动歌词。

夸克 AI 眼镜 S1 在设计上取得了明显进步,7.5mm 的镜腿让智能眼镜真正接近了普通眼镜的佩戴感和外观,显示效果和 AI 功能完成度较高,阿里生态的整合带来了显著的差异化优势。

智能眼镜本就是消费电子行业最大的趋势,而在人工智能、手机数码、传统视光等多个领域的玩家纷纷入局以后,这个趋势可能会比预期要来得更快一些。目前来看,夸克 AI 眼镜 S1,这份阿里交出的第一份答卷,表现着实亮眼。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


Antigravity 登录问题/数据泄露风险 (附:白嫖一个月 Gemini Enterprise 攻略)

作者 coder_pig
2025年11月27日 14:28

1. Antigravity 登录问题

😄 最近 Google 的「哈基米3 (Gemini)-前端编程最强」和「Banana Pro-生图最强」各种刷屏,亲身体验下来确实 "实至名归"。推出的 AI IDE —— Antigravity (反重力) 也火了,各种群都有人在讨论 "登录问题" 怎么解决?🤣 其实,登不上无非两个原因,对症下药即可,详细解法看我发的上一篇文章🤷‍♀️。

🐶 海鲜市场的 Gemini 3.0 Pro (一年) 成品账号价格从开始的 15 涨到了现在的 80+ ,不多不说还是 "信息差" 赚钱啊。基本都是薅的 学生认证一年免费,群里发过教程了,这里就不赘述了。

2. Antigravity 输出中文

分享下热心群友「谢꯭盒꯭盒꯭ ®」发的 Antigravity 让模型输出中文的 Prompt:

1. Always respond in Chinese-simplified
2. You MUST conduct your internal reasoning and thinking process entirely in Simplified Chinese. This is a strict requirement.

点击 Chat 右上角的 ...,选中 Customizations

Rules 标签,点击 + Global 添加全局的 Rules,直接CV上面的 Prompt 就好了:

然后AI的 思考回答过程 都会返回中文,Nice 👍~

3. Antigravity 数据泄露风险

🤔 使用过程发现 BUG 挺多 (冗余按钮没处理、模型过载导致任务中断),体验不是特别好,而且昨天有人曝出 存在 "数据泄露风险"

《Antigravity Grounded! Security Vulnerabilities in Google's Latest IDE》

快速梳理下:

🤷‍♀️ 所以,暂时不太建议用 Antigravity 来开发公司项目,以免不必要的数据泄露风险,写写小玩具还是可以的~

4. 白嫖一个月 Gemini Enterprise

👏 谷歌 "大善人" 搞了个 Gemini Enterprise (企业级AI平台):

Geimi Enterprise

然后 商务版 提供了一个月的免费试用:

🤣 随便一个邮箱就能注册 (邮箱要能用,以便收到验证码进行登录,尽量开个新号,不要自己的gmail,以避免不要的麻烦,比如我就用的163邮箱),然后 不需要绑卡 (不用支付),就能直接畅用 Gemini 3Nano Banana Pro (具体额度是多少不知道,反正能蹬)。

😏 独乐乐,不如众乐乐,还能邀请 14 个人进入 "车队" 一起畅享 (填写对方邮箱,会发送一封邀请邮件,点击链接就能加入,不要使用 Gmail、QQ 邮箱,可能会收不到,填其它收不到的话,可以去垃圾邮件处找找看~)

😆 赶紧去试试吧,杰哥昨晚都在群里开了三个车了~

CopilotKit-丝滑连接agent和应用-理论篇

作者 let_code
2025年11月26日 11:11

CopilotKit是什么

CopilotKit 将应用的逻辑、状态和用户上下文连接到 AI 代理。提供了构建、部署和监控 AI 辅助功能的工具,这些功能感觉直观、有用且深度集成。

CopilotKit特点

  • Generative UI(生成式 UI):使用自定义 UI 组件实时呈现agent的状态、进度、输出和工具调用。
  • Human in the Loop(人机协同):用户可以在关键点指导agent。实现更可靠的输出。
  • Shared State(共享状态):agent和应用状态保持同步。agent可以查看应用中的所有状态,应用可以实时响应agent

CopilotKit和LangGraph的关系

image.png

聊天组件

前三个组件由@copilotkit/react-ui提供。

  1. CopilotChat :灵活的聊天界面组件。
  2. CopilotSidebar :可折叠和扩展的侧边栏聊天组件。
  3. CopilotPopup : 可以打开和关闭的浮动聊天组件。
  4. HeadLess UI : 支持自定义组件。
    import { useCopilotChat } from "@copilotkit/react-core";
    import { Role, TextMessage } from "@copilotkit/runtime-client-gql";
    
    export function CustomChatInterface() {
    const {
        visibleMessages,
        appendMessage,
        setMessages,
        deleteMessage,
        reloadMessages,
        stopGeneration,
        isLoading,
    } = useCopilotChat();
    
    const sendMessage = (content: string) => {
        appendMessage(new TextMessage({ content, role: Role.User }));
    };
    
    return (
        <div>
        {/* Implement your custom chat UI here */}
        </div>
    );
    }
    

设置聊天组件的样式

  • 样式:主要思路是通过样式覆盖的方式进行组件样式的设定。支持通过css变量、css类的方式进行组件样式和字体的定义。
  • 图标:通过组件的icons属性进行定义。
  • 标签:通过组件的labels属性进行自定义。

具体类名、变量名、icons属性、labels属性参考这里

自定义子组件

支持通过组件的props将自定义的子组件传递进去,从而实现子组件的自定义。

import { type AssistantMessageProps } from "@copilotkit/react-ui";
import { useChatContext } from "@copilotkit/react-ui";
import { Markdown } from "@copilotkit/react-ui";
import { SparklesIcon } from "@heroicons/react/24/outline";

import { CopilotKit } from "@copilotkit/react-core";
import { CopilotSidebar } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";

const CustomAssistantMessage = (props: AssistantMessageProps) => {
  const { icons } = useChatContext();
  const { message, isLoading, subComponent } = props;

  const avatarStyles = "bg-zinc-400 border-zinc-500 shadow-lg min-h-10 min-w-10 rounded-full text-white flex items-center justify-center";
  const messageStyles = "px-4 rounded-xl pt-2";

  const avatar = <div className={avatarStyles}><SparklesIcon className="h-6 w-6" /></div>

  return (
    <div className="py-2">
      <div className="flex items-start">
        {!subComponent && avatar}
        <div className={messageStyles}>
          {message && <Markdown content={message.content || ""} /> }
          {isLoading && icons.spinnerIcon}
        </div>
      </div>
      <div className="my-2">{subComponent}</div>
    </div>
  );
};


<CopilotKit>
  <CopilotSidebar AssistantMessage={CustomAssistantMessage} />
</CopilotKit>

子组件包括:

image.png

除此之外,markdown的渲染默认使用react-markdown。支持通过markdownTagRenderers属性来自定义markdown渲染组件。

Actions

允许 LLM 与应用程序的功能交互。当 LLM 调用 Action 时,可以提供自定义组件来可视化其执行和结果。

"use client" // only necessary if you are using Next.js with the App Router.
import { useCopilotAction } from "@copilotkit/react-core"; 

// Your custom components (examples - implement these in your app)
import { LoadingView } from "./loading-view"; // Your loading component
import { CalendarMeetingCardComponent, type CalendarMeetingCardProps } from "./calendar-meeting-card"; // Your meeting card component
 
export function YourComponent() {
  useCopilotAction({ 
    name: "showCalendarMeeting",
    description: "Displays calendar meeting information",
    parameters: [
      {
        name: "date",
        type: "string",
        description: "Meeting date (YYYY-MM-DD)",
        required: true
      },
      {
        name: "time",
        type: "string",
        description: "Meeting time (HH:mm)",
        required: true
      },
      {
        name: "meetingName",
        type: "string",
        description: "Name of the meeting",
        required: false
      }
    ],
    render: ({ status, args }) => {
      const { date, time, meetingName } = args;
 
      if (status === 'inProgress') {
        return <LoadingView />; // Your own component for loading state
      } else {
        const meetingProps: CalendarMeetingCardProps = {
          date: date,
          time,
          meetingName
        };
        return <CalendarMeetingCardComponent {...meetingProps} />;
      }
    },
  });
 
  return (
    <>...</>
  );
}

Agent State

Agent State组件允许可视化 CoAgents 的内部状态和进度。使用 CoAgents 时,可以提供自定义组件来呈现代理的状态。

"use client"; // only necessary if you are using Next.js with the App Router.
 
import { useCoAgentStateRender } from "@copilotkit/react-core";
import { Progress } from "./progress";

type AgentState = {
  logs: string[];
}

useCoAgentStateRender<AgentState>({
  name: "basic_agent",
  render: ({ state, nodeName, status }) => {
    if (!state.logs || state.logs.length === 0) {
      return null;
    }

    // Progress is a component we are omitting from this example for brevity.
    return <Progress logs={state.logs} />; 
  },
});

前端工具

前端工具指的是前端定义的函数可以被 agent 调用。当函数被 agent 调用时,函数在客户端执行,使agent可以直接访问前端环境,从而实现agent对UI的控制和人机交互。

前端工具可以轻松实现:

  1. 读取或修改 React 组件状态
  2. 访问浏览器 API,如 localStorage、sessionStorage 或 cookie
  3. 触发 UI 更新或动画
  4. 与第三方前端库交互
  5. 执行需要用户即时浏览上下文的操作

实现

1.创建前端工具

需要使用 useFrontendTool 钩子创建一个前端工具。

//page.tsx 
import { useFrontendTool } from "@copilotkit/react-core"

export function Page() {
  // ...

  useFrontendTool({
    name: "sayHello",
    description: "Say hello to the user",
    parameters: [
      {
        name: "name",
        type: "string",
        description: "The name of the user to say hello to",
        required: true,
      },
    ],
    handler: async ({ name }) => {
      alert(`Hello, ${name}!`);
    },
  });

  // ...
}

2.修改代理

安装 CopilotKit SDK npm install @copilotkit/sdk-js

要访问 CopilotKit 提供的前端工具,可以在代理的状态定义中继承 CopilotKitState :

import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph"; 

export const YourAgentStateAnnotation = Annotation.Root({
    yourAdditionalProperty: Annotation<string>,
    ...CopilotKitStateAnnotation.spec, 
});
export type YourAgentState = typeof YourAgentStateAnnotation.State;

之后,代理的状态将包括 copilotkit 属性,其中包含可以访问和调用的前端工具。

agent调用前端工具:

async function agentNode(state: YourAgentState, config: RunnableConfig): Promise<YourAgentState> {
    // Access the tools from the copilotkit property

    const tools = state.copilotkit?.actions; 
    const model = ChatOpenAI({ model: 'gpt-4o' }).bindTools(tools);

    // ...
}

Generative UI

用自定义 UI 组件实时呈现 agent 的状态、进度、输出和工具调用。

主要有三种方式使用生成式UI:

  1. 后端工具:通过生成式UI组件渲染工具的调用
  2. 前端工具:为agent提供前端工具来显示自定义组件并且驱动UI
  3. agent 状态:用自定义组件来显示agent的状态、进度和输出

后端工具

工具是 LLM 调用预定义的(通常是确定性函数)的一种方式。CopilotKit 允许在 UI 中将这些工具呈现为自定义组件,我们称之为生成式 UI。

简而言之就是允许我们向用户展示agent正在执行的操作,尤其是当我们调用工具时,允许完全自定义工具在聊天中的呈现方式。

//agent.ts
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "@langchain/core/tools";
import { z } from "zod";

const get_weather = tool(
  (args) => {
    return `The weather for ${args.location} is 70 degrees.`;
  },
  {
    name: "get_weather",
    description: "Get the weather for a given location.",
    schema: z.object({
      location: z.string().describe("The location to get weather for"),
    }),
  }
);

async function chat_node(state: AgentState, config: RunnableConfig) {
  const model = new ChatOpenAI({ temperature: 0, model: "gpt-4o" });
  const modelWithTools = model.bindTools([get_weather]); 

  const response = await modelWithTools.invoke([
    new SystemMessage("You are a helpful assistant."),
    ...state.messages,
  ], config);

  // ...
}

前端通过useCopilotAction钩子在UI中呈现:

//page.tsx  
import { useRenderToolCall } from "@copilotkit/react-core"; 
// ...

const YourMainContent = () => {
  // ...
  useRenderToolCall({
    name: "get_weather",// 注意name保持一致
    render: ({status, args}) => {
      return (
        <p className="text-gray-500 mt-2">
          {status !== "complete" && "Calling weather API..."}
          {status === "complete" && `Called the weather API for ${args.location}.`}
        </p>
      );
    },
  });
  // ...
}

useDefaultTool 捕获所有没有专用渲染器的工具。

//page.tsx
import { useDefaultTool } from "@copilotkit/react-core"; 
// ...

const YourMainContent = () => {
  // ...
  useDefaultTool({
    render: ({ name, args, status, result }) => {
      return (
        <div style={{ color: "black" }}>
          <span>
            {status === "complete" ? "✓" : "⏳"}
            {name}
          </span>
          {status === "complete" && result && (
            <pre>{JSON.stringify(result, null, 2)}</pre>
          )}
        </div>
      );
    },
  });
  // ...
}

前端工具

定义 LangGraph agent 可以调用的客户端函数,执行完全在用户的浏览器中进行。当agent调用前端工具时,逻辑会在客户端运行,使agent可以直接访问前端环境。一般在agent需要和客户端交互时使用。

使用 useFrontendTool 钩子创建一个前端工具:

// page.tsx
import { useFrontendTool } from "@copilotkit/react-core"

export function Page() {
  // ...

  useFrontendTool({
    name: "sayHello",
    description: "Say hello to the user",
    parameters: [
      {
        name: "name",
        type: "string",
        description: "The name of the user to say hello to",
        required: true,
      },
    ],
    handler({ name }) {
      // Handler returns the result of the tool call
      return { currentURLPath: window.location.href, userName: name };
    },
    render: ({ args }) => {
      // Renders UI based on the data of the tool call
      return (
        <div>
          <h1>Hello, {args.name}!</h1>
          <h1>You're currently on {window.location.href}</h1>
        </div>
      );
    },
  });

  // ...
}

agent 访问前端工具:

//agent.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph"; 

export const YourAgentStateAnnotation = Annotation.Root({
    yourAdditionalProperty: Annotation<string>,
    ...CopilotKitStateAnnotation.spec, 
});
export type YourAgentState = typeof YourAgentStateAnnotation.State;

//现在,agent的状态将包括 copilotkit 属性,其中包含可以访问和调用的前端工具。
async function agentNode(state: YourAgentState, config: RunnableConfig): Promise<YourAgentState> {
    // Access the tools from the copilotkit property

    const tools = state.copilotkit?.actions; 
    const model = ChatOpenAI({ model: 'gpt-4o' }).bindTools(tools);

    // ...
}

agent 状态

所有 LangGraph agent 都是状态化的。这意味着当 agent 通过节点时,一个状态对象会在它们之间传递,以保持会话的整体状态。CopilotKit 允许使用自定义 UI 组件(生成式 UI)在应用程序中呈现此状态。

// agent.ts
import { RunnableConfig } from "@langchain/core/runnables";
import { ChatOpenAI } from "@langchain/openai";
import { Annotation } from "@langchain/langgraph";
import { SystemMessage } from "@langchain/core/messages";
import { copilotkitEmitState, CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

type Search = {
  query: string;
  done: boolean;
}

export const AgentStateAnnotation = Annotation.Root({
  searches: Annotation<Search[]>,
  ...CopilotKitStateAnnotation.spec,
});

async function chat_node(state: AgentState, config: RunnableConfig) {
  state.searches = [
    { query: "Initial research", done: false },
    { query: "Retrieving sources", done: false },
    { query: "Forming an answer", done: false },
  ];

  // We can call copilotkit_emit_state to emit updated state
  // before a node finishes
  await copilotkitEmitState(config, state);

  // Simulate state updates
  for (const search of state.searches) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    search.done = true;

    // We can also emit updates in a loop to simulate progress
    await copilotkitEmitState(config, state);
  }

  const response = await new ChatOpenAI({ model: "gpt-4o" }).invoke([
    new SystemMessage({ content: "You are a helpful assistant."}),
    ...state.messages,
  ], config);

前端通过 useCoAgentStateRender 在聊天中呈现agent的状态:

//page.tsx
import { useCoAgentStateRender } from "@copilotkit/react-core";

// For type safety, redefine the state of the agent. If you're using
// using LangGraph JS you can import the type here and share it.
type AgentState = {
  searches: {
    query: string;
    done: boolean;
  }[];
};

function YourMainContent() {
  // ...

  // styles omitted for brevity
  useCoAgentStateRender<AgentState>({
    name: "sample_agent", // the name the agent is served as
    render: ({ state }) => (
      <div>
        {state.searches?.map((search, index) => (
          <div key={index}>
            {search.done ? "✅" : "❌"} {search.query}{search.done ? "" : "..."}
          </div>
        ))}
      </div>
    ),
  });

  // ...

  return <div>...</div>;
}

除此之外还允许在聊天之外呈现agent的状态:

//page.tsx
import { useCoAgent } from "@copilotkit/react-core"; 
// ...

// Define the state of the agent, should match the state of the agent in your LangGraph.
type AgentState = {
  searches: {
    query: string;
    done: boolean;
  }[];
};

function YourMainContent() {
  // ...

  const { state } = useCoAgent<AgentState>({
    name: "sample_agent", // the name the agent is served as
  })

  // ...

  return (
    <div>
      {/* ... */}
      <div className="flex flex-col gap-2 mt-4">
        {state.searches?.map((search, index) => (
          <div key={index} className="flex flex-row">
            {search.done ? "✅" : "❌"} {search.query}
          </div>
        ))}
      </div>
    </div>
  )
}

Human in the Loop (HITL)

用户与 agent 协作处理复杂任务。

主要有三种方式实现人机交互:

  1. 基于中断
  2. 基于前端工具
  3. 基于节点

基于中断

基础

需要一个状态属性来存储名称:

//agent.ts
// ...
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";
// ...

// This is the state of the agent.
// It inherits from the CopilotKitState properties from CopilotKit.
export const AgentStateAnnotation = Annotation.Root({
  agentName: Annotation<string>,
  ...CopilotKitStateAnnotation.spec,
});
export type AgentState = typeof AgentStateAnnotation.State;

在LangGraph 代理中调用 interrupt:

//agent.ts
import { interrupt } from "@langchain/langgraph"; 
import { SystemMessage } from "@langchain/core/messages";
import { ChatOpenAI } from "@langchain/openai";

// add the agent state definition from the previous step
export const AgentStateAnnotation = Annotation.Root({
    agentName: Annotation<string>,
    ...CopilotKitStateAnnotation.spec,
});
export type AgentState = typeof AgentStateAnnotation.State;

async function chat_node(state: AgentState, config: RunnableConfig) {
    const agentName = state.agentName
    ?? interrupt("Before we start, what would you like to call me?"); 

    // Tell the agent its name
    const systemMessage = new SystemMessage({
        content: `You are a helpful assistant named ${agentName}...`,
    });

    const response = await new ChatOpenAI({ model: "gpt-4o" }).invoke(
        [systemMessage, ...state.messages],
        config
    );

    return {
        ...state,
        agentName,
        messages: response,
    };
}

前端使用 useLangGraphInterrupt 钩子,为终中断提供一个要渲染的组件,然后使用用户的响应调用 resolve。

//page.tsx
import { useLangGraphInterrupt } from "@copilotkit/react-core"; 
// ...

const YourMainContent = () => {
// ...
// styles omitted for brevity
useLangGraphInterrupt({
    render: ({ event, resolve }) => (
        <div>
            <p>{event.value}</p>
            <form onSubmit={(e) => {
                e.preventDefault();
                resolve((e.target as HTMLFormElement).response.value);
            }}>
                <input type="text" name="response" placeholder="Enter your response" />
                <button type="submit">Submit</button>
            </form>
        </div>
    )
});
// ...

return <div>{/* ... */}</div>
}

高级

在代理中呈现多个中断事件时,UI 中的多个 useLangGraphInterrupt 钩子调用之间可能会发生冲突。出于这个原因,钩子可以接受一个 enabled 参数,该参数将有条件地应用它:

定义两个不同的中断,通过type进行区分:

//agent.ts
import { interrupt } from "@langchain/langgraph"; 
import { SystemMessage } from "@langchain/core/messages";
import { ChatOpenAI } from "@langchain/openai";

// ... your full state definition

async function chat_node(state: AgentState, config: RunnableConfig) {
  state.approval = await interrupt({ type: "approval", content: "please approve" }); 

  if (!state.agentName) {
    state.agentName = await interrupt({ type: "ask", content: "Before we start, what would you like to call me?" }); 
  }

  // Tell the agent its name
  const systemMessage = new SystemMessage({
    content: `You are a helpful assistant...`,
  });

  const response = await new ChatOpenAI({ model: "gpt-4o" }).invoke(
    [systemMessage, ...state.messages],
    config
  );

  return {
    ...state,
    messages: response,
  };
}

前端定义多个处理程序:

//page.tsx
import { useLangGraphInterrupt } from "@copilotkit/react-core"; 
// ...

const ApproveComponent = ({ content, onAnswer }: { content: string; onAnswer: (approved: boolean) => void }) => (
    // styles omitted for brevity
    <div>
        <h1>Do you approve?</h1>
        <button onClick={() => onAnswer(true)}>Approve</button>
        <button onClick={() => onAnswer(false)}>Reject</button>
    </div>
)

const AskComponent = ({ question, onAnswer }: { question: string; onAnswer: (answer: string) => void }) => (
// styles omitted for brevity
    <div>
        <p>{question}</p>
        <form onSubmit={(e) => {
            e.preventDefault();
            onAnswer((e.target as HTMLFormElement).response.value);
        }}>
            <input type="text" name="response" placeholder="Enter your response" />
            <button type="submit">Submit</button>
        </form>
    </div>
)

const YourMainContent = () => {
    // ...
    useLangGraphInterrupt({
        enabled: ({ eventValue }) => eventValue.type === 'ask',
        render: ({ event, resolve }) => (
            <AskComponent question={event.value.content} onAnswer={answer => resolve(answer)} />
        )
    });

    useLangGraphInterrupt({
        enabled: ({ eventValue }) => eventValue.type === 'approval',
        render: ({ event, resolve }) => (
            <ApproveComponent content={event.value.content} onAnswer={answer => resolve(answer)} />
        )
    });

    // ...
}

选择自定义聊天 UI 时,某些情况可能需要预处理中断事件的传入值,甚至需要完全解析它而不显示其 UI。这可以使用 handeer 属性来实现,该属性不需要返回一个 React 组件。 处理程序的返回值将作为结果参数传递给 render 方法。

//page.tsx
// We will assume an interrupt event in the following shape
type Department = 'finance' | 'engineering' | 'admin'
interface AuthorizationInterruptEvent {
    type: 'auth',
    accessDepartment: Department,
}

import { useLangGraphInterrupt } from "@copilotkit/react-core";

const YourMainContent = () => {
    const [userEmail, setUserEmail] = useState({ email: 'example@user.com' })
    function getUserByEmail(email: string): { id: string; department: Department } {
        // ... an implementation of user fetching
    }

    // ...
    // styles omitted for brevity
    useLangGraphInterrupt({
        handler: async ({ result, event, resolve }) => {
            const { department } = await getUserByEmail(userEmail)
            if (event.value.accessDepartment === department || department === 'admin') {
                // Following the resolution of the event, we will not proceed to the render method
                resolve({ code: 'AUTH_BY_DEPARTMENT' })
                return;
            }

            return { department, userId }
        },
        render: ({ result, event, resolve }) => (
            <div>
                <h1>Request for {event.value.type}</h1>
                <p>Members from {result.department} department cannot access this information</p>
                <p>You can request access from an administrator to continue.</p>
                <button
                    onClick={() => resolve({ code: 'REQUEST_AUTH', data: { department: result.department, userId: result.userId } })}
                >
                    Request Access
                </button>
                <button
                    onClick={() => resolve({ code: 'CANCEL' })}
                >
                    Cancel
                </button>
            </div>
        )
    });
    // ...

    return <div>{/* ... */}</div>
}

基于前端工具

前端工具可以用在多种方式上。其中一种方式是有人工介入的流程,工具的响应由用户的决定来控制。

在这个例子中,我们将模拟一个用于执行命令的“批准”流程。首先,使用useHumanInTheLoop钩子来创建一个提示用户批准的工具。

要访问由 CopilotKit 提供的前端工具,您可以在agent的状态定义中继承自 CopilotKitState:

//agent.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph"; 

export const YourAgentStateAnnotation = Annotation.Root({
    yourAdditionalProperty: Annotation<string>,
    ...CopilotKitStateAnnotation.spec, 
});
export type YourAgentState = typeof YourAgentStateAnnotation.State;

经上述操作,agent的状态将包括 copilotkit 属性,其中包含可以访问和调用的前端工具。接下来就可以调用前端工具方法:

//agent.tsx
async function agentNode(state: YourAgentState, config: RunnableConfig): Promise<YourAgentState> {
    // Access the tools from the copilotkit property

    const tools = state.copilotkit?.actions; 
    const model = ChatOpenAI({ model: 'gpt-4o' }).bindTools(tools);

    // ...
}

基于节点

LangGraph 和 CopilotKit 现在都不鼓励使用基于节点的中断。从 LangGraph 0.2.57 开始,推荐的设置断点的方法是使用 interrupt 函数 ,因为它简化了人机交互模式。

想要了解可以参考这里

状态共享

在 UI 和 LangGraph agent 状态之间创建双向连接。

读取agent状态

不仅可以在聊天界面中使用实时代理状态,还可以在原生应用程序中使用。

LangGraph 是有状态的。在节点之间转换时,该状态将更新并传递到下一个节点。假设agent状态如下所示:

//agent.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

export const AgentStateAnnotation = Annotation.Root({
    language: Annotation<"english" | "spanish">,
    ...CopilotKitStateAnnotation.spec,
});
export type AgentState = typeof AgentStateAnnotation.State;

async function chat_node(state: AgentState, config: RunnableConfig) {
  // If language is not defined, use a default value.
  const language = state.language ?? 'spanish'

  // ... add the rest of the node implementation and use the language variable

  return {
    // ... add the rest of state to return
    // return the language to make it available for the next nodes & frontend to read
    language
  }
}

前端调用 useCoAgent 钩子,传递agent的名称,并选择性地提供初始状态:

//pages.tsx
import { useCoAgent } from "@copilotkit/react-core"; 

// Define the agent state type, should match the actual state of your agent
type AgentState = {
  language: "english" | "spanish";
}

function YourMainContent() {
  const { state } = useCoAgent<AgentState>({
    name: "sample_agent",
    initialState: { language: "spanish" }  // optionally provide an initial state
  });

  // ...

  return (
    // style excluded for brevity
    <div>
      <h1>Your main content</h1>
      <p>Language: {state.language}</p> // [!code highlight]
    </div>
  );
}

useCoAgent 中的状态是响应式的,当代理的状态发生变化时会自动更新

在聊天中渲染 agent 状态

可以使用 useCoAgentStateRender 钩子。

//page.tsx
import { useCoAgentStateRender } from "@copilotkit/react-core"; 

// Define the agent state type, should match the actual state of your agent
type AgentState = {
  language: "english" | "spanish";
}

function YourMainContent() {
  // ...
  useCoAgentStateRender({
    name: "sample_agent",
    render: ({ state }) => {
      if (!state.language) return null;
      return <div>Language: {state.language}</div>;
    },
  });
  // ...
}

useCoAgentStateRender 中的状态是响应式的,当代理的状态发生变化时会自动更新。

写入agent状态

假设 agent 状态:

//agebt.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

export const AgentStateAnnotation = Annotation.Root({
    language: Annotation<"english" | "spanish">,
    ...CopilotKitStateAnnotation.spec,
});
export type AgentState = typeof AgentStateAnnotation.State;

useCoAgent 返回一个 setState 函数,您可以使用该函数来更新代理状态。调用这个将更新代理状态并触发依赖于代理状态的任何内容的重新渲染。

//page.tsx
import { useCoAgent } from "@copilotkit/react-core"; 

// Define the agent state type, should match the actual state of your agent
type AgentState = {
  language: "english" | "spanish";
}

// Example usage in a pseudo React component
function YourMainContent() {
  const { state, setState } = useCoAgent<AgentState>({ 
    name: "sample_agent",
    initialState: { language: "spanish" }  // optionally provide an initial state
  });

  // ...

  const toggleLanguage = () => {
    setState({ language: state.language === "english" ? "spanish" : "english" }); 
  };

  // ...

  return (
    // style excluded for brevity
    <div>
      <h1>Your main content</h1>
      <p>Language: {state.language}</p>
      <button onClick={toggleLanguage}>Toggle Language</button>
    </div>
  );
}

高级用法

重新运行agent,并提示更改内容

新的 agent 状态将在下次 agent 运行时使用。如果您想手动重新运行它,请在useCoAgent钩子上使用run参数。 agent将重新运行,它不仅会获得最新的更新状态,还会获得可能取决于以前状态和当前状态之间的数据增量的提示 。

//page.tsx
import { useCoAgent } from "@copilotkit/react-core";
import { TextMessage, MessageRole } from "@copilotkit/runtime-client-gql";  

// ...

function YourMainContent() {
  const { state, setState, run } = useCoAgent<AgentState>({
    name: "sample_agent",
    initialState: { language: "spanish" }  // optionally provide an initial state
  });

  // setup to be called when some event in the app occurs
  const toggleLanguage = () => {
    const newLanguage = state.language === "english" ? "spanish" : "english";
    setState({ language: newLanguage });

    // re-run the agent and provide a hint about what's changed
    run(({ previousState, currentState }) => {
      return new TextMessage({
        role: MessageRole.User,
        content: `the language has been updated to ${currentState.language}`,
      });
    });
  };

  return (
    // ...
  );
}

agent状态输入和输出

有些属性是内部处理的,而另一些则是 UI 传递用户输入的方式。此外,有些状态属性包含大量信息。在agent和 UI 之间来回同步它们可能成本高昂,而且可能没有实际好处。

假设状态如下:

//agent.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

const AgentState = Annotation.Root({
  ...CopilotKitStateAnnotation.spec,
  question: Annotation<string>, //期望LLM回答的问题
  answer: Annotation<string>,//LLM回应的答案
  resources: Annotation<string[]>,//用于LLM回答问题,不应向用户同步
})

agent定义输入输出:

//agent.ts
  import { Annotation } from "@langchain/langgraph";
  import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

  // Divide the state to 3 parts

  // An input schema for inputs you are willing to accept from the frontend
  const InputAnnotation = Annotation.Root({
    ...CopilotKitStateAnnotation.spec,
    question: Annotation<string>,
  });

  // Output schema for output you are willing to pass to the frontend
  const OutputAnnotation = Annotation.Root({
    ...CopilotKitStateAnnotation.spec,
    answer: Annotation<string>,
  });

  // The full schema, including the inputs, outputs and internal state ("resources" in our case)
  export const AgentStateAnnotation = Annotation.Root({
    ...CopilotKitStateAnnotation.spec,
    ...OutputAnnotation.spec,
    ...InputAnnotation.spec,
    resources: Annotation<string[]>,
  });

  // Define a typed state that supports the entire
  export type AgentState = typeof AgentStateAnnotation.State;

  async function answerNode(state: AgentState, config: RunnableConfig) {
    const model = new ChatOpenAI()

    const systemMessage = new SystemMessage({
      content: `You are a helpful assistant. Answer the question: ${state.question}.`,
    });

    const response = await modelWithTools.invoke(
      [systemMessage, ...state.messages],
      config
    );

    // ...add the rest of the agent implementation
    // extract the answer, which will be assigned to the state soon
    const answer = response.content

    return {
      messages: response,
      // include the answer in the returned state
      answer,
    }
  }

  // finally, before compiling the graph, we define the 3 state components
  const workflow = new StateGraph({
    input: InputAnnotation,
    output: OutputAnnotation,
    // @ts-expect-error -- LangGraph does not expect a "full schema with internal properties".
    stateSchema: AgentStateAnnotation,
  })
    .addNode("answer_node", answerNode) // add all the different nodes and edges and compile the graph
    .addEdge(START, "answer_node")
    .addEdge("answer_node", END)
  export const graph = workflow.compile()

预测状态更新

一个LangGraph agent的状态更新是不连续的;仅在图中的节点转换之间进行。但是,图中单个节点运行往往需要许多秒,并且包含用户感兴趣的子步骤。

预测状态更新帮助我们向用户尽可能连续的反应 agent 正在执行的操作。

当你的LangGraph中的节点执行完毕时,其返回的状态成为唯一的真实来源。虽然中间状态更新对于实时反馈很有帮助,但任何你想持久化的更改都必须明确地包含在节点的最终返回状态中。否则,它们将在节点完成时被覆盖。

在状态中定义一个 observed_steps 字段,该字段将在agent编写报告的不同部分时更新。

//agent.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

export const AgentStateAnnotation = Annotation.Root({
    observed_steps: Annotation<string[]>,  // Array of completed steps
    ...CopilotKitStateAnnotation.spec,
});
export type AgentState = typeof AgentStateAnnotation.State;

有两种发出状态更新的方式:手动预测和基于工具的预测。

手动预测状态更新

对于长时间运行的任务,可以逐步发出状态更新,作为最终状态的预测。在这个例子中,我们通过执行一系列带有每次更新之间一秒延迟的步骤来模拟一个长时间运行的任务。

//agent.ts
import { copilotkitEmitState } from "@copilotkit/sdk-js/langgraph"; 
// ...
async function chat_node(state: AgentState, config: RunnableConfig) {
    // ...

    // Simulate executing steps one by one
    const steps = [
        "Analyzing input data...",
        "Identifying key patterns...",
        "Generating recommendations...",
        "Formatting final output..."
    ];
    
    for (const step of steps) {
        state.observed_steps = [...(state.observed_steps ?? []), step];
        copilotkitEmitState(config, state);
        await new Promise(resolve => setTimeout(resolve, 1000));
    }
}

这些预测将在代理运行时发出,允许您在确定最终状态之前跟踪其进度:

//page.tsx
import { useCoAgent, useCoAgentStateRender } from '@copilotkit/react-core';

// ...
type AgentState = {
    observed_steps: string[];
};

const YourMainContent = () => {
    // Get access to both predicted and final states
    const { state } = useCoAgent<AgentState>({ name: "sample_agent" });

    // Add a state renderer to observe predictions
    useCoAgentStateRender({
        name: "sample_agent",
        render: ({ state }) => {
            if (!state.observed_steps?.length) return null;
            return (
                <div>
                    <h3>Current Progress:</h3>
                    <ul>
                        {state.observed_steps.map((step, i) => (
                            <li key={i}>{step}</li>
                        ))}
                    </ul>
                </div>
            );
        },
    });

    return (
        <div>
            <h1>Agent Progress</h1>
            {state.observed_steps?.length > 0 && (
                <div>
                    <h3>Final Steps:</h3>
                    <ul>
                        {state.observed_steps.map((step, i) => (
                            <li key={i}>{step}</li>
                        ))}
                    </ul>
                </div>
            )}
        </div>
    )
}

基于工具预测状态更新

对于长时间运行的任务,您可以配置 CopilotKit 在执行特定工具调用时自动预测状态更新。在这个示例中,我们将配置 CopilotKit 在 LLM 调用步骤进度工具时预测状态更新。

//agent.ts
import { copilotkitCustomizeConfig } from '@copilotkit/sdk-js/langgraph';

async function frontendActionsNode(state: AgentState, config: RunnableConfig): Promise<AgentState> {
    const modifiedConfig = copilotkitCustomizeConfig(config, {
        emitIntermediateState: [
        {
            stateKey: "observed_steps",
            tool: "StepProgressTool",
            toolArgument: "steps",
        },
        ],
    });

    const stepProgress = tool(
        async (args) => args,
        {
            name: "StepProgressTool",
            description: "Records progress by updating the steps array",
            schema: z.object({
                steps: z.array(z.string()),
            }),
        }
    );

    const model = new ChatOpenAI({
        model: "gpt-4o",
    }).bindTools([stepProgress]);

    const system_message = new SystemMessage("You are a task performer. Pretend doing tasks you are given, report the steps using StepProgressTool.")
    const response = await model.invoke([system_message, ...state.messages], modifiedConfig);


    if (response.tool_calls?.length) {
        return {
            messages: response;
            observed_steps: response.tool_calls[0].args.steps,
        }

    return { messages: response };
}

这些预测将在代理运行时发出,允许您在确定最终状态之前跟踪其进度:

//page.tsx
import { useCoAgent, useCoAgentStateRender } from '@copilotkit/react-core';

// ...
type AgentState = {
    observed_steps: string[];
};

const YourMainContent = () => {
    // Get access to both predicted and final states
    const { state } = useCoAgent<AgentState>({ name: "sample_agent" });

    // Add a state renderer to observe predictions
    useCoAgentStateRender({
        name: "sample_agent",
        render: ({ state }) => {
            if (!state.observed_steps?.length) return null;
            return (
                <div>
                    <h3>Current Progress:</h3>
                    <ul>
                        {state.observed_steps.map((step, i) => (
                            <li key={i}>{step}</li>
                        ))}
                    </ul>
                </div>
            );
        },
    });

    return (
        <div>
            <h1>Agent Progress</h1>
            {state.observed_steps?.length > 0 && (
                <div>
                    <h3>Final Steps:</h3>
                    <ul>
                        {state.observed_steps.map((step, i) => (
                            <li key={i}>{step}</li>
                        ))}
                    </ul>
                </div>
            )}
        </div>
    )
}

子图

一个子图简单地是作为另一个图中的节点使用的图。把它看作是LangGraph的封装:每个子图是一个自包含的单元,可以组合起来构建更大、更复杂的系统。

使用此功能不需要在agent端执行额外步骤。您需要做的就是在 useCoAgent 钩子中启用子图流:

  const { state, nodeName } = useCoAgent<AgentState>({
    name: "sample_agent",
    initialState: INITIAL_STATE,
    config: {
      streamSubgraphs: true, 
    }
  });

子图节点将照常流式传输,你将能够使用 nodeName 变量查看哪个子图正在流式传输。您也可以直接从子图使用 interrupt()

Ilya 罕见发声:Scaling 时代已结束,我们对 AGI 的定义可能全错了

作者 张子豪
2025年11月26日 17:46

修个 bug 可以来回把同一个错误引回来,写代码能绕一圈又走回原地。

但几乎所有 AI 公司都坚信,只要把模型做大、把数据堆满、把算力扔进去,智能就会自动涌现。这套规模定律(Scaling Law)曾经是硅谷最坚定的信仰。

在隐退许久并创立新公司 SSI(Safe Superintelligence)后,前 OpenAI 首席科学家 Ilya Sutskever 用一种极其冷静的语调,宣告「Scaling 的时代结束了,我们重新回到了研究时代。

最近一场 Ilya 与 Dwarkesh Patel 的深度对话中,他不仅给出了,对于 AI 未来的技术路线图,更重要的是,他深刻地回答了,为什么现在的 AI 即使再强,也依然不像人。

🔗 播客链接:https://x.com/dwarkesh_sp/status/1993371363026125147

为什么 AI 是个高分低能的优等生

我们总觉得现在的 AI 很强,它们能在编程竞赛、数学竞赛、各种榜单上拿金牌,每次有新的模型发布,也是一次次刷新着各种 benchmark。但 Ilya 指出了一个让他感到困惑的现象。

▲ 最新发布的 Claude 4.5 Opus 模型,在编程相关的榜单,已经拿到了 80.9 分

他说我们在用 vibe coding,要 AI 写代码时,AI 可能写到某个地方,出现了一个 Bug。我们直接告诉它:「这儿有个错误。」AI 会说:「天呐你是对的,我马上改。」 然后它解决了这个 Bug,又引入了另一个 Bug。 你再指出,它又改回了第一个 Bug。 它就在这两个 Bug 之间无限循环,显得极其笨拙。

他的解释提到了这说明 AI 的「泛化能力(Generalization)」出了问题。为了解释这个词,Ilya 用不同的学生打了一个比方。

想象两个学生都在学编程,学生 A 代表 AI, 极其刻苦,练了 10000 个小时。他背下了所有的题库,记住了所有的解题套路。考试时,只要见过类似的题,他就能拿满分。

学生 B 代表人类,他只是觉得编程竞赛很酷,花了 100 个小时练习,但他真正理解了编程的逻辑,拥有了某种直觉,也能做得很好。长期来看,谁会在职业生涯中走得更远?他说一定是学生 B。

而现在的 AI 就像学生 A。所谓的智能,很大程度上是靠海量数据强行记忆出来的;它们在特定问题的庞大、增强数据集上过度训练,使它们在任务上表现出色,但不一定擅长泛化到其他领域。

一旦遇到训练数据之外的微小变动,比如修复一个重复出现的 Bug,它缺乏那种举一反三的泛化能力。

从堆算力回归拼创意

但这种海量数据的训练方式也不是完全没有用。在过去五年里,AI 行业的发展基本上都是遵循着所谓的「规模定律 Scaling Law」,从一开始的还是以百万参数来衡量的大模型,现在都来到了万亿参数。GPU 显卡算力的消耗,规模更是未雨绸缪,要卷上天际。

这种把一定量的算力,和一定量的数据混合进一个神经网络里的方案,也成了所有大模型开发的必备流程,即预训练。在预训练阶段,不需要思考用什么数据,因为答案是所有数据,它是人类投射到文本上的整个世界。

而 Ilya 认为,「Scaling」这个词,本身就固定了我们的思维。它暗示着我们只需要做一件事:加算力,加数据,保持配方不变,把锅搞大一点,就能做出好菜。

他说这样的法则,让大公司很舒服,因为这是一种「低风险」的投资。相比于需要灵感和运气的研究,大公司不需要雇佣科学家去苦思冥想,只需要「加数据、加算力」,而模型变强的结果是可预测的。

但现在,瓶颈来了。数据不够了,预训练数据,我们的互联网文本语料是有限的,而且已经快被用光了;有专门的研究结构统计过,现在互联网上 AI 内容的比例,已经是超过我们人类输出的内容。

其次是边际效应,把模型再做大 100 倍,也许会有提升,但不会带来质变。

Ilya 也提到了最近在 X 上,有人说 Gemini 3 似乎解决了预训练的一些问题。而此前 The Information 也曾报道奥特曼担心 Google 的发展会影响 OpenAI,甚至已经让他感受到压力。

其中一部分的原因,正是 GPT-5 的推出,遇到了预训练上的问题,即随着预训练数据的增加,模型并没有像之前一样表现出智能的提升。反而 Gemini 确找到了突破的方法,奥特曼在内部备忘录里说,OpenAI 也必须解决预训练的问题,或许才能再次超过 Google。

▲ Google DeepMind 研究副总裁 Oriol Vinyals 提到 Gemini 3 的秘密,是解决了预训练的问题

我们回到了研究时代。只不过这一次,我们有了更大的计算机。

Ilya 把过去这段时间的研究,分成了两个阶段。2012 年到 2020 年是研究时代,大家都在试错,寻找新方法。而 2020 年到 2025 年,是扩展时代,大家都在盲目扩建,算力在扩建,越来越多的 AI 公司在出现。

而现在,单纯的大力出奇迹已经行不通了,或者说单纯靠 Scaling 的红利吃尽了,我们又回到了研究时代。只不过这一次,我们是在用 Scaling 时代建立起来的巨型计算机来做研究,这是一个有着大型算力的研究时代。

总的来说,Ilya 并没有否认预训练和 Scaling 的巨大成功,但他认为这是一种用钱换智能的,低风险暴力美学,而现在这种模式已经触到了天花板,AI 行业必须回归到拼想法、拼直觉、拼创新的硬核研究阶段。

寻找直觉:AI 缺失的那块拼图

如果单纯的数据堆叠无法产生真正的智能,那人类的秘诀是什么?Ilya 给出的答案是:情感(Emotions)

他提到了一个脑损伤患者的案例,这个人失去了情感能力,虽然智商正常、能言善辩,却连穿哪双袜子都要纠结几个小时。 这说明情感不仅是情绪,它本质上是一个价值函数(Value Function)。

不过 Ilya 说目前没有找到很合适的概念,来类比情绪在机器学习中的角色,所以用价值函数来替代。

为了解释什么是价值函数,Ilya 提到了少年学开车的例子, 一个青少年,可能只需要练 10 个小时甚至更少,就能学会开车上路。他不需要像现在的自动驾驶 AI 那样,在模拟器里撞车几百万次才能学会避让。

为什么?因为人类自带了一个极其强大的价值函数,这个价值函数就像一个内置评价器,一旦偏离车道,我们人类会感到紧张,而这相当于一种负反馈。

那么依赖情绪的价值函数,和我们之前一直听到的强化学习,区别又是什么呢?

Ilya 说在没有中间价值函数的强化学习里,通常要等到任务彻底结束,AI 才知道自己是赢了还是输了;但价值函数就像是我们的直觉或内心评分系统。当我们下棋丢了一个子,不需要等到这盘棋下完,我们心里立马会「咯噔」一下,这步棋下错了。

那个学开车的少年,不用等到真的压线丢分了才会改正,而是只要开得稍微偏离车道,他立刻会感到紧张或不自信。这种实时的、内在的反馈机制,让他能极其高效地从少量经验中学习。

对于传统的强化学习,他的看法是这是一种天真且低效率做法。在传统的强化学习中,模型需要尝试成千上万次动作或思考步骤,直到产出一个最终的解决方案,然后根据这个最终结果的好坏获得一个评分,即训练信号。

这意味着在得出最终解之前,模型完全没有进行任何学习。这种方法需要消耗大量的计算资源来进行漫长的推演,但每次推演带来的学习量却相对较少。

而价值函数不需要等到最后,它能提供中间过程的评价;在每一步都给出信号,指引方向,从而极大地压缩了搜索空间,提高了学习速度。

目前的 AI 缺乏这种高效的内心评分系统。如果我们能让 AI,拥有类似人类情感或本能的价值判断能力,它就能摆脱对海量数据的依赖,真正像人一样高效学习。

Ilya 的下一步是直通超级智能

既然认定了拼算力的时代已经过去,而强大的价值函数或许又会成为新的 AI 方法,那 Ilya 的新公司 SSI(Safe Superintelligence)打算怎么做?

他的答案带着一种极其理想主义的色彩,直通超智能,他们选择去攻克那个最根本的难题,实现可靠的泛化

Ilya 直言,现在的 AI 行业陷入了一场老鼠赛跑。为了在市场竞争中存活,公司被迫不断发布半成品,被迫在产品体验和安全性之间做艰难的权衡。SSI 想要做的是从这种商业噪音中抽离出来,闭门造车,直到造出真正的超级智能。

但有趣的是,Ilya 这种「闭关修炼」的想法正在发生动摇。他开始意识到,渐进式发布可能才是安全的必经之路。

为什么?因为人类的想象力是贫瘠的。如果你只是写文章、发论文告诉大家AI 会很强,大家只会觉得这是科幻小说。只有当人们亲眼看到 AI 展现出某种令人不安的力量时,所有人、包括竞争对手,才会真正感到害怕,从而变得更加关注安全 。

Ilya 预言,随着 AI 变得越来越强,现在打得不可开交的科技巨头们,最终会在 AI 安全策略上走向趋同。

播客里他也提到了,SSI 与 OpenAI、Google 那些大型实验室相比,虽然筹集的资金较少,但用于纯研究的计算能力比表面上看是更多的。他说那些大公司将大量的计算资源用于产品推理,并拥有庞大的工程和销售团队,导致其资源分散。Ilya 认为 SSI 拥有足够的计算能力,来证明其想法是正确的。

当被问及盈利模式时,Ilya 只是淡淡地说,我们只专注于研究,赚钱的问题以后自然会有答案。主持也提到了之前 SSI 的前 CEO(联合创始人)选择了离开,然后加入 Meta,在 Meta 希望收购 SSI 时。

Ilya 特意澄清,「他是唯一一个去 Meta 的人。」 他建立 SSI 不是为了在商业市场上套现,而是为了那个唯一的、纯粹的目标,在那个不可逆转的奇点到来之前,把安全的超级智能造出来。

重新定义 AGI,一个 15 岁的少年

那我们距离 AGI 还有多远?Ilya 给出的预测是 5 到 20 年。

但他提醒我们要警惕「AGI」这个词。因为预训练模型让我们产生了一种错觉,以为 AGI 就是一个什么都懂的百科全书。但 Ilya 心目中的超级智能,更像是一个绝顶聪明的 15 岁少年。

这个少年可能还没学过法律或医学,但他拥有极致的学习效率。你让他去学医,他可能几天就能读完人类所有的医学文献,并开始做手术。

而在这一愿景中,最让人细思极恐的概念是融合(Amalgamation)。

人类的悲哀在于知识无法直接复制。这个人学会了开车,另一个人还是得从头练起,但 AI 不一样。Ilya 描述了一个场景,数百万个 AI 分身在经济体的不同角落工作,有的在写代码,有的在打官司。它们在各自学习,然后将所有的经验融合进同一个大脑。

这种集体进化的速度,才是他所认为的 AGI。

面对这样一个能够瞬间融合万千经验的超级大脑,人类又该何去何从?

Ilya 给出了两个层面的思考。首先是给 AI 的设定。不要只让它爱人类,因为这太狭隘了。未来的 AI 自己也将是有知觉的生命体,应该利用同理心的原理,让它关爱所有有知觉的生命,可能是比代码更稳固的安全防线。

其次是人类的退路。如果每个人都有一个比自己聪明百倍的 AI 智能体,人类会不会沦为历史的旁观者?Ilya 给出了一个他坦言「自己并不喜欢,但可能是唯一解」的答案:脑机接口(Neuralink)。

只有当人类选择与 AI 融合,让 AI 的理解直接变成我们的理解,我们才能在那个奇点之后,依然是这个世界的主角。

播客的最后,Dwarkesh 问了那个所有人都想问的问题:作为 AI 领域的传奇,你是如何一次次押对方向的?

Ilya 的回答很像个艺术家:「寻找美感。」

在那些数据都不支持你的至暗时刻,唯有对美、简洁和生物学合理性的自上而下的信念,能支撑你走下去。因为神经网络模仿了大脑,而大脑是美的,所以它一定是通往智能的正确道路。

这或许就是 Ilya 所说的「研究时代」最需要的品质:在算力之外,保留一份对智能本质的诗意直觉。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


夸克 AI 浏览器全面升级,可随时唤起千问

作者 莫崇宇
2025年11月26日 14:55

现在的浏览器,越来越「重」了。

写方案要开着 Word,查资料要切回浏览器,回消息又得跳到微信。屏幕被切得支离破碎,注意力也跟着碎掉。每次想让 AI 帮忙,都要先经历一番「寻找 AI 在哪里」的折腾。

这周,我试着把主力浏览器换成了全面升级的夸克 AI 浏览器。

体验下来,背靠阿里 Qwen 全球大模型,全面融合千问 AI 助手的夸克,发布六大千问 AI 套件,实现系统级「全局 AI」的创新产品形态,随时唤起千问,一句话帮你干活,效率拉满。

用户无需切换标签或应用,就能唤起千问读屏、快捷框、侧边栏、悬浮球、划词、截屏进行提问、协作……主打一个条条大路通千问。

它给我的第一感觉,就是在对标 Chrome 的基础上走得更远,想让 AI 成为你的「最强外脑」和「随身助理」。

体验随时桌面唤起千问方式后,让我彻底告别传统浏览器

先说最核心的,随时桌面唤起千问,这也是夸克和 OpenAI 前不久发布的浏览器 Atlas 最大的差异点。

Atlas 的理念是让 AI 成为操作系统的一部分,但它的实现方式相对保守,更多是在应用间调度。

而夸克则更激进,从底层架构彻底让 AI 融入浏览行为、以全新 AI 交互形态的出现,手撕传统浏览器,随时随地唤起千问 AI 助手,实现「边浏览边对话、边看边总结、即问即答」的丝滑体验。

举个实际场景,只需随手按下快捷键,就能让千问帮我列一个关于「社交媒体对青少年心理健康影响」的论文大纲,从而构建起连贯的学习工作流。

这种「无感接入」的设计,才是系统级 AI 浏览器的真正价值。

一个侧边栏,干掉你一半桌面操作

如果你的日常就是跟一摞摞 AI 技术论文打交道,英文不是很好,我们可以让「千问侧边栏」直接翻译、并总结核心观点。甚至让千问基于文档内容继续深挖准问,完全不用复制-粘贴-复制,也不用离开当前的标签页。

同理,阅读各种新闻资讯时,看到某辆新车发布,我们可以直接问千问侧边栏的「这款车适合哪些人使用?」。千问不仅分析当前页面,还能结合背景知识给出对比,省去了开新标签搜索的麻烦。

刷各种网页自然也是刚需,但信息量一多,自己逐条看、逐个理解既耗时间又费精力。这时候就可以果断交给千问来处理,它也能提炼重点。

千问侧边栏最妙的地方是边浏览边对话、边看边总结。传统浏览器要么让你切标签, 要么跳转新页面, 而夸克 AI 浏览器的设计让交互足够丝滑, 你几乎感觉不到在「使用 AI」。

截图即答案,划词即解释

遇到图表,截个屏,框选区域,千问直接解读数据趋势、图表含义。看到一些复杂的 AI 图片,也可以让它帮忙「整理图片中的动物职业,并翻译成中文」,千问立刻给出结构化总结。

截图提取图片文字也很顺手。

我随手截了一张三宅一生曾经客串出现在苹果「Think Different」广告宣传活动的广告语,它就能准确识别这是苹果的广告词,并给出解释。

在逛知乎时,看到一些不懂的词汇也能直接划词, 千问自会弹出解释。想追问也行,这体验四舍五入等于冲浪时随身带着一个「AI 辟谣器」。

此外,更进阶的场景是「千问读屏」功能。

这个功能的意思是,千问可以「看到」你电脑屏幕上的任何内容,它不仅能与 Microsoft Word 和 WPS 等应用深度联动,还支持快捷划词提问、截屏提问等操作。

简言之,你在用 Word 写文档、在 Excel 做表格、千问都能理解你正在做什么,并基于屏幕内容给出建议。诶,用着用着,真有种生活工作搭子的感觉。

比如我在 Word 写东西,让千问把屏幕上的《蜀道难》改写成剧本,它立马开写。这套联动还能把截屏、划词、共享的内容自动同步到侧边栏,让你能无缝追问。

让 AI 替你干活,一句话的事

除了侧边栏等方式,唤起千问的方式也灵活多样。

比如按下「Alt + 空格」(Mac:option+空格),然后在搜索框里直接说人话就行。

「帮我写一份 iPhone 18 Pro 产品发布会邀请函」「把这段翻译成英文」。这种一句话叫 AI 干活的模式,直接取代传统搜索那堆蓝色链接,从查资料到写文案、从总结到翻译,全程闭眼托管。

它甚至能一句话做表格、一句话生成 PPT,或者直接转换格式,比如把黑板照片里的字直接提取成 Word 文档。

要做到这样其实并不容易,离不开千问对浏览器场景的深度定制。

它能理解你的意图、网页结构、上下文关系, 真正做到即问即答。

除了 AI 能力,浏览体验也没落下。

夸克的标签管理做得很聪明。自动分组、按域名排序,还能识别高内存标签自动优化。实测开 30+ 标签,主打一个纵享丝滑。

还有一个让人特别惊喜的地方,就是连文档的编辑也下了不少功夫。试着直接把 PDF 拖进夸克 AI 浏览器, 直接打开、标注、编辑、转格式,无需下载。

查资料时直接批注,外文 PDF 还能直接对照翻译,省下的时间都是生产力。

从官方 Demo 来看,跨设备隔空传文件更是顺滑。文字、文档、大文件都能手机电脑无缝传输,100G 文件也不怕。网盘整理也变得智能了。一句话就能搜到文件,不用再翻来翻去。

这些听起来都是细节,但加起来就是巨大体验差异。

对齐 Chrome 的性能标准后,夸克给你的是更极简的界面、零广告干扰,以及更轻的内存占用。当你习惯了这种清爽, 再打开某些国内浏览器, 满屏的推荐信息会让你怀疑人生。

哪怕是放在国内一众老牌浏览器里,这种克制也是值得表扬的。而当 AI 成为浏览器的底层能力,配合这些生产力工具,你会发现自己的工作流程被彻底重构了。

标签页的尽头,是 AI 的起点

用了几天夸克之后,我开始思考一个问题:当 AI 真正融入浏览器,它到底在改变什么?

答案可能比想象中更深刻。

过去 20 年里,浏览器的形态几乎没变。1995 年,比尔·盖茨在一份备忘录里写道:微软将操作系统作为人机接口,从而控制整个微机行业,而网景则控制了人们通向互联网的入口。

谁控制了入口,谁就能定义规则、分配流量、获得数据。2010 年,Chrome 成为稳定支持三个平台且拥有书签同步功能的浏览器。但即便如此,它的交互本质仍然是 1995 年的逻辑:

用户负责提出问题,浏览器提供零零碎碎的回答。

你依然要在多个标签页之间来回切换,手动拼凑信息,自己综合结论。这个模式延续了近 30 年,直到 AI 出现。夸克这次做的事情,本质上是在挑战这套交互范式。

通过千问读屏、悬浮球、快捷键,千问已经跨出了浏览器窗口的边界。

你在 Word 里写文章,在 Figma 里调布局,在任何一个应用场景里,千问都能理解你正在做什么,并给出针对性反馈。AI 不再局限于某个应用内部,成为整个系统的基础能力。

 

为什么是夸克先做出来?有几个原因。

首先,这与夸克的用户基础和战略定位密切相关。

随着阿里千问与夸克 AI 浏览器深度融合,也正式成为超 1 亿电脑用户的桌面级智能助理,这个量级的用户基础,意味着夸克有足够的场景数据和反馈来打磨产品体验。

浏览器作为电脑上最核心的入口,几乎涵盖用户获取信息与执行任务的所有场景。而 AI 在这个场景下的能力空间巨大,也标志着阿里巴巴千问正加速实现对 C 端场景的全面覆盖——从移动端到桌面端,从对话框到操作系统级的全局调用。

此外,浏览器的智能化上限,取决于底座模型的智商。

夸克直接接入了阿里 Qwen 全球领先大模型,这意味着它处理中文长文本和复杂逻辑推理时,天然就有语言理解上的优势。毕竟,模型能否准确理解语境,直接决定了体验的质量。

一键唤起是普通人的刚需,而做到全局唤起千问、千问读屏这类功能,需要深入操作系统底层,依赖于阿里的资源支持,夸克才敢于在这个方向上持续投入,而不是浅尝辄止。

与此同时,在隐私敏感和追求效率的当下,夸克选择了一条「反直觉」的路径——无广告、极简界面、内存优化。对于大多数普通用户,他们不需要 100 个插件,他们只需要一个能搞定 90% 麻烦事的 AI 按钮。

当然,坦诚地说,夸克面临的挑战也很明显。

Chrome 强大的插件生态和用户长期的使用惯性,是任何挑战者都难以短期撼动的壁垒。对于重度依赖特定插件的极客用户,迁移成本依然存在。用户对国内浏览器「大杂烩」的刻板印象,也需要夸克持续的克制来打破。

但无论如何,AI 浏览器显然是个趋势。

Chrome、Perplexity、OpenAI 都在做类似的事,国内浏览器都在跟进。

夸克这次的战略升级,选择主动出击抢占身位。依托通义千问 Qwen 在全球大模型评测中的强劲表现,夸克把浏览器从「浏览网页的辅助工具」变成「系统级的任务助手」,率先给出了 AI 浏览器未来形态该有的样子,也有利于它在这一赛道的早期阶段建立心智优势,并在下一轮竞争中获得更大的主动权。

而这个逻辑一旦成立,接下来的演化就清晰了。

你看论文时可以随时唤起 AI 解释概念。写代码时可以随时让 AI 审查逻辑。做设计时可以随时请 AI 给出建议。所有这些场景的共同点是:AI 理解你正在做什么,知道你需要什么,在你需要的时候出现。

如果说 Chrome 教会了我们什么是好浏览器,夸克则给 AI 浏览器打了个样板,放眼全球,都是领先的产品形态。未来的操作系统,将是以「任务」为中心。当你遇到问题,本能反应不是打开搜索引擎搜一下,而是唤起 AI 问一下。

这条路难走,因为它需要更深的技术积累、更克制的产品设计、更长期的用户教育。 但一旦走通,壁垒也会更高。

毕竟,习惯才是最难被撼动的力量。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


ChatGPT 这个新功能,想把淘宝小红书 B 站的活全干了

作者 张子豪
2025年11月25日 14:35

你有没有过这种体验,想买个东西,先去小红书找了二三十篇笔记,B 站看了十几个测评,然后上什么值得买看了下优惠的渠道,最后,人已经麻到不想买了。

今天,OpenAI 给了一个新的统一入口,让 ChatGPT 直接替我们做「购物研究」

在 ChatGPT 的聊天页面,点击菜单(+)选择 Shopping reseach 购物研究,告诉它要买什么,它会去全网查资料、比较参数、问我们预算偏好,然后给出一份量身定制的购买指南。

这听起来很简单,实际上是个非常深的产品变化,也是 ChatGPT 一直以来想要引入广告,又一次的小试牛刀。

和我们现在所熟悉的电商推荐、搜索引擎、比价工具都不太一样。传统工具的逻辑是,我们搜什么,它就给我们看什么。而 ChatGPT 购物研究的逻辑是,我们告诉它需求,它会利用我们在 ChatGPT 内的聊天记录,帮我们找到最适合的那个。

为了迎接黑五、感恩节等假期,ChatGPT 购物研究功能,已经向 Free, Plus, Team 和 Pro 等所有登录用户开放。而 Pro 用户的 Pulse 功能,也会个性化地使用购物研究,来推荐一些相关的产品。

不只是搜索,更是在做功课

国内的多个电商平台,淘宝天猫和京东,都上线了 AI 购物的功能,对话框里输入「我想买」,淘宝就能根据我们过往的购物历史,生成一份详细的购物清单。

▲淘宝 AI 购物功能截图

但是在通用聊天助手里,ChatGPT 是第一个把 AI 购物也加进来的应用。之前用通用助手 ChatGPT、DeepSeek 这些也能询问购物建议,除了推荐的质量,最大的痛点绝对是,给出的链接要么打不开,要么是瞎编的。

新的购物研究功能彻底解决了这个问题,更重要的是把推荐的质量也提上了一个台阶。

进入购物研究模式后,我们可以直接在对话框里输入,「帮我找一款适合小公寓的,静音无线吸尘器」、「我想要找一条看起来,像这个(上传图片)的连衣裙」诸如此类的问题,ChatGPT 就会开始它的调查研究。

和一般的 AI 对话不同,购物研究的体验是 ChatGPT 重新设计的。它会像真人导购一样追问,不会一上来就生成一份报告,而是先要我们做一些选择题,这一点也是和淘宝 AI 购物的区别。

▲我向他提问买相机,它首先问我的预算、接着是买相机的目的、还有一些期待的功能;如果不选择,大概在 15s 之后,ChatGPT 会自动跳过这些问题

它会弹出多个问题选择框,大致的问题是,「预算大概多少?」ChatGPT 会率先研究,关于要研究的产品,主要的价格分布区间,我们可以单选或多选。还有一些问题,根据不同的购物需求,有具体的了解,像是消费电子类会问「主要看重什么功能?」,很明显是礼物常用商品,它会问「是送人还是自用?」……

更厉害的是,如果开启了 Memory(记忆)功能,它甚至会调取以前的对话细节。比如它的记忆里面,保存了平时爱玩游戏的关键词,在推荐笔记本电脑时,就会自动把显卡性能作为重点考量,而不需要我们重复废话。

初步选择了这些属性之后,ChatGPT 会给我们提供一个可视化的挑选界面。不再是纯文字对话,我们会看到一个包含商品图片、价格和参数的可视化界面。

▲ 选择不感兴趣之后,还可以反馈是对品牌不感兴趣,还是价格、功能、款式等具体方面

如果不喜欢某个推荐,可以直接标记 Not interested(不感兴趣);如果觉得某款不错,可以点 More like this(找相似的);左滑不喜欢,右滑喜欢,很有交友软件的味道了。

它会根据我们的每一次点击,实时调整购物调研的方向。在最后生成报告的过程中,为了减少等待的「痛苦」,ChatGPT 还会提供很多小 Tips,来解释关于某个产品背后的内容。就像这里研究相机,它会说「像素不是决定照片质量的唯一标准」等。

等了一会儿,最后就是 ChatGPT 生成的这份深度「买家指南」。这是一份完整的调研报告,里面不仅有热门产品推荐,还有关键差异对比、优缺点权衡、以及来自可靠零售商的最新信息(主要是美国常用购物网站)。

它把原本需要我们花几个小时,去搜索、阅读、拉一个 Excel 汇总的过程,压缩成了几分钟的对话和选择。

除了这种直接的询问有什么新的产品,我们还可以在购物研究里面,发送图片,要求 ChatGPT 找到类似的商品,或者要求它帮我们找到相关的优惠,以及多个同类产品的横向比较。

我们直接问他,「我是学生,这个自行车可以送给我吗」?他很认真的帮我找到了学生专属折扣或补贴、还有一些学校提供的相关支持计划。

什么样的东西适合用它买?

OpenAI 在他们官方博客里面提到,对于查个价格这种简单问题,普通对话就够了。Shopping Research 真正大显身手的地方,是那些决策成本高、参数复杂的品类。

  • 电子产品: 手机、电脑、相机(这类产品参数多,非专业的小白容易晕)
  • 家居与园艺: 吸尘器、扫地机、家具
  • 美妆护肤: 需要看成分、对肤质
  • 运动与户外: 露营装备、专业运动器械

简单来说,凡是需要我们专门去做功课的东西,现在都可以交给 ChatGPT 的购物研究。

OpenAI 最后也提到,他们没收钱。不会因为谁给钱多,就暗中默默推荐谁。他们表示所有的搜索研究结果,都是基于公开的网页信息,用户与 ChatGPT 的聊天记录,同样也不会分享给任何零售商。

其次,这次购物研究的功能,是由一个经过强化学习训练的 GPT-5 mini 版本支持,专门用于购物任务。他们创建了一个新的评估方法,来衡量模型推荐的商品是否符合用户的需求,最后的结果是购物研究达到了最高的 64% 准确率。

不过,尽管模型很强,OpenAI 还是提到,库存和价格瞬息万变,购物研究也可能会有疏漏,建议大家在下单前,点击 ChatGPT 提供的商家链接,去官网做最终确认。

在未来,甚至可以直接通过 ChatGPT 购买,OpenAI 提到那些已经加入 Instant Checkout(支付平台 Stripe 与 ChatGPT 合作的即时结算),且提供该功能的商家,就能让我们边挑选边下单了。

除了模型存在疏漏,更大的局限是在中文市场,大部分的国产,尤其是没出海的品牌,数据缺失比较严重;同时国内电商页面也无法实时抓取。不过,用来调研一些国际品牌为主的商品,ChatGPT 还是能派得上用场。

再者说,以国产 AI 进步的速度,如果想要跟进类似的功能,接入淘宝京东拼多多大概也是「分分钟」的事。

对于 ChatGPT 新上线的购物研究功能,X 上的网友也是各种意见都有。有人说「OpenAI 又一次快速实现了,我的整个创业想法。」、还有网友给出一张密密麻麻的 AI 订阅费用对比,说「AI 能帮我找到最适合的 AI 订阅吗」,也有人犀利的表示「别再破坏我的 ChatGPT 了」……

回头看 GPT-5 发布后,ChatGPT 这三个多月来的更新,群聊、视频社交、即时结账、购物、浏览器以及即将到来的成人模式等,OpenAI 看准了要利用它的庞大流量留住这些用户。对它来说,当前保持住用户的现有存量,比进一步挖掘用户增量可能更重要。

而购物研究,只是 ChatGPT 牢牢绑住现有用户,很小的一次的探索;电商这块巨大的蛋糕,它才刚刚进来。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


❌
❌