
上个月我准备写一个本地日志分析 CLI 工具。按照以前的惯性,第一反应是选 TypeScript 或 Python:自己最熟悉,写起来顺手,出了问题也知道去哪排查。
但这套工具的真正诉求很苛刻:单文件分发、开箱即用、冷启动时间必须压在 10 毫秒以内,而且要在几百兆的日志流中保持低内存。把这些硬指标摆出来后,Node 和 Python 运行时就显得极其臃肿。
最后我让 Agent 用 Rust 跑完了一版,半天时间单测和跨平台编译全过。
类似的事情正在工业界发生。Cloudflare 在 Artifacts 服务里,用纯 Zig 写了一个完整的 Git 协议引擎,编译成大约 100KB 的 WebAssembly 模块直接跑在边缘节点。Vercel 发布的 coding agent 工具 fx 也是纯 Zig 构建,核心卖点就是极小体积和即时启动。
技术选型的第一准则,正在从“我会什么”变成“系统需要什么”。
“会不会”过去买的是排错时间
以前选型紧抓着熟悉的技术栈不放,防范的主要是调试成本。
一门主流编程语言的语法规则,有经验的工程师几天就能摸透。真正卡人的是踩坑经验:一个晦涩的编译器报错能耗掉大半天,一个复杂的内存生命周期问题可能排查整整一周,隐蔽的未定义行为甚至能让程序在运行三天后神秘崩溃。
熟悉的语言,本质上是在用过往积累的肌肉记忆给交付时间兜底。
现在的 coding agent 把这部分成本压缩到了极低。遇到类型系统的刁钻报错或者冷门库的调用细节,Agent 能在几秒钟内给出修复方案并附带上下文解释。语法记忆和基础排错的门槛被抹平后,选型的出发点自然发生了位移。
第一问变成了性能、体积与运行环境的硬约束
在 Cloudflare 的案例里,关键不是 Zig 这门语言有多流行,而是 100KB 体积和 WebAssembly 边缘运行环境这两个硬指标。
当目标被限定在“无需额外运行时、冷启动时间可忽略、能够直接嵌入边缘沙箱”时,可选的语言范围其实已经收窄。此时 Zig 是达成目标的最短路径,“我以前主要写前端和 Node”就不再构成拖延决定的理由。
选型的顺序彻底倒了过来:以前是根据自己掌握的技术储备推导能做什么系统,现在是先划定系统的物理约束,再反推必须使用哪种工具。
很多此前极少接触底层系统编程的开发者,已经开始借助 Agent 涉足 eBPF、网络驱动以及底层系统调用。工具抹平了入场门槛,但工程的重心也随之转移到了更深的地方。
语法门槛抹平后,真正的瓶颈是工程判断
借助 Agent 跨语言编程,确实能极快搭出原型,但系统很容易在延迟、一致性与可靠性上埋下暗坑。
Agent 默认会选一条最省事的实现路径,把代码格式化得整整齐齐,单测全部跑通。但隐藏的工程缺陷往往要在真实负载下才会暴露。
我写那个 Rust 日志分析工具时就踩过一次结实的坑。Agent 迅速提交了一版毫无瑕疵的代码,单元测试全绿。但在处理几百兆的真实大日志时,内存占用直接飙到了 4GB 以上。
翻开代码才发现,Agent 为了写起来简单,在每次检索请求里直接调用 read_to_string 把整个大文件全量加载进内存,并在函数调用间反复做克隆;而在遇到文件 I/O 异常时,它顺手写了一个无退避的静默 loop 重试,瞬间把单核 CPU 占满到 100%。

Agent 解决了语法的编译通过,却在基础的 I/O 模型上选了最偷懒的方案。如果你对内存映射(mmap)、零拷贝流式解析和故障退避机制没有基本的工程判断,这种代码进入生产环境就是灾难。
把工程取舍显式写进任务约束
要让 Agent 跨技术栈交付可靠的代码,核心在于把架构取舍提前变成硬性约束,直接写在任务定义里。
比如在让 Agent 动工之前,明确锁死这几条边界:
- 体积与启动:产物体积上限 15MB,冷启动时间控制在 20ms 以内,严禁引入重型异步运行时。
- 内存与 I/O:峰值内存不得超过 50MB,禁止全量内存加载,强制采用零拷贝流式处理或内存映射。
- 错误恢复:发生 I/O 错误时快速失败并返回标准退出码,禁止无退避的静默重试。
- 复杂度控制:严格控制第三方依赖,优先依赖标准库,非必要不引入复杂并发优化。
当这些硬约束被白纸黑字写进任务时,使用不熟悉的语言反而比使用熟悉的语言更不容易失控。因为在熟悉的栈里,很多工程规矩只是心照不宣的习惯,容易漏掉;而在生疏的语言里,所有的取舍都被迫在动手前交代得一清二楚。
写一门自己尚未掌握的语言,在今天已经不再被语法所阻碍。
真正的门槛始终是工程判断:你必须清清楚楚地知道,系统在用什么代价交换什么收益。