普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月30日首页

云迹科技发布2025年报,智能体应用收入增长194%

2026年4月30日 10:22
36氪获悉,云迹科技2025年年报显示,期内总收入3.01亿元,同比增长23.1%。智能体应用收入增长194.1%,占总收入比重跃升至11.3%;HDOS订阅客户数大增925%;AI数字化系统收入增长57.3%,占比升至29.2%。海外收入增长92.1%,工厂场景增长393%。公司正从硬件供应商向服务智能体平台转型,收入结构迈向持续性现金流,估值逻辑重构。

摩根资产管理认为美联储加息的门槛很高

2026年4月30日 10:21
摩根资产管理亚太首席市场策略师Tai Hui表示,美联储在可预见的未来可能维持利率不变。Tai Hui表示,鉴于多数委员觉得当前政策立场已属于中性,美联储可以保持耐心,观察中东冲突及其对经济和通胀的影响。他还表示,决策官员的分歧显示在高度不确定时期,美联储内部缺乏共识,这可能在新任主席上任后仍将持续。(新浪财经)

阿迪达斯全球2026年Q1营收66亿欧元,同比增14%

2026年4月30日 10:14
36氪获悉,4月29日,阿迪达斯公布2026年第一季度财报。财报显示,今年第一季度,阿迪达斯全球营收66亿欧元,在货币中性下(下同),较上年同期增长14%;营业利润同比增长16%,达7.05亿欧元;营业利润率达10.7%,同比提升0.8个百分点;毛利率维持在健康的51.1%。此外,今年第一季度,大中华区实现营收11.4亿欧元,同比增长17%,已连续十二个季度实现高质量的增长。

「优时科技」完成数亿元B2轮融资,从L4视觉自动驾驶延展至人形机器人,打造数据飞轮|36氪首发

2026年4月30日 10:13

一季度过去,具身智能行业的融资热潮还在继续。

36氪获悉,专注于L4低速自动驾驶的公司「优时科技」宣布完成数亿元人民币B2轮融资。本轮融资由前海方舟领投,前海母基金旗下多支基金参与,联同鲲翎资本、厚天资本等8家投资机构共同完成。

在此之前,「优时科技」已完成了6轮融资:

·2018年6月,拿到 PNP 中国领投、北京汇丰投融、北京金种子和上海平阳复辉跟投的数百万人民币种子轮;

·2019年7月,获得英诺天使领投、驰星创投跟投的千万人民币天使轮;

·2020年10月,获得 Global Brain、英诺天使、驰星创投、PNP 中国、平阳复辉的数千万A轮融资;

·2022年7月,获得海尔资本、金茂资本、惟一资本投资的数千万A+轮融资;

·2023年1月,获得零以创投、厚天资本的数千万A++轮融资;

·2024年7月,完成了B1轮融资,由驰星创投、Global Brain投资,金额在数千万元级别。

「优时科技」成立于2018年,聚焦于通过计算机视觉实现L4自动驾驶,取代了传统多线激光雷达在低速行驶领域的应用。截至目前,「优时科技」已在海内外商圈、步行街、地铁站、机场等大流量场景部署了数千台「优时小车」,追平了成立于2014年的海外自动驾驶配送头部企业 Starship。

「优时科技」CEO林锫森表示:“在人形机器人赛道中,优时以L4视觉自动驾驶为底座,通过大流量场景验证机器人的通用导航和交互能力,进而平移到人形机器人平台。这一逻辑与特斯拉(Tesla)从FSD(完全自动驾驶)向人形机器人 Optimus 延伸的思路相似,两者都是坚持通过‘纯视觉感知算法 + 物理世界真实数据’,来驱动人形机器人走向通用智能。”

“当然,从小车跨越到人形机器人,在机械控制层面存在差异。” 林锫森强调,“优时的核心壁垒并非从零打造一具‘双足躯壳’,而是将成熟的L4视觉算法与空间认知能力,封装为具身机器人的‘社交导航大脑’。在硬件供应链日益成熟的今天,拥有应对复杂人流量的导航和交互大脑,也是人形机器人落地的重要环节。”

1.突破非结构化挑战,低成本转动数据飞轮

聚焦大流量场景,其技术挑战与传统开放道路的L4自动驾驶截然不同。

乘用车面临的环境通常是结构化的:有规整的车道线和室外RTK,算法可通过海量数据学习识别车道,并借助高精地图与多传感器融合进行辅助定位。相比之下,线下大流量商圈场景则是高度非结构化、强动态的复杂环境。这里没有车道线,人群穿梭不息,干扰因素极多。要在这种环境中实现自动驾驶,不仅需要重新构建算法,更必须把方案成本降到极致,才能满足线下商业需求。

“物理世界对成本极度敏感。无论是自动驾驶还是具身智能,低成本都是实现规模化的前提。”林锫森向36氪强调。“目前,可自主运营的人形机器人造价普遍偏高,出货量与乘用车无法在同一个量级,这导致其在物理世界采集的数据无法满足算法训练需求。行业陷入了‘先有鸡还是先有蛋’的困境——没有规模出货就跑不出数据,没数据就做不好智能,进而没法规模出货。具身智能很难直接复制乘用车‘靠海量用户转动数据飞轮’的路线。”

基于此,「优时科技」通过低成本的「优时小车」作为终端载体,率先在大流量场景跑起来。小车在拥挤人群中累积的真实运行数据,补齐了具身智能的“高动态社交数据”与“人机交互能力”。

为了实现这套低成本方案,「优时科技」花了7年时间的技术研发以及市场的探索。与其他竞品普遍采用多线激光雷达不同,优时从成立之初就坚决走纯视觉路线—— 采用双目摄像头实现三维定位和导航。

“如果依赖高精地图,派人重新扫描三维地图的市场价在每公里2000元左右。”一位无人车工程师透露。这对结构经常变动的大流量场景来说,是无法承受的隐性负担。

双目摄像头硬件虽便宜,但要实时生成3D信息,对算力要求极高。为此,优时通过自主研发的算法:在强弱光交替的环境中提取核心三维轮廓,滤除高动态干扰。这种机制确保了环境变化不对导航和运行产生影响。

2.下一步:大流量场景的人形机器人

“优时科技的定位始终是一家机器人公司。六轮小车是我们很专注的产品形态,接下来,我们的产品矩阵会增加人形机器人,未来两者将产生深度的场景和 IP 的结合。”林锫森表示。

在规划中,人形机器人更多承载交互功能,六轮小车则承担负载与移动。林锫森解释:“大流量场景需要高频的人机交互,且对续航要求极高。让人形机器人背着货跑,耗电量非常大,如果没有7到8小时以上的续航,很难在真实的商业运营中成立。”

在林锫森看来,具身智能的发展有两大核心板块:第一板块是 Locomotion(移动能力)与 Interaction(交互能力);第二板块是 Manipulation(精细操作能力)。

他认为,机器人要想渗透进物理世界与人共处,首先要解决在复杂环境中的“共存与通行”问题——能否准确预判人的意图?是否听得懂指令?懂不懂得避让?而这正是「优时小车」的先发优势。每天在人流密集、环境嘈杂的商超中穿梭,积累了海量的人机共存数据,并借此训练出了“社交导航能力”,赋予了机器人意图预判、秩序融入和得体交互的能力。

“虽然小车和人形机器人的物理载体不同,但应对复杂人流的‘社交导航大脑’和‘空间认知模型’是相通的。”林锫森指出,“这能率先解决第一板块的移动和交互痛点。随着技术发展,我们再去慢慢完善第二板块的精细操作能力。”

3.造血式数据采集:线下商业闭环

除了视觉算法的复用,「优时科技」利用高频的线下商业场景,破解了具身智能行业“数据采集成本高”的核心痛点——用商业价值为数据采集买单,让机器人在为B端客户创造收益的同时,源源不断地反哺AI训练数据。

在大流量场景中,优时花了多年时间打磨造血环节:「优时小车」不再仅仅是单纯的物理移动载体,而是可移动的商业智能终端(AI Agent),能够依靠视觉算法主动寻找人流密集的高热度区域,为线下客户提供动态的展示、移动产品体验与线下流量分发。

这种主动找人的交互模式,打破了传统商业被动获客的痛点,将公域流量转化为私域流量;凭借可量化的商业回报,让小车成为基础设施,为客户大幅降低了获客成本。

如今,数千台在高频运转的终端小车构成了自我造血的变现网络,也是一个持续更新的世界数据库。小车在与人群的高频商业交互中,累积了海量的多模态数据与动态空间信息。

本轮投资方前海方舟项目投资负责人表示:“在物理世界里复刻AGI,是一场勇敢者的游戏。优时科技通过技术创新,实现了低成本高精度的L4自动驾驶解决方案;并进一步利用自研方案的优势,锚定赋能线下大流量、高动态环境市场。在快速跑通商业模式形成闭环的同时,逐步构建起了规模效应和物理世界的数据壁垒。该项目是前海方舟基金群在‘AI+物理智能体’垂直领域落下的关键一子。”

据悉,本轮资金将主要用于L4自动驾驶技术向具身智能的规模化迁移、通用视觉技术商业终端的网格化部署,以及多模态AI Agent与生成式动作大模型的研发与市场扩展。

海南:拟布局亚轨道太空旅游中心等前沿设施,做强文昌“航天旅游之都”

2026年4月30日 10:12
36氪获悉,《“十五五”海南国际旅游消费中心规划》公开征求意见。其中提到,丰富航天旅游产品业态。优化升级发射观礼平台、综合观礼营地,开发海上邮轮观礼路线,落地海南航天博物馆、航天游学中心等项目,建设国家级航天科普研学基地,开放火箭总装测试、卫星超级工厂等工业场景,打造沉浸式研学阵地,布局亚轨道太空旅游中心等前沿设施,做强文昌“航天旅游之都”。完善航天旅游配套服务产业链。

海南:将推进航天旅游平台组建,培育本土特色航天文旅企业

2026年4月30日 10:12
36氪获悉,《“十五五”海南国际旅游消费中心规划》公开征求意见。其中提到,培育航天旅游市场主体。推进航天旅游平台组建,支持市场主体参与航天旅游产品开发、运营、推广,培育本土特色航天文旅企业。依托文昌国际航天城建设,整合火箭观礼嘉年华、航天科普中心、卫星超级工厂、研学基地等资源,打造集航天博览、科普教育、科幻体验、娱乐休闲、亲子研学、观光度假于一体的航天旅游综合体。构建以航天科技体验、航天科普研学为核心的沉浸式高端旅游消费集聚区。

钉钉正式推出DingTalk A1 Pro

2026年4月30日 10:02
36氪获悉,钉钉正式推出DingTalk A1 Pro,并在天猫钉钉官方旗舰店开售。据了解,DingTalk A1 Pro内置2980mAh大容量电池,连续录音时可达180小时,待机时达180天。

我测 SBTI,但我不是 SB.skill

作者 马扶摇
2026年4月30日 10:00

四月没过半,你的朋友圈应该已经被反复刷过三四轮屏了吧?

「龙虾」的热度还没完结,网上就出现了另一场新的全民狂欢:SBTI ——

这是由 b 站 up 主 @蛆肉儿串儿 戏仿 MBTI(迈尔斯-布里格斯类型指标)人格测试做出来的小工具,摒弃了严肃的荣格心理学式分类、添加了很多本土化元素:

4 月 9 日 @蛆肉儿串儿 将视频以及 SBTI 测试上线之后,咱们爱范儿编辑部的朋友圈就被迅速刷屏,领导者、伪人、尤物等等不胜枚举。

SBTI 原版链接:https://www.bilibili.com/video/BV1LpDHByET6

爱范儿小编也做了一次测试,如愿以偿地发现自己是个酒鬼:

根据 up 主自己所述,SBTI 本来是为了劝一个朋友戒酒设计的,里面的题目没有什么明确的心理学依据,但只要在有关喝酒的引导性问题上选择了正向答案,测出来的人格就一定是酒鬼。

图|X @VikingSkirts

毕竟在 SBTI 里面,同一个人测三次能拿到三种完全不同的「人格」,它的全部意义就是让你笑一下。

然后截图发朋友圈,把自己笑一下拓展为大家笑一下。

但就在 SBTI 刷屏的同一周,另一个话题却正在以一种安静得多的方式,渗透进每个人的日常——

那就是「你的同事.skill」

注:AI 图,真正把员工 skill 化的公司是不会浪费钱贴工牌的

这一周的前半段,你或许被各种各样的 Skill 刷过屏:能够自己画 k 线的特朗普.skill、记得每条聊天记录的前任.skill、PUA 比真人更狠的老板.skill 等等。

更不用说前两天冒出来的惊天张雪峰.skill 了……

严格来说,Skill 相当于喂给大语言模型的「预设」。

它的原理与你在对话框里写类似「你是一个一个一个香香软软的小蛋糕」之类的角色提示词差不多,只不过比手写更详细、更丰富、更规范而已。

图|X @tuzi_lumaomao

同时,训练(或者说蒸馏)这种 Skill 的过程可以很简单。

把离职同事的飞书消息、钉钉文档、工作邮件喂给蒸馏工具,就能生成一个模仿这个人工作习惯、说话方式、甚至甩锅姿势的 AI 分身。

你的同事走了,他的 Skill 留下来继续搬砖。

接受标签化,反对标签化

然而调侃归调侃,梗图归梗图,这种「个人.skill」模式的流行,与昨天开始的 SBTI 潮流,在本质上其实是同一种现象——

一种人的标签化。

毕竟无论是 SBTI、MBTI、简单的 i/e 人分类,甚至是传统的星座能量和生肖运势,本质上都是在「贴标签」。

我们喜欢通过这种「给自己贴标签」的行为,主动将自己的行为习惯归类,并以此为基础寻找更小的社群。

这种标签化代表了我对于我自己的隐性认同或者期待,以及一种社交谈资。

与此同时,Skill 同样是一种标签化。

2025 年底 Anthropic 发布 Claude Skills,2026 年初 OpenClaw 引爆了智能体热潮,Skill 作为智能体的「技能商店」开始快速扩张,原理就是把某种专业能力打包成可复用模块的文件夹

然而以前我们都只说「做网页的 Skill」,或者「校验照片哈希值的 Skill」,前一阵「同事.skill」的出现则标志着一个明显的转向:

大家开始担心,Skill 的定义从「模型能做什么」正在变成「谁的能力可以被打包」。

既然都是打包贴标签,为什么我们能够接受 MBTI、喜欢 SBTI,却对同事.skill 感到恐惧与不安呢?

我自己去测 SBTI,这是我主动贴上的标签,这个行为本身就带着一种隐秘的快乐——

测出来是「酒鬼」,我笑着发朋友圈,这是一种自我表达,本质上和在朋友圈 emo 说自己是个伞兵差不多。

这种「我自主定义」的标签是轻的,因为我既可以改变,也可以不认。今天我是「酒鬼」,明天测变成「老板」,没有人会因此重新评估我这个人值多少钱。

可公司把我蒸馏成一个 Skill,性质就完全不同了。

「我.skill」是别人对我的榨取,是把我积累的工作经验、处理问题的直觉、同事之间的默契炼化成了一组参数,装进一个几百 KB 的文件里,然后打上一个低于当地最低工资标准的价签,备注「可复用」。

图|《来自深渊》

我是 SB,不是 SB.skill

不可否认的是,智能体 Skill 作为一种技术工具本身,它是没有任何取向性的。

一切问题的根源,都在于我们对于 AI 的使用已经从「人使用工具」,被逼迫、异化、扭曲成了「人化为工具」。

毕竟蒸馏的逻辑很简单:把非标资产(员工)标准化(蒸馏成 Skill),把不可替代变成可替代。

在这个过程中,我丧失的不仅仅是一个用来自嘲的社交标签,更是失去了自己以职业身份存在的权利。

再进一步说,比起「被炼化」更让人不安的,是这条路继续往前走的样子。

冰冷的资本铁律已经证明:剥削的本质不会改变,资本唯一进步的地方,只有它的剥削方式和剥削程度。

而眼下的 Skill 体系,以及整个 AI 技术领域,就处在这个「从技术工具变成剥削工具」的过程中。

当你的 Skill 文件成为你在公司内部的数字替身,HR 就会开始用「这个 Skill 的可复用程度」来评估你的不可替代性,你的标签从一种外化的描述,变成了「你」的存在本身

你不再是「一个会做精美简洁的财务报表的人」,而是「那个做报表的 Skill 的名字贡献者」。

这话听起来科幻,但赛博朋克的典型世界观——人的市场价值由器官和植入体决定——与未来可能的 Skill 世界观之间的距离,比我们愿意承认的还要近很多。

因为用 Skill 来取代人,不是「汽车取代马车」式的技术迭代,而是否认「人作为人」的价值本身。

在工场手工业和手工业中,是工人利用工具,在工厂中,是工人服侍机器。

在前一种场合,劳动资料的运动从工人出发,在后一种场合,则是工人跟随劳动资料的运动。

……甚至减轻劳动也成了折磨人的手段,因为机器不是使工人摆脱劳动,而是使工人的劳动毫无内容。

而我们对于 Skill 的担心的本质,往小了说,是担心资本会以此为工具,冷酷且无底线地压缩用人成本;往大了说,则是对于现代政治理论中「以人为本」观念的动摇。

因此,大家喜欢用 SBTI 来嘲笑自己,给自己打上一个「吗喽」的标签,继续赚香蕉的钱。

但大家同样拒绝被无意识、甚至被迫地蒸馏成 Skill,变成一个「不叫做人」的工具。

直白点说,SBTI 是我自己的游戏,但 Skill 是别人的刀俎。

这或许就是当下这个时代的集体情绪——

在 FOMO(Fear Of Missing Out,害怕错过)之后,被 LLM、Agent、龙虾用鞭子驱赶着的我们正在进入一种新的焦虑—— FOBO(Fear Of Becoming Obsolete,害怕被淘汰)。

FOBO 驱动我们拼命参与、拼命刷屏、拼命测试自己到底是哪种人格,FOBO 则让我们在深夜突然心生警觉:

我的经验、技能、判断力,甚至我说话的语气,是不是都能被压缩进 Markdown 文件,然后被零成本地无限复制?

这种现代生活中的 SBTI 与 FOBO 的精神分裂,恰好从正反两面反映着同一种心理需求:

在这个人多到以十亿计的星球上,我需要确认自己是独特的、是不可替代的,是不能被简化为一串代码的。

我可以骂自己是 SB,但我不能接受被蒸馏成 SB.skill。

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

如何实现 Claude 生成式 UI?一套可落地的工程方案

作者 西陵
2026年4月30日 10:00

首发于公众号 code进化论,欢迎关注。

前言

随着大模型能力增强,单纯的纯文本/图片输出已无法满足复杂内容的展示需求。以 Claude.ai 为代表的产品,已开始支持直接输出 HTML 并进行渐进式渲染,同时渲染出的 HTML 也可支持简单交互,从而实现更丰富的结构化内容表达与更流畅的用户体验。

本篇文章会带大家探索如何通过大模型能力生成可交互的 HTML 内容,并通过前端技术实现流式渲染,从而达到与 claude.ai 相似的效果。

Claude.ai 分析

下面通过一个图表生成的例子来探索 claude.ai 是如何实现 HTML 的流式渲染。

code-1311608451.cos.ap-guangzhou.myqcloud.com/agent%E7%94…

消息协议分析

下面是抓取的 claude.ai 返回的 sse 消息。

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"\"\\n<div style=\\\"padding: 1rem"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":" 0;\\\">\\n  <h2 class=\\\"sr-only\\\">2022\\u5e74\\u81f32025\\u5e74\\u4e2d\\u56fd\\u51fa"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"\\u751f\\u4eba\\u53e3\\u67f1\\u72b6\\u56fe</h2>\\n  <div style=\\\"display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 1."}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"5rem;\\\">\\n    <div style=\\\"background: var(--color-background-secondary); border-radius: var(--border"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"-radius-md); padding: 1rem; flex: 1; min-width: 120px;\\\">\\n      <p style=\\\"font-size: 13"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"px; color: var(--color-text-secondary); margin: 0 0 4px;\\\">\\u6700\\u9ad8\\u5e74"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"\\u4efd</p>\\n      <p style=\\\"font-size: 22px; font-weight: 500; margin: 0;\\\">2022"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"</p>\\n      <p style=\\\"font-size: 13px; color: var(--color-text-secondary); margin: 4px 0 0;\\\">956 \\u4e07\\u4eba"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"</p>\\n    </div>\\n    <div style=\\\"background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem; flex: 1; min-width: 120px"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":";\\\">\\n      <p style=\\\"font-size: 13px; color: var(--color-text-secondary); margin: 0 0 4px;\\\">\\u6700\\u4f4e\\u5e74\\u4efd</p>\\n      <p style=\\\"font-size: 22px"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"; font-weight: 500; margin: 0;\\\">2025</p>\\n      <p style=\\\"font-size: 13px; color: var(--color-text-secondary); margin: 4px 0 0;\\\">954"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":" \\u4e07\\u4eba</p>\\n    </div>\\n    <div style=\\\"background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem; flex: 1; min-width:"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":" 120px;\\\">\\n      <p style=\\\"font-size: 13px; color: var(--color-text-secondary); margin: 0 0 4px;\\\">\\u56db\\u5e74\\u7d2f"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"\\u8ba1</p>\\n      <p style=\\\"font-size: 22px; font-weight: 500; margin: 0;\\\">3795</p>\\n      <p style=\\\"font-size: 13"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"px; color: var(--color-text-secondary); margin: 4px 0 0;\\\">\\u4e07\\u4eba</p>\\n    </div>\\n  </div>\\n\\n  <div style=\\\"display: flex; gap: 8"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"983\\u4e07\\u4eba\\u3002</canvas>\\n  </div>\\n</div>\\n\\n<script src=\\\"https://cdnjs.cloudflare.com/ajax"}}

data: {"type":"content_block_delta","index":2,"delta":{"type":"input_json_delta","partial_json":"/libs/Chart.js/4.4.1/chart.umd.js\\\"></script>\\n<script>\\n  const isD"}}

从 sse 消息可以分析出几个关键点:

  • 每条 sse 消息只输出一部分 HTML 内容,且是无规则的。
  • HTML 的内容输出顺序是 style → content HTML → script ,这也是一个完整的 HTML 文档的标准格式。

HTML 渲染机制

image.png

最终输出的内容在一个独立的 iframe 中渲染,与宿主环境完全隔离。

image.png

如果输出 HTML 的过程中突然中断对话,展示的是已输出的合法的 HTML 内容,像<p style="font-size: 13 这种内容需要过滤。

难点分析

  • HTML 渲染的样式可约束

    最终输出的 HTML 渲染出来的样式是可约束的,而不是大模型随机生成的,这样最终输出出来的 HTML 风格统一,质量稳定。因此需要输出一套大模型可理解的样式规范。

  • HTML 渲染不能影响宿主环境

    HTML 本身可能会包含样式、脚本,直接在宿主环境渲染可能会影响宿主环境。

  • HTML 如何高效的增量渲染

    因为每条 sse 消息拿到的是一小段 HTML 内容,是不完整的。如果等 HTML 内容完全输出后再渲染,等待时间会很长,整体体验也不友好,达不到预期目标。因此需要提供一套高效的增量渲染方案,在保证性能的情况下能够逐步渲染已有的内容。

  • 如何过滤掉不合法的 HTML 内容

    sse 输出的 HTML 内容不能保证是完整的,会出现 <p style="font-size: 13这种情况,在渲染时需要进行过滤。

  • 如何执行 script 脚本

    在浏览器规范中,通过 innerHTMLinsertAdjacentHTML 等基于 HTML 解析器的方式插入的 <script> 标签不会被执行,因此对于 script 脚本需要单独处理。

  • 确保 script 脚本的执行顺序

    script 脚本的执行可能存在依赖关系,比如绘制图表的脚本一定要等 Chart.js 加载完才能执行。

如何定制 HTML 生成规范?

HTML 生成规范可以参考开源项目 pi-generative-ui ,它是一个专为 pi(code agent)设计的插件,能够让 pi 像 claude.ai 一样输出具备一致设计风格的UI。下面展示了部分内容,详细提示词可参考 guidelines.ts 文件。

### Tokens
- Borders: always \`0.5px solid var(--color-border-tertiary)\` (or \`-secondary\` for emphasis)
- Corner radius: \`var(--border-radius-md)\` for most elements, \`var(--border-radius-lg)\` for cards
- Cards: white bg (\`var(--color-background-primary)\`), 0.5px border, radius-lg, padding 1rem 1.25rem
- Form elements (input, select, textarea, button, range slider) are pre-styled — write bare tags. Text inputs are 36px with hover/focus built in; range sliders have 4px track + 18px thumb; buttons have outline style with hover/active. Only add inline styles to override (e.g., different width).
- Buttons: pre-styled with transparent bg, 0.5px border-secondary, hover bg-secondary, active scale(0.98). If it triggers sendPrompt, append a ↗ arrow.
- **Round every displayed number.** JS float math leaks artifacts — \`0.1 + 0.2\` gives \`0.30000000000000004\`, \`7 * 1.1\` gives \`7.700000000000001\`. Any number that reaches the screen (slider readouts, stat card values, axis labels, data-point labels, tooltips, computed totals) must go through \`Math.round()\`, \`.toFixed(n)\`, or \`Intl.NumberFormat\`. Pick the precision that makes sense for the context — integers for counts, 1–2 decimals for percentages, \`toLocaleString()\` for currency. For range sliders, also set \`step="1"\` (or step="0.1" etc.) so the input itself emits round values.
- Spacing: use rem for vertical rhythm (1rem, 1.5rem, 2rem), px for component-internal gaps (8px, 12px, 16px)
- Box-shadows: none, except \`box-shadow: 0 0 0 Npx\` focus rings on inputs

### Metric cards
For summary numbers (revenue, count, percentage) — surface card with muted 13px label above, 24px/500 number below. \`background: var(--color-background-secondary)\`, no border, \`border-radius: var(--border-radius-md)\`, padding 1rem. Use in grids of 2-4 with \`gap: 12px\`. Distinct from raised cards (which have white bg + border).

### Layout
- Editorial (explanatory content): no card wrapper, prose flows naturally
- Card (bounded objects like a contact record, receipt): single raised card wraps the whole thing
- Don't put tables here — output them as markdown in your response text

按照 pi-generative-ui 官方的介绍,它的设计规范的提示词是完成从 claude.ai 中提取出来的,这一点作者已通过爬取 claude.ai 的源码验证过,因此如果大家想在自己的项目中应用这套提示词,这也是一个很好的衡量标准。

除此之外,在 pi-generative-ui 文档中也详细地讲解了 claude 实现生成式 UI 的详细步骤,作者下面要介绍的前端渲染方案就参考了里面的内容。

浏览器解析策略

前端在实现 HTML 流式渲染之前,需要先了解一下在浏览器中渲染一段 HTML 字符串时背后的策略,最简单的例子如下:

const tmp = document.createElement('div')
tmp.innerHTML = `
    <div style="font-size: 13px">
        HTML渲染
        <p>Hello World</p>
        <p style="font-size: 13
`

如果将一个不合法的 HTML 字符串通过 仍给浏览器,最终渲染出来的 DOM 树会是什么样的呢?

根据 WHATWG HTML 标准定义,浏览器在解析 HTML 时遵循 WHATWG HTML 标准中定义的解析算法,该算法本身是容错的。在解析过程中,标签结构会被自动补全,而语法错误的属性则会被直接忽略。因此,最终生成的 DOM 树往往是“修复后的结果”,而非原始字符串的直接映射。因此在浏览器中最终展示的 DOM 树如下:

如何实现 HTML 流式渲染?

Iframe 沙箱隔离

优势:

  • 接入非常简单,接入方使用没有任何心智负担。
  • iframe 天生具备隔离能力,无论是js、css、dom,都完全与宿主环境隔离。

缺点:

  • dom 严重割裂,弹窗只能在 iframe 内部展示,无法覆盖全局。

  • 通信困难

    iframe是独立的运行上下文,并且通常是以跨域的形式出现,与宿主通信困难体现在3点:

    • 方式困难

      仅可通过 postmessage 等方式,难以同步执行、直接调用。

    • 数据结构困难

      仅可传输Transferable Object

    • 效率低,内存限制大

      传输数据(除sharedArrayBuffer), 均需要做structuredClone。

  • 隐私限制

    对于跨域的场景, iframe 中的代码因跨域无法获取到用户隐私信息(cookie, localstory, indexDB)等。极大限制了功能实现。iframe 也难以感知到宿主环境状态。

在对话场景下 HTML 渲染出来的页面是纯展示页面,不存在复杂的交互,不需要和宿主环境通信,因此 Iframe 已经能满足场景需求。

Morphdom 增量渲染

浏览器在解析 HTML 时具备一定的容错能力,因此在一般场景下可以直接将 HTML 字符串交由解析器处理,而无需对其进行严格的预校验。在通过 SSE 获取 HTML 内容后,最直接的渲染方式是使用 innerHTML 将其插入到页面中。然而,innerHTML 在更新内容时会整体替换原有 DOM 子树,这不仅会导致已有状态(如输入框内容、滚动位置等)丢失,还可能引发明显的重绘与闪烁问题,影响用户体验,为了解决上述问题,可以引入 morphdom 进行增量渲染。

定义

morphdom 是一个轻量级的 DOM diff 库,它通过对比当前 DOM 与目标 DOM 的差异,仅对发生变化的节点进行最小化更新,从而避免整树替换带来的性能开销和状态丢失问题。与 React 等基于虚拟 DOM 的方案不同,morphdom 并不引入额外的抽象层,而是直接在真实 DOM 上执行 diff 与 patch 操作,在保持较高性能的同时简化了整体实现复杂度。

基本使用

使用 morphdom 非常简单。以下是一个基本示例,演示如何将一个 DOM 元素转换为另一个:

var morphdom = require('morphdom');
 
// 创建初始元素
var el1 = document.createElement('div');
el1.className = 'foo';
 
// 创建目标元素
var el2 = document.createElement('div');
el2.className = 'bar';
 
// 将 el1 转换为匹配 el2
morphdom(el1, el2);
 
// el1 现在拥有类 'bar'
console.log(el1.className); // 'bar'

除了传递 DOM 元素,也可以传递 HTML 字符串作为目标:

var morphdom = require('morphdom');
 
var container = document.getElementById('my-container');
container.innerHTML = '<div class="old-content">Hello World</div>';
 
// 用新内容更新容器
morphdom(container, '<div class="new-content">Hello Morphdom</div>');

这个就和当前的场景非常类似,但是这里有一个核心功能需要重点关注,当传递 HTML 字符串作为目标时,morphdom 会先调用 DOM API 将字符串转换为 DOM 元素,源码如下:

function morphdom(fromNode, toNode, options) {
    if (!options) {
      options = {};
    }

    if (typeof toNode === 'string') {
        var toNodeHtml = toNode;
        toNode = doc.createElement('html');
        toNode.innerHTML = toNodeHtml;
    }
    //...
 }

这也就是说 morphdom 也是支持传递不合规的 HTML 字符串,因为内部也会先通过浏览器的解析算法进行容错处理并转换为 DOM 元素。

手动执行 Script 脚本

在浏览器规范中,通过 innerHTMLinsertAdjacentHTML 等基于 HTML 解析器的方式插入的 <script> 标签不会被执行,因此需要等 HTML 内容生成完之后手动获取脚本并执行。

const runScripts = async (root: HTMLElement): Promise<void> => {
  const scripts = Array.from(root.querySelectorAll("script"));
  for (const old of scripts) {
    const s = root.ownerDocument.createElement("script");
    if (old.src) {
      // 外部脚本:等待加载完成再继续
      await new Promise<void>((resolve, reject) => {
        s.src = old.src;
        s.onload = () => resolve();
        s.onerror = () => reject(new Error(`Failed to load: ${old.src}`));
        old.parentNode!.replaceChild(s, old);
      });
    } else {
      s.textContent = old.textContent;
      old.parentNode!.replaceChild(s, old);
    }
  }
}

runScripts 方法里展示了 script 执行的大概流程,总结如下:

  • 获取所有 script 元素并遍历。
  • 通过 DOM API 创建并插入新的 script 元素。
  • 如果是加载外部脚本,需要等加载完毕之后再执行后面的脚本。

Demo

code-1311608451.cos.ap-guangzhou.myqcloud.com/agent%E7%94…

这个例子的 sse 数据直接用的 claude.ai 的,可以自己写个简单的 server。

招行“换帅”:王良到龄退休,王小青接棒

2026年4月30日 09:59
招商银行迎来了主帅的“换防”。据了解,4月30日上午9点多,招商银行召开相关会议,会上宣布王小青任招商银行党委书记,现任党委书记王良到龄退休。按照招商银行公司章程第四十条规定:党委书记、行长由一人担任。这就意味着,在走完公司内部相关流程以及获监管核准后,王小青将任招商银行第五任行长。(上证报)

成为AI全栈 - 第1课:后端到底是干嘛的?一张图拆解登录

作者 铁皮饭盒
2026年4月30日 09:58

本文目标: 先建立全局认知,再让AI写代码😁

一个常见的误解

很多人以为后端很难。

“要懂服务器、数据库、缓存、消息队列……”

“要学 Java、Python、Go……”

“要配环境、搭框架、写 SQL……”

其实,后端的核心逻辑非常简单。

今天用一张图,让你彻底理解后端是干嘛的。

图片

后端做什么?

前端发起接口请求。

后端: 接收请求  → 解析验证 →业务处理 → 数据库操作 → 返回响应

就这5步,没了。

以用户登录为例

用户在登录页面输入用户名和密码,点击“登录”。

第1步:接收请求

前端发送:POST/api/login,Body: { username: “张三”, password: “123456” }

后端路由匹配到 /api/login,交给登录处理函数。

// 监听请求
app.post('/api/login'(req, res) => {
  // 处理逻辑
})

第2步:解析验证

检查用户名和密码是否为空?格式是否正确?

如果为空 → 返回 400 “用户名和密码不能为空”,停止执行。

根据 username 去数据库查用户,用 bcrypt 比对密码。

密码错误 → 返回 401 “用户名或密码错误”。

第3步:业务处理

如果密码正确,生成 JWT Token(一个加密的字符串), 同时提取用户登录IP / 时间等。

第4步:操作数据

存储第三步数据到数据库。

第5步:返回响应

返回给前端:HTTP状态码: 200, 接口返回JSON数据

图片

前端拿到 Token,存储起来,后续请求带上它证明身份。 

nodejs + expres示例

🌟注意: 

1. 本文初期用js写后端, 帮助前端同学过渡, 后续会写py和java代码, 都是通过提示词让AI写😁

2. 下面代码大概看下就行, 后续文章会完善真读数据库, 反正都是AI直接生, 主要看提示词:基于express 生成登录接口 输入body参数(username,password), 返{"success":true,"data":{"token":"xxx","user":{"id":1,"name":"张三"}}} token要真验. 

下面是把提示词给deepseek生成的:

const express require('express');
const jwt require('jsonwebtoken');
const app express();

app.use(express.json());

// 模拟用户数据(实际应该查数据库)
const users = [
  { id: 1, username: 'zhangsan', password: '123456', name: '张三' },
  { id: 2, username: 'lisi', password: '123456', name: '李四' }
];

// 密钥(实际应放在环境变量)
const SECRET_KEY 'your-secret-key-123456';

app.post('/api/login', (req, res) => {
  const { username, password } = req.body;

  // 1. 验证用户名密码
  const user = users.find(u => u.username === username && u.password === password);

  if (!user) {
    return res.status(401).json({
      successfalse,
      error'用户名或密码错误'
    });
  }

  // 2. 生成真正的 JWT token
  const token = jwt.sign(
    { userId: user.id, username: user.username },
    SECRET_KEY,
    { expiresIn'7d' }  // 7天有效期
  );

  // 3. 返回结果
  res.json({
    successtrue,
    data: {
      token: token,
      user: {
        id: user.id,
        name: user.name
      }
    }
  });
});

app.listen(3000, () => {
  console.log('服务器已启动:http://localhost:3000');
});

核心结论

后端 = 接收请求  → 解析验证 →业务处理 → 数据库操作 → 返回响应

所有后端语言都在解决这5件事,只是语法不同。

学会用概念描述需求,AI 就能帮你生成任何语言(Bun.js / Python / Java)的代码。

后续

后端并没有那么复杂吧, 别着急, 今天先说这么多, 后续课程会继续拆解其他开发任务。

思考题

回想一下你平时调用的后端接口(比如获取用户列表、提交表单),试着用今天学的“5步法”拆解一下后端做了什么?

欢迎在评论区分享你的思考。

阿里发布数字员工产品QoderWake,可承担工程师、运营、销售等岗位角色

2026年4月30日 09:57
36氪获悉,4月30日,阿里发布数字员工QoderWake和Qoder移动端两款Agent产品,全面覆盖企业和个人场景的需求。QoderWake能在真实工作中承担软件工程师、运营和分析师等岗位角色。目前,QoderWake已开启邀测,个人和企业均可在官网申请雇佣一位或多位数字员工,或根据自身业务流程定制专属数字员工。

OpenAI提前数年实现关键AI算力目标

2026年4月30日 09:55
OpenAI提前数年实现在美国获取人工智能(AI)算力的关键里程碑,为这家初创公司雄心勃勃的数据中心扩张计划注入动力。该公司周三在一篇博客文章中称,已签署了10吉瓦AI算力合同。该公司最初力争在2029年实现这一目标。OpenAI表示,已签订合同的10吉瓦算力中,有3吉瓦是在过去90天敲定的。其中包括亚马逊提供的2吉瓦。1吉瓦的电力足以同时为约75万户美国家庭供电。(新浪财经)
❌
❌