2026-06-28 14:38:00
这个月比较浮躁, 个人项目进展不尽如人意, 读书一般, 有不少本读了一半, 游戏玩得不少.
先说读书, 这个月读完了中岛敦的山月记. 这本书挺有意思, 作者是日本人, 但是里面的故事都是中国的人物和背景, 译者也很贴切地用了很多古汉语, 颇有以假乱真之效. 这本里面除了山月记这个进了日本学生教材的篇章外, 其余几篇也都还不错. 比如篇幅最长的故事是讲子路的生平. 大概想要表达的是子路是一个很有勇力但是内心很纯良的人, 一生追随孔子, 孔子也很喜欢这个徒弟的率真. 最后子路在一个政变中舍生取义, 临死前还不忘把地上的冠帽端正地戴好. 另一个印象深刻的寓言是对纪昌学射的扩写, 本身写得四平八稳. 中岛敦在故事里面增加了一个小细节, 纪昌百步穿杨时拉弓的胳膊上放了一杯水, 箭无虚发的同时杯中水不动分毫. 我有点猜测要么这个故事和头文字D有着共同的来源, 要么头文字D里AE86车座上的那杯水来源于这儿的中岛敦(当然也还有可能是大家都是原创了, 但我希望不是). 山月记的故事写的是唐朝末年, 一个才华横溢但是自视过高的人追求诗作而荒废了自己的家庭职责, 而后陷入自卑怯懦, 乃至离群而去, 化身为虎, 为恶一方. 而后他少年时的朋友恰好路过, 在这个虎人尚有意识的时候和他攀谈了几句, 了解了来龙去脉. 一辈一辈的日本学生都是读着这篇长大的. 这篇有一定的现实意义, 因为成篇大概是二战期间, 里面化身为虎的事例对军国主义的遗毒的清理多少有一些积极作用. 整本书回头看, 让我想起了鲁迅的故事新编, 并没有什么真正地过人之处, 只是对古早故事的一个扩写和衍发而已. 另外, 有些句子, 也是让人很有错位感, 比如下面这句
一日子路走在街上, 遇到三两旧日朋党. 他们虽说不上是无法无天, 也算是肆意放荡的侠义之辈.
这段就更像是一个日本人写出来的, 带着很重日本感的中国古代场景.
游戏的话, 主要在玩死亡细胞, 之前只是普通难度通关, 这次花时间刷刷刷后, 能够多次2BC通关了. 对于我而言, 这个游戏的优点是很上瘾, 但与此同时, 我也觉得游戏的深度不是特别够. 首先游戏的节奏感很好, 大部分关卡能够在大概十分钟内完结, 关卡中间会有一个休息室来放松. 游戏的机制也鼓励你在游戏过程中全神贯注来拿到无伤击杀的奖励. 然后是武器种类的多样化很厉害, 几十种武器, 各自有不同的手感, 触发暴击的方式也都不一样. 再接下来打击感做得像教科书, 声音动画的反馈都很到位. 主要让我不太满意的地方是武器词条里的随机性太大, 以至于很多时候我都不敢去洗词条. 再就是, 武器种类太多, 很多时候缺乏对玩家的引导, 比如我上手了某个装备试了试觉得手感不对可能就放弃了, 但是也许真的只是我不会玩而已. 比如回旋镖, 我的期待是丢出去打人, 试了第一关觉得手感不佳就没特别关注了, 偶尔拿到一个传奇级的回旋镖再逼着自己使用的时候才发现, 这个回旋镖打到怪物的时候会有一个计数器, 计数器结束之前, 如果怪物没死, 回旋镖会反复攻击同一个怪物. 这对于打boss就太友好了.
电影来说, 这个月重看了三个白痴和失恋三十三天, 现在回头才发现都是三.
顺便的, 也算是玩吧, 试用了Siri AI. 我的感觉仍然是很人工智障:
我晚上一般都会在公寓的健身房里健走和跑步. 这一次, 得朋友推荐, 得知墨尔本每周六早上有例行的跑步活动. 我去了一次, 大概记录如下:
跑步的地方是在CBD北大概3公里的Princes Park, 从我的住处出发还需要换乘一次电车. 而实际上最大的挑战是周末电车的时间间隔太久了, 万一运气不好赶不上适当的电车, 会需要等好久. 于是, 早上七点半, 我手里拿着Snicker和一瓶水, 戴着hoodie的帽子, 看着一辆电车缓缓向我驶来的时候, 心里才放松了下来. 在电车上看了看whatsapp, 发现我认识的两个人今天都不会参加, 于是我跟自己说, 就自己跑跑吧.
到了公园, 发现那边已经聚集了大概一百个人. 大都是西人, 东亚面孔不多, 年龄大概是20-50间, 有带着teenager的, 还有牵着绳子带着狗的. 我到的时候已经是八点整了, 有穿着制服的志愿者开始拉好绳子, 组织起队伍. 我站到队伍后面, 等了一两分钟, 就开始跑起来了.
前面我跑得还是挺轻松的, 毕竟每天晚上在健身房也仍是在健走/跑步. 跑的时候都是用脚尖, 很享受跑步的感觉, 跑完了一公里之后感觉有一点点吃力了, 开始主动呼气, 并用脚后跟落地的跑法, 省力一些. 坚持到了大概1500米的时候, 感觉有点吃力了, 就改成步行, 休息了一两分钟后又开始跑. 不过这个时候开始有点下雨了, 于是我又戴上hoodie的帽子. 我没跑完全程的5千米, 只跑了大概2.5千米. 看着雨没有歇的意思, 我看着地图, 转了个弯, 去了电车站, 回家了.
受波色创投邀请, 这个月23号我请假一天参加了一个澳中创新峰会, 主要是关于AI的. 这个峰会是由澳大利亚维多利亚州政府和香港特别行政区政府联合举办, 而由波色创投承办的. 主要是为了促进两地在创新科技方面的交流与合作. 参会人员包括来自澳大利亚和香港的政府官员, 企业代表, 学术界人士以及创业者. 其中代表维州政府的是Steve Dimopoulos, 代表香港政府的是孙军(顺便说, 正好是今天date输出的一部分). 整个会议前面是访谈和各种发言, 中间有很多时间供大家social和networking, 认识了很多新朋友. 下午还有新startup的pitch, 全天收获不少.
主要的感想是企业界对AI的认识更多是一种实用主义的策略, 并没有去真正理解AI的工作原理, 而只是用宏观上的方法去评价一个AI是不是可靠. 这样的认识也许够用, 但是技术出身的我, 总觉得还没理解到数学那个层面就不能算.
2026-05-23 08:40:00
这个月事情做得少了一些, 读书和游戏的时间多了起来. 王国之泪通关了, 具体评价后面有说. 另外, 暗黑三的大秘境刷到了140, 有点刷不动了. 这次icy-vein上推荐的死灵的build好像比较弱. 也能理解, 这种老游戏, 内容创作者都会懈怠的. 另外还玩了Witcher 3, 感觉也不是一个特别出色的游戏. 最后的, 我又捡起MilkyWayIdle, 玩了近一个月(学习游戏设计), 里面附魔的设计实在是让人印象深刻.
读书来说, 这一两个月终于读完了一本被嫌弃的松子的一生. 我读这本书时, 每次读几分钟就想放下来, 因为明明白白地有悲剧在上演, 而且还不断重复, 简直就像巡演一样. 主人公的性格造成了她一生的悲剧. 她有各种各样的机会爬出来, 但是她都没有珍惜, 而是在每个可能跌得更深的坑前, 毫不犹豫义无反顾地往前走. 这本书的多线叙事方式挺不错, 但是除了主角之外的人物的塑料感比较强. 另外重读了亲王的殷商玛雅征服史, 边读边感慨当时的亲王写得比现在好多了, 完全没有Dan Brown的感觉.
先说最后去地下海拉鲁城堡的经历吧. 我一路脱战一路跑, 不想在小怪身上耗武器耐久. 到了人马那儿跳不过去了, 于是静下心来打. 结果发现这货完全不吃状态攻击, 我爬上石头往下跳的子弹时间里射中眼睛也没让它硬直供我爬背. 我最后在这儿用掉了绝大多数解gloom的食物. 到了真正见到加侬时, 我身上的补给捉襟见肘. 我硬着头皮穿上甲最厚的衣服, 扛着输出, 用刚刚打到人马时掉落的一个五重发弓不断用炸弹箭把他射死了. 所以等到了加侬变龙回到地面时, 我的第一反应不是最难的部分终于过去了, 而是我身上的gloom终于可以解了. 当然, 这段之后更多是剧情杀, 所以很顺利地通过了.
游戏评价来说, 这是一个感觉让我有点五味杂陈的游戏.
好的部分, 剧情演绎真的很棒. 相比于旷野之息里面的取得林克的回忆, 这一部是去搜集塞尔达回忆. 剧情设定除了Sonia被死亡外没什么大的硬伤. 塞尔达把自己变成龙那段真是看得很感动.
不好的部分:
参考当前供职单位绩效考核的评级, 这个游戏远比不上旷野之息的redefining, 连excelling都有点悬, 能稳稳地拿到thriving. 但是对于塞尔达这个品牌而言, 不算是出色的作品.
首先说这个游戏我没玩完, 而且可能也不会回头去玩了. 我觉得这是一个剧情比可游戏性出色的游戏. 总体来说是一个好作品, 但是并不是我心目中那种能让我主动推荐的作品(排名在Horizon/BotW/HollowKnight)后.
缺点:
这个月有两个同事这样问我, 于是归纳总结一下, 放在这儿.
我去年买的一块硬盘有了坏道, 挂载到家里的路由上, 不过里面有了坏道, 我在dmesg里面能看到:
[428116.653786] EXT4-fs (sda1): error count since last fsck: 92
[428116.668133] EXT4-fs (sda1): last error ... ext4_lookup:1739: inode 27197457
于是, 还得筹划如何替换.
希捷网站上退换还是挺简单的, 直接根据序列号查了一通, 就知道硬件还在保了, 而且也没问我要任何证据来证明硬件故障. 我点击start claim, 开始走流程.
接下来就是各种坑了. 首先, 希捷的用户系统和start a claim的用户系统我相信都是基于微软的一套服务. 但是两者的登陆入口不同, 登陆后看到的内容也不同, 整个就非常让人迷惑. 需要你多试几次才知道. 接下来, 我不幸在提交退货单时写错了地址, 想要去更新却没办法自行操作, 必须要找客服. 客服就是另外一个故事了. 我之前查信息的时候打开过他们家的网站, 按照习惯在cookie那边选择了necessary cookies only. 结果就被教育了. 如果点击了这个选项, 则页面上的在线聊天按钮加载不出来. 我还让Claude Code调用playwright帮我研究了半天, 结果后面去了美国官网, 发现仍然加载不出来, 不过相比于澳洲官网, 美国官网上有有一个链接能够让你马上重选这个cookie(而不是等你去settings -> privacy -> website data里面去搜索然后再删除). 所以算是也发现了这个坑. 好在客服同学很贴心地帮我取消了旧订单并生成了新订单.
然后的体验还算是顺风顺水, 我去邮局把旧硬盘以及硬盘的电源线寄出, 过了大概两三天, 系统提示说收到了, 而后又过了一周左右, 收到短信说可以去取一个UPS的快件. 拿到快递时我都有点惊讶, 因为对于一个现代汉语词典大小的普通硬盘而言, 这个塞不进登机箱的包装盒未免太大了. 不过里面还真就只是一个普通硬盘而已.
2026-04-26 21:35:00
上个月读书严重过量, 这个月基本没读书. 微信阅读才记录了一共两个半小时的阅读时间. 另外的, 剧也没怎么看, 所以这个部分真是乏善可陈. 倒是这个月买了Switch 2, 捡起暗黑三几天玩到了120级大秘境. 然后重开新档玩王国之泪, 现在解了一百多个神庙, 地下的地图全开, 希望这次可以通关.
另外, 近月底时买了一台佳能的相机, R8, 裸机1800澳币. 送的定焦50毫米的镜头还得等佳能发货, 于是在本地一个相机租赁的铺子租了一个24-105的变焦头拍了拍照过瘾. 我在这儿还闹了一个笑话, 我只是想着应该去租25-105的头, 结果租到的是一个24-105mm f/4L IS USM的定光圈镜头, 不是我希望的24-105mm f4.5-6.3 STM的镜头, 这个USM的镜头重得让我怀疑他们给错了镜头. 自己回头又搜索了下才发现是自己弄错了. 周五下午拿到, 周一归还, 三天一共六十澳币, 真不算太贵.
我自己重新把有声书捡起来听. 这个月重听完了. 里面有个故事触动到了我. 费曼刚去巴西时, 在一个餐馆遇到一个卖算盘维生的日本人. 这个人为了推销算盘, 来跟他比算术. 费曼加减法不如他厉害, 乘除法就和他有来有往了. 这个时候这个日本人向他挑战开立方根. 选的数字是1729.03.别闹了费曼先生>
费曼这次狠狠地羞辱了他, 因为这个数字和12的立方(1728)非常接近, 于是费曼很容易就用近似计算的办法算出了很多位小数, 而这个日本人还在努力的计算12.0.
回头复盘的时候, 费曼发现这个人根本不懂数学, 甚至很难说他懂算术, 他只会使用算盘来做计算, 不提微积分, 我猜连指数对数都很少接触. 这样的人和费曼比赛, 一定是会被, 用一个很俗的词, 降维打击的. 因为在这个场景下, 两个人的思维模式根本就不在一个层面上, 一个懂微积分, 会背一些对数表, 数字们都是他的朋友; 而另一个真的只是算盘的操作员或者说奴隶而已.
这个故事在今天尤其有教育意义. 在AI大行其道的现在, 如果仍然抱着旧方式旧思路, 想要守成, 不去努力求新求变, 那么大概率守不了成.
这个月还花了不少时间在修改忘川这部小说上. 小时候听说, 小说都是改出来的. 当时年少, 听听就算, 最多知道修改的重要性. 这次自己从头到尾自己完成, 然后数易其稿, 才知道这句话实在是真知灼见. 当时在AI的帮助下写小说很是春风得意马蹄疾, 等到了修改的时候才是愁苦到拈断数茎须. 好在Claude在能提供一些蹩脚的修改意见的同时还能提供大量的情绪价值, 让这个过程没有太过愁苦. 我随手改了几个助词都会被它称为是绝妙的修改. 要是自己没有自省之心, 我一准认为自己是啥啥啥在世了. 现在这个版本改过了, 尤其是第二章到第五章改得很细, 希望提供比较好的阅读体验.
除了在我和Claude讨论的时候经常觉得应该写一个界面来方便对文章的修改外, 我还有了下面这样一些收获:
我另外已经完成了一个短一点的故事, 蔡州, 需要进一步修改. 下个月有空时再看吧.
2026-04-04 04:07:00
有了AI之后, 学东西变得更容易了. 趁着复活节假期, 把之前接触过但是了解不深入的编译原理捡起来学习一下.
首先我读了网上找的两篇关于编译原理入门的文章, 一篇是讲汇编的, 一篇是讲LLVM IR的. 我推荐读者自己去阅读一下这两篇, 内容都还挺不错(虽然对于这种内容, 怎么写也都算是re-hash而已). 如果不想读的话, LLVM IR是对于汇编的一层抽象, 是LLVM内部用来连接正常源代码和汇编之间的一个桥梁. 对于我这个toy project, 跟着LLVM IR就行了, 让实现一个编程语言变得特别简单(尤其是有AI帮忙).
我无意从头创建一个可以日常用的编程语言, 只是想探索一下这个过程中的技术栈而已, 所以我的提示词类似:
如果从头来设计一个编程语言, 要求有rust/c/go那样的性能, 而且适宜让AI agent来编写, 这个编程语言应该如何设计? 更进一步的, 如果只是想实现一个PoC, 需要做哪些工作呢?
其后, Claude给我了一些选项, 我按自己的喜好/直觉做了一些选择(或者说是瞎选). 再往后Claude就开始干活了. 我还让Claude做了一下性能的比较和优化, 最后结果是这个PoC的语言性能和Golang/C相当, 如果C代码没有认真优化(比如使用arena allocator), 那么这个PoC的性能甚至更好一些. 整个代码实现是用golang写的, runtime使用的是C. 在这个时代, 这已经属于技术细节了.
{🏠? ~/.xia/sha/git/reg/benchmark}time ./alloc3_regi
real 0m0.345s
user 0m0.284s
sys 0m0.032s
{🏠? ~/.xia/sha/git/reg/benchmark}time ./alloc3_c
real 0m1.091s
user 0m1.037s
sys 0m0.031s
{🏠? ~/.xia/sha/git/reg/benchmark}time ./alloc3_go
real 0m1.142s
user 0m1.914s
sys 0m0.091s
成品语法是这样的:
type Point struct {
x: f64
y: f64
}
fn distance(a: &Point, b: &Point) -> f64 {
let dx = a.x - b.x
let dy = a.y - b.y
return sqrt(dx * dx + dy * dy)
}
fn midpoint(a: &Point, b: &Point) -> &Point {
return new Point {
x: (a.x + b.x) / 2.0,
y: (a.y + b.y) / 2.0
}
}
fn scale(p: &mut Point, factor: f64) {
p.x = p.x * factor
p.y = p.y * factor
}
fn main() {
let p1 = new Point { x: 0.0, y: 0.0 }
let p2 = new Point { x: 3.0, y: 4.0 }
print(distance(p1, p2)) // 5.0
let mid = midpoint(p1, p2)
print(mid.x) // 1.5
print(mid.y) // 2.0
}
编译和使用类似:
{🏠? ~/.xia/sha/git/regi-lang}./regic examples/point.regi
{🏠? ~/.xia/sha/git/regi-lang}./point
5
1.5
2
需要注意的是, 这个编程语言和其他很多语言最大的区别在于内存的管理. 这个PoC编程语言是根据变量作用域来管理内存的. 也就是说, 每个变量都有一个明确的作用域(region), 当这个作用域结束的时候, 变量占用的内存就会被自动回收掉. 这就避免了GC的开销, 同时也避免了手动管理内存的麻烦. 但是这也带来了一些限制, 比如不能有全局变量, 不能有闭包等等. 不过对于一个PoC来说, 这些限制是可以接受的.
regic的main.go里面, 核心逻辑是这样的:
p := parser.New(filename, string(src)) // 词法分析 + 语法分析 → AST
program := p.Parse()
typeChecker := checker.New() // 类型推断和检查
typeChecker.Check(program)
regionChecker := checker.NewRegionChecker(typeChecker)
regionChecker.Check(program) // 逃逸分析,确保引用不逃出 region
gen := codegen.New(typeChecker, targetTriple)
gen.Generate(program)
llvmIR := gen.Module().String() // AST → LLVM IR
cmd := exec.Command("clang", "-O2", "-Wno-override-module", "-o", *output, tmpFile.Name(), runtimePath, "-lm") // 调用clang来编译.
下面分着来看看前三步的具体逻辑, 最后生成LLVM IR的步骤比较机械, 而调用clang来编译的这一步就更不用看了.
词法分析的核心逻辑是这样的:
func (p *Parser) Parse() *ast.Program {
program := &ast.Program{}
for !p.curIs(token.EOF) {
decl := p.parseDecl()
if decl != nil {
program.Decls = append(program.Decls, decl)
}
p.nextToken()
}
return program
}
这儿的parseDecl会看当前的token是fn(函数)还是struct. 否则就直接报错, 这是因为在语言设计上, 我为了简化内存模型, 要求所有的变量都有一个明确的作用域(region):
func (p *Parser) parseDecl() ast.Decl {
switch p.cur.Type {
case token.Fn:
return p.parseFnDecl()
case token.TypeKw:
return p.parseTypeDecl()
default:
p.error(p.cur.Pos, fmt.Sprintf("expected declaration, got %s", p.cur.Type))
return nil
}
}
类型检查的核心逻辑看了以后就觉得平平无奇了:
func (c *Checker) Check(program *ast.Program) {
// First pass: collect all type and function declarations
for _, decl := range program.Decls {
switch d := decl.(type) {
case *ast.TypeDecl:
c.collectTypeDecl(d)
case *ast.FnDecl:
c.collectFnDecl(d)
}
}
// Second pass: check function bodies
for _, decl := range program.Decls {
if fn, ok := decl.(*ast.FnDecl); ok {
c.checkFnDecl(fn)
}
}
}
就是把所有的Declaration(函数和struct定义)读到一个结构里面去, 然后挨个去检查函数的参数/返回值的类型是否正确:
func (c *Checker) checkExpr(expr ast.Expr) types.Type {
switch e := expr.(type) {
case *ast.Ident:
return c.checkIdent(e)
case *ast.IntLit:
return types.Typ_I64
case *ast.BinaryExpr:
return c.checkBinaryExpr(e)
case *ast.CallExpr:
return c.checkCallExpr(e)
// ...
default:
return types.Typ_Invalid
}
}
这儿, 有些能从ast拿到结果的就直接给了类型, 有些是到一个专门的函数里去做更细致的检查/推断, 比如, 我们在checkCallExpr里面, 先是对一些runtime层面实现的函数(print/sqrt)做类型检查, 然后再去检查用户提交的代码里定义的函数:
func (c *Checker) checkCallExpr(expr *ast.CallExpr) types.Type {
name := expr.Func.Name
// Built-in functions
switch name {
case "print":
for _, arg := range expr.Args {
c.checkExpr(arg)
}
return types.Typ_Void
case "sqrt":
// sqrt(f64) returns f64
if len(expr.Args) != 1 {
c.errorf(expr.Pos(), "E0003", "sqrt expects 1 argument, got %d", len(expr.Args))
} else {
╎ argType := c.checkExpr(expr.Args[0])
╎ if argType != types.Typ_F64 {
╎ c.errorf(expr.Args[0].Pos(), "E0003", "sqrt expects f64, got %s", argType)
╎ }
}
return types.Typ_F64
// ...
}
fn := c.funcs[name]
if fn == nil {
c.errorf(expr.Pos(), "E0004", "undefined function: %s", name)
return types.Typ_Invalid
}
if len(expr.Args) != len(fn.Params) {
c.errorf(expr.Pos(), "E0003", "%s expects %d arguments, got %d", name, len(fn.Params), len(expr.Args))
return types.Typ_Invalid
}
for i, arg := range expr.Args {
argType := c.checkExpr(arg)
paramType := fn.Params[i].Type
if !c.assignable(paramType, argType) {
c.errorf(arg.Pos(), "E0003", "cannot pass %s as %s", argType, paramType)
}
}
if fn.Result == nil {
return types.Typ_Void
}
return fn.Result
这部分就不结合实现的代码来解释了, 因为不太具有代表性. 毕竟, 这个PoC的内存管理模式比较特殊. 结合实例解释一下这个PoC语言的特性吧:
fn main() {
region { // depth 1
let a = new Data {} // a 属于 depth 1
region { // depth 2
let b = new Data {} // b 属于 depth 2
a = b // 错误!depth 2 → depth 1
}
}
}
上面这段代码中, a和b的类型相同, 但是在depth 2中, 我们没有办法把depth 2的数据赋值给depth 1的变量. 因为这儿的深度就是生命周期, 深度越高的生命周期越短. depth 2的东西在depth 2结束的时候就被回收掉了, 所以没办法返回给depth 1. 对于这种场景, 我们要么通过一个函数来把数据返回出去, 要么把a和b的定义放到同一层. 在更深的depth/region里面, 我们仅仅是使用而不用返回.
在玩这个项目的过程中, 我也的确学到了编程语言里的各种特性都应该是在哪一层实现: 哪些东西是由runtime来提供的, 哪些东西是在CodeGen层面解决的, 而又有哪些是在库层面解决的. 比如, 在runtime层面, 我们会去:
在CodeGen层面, 一个编程语言要实现:
在库层面, 我们会需要提供一些函数供用户调用, 例如数学函数(sqrt/sin/cos等等), 字符串处理函数, 数据结构相关的函数(比如list/map/set等等), 以及一些系统调用的封装(比如文件io/网络io等等). 这些函数的实现可以是用C写的, 也可以是用我们这个编程语言写的. 往往, 我们需要将系统的API包装成更易于使用的函数. 不过对于我们这个PoC, 我们实际上没有实现这个特性.
2026-03-30 20:29:00
这个月读完的书有四本了. 网络小说两本, 一本是学霸的星辰大海, 这本的内容比较一般, 仍只是有了系统就可以为所欲为的套路. 这类小说的卖点是多巴胺分泌很足, 最大问题是缺乏真正的戏剧冲突. 这本就是典型的例子, 到了后面就不知道怎么往下编了, 只好拿不可言说凑数. 另外一本亏成首富从游戏开始稍好些, 有一个必须亏钱的理由却不断赚钱, 顺便还嘲讽了一群不好好埋头做事却只想着挖空心思捞钱的行业. 但是这本实在是有点太长了, 我到了后面真实一目十行, 就这样也花了84个小时才读完. 这无疑是这过去几年里最花时间的一本了. 总体质量上来说, 这本硬伤也实在太多, 本来几十万字能写完的剧情撑到了500万字. 第三本是本月最佳, 台湾往事. 没想到这本书里有这么多重量级人物, 从侧面记录了很多台湾的史实, 读起来兴致盎然. 最后一本是What if的作者写的How to: 如何不切实际地解决实际问题, 这本我总觉得没之前的what if好, 因为每个不同的topic长短不一, 有些深入讨论, 有些相对比较浅, 或者画一张漫画就过了. 另一个可能我觉得一般的原因是这些讨论都有点太贴近实际, 印象最深的一个场景是一本正经地在房屋外面围一圈熔岩, 但是这远不如之前讨论里让人去摸中子星那么夸张.
这个月蒙同事推荐看完了Netflix上的Arcane, 讲LOL的背景故事. 对于一个从来没玩过这个游戏的人而言, 这个剧没有吸引到我. 最大的感触是, 怎么死一个人那么难? 到了后面很多双主角年幼时已经死透了的人争先恐后地复活, 让人目不暇接, 这个观感并不好. 看完这个, 捡起几年前半途而废的Dota: 龙之血, 这次算是看完了, 但是看完后感觉还是晕晕乎乎. 虽然里面的很多人物我是知道的, 但是他们之前的关系, 以及和这个游戏本身的关系, 我还是看不太明白. 当然, MOBA这种游戏也许不需要背景, 因为真的没人在乎.
这个月vibe coded了一个Claude Code的网页版. 一开始就是让Claude Code自己做一个PoC, 只是能够有一个页面, 里面没有任何前端框架, 纯js/css的页面, 被内嵌到一个go binary里面去, 页面通过websocket和后端的go服务器交互, 控制一个或者多个Claude Code进程. 控制Claude Code的方式是起进程的时候拿到前端状态里面的模型, repo和mode, 启动的时候使用--input-format stream-json来做所有的交互. 实际上, claude agent sdk里面也是这样和Claude Code交互的(ref). 后面, 页面上的内容越来越多, 于是只好转头转成了react, 当然, 还好不是我自己维护.
项目效果挺不错, 我肝了几天后觉得有点累, 特性也做得七七八八了, 就歇着了, 脑子里还没特别想好后面要如何继续演进. 除了可以控制多个tab, 在多个worktree里面打开各种不同的repository, 通过icon显示是否需要人工干预等基本特性外, 我还加上了和Github/Jira的连接, 这样我可以直接把分配给我自己的card里的context读到, 然后找到对应的repo, 让claude开始干活了. 另外, 我还加上了一个pipeline的特性, idea是我们可以将一些常见的操作封装到一个工作流程里面去(比如下面讲的PR审核).
现在, 人们的创造力在AI的辅助下已经得到了极大的提升, 但是这也带来了一系列的问题, 比如机器生成的PR应该怎么样由人来review. 我们应该如何将碳基生命有限的注意力放在最需要关注的文件上?
我现在的想法是:
2026-03-01 07:35:00
This is my very personal, very meta take on AI tooling — not a how-to, just a lens: treat an LLM like an improv comedian. The model is the performer; the context is whatever the performer has to work with — the audience suggestions, the rules of the game, and everything said so far. Change that input, and you change the performance. It’s a simple framing, but it matters, because most of the “new” tooling we talk about later is really just different ways of shaping context.
If we go back a bit — when ChatGPT first went mainstream — prompt engineering became a buzzword. The idea was that the right wording could coax noticeably better output. That hype has cooled, especially as a standalone job title, but not because the practice vanished. My take is that, back then, the comedian simply wasn’t that strong yet, so you had to feed it very specific suggestions to get a good bit. Today, the comedian is better, and the craft has shifted: less about finding magic phrases, more about shaping context and building workflows. In that sense, the kaleidoscopic tools we have today are still extending prompt engineering — they’re just turning it into scaffolding, templates, and context choreography.
Fast forward to today, we live in an age of abundance in AI models. There are a lot of capable performers, and within the top tier the difference is often subtle — and highly task-dependent. So the leverage moves to the room you put them in: the better you can shape the context, the better outcomes you tend to get. Give a decent comedian great suggestions and a clear setup, and they can outperform a better comedian stuck with a confused, noisy room. Context really matters.
How do we control context? Tools can help, but most of them are generic — they don’t really know what you consider signal versus noise, so they can’t safely curate the room for you. For example, Claude Code can compact the conversation to make more room for what comes next. But if you toss in an unrelated question halfway through, or dump a giant chunk of raw logs into the chat, the performer is now doing improv in a noisy room: it becomes harder to track what matters, what’s incidental, and what should be ignored.
At this point, you might think we’re powerless. We’re not. A whole set of inventions exists for one purpose: keep the context window aligned with the problem we’re actually trying to solve.
Let’s start with MCP. To me, it’s a great invention not because it’s yet another integration, but because it changes how much integration knowledge you have to carry in the context window. MCP gives the model a small, discoverable interface to external systems — tools, resources, and even reusable prompts — via clear schemas and structured inputs/outputs. In practice, an MCP server often fronts one or more APIs, but it doesn’t have to expose the entire surface area. It can present a curated menu of capabilities with sane defaults. The LLM sees a menu of dishes, not a book full of recipes: instead of pasting curl/auth/swagger docs into the chat, you give it a handful of typed tool calls. That keeps the context lean and the model focused on the task.
Next, I’d like to talk about subagents. In my opinion, this is another great invention: instead of stuffing everything into one ever-growing chat, you delegate a narrowly scoped task to a separate agent running in its own context window (often with its own prompt and tool permissions), then bring the result back to the main thread. The goal isn’t “zero context” so much as “clean context”: keep the orchestrator’s context focused on the plan and the decisions, not the churn. Debugging is a classic example. Logs are high-volume and usually low-signal, and they can quickly drown out what you actually care about. A subagent can wade through the noise in isolation and can be instructed/designed to return a short, decision-ready summary so the rest of the workflow doesn’t get contaminated.
I don’t see skills as a breakthrough. To me, it’s prompt engineering with better ergonomics: modular, shareable, and loaded on demand. That’s a real UX win. But context-wise, it’s an incremental improvement, not a new paradigm. You’re not eliminating instruction tokens — you’re moving them out of the chat transcript and pulling them in when relevant. Once loaded, those tokens still compete with conversation history and everything else. If anything, a large catalog of Skills can create a new kind of noise: routing and discoverability overhead.
While I know Geoffrey Huntley personally, Ralph Loop still doesn’t feel like a new kind of context management to me. It’s a solid reliability pattern: keep the long-term state outside the conversation, restart with a clean context each round, do one small unit of work, validate it, then loop. That can be very effective precisely because it avoids context rot. But it’s not the “art” I’m seeking. It’s less about shaping the room and more about clearing the room over and over — paying iteration cost for robustness.
Gas Town adds real value in coordination and persistence — it stores work state outside the chat in git-backed hooks/ledgers — but at the end of the day it still inherits the strengths and limits of the underlying agent runtime (e.g., Claude Code or Codex). So if you only care about token-level context shaping, it may feel like ‘nothing new’; if you care about multi-agent reliability, it’s a different story.
So if we zoom out, a lot of AI tooling innovation is really context management innovation — not making the comedian magically smarter, but managing what the comedian gets to hear, when, and at what bandwidth. Different tools optimize different bottlenecks — token budget, noise isolation, state persistence, and coordination. The “art”, for me, is knowing which bottleneck you’re hitting and picking the smallest intervention that keeps the room coherent.