MoreRSS

site iconChen Junda修改

北京大学计算机应用技术硕士,上海微软工作。爱好包括计算机、游戏、羽毛球、纯音乐、电影和音乐剧。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Chen Junda的 RSS 预览

可划分显存 != 统一内存:AI Max+ 395 64G AI推理性能

2026-02-02 20:34:00

前言

之前写过一篇关于HP战99 Ultra(搭载AMD AI Max+ 395)的使用体验,今天聊聊这台笔记本在AI推理场景下的表现。作为这台机器宣传的主要场景,AI推理的实际使用情况却优点一言难尽。

硬件配置回顾

配置 详情
CPU AMD Ryzen AI Max+ 395 16C32T Zen5
内存 64G LPDDR5 8000MT 4通道可划分显存
显卡 Radeon 8060S 40CU RDNA3.5
显存 可在BIOS里将几个固定挡位的内存分配给显存

关键概念:可划分显存 vs 统一内存

在深入分析数据之前,需要理解几个重要概念:

  • 传统显存:传统独立显卡的固定显存,容量固定,如RTX 4090的24G
  • 可划分显存:静态分配机制,将内存的一部分固定划给GPU作为显存使用,如AI Max+ 395
  • 统一内存:内存和显存统一寻址,整个内存空间CPU和GPU都可以访问,无需显式分配(主要见于Apple M系列芯片)

重要区别:AI Max+ 395使用可划分显存架构,需要静态分配部分内存给GPU使用;而统一内存无需显式分配,灵活性更高。

AI推理测试数据

为了方便,以及因为我至今没能在WSL下成功运行rocminfo也就没办法跑vllm等主流推理引擎方案(就离谱),本次测试均在Windows下使用LM Studio运行。

GLM 4.7 Flash

这是个MoE模型,总参数量30B激活3B的规模,主要测试Q4_K_M量化的情况。在这个量化等级下,在模型大小为18.13GB

以下的给出Prompt为:

编写一个科技公司的官网的HTML

另外值得一提的是,LM Studio中对AMD显卡有两种Runtime:Vulkan和ROCm。我本以为两种Runtime不会有什么很大的区别,但是实际测试下来却axm并非如此。

在16K上下文下:

专用显存 512M 32G
显存占用 20.8G 21.3G
Vulkan速度、总数(token/s) 17.26 (6970) 42.89 (6107)
Vulkan 首token (s) 0.8 0.8
ROCm速度、总数(token/s) 15.28 (5262) 14.42 (6351)
ROCm 首token (s) 0.04 0.34

Vulkan在32G专用显存下的速度实在是过于逆天,于是我重新跑了数次,结果均非常接近。后面我们还能拿到如此让人匪夷所思的成绩。

16K的上下文只能说勉强够用。既然还有这么多显存可用,不妨试试更多的长度上下文。根据LM Studio估计,不同长度上下文的显存使用估计值:

  • 16K上下文:18.59G
  • 64K上下文:19.57G
  • 最大支持(198K):22.3G

看起来MoE模型的一大好处就是可以把上下文拉大!于是我选择GLM 4.7 Flash最大支持的长上下文 198K下,虽然LM Studio的估计显存占用也仅有22.3G,但是512M专用显存的无法正常加载:

无法正常加载模型

只有在32G下可以正常使用,在Vulkan下获得了**37.28 token/s(7857 token,首token 0.15s)**的成绩。

同时我还测试了Q6_K的量化模型,在16K上下文、32G专用显存下:

  • 模型大小:24.61GB
  • 预计显存占用:25.12GB
  • 推理性能
    • ROCm:13.79 token/s(6419 token,首token 0.33s)
    • Vulkan:25.51 token/s(5717 token,首token 0.20s)

再次看到了不知道该说是Vulkan逆天还是ROCm的成绩!ROCm作为AMD官方的方案,居然被Vulkan拉开了如此大的差距。

在不开启思考的情况下,10 token/s的速度还是可以应付日常使用的。

Qwen3 VL 32B

稠密模型的情况就不一样了。这一部分我选择了Qwen 3 VL 32B来测试。

这是个支持图像输入的模型,于是我去stackoverflow上截了如下这一张图,

Stack Overflow截图

并给出prompt:

使用html和css重现这个HTML页面

以下为结果:

专用显存 512M 16K 512M 24K 32G 16K
显存占用 25.8G 28.3G 27.5G
Vulkan速度、总数(token/s) 3.74 (4059) 3.51 (3676) 9.41 (6801)
Vulkan 首token (s) 36.67 39.29 18.32
ROCm速度、总数(token/s) 4.15 (3723) 3.10 (3713) 9.42 (4198)
ROCm 首token (s) 24.59 26.56 9.46s

可以看到,在24K上下文已经到32G显存的极限了(28G)。但不管有没有独立显存,这个推理速度用起来已经是比较难受的级别了。

分配48G给显存?

395的另一个宣传点是可以将75%的内存划给显存,在64G的型号上,BIOS中最高可以将48G的内存划给显存。

听起来很美?48G显存甚至可以高量化跑32B模型了!

Qwen 3 VL 32B的Q6_K量化模型大小为28.08G,在32G显存下可以加载,但是推理的时候因为显存不够了,速度比可以完全在显存中的Q4版本慢很多。经过测试,Q5_K_M是最大的32G显存可以充分的量化规格。

而这时候你想到,48G显存岂不是就可以接近这个问题了?

可是事实却是:16G的系统内存不仅使得正常的系统操作会开始缓慢甚至卡顿,甚至模型都无法正常加载!而我已经LM Studio中有三个选项和显存和内存全部调整为不给内存太多压力了:

  • KV缓存卸载到GPU内存中:打开,显存够大!
  • 保持模型在内存中:关闭
  • 尝试mmap():将磁盘上映射到内存中空间中,关闭

Qwen 3 VL 32B的Q6_K模型无法加载

内存可划分为显存 != 共享内存

395的主要的宣传口号,就是内存可以当作显存用。这话当然不假,BIOS里确实可以将内存划分给显存,但是,它和我们预期的共享内存完全是两码事:

  • 被划分给显存部分不可以再作为内存使用
  • 每次切换显存需要重启,不可无缝切换

那,如果我们不划分显存,直接把内存当显存用呢?其实现在的推理框架都支持把内存当显存用,但是以下两个问题让用内存当显存的方案下的推理速度惨不忍睹:

  1. 内存与显存的速度之间有巨大差距
  2. 内存中的数据仅能由CPU计算,而CPU在AI计算场景下速度非常缓慢,且CPU和显卡的计算数据需频繁相互拷贝

理论上来说,395的内存和显存均为同一款芯片,问题1不存在,但实际上问题2的问题仍然无法避免:即使是在同一块芯片上,显存仍然不能直接用内存部分的部分,内存和显存之间拷贝仍然非常频繁。

以下为使用512M专用显存(上)和32G专用显存(下)使用Vulkan运行GLM 4.7 Flash Q4_K_M时的任务管理器的图片,可以看出,512M的专用显存下GPU利用率只有70%左右,而32G下可以到达90%以上。而右上角的Copy也可以看出512M专用显存下显存一直在进行复制的操作。

512M显存跑GLM 4.7 Flash Q4 16K

32G显存跑GLM 4.7 Flash Q4 16K

同一现象也出现在512M专用显存下运行Qwen 3 VL 32B Q4_K_M的情况,GPU利用率更是只有50%,而Copy图中也能一直看到复制的过程,而整个过程中CPU也在(艰难地)参与运算。而CPU参与计算在笔记本场景下有抢功耗的问题,更影响了GPU的性能发挥。

512M显存跑Qwen 3 32B Q4KM,16K

更进一步地,如果把上下文拉到24K,进一步加大显存的需求量,在512M专用显存下情况更加恶化了:GPU有接近一半的时间都闲着。要知道,这个时候显存需求甚至才26G!

512M显存跑Qwen 3 32B Q4KM,24K

总结

我用两个字总结395的优点:能用

  • 大显存确实可以跑一些正常显卡无法跑的模型,虽然慢,但是能跑比不能跑好!
  • 成本相对较低(相比高端显卡)(也只是相对了)
  • 4060移动端的绝对算力,不算高,但是愿意等等的话,它能跑的模型还是能给出结果的

可是这台笔记本形态、64G的总内存的设备却有点尴尬:

  • 为了兼顾日常使用,实际上最多只能32G给显存
  • 80W的最高功耗,无法充分发挥CPU的性能
  • 手动划分显存操作失去了灵活性

所以395确实非常适合小主机场景:

  • 这类主机在分配96G显存的情况下还有32G可以用于日常场景,比64G=48G+16G实用太多
  • 这类主机的性能释放普遍超过100W,也有更完善的散热方案,可以更完美地发挥CPU和GPU的性能
  • 和395刚出来的时候AMD更羸弱的AI生态相比,至少现在主流的推理场景(LM Studio,Ollama、ComfyUI)都已经可以用了(至少我在搜索了包括AMD官网的无数地方后,终于还是找到了AMD官方支持的pytorch

甚至小主机的价格也比笔记本形态的设备(64G 19999)便宜太多(128G普遍15000,希望还没开始涨)。在这个内存价格疯涨的年代,能以这个价格有一台可以跑大模型的机器已经很不容易了。

2025年总结

2025-12-31 15:30:00

主动选择改变

对我来说,2025年的前半年和后半年是完全不同的。

主动告别了一个熟悉的工作,做出一个必定会做出的选择,期望能回到一个熟悉的工作状态,在一个全新的起点重新开始,却开始不停接受充满未知、充满了混乱的挑战。

离职,一个一定会做出的选择

不知道什么时候,我开始认为离开微软是一个艰难、遗憾、但是又一定会发生的事情。

一方面,在公司两年来,虽然绩效都是拉满,但是所做的、所参与的所有项目都胎死腹中,而新的被分配的AI有关的项目怎么看都很不靠谱,很难推动;年初,校招进微软,待了十余年的直接manager从公司离职;身边同事的升职空间和奖金肉眼可见的越来越小;而每个季度都能传出裁员的消息,和身边同事讨论的都是裁员、relocate、大礼包。

另一方面,可能是所有初进社会人的共同点,总是对现状不满,总是还有着自己的想法,想着换一个环境可能会更能实现自己的理想。

想着早晚会做,不如现在就做。于是我在我第一份工作的第23个月,在2025年正好过了一半的日子,我终于决定主动踏出这一步。

离职

可能最黑色幽默的是,我那在之前从不停歇的裁员潮中稳如磐石的组,在我离开三个月后,被全部裁员。也就是说,这一次,我是否主动选择,对结果并没有什么变化,反而主动让我与20多W的赔偿金失之交臂。

“回到”“原”工作

新的工作,其实也没有那么新:“不新”体现在我回到了研究生期间的、由我从第一行开始从零开始的项目,并且一直以兼职的身份在参与。而“新”则是工作内容的新。从兼职到全职,从一个“局外人”到一个“局内人”,看似相同的工作,看似可以回到研究生期间以及兼职期间的更积极主动的工作状态,但其实是进入一个全新的、未知的、不停地尝试和否定的循环。

解决技术问题?

俗话说,所有软件项目到后面都会变成屎山。更别提一个一开始就是没有好好设计,作为一个玩物开始的项目了。

第一个commit

四年可以发生很多事情:项目从开源到闭源,连带着很多设计都需要跟着改变;所使用的框架和技术从无到有,群雄争霸到逐渐稳定;项目功能逐渐增多,需求越来越复杂,发展目标越来越不清晰……在这么大的变化下,事情总是会朝着阻力最小的方向发展。而ToG项目的本质,就决定了大部分工作都是纯业务的,甚至于还会专门花精力做一些不可复制的、临时性的工作。看起来这些工作很没有价值?可是以业务的眼光看,这些工作才是有价值的。

  • 项目中大量使用全局变量维持全局状态?无所谓,你的客户不会部署多个实例。
  • 项目中存在大量重复代码,风格样式不统一?无所谓,不影响功能,重构反而影响交付节奏
  • 明知项目中隐藏着大量的暗雷,但没有精力、时间和能力建立完善的测试方案,甚至都不知道哪里有问题?似乎也无所谓,反正目前客户没有遇到,遇到了

尝试使用效率更高的风格检查工具,却完全不敢动

说到底,只有需求才能定义什么是该做的,什么是不该做的。客户关心的才值得投入精力和人力,而客户不关心的,投入一分一毫的资源都有可能是对时间、精力的挥霍。

解决流程问题?

既然项目的技术本身没什么可做的,于是我将目光投入了一些其他让我不舒服的点。从流程完善到繁琐的大公司到小公司,当然有极大的不适应。其中,信息分散是让我最头疼的:

  • 30个人分了四个飞书组织、三个钉钉组织
  • 文档信息分散到腾讯文档、金山文档、飞书文档中
  • 工作信息和私人信息混杂,工作信息又在飞书又在微信,群聊也有飞书和微信群,想找信息,根本不知道在哪个地方能找
    • 我平时有两台电脑混合着用,没有一台电脑有完整的微信信息(这里再次亲切问候张小龙)
  • 会议有时候在飞书,有时候在腾讯文档
  • 在实际上的多地base的情况下,没有统一的日历管理,甚至不知道你的同事是否已经请假

断开的微信消息记录

于是在来了公司之后的两个月中,我尝试整理流程和推动文档化办公,例如

  • 设立需求管理和评审流程、开发和评审流程、测试流程、发布流程、部署流程
  • 要求所有可能会重用的信息都必须落实到一个文档中

这些措施有的顺利落地,有的难产;有的受到欢迎,但大部分推动起来困难重重:

  • 你的同事认为飞书响应速度很慢,功能不好用,不愿意使用
  • 你的同事并不认为一个问题的解决方案值得被写入文档
  • 你的同事每天都有无数的事情,什么样的流程和方式才是真正可以被广泛接受并正常使用的?

这些问题说到底,和上一段一样,哪些真的是问题?

如果所有成员都已经习惯了工作生活都用微信,微信里聊工作是最方便的方案,即使微信每发一封文件都要复制一份,发到最后自己都不知道哪份是最后的方案;所有人本来就坐在一起,已经习惯了有问题就现场聊天,让留文档反而是负担,即使第二天就忘了第一天聊了什么。

如果想解决的问题本来就不被认为是问题,那解决方案自然也毫无意义。

应该解决什么问题?

如果让你指出你所在公司存在的不合理的地方,你能提出多少条?我相信大多数人都能提出很多,并会对公司对这些问题熟视无睹充满了不满以及无奈。

但是当我屁股反转,真正做到“老板”的位置上后才发现,不是所有问题都可以被解决的。很多你认为存在的问题,实际上并不是问题;很多你根本没有意识到的问题,反而已经在暗处默默地影响工作效率、氛围和情绪;很多你认为你解决了问题,实际上反而让情况更糟。比解决问题更重要的是发现问题,评估问题,以及在采取措施后观察效果。而这些工作将会没有标准流程,没有标准方案,甚至于没有反馈,只能通过从各个渠道收集大量信息和反馈,分析信息,小步快跑地去做出对应的调整。

这半年来,我自认为发现了无数的问题,也尝试了一些措施去“解决”无数的问题。但是回头看来,有什么问题是被解决了,我到底提供了什么价值,又给各个同事添加了多少麻烦?我没有答案,也不知道如何回答。

双城生活

这半年不得不体验了北京和长沙的双城生活,每两周在北京和长沙之间切换一次base地。

航旅纵横

这种生活的前期是新鲜的。北京虽然租房贵,但是多亏有朋友的帮衬,能够免费在西城住上租金过万的、房龄10年左右的电梯房,体验一下全国最核心的城区的生活体验(事实证明北京市中心真不适合年轻人);长沙租房便宜,即使是工作地旁边的公寓也只有1000多,可以体验到通勤走路10分钟的生活。而两地之间的飞机通勤还让我第一次获得了航空公司的常旅客卡,加上信用卡的福利,基本可以实现休息室自由。

挑战赛获取金卡

但是这种新鲜感只是短期的,短暂的体验之后,迎来的是缺乏归属感。

大家都说租房是一种临时生活,我个人持部分肯定的态度。我目前没有对大件的需求较少,即使有,租房并不会阻止我采购升降桌、人体工学椅这类的大件,大不了,叫个搬家公司就搬走了。可是两地通勤让我彻彻底底体验到了这个感受。

由于有两个居住地,两地的生活设施都不完整。台式机在北京,于是在长沙时只能用工作笔记本应付平时的休闲,没有显示器,小小的笔记本屏幕也完全无法获得一个较好的娱乐休闲的体验;衣服也分布在两地,在11月初两地各自入冬后,由于厚被子还在北京,在长沙10多度的时候仅有薄被子,凌晨3点被冻醒不得不开启空调才能继续入睡;两周时间说长不长说短不短,每次切换工作地的时候都要考虑各类要带走的衣物和生活,然后将宝贵的周末的至少6个小时浪费在路途中。什么都是临时的,什么都是够用就好,不常用的东西就不买。在长沙公寓的桌子和椅子都是海鲜市场的二手货;之前每周做2-3顿饭,现在甚至连厨具都没有采购;甚至于当被要求提供常住地时,都要考虑下写哪个位置。

这种临时的感觉也让我没有任何爱好和社交的欲望。这几年几部乐队的动画让我想重拾小时候的电子琴爱好,但是由于居住环境的不稳定性,不敢买任何大件,而开放琴行一般都是钢琴,和电子琴在对手的能力的要求、可以演奏的音乐的类型有比较大的区别(换句话说就是我菜,弹不了钢琴),并且无论是在北京还是长沙,琴行离居住地都有很远的距离。社交层面,在北京的时候,现在还可以找到之前的朋友;而在长沙的休息日,每天睡眠最多7小时的我,可以在装有万恶之源平板架的床上躺14个小时,在不躺的那10个小时中无比后悔又浪费了一天。

世界上有不少人过着或者已经习惯了这种不定的生活,但是经过半年的尝试,我还是不能说我已经习惯这样的生活方式。

混乱的一年

这是一个混乱的一年。公司变了,工作内容变了,生活地点变了,生活状态变了。

是变好还是变坏了?在这一次的变化是主动选择的,是我一定会做出的选择,之后呢?了解了现状,做出这么尝试,而之后应该获取什么样的信息,做出什么样的改变?

这一年我还没休过一天假期。很幸运能在这个一年的最后一周,稍微告别一下这充满挑战的工作,和老朋友去之前从未去过的东北体验寒风和冰雪,时隔一年再次体验滑雪,然后被滑雪劝退。

长春冰雪大世界

在旅途中和朋友聊到五年后的职业发展情况,然而这毕业两年半的经历,让我不敢再奢谈这么久远的未来。

14寸16核32线程:搭载AMD AI Max+ 395的HP战99 Ultra使用感受

2025-07-26 09:14:00

为什么选这一台?

最近有一次换笔记本的机会,因为之后需要频繁旅行,于是选择了14寸的笔记本作为主力机;考虑到平时开发经常需要占用大量内存,32G的内存不够用,需要64G。而现在轻薄本里提供64G选项的,主流的选择只有可以自己加内存的ThinkPad T14p,但是T14p的CPU和GPU性能都在轻薄本中中规中矩,且被11代酷睿折磨了5年的我,现在已经变成了十足的I黑😅。而AMD只有Max+系列的设备有搭载64G及以上内存的产品,且当前只有华硕幻X和战99Ultra(在国外称ZBook Ultra G1a)这两款。前者平板形态虽然非常帅,但是在非桌面场景下使用体验较差,所以最终选择了后者。主要配置如下:

配置 配置
CPU AMD Ryzen AI Max+ 395 16C32T Zen5
内存 64G LPDDR5 8000MT 4通道
硬盘 SK Hynix PC801 2TB PCIe 4
显卡 Radeon 8060S 40CU RDNA3.5
显示器 2880x1800 144Hz OLED带触屏
重量 ~1.6kg
电池 74Wh

16核32线程的Zen5加40CU的RDNA 3.5居然能装在14寸的笔记本上,在这颗处理器真正面世之前简直是不可想象的。虽然用脚趾头想都知道这么小尺寸的笔记本不可能可以发挥这颗处理器的全部性能,但是,规模大了,提高多少功耗就能提高多少性能,而实测下来这台笔记本的功耗在14寸的笔记本中也不低,所以在所有同样的尺寸和功耗等级的笔记本中,这颗CPU的性能应该也是最强的。而四通道内存甚至在MSDT平台上花多少钱都体验不到。

由于价格原因,大多数人应该没有机会能用到这样的笔记本,网上也少有这款设备真实的使用体验的评测。到现在也算用了这个处理器的笔记本3周了,可以说说体验。

设备

性能和功耗

买这台笔记本就是为了性能。这台笔记本的性能确实很强。

插电的状态下CPU-Z可以跑760/12300左右。这段时间内CPU功耗最高80W,虽然不能一直持续,但是长时间跑仍然可以稳定70W。14寸笔记本能稳定70W的据我所知还是比较少的,再加上这个CPU恐怖的规模,基本可以确定这颗CPU的性能应该就是这个尺寸笔记本的顶尖了。

插电性能

离电状态下CPU-Z的结果是326/6892,正常功耗在35W,长时间功耗在25W左右,这个功耗在离电状态下也比较正常,并且可以看出,CPU在低功耗下倾向于重点使用一个CCD,这也是控制功耗的一个做法。

离电性能

两个CCD的使用率分布

打游戏的话,最近只玩了三角洲,大战场下2880*1800分辨率超高画质有100帧左右。

内存性能测试结果这里也放一下。考虑到是LPDDR5内存,延迟较高,但是读写性能确实体现出了4通道内存的水平。

内存性能

续航

影响笔记本续航的因素有很多,并且随着驱动的更新,结果也会变化,这里只说一下我这段时间的使用情况。在正常的主要使用微信和浏览器的办公场景下,CPU基本上在6-15W范围波动,整机功耗12-20W。由于电池是74Wh,所以整机续航在5小时左右。

电池供电下的典型功耗

这个续航表现只能说中规中矩。主要原因我认为还是空载功耗仍然太高。上面这个图里,虽然核心只占了1.41W,但是整个CPU居然消耗了7.75W,和Lunar Lake以及苹果M系列处理器的1W以下的外围功耗比起来,这个功耗实在是过于离谱了。

充电

万万没想到,这台电脑的充电情况比我遇到过的所有设备都要复杂。

PD 100W以下不可用

首先,这台电脑的充电器是C口的,没有问题。但是,这台电脑并不支持最常见的PD 65W充电! 插入PD 65W充电器后直接不充电,而不是像一些联想笔记本一样慢速充电。

插入65W充电器后系统提示

研究后发现,这台设备的包装盒上明确写着仅支持100W以上的PD充电器。

包装盒上充电功率的标识

但是具体测试下来,设备支持联想T34WD-40(京东)上的96W Type-C供电,但是系统会提示低功耗充电器,且CPU功耗被限制在了45W。在这个功耗限制下,CPU-Z全核最高频率2.8Ghz,跑分9500左右,比未限制状态下的12300低了22%,还是下降得比较严重的。并且,现在市面上,除了DELL有两款支持PD 140W给笔记本供电的显示器外,其他显示器都最高只支持90W。所以一线通,这个我本来已经习以为常的办公解决方案,现在也不得不放弃了,在工作时必须再插一个充电器,不过也还好,只是多一根充电器线的事。

96W供电的提示

高功率PD充电器兼容性问题

设备自带的充电器是支持PD 140W的大板砖,除了重,没什么问题。

自带充电器

从上可以看到,其支持28V 5A也就是PD标准的140W的充电器。了解了一下,目前市面上真正在使用PD标准进行高功率充电器笔记本,似乎也就只有MBP一家了。没想到苹果的充电在手机上扭扭捏捏,好不容易搞个C口还和很多iPhone 15出现之前的老C口设备存在兼容问题,反而在笔记本上如何激进地拥抱标准。

可能是覆盖的产品太少,支持这个标准的充电器并不多,并且同样是声称支持MBP和这个标准的充电器,在这台电脑上仍然存在兼容性问题。

酷态科的15号充电器是140W充电器里价格最便宜的(179不带线),支持小米快充,也声称支持MBP,但是实际使用中并不兼容这台电脑,插入电脑后,系统充电图标显示一下,HP的软件弹出如下的提示并且系统稍微卡一下,然后马上断开,以此循环。为了验证是不是线的问题,我还快速购入了酷态科的支持240W的6A线,但是问题依旧。

酷态科

插入充电器后的提示

没有办法,只能换了Anker的充电器。虽然Anker的产品相比起来都更贵,但是考虑到Anker牌子和销量更大,兼容性应该更好,于是花更高的价格(279)购入了Anker的支持140W的充电器。而这个充电器配上自带的电源线一切正常,没有任何问题,但是要是配上之前提到的酷态科的充电线也会有时候会弹出上面的提示并且系统会卡一下(因为电池供电会影响处理器和其他硬件的设置)。

Anker

这个充电器带一个屏幕,可以实时显示系统使用的功耗。在CPU-Z跑分、CPU功耗在70W左右时候,整机功耗为120W+,100W的PD确实不能发挥整台机器的所有能力。

Anker

内存和显存共享

搭载这块CPU的设备的宣传材料都是本地跑AI大模型。内存和显存共享芯片确实是一个大卖点。

宣传语

具体来说,这个电脑支持在BIOS里将固定量的内存分配给显存。这样分配给显存的内存就不可以再作为系统的内存使用了。这个功能似乎很多AMD核显本都有。

在BIOS里分配内存给显存

如上图所示,我的64G版本,可以手动选择将512MB、4GB、8GB、16GB、32GB或48GB的内存分配给显存。如果分配8G,于是日常就只有55G的内存可用了。

分配显存后的任务管理器

但是,这个分配量只是GPU独享的,剩下的内存是真正的共享内存,GPU同样可以支配。根据之前看到的一份材料,GPU可以动态支配剩下的其中一半的容量。也就是说,如果给GPU独享分配8G,那么GPU实际能用的是8 + (64-8)/2 = 35.5 GB。其实对于大多数使用情况来说也完全够用了。

考虑到AMD羸弱的AI生态,我买这台电脑的唯一考虑其实是变态的CPU性能和大内存,所以我没有必要给GPU分配独享的存储,于是最后就选择了512MB给独显独享。这样配置下来,GPU实际上最大也可以用32GB左右的显存,打打游戏也够用了。

模具、外围配置等

这台设备的模具及外围配置同样一般。一句话总结:CPU以外就是个6000块左右设备的水平。

厚度和重量:最厚处18.5mm,重量1.6kg左右,和MBP一个水平,和轻薄不沾边(考虑到我之前的笔记本是980g的Yoga Carbon,这落差就更大了)

屏幕:一块2880x1800 144Hz的OLED屏幕,但是最高亮度只有400nit,且是镜面屏、触控层存在网格纹,甚至似乎还是PWM调光。

触控板:大小、滑动和按键手感还可以,但是并非压感触控

键盘:中规中矩的笔记本键盘,和ThinkPad等不可比。

另外还有一些小问题,例如

  • 有的时候突然无法调整屏幕亮度,只能重启才能解决 亮度
  • 无法连接到华为路由X1 Pro的Wi-Fi 7热点,只能连接到Wi-Fi 5的兼容模式

总结

综上,虽然这台笔记本性能很强,但是我还是不推荐这台笔记本给绝大多数人。

  • 对于需要64G内存的,ThinkPad T14p除了CPU之外,完全满足需求
  • 对于需要打游戏的,20CU的Radeon 8060S在2K级别分辨率下可用,但是A卡仍然存在一定兼容性问题,且没有DLSS等老黄黑科技加持,游戏体验仍然不如NVIDIA独显的。同样的价格已经可以买幻14这类搭载NVIDIA独显的游戏本了
  • 相当于笔记本,AMD或者OEM似乎更愿意把395这块CPU放在一体机上,我非常同意。395非常适合作为一个AI开发者或者小型团队的移动AI推理工作站(考虑到AMD的软件生态,可能也就只有推理容器做了),而不是放在一个笔记本上作为一个正常的CPU。目前市面上搭载395+128G内存的一体机价格在13000-15000,且性能释放在100W以上,完全没有必要花更高的价格买一台笔记本(战99Ultra 395+128G的配置国补后仍然需要24000)

这种小众机器看着非常诱人,但是价格昂贵,和外围设备兼容性存疑,并且遇到问题(例如充电器)都无法在网上找到解决方案,厂商的后续支持(例如驱动更新等)也一定会比较有限。只有像我这样什么都要的且愿意折腾的,才可以建议试试这台机器😊。

这台机器在史无前例地在14寸的机器下提供了16C32T CPU+64G/128G四通道内存的配置。虽然表现很亮眼,但是最终市场上设备种类少,价格贵,销量也低,后续AMD还会不会出下一代呢?

Node是并发性能的绊脚石吗?测试Express服务器的基准并发能力

2025-03-08 08:47:00

问题发现

最近在一个项目中,我遇到了一个使用Node.js编写的请求转发服务的性能瓶颈问题。这个服务的主要工作看似非常简单:获取用户的请求,将请求体(body)转发到后端的服务器,然后将服务器的响应原样返回给客户端。

然而,在进行压力测试时,我们发现当并发请求达到约2000时,系统表现出了明显的性能问题:

  1. 大约6%的请求出现错误
  2. 服务器资源利用率极不平衡 - 只有一个CPU核心达到了100%利用率,而其他核心几乎处于闲置状态

大家都说Node.js的IO性能并不算差。这个现象引发了我的思考: 是什么限制了Node.js在这种场景下的性能表现? 一个看似简单的请求转发工作,为何无法充分利用多核资源?

带着这些疑问,我决定对Node.js代理服务的基准性能进行一次深入研究。我想了解在没有任何特殊优化的情况下,一个标准的Express服务究竟能够处理多少并发请求。这将帮助我确定问题是否出在Node.js本身的并发处理能力上,并在之后遇到类似性能问题或技术选项的时候,对Node本身所能达到的极限能力有个心理预期。

实验设计

为了进行这项研究,我采取了以下步骤:

  1. 编写两个简单的项目:

    • 一个模拟AI后端服务的Express服务器
    • 一个标准的Express代理服务,负责转发请求到模拟的AI后端
  2. 使用wrk作为性能测试工具,这是一个常用的HTTP基准测试工具,能够产生大量并发连接来测试服务器性能

  3. 在相同硬件条件下,测试不同并发级别下的性能表现,包括:

    • 请求成功率、超时率
    • 响应时间
    • 各个核心的CPU利用率

实验实现

模拟后端服务

这个项目是一个简单的Express服务器,它接收POST请求,并返回一个模拟的AI响应。

为了模拟真实响应,这个服务器返回结果前可能会延迟一段时间。我同样会测试延迟不同的时间会对代理服务的性能表现的影响。

代理服务

代理服务同样使用Express实现,它的核心功能是:

  1. 接收来自客户端的请求
  2. 提取请求中的payload
  3. 将payload转发到后端AI服务
  4. 等待后端响应
  5. 将后端响应传回给客户端

这个服务保持了最小化的实现,没有添加额外的错误处理、负载均衡或缓存等优化措施,以便我能够测试Node.js的基准性能。

测试结果与分析

测试运行于WSL2,CPU为5900X 12C24T @ 4.5 Ghz,Node版本22.14.0。

后端服务直接返回

使用6个线程和不同的连接数,超时时间设置为5s,使用wrk对两个服务分别进行压力测试。其中,运行在5001端口的是模拟后端服务,5000是代理服务。

Server Connections Requests/sec Avg Latency Max Latency Total Requests Timeouts Timeout % Total Errors Error %
5001 50 9776.19 6.03ms 291.00ms 97839 0 0.00% 0 0.00%
5001 100 9294.12 12.84ms 537.33ms 93006 0 0.00% 0 0.00%
5001 150 9322.45 31.57ms 1.31s 93276 0 0.00% 0 0.00%
5001 200 8688.89 63.29ms 2.14s 86951 0 0.00% 0 0.00%
5001 500 8769.33 163.54ms 4.99s 87741 121 0.14% 121 0.14%
5001 1000 8200.58 98.60ms 4.96s 82284 67 0.08% 67 0.08%
5001 2000 8808.86 102.43ms 4.95s 88480 54 0.06% 54 0.06%
5001 5000 7769.21 248.05ms 314.09ms 78333 25 0.03% 1134 1.45%
5001 10000 7531.77 453.61ms 592.39ms 76076 13 0.02% 6176 8.12%
5001 20000 6601.98 414.19ms 582.31ms 66423 15 0.02% 15917 23.96%
5000 50 2673.49 74.76ms 2.34s 26763 0 0.00% 0 0.00%
5000 100 2884.08 40.05ms 909.96ms 28860 0 0.00% 0 0.00%
5000 150 2729.84 94.20ms 2.16s 27322 0 0.00% 0 0.00%
5000 200 2586.36 176.31ms 3.61s 25887 0 0.00% 0 0.00%
5000 500 2375.25 192.97ms 4.96s 23767 70 0.29% 70 0.29%
5000 1000 2454.10 139.51ms 5.00s 24629 90 0.37% 90 0.37%
5000 2000 2449.30 326.00ms 4.85s 24597 33 0.13% 33 0.13%
5000 5000 1786.15 326.11ms 5.00s 18038 476 2.64% 1768 9.80%
5000 10000 2016.64 78.55ms 3.78s 20313 10 0.05% 6306 31.04%
5000 20000 1398.34 3.40ms 639.14ms 14072 0 0.00% 16275 115.66%

数据比较多,值得关注的结论如下:

对于后端服务:

  • 200-500连接数开始已经出现了5s内无法完成的超时请求
  • 2000-5000连接数开始出现并非超时的错误,说明此时node本身已经无法接受更多请求
  • 连接数打到5000后,错误率开始指数上升

对于代理服务:

  • 几乎所有指标都大幅差于后端服务,在50连接时请求数就已经只有后端服务的1/3
  • 2000连接数开始错误率即开始指数上升
  • 把平均延迟和后台服务的平均延迟作差,可以发现代理本身逻辑执行在1.5-2s附近

CPU使用

在所有实验中,我还记录了CPU各个核心的使用率,下面是测试后端、2000个连接数时其中一秒的CPU使用率,可以看到,只有一个核心(2)很忙,其他核心没有被充分利用。其他所有数据都具有类似的情况。

10:51:38 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
10:51:39 AM  all    5.93    0.00    1.52    0.00    0.00    4.97    0.00    0.00    0.00   87.58
10:51:39 AM    0    1.75    0.00    0.88    0.00    0.00   11.40    0.00    0.00    0.00   85.96
10:51:39 AM    1    0.00    0.00    1.00    0.00    0.00    1.00    0.00    0.00    0.00   98.00
10:51:39 AM    2   84.00    0.00    6.00    0.00    0.00    0.00    0.00    0.00    0.00   10.00
10:51:39 AM    3    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
10:51:39 AM    4   11.00    0.00    3.00    0.00    0.00    0.00    0.00    0.00    0.00   86.00
10:51:39 AM    5   18.18    0.00    3.03    0.00    0.00    0.00    0.00    0.00    0.00   78.79
10:51:39 AM    6    1.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00   98.00
10:51:39 AM    7    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
10:51:39 AM    8    4.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00   95.00
10:51:39 AM    9    2.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   98.00
10:51:39 AM   10    2.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   98.00
10:51:39 AM   11    0.00    0.00    1.98    0.00    0.00    0.00    0.00    0.00    0.00   98.02
10:51:39 AM   12    3.96    0.00    4.95    0.00    0.00    0.00    0.00    0.00    0.00   91.09
10:51:39 AM   13    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
10:51:39 AM   14    4.50    0.00    3.60    0.00    0.00   10.81    0.00    0.00    0.00   81.08
10:51:39 AM   15    0.00    0.00    0.00    0.00    0.00    2.04    0.00    0.00    0.00   97.96
10:51:39 AM   16    2.65    0.00    0.88    0.00    0.00   15.93    0.00    0.00    0.00   80.53
10:51:39 AM   17    0.92    0.00    1.83    0.00    0.00   12.84    0.00    0.00    0.00   84.40
10:51:39 AM   18    2.44    0.00    4.07    0.00    0.00   19.51    0.00    0.00    0.00   73.98
10:51:39 AM   19    0.00    0.00    2.75    0.00    0.00   13.76    0.00    0.00    0.00   83.49
10:51:39 AM   20    4.63    0.00    0.00    0.00    0.00   11.11    0.00    0.00    0.00   84.26
10:51:39 AM   21    2.73    0.00    0.00    0.00    0.00   11.82    0.00    0.00    0.00   85.45
10:51:39 AM   22    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
10:51:39 AM   23    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00

较慢的后端服务、打日志的差别

在上述实验中,后端服务收到请求就直接返回。但是实际上后端服务可能需要一定时间处理。打印日志也是Node服务常见的实践。这两个场景到底对资源消耗有多大呢?

为了更直观地对比不同场景下的性能表现,多设计两个场景

  1. 后端等到500ms后才返回结果
  2. 后端、代理端每收到请求和响应就将请求和响应的URL打印出来(console.log

我整理了以下对比表格,重点关注平均延迟(Avg Latency)、超时率(Timeout %)和错误率(Error %)这三个关键指标:

连接数 服务器 直接返回-延迟 延迟-延迟 输出日志-延迟 直接返回-超时率 延迟-超时率 输出日志-超时率 直接返回-错误率 延迟-错误率 输出日志-错误率
50 后端 6.03ms 503.92ms 9.17ms 0.00% 0.00% 0.00% 0.00% 0.00% 0.00%
500 后端 163.54ms 506.11ms 132.43ms 0.14% 0.00% 0.13% 0.14% 0.00% 0.13%
2000 后端 102.43ms 533.43ms 105.53ms 0.06% 0.00% 0.08% 0.06% 0.00% 0.15%
5000 后端 248.05ms 529.92ms 358.23ms 0.03% 0.00% 0.05% 1.45% 7.73% 2.23%
10000 后端 453.61ms 607.15ms 641.06ms 0.02% 0.00% 0.00% 8.12% 9.89% 12.64%
20000 后端 414.19ms 610.10ms 375.80ms 0.02% 0.00% 0.00% 23.96% 30.43% 35.20%
50 代理 74.76ms 519.05ms 54.27ms 0.00% 0.00% 0.00% 0.00% 0.00% 0.00%
500 代理 192.97ms 717.28ms 208.93ms 0.29% 0.00% 0.29% 0.29% 0.00% 0.29%
2000 代理 326.00ms 726.51ms 417.52ms 0.13% 2.03% 0.21% 0.13% 2.03% 0.21%
5000 代理 326.11ms 892.77ms 434.87ms 2.64% 1.35% 2.87% 9.80% 13.92% 10.33%
10000 代理 78.55ms 788.52ms 89.68ms 0.05% 2.90% 0.01% 31.04% 36.76% 36.39%
20000 代理 3.40ms 777.70ms 94.90ms 0.00% 0.00% 0.00% 115.66% 232.21% 107.78%

从这个对比表格中,我们可以得出几个重要观察:

  1. 延迟500ms的影响:当后端服务增加500ms延迟后,整体延迟有增加,连接数越多,平均延迟增加越少,但是增加的延迟仍然会使得错误率增加

  2. 超时情况分析:在大多数连接数下,超时率都相对较低;但在代理服务的中等连接数(2000-5000)场景下,超时率明显上升,特别是在延迟返回的测试中,显示出代理服务在处理较长延迟请求时的瓶颈

  3. 日志输出的影响:与直接返回相比,增加日志输出确实会增加延迟,但影响不是特别显著。在低并发情况下(50-500连接),日志对后端服务的影响较小;但在高并发时(10000+连接),日志输出会明显增加系统负担

  4. 错误率增长点:无论哪种场景,代理服务的错误率普遍高于后端服务,且在5000连接数左右开始出现明显的错误率上升

  5. 极端高并发下的异常:在20000连接的极端情况下,所有配置都表现出较高的错误率,但代理服务的延迟反而下降,这可能是因为大量请求被直接拒绝,导致成功请求的平均延迟降低

Go

为了对比,我又准备了用Go使用标准库net/http编写的相同功能的两个程序,并在后端500ms延迟、不打log的情况下,测出go的成绩如下(未列出的连接数并未发生错误):

Server Connections Requests/sec Avg Latency Max Latency Total Requests Timeouts Timeout % Total Errors Error %
5001 5000 7310.92 501.39ms 516.91ms 73728 0 0.00% 902 1.22%
5001 10000 7060.75 501.72ms 517.20ms 71154 0 0.00% 5900 8.29%
5001 20000 6493.01 501.33ms 512.36ms 65536 0 0.00% 15902 24.26%
5000 5000 5910.59 636.54ms 3.46s 59611 0 0.00% 903 1.51%
5000 10000 5441.54 657.59ms 1.25s 54953 0 0.00% 5900 10.74%
5000 20000 4857.47 663.12ms 2.11s 48912 0 0.00% 15902 32.51%

二者的差距还是在预期的,go从来没有发生过超时,整体延迟、错误率数据也比node好很多。如在5000个连接下,代理程序出现1.51%的错误,node版本出现9.08%的错误,差距在6倍左右。但是需要注意的是,go可以利用全部CPU核心,而node的js线程只能利用一个核心,如果启动多个node并进行负载均衡,最终结果不一定有很大的差别。

结论

通过这些简单数据,我们发现

  • Node本身的单线程模型无法利用所有CPU的能力,即使在纯网络IO任务中也可能成为性能瓶颈
  • 在这次实验中,express在2000连接数是个门槛,在此之上,超时率、错误率会迅速增加
    • 并且,我的测试机器是消费级CPU,而一般服务器CPU并不能达到如此的单核性能,所以在生产环境中的性能表现会更差

要想解决这个问题,在代码中做出一定的优化,例如减少日志打印、简化Node中的逻辑等,也会有一定的效果。如果优化代码的效果不佳,唯一的办法是运行多个node进程,可以考虑的方法主要是启动多个node服务并增加负载均衡,或者使用node cluster让node可以启动多个worker process。

本实验中的代码和结果均在 https://github.com/ddadaal/node-express-concurrency-baseline-test 中可用。

Acknowledgements

整个测试项目、测试脚本甚至本篇文章基本都是直接使用Copilot + Claude 3.7 Sonnet模型生成的,不得不说,让AI生成大框架、自己再来完善细节的做法确实能提高不少效率。这种实验的大多数工作实际上是框架代码,代码本身逻辑简单,但是需要使用大量API、编写繁琐的测试逻辑、数据分析以及做表,手写非常耗费精力,让AI来做这些繁琐的工作实在是再合适不过了。写文章也可以让AI帮忙做,我之前写篇文章至少需要花一整天,这一次居然一个上午就搞定了。

哦,上面这一句话不是AI写的😀

用大模型总结文章:效果很好,但是玄学

2025-02-14 23:54:00

Azure AI Language Service的结果太差了

去年我给我的文章增加了AI文章总结功能。在介绍此功能的文章,我提到当时这个功能是通过Azure AI Language Service Text Summarization的功能实现的。

当时我已经发现,这个功能在英文文章上效果还行,但是在中文文章上就基本不可用。

比如,上一篇文章2024年总结的总结结果是:

本文讲述了作者在毕业后的第一年,通过深入体验现有生活,旅游,搬家,工作和生活。

这写的是啥?

这是人话吗?且不说用的英文逗号,前两个分句看着还行,后面就变成关键词的叠加,完全没有概括意思。

一年过去了,DeepSeek全球爆火,而我又想起了这个问题,又重新尝试了用原有的方案生成概括,结果差不多,仍然不可用。

拜托,随便一个大模型都应该比这个好吧!

去研究了一下此功能的文档,发现文档上完全没有这个功能的任何细节信息,没说用的什么模型、什么Prompt,也不让用户自己定义模型。一年过去了,功能效果丝毫没有改进,似乎像是被放弃了。说得通,毕竟是微软。

用Azure AI部署的DeepSeek R1总结文章

实话说,我很少直接和大模型聊天。我使用AI基本只有让Copilot回答编程问题以及生成代码,在编程场景之外我基本完全不用AI,所以也一直不知道怎么把AI应用到我自己的工作和生活流中。我的工作也和AI毫无关系,即使公司策略是All in AI,但是我组仍然和AI似乎扯不上边。

而此时,需求终于来了,为何不让大模型帮我总结文章?

Azure AI是一个微软做的Model as a service平台,可以直接在上面部署、使用、微调模型,不需要自己管理基础设施。DeepSeek R1模型发布后没几天,Azure AI可以直接就支持了部署(公告),甚至没有价格表,意思是:它是免费的?

我立刻去Azure AI上注册了Project,部署了DeepSeek R1。

用Azure AI部署模型非常方便:

  1. 注册好Project
  2. 进入模型市场,选择DeepSeek R1,填一个Deployment Name,部署
  3. 然后拿着Azure AI Endpoint, API Key以及这个Deployment Name,根据文档安装调用TS SDK
  4. 设计一个Prompt
  5. 调用SDK

点点就能部署模型

Prompt我随便想了一个:

Summarize the article in the next message in language ${languageCode} in 100 words. Return the result in plain text format, without any other information.

其中包含三个消息:

  1. 语言是${languageCode},这是文章的语言参数(cn, en),这样文章的总结和文章本身的语言一致
  2. 要求返回纯文本信息,不包含markdown
  3. 100字左右

另外,R1模型总是会返回思考过程,思考过程用<think>标签包裹,所以还需要在结果中把<think>中去除。

然后我立刻把2024年总结扔给AI,很快就拿到了结果:

作者回顾毕业一年后生活,探讨如何在最佳年龄充分体验当下。通过密集旅行与亲友刷新地图边界,感受陪伴的意义;开启独居生活后在郊区保租房打造个人空间,享受烹饪与自由。工作方面身处技术运维"小而美"团队,虽遇职业发展隐忧但珍惜当前性价比高的稳定状态。面对年龄增长带来的体能下降与生活抉择困惑,既珍视现有平衡又焦虑是否该打破舒适区。最终秉持认同感驱动原则,既保持现状又在游戏启发中思考:是继续深耕现有生活,还是用黄金年龄冒险转型,答案留待明年揭晓。

哇!这效果真不错啊,句子比我自己写得工整多了!

于是,我将脚本应用到博客中的所有文章,基本上所有文章都获得了极好的效果。这里给出几个例子:

文章 原总结 现总结
在西雅图,给生活换个环境 本文描述了作者在参加微软的Aspire Start Strong+活动时,感受到了全新的生活环境和社交元素。 作者参与微软组织的Aspire Start Strong+活动,赴美体验全新生活节奏以缓解职场单调感。西雅图市区高楼林立却人流稀少,郊区以分散式城市结构为主,无车出行困难。活动中高强度社交贯穿全程,跨文化交流时语言障碍明显,英语听说能力面临实战考验。与全球同龄校招生互动后,作者反思环境对人际关系的影响:校园阶段共同目标易建立联结,职场后各自生活轨迹差异导致社交需求转变。短暂六天打破常规,接触多元文化,更深刻思考个人追求与环境的关系。
从调库到翻源代码:给wakapi增加SQL Server支持 本文作者在上一篇文章中提到了如何为博客增加点击量监测,并部署到Azure。 后来,同学推荐了wakapi项目,重新实现了wakatime的后端API。 作者发现wakapi并没有原生支持SQL Server,但使用了gorm作为数据库访问框架。 作者通过重用Dialector的逻辑,为关键词加上引号,把同一个go类型在不同的数据库中映射为不同的列类型,以及使用merge into语句来模拟upsert的行为。 他认为go非常explicit,虽然他不喜欢它,但它非常简单。 解决这些问题后,PR顺利合并进了主分支。 作者在尝试将Wakapi项目迁移至SQL Server时,遇到一系列数据库适配问题。包括SQL语法差异、ORM框架配置、外键约束冲突及GORM库的Upsert功能缺陷。通过修改原生SQL语句、动态调整时间字段类型映射、重构外键关系、手动处理唯一索引冲突,最终解决兼容性问题并成功合并代码。此次实践深入了解了SQL Server特性与GORM内部机制,验证了通过实际项目攻坚学习技术的有效性。
A Kotlin DI Framework in 50 Lines and Thoughts on Kotlin The document discusses the challenges and benefits of using a Dependency Injection (DI) framework in a Java project. It highlights the two main options for dependency management: introducing a full-blown DI framework or using traditional object instantiation or simple factory pattern, which can be time-consuming and cumbersome. The author uses the example of a simple Java project where the interface and implementation class pattern was used to decouple the interface and implementation, but it also introduced complexity. The document suggests using delegation and classpath scan capability to achieve minimal dependencies and extra code, and provides a code example to help understand the process. The article discusses choosing dependency injection (DI) for small projects, comparing full DI frameworks (verbose) versus factory patterns (clumsy). The author developed a lightweight DI solution using Kotlin’s delegation and classgraph for scanning. Annotations (@Service, @ServiceImpl) mark interfaces and implementations, while a di() function delegates dependency resolution, enabling singleton injection with minimal code. Benefits include simplicity, circular dependency support, and dynamic resolution, though limitations include no init block usage and lack of advanced features. The author praises Kotlin’s modern features (null checks, lambdas) and how diverse programming paradigms expand problem-solving approaches, emphasizing tools’ influence on design thinking.

本地模型的效果比较玄学

本来这篇文章到这里就该结束了,可是写到第一段的时候,突然想到:

随便一个大模型都应该比这个好吧!

那……我本地跑一个呢?

我的台式机是3070,一搜得知这个显卡最大可以装DeepSeek R1 8B版本。于是赶紧打开许久没有打开的Ollama,拉下deepseek-r1:8b

ollama pull deepseek-r1:8b

Windows版本的Ollama会在本地11434端口启动Ollama的API(定义),而由于我们是用的JS,Ollama单独出了ollama-js SDK,用起来更简单。

我直接pnpm i -D ollama,学习了ollama的SDK的使用,直接把给完整版R1用的Prompt发给R1 8B,拿到以下结果:

这篇文章通过作者的个人经历和思考,探讨了在“最好的年龄”该如何度过这一主题。作者从20多岁进入巅峰年龄开始,经历了身体素质逐渐下降、工作环境变化以及面对各种选择的内心挣扎。\n\n### 主要内容总结:\n1. 身体与年龄的关系:作者承认随着年龄增长,身体素质逐渐不如从前,尤其是到了“下半场”,这可能对日常生活和工作产生影响。\n \n2. 工作环境与不确定性:虽然选择了一家外企,因为其稳定性和良好的发展机会,但半年后发现公司结构频繁调整,高层变动较大,这让他对未来充满担忧。\n\n3. 面对选择的内心挣扎:\n - 职业与生活的平衡:作者更倾向于保持现状,尤其是对稳定工作的认可和对外资企业组织结构和晋升路线的信任。\n - 物质与生活的影响:虽然对大城市有向往,但也清楚地认识到当前平淡的生活状态的珍贵,不愿为了追求新潮而放弃现有的优秀工作。\n\n4. 游戏中的价值观:通过《沙石镇时光》这款游戏,作者找到了认同感和热爱一件有意义的事的精神状态,这成为他生活中重要的支撑力量。\n\n### 总结:\n文章表达了作者在成熟与不稳定之间的平衡问题上缺乏明确答案,内心对现状的满意与对变化的恐惧之间的矛盾。尽管没有给出明确的选择建议,但通过个人经历和情感描写,揭示了在最佳年龄如何度过这一哲学性问题,鼓励读者反思自己的生活态度和价值观选择。\n\n文章语言流畅,情感真挚,通过对工作、生活和游戏的多角度描述,展现了作者内心的复杂性和对未来的不确定性。

嗯?这个模型怎么不听话?这个Prompt提到的三点(语言、字数、格式),字数和格式的要求根本没有满足!

Summarize the article in the next message in language ${languageCode} in 100 words. Return the result in plain text format, without any other information.

我试了很多次prompt,仍然没找到什么方法能够让它同时满足这三个需求。同一个提示词,有时候能生成不含markdown的文本,有时候生成又包含;文字字数的限制也是不一定生效。试了多次也没获得好的结果。

除了DeepSeek R1 8B,同时还试了llamafamily/llama3-chinese-8b-instruct,而这个模型的效果就好一些,但是生成多了也会出现不听话等问题。

本文讲述了一名25岁男青年在他的第二十年代度过的时间,他在这段时期里,选择了深入体验现有的生活,在旅游和工作方面都有所变化。他认为这个阶段是他的成长期,是他开始独立生活、选择自己喜欢的事物,并且接受不确定性的阶段。在文章中,他对未来充满了想法和担忧,但最终还是无法预测。

小模型的效果确实和大模型没法比,而不同小模型的精调不一致,效果也差别很大。

推理过程中GPU计算量不大,主要是占了很多的显存。看来接下来换个16G显存的显卡,应该就可以跑更高级的模型了。

运行推理过程的GPU占用

代码不是业务逻辑,而是大模型调用脚本

这次体验让我认识到一点,用LLM写功能的流程和传统的软件工程完全不同:

在传统软件中,业务逻辑总是精确地通过代码表示。不管需求多么复杂,这些需求总会在代码中出现。

而用LLM做的功能,不管写什么需求、是什么领域,写出来的代码是基本上都是一样的,代码本身只是个大模型API Caller,实际上的业务逻辑包含在大模型里,二者的接口是提示词。

如何编写提示词完全就是一个玄学,完全和精确、科学完全不沾边。不同的提示词就得出完全不一样的结果,甚至同一个Prompt得到的结果都不一定相同。

这种不确定性让我感觉有点不安。传统的软件即使再复杂,如果模块划分合理、测试充分,起码行为是可预测的,也总做或多或少的维护。而用大模型实现的功能,世界上没有人能直到它是怎么运行的,下次能不能用、有没有可能出什么问题,完全靠天决定。

不过AI确实解决了很多之前想都不敢想让机器解决的问题,很多问题也不需要那么精确。希望以后能找到更多大模型适用的使用场景。

2024年总结

2024-12-31 19:45:00

最好的年龄该如何度过?通过深入体验现有的生活

毕业后的第一年,没有物质压力,有大把时间可以自由支配。这最好的年龄该怎样度过? 我今年的答案:深入体验现有生活

旅游,和朋友和家人刷新地图的边界

随着之前的朋友毕业、上班,有了更多时间,以及个人工作生活的稳定,今年的旅行数量可能大于之前26年来的总和,三个国家,国内十余个城市和景点。根据航旅纵横的数据,只算飞机,今年的飞行里程甚至超越了99.13%的用户。要是有规划地选择航司,现在应该能飞个银卡吧。

航旅纵横数据

旅游照片

我不是一个非常喜欢旅游的人,如果只有一个人,外出旅游不会成为我的首要选择。正因为有了朋友和家人一起,我才能有机会和动力去打卡这些可能之前都没有听说过的地方。比旅游本身更重要的,是和朋友和家人在一起的这段经历。很感谢你们愿意花时间陪我去做我一个人不会去做的事情。

和朋友们欣赏演出的票根

搬家,开启独居生活

和大多数人一样,上大学前和家人合住,上大学后和舍友合住,而在今年8月,随着合住的大学同学搬走,我终于租下了一个一室一厅的公寓,第一次开始独居生活。

我的“第一套房子”是一个公司附近的保租房公寓。好处很明显:离公司比较近(电动车10分钟),楼体和装修新,空间勉强够用,各个功能区分割比较现代和合理(甚至是三分离的卫生间),且也没有遇到太多质量问题。

但更重要的是,没有其他选择了!公司地处偏远,附近几乎全是老破小楼梯房,电梯房本来就寥寥无几,而离地铁和公司近的房子只有几栋10年前的动迁房,而实地看房的第一印象就是廉价的装修:本来就只是为了出租而进行的装修,在10年后更加显现出岁月的痕迹,租金却也没比保租房公寓便宜多少。

于是也不用犹豫了,很快定下合同,还没入住的时候我就迫不及待地购入了升降桌,在家人的帮助下,将这个可能会是待的时间最多的地方好好打造了一番,还正好蹭上手机号所在的运营商的活动,拉上了18块一个月500M的宽带,开始美美地独享这个小窝。

客厅(工作室)以及升降桌

由于公寓是住宅标准,所以有正常的厨房和煤气。一个人住,也不用拘泥于吃饭的形式:想吃火锅却懒得买电火锅,也可以直接凑在灶台前吃。

涮肉

为了解锁更多菜谱,我还买入了一个电压力锅,平时可以当快速的电饭锅,当想做需要长时间炖煮的菜品,如烧牛腩、焗鸡、梅菜烧肉时,因为锅可以产生压力,所以这些菜品都可以用一小时左右的时间完成,操作也非常方便。

焗全鸡

这次搬家,算是达成了独立生活的第一个小目标。接下来又追求什么呢?

公司有非常宽松的在家工作的政策,越来越老油条的我去公司的次数越来越少。而只要进城,不管具体去哪儿,甚至都得先花40分钟才能到城市边缘。即使不进城,当我在外完成每天8000步,差不多6-7km的散步任务时,路线上只有老破小、厂房和大货车。

阳台外景色,楼下是菜地,对岸是厂房

突然有一天想通了:既然不用每天通勤,为何不进城呢?公寓的单位租金已经100块/平米,接近中外环的楼梯房,为什么不再加点钱,去体验真正的大城市生活?

下列打油诗来自这个知乎回答,我觉得不仅是设备,任何选择都适用此原理。

“顶配论”

明年的7、8月又将迎来搬家,我已经开始期待下一个房子,以及真正的住在大城市的体验了。

工作,难得的平衡,却隐含风险

今年是第一个完整工作的年份,也第一次享受了公司组织的福利和活动:

  • 6月份的西雅图之行是个意外之喜,花了公司3万块免费旅游,在西雅图给生活换了个环境
  • 每年例行的迪士尼票还正好在国庆大假前,人流量反常地少,以至于没有买速通还能一天玩完所有项目
  • 年底第一次接触滑雪,直接选择找教练练单板,2小时好歹学会了落叶飘,能正常滑下来了

工作中的小小福利

我对公司和小组的工作也有更深入的理解。我发现,我很幸运在一个“小而美”的组:

  • 产出为运维领域的技术产品,并不是在做黄赌毒、投机倒把、坑蒙拐骗的帮凶,符合我自己的价值观
  • 所用技术本身和市场并不过于脱节,且以功能而非技术分工,鼓励大家了解项目的各个方面,而非仅仅是个螺丝钉
  • 主要为企业用户,以稳定为重,节奏较慢
  • 同事友好,人员组成也比较稳定

再加上宽松和假期和在家工作政策,听起来是一个性价比高、适合享受生活的工作。

当然,有时候也会有一些担忧:

  • 无法和当前大热的AI扯上关系,发展空间受限
  • 客户本身的需求也不复杂,造成产品深度和难度不够
  • 想卷都卷不起来,很多时候有一拳打在棉花上的感觉,再加上经典的大公司病,很多时间和精力都无谓浪费掉了
  • 实习两年后我甚至仍然是全组最年轻的成员,没有新人加入

所谓相对稳定也是当年选择公司的一个重要原因。

  • 作为J人,有计划、有秩序的生活让我觉得安心
  • 大公司确实有比较成熟的组织结构、产品规划、工作流程以及晋升路线,作为小兵需要考虑和有能力左右的事情不多
  • 公司大多数同事都是要么毕业就来,要么在外面没干多长时间就过来并在此长时间工作

可是,

  • 仅今年上半年期间,认识的朋友所在的组有的被多次调整所在组织和业务,有的直接离开中国,像我组这样组织结构和业务没有变化的反而是少数
  • 也就在一年以前,公司因为在AI领域的大手笔动作,股价接连高升,彷佛50年的企业即将迎来第二春,结果今年上半年多次组织结构调整,几次财报均不达预期,明年初裁员的传言连父母都有所耳闻
  • 认识了Intel的被裁员的老哥,想起五年前第一次来到闵大荒这边看到Intel的大楼,还觉得Intel的统治地位牢不可破,谁能想到也就不到5年,Intel的市值已经不足当年濒临倒闭的AMD一半

外企总是被公认为稳定。可是,仅仅半年就能发生这么多变动,谁知道明天又会有什么惊喜?

该有所改变吗?

回答文章开头,最好的年龄该如何度过?,为什么会有这么一个问题?

今年有一次羽毛球局,和一个偶尔组的同事大姐姐混双打男双,打完后她对我说的第一句话是:“感觉你的身体素质不如之前”

混双打男双局里,混双方男队员的能力能很大程度影响表现,而能力主要又分技术和身体素质。我没有做技术和身体素质的专门训练,但我自认为和之前也没有什么区别。排除了这些因素,那为什么身体素质下降了?只能归结于年龄大了一岁。20多岁是人类的巅峰年龄,而我已经处于20多岁的下半场,身体素质已经开始走下坡路,时间已经不站在我的这边。

工作之后,生活逐渐稳定,可内心却充满了各种患得患失:

  • 想留在大城市,但又觉得付出了金钱和住房质量,却并没有充分利用到大城市独有的东西
  • 清晰地明白当前平淡的生活状态的珍贵,但有时候又想追求更年轻化、更有活力的生活
  • 舍不得这在各个方面都十分优秀的工作,但又认识到稳定的预期已不存在,变化不可避免

该维持现有状态,还是应该有所改变?

今年我也面临过一些选择,进行了或者仍然在进行很多心理斗争。在这些选择和心理斗争的过程中,心里没有决定身体没有行动二者互为因果,最终保持不变成为了今年对这个问题的答案。

今年我游戏时间最长的游戏是《沙石镇时光》。在这款游戏里,玩家扮演一个新的沙石镇工坊主,去到一个没落的城镇开始职业生涯,认识了大量的镇民、经历了各种各样的事,最终让这个没落的城镇重现辉煌。

steam资料

这游戏剧情平平无奇甚至有点幼稚,好在内容丰富,设定也比较接地气。玩完后,给我印象最深刻的反而是主线的精神状态:认同、热爱一件有意义的事,和一个团队一起去追求它

回想自本科以来,所有我真心投入了大量时间精力的事,都是因为我认可它。如果我不认可一件事,那么无论这件事能给我提供多大的物质回报,我都没有办法说服自己去做它。即使不得不去做,最终都放弃了。

我总是尝试做一个理性的人,可是这一点就是最大的不理性。很多选择,即使理性告诉我它就是最优解,即使我知道我的想法是有局限性的,可是我还是无法接受。

明年还会出现选择,且会更加急迫。最好的年龄正在慢慢消失,明年我会做出什么选择呢?是充分珍惜当前难得的生活工作状态,在已经拥有的基础上尝试改良?还是打破平衡,用最好的年龄去冒险?那就只能明年才知道了。