大家好,我又来了。
本来以为写完第七章的性能优化,这个系列就该画个句号了。但本着“贼不走空”的极客精神,我又在源码的src目录下瞎溜达了一圈。
结果,在一个叫src/buddy/的隐秘角落里,我挖到了 Anthropic 工程师们藏的一个惊天大彩蛋——他们居然在一个硬核的 CLI 效率工具里,偷偷塞了个电子宠物(Buddy)系统!
你想啊,在这个枯燥的命令行世界里,当你每天被满屏的报错、跑不通的单测折磨得想砸键盘的时候,如果终端角落里能有一只专属于你的、独一无二的小鸭子或者小恐龙陪着你,是不是瞬间就觉得没那么烦躁了?
今天咱们就当个番外篇,不聊什么高深架构,纯粹用扒一扒代码的方式,看看牛啤工程师们的浪漫是怎么写进代码里的。
源码里藏着什么好玩的?
翻开src/buddy/目录,你会发现他们不仅写了个彩蛋,还真把它当成个微型 RPG 游戏在做:
- 看看他们是怎么用伪随机数生成器(PRNG)来搞“抽卡”的。
- 看看为了防作弊(防止玩家改配置刷极品宠物),他们是怎么设计“骨肉分离”的数据结构的。
- 甚至为了躲开代码扫描工具的误伤,他们是怎么给宠物种类名字“加密”的。
1. 抽卡机制与 Mulberry32 算法
这只小宠物是怎么“生”出来的呢?如果你打开src/buddy/companion.ts,你会看到一个叫mulberry32的函数。
为了保证你的宠物虽然属性是随机的,但只要“种子(Seed)”不变,你每次打开终端它都长得一模一样,他们专门手搓了这个轻量级的伪随机数算法。官方还在注释里调侃了一句:
// src/buddy/companion.ts// Mulberry32 — tiny seeded PRNG, good enough for picking ducks// 翻译:“足够用来抽鸭子了” 😂functionmulberry32(seed:number):()=>number{leta=seed>>>0returnfunction(){a|=0a=(a+0x6d2b79f5)|0lett=Math.imul(a^(a>>>15),1|a)t=(t+Math.imul(t^(t>>>7),61|t))^treturn((t^(t>>>14))>>>0)/4294967296}}他们把你的账号 ID 或者本地标识(userId + SALT)哈希处理后当做 Seed。这意味着什么?
这意味着从你用 Claude Code 的那一刻起,你的这台电脑、这个账号,注定只会孵化出那只命中注定的宠物。
2. 稀有度、属性与“闪光”设定
玩过抽卡手游的兄弟们都知道,SSR 有多难出。Anthropic 的工程师们把这套拿捏得死死的。
在src/buddy/types.ts里,我看到了完整的概率表(RARITY_WEIGHTS):
- Common(普通): 60%
- Uncommon(罕见): 25%
- Rare(稀有): 10%
- Epic(史诗): 4%
- Legendary(传说): 1%
宠物甚至有五维属性:DEBUGGING(调试)、PATIENCE(耐心)、CHAOS(混沌)、WISDOM(智慧)、SNARK(毒舌)。
稀有度越高,属性的保底值就越高。而且,每次生成必定有一个巅峰属性和一个拉胯的“下水道”属性。
最离谱的是,他们还加了个类似宝可梦的“闪光(shiny)”机制,只有可怜的 1% 概率触发:
// 只有不到百分之一的欧皇能拿到闪光宠物shiny:rng()<0.01,3. 防作弊设计:骨肉分离的“灵魂”
既然属性这么难抽,那我直接去改本地配置文件(config.json),给自己捏个“闪光传说级”宠物不就行了?
抱歉,你想到的,工程师早想到了。
他们把宠物的数据拆成了两半:CompanionBones(骨架)和CompanionSoul(灵魂)。
- 灵魂(名字、性格):是由大模型根据你的属性自动生成的,保存在你的本地配置里。
- 骨架(稀有度、种类、属性、外观):从来不保存!每次启动时,它都会严格根据你的
userId重新计算一遍。
源码里是这么写的:
// src/buddy/companion.ts// What actually persists in config. Bones are regenerated from hash(userId)// on every read so... users can't edit their way to a legendary.// 翻译:骨架每次读取时从哈希重新生成,这样玩家就没法通过改配置来刷传说宠物了。这波操作,直接把想作弊的黑客们按死在了起跑线上。
4. 为了躲避扫描,连物种名都加密了
在看物种列表时,我发现了一段极其诡异的代码。普通的数组定义不写,非要用String.fromCharCode把字母一个个拼出来:
// src/buddy/types.tsconstc=String.fromCharCodeexportconstduck=c(0x64,0x75,0x63,0x6b)as'duck'// 鸭子exportconstoctopus=c(0x6f,0x63,0x74,0x6f,0x70,0x75,0x73)as'octopus'// 章鱼为什么要这么搞?注释里给出了答案:
- 原来他们内部有一个“敏感词扫描”工具,用来防止代码里泄露正在研发的 AI 模型代号(codename)。
- 结果很不巧,某个宠物的名字跟内部未发布的模型代号撞车了!
- 为了不让扫描工具天天报假警,工程师干脆把所有的宠物名字都在运行时动态拼装,绕过了静态扫描。
- 这真是一个被逼出来的机智操作啊!
最后:这才是工程师的浪漫
看完整个src/buddy/模块,我确实被这帮老外圈粉了。
在一个承载着巨量代码、复杂的 AST 解析、深度的 MCP 协议的硬核效率工具里,在一个每天都在卷性能、卷大模型智商的环境下,他们依然愿意花时间写这么一套对核心功能毫无帮助、却趣味拉满的代码。
可能它只是终端里一只戴着高顶礼帽、长着星星眼的 ASCII 小鸭子,但它确实能在某个深夜,给那些对着屏幕抓头发的程序员们,带来一丝会心的微笑。
这,大概就是写代码最纯粹的乐趣吧。
开源
我自己也做了一个桌宠,还在迭代中:
CodeWalkers:让 AI 助手化身桌面宠物,陪你敲代码的赛博伙伴!
源码地址:https://github.com/you-want/CodeWalkers 欢迎给个 Star ✨。