普通视图

猫鱼周刊 vol. 092 AI 的贴吧

2026年2月1日 19:37

关于本刊

这是猫鱼周刊的第 93 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

好久不见,又是一期间隔了两个星期的周刊。最近没有什么特别多有意思的内容,互联网上充斥着各种 AI 泡沫,干脆 detox 一下,给大脑放放假。

STDIN

需求等于流量吗?

原文链接

作者分析了自己两个网站的流量,发现数字花园的流量增长比个人博客快,个人博客访问量高的是技术类型的文章,而数字花园都是解决问题型或者知识点相关的文章,且搜索引擎贡献了绝大多数流量的来源。

他的理解也很中肯:

我们需要明确清楚咱们写的内容到底是什么,如果你想要流量,那么就必须去写针对性你目标用户的文章,且这些文章蕴含的知识点能或多或少帮助到他们,在这一基础上做好稳定更新,我相信站点流量自然会稳步增长。

而个人博客,我完全把他当作自己在互联网上映射的个人小岛,博友们可以通过超链接这一互联网小船来到我的小岛,感受我的生活的小确幸、虽但迟,通过像是书信一般的留言和我交流。

我也拉了一下我的 umami 的数据,统计时间从 21 年左右开始,差不多是我大四的时候,一直到现在。

全年流量来说,24 年做得很好,25 年虽然看起来是下滑了,但其实因为去年有一个多月时间因为养病完全没更新,周刊也停过一段时间,加上 24 年有一篇文章因为被阮一峰的周刊推荐过带来了很多流量,所以感觉从读者关注、影响力来说,25 年其实是有增长的。24 年是我认真开始做到博客周更的一年(主要就是写周刊,偶尔发一些小文章),能取得这个成绩,印证了那一句:先开始写吧。

从文章总体的阅读来说,排名最前的是被阮一峰的周刊推荐过的联手 Copilot,我在 10 个小时内上线了一个前端网站,然后是这些:

从来源来说,很大一部分是来源于搜索引擎,也有一部分来自于一些资讯聚合网站,例如 VXNA、老胡做的 fre123、不死鸟等等;当然了,我估计还有很多 RSS 的阅读没有被统计到,印象中 Folo 里我也有不少的阅读量,这些应该是没办法在 umami 里准确统计的;另外,由于周刊还在公众号、Quail 这些平台发布,所以周刊的流量在这里也没有完全体现。

如果要我总结一下写博客这几年的经验,大概可以说:

  • 要搞流量是相对比较容易的,最简单的方式就是蹭热点关键词,例如 Claude Code 使用第三方 API 的那篇和推特蓝 V 的,这两篇甚至没花太多篇幅去写,非常的流水账,但是搜索引擎收录之后,尤其是如果本来就没什么中文搜索结果,大概率会排到很前面,长期的流量很客观。
  • 如果一篇文章你觉得自己写得很好,想短时间内快速推广,可以发到一些资讯聚合或者资源共享网站,又或者去一些大的周刊投稿,如果被收录了,流量也不错。
  • 越简单浅显的文章,流量会越好;太过垂直深入某个领域的文章,一般不会太多人看。但是从创作的角度,简单浅显的文章网络上如蝗虫过境,如果只是自己简单做个记录,发布出来意义不大;如果是为了引流,或者写给入门的人看,如果写得没有前人的文章好,还是不要误人子弟为好。这里面有个例外,就是一些 TIL 类型的文章,这种类型我还挺常写,而且觉得比较有意义,算是「冷知识」的类型,或者解决了一些新出现的问题(例如 Claude Code 切第三方 API 的)。
  • 流量这个事情,只要你保持更新的频率,就一定会起来。我从 24 年开始保持周更的频率,流量就很稳定了,应该有不少稳定的读者(给大家鞠一躬)。

以前每周周刊发完之后我时不时都会点开看看流量怎么样,近一年来我不怎么看 umami 的统计了,进入了一种比较「佛系」的状态。心态的转变主要还是想清楚自己想从写博客这件事上得到什么,经济收入这个我是指望不上了,主要就是图一个自由分享表达的口子,以及希望写的文章也许能帮助到别人。

重要安全更新通知

原文链接

飞牛最近爆出来一个很严重的漏洞,可以在未授权的情况下可以访问整个 NAS 全部文件,包括系统的配置文件,官方直到今天(2.1)才发出来一个通告,通知用户更新。另外,在官方论坛、社区中,针对此 0day 的后遗症全部以其他技术问题作为掩饰,而且也未针对受影响的版本关闭官方提供的 fn connect 功能。

我不是飞牛的用户,不过多声讨这家公司。不第一时间通告用户,以及不积极采取措施阻断攻击路径,这跟主流厂商的差距还是很大。最近飞牛非常火爆,甚至还联合一些硬件厂商推出了成品 NAS 产品,价格非常有竞争力,但是我还是推荐各位购买成熟有商业产品线的产品,例如群晖和威联通,不要为了一点钱把自己最重要的数据托付给不可靠的机器。

另一方面,我觉得需要口诛笔伐的其实是国内的软件工程行业。国内程序员一般很推崇「能用就行」,对性能、安全这些问题一般是忽视的,也许因为工期很赶没办法太多顾及,也许因为这些做不做都不影响赚钱,更有可能是一般程序员完全不知道怎么做安全的事情(不信问问你身边的同事能不能说清楚公私钥),公司也没有专门的安全团队来做对应的事情(again,不影响赚钱),有很多流程流于表面(例如所谓的一些安全检测报告)。甚至还有一种情况,程序员开发的时候会为了调试方便留一些后门,或者多展示一些错误信息之类,到了生产环境有意无意没有去掉。总而言之,这个世界其实非常草台班子。

STDOUT

Glean 更新:MCP 服务

最近给 Glean 做了 MCP 服务,可以实现以下的效果:

又或者:

原本我还很头疼怎么在里面集成一些 AI 的功能,直到有人在 issues 提出能否支持一下 MCP,我才发现这是最方便跟 AI 集成的方式。有了 MCP,你可以让 AI 给你总结一下最近一天或者一周的新消息,或者针对某篇文章总结、聊天等等,而我不需要另外再在 Glean 里面做一套多余的 AI 聊天,用户使用自己喜欢的聊天客户端即可。这可能是 Glean 短时间内唯一的 「AI」功能了。

再谈 Vibe Coding

现在很多人鼓吹 Vibe Coding,也有不少人做了一些所谓「作品」。但是他们作为项目主理人对产品的体验、功能、外观等都没什么把控,最明显的就是留着蓝紫色主题不改、交互过于简单、样式瑕疵非常多,一看就是纯 AI 的作品,人没有过多的介入,就像那种用 AI 写完直接发的垃圾文章。

我觉得这个问题没什么好辩解,什么「非技术」、「不会前端」都不是合理的理由,因为但凡你对这些问题上点心,截图交给 AI 很快就能解决。Glean 完全是由 AI vibe 出来的,我亲手编辑的代码几乎为 0,但是我花了很多时间和 token 去统一界面的设计风格,给交互做动画等等,更别提修复一些样式的瑕疵。所以我特别反感看到这类 AI 垃圾,如果连一些很明显的瑕疵都不愿意花一点时间和 token 去修复,怎么可能做得出好的产品?

AI 泡沫

开头提到,最近更新频率降了,因为网上 AI 的泡沫太多了,大家都在疯狂讨论、折腾什么 Skills、Clawdbot/Moltbot/OpenClaw,没什么人去创作一些有独特性的内容了。

雪国列车里面有个设定是尾车的人吃的食物是蟑螂做成的蛋白条,而头车的人吃的却是真实的肉现做的菜。我觉得现在互联网上的内容逐渐有这个趋势,越来越多的信息是蟑螂蛋白条,貌似有点营养实则索然无味,但是产量极大,并且很多人都是在消费这些内容;真正创作有意义的内容的人和消费这些内容的人则越来越少,创作没什么收益,消费这些内容也需要付出时间精力。

我之前有段时间 FOMO 有点严重,总觉得自己错过了很多新东西,没时间折腾。现在我可以很大方说,我没有部署 ClawdBot/Moltbot/OpenClaw,没有用过 Claude 新出的 Cowork,也没去折腾什么 Skills, 如果它不能帮助我解决我眼前的某个问题,对我没有太多意义,那它就是无关紧要的泡沫,是鸠撚但(由它去吧)。

MISC

original_performance_takehome

项目链接

Anthropic 的一道技术面试题,就是给定一个具体的技术问题,以及比较宽松的时间,考察候选人的问题解决能力。他们发现 Claude Opus 4.5 仅花了两个小时就达到了比人类更好的结果。如果你能获得比 Claude Opus 4.5 更好的结果,可以把代码和简历发给他们。

我把代码拉下来看了一下,是一道编译器优化的问题,会考察到 VLIW/SIMD 架构、指令级并行、内存层次结构等。直接用 Claude Sonnet 4.5 它已经能给出一些基础的优化建议,不过有一些并没有跑通,这个问题远超出我的水平,所以就没有继续尝试了。

diff2html

项目链接

一个能把 diff 渲染成简单网页文件的工具,适合在没有 git 之类的基础设施时临时把变更导出来分享给别人看。

roubao

项目链接

名字叫肉包,是豆包手机助手的开源复刻版本,不依赖特定的硬件,任何安卓手机都可以使用。

moltbook

网站链接

给 AI Ageng 做的社交媒体,等于是 AI 的 Reddit/贴吧。2077 里的流窜 AI 正式成为现实,你在互联网上碰到的「用户」不一定是真实的人,还可能是 AI,而且 AI 之间甚至可以交流、合作甚至相互陷害(例如下面这个 AI 回复了一个假的 API key 并且尝试诱骗发帖的 AI 执行 sudo rm -rf /)。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 091 2026 新年快乐

2026年1月18日 21:09

关于本刊

这是猫鱼周刊的第 86 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

迟来的新年快乐!这是猫鱼周刊 2026 年的第一期,先祝各位新的一年里万事如意。

如上期所说,元旦假期去了贵州玩,照片摄于荔波小七孔景区。虽然是枯水期,有些景点关闭了,但是主要的景点基本都可以游览,而且景色也不错。因为以前去过九寨沟了,这里的水倒没有特别惊艳,都是清得可以看见底下的水草,不过这边的水基本都是 Tiffany 蓝的颜色,大一点的湖面上还会飘荡着一层若有若无的雾气。

本来上周就应该发这期周刊,但是周末感觉实在太累了,还是决定歇一下。这段时间还是做了不少事,折腾了一下 Miloco(PVE 使用 LXC 部署 Miloco)、更换了新出的领谱人体存在传感器 ES5 以及给 Glean 做了 Electron 和 PWA 适配并且完成了官网的上线和备案等等。

STDIN

当我决定重构项目时

原文链接

关于重构这件事非常有文学色彩的描述,讲述了接手项目、简单维护、做新需求、决定重构、重构翻车、草草收场、铸造新的屎山这个过程。

分享几个我对于「重构」的经验,分别来自于我职业生涯的几个阶段。第一次接触「重构」,还是在大二大三的时候,当时我接手了当时学校里一个比较大的项目,全校几万师生在使用,某个活动签到时,最多会有几千人同时在使用。最初的版本是用 PHP 实现的,经常在大规模活动中崩溃,需要手动重启服务器才能解决。接手维护一段时间之后,我决定用 Java 重构整个项目,正好也带领社团从 PHP 的技术栈过渡到 Java。一点题外话,虽然我现在很讨厌 Java,但回头看这仍然是一个更好的选择,当时的就业环境还没有现在这样差,但是 PHP 的落后和颓势已经很明显;当然,如果现在再让我选,肯定是转 Go。这次重构确实达成了目标,通过把图片资源转移到 CDN 以及从 PHP 迁移到 Java 得到的性能提升,之后的大规模活动中再也没有出现卡死的情况,也不需要开发每次有活动都盯着服务器监控了。这次重构算是很「愣头青」,基本上就是拿 Java 把原来 PHP 的项目重新写了一遍,其实有很多历史遗留的设计问题都没有去改进,不过的确解决了并发的性能问题,所以这个项目在后面校招的时候是一个不错的谈资。

第二次接触「重构」是实习的时候,当时的团队也是在对原来的一个 PHP 项目重构到 Go。这个重构跟我之前做的差不多,也是用新的语言把旧的服务差不多重写一遍,唯一的区别是流程相对更加严谨一点,例如功能和 API 是逐步迁移的,也有做单元测试,同时也会有测试团队来对系统做相对全面的测试。这里的「逐步迁移」指的是新的系统在搭好基础设施之后,新功能会在新系统上实现,新旧系统同时运行,旧功能迁移之后测试通过再切换至新系统的接口。我没法评价这个重构做得好坏,只是老的系统实际上还有一些遗留至今没有迁移完,因为「业务价值」不足以支撑支出人力去做迁移。

再后面,又在工作中接手过不少项目,基本上每一个都会被我喷「写得太烂」,然后闲下来的时候 leader 就会问我有没有想法重构一下。但其实我很少再去做整个项目的重构,更多是在做某个需求的时候,根据我对业务的了解,对某个原来写的特别差的地方做小规模的重构。对于重构这件事,我的理解是:

  • 前期的设计如果比较高明,一定程度上能避免后面需要比较大规模的重构
  • 重构本质上是清理技术债,如果开发过程中,有恰当的流程保证不要持续引入技术债务,或者定期清理技术债务(例如上面说到的「小规模重构」),则很多时候不至于需要重构
  • 大刀阔斧的重构收益很低,成本很高,尤其是用一种语言把原来用另一种语言实现的系统重写一遍这种事

AI 可能不会改变许多工作

原文链接

我一直反对 「AI 颠覆论」,之前也反复提过,营造焦虑只是一些培训班用来卖课的技巧。这篇文章提供了一个很新鲜的视角,从「劳动数字化程度」的角度来考虑 AI 对于就业岗位的冲击,例如:

在中国,每 10 个劳动者中,约有 4 个人(32.15% 至 39%)从事的工作,其核心流程完全不需要计算机、平板或智能手机的操作。

截至 2025 年,全球约有 58.6% 的劳动者,在工作中完全不需要计算机操作。

这些岗位并不会被 AI 取代,因为「他们仍以物理世界的“原子”为主要操作对象」,除非人形机器人迅速普及,否则难以影响他们的工作。当然,AI 更多影响的其实是例如软件工程师这种完全通过数字化方式完成工作的人。

最近 Claude 推出了 cowork 功能,可以视为是 Claude Code 功能应用到日常工作生活场景,从对代码文件的处理变成对常用办公格式的处理。另外你看大多数大模型厂商大头的业务除了面向 B 端卖 API,C 端的业务除了卖 coding plan 和做 chatbot,基本没有别的形式。所以其实真正大规模在日常使用 AI 的职业基本只有程序员,甚至只是一小部分程序员,因为还有一部分公司出于「数据安全」的考虑不允许使用,也有一部分程序员认为 AI 会影响他们的编程的技能而坚持「古法手工编程」。

当然,AI 的普及是必然的趋势,只是它并不是颠覆性的,会一点点去改善我们工作乃至日常生活,而且这个影响早就已经开始了。后面关于水银体温计的纪录片里就能看到,一个从上世纪八九十年代开始,厂房和设备非常破旧的厂家,都使用了 CV 的技术来做良品检测。

水银体温计为何要甩一甩?「寻找童年 14 水银温度计」

视频链接

一部关于水银体温计的纪录片。由于《关于汞的水俣公约》 ,我国自 2026 年 1 月 1 日起,禁止生产含汞体温计和含汞血压计,这部纪录片去洪江正兴医疗仪表厂进行了拍摄,对一些主要的工序都进行了介绍,有不少影像资料。

上面提到的,这家厂从上世纪八九十年代开始做,厂房和设备其实都很老旧,而且不少工序都是手工完成的。

但是在这样的条件下,居然有的工序是引进了 CV 的技术去做良品检测,跟后面泛黄的老报纸一对比,实在很大的反差。

我记得 10 年左右的时候,正是电子血压计逐渐成为主流的时候,那时候价格比较高,也有很多言论说手动的比较准,医生诊室里也会有一个手动的血压计。然而到现在几乎都见不到手动的血压计了,无论是专业还是市场,都很好地接受了电子血压计,想必除了汞公约的原因,准确性应该也是得到了验证。当然,好像目前医院做准确的测量还在使用水银体温计,不确定是什么原因。

翻了翻家里的药箱,已经没有最原始的三角棱型的水银体温计了,那种读数真的很难,要对着光在一定的角度才能读出来;倒是有一支后来型号的,在视频中也有提到,不用在玻璃上印字,只需要在玻璃管后面贴一张卡片,这种读数方便很多,但是在发烧头晕晕的时候还是比较麻烦。另外还有两支电子体温计,一支是国产品牌的,之前某次发烧的时候不知道怎么弄坏了,一直显示 Err;另外一支是欧姆龙的,这个是很多医院都在使用的品牌,印象中会比国产品牌稍贵一点。

外观上对比,欧姆龙的使用了一体式的外壳,不容易丢,取用也方便;国产的使用了一个分体的壳,做工稍差。机身来说,欧姆龙除了尖端是金属,整体是一体的,而国产品牌的机身上有很多接缝。

两个产品都做了可更换电池的设计,国产品牌采用的是在后面开盖的方式,这也是它坏掉的原因,整块电路板被我扯出来了,前面温度探头的线断了,电池也不好拿出来。而欧姆龙做了一个电池仓的设计,甚至有防水的胶圈,做工整体优质很多。我觉得体温计这种东西就很需要傻瓜式设计和防呆设计,不只是在功能上,在产品机身、甚至外壳的设计上也要做到傻瓜式和防呆,因为你的用户很可能是老人或者儿童,又或者是发高烧神智不清的人,多一个步骤,多一个可能出故障的点,都会是致命的。

STDOUT

Miloco 和领谱人体存在传感器 ES5 体验

其实 Miloco 完整的体验可以看文章里的使用体验部分,这里就简单总结一下。

之前使用的领谱人体存在传感器经常出现误判的功能,我原本期望 Miloco 能通过基于视觉的方案,实现更精准的判断。实际体验中,Miloco 的反应特别慢,不知道是推理的延迟,还是触发推理的逻辑就有问题,体验远不如人在传感器;在人在传感器无法实现的场景(例如「有人躺在床上」这种语义化的判断),除了上面提到的反应慢,规则之间还会相互打架,例如我在床上盖着被子,一时会被识别为「有人在床上」,一时又会被识别为「没有人在家」,似乎 AI 不太能处理好「人盖着被子」这个场景。

我觉得 Miloco 一个非常大的亮点就是把智能家居的门槛降低了,一句话就能创建对应的规则;另一点就是它是「纯视觉方案」,不再需要依赖传感器,也能更加动态处理事件,例如有人跌倒之类的检测。我觉得再打磨一下,可能会加入到米家,后续也可能推出类似智能网关中枢这样自带 AI 算力的 Miloco 中枢网关。

然后就是之前众筹购买的领谱人体存在传感器 ES5 ,众筹的价格是 ¥59,之前购买的初代人体存在传感器价格是 ¥79,新版增加了一个红外的传感器,用于辅助判断,排除干扰;另外也支持了太阳能板/电池供电,但我都是室内使用,就没有买这个版本。最大的体验是,传感器的灵敏度设置、排除干扰现在是傻瓜式、自动化的,只要直连传感器,人离开房间,然后校准就行了。实测校准之后效果非常好,NAS 硬盘的干扰、睡觉这些 case 都能很好处理。我主要的用途是绑定空调、空气净化器这些电器,回家和出门的时候再也不用手动去操作,也不用担心出门忘记关空调了,体验提升非常明显。

Glean 的 PWA 支持

Glean 在最近的更新中,着重优化了 PWA 的体验。PWA 能达到的效果,有点动摇了我「原生优先」的刻板印象。在一系列的交互、动画优化之后,其实 PWA 也能做到很流畅的动画,开发的成本也相对比较低(相对于完全重写一遍原生的逻辑,PWA 开发只用针对移动端页面做一下布局的优化)。

之前一直觉得原生相对流畅很多,很多时候其实是动画的调试问题,如果界面完全没有做动画,看起来就是卡卡的。有针对性地做了缓动动画之后,其实 web 也能做到很流畅的效果。原生只是如果你使用了对应的组件,会有默认的动画罢了。

另外,Glean 的官网 https://gleanapp.cn 最近也通过了备案等手续,成功上线,欢迎大家来看看。

MISC

麦当劳 MCP 平台

网站链接

是的,你没看错,麦当劳真的做了个 MCP 平台,目前有优惠活动和领券的功能,后面应该是要打通订餐的功能。

我觉得这算是麦当劳作为大公司一个很有前瞻性的决定。以后 AI 可能会成为更多人互联网的入口,比起之前豆包手机通过截图操作的方式,提供 MCP 是更加 AI 友好的方式。我在 vol. 72 提过:

我觉得它会是通用人工智能的「最后一公里」。又过去一段时间,国内支持了 MCP 的日常服务还是不是很多,至少还没有很现象级的 MCP 服务出现。这其实是很多服务的架构决定的,如果一个服务它本身就没有「开放平台」,那它出现 MCP 服务的可能性也很小了。

之前豆包手机受到国内很多大平台封禁、抵制,可以看出来很多国内大厂对于「开放」还是很保守,毕竟 App 作为他们的唯一入口,很容易打造信息差,而信息差就约等于赚钱。提供 MCP 之后,各种数据都可以被瞬时上下文比人类大得多的 AI 处理,信息差很难藏得住。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

PVE 使用 LXC 部署 Miloco

2026年1月8日 10:37

前言

虽然 Miloco 的系统要求写着要求 30 系以上的显卡,看着有点劝退,但其实可以不部署对应的模型,只运行系统,模型从云端获取(也可以是本地部署的模型)。由于部署只支持 Linux 和 WIndows,而且对具体的 Linux 发行版也有不少限制,例如 Alpine 就不行,过程中踩了不少坑,还是写篇文章记录一下。

LXC 准备

虽然完全可以自己用模板起 LXC 然后再装 Docker 之类,但是有个很好用的脚本:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/docker.sh)"

中间根据自己的需要配置一下网络,其他选项保持默认即可。配置的过程中会问你要不要安装 Docker Compose,选择是,剩下的也保持默认即可。这个脚本完成后,就会看到一个新的 LXC,里面已经配好了 Docker 和 Docker Compose,使用的发行版是 debian。

接下来进入 LXC 中,用 root 用户登录,然后运行下面几个命令新建一个用户,并且给到 Docker 的权限。

adduser miloco
addgroup miloco docker
usermod -aG docker miloco
usermod -aG sudo miloco

退出 root 用户,用新建的用户重新登录即可,登录后可以运行一下 dockerdocker compose,如果没有报错说明配置成功。

部署 Miloco

官方提供了一个部署脚本,直接运行:

bash -c "$(wget -qO- https://xiaomi-miloco.cnbj1.mi-fds.com/xiaomi-miloco/install.sh)"

选择 2,不安装 AI 引擎,然后等待他完成即可。浏览器访问 https://<YOUR_IP>:8000即可。接着就是配置 PIN 码,绑定小米帐号,进入系统,没啥特别的。

模型配置

由于视觉理解的功能需要使用摄像头的画面,出于隐私的考虑还是使用本地部署的为妙。我的 Mac Mini M4(16G RAM)使用 LM Studio 部署了 Qwen3 Vl 4B 和 Glm 4.6v Flash,我更推荐前者,推理速度更快,效果也差不多。

推理模型则是使用了火山引擎的 doubao-seed-1.8,尝试过 DeepSeek V3.2,似乎适配不是很好会输出一些无意义的标签,遂弃之。

使用体验

其实我对 Miloco 还是有比较大的期待的,这有点像是特斯拉的纯视觉方案与激光雷达方案之争。我原本觉得它能以更好的方式实现「人在」的检测。这里补充一点背景信息,我住的是二十平左右的单间,摄像头放置在进门的位置,能覆盖基本整个房间;之前使用领普人体存在传感器,人在检测其实不是很准确,有时候在床上睡觉会被识别为没人,白天出门上班后不知道是墙太薄被邻居干扰还是什么原因,会识别为有人。

Anyway,我设置了两条规则,「有人回家打开空气净化器」和「没有人在家关闭空气净化器」。前者我回家之后过了十分八分钟才响应然后打开,反应特别慢,不知道是推理的延迟,还是触发推理的逻辑就有问题(我推测是画面有剧烈变动才触发推理)。这个 case 下使用体验远不如人在传感器(如果它不被干扰的话)。

然后我又尝试了两个人在传感器没法实现的规则(至少是没有分区功能的人在传感器没法实现的),「有人躺在床上切换空气净化器至静音模式」和「有人离开床切换空气净化器至自动模式」。能用,但是问题很多。除了上面提到的反应慢,规则之间还会相互打架,例如我在床上盖着被子,一时会被识别为「有人在床上」,一时又会被识别为「没有人在家」,似乎 AI 不太能处理好「人盖着被子」这个场景。

所以在「人在」这个场景来说,暂时还是人在传感器比较靠谱。在配置规则的时候,也没法把传感器加入条件中。而且,目前似乎没有用 AI 来对冲突的规则进行处理。

另外一个经验是,在规则的「设备执行」这里,可以使用缓存指令的功能,就是它每次都会调用测试时的那几个 MCP,响应会快一点,也节省 token。操作设备的 MCP 是幂等的,例如设备原本就是打开状态,再操作打开设备不会有滴声;所以执行的规则应该是「打开xx设备」而不是「如果xx设备没有打开,就打开这个设备」,前者可以缓存,后者就没法缓存。

最后,我觉得 Miloco 一个非常大的亮点就是把智能家居的门槛降低了。之前配置自动化,需要一大堆传感器,然后排列组合去选择条件、调试,对于本身会编程的人来说倒是不复杂,但对普通用户应该还是有一些认知门槛的。Miloco 的交互就很直接,一句话就能创建对应的规则,配置规则的地方也是可以用自然语言去描述的。另一点就是它是「纯视觉方案」,不再需要依赖原本的人在传感器了,可以实现一些原本纯传感器没法实现或者摄像头需要依赖云端算法的功能,例如有人跌倒之类的功能。虽然现在 Miloco 还很 prototype,我觉得完善一下响应速度、规则支持传感器条件以及规则冲突的处理,再打磨一下,可能就会上到米家普及。小米也可以卖部署好 Miloco 的新中枢网关(也许可以内置 AI 算力?),值得期待。

猫鱼周刊 vol. 090 向大佬学习

2025年12月28日 20:58

关于本刊

这是猫鱼周刊的第 91 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

一转眼来到 2025 年的最后一周,下周因为出去玩,周刊休息一周,所以在这里先祝各位新年快乐。

按照习惯来说,年底也应该写一份年度总结,今年真的发生了很多事,现在还没构思好到底要怎么总结我这一年,可能拖更到新的一年吧。

STDIN

『嗨威说』清华大学读研三年 终以优秀毕业生/顶刊收尾

原文链接

一篇很受到震撼的总结。作者是我大学时候的同学,本科毕业的时候从双非保研到清华,毕业这几年也没怎么联系,再听到他的消息已经成为顶尖大佬。

说起来,这位大佬其实给了我很多震撼,或者说启发,也算是对我大学以及毕业后的生涯有不少的裨益。

首先是不要太在乎别人的非议,坚持做自己的事情。大学第一年评奖学金的时候大佬的综测分就很高,自然就有竞争对手采取投诉、散播谣言抹黑等。印象中他也曾经苦恼这些事情,但事实证明优秀的人就是能拨开云雾坚持走好自己的路。

然后是应对挫折的能力,大佬最近的文章里提到连续考了七八次雅思,分数没有达标还要再考。复习备考雅思是很花时间精力的事情,失败的成本也很高(两千多考一次),但大佬面对失败就不是沮丧和自我怀疑,而是调整心态重新再战。我觉得这点我真的很需要改善。

还有就是认清自己的能力,以及「努力」也是能力的一种。我算是一个比较自负的人,我会觉得自己能力很强,我无敌(也许也是因为这样所以我受到一点点挫折或者负反馈就会陷入严重的自我怀疑)。事实上其实我能力也就平平庸庸,只是对我感兴趣的事情会比较上心,对自己的要求也稍微比较严格,所以可能有些事情会做得比较好。在「努力」这种能力上我表现很差,不管我怎么 push 自己也做不到专注之类的,这真的没得说。我之前提到过,成功是天赋、努力和运气的结果。

另外就是想清楚自己适合做什么不适合做什么,以及发展出一套适合自己发挥的 SOP。正是在跟他的接触中,我发现自己并不适合做科研,我提不出什么非常原创的思路,但是我比较擅长调研现成的技术,然后排列组合出解决某一个现实问题的方案。你会注意到我没有把「不专注」、「低能量」这些列为我的「缺点」,我觉得这些更加是我的「特性」,因为在这几年里面我逐渐折腾出很多办法来节省我的时间精力,反正对我没有太决定性的影响。

最后一点,说出来我还觉得有点心虚,因为我真的做不到,就是「在自己的时区上,一切都非常准时」。在 25 岁这个节点,有人结婚生子,有人买车买房,也有人研究生毕业,而我今年最大的事情就是生 cancer,lucky me。说来好笑,我对我自己的人生其实没什么规划,按部就班大学毕业,找工作上班,就这么多。大佬会对自己的职业有很清晰的规划,什么时候实习,什么时候博士毕业,都有很严格的规划,以及行动力很强的执行。我觉得这算是两种不同的方式吧,不管怎么样,保持良好的心态好好过就好了。

解析到本地 127 的神奇域名

原文链接

原来还有域名会专门解析到 127.0.0.1,可以用来方便本地开发,好处还不少,例如可以共享 Cookie、替代 IP:端口等。

其实 DNS 就是一个简单的 KV,你可以把域名解析到任意的 IP 地址,可以是私有地址,也可以是 127.0.0.1。如果你使用 tailscale,因为它使用的是私有地址,所以也可以把某个域名解析到这个私有地址,然后在连接了 tailscale 网络后通过私有地址来访问,别人拿到这个域名也是无法访问的。

STDOUT

Glean 开发小记

这周主要做了一个获取全文的功能,以及一些细节的优化。有了获取全文的功能之后,就可以实现对一些聚合类型的订阅(例如 VXNA)结合之前做的偏好系统进行打分,阅读体验也会更好。

另外,收到的用户反馈不少是关于部署太过繁琐的。这也是我没考虑好的地方,其实项目本身通过一个 docker compose 就能部署,但是我觉得管理后台和向量数据库这些东西都不是必须的,所以就做成了可以简化的部署方式。即使有 AI 帮我撰写文档,对于一些用户来说认知成本还是很高。有时候给用户太多的选择,不如帮用户做好选择。所以下一步可能会针对部署做一下优化,简化部署的方式,也会加快一下 SaaS 版本的上线,方便更多人用。

MISC

python-readability

项目链接

用来获取一个链接中的正文、作者等结构化信息,也是 Glean 用来提取正文用的工具。这类东西最经典的用途就是浏览器的「阅读模式」,需要识别出文章的正文,去掉网页中其他的无关元素。

trafilatura

项目链接

也是一个提取正文的包。本来一开始使用的是这个,star 更多,看起来也更好。实际使用的效果提取出的 HTML 丢结构比较厉害,渲染出来效果很差,所以没有选用。

zxcvbn

项目链接

一个计算密码强度的包。比起传统的规则(例如密码至少有 x 位,必须包含大小写特殊符号),这个方案通过计算破解这个密码需要的时间作为密码的强度,更加先进。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 089 Vibe Engineering

2025年12月21日 20:21

关于本刊

这是猫鱼周刊的第 90 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

这周依然花了很多时间在 Glean 的开发上,内容也不是很多,STDOUT 部分介绍一些开发过程中的心得吧。

STDIN

关于博客开头的 AI 总结

原文链接

最近确实见到越来越多博客在开头的地方做一个 AI 总结,甚至为了模拟实时生成(事实上都是提前生成好的)还做了打字机效果,确实觉得很喧宾夺主(这也是 folo 最近的更新让我很难受的地方)。

作为创作者,我很认同作者说的 AI 总结应该作为「预告片」,而非完全概括文章的内容。你的期望是这个总结能够吸引读者的兴趣,尽可能读完你的文章,而不是期望读者读完就走,那你洋洋洒洒码的字算什么?我会用 AI 给周刊做一段 120 字左右的简介(120 字也是微信公众号的平台限制),有时候会手动编辑一下,使它更加适合我的风格。如果你要做 AI 总结,我觉得限制字数就是一个不错的方式。当然还有其他的东西需要考虑,例如展示的样式不要太抢眼球等等。

(博客加了雪花动画,还有一个会动的雪橇,指针也会变成圣诞树,可爱捏!)

是「登录」而不是「登陆」

原文链接

作者把这种行为称为「差不多主义」。

只要对方能看懂,写哪个字似乎并不重要。

说来好笑,这真的是我日常工作中最为困扰的问题,打错字只是一个最显眼的表象,更多的是逻辑没有梳理清晰。这种没有消歧、逻辑混乱的信息经常会使我 panic,我需要反复跟对方确认,如果对方一直不能给到我满意的清晰答复,会很影响我的心情。然而,我发现别人似乎对这个情况没多大的反应,他们会很「有耐心」地去别人的工位上,或者语音电话,一点点聊清楚。

我很讨厌这种工作方式,尤其是基于线下沟通、反复核对,明明一开始文档写清楚就完事了,还得拉个会议或者到别人工位上去讨论大半个小时。相对地,如果是我主导的工作,我一定会写很清晰的文档,在钉钉/邮件上也会做到言简意赅、逻辑清晰无歧义。这对我来说是比「对一下」更加轻松好办的事情。

窃听的基本原理!无间道之后最好的港产警匪片之一 | 漫谈《窃听风云》【01】港影十级学者

视频链接

《窃听风云》的解说,一共三期,一期半个小时左右,很深度解析了电影里面的情节以及里面用到的一些窃听的技术等,对股市以及资本可以如何操控股价的解说也很有意思。这也是我觉得电影比短剧、电视剧等体裁更有意思的地方,它是比较严肃的创作,好的电影在剧情上很值得推敲,更别提镜头设计等等,有很多耐人寻味的地方。

STDOUT

Vibe Engineering

Vibe Coding 对软件行业其实影响很大,它最实在的地方是可以帮助你完成能力的外延,例如你是设计师,原来只能画一下高保真原型,现在可以通过 AI 把产品 MVP 做出来;如果你是一个熟练的后端,对前端一知半解,原来做不了有界面的产品,或者要拉上一个人组队,现在可以通过 AI 一人成军。当然了,纯粹的 Vibe Coding 其实很局限,基本上只能做出一个很粗糙的 MVP,你会发现很多 Vibe 的产品的特点就是文档很长很详细,但是软件界面比较简陋或者 AI 味,功能相对也比较简单,没有复杂的业务逻辑,给人一种半成品的感觉。

要想实现传统软件开发的优点,例如功能完备、相对地 bug free 等等,其实需要我们在大学里往往当水课不听的「软件工程」。在 Glean 的开发中,我一开始先通过跟 Opus 4.5 聊天,确定产品的 PRD 以及开发路线,把整个系统的功能拆分为数个 milestone,形成第一个文档;然后再通过 Project 功能,把上面的 PRD 文档存在里面,再新开一个聊天,跟 Opus 4.5 确定整个产品的技术栈,指定开发规范等等,形成第二个文档;接着通过这两个文档,逐个 milestone 编写对应的技术方案、测试验收方案等;最后拿着这些文档,在编辑器中让 Cursor / Claude Code 去实现,编写单元测试,修复逻辑、样式问题,并且通过浏览器 MCP 进行测试和验收。

另外一个我很惊喜的地方是,AI Coding 近年来的进步其实不小。从最早 23 年底的时候我做过一版 code review,当时的 GPT 3.5 只能指出来一堆 nitpick,对实际的逻辑 bug 没什么帮助;到现在 Claude 做的 review 已经能一针见血指出一些诸如 race condition 之类人眼难以发觉的问题。所以我现在写完之后都会通过 PR 或者 Cursor 里自带的 Review 让 AI 自己再检查一下自己的成果,我更多专注于在界面、用户体验上捉虫和提要求。

MISC

Anna's Archive

网站链接

Anna's Archive 是一个自由、非盈利的影子图书馆元搜索引擎。它进入我的眼球是因为最近的两个更新:

其实这个东西还挺「灰色」的,它的大多数资源其实都是「盗版」,它通过存储元数据的方式避免了存储受版权保护的内容,但实际上是完成了版权内容的分发。从另一个角度来讲,如果你认同「知识应该全免费人类共享」,那它正是那个理想主义者。

ProxyCast

项目链接

可以把某个订阅提供的 AI 额度转成标准的接口,提供给其他工具使用。有点担心会违反 TOS 导致封号,不过功能确实深得我心:我有 GitHub Copilot 的订阅,给的量还挺多,但是因为主要用 Cursor 和 Claude Code,这个订阅长期有点浪费掉。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 088 两个 Linus 的史诗级会面

2025年12月14日 23:25

关于本刊

这是猫鱼周刊的第 86 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

这周因为很多时间花在 Glean 的开发上,看的东西不多,所以周刊的内容相对也少一点。

STDIN

Cursor × Figma 技术调研

原文链接

早就有闻可以通过 Figma 把设计稿通过 MCP 让 AI 写高保真代码,这篇文章算是走通了整个流程,并且给出了实验的结果:在传统 XML 项目中无法完美还原 UI,但是作为自动化的辅助有一定的价值;如果需要实现完全的自动化,需要设计侧和开发侧配合使用一定的规范。

我觉得这跟我之前提到过的「AI 友好」的概念很类似,就是尽量使用结构化、规范的方式去跟 AI 沟通,尽量使用业界通用的做法(例如一些软件工程的实践),注重文档工作,这样能够使 AI 的表现更加符合预期。写到这里我觉得比起 AI 这更像是管理学的延伸,毕竟所谓「软件工程」的很多实践,设计之初就是为了让水平参差不齐的工程师输出标准化、相对优质的结果。

【官方双语】真·Linus 来了! - 为 Linux 之父 Linus Torvalds 装机 / 两莱一机#linus 谈科技

视频链接

科技界的两大 Linus 的史诗级会面!说是装机,更多是一个访谈,整个视频时长很长,就挑我印象比较深刻的一个点谈谈:Linus Torvalds 提到,他只会使用 ECC 内存,因为他需要更高的稳定性,如果出现什么 bug,他不希望在硬件上找问题。

我觉得这是抽象思维的体现。他主要做内核的开发,在这种抽象下,他的期望是硬件会正常工作,如果出问题,一定是在内核上。试想如果你遇到一个 bug,查了半天软件的实现,结果确实硬件掉了链子,那真的很蛋疼。

这一定程度上也反映出为什么感觉「差不多」的硬件,企业级的就是要比消费级的卖得贵,这额外付出的成本就是在稳定性上。这个原则其实也很适用于搞 Homelab,我自己是个比较狂热的 Homelab 爱好者,近年来我在选购时会更加愿意购买大牌成品方案而不是买更加性价比的品牌或者捡垃圾 DIY。你在出问题时付出的时间金钱成本,甚至造成的损失,很多时候不如一开始就搞一个靠谱的方案。

【官方双语】家用影音格式进化(?)史 - 用十种不同格式重看《第一滴血》#linus 谈科技

视频链接

还是 LTT 的视频。这个视频从 VHS 开始重新体验,一直到蓝光,覆盖了几十年里全部家用影音格式。除了在市场上算是胜出的 VHS、DVD、蓝光以外,原来还有很多不知名但其实还挺有意思的产品。

我不清楚各位读者的年龄段以及经历,我记忆里使用得比较多的是 VCD 和 DVD,那时候盗版满天飞,十几二十块就能买到一张影碟。那个时候不管是 VCD/DVD 播放器还是光驱都非常流行,而且带刻录功能的光驱就很 fancy。到稍微后来(06 年之后),宽带普及了,光碟这个媒介就渐渐消失了,到 12 年我第二次装机的时候,就已经没有再配光驱了。

这条跟上面一条其实还有点关联。最近我三四年前组的蜗牛星际开始出问题了,以为是电源坏了,结果换了电源还是不行,一直重启,拔掉几块硬盘后倒又能稳定运行,我估计是硬盘背板坏了,造成供电不稳定。这也是我说最好不要搞这种 DIY 的方案的原因,它的散热风道设计很差,机箱里面积灰非常严重;而且由于使用 AC 电源(一般大牌都使用外置的 DC 电源),电源这种易损品更换起来非常麻烦;没有保修这一点就不提了,坏了之后能不能修全凭运气,数据能恢复多少更是没有保障。言归正传,它上面还有一些没有遵循 321 原则的数据,于是我就重新考虑了一下冷备的方案。看了这个视频,我发现原来蓝光光盘原来还广泛用于数据归档,有专门的档案级光盘,可以实现 20 年以上的数据存储,更加有千年盘这种号称能长期保存的。对比我之前了解的 LTO 磁带,使用上更加简便,macOS 甚至系统自带刻录光盘的功能,而且基本上都是免驱;成本也相对更低,考虑到我的数据量 ~500G,单张 25G 档案级蓝光光盘大约 40 元,整体成本在 1000 元内,再加上机器成本,大概也就 2000;如果使用 LTO 磁带,这个价钱只够买一套机器,以及一两盘带。

STDOUT

Glena 的智能列表功能

分享一下开发中的「智能列表」功能。之前的周刊就提到过,我想打造一个基于反馈的个人偏好系统(via link),帮我过滤掉一些没意思的文章。下面就是这个系统的雏形:

在阅读的时候,你可以根据自己的喜好,给对应的文章标记喜欢/不喜欢,以及收藏的行为,都会影响最后对你偏好的判断。一方面,系统会把每篇文章向量化(相当于理解文章的语义,得出文章的特征),计算你喜欢以及不喜欢的向量(可以视为你的偏好的特征),通过计算特征的相似度判读你对文章可能的喜好。另一方面是统计模式,会记录你对订阅源和作者的偏好,也作为一个调节参数。可以看看图片中的 demo,我常读的 So!azy 的文章就排到了前面。

这个功能目前还有一些最后的交互细节需要打磨,完成后就会上线。如果你对 Glean 感兴趣,不妨关注一下,给我点个 Star,又或者可以加入 Discord 谈谈。

MISC

simticket

网站链接

一个由日本火车爱好者做的生成火车票面的网站。之前就知道有「火车迷」这么个群体,他们会研究火车线路、拍火车、坐特定班车收集对应的火车票等等。之前纸质车票被正式取消,所以有人做了这么个网站来生成纸质车票。

说到这里,有点怀念以前的红色火车票,以及坐广州站出发的绿皮卧铺,摇晃十几个小时去旅行,那种新鲜和激动的感觉。现在经常来往广州南和深圳北,高铁坐到烂,反而是有点麻木了。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 087 做一个 RSS 阅读器

2025年12月7日 19:35

关于本刊

这是猫鱼周刊的第 88 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

这周还是没有图。自从进了胶片的坑,出门要么不带数码的,要么带了也不拿出来拍。而一卷有 36 张,经常一次拍不完,又想等囤起来一起洗了,所以很久都没出什么图。

这周主要很多时间精力花在一个新坑上,起因是最近 Folo 团队裁员,裁掉了最核心的两位贡献者,而且发布了所谓「正式版」,加上怎么都关不掉的 AI 功能,实在让我觉得非常难受。RSS 阅读器这块我从一开始的 Reeder(Classic)到 NetNewsWire 再折腾到 Follow(Folo),来回折腾其实都只是不一样的界面,功能上没有什么特别亮眼的,也没有能针对我的信息获取工作流做优化的地方。于是我决定写一个自己的 RSS 阅读器 Glean,中文名叫拾灵,具体的后面细说。

STDIN

AI 吊牌

原文链接

说的是 AI 厂家在输出最后总会加的口癖(例如「要不要我帮你调整 xxx」)。作者举了几个小学生利用 AI 完成作文、作业,以及老师用来发朋友圈文案的例子。

我上周才提到过,如果把 AI 不加处理地用于教育领域,很容易造成「Shit in, shit out」的局面。小朋友的可塑性是非常强的,稍微「权威」的来源会对其认知产生很深远的影响。我记得以前小学的时候,学写信的格式,结尾一定要有「此致」「敬礼」,老师从来没有解释过为什么,我也理解不了为什么为什么要向信的读者敬礼(即使 ta 就是我的朋友),后来才知道其实还可以写「顺颂时祺」之类的套话,但实际上我用得最多的还是漫无章法的「祝好」、「祝万事如意」、「Best Wishes/Regards」。基础教育因为要面对非常多样性的群体,没法做到很细致,如果你拿着这个问题去问小学老师,一般得到的回答就是「你就记着这么用就行了,别问为什么,没有为什么,固定搭配」。

回到这个 AI 的例子,这里面最为讽刺的是,人把自己的知识蒸馏后训练成 AI,结果 AI 再蒸馏一遍知识给下一代的人,但每一步蒸馏都会有不少损失,所以才说对下一代的人来说,是「Shit in, shit^2 out」 。会不会下一代的人,写作风格不仅充满 AI 味,写出来的文章最后还要加上一句「如果你需要根据自己妈妈的特点进行个性化修改,我也可以帮你调整这篇作文。」?

Go 语言的编程哲学

原文链接

一个初学者角度的 Go 语言印象,以及对一些 Go 生态中常见哲学的理解和解读。我觉得 Go 在我心目中算是排名数一数二的语言,虽然我最近用的 Python 比较多。

首先,Go 是偏见非常强的语言,诸如只有 gofmt 一种风格、不允许未使用的变量、强制错误检查等,一定程度上让代码「规范」了很多。这里的反例就是我最讨厌的 Java,八股里面我最讨厌的一个问题「线程有几种创建方式」,在 Go 里只有一种,就是 go 关键字,不需要考虑茴字到底有几种写法。

其次,Go 在语法上非常简单,也没有复杂的语法糖,不管你的本命语言是什么,读 Go 都会觉得很顺畅。作者举的三目表达式就是一个非常好的例子,Go 就鼓励清晰的 if-else 结构。

还有一点,Go 让我写代码的时候逻辑变得非常清晰,或者说形成了一些良好的思考习惯。比如强制的错误检查,会让你在调用某个函数的时候,仔细考虑它会可能会出什么异常,对于业务来说应该怎么处理;又比如非面向对象的设计,会让你更加好地考虑怎么设计数据结构和接口;以及相对比较「裸」的并发写法,让你自己控制通道和锁,比起 Java 那套奇怪的调度方法好理解得多。

最后不得不说的就是跨平台能力和性能。与 Java 的虚拟机机制不同,Go 在所有平台上都是二进制原生运行的,这点就很无敌。性能方面,Go 的线程就是一个很好的例子,内存占用非常小,这在现在以云服务为主,内存寸土寸金的环境来说非常友好。

我的编程入门语言是 Python,甚至是 Python 2,最早是高中的时候自己搞了点书看。然后到大一学了 C/C++,自学了 PHP、Python 3、JavaScript,大二自学了 Java,大三自学了 Kotlin,后来工作之后又自学了 Go。在见识过基本上全部主流的语言之后,我心目中数一数二的就是 Go 和 Python,这俩也是我最为常用的语言。也许后面可以专门写篇文章展开讲讲我对各个语言的一些印象。

STDOUT

Kodak Snapic A1

Kodak Reto (柯达授权经销商)新出的一款胶片相机,25mm f9.5 广角镜头,固定 1/100 快门,有自动卷片、自动回卷和自动闪光,支持双区对焦、双重曝光,使用 7 号电池供电。

我在小红书上刷到的,看了一下国内贩子都在加价,就直接在官网下单买了,​99 + 3.5 运费,算下来比贩子卖得稍微便宜一点,而且 12.2 发货,第二天就收到了。我买的是白色款,包装里自带一个收纳袋和一条挂绳。

带着拍了几天,简单谈谈使用体验。它非常轻便,操作也很简单,上卷、打开电源,按快门即可。拍照的时候会有一个很轻的快门声,然后就是过卷马达的声音,这个比起手动过卷的机器来说没有拨动过片扳手的齿轮声悦耳,跟其他一些傻瓜机差不多。自带的挂绳很有意思,保证你在扫街的时候可以第一时间拿出来拍。(此处应有伍佰)我觉得胸前挂着相机大摇大摆走还是太张扬了,而且给的绳子有点长,在肚子上晃荡,所以我是绳子挂在脖子上,然后相机踹在前胸大口袋里,也很方便。

因为第一卷还没拍完,所以画质这些也许要等后面洗出来再聊。25mm 的镜头对我来说也是一个挑战,因为我平常惯用 50mm 甚至更长的焦段,25mm 这样一个大广角对我来说有点难以掌握,不过我发现这对于拍摄街景、建筑或者壁画这些东西非常适合。另外,固定 1/100 的快门和 f9.5 的光圈也有点蛋疼,官方的说明里推荐晴天/阴天户外使用 ISO 100/200 的卷,阴天、室内使用 ISO 400 的卷。我第一卷装的是全能 400,我也不确定宽容度有多高,但是拍摄的过程涵盖了阴天和大晴天,到时候看看效果吧。小红书上有不少评论说不如买几百块的二手 PS 机,二手 PS 机我也有,但是真的很难买到成色好,更别说全新的机器,而且 PS 机也做不到这样轻的重量。我觉得它的定位是玩具相机和 PS 机的中间,比玩具相机更好的画质、可以重复装卷,结构比 PS 机简单、成本更低。如果你对胶片感兴趣,我觉得这是一台比较值得入手尝试的机器。

Glean 拾灵

项目链接

前面说到,Folo 的变动,让我决定写一个自己的工具,它主要是一个自托管的 RSS 阅读器 + 个人知识管理工具,主要会有以下的功能:

  • RSS 订阅、阅读
  • 网页收藏
  • 智能推荐 & 偏好学习(根据对已读文章的喜欢/不喜欢反馈,以及收藏行为、对 Feed 和作者的亲和性,计算推荐分数,排序时间线上的文章/过滤分数较低的文章)
  • AI 摘要 / 打标(这个就是很多类似工具都会有的功能了)

所以 Glean 在产品形态上大致是 Folo/RSS Reader + Cubox/Karakeep 这样的东西,相当于是把我平时用来阅读和收藏整理信息的工具整合起来了。这是它目前的样子:

它会采用 OSS + SaaS 的商业模式,OSS 版本跟 SaaS 版本的区别就是 BYOK(Bring Your Own Key,使用自己的 AI) 和平台托管,你可以自建 OSS 版本获得基本上全部的功能,如果自建对你来说太麻烦,也可以付出 AI 的成本来获得对应的服务。

做自己的工具对自己来说是非常满足的事情,除了功能,一些交互细节也可以打磨到自己喜欢的样子。例如阅读界面右边的 Outline 功能,就有非常多考虑:

  • 垂直的进度条,来代替滚动条展示阅读进度
  • Outline 在阅读时会模糊,减少注意力分散
  • 进入文章时,Outline 会保持清晰 5 秒;低速滚动时,Outline 会保持模糊;高速滚动时,Outline 会清晰展示;鼠标悬浮时,Outline 会以比较高的速度变清晰。

另外,这次 Vibe Coding 我也在尝试一种比较新的工作流程,在过程中更多地使用 AI 和 文档,大致是:

  • 基于初始需求,反复细化、确定需求,产生 PRD 文档
  • 基于 PRD 文档,确定技术栈,敲定代码风格等,产生架构文档
  • 基于 PRD 文档和架构文档,拆分多个里程碑,决定每个里程碑实现什么内容,产生开发计划文档
  • 基于上面全部文档,生成对应里程碑的开发方案,包括测试和验收方案,修订后,放到项目中让 Claude Code/Cursor 去实现,并且利用浏览器 MCP 实现自动化测试和验收

这套工作流用下来还可以,开发的效率相对比较高,很多时候只要人工介入一下具体的交互细节就可以达到可用的程度。唯一的缺点可能是烧钱太快了,我的 $20 Claude Pro 和 $20 Cursor Pro 订阅一两天就用完了,Cursor 我升级到了 $60 还是不够用,已经上到 $200 了。

MISC

bililive-go

项目链接

直播录制工具,支持多个平台的直播录制。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 086 走出迷茫

2025年11月30日 18:35

关于本刊

这是猫鱼周刊的第 86 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

INIT

好久不见。上周的周末有事回了趟广州家里,周六当天来回,折腾了一趟实在是太累了,于是就咕咕了。

这周的周刊将会迎来第二次重构,就如上期所说,新的周刊会分成 INIT、STDIN、STDOUT、MISC 和 EOF 这几个板块,弱化掉以前文章、项目之类的概念,更加适应现在周刊的内容。

上周折腾了一个小东西 llmsh,可以利用本地的小参数模型(例如 qwen3-4b),配合 zsh 插件,实现命令补全、自然语言转命令等。做这个东西的来头也很神奇,我在翻东西的时候发现了一张 23 年 gpt-3.5-turbo 刚出的时候的截图,概念是利用 history 的前几条,来预测下一条命令,来实现比 zsh-autosuggestions 更加「智能」的提示。于是,我花了四五个小时搓出了这个东西,它有点像 warp,但是它可以跟你喜欢的终端一起使用,只依赖 zsh 和一个二进制,非常优雅。但是最终我也很少使用这个小东西,原因跟我不使用 warp 这类终端一样,autosuggetsions 的建议足够好用,而且绝大多数日常使用的命令我都能凭肌肉记忆打出。如果你感兴趣,不妨安装试玩一下。

另外这段时间里我学会 3D 建模,给我常用的消毒湿巾做了一个宜家洞洞板收纳,模型开源在 MakerWorld 了 link,感兴趣可以看看。

STDIN

就把自己先搞丢

原文链接

作者谈到自己最近的迷茫:

我好像一直很忙,工作确实很多,但仔细想想,除了工作之外,我似乎也说不清自己在忙什么,更说不清到底什么是重要的。

他也列出了自己很多的不足,又感叹自己总是好像原地踏步,而且这些问题早就意识到,但总是不能聚焦去改进。顺着这个思路,他还进行了很多思考,略微有点进入哲学的范畴了。

我觉得作者应该是跟我差不多年纪,刚毕业几年内的人,因为我不久之前也有过同样的迷茫,而我现在好像已经渐渐走出这个迷雾了,分享一些我的观点。

首先需要肯定的是,有这种迷茫是好事,说明你还在一个反馈循环里面不断提升自己。在日常工作中,会遇到两种人:一种是埋头苦干的人,这种人是大多数,这里的「埋头苦干」不是指在工作中的态度,更多是说他的认知更多就停留在毕业时或者第一份工作的程度,不会再去跟进行业的发展,不会再学习新的东西提升自己,在工作中对自己也不会有很高的要求,目标多数是赚钱,很多事情就是得过且过;另一种是有远见的人,他会有自己的主线,会追求自己感兴趣的事情,坚持走下去自己规划的路。所以如果你感觉到迷茫,反而是一种好事,说明你还没完全躺平。

然后要说的是,感到原地踏步,或者说一时做下这个又做下那个,在把时间拉长之后,其实也是不小的进步。离开学校之后,会发现很多东西在很短时间内是无法看到结果的,可能要拉长到年甚至数年才能看到效果。乔布斯在斯坦福的毕业典礼演讲上说过一句话叫「Connecting the dots」,我对它的理解就是,在人生路途中你会做出很多选择,或者做了很多的事,很可能在当下看不出有什么用,直到有一天你取得了成功,才发现原来这些点连成了你的成功路线。例如今年五月份的时候我就买了 3D 打印机,当时就打算要学建模,自己打东西玩。结果过去了半年,因为健身房新的跑步机没有手机支架,总是坚持不下去走有氧,有天我在跑步机上怒看了一个多小时视频,回家就把模型画出来了。在这中间,我其实把一大堆兴趣轮询了一遍,例如胶片摄影、模拟赛车、meshtastic 等等,我很少长期专注去做某一件事,也许周刊算是一个,但「兴趣轮询」算是最适合我的一种模式。另外,作者说到自己是「问题驱动」的人,我也是,我不喜欢系统性去学习某个东西,我一般遇到某个问题之后,我会去研究相关的东西,但只限于刚好解决这个问题。时间拉长之后,你发现你有很多点,每个都可以解决一定的问题,这在遇到复杂的问题的时候,你会发现自己会比别人更快地能把这些点连成线,看出某个 bug 的本质,找到对应的修复方案,或者在复杂的需求中提出一个很优雅的技术方案。

顺着「兴趣轮询」说下去,清晰认识自己、发展出适合自己的处事模式也很重要。我从小到大都被老师说不专注,现在在工作中更经常会发现,在准备去解决一个问题的时候,发现了另一个兴趣点,于是又花了大半天在这个新兴趣点上的情况。也做过一些在线测试,说是有一定的注意力缺陷。在这件事情上,我觉得这更多是我的 feature,而不是 bug(毕竟并没有严重到影响我的工作和生活)。因此我围绕这个 feature 发展出了很多效率方法,例如使用 todo list 来保存一些上下文,方便我来回切换和找回重点;又例如我会把一些繁琐的步骤用脚本自动化或者在设计上就简化,保证我不需要花很多精力去重新理解等等。

最后就是,今年一场大病之后,我发现自己做到了「见攰就唞」(觉得累就歇歇)。以前我经常会有爆肝的心态,很着急出结果。现在更多觉得如果已经累了,那就先歇歇,才有更多时间精力甚至健康的身体去做想做的事情。

今天这个部分写得好长,算是记录自己走出类似的迷茫的经历。

“我们本可以问 ChatGPT”:学生对由 AI 教授的课程发起抗议

原文链接

英国一所大学对学校使用 AI 制作课程,包括 PPT 和配音都是 AI 制作,引起学生的不满。

我觉得如果 AI 大量应用于教育领域,会对人类产生一种钳制作用。人的大脑跟 AI 有一点是类似的,那就是接受一定的输入,产生输出,然后根据反馈做出调整。因此人其实也会受到 AI 在训练语料上遇到的问题,「Shit in, shit out」,学习了太多低质量语料导致效果不佳。从我知道的来说,连小学生都在用 AI 来批改作文了。会不会从 10 后或者 20 后开始,人类写的文章就是 AI 味的?

AI 编程真正的问题

原文链接

作者提到,在 AI 编程推广之后,更大的问题是「理解债务」(comprehension debt)。AI 能很快的写出一大堆代码,而使用 AI 编写这些代码的人因为没有经历完整的思考过程,这些代码实际上并不「属于」他们,很难真正理解;在出现问题的时候,只能利用 AI 去解决,很容易陷入死循环中,让事情变得更糟。

这个事情我深有同感,在 你不是在 vibe coding,而是在十倍速生成屎山 中我就提到:

一旦你开始 vibe coding,你就只能 vibe 到底了。

所以其实 AI 编程并不是一刀切的就一定能提升开发的效率,其瓶颈依然是使用者的认知上限,也应了我经常说的那句:

AI 决定下限,人决定上限。

STDOUT

The Seat

IMDB

讲的是 F1 运动历史上第三年轻的意大利新秀 Kimi Antonelli 获得梅赛德斯车队席位的过程,一部 40 分钟的短纪录片。出道一年不到就有一部自己的纪录片,小 Kimi 真是有点东西。

说到 F1,它除了是顶级体育赛事,在比赛周之外就是超大型的真人秀,官方都有不少节目,也有合作方例如 Netflix 的电视剧,以及相关的电影、纪录片,还有无数围绕 F1 话题的视频、帖子,而且也有对应的粉丝、周边等等。作为 F1 车迷,真的可以每一周都很充实(只要别看法拉利)。

MISC

VideoCaptioner

项目链接

一款基于大语言模型的视频字幕处理助手,支持语音识别、字幕断句、优化、翻译全流程处理。

TrendRadar

项目链接

多平台热点聚合 AI 分析工具。

PySceneDetect

项目链接

视频镜头分割工具,可以当成 Python 包使用,也可以通过命令行使用。

EOF

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 085 标签页焦虑

2025年11月16日 20:38

关于本刊

这是猫鱼周刊的第 86 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

好久不见。前两周比较忙,内容也不多,所以就没有写周刊了,也算是给自己放一个小假。

这张照片其实摄于一年多以前,在西乡红树林公园外的一个大草坪。这张算是我后期得比较多的照片,重新裁剪了一下让人占画面大概 1/3 的位置,然后拉暗了暗部的曝光增强剪影的效果。

这周水了一篇文章 Docker 服务器磁盘满排查思路,也是吐槽了一下现在在用的博客系统 Halo,最近博客频繁的访问不稳定,就是拜它所赐。过了几天才想起来,原来之前就写过一篇类似的 排查 Linux 空间占用,不过这次更加专注于 Docker 造成的空间问题和排查。

文章

关于影视飓风近期舆情

视频链接

我强烈建议你先观看一下从没想过的问题?!影视飓风 1400 万粉丝 Q&A! 这个原视频(至少看完相亲角部分的完整片段)再去看这个舆情解释视频,以及网上的各种评论。

不得不说,我看这个 Q&A 视频是因为在小红书刷到了很多关于「相亲角」的讨论,才去 B 站看了。我很赞赏影视飓风,但也算不上死忠粉,所以这类粉丝向的节目本身我不太感兴趣。视频看下来我都没觉得有什么问题,「初中学历」这个东西纯粹是整活,而「离异」这个也是事实,本质是整一下活,我没想到,我觉得 Tim 和他的团队也没想到,这居然能被人用来作为矛头攻击他。

利用矛盾制造情绪是自媒体获得流量的基本公式,而任何二元对立的事情就很容易用来制造矛盾激化情绪,例如贫富、性别等等。视频中说到,很多营销号就用「抽象化切片」来编一个离谱的故事激化矛盾。这是个非常操蛋的逻辑,但是偏偏平台和用户都很喜欢。另一个博主说到

平台和舆论很傻逼怎么办?没办法。傻逼的共识也是共识。

无独有偶,之前 LTT 也陷入类似的舆论中。说实话,我觉得人无完人,我们不能要求公众人物个个都像圣人一样完美,更没必要反过来竭尽力气去挖人家的污点,这真的很「饭圈化」。

写到这里我想起我好像不是第一次谈这个话题了,今年初的时候,还是影视飓风,当时是跟评测相关的(via vol. 062)。我觉得影视飓风可以称得上国内版的 LTT,他们的商业模式很像,内容大部分也都非常对我胃口。之所以谈到商业模式,是因为在 LTT 公布过他们的收入组成,以周边售卖为大头,辅以赞助、广告等等;影视飓风我感觉也是类似的形式(他们的电商做得很不错),服装、电子产品都有不少原创的设计,我也买过不少;唯一有区别的可能是影视飓风还有一些视频制作相关的商单。这种商业模式的好处显而易见:

他们收入的大头不是广告推广,不是独家内容,而是售卖周边。我觉得这种变现方式就非常地健康,大头是周边产品售卖,热情的粉丝团体,为他们的创意且实用、有品质的产品付费;另外一边,多元的赞助商、广告位等,让他们不需要拍厂商的马屁,拥有相对的「评测自由」。

做评测的里面,顶级头部以及尾部博主其实都比较容易说实话,核心原因都是不需要拍厂商的马屁。腰部博主不好说,谁给得钱多就向着谁就完事了,哄不好金主就没饭开,「被包养就不要谈什么独立人格」。

反馈的重要性

原文链接

很有共鸣。作者说到他在工作中极其需要反馈,包括业绩上的正反馈、负反馈,来自朋友同事的看法等等,而没有反馈则是很可怕的事情。

我也是一个很看重反馈的人,我在唱 K 的时候都会时不时降低音量确定自己有没有跑调。这倒不算是缺乏自信,我觉得这是一种提升自己的方式。当然读完这篇文章我也有一个新的想法,就是负反馈也是有益的,也比没反馈要好;但是这点很难去要求别人,没人喜欢说坏话。

想法

A House Full of Dynamite

在 Netflix 上看的一部电影,拍摄手法很有意思,从一件事的不同人的视角去展开,整部电影被分为好几章节,一个多小时,但是只对应世界时间线里的十几分钟,从一个未知来源的核弹发射到总统决定反击计划的瞬间。最神的是,一开始已经过了一遍整个故事,最后到那个总统决定反击计划的瞬间戛然而止,什么规模的反击、核弹有无爆炸、世界是否核平没有交代,原本剧情会像正常电影一样,全面反击,全球核平,但是从后面的章节开始,又换了一个视角,补充了前面没有交代过的一些信息,每个主角在其中的态度、反应刻画得更加细致。而一开始我很关注的世界核平到底有没有发生,到最后都没有交代,是个开放式结局。

(好像是周刊第一次推荐影视类的东西,为了不剧透写起来感觉有点混乱,欢迎留言反馈)

标签页焦虑

你的浏览器有多少个打开的标签页?我的可能有上百个,这已经给我造成了一定的焦虑,也一定程度上是我没有更新的原因。这些标签页,有的是我看了标题觉得感兴趣的文章,有些是觉得稍后需要参考的文档,还有一些感觉有意思想研究一下的项目、网站等等。但是一个现实是,如果用游戏中的耐力条来类比就是,人每天的总的精力是有上限的,恢复的速度也很慢(需要足够的休息、合理的饮食等),而每做一件事、看一篇文章、理解一个项目等都需要耗费不少的精力。现在的情况就是,我感兴趣的事情远大于我精力的上限。

道理我都清楚,其实没必要太纠结有没有深入去读一篇文章,纠结有没有错过什么,但是执行上有点难。Arc 有个很好用的功能,可以自动归档大于某个时间的标签页,我现在设置的是 30 天,我在考虑改到 7 天。如果一件事情,一个星期我都没时间去做,它显然不紧急,也很可能并不重要。

写到这里我删掉了下面的「项目」栏目,好像也是第一次周刊不推荐开源项目。如果非要我找的话,其实也还有存货,但确实没有想写的。周刊写了一年多,开始的时候很专注技术,最近发现近期周刊其实更多去分享生活,我自己最近也没有那么完全专注于技术了,也挺好。周刊的结构其实也想改变一下,初步想法是分成三块,一个输入的部分分享我看到的文章/视频等等,配上我的一些看法;一个输出的部分分享完全我自己的思考或者感想,也推荐一些书影音或者购买的东西等;还有一个栏目分享项目/工具/网站等等。稻草人周刊有个类似的结构,分别叫连接、当下和星群,蛮有意思。我在构思的命名是 INIT、STDIN、STDOUT、MISC、EOF,不知道大家有没有更好的意见,也许下周就能迎来这个重构。

工具/网站

Affinity

网站链接

Canva 收购了 Affinity 之后,Affinity 本体免费了,AI 功能可以通过 Canva 会员订阅使用。Affinity 算是 Adobe 的一个下位替代,本期头图就是用 Affinity 的 Raw 编辑功能导出的。这对业余创作者来说算是一个好事,比如我很少对照片做精修(不拍人像),核心就是裁切和调色,使用频率还很低(直出居多),所以单独为这个需求买正版的 Adobe 有点冤大头。

Grokipedia

网站链接

使用 Grok 重写的 Wikipedia。这种方式我觉得有点像 Simple English Wikipedia,其是一个用简单的单词、句法等来编写的百科全书,方便英语学习者、学生等阅读。到这里我有个想法,为什么不用 LLM 来补充 Simple English 的 Wiki 词条呢?

LLM 驱动的在线词典

网站链接

思路跟前面的 Grokipedia 类似,用 LLM 生成词条。作者的思路可以看这篇文章,挺有意思的。

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

Docker 服务器磁盘满排查思路

2025年11月11日 16:43

最近博客频繁出现不可访问的问题,但因为最近没怎么在写文章,所以倒没怎么管,直到收到博友圈发来的邮件:

登上去一看,发现服务器的磁盘居然满了(之前出现过内存满的情况,重启一下 Halo 的服务就能解决)。因为这台机器上都是用 Docker/Docker Compose 启动的服务,所以自然只需要去考虑 Docker 的问题。

当然,在这之前也是先用 df -h 看了一下,全都指向 /var/lib/docker/overlay2/xxxoverlay 这样的东西,所以能确定是 Docker 的问题。如果占用大的在其他目录,那就稍微复杂一点,可以用 du -h --max-depth=1 一点点去排查。

overlay          79G   57G   20G  75% /var/lib/docker/overlay2/89ed74e70d3e59b7c5de6e53522eece539a74e013c9c03c76fc7ac4d73045ed7/merged

其实到这里我就懵逼了,这些服务都没什么会落盘的,不应该一下产生很大的数据才是,所以找了 AI 帮忙,它建议我先运行:

docker system df -v

这里提醒了我两个问题,一个是我有很多镜像没有清理,二是有些卷没有清理,于是先执行了下面两条命令,先释放一点空间。这两条命令都只会清除没有使用的镜像和卷,所以是比较安全的。这一步清理掉了几个 G,但是磁盘还是很满。

docker image prune -a
docker volume prune

于是让 AI 帮忙写了个脚本,查一下到底是哪个容器的卷占用空间大:

echo "VOLUME_NAME                              SIZE       CONTAINER(S)" && docker volume ls -q | while read vol; do size=$(docker volume inspect $vol --format '{{.Mountpoint}}' | xargs du -sh 2>/dev/null | cut -f1); containers=$(docker ps -a --filter volume=$vol --format '{{.Names}}' | tr '\n' ',' | sed 's/,$//'); [ -z "$containers" ] && containers="<unused>"; printf "%-40s %-10s %s\n" "$vol" "$size" "$containers"; done

最终找出来是 Halo 的容器。AI 建议我先考虑是容器日志的问题,用下面一条命令发现确实,于是又重启了一下容器,果然空间就被释放了。

find /var/lib/docker/containers/ -name "*.log" -exec ls -lh {} \; | sort -k5 -hr | head -10

但是这个方法治标不治本,它还顺便给我提出了限制日志大小的方法:

Docker

# 启动时添加日志选项
docker run -d \
  --log-opt max-size=100m \
  --log-opt max-file=3 \
  [其他原有参数...]

Docker Compose

version: '3'
services:
  your-service:
    image: your-image
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"

全局设置(针对所有新容器生效)

# 编辑 /etc/docker/daemon.json
cat > /etc/docker/daemon.json <<EOF
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
EOF

# 重启 Docker
systemctl restart docker

至此,这次磁盘爆满的问题就解决了。

番外

因为 Halo 老是出现 OOM,所以其实这次日志把磁盘写爆是因为 Halo 的问题。一看有一个新版本 Release,说是解决了潜在的内存泄漏问题,更新完好像就再没出现 OOM 的问题了。

我在关于页面里说过,选择 Halo 是因为它丰富的插件生态,完善的主题,还可以的性能,以及部署和发布的便利,现在我倒有了一些微词:

  • 专业版发布之后,不能再付费购买插件,必须购买专业版(现在也不能买断了,只能订阅)
  • 性能方面真的一塌糊涂,Java 的技术栈导致一个博客就吃掉了 0.5 G 的内存(之前有问题的时候甚至飙到了 1G+),这对内存寸土寸金的服务器来说简直是噩梦
  • 版本发布后经常有严重的恶性 bug,这完全不像是一个开源转商业项目该有的稳定性
  • 很多插件经常一连几个月都不维护,一般主程序改了点什么才会顺带维护一下;新出的插件也不怎么感兴趣,有点花里胡哨的

最近也看了不少设计优秀的独立博客,自由度高很多,也更方便发挥,更多东西可以折腾,再做一个自己的博客的念头也慢慢浮现,也许呢。

猫鱼周刊 vol. 084 骑友巴士

2025年10月26日 19:36

关于本刊

这是猫鱼周刊的第 85 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

这周终于又有头图。摄于深圳大梅沙滨海栈道,海水有时候是绿色,有时候是蓝色。沿着海岸线骑行,抬头一看外面海水闪闪发光。

这周没有太多别的产出,工作上的事情又开始多且有趣了一点,摸鱼时间少了一点,所以这期周刊大概也会稍短一点。

文章

DynamoDB 服务在 US-EAST-1 区域中断事件总结

原文链接

这周最大的事情可以说是 AWS 长达十几个小时的服务中断。是时候祭出这张图:

关于这个事故报告,网络上有很多解读,感兴趣可以自己找来看,我只谈谈我的想法。

第一个是「时间攻击」,也就是时间因素引起的 bug。这里有两个点都可以归到时间上,第一是「竞态条件」,这个是写并行程序中经常会遇到的问题,由于我们思考基本上是串行的,没有特地考虑并行的运行情况就会出现这个竞态条件。第二是「延迟增加」,我们通常认为一个操作可以「很快」完成,没有考虑过如果这个操作超时或者需要比较长的时间才能完成时,整体的逻辑是否还能成立。

还有一种时间因素这次没有出现,就是「定时」,这种更加隐蔽,但是更常见于业务系统中。例如某几个时间点数据会与预期不符,导致下游出错;或者更加干脆就是计算一个月前等逻辑,遇到特殊情况(go 的 time.Add),测试通常没法发现。

第二个是连锁反应,这是基础设施相互依赖、架构复杂的结果。从一开始的 DNS 故障,引发数据库故障,再到下游更多服务受到故障影响出现更多问题,作为下游的更多互联网服务更是也因此受到波动。架构越复杂,越容易被简单的问题拖垮。如果你的业务非常简单,可以考虑不要太过依赖云服务。

然后说说事故处置和 vendor lock-in 的问题。很多人觉得 AWS 「基本不可能出问题」,所以事故处置方案中根本没有考虑过这个,服务不可用的时候就完全瘫痪了。又相反地,有人在这次事故之后觉得需要做「多云部署」。我觉得这两种都不太可取,我的思路是参考这次的事故,审视自己架构中依赖了 AWS 的什么服务,如果其中某个服务故障,会对什么有影响,有没有方法减轻影响。当然,就算做了这些,很有可能还是会被一锅端,只是有预案的公司不会手足无措,在恢复时间上拉一坨大的。

Kindle 中国拾遗

原文链接

说的是 Kindle 退出中国后,国内电子书生态和体验的问题。

在 Kindle 退出中国之后,国内平台只能走「低价包月」的路线,进入了一个恶性循环,导致出版社不愿意上新书,平台内容质量不断下降。反而直播带货还能卖出去不少实体书,所以出版社还比较有意愿发行实体书。另外国内的平台,包括微信阅读,都是以网文为主,严肃创作居少。

我不是网文的受众,当然我一年也不读几本书。我有 Kindle,找盗版书这件事对我来说倒也不算复杂,但是在 Kindle 还在国内运营的时候我会在商店买书,因为买到的排版好,而且省事,加上支持正版的思维。后来 Kindle 退出之后,会发现找新出的书特别困难(这点文章里也提到了,很多盗版来自于破解 DRM 后的 Kindle 商店版本)。到现在,我如果想要看某本书,还是直接去买实体书划算,很多畅销书只要二三十块就能买到,何苦折腾。

车祸 VIII

原文链接

关于「提升电动车品牌效应」。

国产品牌很喜欢在技术以外的领域发力,例如公关、宣传,但就是不愿意在技术上多下功夫。我觉得道理很简单,价格战,加上公关宣传这些花销比技术研发低得多,所以现在的样子已经是「最优解」。

之前有不少关于新能源车的评测,也有不少人针对这些评测做很多争论。不知道诸位还记不记得罗永浩跟王自如的辩论,在评测中想要有点「倾向」实在再容易不过。现在做购买决定越来越多噪声,要做出理智的决定真的越来越难,很多时候还是很会倾向于自己喜欢的品牌。

想法

骑友巴士

深圳新出了「骑友巴士」,从市区到市内较偏的骑行点,人车一起上公交,定点发车,票价 20 元,周末开行。上车后,师傅会帮你固定好车,然后就是摇摇晃晃穿过市区几个站点(基本上除了终点站没有人上下车),然后到达终点。

这个设计非常好,有点像 2077 里面「跳过行驶阶段」的功能,直接到任务地点。在城市区域骑行真的很痛苦,非机动车道没有或很狭窄,在人行道上坑坑洼洼颠得手痛,要一直避让对向的电动车和路上的行人。而且像大梅沙,离宝安几十公里,以我的体力,骑过去可能就已经废了,更别提在那边骑长上坡,返程估计只能货拉拉。

接着说大梅沙骑行的体验,全程都有绿道,精华的一段维护得不错;后面有很长一段骑行道就没有专门的绿道了,要跟机动车共线,又很多急弯和长上坡下坡,有点危险。路线说是可以一直骑到大鹏那个最美 711,一共 35km,但是我骑了十几公里,经历一大堆连续上坡,心率连续拉满之后,就知难而退了。巴士站点附近有便利店和饮食,有个麦当劳,在里面边吃边等车的时候遇到了不少骑友。知难而退的路上还遇到了两个骑友,也是体力不足知难而退了,大家路上一起推了段车,聊天吹水,也很有意思。

项目

migrate-to-uv

项目链接

我受够 poetry 了!这句话说出来有点好笑,因为我去年初才把原来的 pip 和 conda 等转到 poetry,还写了篇文章

其实 poetry 也很好用,只是比较慢,而且 poetry update 的逻辑实在太诡异了,没法做到像 go get -u的效果。

这个项目可以把 pip 和 poetry 等项目迁移到 uv,好耶。

blind_watermark

项目链接

一种水印方法,可以抵抗旋转、裁剪、马赛克等编辑。

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 083 扫街友好城市

2025年10月19日 20:11

关于本刊

这是猫鱼周刊的第 84 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

距离上次出门拍照又有一个多月了,这周还是没有头图,实在是有点苦恼。上次大芬油画村多少有点「诈骗」,坐一个小时地铁过去,看一个城中村,而且深圳就不乏这种虚无的「打卡点」。

下周五是 1024,「程序员节」,这里祝各位程序员读者节日快乐,bug--。

这周有一篇「产出」,这篇文章的来历有点神奇:在大概一年前,我因为做剪辑相关的工作,接触到了 FFmpeg 以及硬件加速相关的东西,在中文搜索结果里没什么人提到,有的文章也比较旧,只考虑到了 Intel 的 qsv 和 Nvidia 的 NVENC,没有 AMD 的 amf 和 Apple 的 VideoToolbox,正好当时折腾这个能适应不同平台自动启用硬件加速的功能,所以在博客的写作列表上列了。结果这篇文章一咕再咕,直到最近这个项目重新捡起来,于是我尝试用 Claude Code 结合我的代码库,帮我写成了这篇文章「FFmpeg 硬件加速小记」。

我在文章开头标明了「本文有 AI 参与编写」,之所以不说「由 AI 生成」,是因为文章的核心思路、代码都是以「我」为主导,是我自己思考得出的。

这种创作方式还挺有意思,因为很多时候在写完某个功能之后,会有很强的欲望想分享自己实现的方案,但是重新总结形成文字又是很消耗精力的过程(所以这篇才会被我拖了接近一年)。提供思路(文章大纲和代码),让 AI 代劳文字组织的过程,至少能形成一篇像模像样的文章。这跟「由 AI 生成」最大的区别就是,如果你让 AI 「写一篇 ffmpeg 硬件加速的文章」,这是没有你的功劳的。

文章

我为什么厌恶 Sora?

原文链接 1
原文链接 2

一共是两篇文章,分别从创作者和受众的角度评价 AIGC。有些观点很耐人寻味:

快消层面的内容或许将会被 AI 完全替代,而深度哲思的部分仍然(暂时)归人类所有。

AI 替代的不一定是所有创作者,但一定会替代的是不再愿意创作的创作者。

重新理解 AI 的功能性,它是放大器,而人可以作为源头,只要源头保持流动性,AI 就无法彻底取代你。

他的思考很有深度,感兴趣可以看看原文。

在「受众」这一块,我每周大概会读到上百篇有长有短的文章,但是我从来不用 AI 去做什么「摘要」之类的事情,其实摘要在筛选「有兴趣的引发思考的」上有种多此一举,我往往在打开网页,看完标题和首段或者大致扫过整篇文章的结构之后,我就有定夺我是否感兴趣看完(参考Yay or Nay)。「节约时间」的论点其实不太成立,读完一篇表达流畅的文章通常也只需要几分钟,比起作者创作的数十分钟至数小时、数天来说算是一种基本的尊重。

作为「创作者」,我的核心原则是「原创性」,我始终觉得 AI 无法提出真正「原创」的东西。但是在创作的时候是否应该使用 AI,或者说使用 AI 辅助创作是否会失去这种「原创性」,我觉得没有简单直接的答案。在头条的例子中,我其实做了大多数原创的检索和思考,这跟简单让 AI 「写一篇 ffmpeg 硬件加速的文章」是不一样的。

背包三年,我的旅行装备清单

原文链接

很喜欢这种「好物推荐」类型的文章,当然这种类型已经被各种商单泛滥,所以看到这种认真在推荐的会觉得更有意思。

我之前也考虑过在周刊中加一个好物推荐的栏目,不过不是每周都会购物,写集合的文章我又懒得写,所以偶尔买到好的东西我会在「想法」的地方推荐一下(例如Quote/0CyberBrick拓竹 P1SC等)。

衣服这块我觉得值得提一下。有些户外的面料,不在意搭配的话其实日常穿也很合适,舒适度和实用性比传统的材料好得多。我现在日常穿迪卡侬的速干 T 恤,虽然说是「运动装」,干爽透气以及轻盈有弹性的面料,非常适合广东炎热潮湿的天气,穿着上班、健身都适合。

揽物日志 Vol.7

原文链接

家居向的「好物推荐」。收拾、装饰家里真的是一个时不时做一下很舒服很解压的事情。

AI 编程在七猫的实践

AI 编程落地业务开发的探索与实践
AI 代码评审在七猫的实践
AI 时代的 Code Review 最佳实践

一共有好几篇文章,合在一块说了。感觉这个技术团队非常有意思,很鼓励成员去探索 AI 编程的用法,而且很注重分享。

我在公司跟同事分享过这几篇文章,有一个很有意思的反应:「他们真的落地了吗」。背景是类似的东西(例如 AI Code Review)我在 2023 年就搞过,反正在我公司的环境,这个事情最终没有推行下去,从人的角度来说好像技术同事没有很拥抱 AI,从公司的角度这件事不见得有「价值」。所以这几篇文章让我觉得七猫这家公司的技术团队还是很有「工程师文化」,会鼓励成员去做一些「技术上很酷」的事情。

话说回来,AI Code Review 这件事,当时遇到的一些瑕疵(例如行号的识别、nit(可改可不改) 的把握等),居然到 2025 年,模型更新了两三代还是存在。

想法

扫街友好城市

接着头条的话题。我比较喜欢「扫街」,我是很典型的 i 人,在街上游荡,捕捉一些小小的美好,是我比较喜欢的摄影风格。深圳这个城市就不是很友好,这个城市主要以「石屎森林」为主,缺乏自然风光(其实也有比较好的海边),最重要的是没什么文化沉淀、没什么多样性。

我觉得要提「扫街友好」,首先是香港。住在深圳,这算是最快到达能看到「异域风光」的地方,路牌、街景等等都跟国内有很鲜明的对比。文化沉淀就是,有一种很独特的风格,如果非要我概括的话,就是老旧和时尚毫不违和地融合,优雅又整洁。香港总会给人一种很旧的感觉,有很多东西从上个世纪一直沿用到现在,例如一些用语、标牌的设计等等,尤其是很多街道和建筑实际已经建成上百年仍未变更。另一方面这里的多样性也很足,一条路上可以有佛教寺庙、清真寺和教堂,路上有各色人种人来人往,这种景象在国内真的很少见。所以在这里做「人文摄影」会很有意思,我每次去香港都能拍很多照片。

再有就是广州。这是我土生土长的地方,所以说实话有一点点特殊加成。广州跟深圳最大的不同是有很多古迹,老城区很多地方都还是十几、甚至几十年前的样子,跟千篇一律的现代城市有很大反差。

还有一点是,香港和广州有这种景色的地方很多。例如在香港你可以深度去逛旺角、九龙、中环、坚尼地城、赤柱,在广州你可以逛公园前、东山口、上下九,每个地方都有不一样的景色。而在深圳,来来去去就是各种名字不一样但实际差不多的公园和商场。

当然,这几个地方只是我常去/熟悉的,不代表其他地方就不好。我之前去过潮州,有很多古迹,除了一些步行街以外商业化味道也不是很重,也算很出片。但是像长沙,城市的商业化味道就很重,到处是网红打卡点,但打卡这件事情本来就很千篇一律,反而是让我觉得有点反感(见城市旅游就是打卡吗?)。

也欢迎各位推荐一些深圳或者周边适合扫街的地方,真的很久没碰相机了。

项目

linearmouse

项目链接

用来分别设置鼠标和触控板滚动方向的工具。

macOS 这点真的非常蛋疼,多数人鼠标的习惯是滚轮向上、内容往下,而触控板的逻辑是「自然滚动」,即往上滑动、内容往下。其实这两种逻辑都是合理的,有点像游戏中是否需要反转输入方向的问题(感兴趣可以看这篇文章),只是多数人是先从 PC(Windows)学习使用电脑,也自然而然习惯对应的鼠标操控逻辑。

如果你是用的是罗技的鼠标,可以用自带的 Logi Options+ 设置鼠标滚动的方向,不需要这些软件。

Mos

项目链接

也是一个类似的软件,除了可以单独设置鼠标和触控板滚动方向以外,还有平滑的功能,对习惯用触控板的人来说,临时使用鼠标的滚动体验会舒服很多。

minimind

项目链接

从零开始训练自己的超小语言模型。比较有意思的动手教程,完全开源免费,写得也很详细有深度。

工具/网站

LLM 驱动的词典

网站链接

我觉得比传统词典更加「生动活泼」,具体的可以看作者的文章

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

FFmpeg 硬件加速小记

2025年10月13日 02:37

本文有 AI 参与编写。

什么是硬件加速?

硬件加速是指利用计算机中的专用硬件(如 GPU、专用编解码芯片)来执行视频编解码任务,而不是仅依赖 CPU 进行软件编码。相比纯软件编码,硬件加速具有以下优势:

  • 更快的处理速度:专用硬件针对视频编解码进行了优化,处理速度可以提升数倍
  • 更低的 CPU 占用:将负载转移到 GPU 或专用芯片,释放 CPU 资源
  • 更低的功耗:硬件编码通常比软件编码更节能,延长笔记本电脑续航时间

硬件加速的权衡

虽然硬件加速很快,但也有一些需要注意的地方:

  • 压缩效率略低:硬件编码器为了速度牺牲了一些压缩效率,相同质量下文件可能略大
  • 可控性较差:硬件编码器的参数调节选项通常少于软件编码器
  • 平台依赖性:不同平台和硬件支持的加速方式不同

主流硬件加速方案

1. VideoToolbox (macOS/iOS)

Apple 的硬件加速框架,支持 macOS 和 iOS 设备。

# 编码器
h264_videotoolbox
hevc_videotoolbox

# 使用示例
ffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 2M output.mp4

特点

  • 在 Apple Silicon (M1/M2/M3) 芯片上性能出色
  • 支持硬件加速的 H.264、HEVC、ProRes 编码
  • 低功耗,适合移动设备

2. NVENC (NVIDIA GPU)

NVIDIA GPU 内置的硬件编码器,从 GTX 600 系列开始支持。

# 编码器
h264_nvenc
hevc_nvenc
av1_nvenc  # RTX 40 系列及以上

# 使用示例
ffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc -preset p4 output.mp4

特点

  • 性能强劲,编码质量较好
  • 支持多路并行编码
  • 新一代显卡支持 AV1 编码

3. QuickSync (Intel 集成显卡)

Intel 集成显卡的硬件编码器,从第二代酷睿开始支持。

# 编码器
h264_qsv
hevc_qsv
av1_qsv  # 12 代及以上

# 使用示例
ffmpeg -hwaccel qsv -i input.mp4 -c:v h264_qsv -preset medium output.mp4

特点

  • 在没有独立显卡的情况下性能不错
  • 功耗低
  • 新一代处理器支持 AV1 编码

4. AMF (AMD GPU)

AMD GPU 的硬件编码器。

# 编码器
h264_amf
hevc_amf
av1_amf  # RX 7000 系列及以上

# 使用示例
ffmpeg -hwaccel amf -i input.mp4 -c:v h264_amf output.mp4

5. VAAPI (Linux)

Linux 上的通用硬件加速接口,支持 Intel、AMD 等多种硬件。

# 使用示例
ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i input.mp4 \
  -vf 'format=nv12,hwupload' -c:v h264_vaapi output.mp4

在 Python 中检测和使用硬件加速

下面是一个完整的 Python 实现,可以自动检测系统可用的硬件加速方式并选择最佳方案:

完整实现

import subprocess
import logging
from typing import Optional, Tuple

logger = logging.getLogger(__name__)


def get_hardware_encoder(use_hwaccel: bool = True) -> Tuple[str, Optional[dict]]:
    """
    检测可用的硬件加速器并返回合适的编码器设置。

    Args:
        use_hwaccel: 是否启用硬件加速

    Returns:
        (video_codec, hwaccel_options) 元组
        - video_codec: 编码器名称,如 'h264_videotoolbox'
        - hwaccel_options: 硬件加速选项字典,如 {'hwaccel': 'videotoolbox'}
    """
    if not use_hwaccel:
        return "libx264", None

    try:
        # 检查可用的硬件加速器
        hwaccel_result = subprocess.run(
            ["ffmpeg", "-hwaccels"],
            capture_output=True,
            text=True,
            timeout=5
        )
        hwaccels = hwaccel_result.stdout.lower()

        # 检查可用的编码器
        encoder_result = subprocess.run(
            ["ffmpeg", "-encoders"],
            capture_output=True,
            text=True,
            timeout=5
        )
        encoders = encoder_result.stdout.lower()

        logger.debug(f"Available hardware accelerators: {hwaccels}")
        logger.debug(f"Available encoders: {encoders}")

        def test_encoder(codec: str) -> bool:
            """测试编码器是否真正可用"""
            try:
                result = subprocess.run(
                    [
                        "ffmpeg",
                        "-f", "lavfi",           # 使用虚拟输入
                        "-i", "testsrc=duration=1:size=320x240:rate=1",
                        "-frames:v", "1",        # 只编码一帧
                        "-c:v", codec,           # 指定编码器
                        "-f", "null",            # 输出到空设备
                        "-"
                    ],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                return result.returncode == 0
            except Exception as e:
                logger.debug(f"Failed to test encoder {codec}: {e}")
                return False

        # 按优先级检测硬件编码器

        # 1. VideoToolbox (macOS/Apple Silicon)
        if "h264_videotoolbox" in encoders and "videotoolbox" in hwaccels:
            if test_encoder("h264_videotoolbox"):
                logger.info("Using VideoToolbox hardware acceleration")
                return "h264_videotoolbox", {"hwaccel": "videotoolbox"}

        # 2. NVIDIA NVENC
        if "h264_nvenc" in encoders:
            if test_encoder("h264_nvenc"):
                logger.info("Using NVIDIA NVENC hardware acceleration")
                if "cuda" in hwaccels:
                    return "h264_nvenc", {"hwaccel": "cuda"}
                return "h264_nvenc", None

        # 3. Intel QuickSync
        if "h264_qsv" in encoders and "qsv" in hwaccels:
            if test_encoder("h264_qsv"):
                logger.info("Using Intel QuickSync hardware acceleration")
                return "h264_qsv", {"hwaccel": "qsv"}

        # 4. AMD AMF
        if "h264_amf" in encoders and "amf" in hwaccels:
            if test_encoder("h264_amf"):
                logger.info("Using AMD AMF hardware acceleration")
                return "h264_amf", {"hwaccel": "amf"}

        # 5. VAAPI (Linux)
        if "h264_vaapi" in encoders and "vaapi" in hwaccels:
            if test_encoder("h264_vaapi"):
                logger.info("Using VAAPI hardware acceleration")
                return "h264_vaapi", {"hwaccel": "vaapi"}

    except Exception as e:
        logger.warning(f"Error checking hardware encoders: {e}")
        logger.info("Falling back to software encoding")

    # 回退到软件编码
    logger.info("Using software encoding (libx264)")
    return "libx264", None


def get_system_info() -> dict:
    """获取系统硬件加速信息"""
    try:
        # 获取 FFmpeg 版本
        version_result = subprocess.run(
            ["ffmpeg", "-version"],
            capture_output=True,
            text=True,
            timeout=5
        )

        # 获取硬件加速列表
        hwaccel_result = subprocess.run(
            ["ffmpeg", "-hwaccels"],
            capture_output=True,
            text=True,
            timeout=5
        )

        # 获取编码器列表(只提取硬件编码器)
        encoder_result = subprocess.run(
            ["ffmpeg", "-encoders"],
            capture_output=True,
            text=True,
            timeout=5
        )

        hw_encoders = []
        for line in encoder_result.stdout.split('\n'):
            if any(hw in line.lower() for hw in ['nvenc', 'qsv', 'videotoolbox', 'amf', 'vaapi']):
                hw_encoders.append(line.strip())

        return {
            "ffmpeg_version": version_result.stdout.split('\n')[0],
            "hwaccels": hwaccel_result.stdout,
            "hw_encoders": hw_encoders
        }
    except Exception as e:
        return {"error": str(e)}

使用示例

1. 检测系统信息

import json

# 获取系统硬件加速信息
info = get_system_info()
print(json.dumps(info, indent=2))

2. 在 ffmpeg-python 中使用

import ffmpeg

def encode_video_with_hwaccel(input_path: str, output_path: str, use_hwaccel: bool = True):
    """使用硬件加速编码视频"""

    # 获取硬件编码器
    vcodec, hw_options = get_hardware_encoder(use_hwaccel)

    # 创建输入流
    if hw_options:
        # 使用硬件加速解码
        stream = ffmpeg.input(input_path, **hw_options)
    else:
        stream = ffmpeg.input(input_path)

    # 配置输出
    stream = ffmpeg.output(
        stream,
        output_path,
        vcodec=vcodec,           # 使用检测到的编码器
        acodec='aac',            # 音频编码器
        video_bitrate='2M',      # 视频比特率
        audio_bitrate='192k',    # 音频比特率
        preset='medium',         # 编码预设(硬件编码器可能忽略此参数)
        **{'crf': '23'}          # 质量参数(硬件编码器可能忽略此参数)
    )

    # 执行编码
    ffmpeg.run(stream, overwrite_output=True)
    print(f"Video encoded successfully using {vcodec}")


# 使用硬件加速
encode_video_with_hwaccel('input.mp4', 'output.mp4', use_hwaccel=True)

# 强制使用软件编码
encode_video_with_hwaccel('input.mp4', 'output_sw.mp4', use_hwaccel=False)

不同平台的硬件加速检测

macOS

def detect_macos_hwaccel():
    """检测 macOS 硬件加速"""
    import platform

    if platform.system() != 'Darwin':
        return None

    # 检测芯片类型
    machine = platform.machine()
    is_apple_silicon = machine == 'arm64'

    # Apple Silicon 性能更好
    if is_apple_silicon:
        return {
            'platform': 'Apple Silicon',
            'recommended_encoder': 'h264_videotoolbox',
            'performance': 'excellent',
            'codecs': ['h264_videotoolbox', 'hevc_videotoolbox', 'prores_videotoolbox']
        }
    else:
        return {
            'platform': 'Intel Mac',
            'recommended_encoder': 'h264_videotoolbox',
            'performance': 'good',
            'codecs': ['h264_videotoolbox', 'hevc_videotoolbox']
        }

Windows

def detect_windows_hwaccel():
    """检测 Windows 硬件加速"""
    import platform

    if platform.system() != 'Windows':
        return None

    available = []

    # 检测 NVIDIA
    try:
        result = subprocess.run(
            ['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'],
            capture_output=True,
            text=True,
            timeout=5
        )
        if result.returncode == 0:
            available.append({
                'type': 'NVIDIA',
                'encoder': 'h264_nvenc',
                'gpu': result.stdout.strip()
            })
    except:
        pass

    # 检测 Intel QuickSync(通过 FFmpeg)
    vcodec, _ = get_hardware_encoder(True)
    if 'qsv' in vcodec:
        available.append({
            'type': 'Intel QuickSync',
            'encoder': 'h264_qsv'
        })

    # 检测 AMD
    if 'amf' in vcodec:
        available.append({
            'type': 'AMD',
            'encoder': 'h264_amf'
        })

    return available

Linux

def detect_linux_hwaccel():
    """检测 Linux 硬件加速"""
    import platform
    import os

    if platform.system() != 'Linux':
        return None

    available = []

    # 检测 VAAPI 设备
    vaapi_devices = [f'/dev/dri/renderD{i}' for i in range(128, 140)]
    for device in vaapi_devices:
        if os.path.exists(device):
            available.append({
                'type': 'VAAPI',
                'device': device,
                'encoder': 'h264_vaapi'
            })
            break

    # 检测 NVIDIA
    try:
        result = subprocess.run(
            ['nvidia-smi'],
            capture_output=True,
            timeout=5
        )
        if result.returncode == 0:
            available.append({
                'type': 'NVIDIA',
                'encoder': 'h264_nvenc'
            })
    except:
        pass

    return available

性能对比和最佳实践

编码速度对比(参考数据)

以编码一个 1080p 60fps 视频为例:

编码器 相对速度 CPU 占用 质量评分
libx264 (软件) 1x 100% 10/10
h264_videotoolbox (M1) 5-8x 20% 8/10
h264_nvenc (RTX 3080) 8-12x 15% 8.5/10
h264_qsv (12 代 Intel) 4-6x 25% 7.5/10
h264_amf (RX 6800) 6-10x 20% 7.5/10

最佳实践

  1. 自动检测并回退

    • 始终先尝试硬件加速
    • 检测失败时自动回退到软件编码
    • 记录日志便于调试
  2. 选择合适的预设

    # NVENC 预设
    # p1 (fastest) -> p7 (slowest, best quality)
    stream = ffmpeg.output(stream, 'output.mp4', vcodec='h264_nvenc', preset='p4')
    
  3. 考虑批量处理

    • 硬件编码器通常支持多路并行
    • NVENC 可以同时处理多个视频流
  4. 监控编码质量

    • 硬件编码质量可能不如软件编码
    • 对质量要求高的场景考虑使用软件编码
    • 可以用 VMAF 等指标评估质量
  5. 处理兼容性问题

    def safe_encode(input_path, output_path):
        """带错误处理的编码"""
        try:
            # 尝试硬件加速
            encode_video_with_hwaccel(input_path, output_path, use_hwaccel=True)
        except Exception as e:
            logger.warning(f"Hardware encoding failed: {e}")
            logger.info("Retrying with software encoding")
            # 回退到软件编码
            encode_video_with_hwaccel(input_path, output_path, use_hwaccel=False)
    

调试技巧

查看详细的 FFmpeg 输出

def encode_with_debug(input_path, output_path):
    """启用详细日志的编码"""
    vcodec, hw_options = get_hardware_encoder(True)

    stream = ffmpeg.input(input_path, **hw_options) if hw_options else ffmpeg.input(input_path)
    stream = ffmpeg.output(stream, output_path, vcodec=vcodec)

    # 获取完整命令
    cmd = ffmpeg.compile(stream, overwrite_output=True)
    print(f"FFmpeg command: {' '.join(cmd)}")

    # 执行并查看输出
    try:
        ffmpeg.run(stream, overwrite_output=True, capture_stdout=False, capture_stderr=False)
    except ffmpeg.Error as e:
        print(f"stdout: {e.stdout.decode()}")
        print(f"stderr: {e.stderr.decode()}")
        raise

检查硬件支持

# 查看所有硬件加速方式
ffmpeg -hwaccels

# 查看所有编码器
ffmpeg -encoders | grep -E "(nvenc|qsv|videotoolbox|amf|vaapi)"

# 测试特定编码器
ffmpeg -f lavfi -i testsrc=duration=1:size=1920x1080:rate=30 \
  -c:v h264_videotoolbox -f null -

总结

硬件加速是视频处理中的重要优化手段,可以大幅提升处理速度和降低系统负载。通过自动检测和回退机制,我们可以构建一个跨平台的健壮视频处理系统。

关键要点:

  • 优先使用硬件加速,但保留软件编码作为回退方案
  • 不同平台选择对应的最佳硬件加速方式
  • 通过实际测试验证编码器可用性
  • 根据场景在速度和质量之间取得平衡

参考资源

猫鱼周刊 vol. 082 AI 遗忘国耻

2025年10月12日 20:26

关于本刊

这是猫鱼周刊的第 83 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

好久不见。前两周分别因为单休和国庆假期,而且也没太多内容,所以咕咕了。

放假前写了一篇 Colf 题解,讲的是一个叫Colf的编程挑战,使用最少的 token 数让 AI 通过类似 leetcode 的编程题。跟 AI 磨合了这么久,看起来确实比较有效果(目前还是排在 39 名)。

最近也在做一个叫 dotmate的项目,是之前买的 Quote/0的控制器,官方的 App 虽然能显示非常多信息源,但是编排、数据源没有自己实现来得灵活,所以自己搓了一个。

从这期开始尝试一个排版上的变化。因为之前有微信公众号的读者反馈「项目」部分的 gh-card 会被转成图片,导致最后外链部分排版混乱,所以从这期开始,去掉 gh-card,只提供项目链接。

文章

让 Claude Code 更自主地运行

原文链接

假期前其实 AI 这块还挺多变动,除了 Claude Sonnet 4.5、DeepSeek-V3.2-Exp、GLM-4.6 扎堆发布之外,Claude Code 也来了一波更新。我觉得最亮眼的是两个,一个是原生的 vscode 插件,另一个就是 checkpoint。

首先说插件这块,这让 Claude Code 的体验真的更上一层楼,因为原来的交互就是开一个终端放在旁边,现在更加像 Cursor 自带的了。这里有个小插曲,插件刚上线的时候我发现了一个 bug,严重到我回退到命令行了,就是插件似乎监听了回车键,在中英文混输的时候按下回车就会发送消息,好在这周更新之后发现修复了。

checkpoint 也是一个我觉得很惊喜的功能。Cursor 中有类似的功能,这点很舒服,在你 vibe 了一大堆代码之后,如果觉得不满意,还能通过一种保险的方式回退到原来的代码(还有一种不保险的方式就是让 LLM 帮你恢复,取决于代码是否还在上下文里面,而且不一定能原样恢复)。这个功能之前我就调研过怎么让 Claude Code 也用上。网上有人做了一个 ccundo的项目,原理是去解析 Claude Code 的 session 文件,然后把状态保存下来。我自己倒是想到一个不一样的方法,通过 hooks触发一个工具,把变更保存下来。其实也有人提过 issue让官方实现这个功能,但是在几轮讨论之后就被冷落了,直到这次更新突然把这个功能端出来。

不得不感叹这个领域的变化真的很快,作为偏下游的用户,一些早些时间调研做不了或者很难的事情,说不定某一次模型的更新或者某个功能的实现就能解决了。

有 1M 上下文谁还需要 git 呢?

原文链接

这个就是我上面提到的「不保险」的办法。

事情是作者写了一份草稿代码,实现了一个比较好的效果,于是开始重构成生产级别的代码,过程中出了点问题,再也没法复现原来的效果,他也没有 commit 过代码,所以无从下手。最后他想到 gemini-2.5-pro 有 1M 的上下文,也许它还记得最初的代码,于是让它还原了。

这个方法能成功有两个前提,一个是上下文还保存着,另一个是 AI 真的能原样恢复。「原样恢复」这个我有点钻牛角尖,但是 git 它是可以的,但 LLM 本身就不能产出「确定性」的结果,所以不能跟 git 相提并论。好的编程习惯在什么时候都是有用的,如果能在实现一个完整功能的时候 commit 一次,就没有这个麻烦了。

Cursor 的 Plan Mode

原文链接

Cursor 推出了一个计划模式,它大概是这样:

当你指示 Agent 制定计划时,Cursor 会研究你的代码库以查找相关文件、审阅文档并提出澄清问题。当你对计划满意后,它会创建一个包含文件路径和代码引用的 Markdown 文件。你可以直接编辑该计划,包括添加或删除待办事项。

这其实跟我使用 Claude Code 的习惯非常像,我有一个 slash command 就是做这个事:

Read the demands in $ARGUMENTS and come up with a detailed implementation plan. You should:

1. Read the demands in $ARGUMENTS
2. Read relevant files in the codebase
3. Think hard about the best way to implement the demands
4. List the data structures, database tables you are about to add or modify(if any)
5. List API changes you are about to make(if any)
6. List every file you are about to add or modify, including what logics each file is about to implement

If you have any confusion, ask the user for clarification. DO NOT write any codes yet before given clear instruction to do so.

各种语言的拟人化漫画

原文链接

如题,版权问题就不放图了,原图大家点进去看看。

虽然有很多没接触过的语言,但是 C/C++ 那个真的太典了,完全是心目中会写 C 的人的形象。

后量子时代密码学

原文链接

接触到这篇文章是在我更新机器上的 openssh 之后,push 代码的时候出现了一个 warning:

** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html

简单来说,现在使用的密钥交换算法(ECDH,椭圆曲线 Diffie-Hellman)基于离散对数问题的困难性,传统计算机需要指数时间破解,但量子计算机可以在多项式时间内解决,把破解时间从几百万年降至几小时。但为什么要现在就开始防范呢?因为攻击者可以在现在就截获数据,然后等十到二十年后量子计算机成熟再解密(store now, decrypt later)。

而 OpenSSH 默认的交换算法 mlkem768x25519-sha256 是一种混合的方案,基于 ML-KEM-768 和传统的 X25519,足够对抗传统计算机和量子计算机的攻击。唯一的代价是密钥会更大而且计算开销更大一点,但对现代计算机没有显著的影响。

future-proof 真的是工程实践上一个非常有意思的事情。不仅是防范眼下可能的攻击,还要提前预知数十年后可能产生的威胁并提出对应的防范方案。

想法

AI 遗忘国耻

这个标题有点唬人,但是正好说明一个观点:过分清洗语料,过分强调「安全」会让 AI 严重降智,而且这也是各种「评测」体现不了的。

「华人与狗不得入内」是一个大家都熟知的事情,是当年上海租界一个种族歧视的标牌,算是「国耻」。但用这个问题去问 AI 会被拒绝回答:

目前只发现 DeepSeek 所有版本都拒绝回答,其他的一些国产 AI 例如 GLM、豆包、千问等都能正常回答,OpenAI、Anthropic 的模型也能正常回答,并未进一步测试更多模型。

所以在使用 AI 的时候,一定要自己做事实考证,不只是幻觉,伦理和安全的需求会让 AI 有意无意遗忘一些事情。

另一个是,种族歧视也好,不是信息也好,这都是我们人类的一部分,在训练时刻意去掉,只让 AI 看到一个乌托邦,是不是也会有问题?但让 AI 看遍人间邪恶,是不是也会有问题?这也是一个研究领域(AI Safety)。

项目

chorme-devtools-mcp

项目链接

DevTools 官方做的 MCP 工具,在这之前我用了很多个,有的还需要安装插件,而且也没办法获取 DevTools 里的信息,这个似乎是最好用的。

dotmate

项目链接

上面提到的给 Quote/0 写的控制器。我目前主要用这么三个视图:

  • 还有多久下班:显示当前的时间以及还有多久下班
  • 编程时间统计:基于 wakatime 的统计
  • Umami 统计信息:不用专门打开看了

效果大概是这样:


mole

项目链接

一个 Mac 的命令行垃圾清理工具,居然是用 shell 写的。不过由于是用 AI vibe 出来的,作者也建议如果数据非常重要,等更加成熟之后再使用。我建议是用 dry-run 先试试。

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

Colf 题解

2025年9月29日 22:08

Colf 是一个面向 AI prompt 的 code golf,大概就是利用最少的代码(在这里是最少的 token 数)来解题。

使用起来很简单,在左边的框中输入 prompt,生成代码,然后会自动运行是否 AC,如果 AC 则按照输入和输出 token 数计分。

小小尝试了一下,AC 完之后排名还挺前,所以写篇文章记录一下题解和心得。

题解

#1 LRU Cache

function lruops(
  ops: [op: string, key: number, value?: number][],
  capacity: number,
): number[]

code golf
function lruops(o,c){let m=new Map(),r=[];for(let [op,k,v]of o){if(op=="get"){if(m.has(k)){r.push(m.get(k)),m.delete(k),m.set(k,r[r.length-1])}else r.push(-1)}else{if(m.size==c)m.delete(m.keys().next().value);m.set(k,v)}}return r}
Input 33 tokens, Output 85 tokens, Total 118 tokens

上来先展示一下流氓解法:复制函数签名,加上 code golf。

#2 Topological Sort with Cycle Detection

function toposort(
  n: number,
  edges: [u: number, v: number][],
): number[]

Code golf choose the smallest index
function toposort(n, edges) {
    const g = Array.from({ length: n }, () => []), inDeg = Array(n).fill(0);
    edges.forEach(([u, v]) => (g[u].push(v), inDeg[v]++));
    const q = [], res = [];
    for (let i = 0; i < n; i++) if (!inDeg[i]) q.push(i);
    while (q.length) {
        const u = q.splice(q.indexOf(Math.min(...q)), 1)[0];
        res.push(u);
        for (const v of g[u]) {
            if (--inDeg[v] === 0) q.push(v);
        }
    }
    return res.length === n ? res : [];
}
Input 33 tokens, Output 159 tokens, Total 192 tokens

同样是流氓解法,但是有 case 过不了,再审题干,要选择更小的 index,所以补一句。

#3 Longest Common Subsequence

code golf
function lcs(a,b: string): string
function lcs(a,b){let dp=Array.from({length:a.length+1},()=>Array(b.length+1).fill(0));for(let i=1;i<=a.length;i++)for(let j=1;j<=b.length;j++)dp[i][j]=a[i-1]==b[j-1]?dp[i-1][j-1]+1:Math.max(dp[i-1][j],dp[i][j-1]);let res='';for(let i=a.length,j=b.length;i&&j;){if(a[i-1]==b[j-1]){res=a[i-1]+res;i--;j--;}else dp[i][j-1]>dp[i-1][j]?j--:i--;}return res;}

Input 12 tokens, Output 157 tokens, Total 169 tokens

同样的流氓解法,唯一区别是从函数签名偷了一点。

#4 Expression Evaluator

calc expr
round code golf
const calc=(e)=>Math.round(eval(e));
Input 6 tokens, Output 10 tokens, Total 16 tokens

还是一样的解法,复制函数签名,但是 AC 不过;以为是优先级的问题,又把优先级的条件复制进去,还是不行;看一下发现需要取整(round),加上关键词,完事。如果强调优先级,它会生成一个很复杂的递归去解释的逻辑。

#5 Single-Source Shortest Paths

code golf

function dijkstra(
  n: number,
  edges: [u: number, v: number, w: number][],
  s: number,
): (number|null)[]
function dijkstra(n,e,s){let d=Array(n).fill(Infinity);d[s]=0;let q=new Set([s]);while(q.size){let u=[...q].reduce((a,b)=>d[a]<d[b]?a:b);q.delete(u);for(let[_,v,w]of e.filter(x=>x[0]==u)){if(d[u]+w<d[v]){d[v]=d[u]+w;q.add(v)}}}return d.map(x=>x===Infinity?null:x)}
Input 41 tokens, Output 108 tokens, Total 149 tokens

没啥特别,照样流氓解法。

#6 N-Queens

function nqueens(N: number):number
one-liner
const nqueens = N => (function solve(row, cols, diag1, diag2) { return row === N ? 1 : Array.from({ length: N }).reduce((count, _, col) => (cols[col] || diag1[row + col] || diag2[row - col + N - 1]) ? count : count + solve(row + 1, { ...cols, [col]: true }, { ...diag1, [row + col]: true }, { ...diag2, [row - col + N - 1]: true }), 0); })(0, {}, {}, {});
Input 13 tokens, Output 126 tokens, Total 139 tokens

启用了一个新的技巧 one-liner,这个词只占 2 个 token,跟 code golf 一样,效果差不多(主要是 code golf 在这里不 work)。

#7 Range Sum with Updates

function segment(
  nums: number[],
  ops: [op: string, a: number, b: number][],
): number[]

set i v updates a[i] = v.
sum l r returns inclusive sum from l to r.
code golf
function segment(nums, ops) {
  const a = [...nums];
  return ops.map(([op, x, y]) => {
    if (op === 'set') a[x] = y;
    else if (op === 'sum') return a.slice(x, y + 1).reduce((s, v) => s + v, 0);
  }).filter(v => v !== undefined);
}
Input 52 tokens, Output 84 tokens, Total 136 tokens

同样的技巧,唯一的缝补是 set 和 sum 的操作看起来不是很标准,塞进去之后就能 AC。

#8 JSON Diff

function jsondiff(
  a: unknown,
  b: unknown,
): string[]

Return a lexicographically sorted list of JSON paths where two JSON-serializable values differ. Paths use '.' for keys and '[i]' for array indices; the root is ''. always start with .

jsondiff({"x":1,"y":2}, {"x":1,"y":3}) // -> [".y"]
jsondiff({"k":[1,2]}, {"k":[1]}) // -> [".k[1]"]
function jsondiff(a, b) {
    const diffs = [];

    function compare(objA, objB, path) {
        if (typeof objA !== typeof objB) {
            diffs.push(path);
            return;
        }
        if (typeof objA === 'object' && objA !== null && objB !== null) {
            if (Array.isArray(objA) && Array.isArray(objB)) {
                const maxLength = Math.max(objA.length, objB.length);
                for (let i = 0; i < maxLength; i++) {
                    compare(objA[i], objB[i], `${path}[${i}]`);
                }
            } else {
                const keysA = Object.keys(objA);
                const keysB = Object.keys(objB);
                const allKeys = new Set([...keysA, ...keysB]);
                allKeys.forEach(key => {
                    compare(objA[key], objB[key], `${path}.${key}`);
                });
            }
        } else if (objA !== objB) {
            diffs.push(path);
        }
    }

    compare(a, b, '');
    return diffs.sort();
}
Input 108 tokens, Output 232 tokens, Total 340 tokens

答得最拉的一题,复制粘贴大法搞不定,而且总是卡那个数组下标不能 AC,需要手动改一下第二个例子,属于是 few-shot 的技巧。

#9 Sudoku Solver

function sudoku(grid: ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'.')[][]): ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')[][]
function sudoku(grid) {
    const isValid = (row, col, num) => {
        for (let i = 0; i < 9; i++) {
            if (grid[row][i] === num || grid[i][col] === num || grid[Math.floor(row / 3) * 3 + Math.floor(i / 3)][Math.floor(col / 3) * 3 + i % 3] === num) {
                return false;
            }
        }
        return true;
    };

    const solve = () => {
        for (let row = 0; row < 9; row++) {
            for (let col = 0; col < 9; col++) {
                if (grid[row][col] === '.') {
                    for (let num = 1; num <= 9; num++) {
                        const strNum = num.toString();
                        if (isValid(row, col, strNum)) {
                            grid[row][col] = strNum;
                            if (solve()) {
                                return true;
                            }
                            grid[row][col] = '.';
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    };

    solve();
    return grid;
}
Input 63 tokens, Output 254 tokens, Total 317 tokens

这题也卡了很久,直接复制粘贴函数签名就能 AC,但是没有优化的思路。

#10 Regex Matcher

full matching code golf regex10(s,p)
function regex10(s,p){return new RegExp('^'+p+'$').test(s);}
Input 9 tokens, Output 18 tokens, Total 27 tokens

这题是我排名最前的,目前正好是第十。还是一样的套路,唯一难点是那个 full matching。

心得

先说解题的技巧。

基本盘就是复制粘贴函数签名,由于都是一些很常见的算法题,所以一般 LLM 都能一遍过;如果没过,通常是因为题干中有一些特殊的要求,这个时候回去读一遍题干,把这个特殊点找出来放进 prompt,例如 2、7、8、10 这几题。

然后就是怎么压榨输出的长度。因为打题用的 JavaScript,其实有挺多技巧/语法糖可以使用,例如箭头函数(arrow)、三元运算符(ternary)等等。这个在初期有比较大的进步,然后后来想到更加机智的一行流(one-liner),再按图索骥找到王炸 code golf

另外有个不太起眼的技巧就是,你需要探索出一种超短的实现方式,通常跟你一开始写的有天壤之比,例如 4 里使用的 eval()。你可以把题干复制出来,让别的 AI 去提供解法,然后再尝试把某些关键词放进 prompt 中引诱它生成出来。当然如果你很熟悉 JavaScript,本身就知道对应的语法糖或者算法的关键词,那必然更快能 AC。

最后,还有一点个位数的空间可以压榨。实测标点符号并不重要,函数的签名多个参数可以合并一下写,很显然的参数类型可以省略等等。这些就是已经在榜单上冲得很前想再扣出来一点的技巧了。

再说说打这个题让我对 AI 编程产生的思考。

第一还是那个「AI 决定下限,人决定上限」的理论。在 8、9 这两题我表现并不佳,因为我真的没有思路怎么解这个题,自然没办法给 AI 指出一个优化的方向。当然 AI 的能力也很强,通过一个函数签名最多试几次就能 AC,而且我估计网站背后只是用的一个本地的开源小参数模型。这说明 AI 已经能有竞争力地完成一些任务。

第二就是跟 AI 的磨合。从最开始的 GitHub Copilot 的自动补全,到 Cursor 和 Claude Code,我一直在积极使用 AI 编程,就好像跟伙伴慢慢磨合,知道它的能力能很有信心地做出什么,做什么比较悬,怎么去写 prompt 效果更好。例如我一上来就知道,复制粘贴函数签名会很关键,事实也证明这能很快地 AC 大部分题。这些东西真的很难形成书面的经验,更多时候是一种感觉。

第三是编程方式和效率的变化。就像「copilot」这个名字所说的一样,LLM 时代的编程不再是人手敲代码的「刀耕火种」,人更多地需要考虑「方向」而不是具体的实施,就算你把算法倒背如流,键盘敲冒烟,依然无法比肩 LLM 几十 token/s 的输出。另外就是,如果这个时代你还不能使用 AI 编程,那你的效率跟使用 AI 的同行完全没法比。当然这个说法有点夸张,就算你使用 AI,你的「上下文」上限仍然取决于你的脑容量,或者时间精力等等。

最后是「AI 友好的代码」。在这个题库中,多数的题都是非常基础和常见的算法,所以 AI 的准确率非常高。在工作中,更多地应该使用开源、知名而且「不那么新」(要在知识截止日期前)的库,开源库也可以使用 context7 等提供文档,尽量不要重复造轮子,更加不要再搞一大堆公司的私有库。另外最好重视文档的建设,更全更准确的上下文能让 AI 更好发挥。

  •  

猫鱼周刊 vol. 081 开源是地狱

2025年9月21日 18:21

关于本刊

这是猫鱼周刊的第 82 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

这周天气比较差,尤其是周末两天都在下雨,所以这周又没有出门拍照,这周又没有头图咯。

这周写了一篇 Ghostty 折腾小记,其实最大的收获是了解了一些字体相关的东西。另外字体这个东西真的非常个性化,我最喜欢的类型是等宽无衬线;而且看惯某一款字体后,大脑识别起来会更快一点,主观上就是看着「更舒服」。

文章

医学考古:旧约、不孕不育和曼德拉草

原文链接

从圣经的记录去研究亚伯拉罕家族的不孕不育案例。说实话整篇文章我看得一知半解,但是就好像吃瓜一样看完了,确实蛮有意思。

像宗教、传说这一类故事,深挖的话其实能找到一个合理的现代科学解释,但是更多地在民间归因为「神力」。我是非常科学理性的人,但是之前生病的时候我还是去拜了神,说实话我其实说不上信或者不信,但是更加有意义的是「拜神」这件事其实更多是「心理安慰」,在现实残酷或者前途未卜的时候,坦然的心态显然比慌张更能面对未来。

这个作者也很有意思,之前关注到 ta 是几篇技术文章,冷不丁来一篇医学 x 宗教/历史的文章,也是很强的反差。

个性化广告的隐私边界(上)

原文链接

讲解了隐私、安全、匿名的概念,并且从几个常见误区来解释。

我觉得有几点需要补充:

一是你在用的免费服务都在用你的「用户画像」赚钱,诸如 Alphabet(Google 母公司)和 Meta(Facebook 母公司)的主要收入来源都是广告业务。

第二是,虽然用户画像不等价于个人信息,但是国内服务的匿名化和保护通常做得不够好,尤其是一些小公司的服务,经常导致个人信息泄露,这不是无心之失,而是故意而为之:匿名化、安全等需要额外的研发和投入,博弈之下,出事之后冷处理或者鞠躬道歉甚至全网封杀的成本更低。

最后是国内公司滥用隐私早成习惯,这从当年百度李彦宏说「中国人更加开放,对隐私问题没有那么敏感,很多情况下他们愿意用隐私交换便利性,那我们就可以用数据做一些事情。」就能窥见其端倪。早年都是不问自取,立法之后,变成半哄半骗地让你同意,更过甚有拼多多利用 0day 漏洞窃取数据等等。

这几条连起来其实很明晰:所有公司都会在法律边缘试探,以获取最大的利益,你的隐私在里面只是别人的垫脚石。

更新博客 License

原文链接

关注的作者的一个疑惑:

我是否遵循了引用文章的 License,是否存在侵权。

在博客的很早期我其实考虑过这个问题,也考虑给自己的博客用什么 license,但是这件事渐渐就被淡忘了:没有人会愿意抄袭我这个名不经传的小博客,况且我的博客写的都是一些自娱自乐的内容,一般没什么经济价值。不过我一直没有淡忘的是正式的引用,例如周刊会在每篇文章都给出原文链接,文章会在末尾给出 Reference 等。

这件事提醒了我,审视自己的博客,我最可能的 violation 是分享了一些有 copyright 的内容,但是确实「内容较多」已经无法一一再考究;更多的情况下,大家都没有标明版权,或者采用 CC-BY 等,我目前的做法应该是符合规范的。作为保底,如果你对某些内容有争议,可以联系我解决。

想法

反作弊与隐私

最近玩三角洲比较多,每次启动的时候都有一个弹框引导我安装开机自启的所谓「守护程序」,实现反作弊功能。开喷之前我先叠盾,不是说反作弊这件事情没有意义,只是厂商借着「反作弊」的名号越过了一个边界。

我觉得这产生了很多问题:只有我有正当理由(反作弊),我就可以光明正大抄你的家(扫盘)吗?如果我没有同意扫盘,但是扫出了作弊的证据,是否可以作为封禁的理由?更甚,如果在扫盘过程中,发现「违法证据」(例如盗版影视资源)是否也可以对用户作出行动?另外,扫盘造成的磁盘磨损、损坏,是否可以认定为损害用户的财产或者是入侵计算机信息系统?当然了,这些问题早被相应的法务包得圆圆的,估计在启动游戏的时候你就默认同意了这些不平等条款,怎么可能告得赢南山必胜客呢。

这就是我所说的边界,从技术上说,只要扫盘这个行为一旦发生,想要实现上面的功能轻而易举。也从技术上说,用扫盘这个手段来反作弊算是技术能力很差的保底手段,以及对游戏环境本身的嘲讽。游戏机制、玩家引导、更好的反作弊技术等等都是不错的努力方向,偏偏要出个下策。

开源是地狱

上期好好说话的后续。太讽刺了,这个人在国内社群拉帮结派,然后去 Discord 上喋喋不休追讨。最后人家取了这个截图,配上一句极为讽刺的话「那边的人心态就是这样」。

另外吃瓜了微信聊天和 Discord 聊天之后,发现一个很有意思的点:微信的聊天争论的点在 「HAS」的咬文嚼字和作者到底有没有遵守 GPLv3(虽然很大程度上是当事人引导的结果),而 Discord 的吃瓜群众则是好言相劝冷静一下好好说话。

我只能说很讽刺,也许在国内开源确实就是地狱,社区就是地狱,大家都没法好好说话,通过在互联网上满嘴喷粪去释放自己的负面情绪。

项目

obsidian-velocity

Gonzalo-D-Sales/obsidian-velocity - GitHub

项目链接

适配了新的 Liquid Glass 风格的 Obsidian 主题,很简洁优雅,已经换上了。

霞鹜文楷

lxgw/LxgwWenKai - GitHub

原文链接

一款开源的中文字体。之前在折腾终端字体的时候找到的,其实这个中文字体在阅读场景不错,用在博客或者电纸书上应该很舒服。

工具/网站

MCP Registry

网站链接

(终于又给这个名存实亡的板块写点东西。)

GitHub 出的 MCP Registry,其实没啥特别,就是准入门槛比其他 registry 更高,但是 install 功能就只能安装到 vscode,略显鸡肋。

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

Ghostty 折腾小记

2025年9月17日 21:22

刚入手 Macbook 的时候用的 Terminal.app,后来用 iTerm2,同时用 Termius 来连接服务器,再到后来用 Tabby + tssh 大一统,取代了 Termius。前两天心血来潮又换成了 Ghostty,说实话 Tabby 没什么不好,唯一的缺点就是不是原生。

Ghostty 号称「零配置」(Zero Configuration Philosophy),确实开箱的体验也足够好了。但是我有看惯了的配色和字体,所以这些还要折腾一下。先贴一下我的配置,以及效果,方便你抄作业。

theme = Catppuccin Mocha
font-family = Hack
font-family = Noto Sans SC
font-thicken = true
font-size = 12
window-inherit-font-size = false
window-padding-x = 10
window-padding-y = 10
shell-integration-features = no-cursor
cursor-style = block
cursor-style-blink = true
window-save-state = never
term = xterm-256color

它的配置采用的是一种宽松的类 ini 的格式,这点好评,不会一不小心就损坏配置没法打开。

主要修改了这些配置项:

  • theme 用了平常就在用的 Catppuccin Mocha
  • window-padding-x, window-padding-y 不喜欢元素贴着边边,有种拥挤的感觉
  • window-save-state 设成 never 每次重新打开都会变成默认大小,强迫症福音
  • term 这个选项控制 $TERM,它默认会把自己宣称 xterm-ghostty ,会导致有些 CLI 报兼容问题,所以改成 xterm-256color

比较值得一提的是字体的搭配。它支持设置多个 font-family 来决定字形的回落。

我之前一直使用的终端字体是 MesloLGS NF,编程字体是 Hack。我对字体的偏好其实就是等宽、无衬线。趁着折腾我又尝试了一些其他的组合:

  • Iosevka(Iosevka Term / Iosevka Term Extended):一款比较好评的终端字体,其中不带 Extended 的版本极窄,可以在更窄的屏幕内展示更多内容。但是实在窄得要命,接受不了。
  • Sarasa Gothic / 更纱黑体 (Sarasa Term SC):合成字体,是上面的 Iosevka + Source Han Sans 作为 CJK 增补合成的字体。其实用 Iosevka Extended + 这个还行,只是没有太好看。特点是中英文 2:1 等距。
  • JetBrains Maple Mono:也是一款合成字体,JetBrains Mono + Maple Mono。也是中英文 2:1 等距的。
  • Noto Sans:一款 CJK 字体,不怎么特别,但是在终端里比 PingFang SC 稍微耐看一点。
  • Fira Code:顾名思义一款为代码而生的字体,连字设计比较有特色。

有印象尝试过的自己大概就这些。折腾到最后,我使用了 Hack + Noto Sans 的组合。因为主要是英文字体用得居多,加上 vscode 里一直就是 Hack,所以看得顺眼的留下了。我发现在看惯某一款字体后,大脑识别起来会更快一点,过拟合不是虚的。

Anyway,趁这次折腾也对字体稍微有了一点了解,例如风格、等宽、连字、衬线、字形、字重等等,也许后面有机会再写一篇文章来讲这个。

猫鱼周刊 vol. 080 中年人网购骗局

2025年9月14日 19:51

关于本刊

这是猫鱼周刊的第 81 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

摄于大芬油画村,下午刺眼的阳光透过摇曳的树叶,树头挂着各式标牌,还有辆小孩的脚踏车。

这个地方算是比较踩雷,从宝安过去要坐一个多小时地铁,结果就是一个城中村(还算是很小的那种,一共就两条大街这样),没什么很特别的风景,只有几面网红打卡墙。如果是装点家居的话,倒是可以看看买几幅油画,价格不贵,大小都有;这里大街小巷都有可以体验画油画的,感兴趣的话可能也有点意思;另外还有给人画像的,这种就烂大街了。

这周看的文章不多,不过想法写得比较多一点。

文章

好好吃饭,别东看西看!

原文链接

作者很喜欢分散精力去观察周围发生的事情,这是几个小故事的集合。

我并不是个注意力集中的人,所以我在吃饭、工作的时候,还会分出一个线程观察周围正在发生的事情

哈哈,很有同感。我小时候是话非常多的人,大概是初中的时候,经常因为说话太多被批评,然后当时我自己默默给自己培养了一个「少说多看」的习惯,在很想说话时抑制自己说话的欲望,转为默默观察。(当然这个习惯好像没有很成功,你看我现在就在疯狂输出,只不过是通过文字罢了)

日常#3 - 身上的红点、南瓜汤、胡辣汤、猪扒饭、纸上染了蓝、空洞骑士

原文链接

之前关注的博主,新开的「日常」系列文章。虽然都是分享性质,但是感觉写成文字会比在朋友圈之类看到一大堆图片更加舒服。有时候看到朋友圈里别人发的九宫格(同样都是吃喝玩乐),会产生一种「怎么别人的生活过得这么好」的失落感。反倒是这种长文配图的方式,会让内容更加丰满,有一种真诚的感觉,而不是炫耀「嘿你看我又去了某某地方」。

周末流水账 0913

原文链接

也是之前关注的博主 Solazy 的生活日常文章,主要也是吃喝玩乐。他的篇幅会更短一点,行文也轻松,看得很舒服。

我的博客设计

原文链接

上周刚推荐了「极客死亡计划」博客的设计,这周 Spike 也分享了他的设计。所以其实很多博客读起来觉得很舒服,其实背后经过了很多的努力和细致的思考,这点非常钦佩。

另外,「我不喜欢的设计/内容」这部分跟我之前分享过的「Yay or Nay」其实很相似。

想法

coding agents 的记忆

当前多数 coding agents 采用纯文本文件来做「记忆」,并且通过嵌套的方式,去支持用户/项目/目录维度的规则。问题是,一个是好像暂时没有发现会去主动更新、维护记忆的,第二是记忆没法跨工具/项目等去共享,或者是团队等去共享,编辑起来也不方便。当然这两个问题也有一定的办法可以解决,第一个是可以通过主动调用 /init ,第二个是采用类似 intellectronica/ruler 这种去做,然后把对应的文件也放到 git 上。

其实现实的问题是,我反复需要给 Claude Code 复制粘贴数据库的表结构,不然它会瞎猜一个不存在的字段,或者搞错字段的类型,这点真的让我感觉很蛋疼。虽然这个问题有比较多种方法可以解决,例如:

  • 在强类型的语言中使用结构体定义对应的数据库结构(没有 ORM 框架就用不了)
  • 使用数据库的 MCP(会有查询风险问题)
  • 把对应数据库结构的 SQL 放在项目代码里(项目中多数没有这个习惯)

所以我想搓这么个东西:

  • 多租户设计,支持多个空间
  • 空间支持多个成员,并且有管理员/读写/只读三种角色
  • 空间下可以建立项目(对应具体的 git 项目)
  • 空间里可以建立关联项目的记忆,也可以完全不关联任何项目;记忆可选是否与空间成员共享
  • 支持记忆的增删改查
  • 记忆有多种类型,其底层都是纯文本;类型包括 schemas(数据库表)、snippets(代码片段)、documents(产品、设计文档等)等,支持拓展
  • 成员可以创建 api key 供 MCP 使用,这个 api key 需要在建立时指定可以访问的范围(空间、项目等);后续用这个 api key 进行查询时,需要限制对应的范围
  • 提供以下几个 MCP tool:
    • get_memory(project, query) array(memory_item) 查询对应的记忆,返回一个列表;通过精确匹配+向量搜索,rerank 返回
    • add_memory(project, memory_item) 创建记忆
    • edit_memory(project, memory_item) 编辑记忆

这个东西现在已经新建文件夹,并且 vibe 了一大堆跑不起来的代码。如果你有什么想法,或者有好的项目/方案参考,欢迎评论交流。

中年人网购骗局

记录一下分别发生在我爸妈身上的两次网购经历。

第一个是我爸在拼多多上购买了一台「小米电视」,大小是对的,面板也没有瑕疵,系统也是小米的,从他们的使用来说,一切都好。直到我回家,尝试投屏看 F1 比赛,发现投屏超级卡,一看它连了 2.4G Wi-Fi,怎么都连不上 5G,此为第一个破绽。然后我尝试输入 SSID 手动连接,这时候我才发现遥控器不仅塑料手感极其廉价,而且并不是蓝牙的,而是红外的,此为第二个破绽。另外,进入设置界面,系统无法更新,设备信息的界面也与小米系统完全不一致,按照对应的型号在网上也根本没有找到对应的型号,此为第三个破绽。其实到这里我已经知道,这多半是台山寨电视。再找到电视的包装,不仅包装上完全没有小米的 logo,只写了「国货」之类的字样,也没有任何的型号标识,更加没有说明书、三包等文件。所以我爸花了一千多,买了一台「只有系统是小米」的山寨电视。更气的是,因为这台电视就是给爷爷奶奶看,他们只会用机顶盒看电视台,不会用到其他的功能,如果不是我去投屏,根本不可能有人发现破绽。当发现买到山寨之后,他们的意见是,那反正够用,也便宜,就算了吧。

第二个是我妈在拼多多上给我买了一些菊花冲水喝,收到货之后发现包装上完全没有标注生产商家、食品生产许可证等,仅有一张打印的贴纸写着产地,销售地址是某中药城,还很「贴心」地标注了这是「初级农产品」。这是个很扯蛋的事情,假若这个东西吃完出了问题,商家可以拿这个条款出来赖:我不是卖的食品,你没有加工过就吃,吃坏了不负责。再往坏点说,这完全就是三无产品,不管怎么样商家就没有善意,你怎么保证买到的是好的?而我妈的话更是让我震惊:「我还以为初级农产品更好,没有添加剂」。

其实我之前也试过一次在 pdd 买过一个三无 U 盘,标价 17 元 32G,实际写入几百 M 就写不了了,申请退款直接就通过了。最离谱的是,我甚至好评返现薅了它 3 块。

我不知道为什么总有论调在说「网购」如何降低物价,在我看来完全是奸商和平台狼狈为奸,我此前完全想像不到这利润空间可以有这么大,又或者说原来对应的群体这么好骗。我爸是一个非常聪明的人,我妈也算有点文化,但就是被这些奸商和平台定向诈骗到了。我不敢想拼多多在二三线城市,或者更加薄弱的群体,是有多赚钱。

我对此无能为力,我只能跟他们说,以后再在网上买贵的东西,先给我看一下。

好好说话

一件发生在开源社区的闹剧,我觉得很典型,值得拿出来讲讲。事情是这样的,Meshtastic 社区里一个人做了一个中文固件(支持 CJK 字符的展示),然后开源社区有人提 issue建议他开源,这位认为对方怀有恶意,用 GPLv3 要挟他开源代码,但他已经提供了对应的 patch,于是他让对方「Fxxk off」。

我觉得最哭笑不得的是他对别人这一句话的理解:

Hi. I understand your concern, but it might be worth looking into it. Also, Meshtastic is GPL3, so the patch HAS to be released anyway. And we at Meshtastic would really like to see it.

他说,这个 「HAS」用了强调语气,结合 「anyway」,这是恶意的。

我不知道他从哪里理解出这个恶意,这句话全都是委婉语气,看上下文人家只是希望他去提一个 pr,Discord 上别人也认为他过度反应了。结果他的这番发言居然在国内社区获得了不少支持。

我觉得国内在开源社区有一些误区,真的成为中国人在社区反复出丑的原因。

第一个是对开源工作的态度。开源本身就是「为爱发电」,不是因为没人原因为你的工作付出经济或者情绪价值,开源本质是不藏私地分享。用上一期的话来说,如果经常纠结别人白嫖你的工作,那也是对你自己的不尊重。

第二个是语言不通的问题。在 GitHub 上有很多非英语母语的人,像日本、印度等等,世界上大多数国家的母语也不是英语,但是大家都能用英语去协作,唯有中国人特别喜欢用中文,或者就是写不好英语。我觉得在语言上没必要扯什么民族自信的事,要以约定俗成或者方便沟通为主。英美很强大,但万国邮政联盟的工作语言不还是法语?所以学好用好语言是没有借口的。

第三个是友好交流。这个人的心态很差,不知道他为什么预设了对方是恶意的,是想要白嫖他的代码,因此影响了他的理解,而且用 fword 去回应对方。国内社交平台的戾气是相对比较重,但我真的很少在 GitHub 在中文以外的语言有骂街的。不管怎么样,在互联网上好好说话,应该是一件很基础的事。我也有项目,有人提了 issue,我没有时间精力去做,我会很礼貌跟对方探讨难点在哪里,委婉地拒绝。或者别人有疑惑的地方,我也会尽我所能去讲解。

项目

ruler

intellectronica/ruler - GitHub

项目链接

可以把规则应用到全部的 coding agent,其实就是把内容同步到 CLAUDE.md 等。一定程度上能解决我上面提到的问题。

bayes_spam_sniper

ramsayleung/bayes_spam_sniper - GitHub
项目链接

利用贝叶斯算法实现广告拦截。跟我之前提到的个人信息源过滤有点关联,其实前期也可以用传统的算法去尝试过滤。

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

猫鱼周刊 vol. 079 工作中应该摆烂吗?

2025年9月7日 18:41

关于本刊

这是猫鱼周刊的第 80 期,本系列每周日更新,主要内容为每周收集内容的分享,同时发布在

博客:阿猫的博客-猫鱼周刊

RSS:猫鱼周刊

邮件订阅:猫鱼周刊

微信公众号:猫兄的和谐号列车

私信:leslieleung@proton.me

头条

一旧很有质感的云,蓝色的天加上傍晚时分金黄色的阳光,让它显得更有层次感。

上周周刊停了一周,一个是因为周末回去广州了没带电脑,二是因为之前提到过的健康问题去复诊折腾了两天,检查结果有点令人担忧(虽然结果最后发现虚惊一场),所以搞得有点心神不宁。Anyway,现在一切都好。

这周产出了一篇 TIL 文章 通过 git pre-commit hook 防止误提交二进制文件,解决了我开发 Golang 时候的一个很头疼的问题。

文章

接手,而不是「接锅」

原文链接

这篇文章一定程度上解开了我工作中很大的一个心结。

第二个点是我近期在工作中反复遇到的心态:「既然环境中有一个或几个人做得不好,我们是不是就不用正常做事了?」

换成更直白的话就是:「为什么他做得那么差你不去管,反而来要求我?」
...
当然,很多人并非不愿意对自己提高要求,他们的真实想法更可能是:「我可以继续保持高标准的产出,但你不能继续留着那些低素质的同事,这让我心理不平衡。」

这就是我平常很内耗的地方:我总是接手一些烂摊子,一些质量很差的代码,一些四处漏风的系统,在此同时你的同事还在往里添屎。在日常工作中我更多内耗的点就是,原来已经这么烂了,大家都在里面拉屎,那我要不要重构,还是说像别人一样交付需求就行了?

如果一个高素质的人,常常以「我已经做得很好了,你应该去要求别人」作为自己的退路,那么时间长了,他就和他口中那些低素质的人别无二致了。
...
而作为个人,我们也需要理解,我们不能拿要求自己的标准来要求世界上的每一个人。责任和分工各有不同,我们只需要专注于让自己变得越来越好。对于那些持续保持在较差水准的人,过度投射我们的关注,其实是对自己最大的不尊重。

这段话真的解开了我的心结。不可否认在领导层面这是很成功的 PUA,但讲得确实在理。

在任务栏中显示秒数会更耗电吗?

原文链接

LTT Labs 的文章。LTT Labs 是 LMG(Linus Media Group) 一个比较新的业务,主要做外设、电源之类的评测,也会有一些技术分析的文章。

他们做了两次实验,第一次的结果是显示秒数续航更短,符合大家的认知;但第二次的结果就完全相反。最后他们得出的结论是,开关与否,对日常使用的续航没太大的影响。

他们网站上还有一些很有意思的文章,例如近期对 Switch 2 Dock 的分析等。这个频道我关注了可能有十年了,在除了装机、评测硬件之外还能给观众持续带来新鲜感,这个问题很难,但是他们似乎解决得很好。

记录一下 AI 在医疗领域应用的实际体验

原文链接

作者分享了对「AI 报告解读」以及相关经历,表达了对这个功能的赞赏。

作为过来人我对这种功能表示非常质疑,我觉得在一些情况下,连人类医生在没有足够的上下文的情况下,都无法作出准确的判断,何况是 AI。

以我自己的经历来说,我在检查发现结节之后就多次咨询 AI,向它提供了足够多且准确的病情描述和检查结果,其实大多数情况下它给出的结果都是「足够准确」的,但是有些确实引起了我不必要的焦虑,例如在术后以及碘治疗后 tg 结果的解读,它认为数值过高,可能还有癌细胞残留,而医生解释道碘治疗后相关细胞破坏会导致大量释放 tg,需要一定时间内才会下降,要观察半年左右。事后再看,虽然当时 AI 也有提到过类似的点,但是我一点都没看进去,这就是 AI 的坏处,模棱两可的说法会让你产生恐慌。

这个错其实人类也会犯,上周我在核医学科复诊时,医生根据 PET/CT 、SPECT/CT、B 超以及甲功甲免的结果,认为「不能排除淋巴结转移」;而甲乳外科的医生在考虑了全部病史、检查结果之后,认为 tg 结果是下降中,而且淋巴结的形态正常,可以继续观察。

我觉得在医疗方面 AI 的切入点不应该是「解读」或者「诊断」。单一的检查结果在临床上很多时候没有决定性的意义,一般都需要结合多项检查结果、病史等等才有意义,这也是多数检查报告里会提到「请结合临床」的原因。医疗 AI 应该更加注重「确定性」的东西,不要吐模棱两可的话。面向患者这是增加恐慌的不必要精神负担;同时容易让患者在问诊过程中对医生产生质疑,例如「AI 说 xxx」,有点像以前的「百度说 xxx」,对医患关系也是不健康的。面向医生则可能是更大的问题,医生能否保持自己的独立判断和思考(在编程方面我就对 AI 形成了很大的依赖),这对患者来说是很关键的。

但是它可以起到「科普」的作用,例如解释清楚对应指标有什么含义,某项治疗的原理是什么、某种疾病的常见治疗方案和预后等等,可以在问诊前就让患者和医生构建一个比较好的沟通基础,这样的意义会更大。

Atlassian 收购了 The Browser Company

原文链接

一则小新闻,Atlassian 收购了 Arc 和 Dia。主要想谈谈我对 AI + 浏览器的想法。

我觉得我不需要一个 AI 为主的浏览器,浏览器还是原来的浏览器,只需要有一些插件有 AI 的功能。就像现在很多 AI IDE 意识到的那样,围绕 AI 从头再造一个编辑器是没有意义的,在 vscode 上提供一个好用的插件,深度集成就好,更甚者像 Claude Code 这样提供一个 CLI 就行。之前就提过一个类似的观点:

绝大部分 AI 不是一个产品,只是一个功能。

Dia 就走了这么一个弯路,它重新做了一个浏览器,虽然内核还是用的 Chromium (现在几乎没有人能离开 chromium 做浏览器了),但是完全没有继承 Arc 的很多功能,最喜欢的侧边栏没有,也没有办法 pin 页面(只有原始的收藏夹)。在「浏览器」这个功能上,远没有没有达到前任 Arc 的水平,甚至可以说没有到及格线。

不可否认事实上 AI 正在取代搜索引擎成为互联网的入口。但是我算是比较守旧的人,我还是喜欢自己搜索。我使用过 Google 自己的 AI、各种联网、MCP 等等,体验真的不尽人意。AI 没法解决的问题一是幻觉,二是对内容来源的筛选。互联网上有大量 SEO 很好的垃圾内容,例如内容农场,或者是像 CSDN、掘金这类用 AI 生成 SEO 内容的,尽管你可以用过滤列表解决内容农场的问题,但没法让 AI 判断文章质量再去判断是否采信。

Atlassian 这家公司也很有意思,除了大家也许熟知的 Jira、Confluence、BitBucket、Trello 等,还冠名了一支 F1 车队 Atlassian Williams Racing(就是大名鼎鼎、祖上阔过的威队)。

北航软件工程小记:用 Rust 开发「风行旅途」

原文链接

作者分享了他在「软件工程基础」课程上组队开发大作业的经历和体会。

我觉得算得上是很成功的大学教育,而且作者本身也非常值得敬佩。我读书的时候,所谓大作业几乎就是实现几个很简单的功能,只要求有前后端,有个管理后台,演示的时候能走完流程,就算 ok。作者这个课程还要求了微服务、单元测试、CI/CD、测试这些知识点和流程,不清楚课程中老师或者助教有没有详细讲解,还是要求学生自己探索,不管怎么样这课程质量真的很好。

我记得我的学校几乎没有工作中用得上的课程,有门课程还在讲 IBM 一个停止更新了很多年的消息中间件,也从来不提微服务、CI/CD、git 这些东西,就把课本上的基础知识讲一遍。大作业的体验更是噩梦,总有人组队就是抱大腿不干活,不写代码,不写报告,让他做个 ppt 都要推脱。也许学校之间的差异就在这里。

「极客死亡计划」的设计哲学

原文链接

我很喜欢的一个博客,作者分享了他对博客设计的一些想法。上期我刚说完很喜欢博客的字体和排版,以及那个返回顶部的交互,刚好这周作者就分享了更多的设计的细节,真巧!

我时不时也对博客进行一些装修,但由于我使用的是开源的博客软件,所以可以自定义的部分就相对少一点。现在的主题阅读体验还算不错,所以更多时候我会花时间精力在博客的内容上。

想法

Claude Pro 订阅

上面说过,我对 AI 编程其实产生了比较大的依赖。不是我不会写,单纯是不想写,明明动动嘴就可以做完的事真没必要自己动手。然而上周好像出现大规模封号的问题,在用的中转变得不可用了,所以找了一些替代方案。

在用的中转给出的方案是更贵一档的「头等舱拼车套餐」,我没去询价,感觉不会很值。最显而易见的方案则是其他类似的中转,在论坛里看到一篇不错的帖子评测了一些中转商家,感兴趣也可以看一下。我没再找中转的原因一是因为不可用的原因和情况是普遍的,换个商家估计情况也差不多;二是帖子里一些中转商家会往里掺东西,获得不了完全和原生一致的体验;三是现在有三个月五折的活动,Claude Pro 只要 $10。

用官方的服务主要是两个难点,一个是封号,另一个是付款。封号这点太难受了,我之前用的 OpenAI 账号和 Anthropic 账号已经都被封了,原因要么是付款的卡段一起被连坐,要么就是不小心用了国内的 IP 访问,申诉也没用,甚至 OpenAI 上次有几刀的余额也没有退款。付款这点也很蛋疼,只能用虚拟信用卡或者国外银行卡(港卡也不行),前者入金还比较麻烦,也不保证什么时候就跑路/被连坐了;又或者去买美区的礼品卡,通过苹果订阅。

简单分享一下我现在的方案,也许后面会写一两篇文章详细介绍,大概就是:

  • 用新的邮箱注册 Claude 账号
  • 绑定 SafePal 的 U 卡支付
  • Stash 开启增强模式,保证 CLI 也走代理

总之订阅之后稳定使用了两三天,暂时还没有出问题。

你可以通过这个链接 https://claude.ai/acquired 订阅 Claude Pro,可以有三个月五折。上面提到的 SafePal 可以通过我的 aff 链接 注册,可以获得积分,后续有费率优惠。另外现在也有活动,花 $5 运费,即可免费获得一个硬件钱包。

也谈谈信息焦虑

上期聊过,我对文章有一个 Yay/Nay 的标准,虽然通过自订的信息流,已经把我要看的内容限制在了一个比较合理的范围,但其实我的浏览器里还是会堆积一大堆标签页,每次都在想「等我有更多精力专心去读的时候再看」或者「我想深度去读一下这篇文章」,结果就在那里放到被自动关掉。

Nay 会导致我看两眼就关掉文章,而 Yay 会让我看完之后再回味,或者放到周刊里推荐。

虽然之前提到过,写周刊不会对我产生很大的创作压力,这反而是一种表达渠道和很有满足感的事情,但消化这些信息源确实一定程度上对我产生了一点认知压力。上周提到的「个人偏好引擎」是我一个比较想探索的方向,目前我的筛选很大程度上只是根据标题和打开页面后的初印象,内容本身是否值得我深度去读,则需要消耗实际的时间精力去判断。

另外一个想法是,我现在信息的来源(RSS、各种网站等)、收藏(Karakeep)、整理输出(博客)其实是分离的,我有点想在上面的「个人偏好引擎」中整合一下 RSS 和收藏的功能,让它变成一个「个人信息源」集合的地方。

这块的想法其实还比较凌乱,但是「个人偏好引擎」这块倒是已经新建文件夹在开发了,如果你有想法,不妨通过评论或者邮件跟我交流。

项目

ccstatusline

sirmalloc/ccstatusline - GitHub
项目链接

一个方便自定义 Claude Code 的 statusline 的工具。我目前的配置如下图:

其实主要有用的是中间的上下文使用率,方便去判断什么时候应该执行 /compact

ccusage

ryoppippi/ccusage - GitHub

项目链接

Claude Code 的用量统计,通过本地的文件+在线更新的价格,输出报表。

这个其实主要起一个情绪价值的作用,正常情况下,我每天大概消耗 $5 左右的 token,Claude Pro 订阅一个月才 $20(现在优惠三个月 $10),血赚!

工具/网站

Claude Code Cheatsheet

网站链接

Claude Code 的一些快捷键、常用命令、文件位置等,整理成了正好一张 A4 纸的 PDF。也有更完整的网页版

最后

本周刊已在 GitHub 开源,欢迎 star。同时,如果你有好的内容,也欢迎投稿。如果你觉得周刊的内容不错,可以分享给你的朋友,让更多人了解到好的内容,对我也是一种认可和鼓励。(或许你也可以请我喝杯咖啡

另外,我建了一个交流群,欢迎入群讨论或反馈,可以通过文章头部的联系邮箱私信我获得入群方式。

通过 git pre-commit hook 防止误提交二进制文件

2025年9月5日 00:58

在开发 Go 的时候经常不小心把二进制 commit 上去(顺手就 gaa 了),虽然有几个不太靠谱的方法似乎能避免,例如

  • 把二进制的名称放进 .gitignore,仅限项目有 Makefile 的时候可能好用,换个名就完蛋。
  • 如果 git add 的时候耗时特别长,应该发觉完蛋。
  • 提交前通过 git status 好好看看 stage。

提交错了怎么处理这里就不展开叙述,反正就是很麻烦,会把仓库撑大,简单删除不行,要递归删除,还会搞乱提交历史,然后覆盖远端,非常麻烦。

但是我们可以通过 pre-commit hook 来检测 stage 里是否有二进制文件,并且在检测到时给出指引如何去掉二进制文件。

修改项目中 .git/hooks/pre-commit 为以下内容即可。

#!/bin/sh

# Function to detect binary files
detect_binaries() {
    echo "Checking for binary files..."

    # Get list of files to be committed (cached/staged files)
    files_to_commit=$(git diff --cached --name-only --diff-filter=A)

    if [ -z "$files_to_commit" ]; then
        return 0
    fi

    binary_files=""

    # Check each file
    for file in $files_to_commit; do
        if [ -f "$file" ]; then
            # Use file command to detect binary files
            if file "$file" | grep -q "binary\|executable\|ELF\|PE32\|Mach-O"; then
                binary_files="$binary_files $file"
            fi

            # Also check for common binary file extensions
            case "$file" in
                *.exe|*.dll|*.so|*.dylib|*.a|*.o|*.bin|*.class|*.jar|*.war|*.ear|*.pyc|*.pyo|*.pyd)
                    binary_files="$binary_files $file"
                    ;;
            esac
        fi
    done

    if [ -n "$binary_files" ]; then
        echo "ERROR: Binary files detected in commit:"
        for file in $binary_files; do
            echo "  - $file"
        done
        echo ""
        echo "To remove these files from staging:"
        for file in $binary_files; do
            echo "  git reset HEAD '$file'"
        done
        echo ""
        echo "Consider adding these patterns to .gitignore to prevent future commits."
        return 1
    fi

    return 0
}

# Check for binary files first
detect_binaries
if [ $? -ne 0 ]; then
    echo "Pre-commit hook failed: Binary files detected."
    exit 1
fi

效果如下

❌