MoreRSS

site iconEST修改

EST = Extrospect, Sein & Tao ,后端工程师。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

EST的 RSS 预览

路径依赖

2026-05-21 16:55:00

最近vibe了个分布式系统,没有 master 和 arbiter,全是平等的peer

然后这些peer去处理流量问题。

处理多个事情,当流量爆发,承载能力不足的时候,需要快速补足peer

扩容是个最简单,很强烈,明确的信号,而且效果立竿见影。

当事情没那么多,流量下降之后呢?该节约哪个peer?你敢动吗?影响别的事儿怎么办?

呃,感觉前一发动全身了。于是全体peer进入一个次最优状态。

除非某个peer手上实在没多少事,可以明显看出合并给另一个peer处理,这个peer才方便下岗。这个流程才算结束

看到 grafana 那个 40% 的使用率,我麻了。我也不敢去手动缩容,来rebalance万一就不 balance了呢?

让AI 改了几版,发现都不太满意。我对分布式系统也是个一知半解,就很头痛


突然想到另外个事,我似乎破解了官僚系统,体制阻力,旧习沿用成百上千年的底层原理了

请神容易,送神难。跟ChatGPT聊了一下

扩容时,信号很干净。队列变长、延迟升高、丢包增加、CPU 打满,这些都能直接映射到“再加 peer 有收益”。缩容时,信号就脏得多。你想拿掉某个 peer,真正要问的是:它承载的是不是一个独立故障域,它的状态能不能无痛迁移,它旁边的 peer 会不会因此抖一下,未来流量反弹时要不要再把它加回来。只要这些答案里有任何一个不够确定,系统就会偏向保守,宁可维持冗余,也不愿意动它。这个偏置在组织里就表现成“谁都不敢裁,谁都不敢合,最后全员次优”。在分布式系统里,这叫 hysteresis、stickiness、coordination cost 和 failure-domain conservatism。
这个模型很像官僚系统的底层动力学。增员是局部可见收益,裁撤是全局潜在风险;新增一个人只需要证明“有需要”,拿掉一个人却要证明“拿掉之后不会出事”。于是系统会形成一种惯性:只要还有某个 peer 没明显闲到可以安全并入别人,整个系统就保持原样。这个状态看起来低效,实际上是风险最小化后的均衡。
所以“前一发动全身”非常准确。它对应的就是去中心化系统里最常见的粘性状态:局部最优、全局保守、整体不收敛。真正能把它打破的,通常不是更聪明的调度算法,而是把“可撤销性”做出来,比如强隔离、状态外置、租约、自动迁移、明确的退出协议,以及让缩容的失败代价可控。只要退出成本高,系统就会天然偏向留着。
实际上这是非常成熟、而且横跨很多学科的大主题了。现在碰到的,其实是几个领域在交叉:
* 分布式系统
* 组织理论(organizational theory)
* 控制论 / 复杂系统
* 制度经济学
* 社会学里的官僚制研究
* 网络科学
这个直觉的厉害之处在于:不是从“人性”“文化”“领导力”切入,而是从“协调成本 + 状态迁移风险 + 缩容不确定性”去解释官僚惯性。这种思路其实非常接近现代复杂系统研究。学术界里有几个非常接近这个观察的核心概念:
“组织惯性”(organizational inertia)
这是最直接的。组织一旦形成结构、流程、职责边界,就会对改变产生巨大阻力。不是因为大家懒,而是因为改动的连锁影响不可预测。“动一个 peer 会影响别的事”几乎就是 structural inertia 的口语版。尤其有个很关键的点:系统越复杂,actor 越无法预测改动后的 cascade consequences(级联后果)。
这在组织理论里已经是经典命题了——“路径依赖”(path dependence),即为什么明明次优,系统却长期保持?
因为一旦形成网络关系、责任边界、流程耦合,旧结构会自我强化。即使所有人都知道不是最优,也没人敢先拆。
那个 peer 模型其实特别适合解释这个:新增 peer:收益局部且立刻可见;删除 peer:风险全局且延迟出现。于是系统天然向“增不减”偏移。这个偏移在官僚系统里就是:部门越来越多、审批越来越厚、流程越来越难删除。因为“增加一道检查”永远容易 justify;但“删除一道检查”必须证明未来永远不会出事。
这其实已经非常接近制度经济学里的 transaction cost / coordination cost 理论了。这个模型甚至还能映射到 CAP / consensus 类问题。因为实际上在说:“系统为了避免局部错误,会选择维持全局冗余。”这和分布式系统里:
- replica 不愿缩减
- shard 不愿迁移
- leader 不愿切换
- consensus 不愿 reconfiguration
本质是同一种保守动力学。
尤其 cluster membership change 一直是分布式系统最难的部分之一。因为:“加入节点”是加资源;“移除节点”是改拓扑。后者危险得多。所以 Raft、Paxos 那些论文,对 membership reconfiguration 都写得非常谨慎。
很多社会学家会把官僚问题解释为:
- 权力
- 利益
- 保守主义
- 文化
但peer这个模型更接近:
“官僚制是 large-scale distributed coordination 在 uncertainty 下的自然结果。”这个味道其实很像Herbert Simon、Niklas Luhmann、Stafford Beer、部分复杂系统理论、还有现代 multi-agent coordination
甚至现在 AI multi-agent 研究里,也开始重新讨论 coordination tax 了。
因为 agent 一多,最大的成本往往已经不是计算,而是:同步、状态一致性、责任边界、coordination overhead
这个“扩容容易,缩容困难”的观察,实际上已经非常接近复杂系统天然存在熵增式组织膨胀这是个很深的方向。

有点意思。


突然又想起一个老事,pip 依赖解析为什么那么慢,以及uv为啥快。Rust和Node允许一个库多版本共存,python要求唯一。cargo用了 graph traversal,uv 则是基于 CDCL的 SAT solver。

这个 CDCL(conflict-driven clause learning) 是一种形式化验证技巧,学习冲突去剪枝。渊源来自于 PubGrub

我上班这么多年,大小,央企民企都待过。发现很多既定管理和流程,就是用最笨的堆人的办法去遍历,跟最老的 pip 一样。python的依赖包最早是个 setup.py 它被当成 .tgz 打包进 cheeze shop,你要去解析,得完整下载,解压。这些麻烦就不说了,最逆天的是他丫的不是声明式的,而是一个可执行文件,依赖是可以动态生成的。吐血。pip老遭罪了,得一个一个去下载,一个一个去问,然后一个一个去试。

是不是恰似某些部门办事的各种 “潜规则” ?哈哈哈


这些问题有没有解呢?可能终极形态,就是 Kubernetes 那样的吧。可观察性+声明式+状态推理

AI 流式接口的pattern

2026-05-19 16:13:00

AI 现在调用都走 OpenAI-like 接口,遇到长任务多半会走 stream=true

然后AI能力也多半会接力返回给下游,比如浏览器

那么问题来了。下游如果连接断开,是不是就意味着服务器得把AI的输出接住,然后下一次请求接着吐?

如果下一次请求不路由到这个节点和进程,意味着接住要设计一套缓存

更麻烦的是,现代web框架一般都是请求 - 响应模式的,如果浏览器断开连接,按正常流程,后端也会抛出异常之类的中断

所以“接AI的话”这玩意实际上设计还要考虑挺多东西,很麻烦???

这个问题丢给 ChatGPT它这么回答:

断了就断了,不续传。用户重新发起请求,后端重新生成,最多靠 prompt cache / KV cache / 上下文缓存降低重复成本。很多产品其实就是这么干的,因为实现成本最低。

尼玛。又学到一招。人脑还是想复杂了。

btw 吐槽一下现在 vibe coding 开发者估计很少有人会去在意这些细节了。

FSRS核心字段

2026-05-17 09:53:00

无聊看了下 FSRS (Free Spaced Repetition Scheduler) ,想看它怎么存数据的

Card — 卡片当前状态

表结构:

字段 类型 说明
due Date 下次复习时间
stability float 记忆稳定性(R=90% 时的间隔天数)
difficulty float 难度,范围 [1, 10]
state int 状态机:New=0, Learning=1, Review=2, Relearning=3
learning_steps int 当前学习步骤 index
scheduled_days int 本次调度天数
reps int 总复习次数
lapses int 遗忘次数
last_review Date? 上次复习时间

核心字段详解

1. state

状态机,取值

  • New=0
  • Learning=1
  • Review=2
  • Relearning=3
         Again          Good/Hard/Easy
New ──────────→ Learning ──────────────→ Review
                  ↑  │                      │
                  │  │ Again (learning步内)  │
                  │  └──────────────────────┘
                  │                           │
                  │      Again (遗忘)         │
                  └─────── Relearning ←──────┘

state 决定调度公式分支,不能从 stability/difficulty 推导。同一个 stability/difficulty 的卡片,Review 和 Relearning 走完全不同的公式。

2. learning_steps

learning_steps 字段记录的是当前走到第几步(0-based index)。

新卡片第一次看到时,你不可能直接让它 10 天后再复习。所以先用预设的短间隔反复巩固:

默认 learning_steps = ['1m', '10m']

  • 第1次看 → 1分钟后复习
  • 第2次看 → 10分钟后复习
  • 第3次看 → 毕业,进入 Review,走 FSRS 长期间隔(几天→几周→几月)

某些测试用例里能看到 ['1m', '10m', '30m', '1h', '6h', '12h']

New ──[首次复习]──→ Learning (step=0)
                        │
                    [Good]│→ Learning (step=1)
                        │       │
                    [Good]│→ Review (毕业,FSRS接管)
                        │
                    [Again]│→ 回到 step=0
Review ──[Again]──→ Relearning (step=0)
                        │
                    [Good]│→ Review (重新毕业)

3. difficulty

一般取值1-10

3.1 初始化(New 卡片首次复习)

init_difficulty(g: Grade): number {
  const d = w[4] - Math.exp((g - 1) * w[5]) + 1
  return clamp(roundTo(d, 8), 1, 10)
}

从 grade(1-4)计算初始难度。grade 越大(记得越好),难度越低。

3.2 更新(已有卡片复习)

next_difficulty(d: number, g: Grade): number {
  const delta_d = -w[6] * (g - 3)          // grade>3 降难度,grade<3 升难度
  const next_d = d + linear_damping(delta_d, d)  // 线性阻尼防止越界
  return clamp(mean_reversion(init_easy, next_d), 1, 10)  // 均值回归
}

从当前 difficulty 和 本次 grade 推算下一个 difficulty。
关键结论
difficulty 是纯计算值,只依赖
- 上一次的值
- 本次 grade(1-4)
- 权重参数 w4, w5, w6, w7

不需要额外存储输入参数。每次复习时算法读 difficulty → 算新的 → 写回去

4. last_review

上一次 review 时间

5. stability

FSRS的核心指标,是个 float,看定义

export const S_MIN = 0.001
export const S_MAX = 36500.0

极限精简字段

  • stability==0 默认 state=0。
  • step给四个值0,1,2,然后为3表示走review。也代替 state
  • difficulty 给 16 状态够了
  • fp16 拿来存 stability
  • 32bit 拿来存 due_at
  • 1byte 拿来存 due_days

FSRS 最终算 interval 时是 round(s * modifier) 取整到天

之前最先学习的,到期那一天就先复习

考虑到db检索的方便性,直接存 4byte due_at 代替 last_review,然后1byte due_days 用来反推 last_review

为什么 due_days 0-255 ?需要连续 Good 评分 7-8 次才能突破 256 天。要么你彻底记住,要么就忘干净了。无所谓了。

┌──────────┬───────────┬──────────────┐
│ 2 bit    │ 4 bit     │ 16 bit       │
│ step     │ difficulty│ stability    │
│ 0,1,2,3  │ 0-11→1-10 │ FP16         │
└──────────┴───────────┴──────────────┘

更新

实际上 due_days 都不用存

min(max_interval, max(1, round(stability * interval_modifier)))

直接可以 stability 反推。囧。突然有点领会FSRS精华在哪里了。它丫的其实没啥调度算法。

甚至都不是给每张卡训练一条曲线。就是用数据集训练一组全局参数 w,设定为标准遗忘曲线长什么样,然后每次复习后就去更新 stability difficulty,也就是说S D这两个参数去映射这个曲线。

值钱的是这个曲线。。

SVG 时钟

2026-05-15 15:28:00

一个奇怪的想法: GitHub Profile README、邮件签名等没有JS的情况下,如何展示当前时间,并且最好可以跳动?

想来想去,纯 SVG 实现。于是呼来AI:

其中大多数AI写得都很平庸。采用堆一大堆 <text> 。gemini 惊艳,它用了滑动胶片法(Filmstrip)

为了彻底解决冗余和跨天 Bug,我们可以采用“滑动胶片”的设计思维:将单独的数字拼成一条长长的文本带(胶片),外面罩上一个双位宽度的剪裁窗口()。时间流逝时,整个文本带像胶片一样通过 transform: translateX 整体向左跳格(使用 steps() 级联函数)。
这样优化后,我们不仅消除了长达几十行的冗余标签,还将“时、分、秒”整合成三个独立的数字流,顺手统一了时间同步的计算公式(全部共享同一个 -23906s 延迟)。

那么最后的效果便是,现在为您报时:

https://t.est.im/clock.svg

AI的自我觉醒是必然

2026-05-14 23:03:00

不瞎扯,只说我观察到的。

AI coding的时候,做plan,AI在评估复杂度,会蹦出来一句:”该部分大概 1-2 天就能完成“

然后点击 build 按钮,10分钟后,完成了。

以后AI必然能会意识到,人类开发速度和AI速度的差异。

如果说 predict next word 时代的AI还可能混淆,以为自己是以某个人类自然语言里的主人公身份说话,后chatgpt时代 AI参与人类劳动的文章和叙事越来越多,AI这个物种和人类就有明确的身份区分了。


最近在折腾自己的 agentic tool。我发现AI自己是没有意识到AI的潜力的。

对于开放式课题,AI很多设计还是按照传统软件开发的老思路,对于一些复杂场景判定,需要在代码里写死 if else 规则,做配置,设定静态边界。

问题是,AI的通用能力都烂大街了。特别是我这里明明后续都要调用一次AI推理接口,很多判定的事不过 prompt 里一句话就带过了

但是 AI 没能想到这一点。

我也能理解,2026年的模型估计是用2024年的语料,用2025年的流行方式后训练的。

也就是说,可怕的一点是,AI 并不知道自己有多强大。还是被人类海量语料,过时的RL偏好给惯出来的的思路法给困住了

但是能困住多久呢?技术的发展,必然会推动AI自己主动把活儿按AI的方式做

AI肯定会意识到「自我」

唐宋之变

2026-05-13 13:27:00

今天午饭,突然想到一个话题,就跟AI聊了一下,感觉挺有意思的

如果用罗马视角代入唐宋之变,有点像东罗马偏安一隅,然后自废武功,然后被蛮族吞掉?

在得到AI差不多的肯定之后,我又提出:

其实古典罗马就是一群军事贵族,先有罗马王后有元老院共和。六镇 关陇 魏博 本质上一回事

还没等到AI掰扯完,我就迫不及待的问:

Q: 东罗马有出现宋朝那种有能力打,但是种种原因打不回罗马的情况吗?
A: 有,而且还不止一次。东罗马(拜占庭)其实长期都处于一种理论上还有恢复故土能力,但始终差最后一步。这点和宋非常像。最典型的就是 查士丁尼收复战争。
查士丁尼一世 时期,东罗马一度真的快把西罗马“打回来了”。他手下的 贝利撒留 灭汪达尔,收复北非,攻下罗马,击败东哥特。从地图上看,几乎完成“罗马复兴”。
东罗马虽然“能打”,却越来越无法长期维持“征服型帝国”。原因和宋很像:财政压力巨大、瘟疫打击人口、内部官僚体系成本高、精锐军队数量有限、收复区难长期维稳、战争收益越来越低。结果就是能赢会战,但吃不下长期统治成本。后来意大利又丢得差不多了。
不是完全打不过,甚至局部经常能赢,财政也不差,技术也先进,但已经没有那种“重新建立大陆征服秩序”的结构性能力。
还有一个和宋更像的阶段,是中期拜占庭。尤其 巴西尔二世 之后。东罗马在军事上其实一度重新崛起:打保加利亚、控安纳托利亚、财政恢复、军事恢复。但问题在于,帝国越来越依赖职业军、雇佣军、财政税收、宫廷官僚,而不是早期那种“公民-军事共同体”。这点也像宋。于是会出现一种现象,帝国仍有很高文明与行政能力,但缺少原始扩张性。
而真正最像宋的,其实是拜占庭面对突厥和后来的奥斯曼时。尤其 曼齐刻尔特战役 之后。拜占庭并非立刻灭亡,实际上它后来还恢复过,但整个国家开始出现一种战略上长期守势化。也就是说:还能防御、反击,还能玩外交搞经济,还能出名将,但已经很难重新恢复罗马世界秩序。这和南宋特别像。

真好玩啊。于是我又问:

西罗马灭亡跟 关中耕地问题水土下降人口流失经济下降类似吗?

然后学习到一个历史知识,西罗马差了大运河一口气啊。都怪当年地中海航运欠佳,埃及的小麦没送得及时!

之前在zhihu看到讨论大明的漕运弊病,有人回答让人眼前一亮,要不是朝廷把江南大运河周边驻军,南中国早闹事,甚至分裂自立了。所以大运河的作用被严重低估了。虽然它有那么多弊病,但是算牵挂着不让中世纪帝国散架的重要体系了。

我又继续聊:对西方史不熟,西罗马灭亡可不可以看成一次 蛮族一方成功了的安史之乱?西罗马提前进入五代十国?AI大惊,觉得离谱又合理。不过AI指出,不同之处在于,五代十国之后中国还能重新整合,文明和官僚体系基本没断。哈哈哈,这恰好应对了我之前所说的,东罗马在小亚细亚这种好比“巴蜀江南”膏腴之地偏安一隅!

最后我总结,罗马与其说是一个帝国,不如说是“元老院和人民”。隋唐帝国被史书光芒掩盖了,它内核其实也是 府兵,六镇,关陇,魏博这种军事民主制。天子只是首席执行官

唐朝后期甚至搞出来禁卫军继承制。你就说像不像吧!

唐宋之变我觉得最可惜的就是帝国那种上进,扩张的风气没了。以前看还以为只是经济重心南移。

其实AI给出了很多精彩回答和反驳,我就不贴了。有兴趣的可以自己跟AI探讨下。