QQ 9“傻快傻快”的?!带你看看背后的技术秘密

628e86625c49f7ddab772ecb7ab55ecc.png

fe2d1b04da4576d5829f3826289d2705.gif

👉目录

1 仍有5亿人坚持用 QQ

2 吹毛求疵的打磨

3 轻盈焕新的 QQ 9 

4 总结和展望

最新发布的 QQ 9 自上线以来,流畅度方面收获了众多用户好评,不少用户戏称 QQ 9 “傻快傻快”的,快到“有点不习惯了都”。

作为庞大量级的应用,QQ 9 从哪些方面做了哪些优化,使得用户能够明显感觉到流畅度的提升?本文将详细介绍 QQ 9 流畅背后的技术实现,以及在全流程做的性能优化探索,为应用提升流畅度提供可复用的经验。

01

仍有5亿人坚持用 QQ

今年是中国开启互联网时代的第 30 年,也是 QQ 作为“初代互联网产品”的第25年,手机 QQ 的第 14 年。

#仍有5亿人坚持用 QQ # ,正是有这群用户的坚持,督促着 QQ 技术团队不断的自我革新,为了能给用户更好的体验,对性能孜孜不倦的追求。

86a2385e49ecd6004fe08f2360ea58f8.png

QQ 9 宣传图

QQ 9 开始,我们从底层架构自底向上全部重构优化,解决了手机客户端原来启动缓慢、容易卡、转菊花等待时间长、UI 跳变等一系列问题。上线后,收获了用户众多好评,其中有个高频关键词是「丝滑」,在丝滑的背后,其实是技术人吹毛求疵般的打磨。

本文将为大家揭开 QQ 9 背后的技术探索,分享 QQ 匠人们硬核的优化手段。

02

吹毛求疵的打磨

   2.1 极致秒开 — 启动速度优化

QQ 的丝滑体验从「启动优化」开始,以 iOS 端为例,启动流程主要分为 3 个阶段:

  • T0:点击图标到 main 函数开始;

  • T1:从 main 函数开始到 didFinishLaunchingWithOptions 结束;

  • T2:didFinishLaunchingWithOptions 结束到首帧渲染完成。

一般将启动过程按阶段分为 pre-main (T0) 和 post-main (T1 + T2) 两个执行阶段:

  • pre-main 阶段:系统 dyld 加载 App 镜像和初始化行为,与程序结构和规模关系较大。

  • post-main 阶段:App 在渲染上屏前做的业务初始化行为,与具体业务逻辑关系较大。

一般工程上的优化方向:

  1. pre-main 阶段降低加载和链接的耗时:如动态链接转为静态链接,代码拆分组成动态库并进行懒加载。

  2. post-main 阶段减少主线程所执行的代码总量:如代码下架,代码执行时机延后或异步子线程化,代码逻辑执行效率优化等。

以下就这两个方向,介绍一下 QQ 本次做的有亮点的地方。

   2.1.1 pre-main 阶段 - 按需装载代码

ed6b0b39bbaeefd01ecf960cb343bbda.png

动态库懒加载方案原理图

代码拆分组成动态库并进行懒加载这项技术多应用于业界大型 App(抖音、Facebook、快手)中,但 QQ 的业务复杂度颇高,直接使用业界方案无法满足我们的需求。经过一番探索我们找到了一些创新技术点:

  1. 使用 __attribute__((objc_runtime_visible)) 实现低成本代码动态化改造。

  2. 使用 objc_setHook_getClass 实现动态化代码入口收敛,保证了方案稳定性。

最终在 QQ 9 中大规模的应用实现了对 pre-main 阶段的启动耗时优化(这个技术方案约贡献了33%左右的启动总耗时优化数据收益):

1abeb5ad837c9b5312be2474a545d39e.png

Xcode Organizer Launch 数据图

   2.1.2 post-main 阶段 - 线程治理

我们防劣化系统监控到主线程抢占的问题越来越严重,通过 Instruments 查看,我们发现一些严重的情况下,温启动过程中主线程有 14%的时间片处于被其他线程抢占的状态。

7b05d395d50281e44a2b2abcc7477b0b.png

Instruments 分析 QQ 启动耗时图

什么是主线程抢占(Preempted)问题?简单来说就是主线程的 CPU 时间片被其他线程抢占,导致主线程得不到 CPU 资源。随着抢占问题越来越严重,也引出一些相关的问题,例如启动总耗时也随着劣化、启动后卡顿、启动耗时波动大、防劣化性能报告误判概率增大等。

为什么会出现主线程被抢占?简单来说有以下几个原因:

  1. 系统调度行为、系统级线程(比如 PageIn 线程)抢占。

  2. APP 频繁开辟子线程却不注意管理子线程的数量,可能会出现「线程爆炸」的情况,而且子线程不恰当地设置 QoS,会容易导致主线程被抢占。

  3. 主线程任务过重,占用时间片过长,会被系统惩罚降级,然后被其他子线程抢占。

了解了原因以后,我们从以下三个方面进行治理:

减少子线程的数量

手 Q 大部分业务广泛使用 GCD,经过查找资料和研究,我们发现频繁使用 GCD 的全局队列,可能会导致线程爆炸,原因是当子线程在 sleep/wait/lock 状态时,会被 GCD 认为是非活跃的状态,当有新的任务到来时可能便会创建新的线程。

93583f0eafbffc88cb36246d2751d06c.png

Apple 工程师、前 GCD 开发工程师发表言论

苹果官方建议不要创建大量队列,使用 target_queue 设置队列的层级结构,多个子系统就形成了一个队列的树状结构,最后队列底层使用串行队列作为 target_queue 。详情见《Modernizing Grand Central Dispatch Usage - WWDC17》

降低子线程 QoS

如果全局队列 QoS 设置为 DISPATCH_QUEUE_PRIORITY_DEFAULT ,则该任务的 QoS 将继承原来所在队列的 QoS (如果原来队列是主队列,将从 QOS_CLASS_USER_INTERACTIVE 降低为 QOS_CLASS_USER_INITIATED)。开发同学经常在主线程将任务派发到全局队列,并指定 QoS 为 DISPATCH_QUEUE_PRIORITY_DEFAULT ,这将导致存在大量子线程 QoS 为 QOS_CLASS_USER_INITIATED。以下是 QoS 优先级排序:

__QOS_ENUM(qos_class, unsigned int,
  QOS_CLASS_USER_INTERACTIVE = 0x21, // 33
  QOS_CLASS_USER_INITIATED = 0x19, // 25
  QOS_CLASS_DEFAULT = 0x15, // 21
  QOS_CLASS_UTILITY = 0x11, // 17
  QOS_CLASS_BACKGROUND = 0x09, // 9
  QOS_CLASS_UNSPECIFIED = 0x00, // 0
);

而实际开发中,很多网络请求、写磁盘 I/O,都使用了该 QoS,实际上是可以通过降低 QoS 来降低子线程的优先级。

提高主线程的优先级

QoS 并不完全等价于最终的线程优先级,主线程优先级范围为 29~47 。为什么运行过程中主线程优先级会变化?官方文档 《Mach Scheduling and Thread Interfaces》中的 “Why Did My Thread Priority Change? ” 章节解释了这个原因:如果线程的运行超出了其分配的时间而没有被阻塞,则会受到惩罚甚至被降低优先级,这么做的目的就是为了避免高优先级的线程一直抢占系统资源,导致低优先级的线程一直处于饥饿的状态。

如何避免主线程运行超出 CPU 分配时间,而免除降级惩罚?可以从 RunLoop 层面做减负。

App 启动过程开始的第一个 RunLoop,会执行持续到首屏渲染结束。而首屏的任务一般很重,导致 RunLoop 耗时很长,容易被系统降级。

061fc62710736bc2b159a1060ae632e4.png

QQ 启动时第一个 Runloop 耗时示意图

解决方案是对第一个 RunLoop 里的任务做拆分。我们的做法是保留必要的全局初始化逻辑在第一个 RunLoop 中,把主 UI 的创建延迟到下一个 RunLoop 里。这样不仅有效地解决了启动时主线程被抢占的情况,还能够加速启动更快看到主页面。

其实这里还有一些优化空间,我们将第一个 RunLoop 的任务都挪到第二个 RunLoop 了,就又导致第二个 RunLoop 耗时较大,可以按照此思路继续优化。

   2.2 "众"享丝滑 — 性能流畅度提升

   2.2.1 如何定义流畅?

流畅(丝滑),体感上的表现是屏幕内容跟随手指操作即时变化,每一次操作都即时地反馈在屏幕上。如图所示,未开启高刷帧率时应保证 16.67ms 内将用户操作更新至屏幕上。

887b7720005f84519005e8b733a45fe1.png

用户每个操作,都需经历图中的4个步骤,任一步骤时间过长,都会无法及时更新画面造成卡顿。来源:《Advanced Graphics and Animation Performance》

让 App 做到每 16.67 毫秒更新一次用户操作很难吗?难,难在这么短的时间内 CPU 和 GPU 需要完成很多事情,更具体的:

  • 屏幕上显示的内容只能在主线程更新(只能单核,无法利用到手机的多核 CPU)。

  • 影响 GPU 的耗时因素多,展示的界面越复杂耗时越多。

主线程的 16.67 毫秒 - 系统需要的耗时 = 开发者可用的时间。如下图所示,蓝色区域为开发者占用的时间,当开发者使用的时间过长即会造成 hang,即卡顿。

7d25b75cabcf2b2d41fcba0715f340ef.png

紫色区域:系统接受与处理用户手势操作的耗时

蓝色区域:开发者转换用户操作为屏幕显示内容的耗时

黄色区域:屏幕展示内容的耗时

来源:《Explore UI animation hitches and the render loop》

如此,想要丝滑就必须做到以下两点:

  1. 善用多线程编程,尽可能少在主线程上做更新 UI 以外的事情。

  2. 尽可能让 GPU 绘制简单的界面,减少 GPU 耗时。

   2.2.2 善用多线程编程,尽可能少在主线程上做更新 UI 以外的事情。

NT 内核架构打好基础

QQ 9 所采用的 NT Kernel(NT:New Technology,此处向 Windows NT 内核致敬),基于尽可能发挥多核 CPU 能效的理念而诞生,如下图所示,最大程度将业务处理逻辑从负责 UI 展示的主线程中剥离,且使用异步调用代替线程锁,提升效率的同时降低死锁的可能。

876b3c237a0afc866b6ffda7369d232c.png

NT Kernel 多线程模型

此外,NT Kernel 采用 C++ 实现 IM 软件的核心基础能力,使其能跨平台使用,保证各平台的性能体验一致,用户交互界面则采用各平台原生语言实现。让用户感受强劲性能的同时保证了各平台特有的体验。

d9ac099bb6f8fff6b7b32d133d0a57f0.png

NT Kernel 支持多平台架构图

全量刷新改增量刷新

在全新 NT 内核的加持下,耗时业务逻辑都已经挪到子线程,主线程仅剩刷新 UI 的相关工作。那刷新 UI 这个事儿还有进一步优化的空间吗?答案是肯定的,14 年陈的手机 QQ 在屏幕上更新一条新消息,会将当前展示的消息全部刷新一遍,即"全量刷新"机制。滚动时无法刷新消息、资源跳变等坏体验,都是该机制导致的。

为什么滚动时无法刷新消息?并非无法刷新,而是不能刷新。多余的刷新操作很容易使得 UI 更新无法在 16.67ms 内完成,进而诱发卡顿。

为什么会出现资源跳变?全量刷新会触使屏幕上的所有节点回收、重用,并且这种重用还是无序的。如下图所示,全量刷新后节点位置会随机发生改变,例如:尾号1b400(左图第2个)的节点刷新前用于展示2,刷新则展示7(右图第7个)。

c13388155001596e05b9c3739793267e.png

对比左右两张图的节点内存地址可见,全量刷新后会出现随机变化,并无规律可言。

无论是静态或是动态图片,都存在磁盘 I/O、解码等耗时操作,一般都会采用异步加载,避免主线程的卡顿。再叠加这种随机重用的特性,也就造成了"资源跳变"的表现。

根据不同的重用情况会有以下三种表现:

  • 恰好是上次所用的节点或者内容恰好相同:相同内容赋值,没有任何变化。

  • 没有相关动/静图:内容从无到有,符合预期。

  • 有相关动/静图,但与当前 Model 的内容不一致:出现闪烁。如图下图所示。

d457f35d50bfac6b9ce07a7ca2b6e670.png

所有异步加载数据的元素搭配全量刷新,在未加载完毕前会展示其他节点的旧信息;即使刷新时重置视图也无法解决,只是从A->A->B改成A->空->B,依然存在明显的跳变。

QQ 9 采用的"增量刷新"就能很好的解决上述两个体验问题。此外,还有一个全量刷新无法实现的隐藏福利:节点动画,如下视频所示。

实现增量刷新需要有个可靠的 Diff 算法,告知系统有变化的节点是需要执行刷新、插入、删除、移动中的哪种操作,一旦给到错误的信息将会直接导致 App Cras。敲定算法过程也是一波三折。

首先,阅读源码发现 Android 与 iOS 系统内置的 Diff 工具都是采用 Myers 算法实现的。

Myers:计算结果保存在changes的数组内,其中只有insert、remove两种类型。(来源:Swift Diffing)

29f4ea387951277698247c024eb07e51.png

Myers算法求解过程,通过插入、删除求源到目的的最短编辑距离。来源:AnO(ND) difference algorithm and its variations

该算法在计算移动时存在"缺陷",其通过插入+删除行为推测移动,特定场景下移动操作会降级为插入+删除。比如,先删除再移动就会转换为删除+插入,反之则是移动+删除:

  • 删 + 移 → 删 + 增:

    数据集A:[1, 2, 3, 4, 5]->数据集B:[2, 3, 5, 4]。会删除1、4,接着插入4。

  • 移 + 删 → 移 + 删:

    数据集A:[1, 2, 3, 4, 5]->数据集B:[1, 2, 4, 3]。会交换3、4,随后删除5。

经过分析,理想的 Diff 算法应该具有以下两种特质:

  • 能够记录节点之间的移动关系,并不是通过插入、删除的联系推断移动。

  • 具备较低的时间复杂度与空间复杂度。

对比行业方案后,选中论文《A technique for isolating differences between files》中描述的 Heckel Diff 算法。该算法的最优、平均、最差复时间/空间复杂度均为 O(m+n),优于 Myers 算法的 O((m+n)*d)。其符号表的实现方式保证所有移动操作均被记录,不会再出现 Myers 中丢移动操作的情况,如下图所示。

fa0ca37d2f06e0e0adeb97dfeb095f9f.png

Heckel算法通过6个步骤借助符号表产生新老数据之间的Diff信息

  • PASS1. 建立新数据所需新索引数组(NA)与 Symbol Table 之间的关系

  • PASS2. 建立老数据所需旧索引数组(OA)与 Symbal Table 之间的关系。

  • PASS3. 查找位置没有变化的节点,更新新旧索引数组(NA、OA)中的索引信息。

  • PASS4 - PASS5:适用于对两个本文进行比较的 Case(存在 Key 值相同的情况),在 QQ 的应用场景中不允许出现相同 Key 值的情况,可跳过。感兴趣的同学可以直接查阅论文。

  • PASS6. 根据现有结果计算差异,如图下图所示:

828a0c556c0fd7fbefced11de4827e37.png

D表示被删除,U表示没有变化,4、5之间存在移动关系。

那么 Heckel 算法是完美的吗?不然,它并没有考虑冗余的移动信息,冗余的移动操作会导致下图中的动画错乱问题。

38cf6e77103d072cedd1845c39791c59.png

我们在 Heckel 算法的基础上进行改良优化,追踪记录移动操作,区分出直接移动与间接移动,并将间接移动部分进行过滤删除,最终得到满足 QQ 9 各项指标要求的 Diff 算法。如下图示例,ID5 直接移动到第一行,ID1-4 都是间接往下移动。

f17460de389418bc10761200a7698219.png

记录直接移动的偏移量(move = insert X + delete Y的偏移量都需要记录),修正间接/被动移动的结果(ID 1-4的移动)

并行预布局

异步布局作为业界的最佳实践,自然不能在 QQ 9 上缺席。我们也进一步尝试将异步布局并行化,深挖性能极限。

首先尝试了 N 条消息 N 个线程的方案:用 GCD 派发 N 个并发任务,然后用 DispatchGroup 等待这些任务执行完成。通过并行预布局,将原本一个线程需要几十毫秒的预布局减少到了十几毫秒。这个方案后来发现了 2 个问题:

  • 并行布局 N 条消息的总耗时还是比串行布局一条消息的耗时要大得多,受限于 CPU 核心数,代码中的锁或其他资源竞争导致 N 条消息的参数准备和布局计算没有能充分的并行。

  • 这N条消息的布局任务分别和 N 个 GCD 任务一对一绑定了,GCD 调度这 N 个任务中有任何一个调度慢都会拉长整个预布局的耗时。

2e6b683cc6b4ea5c633abddbf07b2278.png

充分利用多核CPU的算力;使用并行计算,布局计算的总耗时减少了约76%。

调整后的方案如上图所示,使用了 M 个执行者来执行N条消息的布局任务(N>=M>0)。当前线程(异步布局主线程)来执行 1 个执行者,然后再由 GCD 额外调度(M-1)个线程来执行(M-1)个执行者。 首先将待计算的消息放入一个队列中,每个执行者都会循环从待计算的消息队列中取出一条消息执行布局计算,直到待计算的消息队列为空。因为消息的布局任务没有和任何一个执行者绑定,即使有执行者较长时间没有被调度也不会导致布局计算迟迟无法完成,大部分情况下这 M 个执行者会被 M 个线程并行执行。

d8e82f8102f3a821d2de5cae0c2aadb2.png

并行布局的总耗时会随着并发线程的增加而减少,当增加到5以后耗时就基本没有怎么减少了。

看上去目前布局计算的工作已经从主线程挪走了,现实是很多时候计算出来的坐标与大小并没有与屏幕的像素点大小吻合,此时系统会在主线程再做一次“像素对齐”。在“异步布局”时也不能忽略该细节,才能确确实实减少主线程的负担,如下图所示。

80e5511daf574d65aded38a74f883539.png

OLED屏幕的1个像素R:G:B比例为1:2:1,显示时DDIC(Display Driver IC,显示驱动芯片)会进行次像素渲染从其他像素借元素使显示更饱满。但代码并不能直接控制该行为,系统需要保证提交的内容与屏幕像素完全对齐,即不能出现类似使用0.5个像素的情况。

e7aaff83321cbb525f1fee13820c60f8.png

标黄区域为坐标、大小结果与屏幕像素未对齐

其他的优化还有:智能预加载、消息回收、图片资源异步解码等。如下图所示,根据屏幕比例得到一级缓存 display ,二级缓存 preload ,超出的部分则被回收释放。

440a281790f04b834283faae6ae4e655.png

资源预加载策略图

   2.2.3 尽可能让 GPU 绘制简单的界面,减少 GPU 耗时。

除了布局可以异步计算,复杂的图像也能使用"异步渲染"的方式降低 GPU 的耗时;特别是面对需要叠加裁剪的图形时, GPU 的绘制任务无法在一个 Frame 内完成,就需要再额外开辟一个 Frame Buffer 进行绘制,并在全部完成后将两个 Buffer 的内容进行合成,这被称作“离屏渲染”。离屏渲染对于性能的损耗非常大,主要在于 GPU 的上下文切换所需的开销很大,需要清空当前的管线和栅栏。原话在这:A Performance-minded take on iOS design | Lobsters。对于这种情况,苹果的工程师给出的建议是用 CPU 绘制来给 GPU 分担一部分工作。如下图所示:

6994535d418664087e7da243692ef0d3.png

标黄区域为GPU离屏渲染,不可否认GPU的off-screen比CPU的off-screen代价高很多;在无法避免mask的场景下,使用多核CPU进行异步渲染性能更好。

我们在渲染消息时利用了多核 CPU 进行异步渲染,降低 GPU 部分的耗时。这里面临的难点在于:在可快速滑动更新的列表场景使用时会出现"闪白"的问题;如著名第三方开源框架 YYKit 也存在此类问题,我们通过 LRU 缓存+增量刷新的方式很好的解决了此问题。

   2.2.4 叠满 buffer 的丝滑体验

基于上述 CPU 与 GPU 维度的各项优化,我们在消息 Tab 上实现了国内头部同类应用目前也不具备的滚动中实时接收消息的能力,且不会出现卡顿;此外,也扩展了老版本 150 个会话的限制,与聊天界面一致以分页的形式加载用户所有的会话节点,如下所示:

滚动中接受消息,且不卡顿

进入群、好友聊天界面的速度也得到了质的提升,在加快进入动画的同时,依然能够保证即刻就能看到最新的聊天内容。如下图所示 —— 同一个帐号进入同一个聊天页面。左边是优化前的效果,聊天页面都快全部展示了,内容还在加载中;右边是优化后效果,聊天页面只展示了一点点,就已经能看到发送方头像和消息内容了。

c912c7c373507aa2b88a9e2fdd5ad3ca.png

进入聊天页面加载速度对比图(左为优化前,右为优化后)

除了进入速度的提升,聊天内容翻页的速度也达到了业内顶尖水平:超越国内头部同类应用,对标 Telegram。不论用户有多少消息,都能够通过不断上拉看到,并且用户感知不到 loading 态。

652241cccd6c7b321ccdecb6b7769954.gif

76811a72de13a45fce366e3caa9c9ccc.gif

聊天页面优化前后对比图(上为优化前,下为优化后)

   2.3 青春常在 — 防劣化系统

打江山易,守江山难。防劣化是所有达到一定规模的技术团队都会头疼的问题,面对复杂的业务和技术债,手 Q 团队投入了 3 年的时间迭代优化,现在手 Q 的防劣化系统已经达到了业界先进水平。作为手 Q 质量的守门员,我们将其命名为 Hodor(Hold the door)。

防劣化目标:提前发现部分主路径问题,通过门禁防止性能劣化。

  1. 主干合流门禁:对于较稳定的性能指标,合流前自动检查。

  2. 日常自动提单:针对偶现的性能问题,开发阶段提前发现。

  3. 性能数据看板:常态化详细数据看板,上帝视角观测性能。

  4. 告警机器人:自定义各性能维度告警规则,第一时间反馈问题。

整体方案是基于 Instruments 动态追踪技术采集 diagnostic 诊断数据;xctrace 自动解析 trace 文件,翻译堆栈精准归因;每次提交构建均执行防劣化检测,精准定位问题;还有数据可视化看板 + 自动提单派发,将质量左移到开发阶段。最终实现了性能报告、数据分析、智能调度、提单告警、设备管理、用例管理等一系列能力。一图以蔽之:

2a71ea7f87dda1c521e9fa2c54df4af3.png

防劣化系统方案简介

Xcode 12 开始提供了 xctrace,其 Release Notes 中解决的很多 issue 也来自于手 Q 团队在防劣化开发过程中发现与反馈。在性能优化方面 QQ 与 Apple 性能团队交流紧密,大家也会加班克服中美时差。

整个手 Q 防劣化系统上线以来,有效地保证了开发主干的稳定性,也检测到了大量的性能和崩溃问题,同时拦住了很多新需求引入的性能问题。

0a2fb7330950c08ee0cb7de6e45b9b4e.png

防劣化成果图

目前 Hodor 已经覆盖数十个场景,并落地 iOS/Android/Windows/macOS/Linux 五个平台。

03

轻盈焕新的 QQ 9 

经过上述全方位优化,QQ 9 在各场景的性能都较历史版本较大的提升,如下图所示:

42189ff381dea5518a402ef77264e95e.png

使用苹果官方的工具:Xcode Organizer 可以看到 QQ 9在流畅度上较之前的版本 50 分位提升35%,卡顿率降低48%,启动耗时降低40%。如下图所示。

1b73f3987efd7fd4ff13507ac413381a.png

04

总结和展望

本文我们介绍了 QQ 9 丝滑背后的技术实现,从启动速度,页面刷新,差异算法,预加载和回收,异步布局和渲染等方面介绍了我们在性能方面做的全流程优化,并介绍了几个用户体验提升的场景表现。

其实技术领域深入复杂,每一项优化点都可以单独拎出来好好地展开说明,因为篇幅问题,只能留到以后慢慢和大家分享。

希望 QQ 技术团队做的这些打磨,可以给用户带来切实的体验提升;也希望 QQ 能越来越好,因为我们每一位也是坚持使用 QQ 的 5 亿分之一。

-End-

原创作者:张曌丶毕磊

联合作者:杨萧玉丶姚伟斌丶戴黎明丶梅永盛丶林晓荣丶王哲

技术指导:钟雨丶唐琨

 c812f1c978db8c2638976901e6119840.png

还想了解那些 QQ 9的故事?欢迎评论留言。我们将选取1则优质的评论,送出腾讯Q哥公仔1个(见下图)。4月24日中午12点开奖。

fbfa15e9db8197c4eb7bdbdafd367c33.png

📢📢欢迎加入腾讯云开发者社群,享前沿资讯、大咖干货,找兴趣搭子,交同城好友,更有鹅厂招聘机会、限量周边好礼等你来~

bcf047774f57b8232a52727fb7dd5152.jpeg

(长按图片立即扫码)

c8ff8c8a95dc4529ef4927e8d742e253.png

02888936c3d522609bf525d0ecbd5eb5.png

2b083f038803b16109156ab1e4daf981.png

9b18e466102a5865b3c285ce2cdb7bed.png

23ca3c9021e2dfedfeb8d7e296b1b552.png

相关推荐

大模型的Agent Skill功能,在LLM HTTP底层交互流中是怎么承载的?

网络文章文本的 skill,昨天我实现了之后也就开始好奇起 Skills 的底层原理了——相比起各种花里胡哨的 agrnt 应用,我一直以来都很对大模型在纯粹的 HTTP 交互层面是如何交互的更感兴趣。Skill 的全部"魔法"都发生在 system prompt 的措辞和 SKILL.md 文件的编写质量上——本质上是一种 prompt engineering + 文件系统的组合。但是各种天花乱坠的 skills,是如何在底层的 HTTP 中,与大模型——这个只会嘴遁的工具交互的呢?

QcloudCommunity的博客 407

万字入门AI Infra:深入理解大模型中的数学与Infra优化

关注腾讯云开发者,一手技术干货提前解锁👇AI Infra科普、入门或者进阶 ~~ 不到 5 万字,带你融会贯通理解大模型的数学、算法、硬件到系统工程。任何问题欢迎沟通交流。可怕,我竟然有点认同这句话。当然大概率是因为姚顺宇太懂AI了,而我则是因为无知者无畏。不过仔细想想,大模型推理中的数学逻辑确实不复杂,很多原理只需要高中数学知识就能看懂。但是为什么像 vLLM 这种推理系统这么复杂呢?本文将拆解大模型中几个核心操作(RMSNorm、Softmax、Causal Mask、Sampling)背后的数学与

QcloudCommunity的博客 1167

平平无奇的源码,竟藏着Agent的核心秘密?

System Prompt 是剧本,Skill 是剧本的扩展包,Agent Loop 是演员按剧本行动。欢迎留言,我们将邀请作者针对性回复你的评论,我们将选取1则优质的评论,送出腾讯云定制文件袋套装。,让 Agent 能主动"巡逻",而不只是被动等待用户消息。OpenClaw 的 System Prompt 分层结构。的"行为底线",任何 Skill 或用户命令都无法覆盖它。精华 2:Skill 的"按需加载"避免 token 浪费。精华 1:System Prompt 是"分层乐高积木"

QcloudCommunity的博客 426

QQ音乐Harness Engineering实践

一个看似简单的需求,背后可能牵动服务调用链、配置、灰度、埋点、错误码、接口契约和历史兼容性。当 AI 开始快速生成大量代码,真正的瓶颈就不再是"写不出来",而是"看不完、想不清、管不住"。在对话式编码阶段,一种典型的工作模式逐渐流行:开发者把需求丢给 AI,扫一眼输出"看起来对"就直接采纳,不审 diff、不追问逻辑、不验证边界。以音乐商业化业务为例,一个需求可能从 TAPD 单开始,经过需求评审、技术方案、服务影响面分析、IDL 契约变更、业务代码实现、测试验证、CR、灰度上线,最后才进入稳定运行。

QcloudCommunity的博客 714

从Prompt、Context到Harness,工程的三次进化与终局之战

同时,强制要求散落各处的决策记录(Slack、邮件、文档)全部迁移至代码仓库,确保 Agent 的唯一信息来源是可信的、版本受控的仓库。更坑爹的是,研究表明,当上下文过长时,模型会出现"中间遗忘(Lost in the Middle)"现象:它对开头和结尾的内容记忆较好,对中间大段内容的关注度大幅下降。这篇文章,我想带你完整走一遍这三次进化的逻辑:它们分别解决了什么问题,它们之间是什么关系,它们的边界在哪里,以及:当三者融合,AI 工程师的终极形态究竟是什么?大语言模型的本质,就是这位金鱼助理。

QcloudCommunity的博客 718

让Skill自己训练自己:8阶段Loop、3层评测、5维AND门控,从此实现自进化

所以每一轮改动都是有据可查的,不是「感觉这里可以优化」,而是「Case 41 挂了,因为 agent 把离职问题路由到了邮箱分类,但正确答案在通讯录,所以我改 root_index.md 加个易混淆提示」。但让我最后决定把它记录下来的,不是这的个「吸收」过程,而是它真的在替我探索我不想费脑力触达的边界,这看起来更像是一个机器智能应该有的样子。不准跨层,每轮只改一层的东西。但我经过这 19 轮之后觉得,更准确的描述是互补——你在明处看着,AI 在暗处替你试错,你看不见的那一半就是 AI 能贡献的地方。

QcloudCommunity的博客 1127

只加两行代码,为什么要两天?一文深度理解业务系统的复杂性

关注腾讯云开发者,一手技术干货提前解锁👇业务系统复杂性一直是令开发者头痛的问题。复杂的不是增加一个需求需要耗费多少时间,而是在增加一个需求后带来的蝴蝶效应:其它功能会不会受到影响、要如何去找到这些影响,最终如何实现系统正常运行......功能之间隐秘增加的耦合、不可避免的代码腐化在导致业务复杂性增加。大家都在说的软件开发提效到底在提什么?程序员日常工作中应该如何提升开发效率?敏捷开发、瀑布流式开发孰是孰非?欢迎阅读。业务背景与目标我依然非常清晰地记得某个时候,我所在团队 Leader 曾讲过一段话:“我担

QcloudCommunity的博客 713

从零设计生产级 Multi-Agent Harness:架构、评估、记忆、成本与 MCP 工具接入全拆解

在 AI Agent 领域,Multi-Agent Harness 指的是把多个 Agent 的能力、工具、状态、通信、编排、监控统一收束在一个运行时之内的框架。第三,Agent 路由。一个输入框,一个大模型,几个工具,一段写得很漂亮的 System Prompt,再配上一个炫酷的前端,看起来就像一个能干活的“数字员工”。Multi-Agent 完全不一样——它有计划、有中间步骤、有工具调用、有 Agent 协作、有重试、有反思、有最终合成。增加 Budget、权限、重试、压缩、轨迹评估、审计、回归测试。

QcloudCommunity的博客 710

拆完Hermes源码,我发现Agent的“自我进化“根本不需要训练模型

两个月 5.2 万 Star,Hermes Agent 用一个"LLM 审判官"机制实现了 Agent 的自我进化——不改模型权重,只改"怎么用模型"的策略。OpenClaw(社区昵称"龙虾"🦞)是 2025-2026 年最火的开源 Agent 框架,30 万+ Star,插件市场 ClawHub 里有数千个插件,能接入 Telegram、WhatsApp、Slack、飞书、企业微信——几乎是一个"个人 AI 操作系统"。Skill 是英语写的,Memory 是英语写的,审查 Prompt 也是英语写的。

QcloudCommunity的博客 909

AI Infra 其实没有多少新东西

传统 Infra 追求横向扩展,而 AI Infra 呈现 “AI 大型机”特性,是因为传统后台服务的可以容忍毫秒级延迟,但 AI 集群不行,GPU 的算力是 CPU 的数百倍,微秒级的延时等待也会造成很大的算力损耗,需要硬件的高度集成。在可预见的1-3年的未来,这样的专用硬件+网络的集中式架构很难发生比较大的改变。与之相似,模型推理的批处理就是将多个输入样本打包(batch),将原本串行的 N 次轻量的推理计算,合并为 1 次重量的计算,实现单位时间内处理更多的请求,提高了 GPU 利用率。

QcloudCommunity的博客 825

程序员越早想通这些越好

永远没有正确架构,你永远无法偿还完所有的技术债务,如同你永远不会设计出完美的界面,请避开完美主义的陷阱,永远没有完美的代码,能够满足当前需求,又为未来不管是自己还是他人留有扩展空间,就很好了。我们努力的方向就是将现实世界映射到有限的数据结构中,这就需要用户自定义类型,如果你的代码中包含类似 trader portfolio 这样的概念,你就可以使用他们的名称来建模,而不是使用基本数据类型复杂嵌套表述你的目的。从另一个角度看,代码里的注释都是补丁,是碎片化的,局部的注释很难推导模块整体的顺序及耦合关系。

QcloudCommunity的博客 465

RAG已死?不,是Grep回归了!

这样一来可以直接复用已有的计算缓存,只为新增的增量部分付全价,前面累积的大头按约 1/10 的缓存价计费。所以实际的工具组合方式是灵活的:Grep(默认模式)→ Read 是最常见的路径,但 Grep(content 模式)可以独立使用,LLM 也可以直接调 Read(如果已经知道文件路径),或者一次同时发起多个 Grep 并行搜索。它从零开始构建自己的对话历史,不继承主对话的消息,这意味着它搜索过程中产生的大量 grep 结果、代码片段都留在自己的 context 里,主对话只收到一段总结性的文本结论。

QcloudCommunity的博客 576

深入浅出Harness Engineerring之核心模式与理念

在智能体生命周期的关键节点(如会话开始、工具调用后)自动触发预设动作(如代码格式化),由系统确保关键流程被执行,不依赖可能被模型遗忘的指令。简单讲就是利用向量存储这个技术,来实现模糊检索,原理是:即使字面不同,但语义相近的文本,其向量在数学空间中的位置也很接近。根据命令类型、参数和影响,自动评估其风险等级(安全、有风险、危险),并采取自动执行、请求确认或直接拦截等不同策略。关键特性是可隔离、可重建、可扩展。不是一次判断就定终身,允许你改变、允许情况复杂,通过不断观察、思考、调整,越来越懂真实的你。

QcloudCommunity的博客 624

Harness Engineering实践心得:如何高效驾驭AI?

但如果这些经验被拆成一条条 Rule、一个个 Skill、一项项 Script 检查——"XAML 不能有中文"、"编译要用这个路径的 MSBuild"、"SVN 命令必须带认证参数"——AI 就能在秒级时间里"吸收"十年的踩坑经验。然后可以看到下方的图,我的PM会很顺利的调度其他agent分别负责不同的事项,遇到问题的时候也能准确的找到合适的agent。MCP 本质上是在扩展 AI 的"感知范围"——Rule 管"该怎么做",Skill 管"怎么操作",MCP 管"能看到什么、能碰到什么"。

QcloudCommunity的博客 842

从第一性原理思考 Agentic Engineering

需要注意的是,这一结论是有条件的:如果 AI 缺乏领域知识,过早介入反而可能引入 1.2 节所述的"似是而非"损耗——因此上下文供给(实践 1)是 AI 全链条参与的前提,而非结果。通过一个专门的自迭代 Skill 实现——当 AI 在协作过程中识别到自己被纠正(用户否定了 AI 的输出并给出了正确方向),它自动评估这个错误的根因,搜索现有的 Rules 和 Skills 中是否已有针对该类问题的处理规则。事实上,越是复杂的项目,工程师的认知负担越重(公理 3),AI 分担认知负担的潜在边际价值也越大。

QcloudCommunity的博客 757

万字干货!Harness Engineering如何工程化落地?

关注腾讯云开发者,一手技术干货提前解锁👇Harness Engineering 的概念已经火了有一阵了,全网很多文章基本都是在讲理念,讲为什么今天做 AI 开发,不能只靠一段提示词,也不能把模型当一个“更聪明的代码补全”。但与此同时,一个问题也在持续地发酵:这个问题特别重要。因为 Harness 这个词听上去很大,很像一个抽象的方法论,但它如果不能落到工程、目录、文档、脚本、工作流里,那它最后就只是一句漂亮的话。事实上,不同项目落地出来的 Harness,表面上可能完全不一样。有的项目是 CI 很强,有的

QcloudCommunity的博客 1169

全方位对比:Hermes VS OpenClaw

多账号矩阵运营 如果你的业务涉及同时管理多个社交媒体账号、多个平台的内容分发、多渠道的客户互动——OpenClaw是目前市场上的"无可替代的底座"。一个有专业背景的个人,现在可以快速构建一个垂直领域的AI助手:比如"财务分析Hermes"、"法律咨询Hermes"、"技术架构Hermes",直接通过微信提供服务,积累自己的专业IP。跨平台生态融合 如果你的工作流涉及飞书、Slack、Discord等多个平台的深度集成,需要这些平台之间的数据流转和联动——OpenClaw的生态支持是强大的。

QcloudCommunity的博客 1217

一文讲透:Harness Engineering即控制论!

而研发模式的升级我认为将会是一个飞跃的过程,之所以现在我们仍然需要需要参与编码,一个非常大的原因就是缺乏传感器和基建,仍然需要人来串流程,比如需要人来验证UI是否正确、需要人来告诉AI代码不符合代码规范,因此在有些场景我们仍然感觉 AI 完成的很吃力,但这不是 AI 能力不行,而是我们并没有为 AI 提供友好的环境……控制论中的突变理论介绍了矫枉过正和飞跃现象之间的矛盾,如果质变中经历的中间过渡态是不稳定的,那么他就是一个飞跃的过程,如果中间过渡态是稳定的,那么他就是一个渐变的过程。但是这些阶段要解决的。

QcloudCommunity的博客 1204

神级开源插件!一句话让QClaw变3D小镇,Agent工作可视化,赛博云监工

这个架构是翻了几次车才想通的—原有AI的实现机制是用 setTimeout 猜动画时长导致了幽灵 NPC、工位撞车、越改越崩,后面我停下来换了思路,推翻原有的架构,按照“意图+回传”的架构进行重构,之前的问题一次性全部解决。15 天,我和 AI 吵了 185 次架, 4.5 万行代码,开发了一款 QClaw / OpenClaw 的UGC游戏插件,这可能是人类跟 Agents 交互的新范式,插件已完全开源,有需要的欢迎自取~我天天用,用着用着我就在思考,Agent 产品现在的交互体验,基本都一个样。

QcloudCommunity的博客 1196

一文搞懂Hermes:新顶流Agent如何从经验中自我进化

Voyager 是一个能在 Minecraft 中自主探索、学习技能、无限积累能力的 AI Agent,它提出了 "Skill Library"(技能库)的概念——Agent 将成功的行为序列编码为可复用的技能函数,存储在一个持续增长的代码库中。如果 Skill 的名称和描述不够精准,或者用户的任务描述与 Skill 的触发条件有语义差距,Agent 可能会错过相关的 Skill。如果进程在写入过程中崩溃,目标文件要么是旧内容(还没被替换),要么是新内容(替换已完成),绝不会出现写了一半的损坏文件。

QcloudCommunity的博客 2635

自掏腰包一万元,拥抱AI这一年,我的工具、实践和思考

其实也很好理解,过往的每个领域(比如前端、后端、设计、测试等等)都主要是这个领域的从业者在为它添砖加瓦,但是大模型时代的 AI 应用领域却几乎是所有使用 AI 的人类一起在迭代,无分领域,无分文理,无分老少。因为每个时期的 AI 都有着不同的特点,很多时候当我费尽心思去钻研,自以为有点弄明白 AI 应该怎么玩的时候,基座模型和行业范式常常就会迎来颠覆式的变革,很多过往的经验都会倾覆,然后只能从头再来。过去一年多,被热议的 AI 范式大概是沿着四个阶段递进演化,每一个阶段其实都在解决前一个阶段的核心问题。

QcloudCommunity的博客 627

办公Agent的CI/CD时刻到来了

核心观点是:企业给员工配了一堆 AI 工具,试点跑了几百个,但真正拖慢 AI 转型速度的瓶颈不在模型能力,在"最后一公里":AI 输出和实际工作流之间的那道鸿沟。代码写完,打个 tar 包,开 FTP 传到服务器上,SSH 进去解压,改配置文件,重启服务,刷一下页面祈祷别 500。你复制,切窗口,粘贴到腾讯文档里,发现 Markdown 格式全乱了,手动调标题层级,代码块重新标记语言类型,表格散架了重排一遍。模型是越来越聪明了,但"生成"到"落地"之间那段路,还是你自己在走,一步一步,手动搬运。

QcloudCommunity的博客 608

4亿token买来5个教训:让6个AI Agent连写4天代码发生了什么?

Watchdog 检测到崩溃 → 启动诊断 Agent 分析原因 → 诊断 Agent 跑满 20 轮没搞定 → Watchdog 判定“已修复”,重启系统 → 重启的系统因为诊断 Agent 留下的环境变量被继承,连续 3 次拒绝启动 → 触发连续失败保护退出 → Watchdog 第 3 次巡检,发现进程和记录文件都没了,尝试手动重启,自己也停了。启动前我翻了论文、做了架构设计、写了监控+修复异常的脚本。这个发现让我的情绪从沮丧变成了兴奋——不是那种"终于修好了"的释然,是"我找到根因了"的快感。

QcloudCommunity的博客 584

赛博斗蛐蛐:9大模型决战三国志,天命在谁?

我猜是这样的,当Gemini面临决策的时候,一系列关键词比如 守城,劣势,粮草,三国等等,在语义层面的关联性中LLM发现了竖壁清野这个关键词概率非常高,所以以此为策略,然后再根据这个策略完美执行操作。MiMo 的外交是三方中最精明的。Kimi作为国产模型,也同样颠覆了我对他的看法,最后的比赛他甚至一度是优势者,存在很多夺冠的可能性,要知道他的对手可是claude和gemini,而他经常出兵慢,回过头来想想或许正是他的策略,毕竟中后期他的优势都来自于稳健的发展和较少的战斗频率(和claude比).

QcloudCommunity的博客 874

Claude Code是怎么知道你在骂他的?这 12 条发现值得关注

确实存在——5,500+ 行,集成了消息队列、工具装配、MCP 编排、会话状态、权限、分析、文件持久化和优雅关闭,基本上一个文件干了所有事。对抗虚假声明——"不要在输出显示失败时声称所有测试通过,不要压缩或简化失败的检查来制造绿色结果"。完整的 KAIROS 是一个持续驻留的守护进程,能感知你在不在电脑前、主动寻找有用的工作做,更像是住在终端里的全职同事。源码里藏着一个叫 "Buddy" 的电子宠物系统,完整度令人惊讶——这不是一个 TODO,而是一个从数值系统到 ASCII 动画都实现了的完整功能。

QcloudCommunity的博客 701

逆向深扒Claude Code源码,我发现了什么!?

Anthropic 内部用户获得更严格的质量控制 prompt、更好的验证机制(独立 Verification Agent)、以及针对 model 弱点的专门对策(如 Capybara v8 的 29-30% 错误声明率对策)。这不是代码混乱的标志——它是整个 Agent Loop 的心脏,所有的流式处理、工具调度、上下文压缩、子代理管理都在这个文件中协调。这种"胖核心"设计是刻意的:保持核心循环的原子性,避免分散到多个模块导致的协调复杂度。核心价值:Fork 代理的工具输出不会回到主代理的上下文窗口。

QcloudCommunity的博客 892

一文讲透如何构建Harness——六大组件全解析

本文将从"裸模型的四个硬伤"出发,逐一拆解 Harness 的六大组件——文件系统、Bash + 沙箱、记忆(AGENTS.md)、Web Search + MCP、上下文工程、编排 + Hooks——带你看清 AI Agent 真正的竞争壁垒,不在模型层,而在 Harness 层。如果你用过 Agent 做复杂任务,你一定有过这样的体验:一开始 Agent 的表现很好,但随着对话变长,它开始"变笨"——遗忘之前的约定,重复之前犯过的错误,甚至对同一个问题给出前后矛盾的回答。对于简单的问答场景,这无所谓。

QcloudCommunity的博客 761

Harness Engineering 来了,SDD 还有意义吗?

他们的解法是把「品味」编码进规则,然后用一个定期运行的「doc-gardening」Agent 自动扫描漂移、发起修复 PR——「技术债务就像一笔高息贷款,不断地以小额贷款的方式偿还,总比让债务不断累积要好」。代码仓库本地的、已版本化的工件,才是 Agent 所能看到的全部。在 Vibe Coding 模式下(即不做规划、随意向 AI 提需求的开发方式),大量设计决策、跨服务约定、「为什么不选另一个方案」的讨论,全部停留在一次性的 AI 对话里——下一个人,或者下一次 AI 会话,完全无从获取。

QcloudCommunity的博客 419

零废话!一文讲透从0构建AI Agent

每个工具都要写一套"定义→解析→执行"的胶水代码。上下文管理就是在"记住足够多"和"别超标"之间找平衡,常见策略包括滑动窗口、摘要压缩、RAG 检索增强。上下文窗口是 Agent 的"工作记忆",但它有硬性限制。LLM 负责"动脑"决策,代码负责"动手"执行。这是从"聊天机器人"进化到"Agent"的关键一步。每次调 API 都把完整对话历史发过去,LLM 本身是无状态的,"记忆"完全靠客户端的数组模拟。这样 Agent 一开始就知道自己"在哪里"、"手头有什么",不需要先花一轮工具调用去探索环境。

QcloudCommunity的博客 711

距离AI把小编我裁掉还有72小时

这是一个基于 OpenClaw 开源生态打造的本地化 AI Agent 助手,已于上周开启全量公测,无需复杂配置,三步即可上手,自带安全防护,支持微信直连绑定,内置多款优质国产大模型,现阶段也是完全免费使用,基本上前面提到过的痛点都可以靠它解决。对了,这里特别强调一点,上面的截图让产品同事汗流浃背,再三找我确认 QClaw 思考过程中优美的“草”字说法,不会是默认出现的吧?AI 好,AI 得学,但更重要的是,在你的工作和生活里,哪些东西是能结构化地被 AI 所接入的,不要死守着那些脏活累活不放。

QcloudCommunity的博客 673
上一篇: 腾讯联合新加坡国立大学研发的这个传播模型,已入选WWW 2024
下一篇: 十年编程经验一朝面试被刷,技术面试如何提升表现?
腾讯云开发者
腾讯云开发者 企业官方账号 企业官方账号
博客等级 码龄10年 6291粉丝 1962原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值