MoreRSS

site iconChen Junda修改

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

Inoreader Feedly Follow Feedbin Local Reader

Chen Junda的 RSS 预览

我是如何将自己逐出主流就业圈的

2026-09-15 21:39:00

在开始文章之前,我先下个定义,本文的“主流就业圈”指代大厂、头部初创这类需求量大、人员流动性高、认可度高,对求职者的要求、能提供的待遇标准趋同的工作。我并不认为主流就业圈是唯一的就业正解,但是对大多数人来说,这些工作就是较优解。

毕业两年后,我从一家大厂离开,加入了一家创业团队。如今,我甚至无法通过一些主流岗位的简历筛选。回望这段经历,我做错了哪些事情?

做远离趋势的工作

AI彻底改变了程序员工作的流程,也改变了整个就业市场,几乎已经不存在和AI无关的工作。但是,这个趋势是从什么时候开始的呢?

我毕业时,ChatGPT已经出现,但多数人仍把它看作更强的聊天机器人,很少有人认为它会成为新的生产力。后来,AI逐渐进入企业工作流,能够调用外部工具、编写和修改代码,也开始承担越来越完整的工作。在工具和基础设施领域,原本的部署和运维工作也逐渐加入了越来越多AI相关功能。

等到我真正意识到AI已经成为就业市场的必选项时,这个趋势已经非常明显了。

我没有看到这个趋势吗?

2024年起公司内部的AI工具和探索已经满天飞,AI已经接入多个关键的内部系统并开始发挥作用。我也尝试过用 AI 探索代码库、修复问题和辅助评审,尝试将AI在团队内部推广,获得过定期与+3大老板沟通AI应用的相关讨论。我甚至还获得过头部AI公司的面试机会。

但这个时候我的重心在哪儿呢?

我的主要精力放在内部工具链、合规改造和一个从实习的时候就开始推进、但是在发布前夕被砍掉的项目上。在私下的项目,我也把大量时间用于扩展机制、权限系统、项目管理,甚至想牺牲做业务功能的时间,把项目用另一种语言重写,却没有真正推动 AI 功能或解决用户最迫切的问题。

在那个时候我看来,这些工作都很重要:流程要合规,项目要上线,系统要考虑长期维护。我甚至没有好好准备面试,在这家头部 AI 公司的面试中败在了一些完全是常识的问题上。

我做了许多在当时看来对公司、对项目重要的工作。但这些工作没有一个和趋势有关,在现在的就业市场面前看来,几乎就等于无价值。

缺乏主线的工作内容

如果说在上一家公司工作时还能找到一条比较清晰的主线,回到创业团队后,我的工作内容就越来越“丰富”了。

  • 部署复杂?从零开始搭CI/CD流水线,制品仓库,开发全自动的部署方案
  • 团队人数较多,分工复杂?讨论、设计开发流程,明确分工,设置例会制度
  • 开发环境不够?找机器搭集群,设计网络方案,开发系统,让部署开发环境从人工+2天缩短到一键+半个小时
  • 客户来了稀奇古怪的需求?探索、设计方案,拆分模块,讨论功能细节
  • 团队要扩张,公司要融资?带实习生,参与招聘,做融资PPT,见投资人

总是有来自各个方面的需求,总是在解决问题。即使每个内部基建最终都成为了项目开发不可或缺的工具,质量我也认为已不弱于大多数公司,设计的流程也或多或少一直发挥着作用,但放在一起,连我自己都说不清楚我究竟擅长什么,也很难让下一位面试官判断我适合什么岗位。

缺乏真实问题和深度的工作经验

主流就业选项需要的是专精的人,并不需要什么都会的人。

所有人都可以在AI的帮助下快速学习一个全新的领域并解决一个从未见过的问题。我曾在几乎不了解某项底层技术的情况下接手一个虚拟化和GPU的相关项目,并在很短时间内借助AI完成了大量学习、改造和兼容工作。但这更像是快速完成任务,而不是在稳定、真实、大规模的问题中形成自己的专业深度。我可能暂时比其他人知道得更多,但所有人都可以借助 AI 很快追上来。

AI比人类更快、更好地完成绝大多数具体工作,也可以设计出比绝大多数人更全面的解决方案。解决问题本身已不值钱,而值钱的、有意义的是接触真实问题的机会。

  • 传统的软件工程的各类复杂方案,都是足够大的规模、足够高的性能需求里孵化的
  • 做训练、推理优化的工作,需要有更大规模的集群以及真实的训练和推理需求,才能找到现有的软件系统和架构在真实的负载中出现的问题,有了真正的问题才能真正地去学习对应的知识,去解决对应的问题
  • 做调度、集群管理的,同样需要真实规模的集群来实践,需要有真实的集群用户和工作负载,才知道需要开发什么功能、在哪些环境下会出问题
  • 甚至做管理工作,也需要一个真正的权力和责任,需要一个有权力奖惩别人、也会被上级和市场奖惩的环境

但是,

  • 手头项目的难点在于实现连客户都理不清楚的复杂逻辑,接入网上几乎没有公开资料的私有环境,在性能、高可用、并发这些方面的需求为0
  • 研究推理,能实际碰到的环境仅仅是V100、CentOS 7这种老硬件、老软件,甚至连公网都无法直接访问
  • 想做集群管理,然而自有的和客户的环境也就个位数、最多小两位数的机器数量,也没有非常大规模、复杂的功能需求
  • 甚至想做管理工作,结果不能设置激励,不能也无需扩张规模,换作我是员工,我也直接躺平

连真实环境中会遇到什么问题都不知道,怎么知道应学习哪些知识、应设计什么方案、应作出哪些取舍?闭门造车出来的方案,拍脑袋想出来的产品、制度,销售不知道有什么优点,客户用起来别扭,面试官不理解项目有哪些特点,同事不知道应该怎么做,除了自娱自乐,还有什么实际作用?

我虽然表面上可以把大多数工作归类为调度、集群管理或 DevOps,但是当真正寻找类似岗位时,有些岗位要求大规模集群经验,有些岗位虽然没有明确写出这些要求,却在投递后直接拒绝。其他相关方向又缺乏足够有说服力的深度履历。管理就更不用提了,谁会招一个没有完整成功项目经验的人来做真正的管理呢?

总是错位的希望

之前我一直没有考虑互联网公司,因为那时我以为自己已经知道想要什么。上一家公司同时满足了我当时的大多数追求:喜欢的城市、认可的公司、感兴趣的工作内容、WLB、社会认可、稳定,而它的劣势,也就是待遇和发展潜力,在那个时候的我看来没有那么重要,因为我以为未来总是会越来越好。

可是,后来这类工作的机会逐渐减少,裁员越来越频繁,升职和涨薪也越来越难。而那个时候,创业团队的业务看起来蒸蒸日上,融资似乎也近在眼前。这个时候,“想做出一番事业”这一想法的权重提升,而“社会认可”“城市”“社交”等因素的重要性被调低,我去了创业公司。

而随着创业公司的业务逐渐定型,我又重新开始追求“城市”“公司”和“社会认可”,也曾尝试进入一家头部 AI 公司。可此时,在情绪的主导下,虚假的“WLB”诱惑让我早早放弃了这个机会。当我最终认识到 AI 已经成为必选项,以往选择工作的标准已经过时,却发现已经不再有加入新时代的机会。

行动力是双刃剑

我认为,自己在认可的事情上一直有不错的行动力。求学和早期工作阶段,我曾把大量精力投入社团和项目,曾在保研材料提交DDL的时候相通并申请保研,也曾主动选择当时被认为缺乏前景的外企和创业团队。

但是这之后,我的“行动力”反而带来了不幸:

  • 我因为错误判断趋势,错过了更好的离开时机
  • 仅根据历史的趋势选择跳槽,在最应该拥抱趋势的时候沉迷熟悉但缺乏深度的工作内容
  • 曾短暂尝试一个正确但困难的机会,却因为工作节奏的不适应、以及一个终于有进展(但最终证明仍然只是一个虚幻的泡沫)的执念而快速下车,让整个行业的大门对我关闭

有人说做点什么总比什么都不做好。我不赞同。不行动也是一种行动。朝着正确的方向行动固然可以带来巨大的收益,但是如果行动错了呢?

上学的时候选错方向,还能通过实习或者升学争取机会和时间弥补;第一份工作找得不好,还能时间、有精力学习新知识、更换公司,其他人也愿意给机会。但是,当每个行为都被记录在案,每个变动都决定了接下来几年时间中自己的方向,每个选择需要几年的时间才能消减影响,人生还有多少机会去试错?

未来怎么办?

在该发展能力的时代选择了安逸,在该利用平台的时候放弃平台优势,在该沉淀能力的年纪浅尝辄止,在新热点发展最快的时代沉迷于过时的领域而白白浪费时间,在好不容易到手的正确机会上因妄想维持原有的生活方式狼狈逃避。

现在偶尔仍会遇到一些真正有价值的机会,例如主导真正的集群的建设和维护、推动公司走向正常化,或弥补过去没有准备好的面试。我也曾认真投入,享受做这些真正有意义的工作的过程,并努力补上过去缺失的知识,甚至都已经做到初见成效,可是这些事情总是悄悄走向了沉寂,这些机会最终还是没有落到我手里。是啊,有背景更匹配、经历更深入贴合、节奏更适应的选择,为什么会选我呢?

果然,我几乎不可能回到主流就业圈了。

文章到了最后,我也想提出几个“人生建议”。如果有读者可以从我的故事中学到点经验,避开点坑,那也算是没有浪费读者阅读这篇文章的宝贵的时间。

紧紧跟随、快速转向主流方向

每个阶段,总有一些主题在市场上有巨大的需求。13年后的移动开发,16年后的互联网,23年后的AI。方向主流意味着这些方向有着最多的需求、最快的发展潜力、进步空间和最大的当期和未来回报。作为求职者,应永远将时间和精力面向这些主流的方向,尽量少投入时间和精力在已经明显走下坡路的方向。一旦有机会,应尽快投入主流方向的工作,在时代的浪潮中占据一个自己的位置。

在 AI 时代、大学生越来越多也越来越强的情况下,时间越来越重要。现在每年毕业上千万的应届毕业生没有过往知识、技术和角色的包袱,有精力、有最新的知识和更广阔的眼界。任何一个需要人才的公司都会、也应该以应届生和年轻人为主要培养对象。如果不尽快给自己在新的发展中找个位置,等待着我们的只有被社会、被年轻人淘汰。

充分利用平台的力量

AI时代,问题最重要。移动互联网时代,草根还可能通过一些工作量少的创新逆袭大平台,而现在,没有优秀平台提供的挑战、资源和社交圈,我们甚至没有办法跟上主流方向的前沿。所以,应尽可能加入可以提供真正的挑战的平台,应尽可能利用好平台提供的资源以及身边同事的能力,尽快把解决最新、最实际的问题的经验写进自己的履历。即使没能真正接触这些核心的问题,平台本身也是履历的最好的背书。

做让未来拥有更多选择的选择

平均下来,每个人应该还有一段不会被社会淘汰的工作时间。在这段时间内,我们一定会做出多次改变,而且改变可能越来越频繁。为了让每次改变都尽可能有利于自己的发展,每次选择最重要的考虑因素,不是待遇或 WLB,而是如何让自己在未来拥有更多选择。

  • 如果年轻的时候就不996养成习惯,那未来还想996,身体会第一个直接罢工
  • 如果年轻的时候就不在大平台、不在核心圈子,那未来想进入大平台、核心圈子就需要更多的努力和运气
  • 如果年轻的时候就害怕搬家、害怕换圈子,那未来面对机会的时候顾虑只会更多
  • 如果年轻的时候不去拥抱新的发展趋势,那未来只会越来越迟钝

稳定只是幻影,按部就班、讲究经验的发展模式已经过时。只有不停地调整方向,才是真正的稳定;只有面向真正的问题,才能真正提高自己在社会竞争中的能力;只有不断淘汰自己的过去,才能让自己不被未来淘汰。

博客的发展3:将博客迁移至Azure并添加访问指标采集

2026-09-12 19:02:00

时隔三年的又一次博客更新

自从上一次将博客重写为一个静态网站后已经运行3年了。

这套架构非常简单:所有网站代码以及文章源码全部都在仓库里。要更新网站,直接改代码或者写文章,推送到github上,CI构建网站,把构建好的静态文件推到另一个发布为github pages的仓库ddadaal/ddadaal.me.github.io里,更新后的网站就可以访问了。

为什么要折腾了?

添加访问指标采集

由于之前是纯静态网站,完全没有办法记录动态的信息。之前的博客的评论数据都是存放在ddadaal/ddadaal.me.github.io的Issues里的。

在前AI时代,我也部署过一个简单的访问量采集服务,当时还写了个文章增加自制博客点击量统计。这篇文章单独写了一个Node.js服务,本博客中加了一些JS钩子。现在看来,把逻辑分在两个项目里还是太麻烦了。

而在现在AI时代,写一个完整的指标采集服务也是个非常简单的工作,于是一不做二不休,一口气把完整的指标采集都给实现了。

由于访问指标采集会涉及到隐私相关的信息,这里列出目前会采集的信息,并且,由于博客代码纯开源,后续有任何改动,都可以在代码中看出来:

  • 文章ID、访问总数、最后访问数据
  • 每次访问的事件 ID、时间、文章路径
  • 访客标识
  • 来源页面
  • 推广来源
  • IP 哈希
  • 浏览器、操作系统、设备类型
  • 是否机器人、状态码和耗时字段

以GDPR的标准来说,其中有的数据已经涉及到个人信息,如可以关联多次访问的IP哈希。但以后有问题再说吧。

利用Azure资源

微软一直在给微软员工发150刀每年的Azure订阅。我从2019年第一次在微软实习开始就开始领,并且竟然直到现在这个订阅还生效(感谢微软爸爸),我一直没有充分利用好这些资源。

这次趁着想要添加指标采集的功夫,就直接把整个网站+数据库全部搬迁到Azure。

第一次:AKS

第一次先选择了经典的全托管AKS+Azure SQL Server方案:

访问 -> [AKS] -> [Azure SQL Server]

整个网站代码本身放在AKS上:

  • AKS本身使用最低级的托管等级,免费
  • Node pool使用最便宜的Standard_D2as_v5虚拟机(2C8G),并打开Auto scale,允许1-5个节点自动伸缩
  • 使用Gateway API暴露网站服务到公网
  • 使用cert-manager自动签发TLS证书

AKS正常运行情况下用量其实挺小的:

❯ kubectl top nodes
NAME                                CPU(cores)   CPU(%)   MEMORY(bytes)   MEMORY(%)   
aks-agentpool-27587481-vmss000000   229m         12%      3669Mi          63%  

但是呢,AKS会默认装一些用处不大的功能在集群里,这些功能的Pod会占用集群的配置资源。AKS集群创建后,自己装的pod就占用了1300m的CPU,然而2C的集群总共只有1900m的CPU可以分配,也就是留给应用程序的只有600m。如果自己的应用设置了requests,那么很容易出现资源不够、触发scale up,花费更多钱。所以针对我们这些穷逼用户,最好还是关闭Azure的一些没那么常用的功能,包括

  • Managed Prometheus(关闭后,不能直接从Azure Portal看到各个应用的CPU、内存实际使用情况)
  • Image Cleaner(关闭后,AKS的未使用的镜像不会自动从机器中被清除)
  • Cilium(可以用原生的网络方案)

数据存放在Azure SQL Server中:

  • Azure SQL Server提供免费额度(官方文档),10W核心计算时间+32G的数据
  • Azure SQL Server本身是个SQL Server,用标准的SQL Server库就可以连接
  • 之前给wakapi做SQL Server适配的时候也熟悉了一些SQL Server,所以运维托管SQL Server也挺简单的

IP和流量对于国外的云来说几乎免费。这样下来,花钱的大头也就是Node pool的虚拟机,通过计算器估算一个月70/80刀,150刀勉强够用。

CI/CD

之前的CI/CD很简单:推送代码 -> 构建静态HTML/JS/CSS -> 推送到github pages仓库 -> github pages部署。

现在由于变成了一个完整的网站项目,所以CI/CD也需要较大的改动。推送代码后,GitHub Actions需要:

  1. 构建镜像
  2. 推送到ACR
  3. 登录AKS
  4. 触发deployment更新

整个过程中完全没有密码参与:

  • GitHub Actions通过OIDC联邦身份认证关联到一个Azure identity,可以直接以这个identity的身份登录Azure
    • 这个Identity可以Push到ACR(AcrPush role),可以获取AKS的kubeconfig(Azure Kubernetes Service Cluster User Role)
    • 所以整个CI/CD过程只需要标准的az CLI命令就可以全部完成。
  • AKS和ACR通过Managed Identity认证,直接可以从ACR拉取镜像

这样一套下来,我完全没有任何运维压力。数据库、AKS、扩缩容、TLS证书、部署全部不需要手动管,平时的运维也直接用标准的Kubernetes工具链即可,不太需要熟悉其他技术。

不得不说,Kubernetes生态真的是好东西,不仅是统一了软件的管理,还尽量把不同云服务商之间提供的服务也给统一了,大多数时候只需要和kubernetes本身打交道。之前我有一些服务放在Azure App service上的,其部署、运维都是一套单独的API,要使用就得重新学一整套概念、一整套新的UI以及新的CI/CD。

AKS太贵了,换VM

本以为这样就大功告成了,没想到隔了两天后再进Azure Portal发现余额少了20刀,并且发现博客的加载量没有增加,重启服务后发现时候就莫名其妙访问不了了。

经过一番研究后才发现,我之前博客的访问数据只是做了个读缓存,一旦有访问或者缓存失效就会写数据库,这样10万小时的CPU时间完全不够,用了2天就用完了。

于是为了恢复访问,我紧急打开了SQL付费,并优化了一下数据库访问设计,直接做了个内存缓存,所有读只从内存读。

这样解决了数据库vGPU的问题,但是带来了另一个问题:当长时间没有访问(也就没有数据库写入),数据库会自动暂停。然而数据库从暂停到启动的时间又大于30s,超过了我配置的数据库超时时间,于是读写数据库就又失败了。但如果不打开自动暂停的话,数据库一直运行就一直收CPU的费用。

再加上AKS本身的费用也比预想中的多很多,于是我下决定,还是放弃花里胡哨的全托管,回归了最经典的虚拟机+单节点kubernetes的形式。代码也改成了直接读写本地SQLite数据库,部署起来方便。

开好VM,直接让AI给装了个k3s,把所有yaml直接迁移过去,改了改CI,费用果然就下来了。也没有更多的付费内容,2C8G一个月80刀左右,再加上公网IP的费用,150刀这下才真正够用。

最近费用折线图,换成VM后斜率明显减小

而且用VM还有个好处:没有那么多花里胡哨的AKS专属的功能pod,可用的资源也变多了。现在我把所有服务(例如内网穿透、梯子)全部迁移到这里,也完全够用。

Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests    Limits
  --------           --------    ------
  cpu                500m (25%)  2 (100%)
  memory             780Mi (9%)  1706Mi (21%)
  ephemeral-storage  0 (0%)      0 (0%)
  hugepages-1Gi      0 (0%)      0 (0%)
  hugepages-2Mi      0 (0%)      0 (0%)

后续

现在博客项目使用Next.js实现的,做起来确实比较简单,但是构建的镜像太大了(300M),推送还挺耗时间的。有了AI后,后续可考虑把博客逻辑改成go写,前端改成vite+react纯前端,最后构建一个十几M的纯go二进制。

在做这个过程中的时候,我又遇到了前两年工作的时候几乎天天接触的Azure的各种概念。这些概念纯学起来非常抽象,真正用起来才直到用处在哪儿。最近工作也接触了一些国产云,感觉国产云在这些管理和开发者友好的功能上还是有一定差距的。

fork subgen实现纯本地AI视频字幕生成和翻译

2026-03-14 11:53:00

最近我想看一场时长 5 个多小时的日语演唱会录像,但这份录像没有可用字幕,我又不懂日语,没有字幕MC部分根本听不懂。

于是我想到可以用本地语音转录生成字幕。调研后我发现了 McCloudS/subgen 这个项目,发现它已经把“本地自动转录”这件事做得很完整,并且可以用jellyfin集成实现视频加入和播放时自动生成字幕。

在实际体验中,我进一步希望它能覆盖“转录后翻译”的需求,于是决定在原项目基础上做一层轻量扩展,把翻译功能补齐到同一条工作流中。

因此,我在原仓库上创建了一个fork https://github.com/ddadaal/subgen-translate ,实现了:

  • 在不破坏原有 webhook / Bazarr 使用习惯的前提下,增加“转录后翻译”能力
  • 添加使用CLI转录和翻译的功能,可以直接在命令处理文件,无需从媒体服务器走
    • 转录: uv run launcher.py -f "D:\Movies\movie.mp4" -t transcribe
    • 翻译: uv run launcher.py --srt "D:\Movies\movie.subgen.medium.jpn.srt" --srt-to zh
  • 添加一些工程管理的最佳实践,例如使用uv管理环境、subgen.env.local来编写本地配置等

个人使用场景

我的实际环境是一个典型的家庭局域网多机协作场景:

  • 一台较老的 Windows 笔记本作为 NAS 主机,部署了 Jellyfin,并通过外接硬盘盒存放媒体文件。
  • 局域网里其他机器没有可用 GPU,CPU 做转录与翻译(尤其翻译)速度过慢。
  • 因此需要另一台带 GPU 的机器专门承担转录/翻译计算。

在 Subgen 与 Jellyfin 集成时,有一个关键前提:Subgen 看到的媒体文件路径,必须与 Jellyfin 看到的路径完全一致。为了实现这一点,我

  1. 在 GPU 机器上把 NAS 外接硬盘映射成与 NAS 机器相同的盘符路径。
  2. 配置 Jellyfin 与 Subgen 的互通(网络可达、Webhook 与服务地址正确)。
  3. 让 Jellyfin 的“新增媒体/播放媒体”事件自动触发 GPU 机器上的 Subgen。

这样,Jellyfin 仍然负责媒体管理与播放触发,GPU 机器负责高耗时的转录与翻译,实现了“存储在 NAS、计算在 GPU 机器”的分工。

部署拓扑图

flowchart LR
	subgraph LAN[家庭局域网]
		subgraph NASHost[老 Windows 笔记本(NAS)]
			Jellyfin[Jellyfin 服务]
			Disk[外接硬盘盒 / 媒体库]
		end
 
		subgraph GPUHost[GPU 机器]
			Subgen[Subgen 服务]
			Model[Whisper + TranslateGemma]
		end
 
		Client[局域网播放器/客户端]
	end
 
	Disk -->|媒体文件路径| Jellyfin
	Disk -.同盘符映射.-> Subgen
	Client -->|播放/新增媒体| Jellyfin
	Jellyfin -->|Webhook 事件| Subgen
	Subgen -->|转录/翻译| Model
	Model -->|生成字幕(双语/纯译文)| Disk
	Jellyfin -->|读取字幕并展示| Client

使用体验

配置情况:

  • NAS机:i5 1135G7 15W + 16G
  • GPU机:R9 [email protected] + 64G DDR4 3200 + RTX 5070 Ti
  1. 转录和翻译过程都没有充分利用GPU,两个步骤的显卡利用率都只有 40%。转录过程需要 CPU 参与处理音频流,翻译过程应该是每一行都要重新推理影响速度

转录过程中CPU和GPU使用情况

  1. 视频时间越长,视频后半段就越容易出现错误、重复、未识别的情况,需要通过调整各种参数来缓解,至少需要打开vad功能,其他参数可让AI来调整。
# subgen.env.local
SUBGEN_KWARGS={'vad': True}
  1. faster-whisper支持多种模型( https://deepwiki.com/SYSTRAN/faster-whisper#supported-model-variants ),但是不同模型的使用体验有较大区别:
    • medium:在 i5-1135G7 上用CPU大约可以做到 1s/s(每 1 秒处理 1 秒原视频),台式机RTX 5070 Ti 6s/s (每秒处理约6秒原视频),速度可以接受
    • large-v3:模型大小 3G,在台式机 RTX 5070 Ti 上最快可达 9s/s,和medium差不多,因为瓶颈在CPU上
    • large-v3-turbo:模型体积和 medium 差不多,都是约 1.5G;但在我的环境里只能正常处理视频开头,后面基本识别不出文字,估计也和调参有关,而且既然large-v3也这么快了,直接用large-v3就好
    • distil-large-v3:只支持识别英文
  2. faster-whisper只支持CUDA 12,不支持最新的CUDA 13
  3. 翻译过程按最简单的每行推理一次的写法,使用原版 translategemma-4b-it和默认参数在RTX 5070 Ti上推理一次2.3s,速度勉强可以接受。但是考虑到字幕的每一行一般较短,将多个字幕合并后同时推理效率更高,所以提供了批量翻译的功能,每一次推理翻译多行,需要根据README中的描述以及本地硬件的情况调整相关参数
  4. 如果只是偶尔用一次、而且每次翻译的数量不多的话,字幕翻译和合并功能其实有很多在线的免费服务可以用,且速度和质量都非常好(甚至比本地模型效果更好)
    1. 翻译: https://translatesubtitles.co/
    2. 合并: https://subtitletools.com/

把nanobot关进Docker后,如何同时保留浏览器可视化与自动化

2026-03-06 18:50:00

实在不太放心把 nanobot 这类可以直接操作本地电脑的程序直接装在操作系统上,所以我选择把 nanobot 放在容器里运行。但是nanobot很多有意义的工作又需要和宿主机上的环境(例如浏览器)交互,而浏览器上很多网站需要我们先去登录才可以正常使用,这就需要一个既可以由 nanobot操作、也可以由我们自己的操作的浏览器

经过一番查找,终于找一个不影响 nanobot 本身的方法,操作是在部署 nanobot的 docker-compose.yaml 目录下再创建一个 docker-compose.override.yaml,内容如下:

services:
  chromium-vnc-cdp:
    image: linuxserver/chromium:latest
    container_name: chromium-vnc-cdp
    ports:
      - "3000:3000" # Web 界面
    shm_size: "2gb"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - CHROME_CLI=--remote-debugging-address=127.0.0.1 --remote-debugging-port=9222
 
  chromium-cdp-proxy:
    image: alpine/socat
    container_name: chromium-cdp-proxy
    restart: unless-stopped
    network_mode: "service:chromium-vnc-cdp"
    command: "TCP-LISTEN:19222,fork,bind=0.0.0.0,reuseaddr TCP:localhost:9222"

启动后,给 nanobot 一条明确指令:

之后都使用 chromium-vnc-cdp:19222 这个 CDP 端口操作浏览器。

为什么是两个容器

chromium-vnc-cdp 的职责是提供浏览器本体和 Web 访问界面(3000 端口),这样我们可以直接使用localhost:3000访问这个浏览器。

chromium-cdp-proxy 的职责是把 Chromium 容器里只监听 127.0.0.1:9222 的 CDP 端口,转发成同网络命名空间下可访问的入口。实际上这两个容器在同一个网络中,所以需要换个端口监听,这里选择了19222,其他任何端口都可以。

这里有一个关键限制:根据 pyppeteer 相关讨论中的实践结论,--remote-debugging-address=0.0.0.0 往往需要和 --remote-debugging-port、--headless 一起使用;但一旦使用 --headless,就无法达到“实时查看浏览器界面”的目标。

来源:https://github.com/pyppeteer/pyppeteer/pull/379#issuecomment-2072215518

因此我不走“浏览器直接对外暴露 CDP”的路线,而是保留有界面的 Chromium,再通过独立的 socat proxy 容器做端口转发。

这样拆分有三个好处:

  1. 浏览器容器保持默认安全策略,CDP 仍然只在本地监听。
  2. 通过 socat 单独做代理,不需要改 Chromium 镜像或启动脚本。
  3. nanobot 只需要记住一个固定地址(chromium-vnc-cdp:19222),配置简单且稳定。

实际效果

这套配置完成后:

  1. 你可以在 3000 端口看到浏览器 Web 界面。
  2. nanobot 可以通过约定好的 CDP 地址持续复用同一个浏览器环境。
  3. 浏览器自动化和人工观察(VNC/Web)可以并行进行,排障体验更好。

可划分显存 != 统一内存: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个小时中无比后悔又浪费了一天。

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

混乱的一年

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

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

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

长春冰雪大世界

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