跳到主要内容

24 篇博文 含有标签「developer-tools」

查看所有标签

与先验对抗:当模型掌握了错误版本的技术栈时

· 阅读需 12 分钟
Tian Pan
Software Engineer

有一种特定的争论,你只会和语言模型发生。你粘贴进代码。它把一个能运行的调用改写成了早在几个大版本前就不存在的形式。你纠正它。它道歉、表示同意,然后在下一轮对话中故技重施。你不是在对抗无知,而是在对抗一段对 不同 版本技术栈的、自信且经过充分排练的记忆——这段记忆被远超你纠正信息的训练样本所强化。

这就是我所认为的“与先验知识对抗”(fighting the prior)故障模式。模型的参数化知识——它在训练期间吸收的一切——包含了流行的、过时的,或者仅仅是与你实际使用的框架版本不同的内容。当你的上下文与它的先验知识发生冲突时,先验知识往往会胜出。与纯粹的幻觉不同,这种错误之所以危险,恰恰是因为它具有误导性的合理性:那个被弃用的 API 曾经是正确的,所以代码看起来没问题,能通过随意的阅读,甚至有时还能编译通过。

工程师离职,Agent 记忆也将随之消失

· 阅读需 10 分钟
Tian Pan
Software Engineer

你最高产的工程师刚刚递交了辞呈。你对这套流程已经烂熟于心:移交工单、记录部署流程、交接值班轮换、安排知识分享会议。这份离职核查清单经过了数十年的完善,涵盖了公司认为其拥有的一切资产。

以下是 2026 年的核查清单所遗漏的内容:那位工程师的家目录(home directory)中包含一个经过 18 个月调校的个人 CLAUDE.md 文件、十几个编码了如何处理最棘手子系统的自定义技能(skills)、存储了智能体积累的关于代码库难点事实的记忆文件,以及经过数百次尝试和错误校准的座架(harness)设置。这些都不在代码仓库中,也不会随账号一起移交。

在他们的最后一天,IT 部门停用了笔记本电脑,数月积累的智能体配置——这正是他们的智能体能独立交付功能而其他人的智能体却在挣扎的区别所在——在无人察觉的情况下蒸发了。

会话记录记住了提交信息遗忘的内容

· 阅读需 11 分钟
Tian Pan
Software Engineer

就在此时,你的笔记本电脑里的某个角落正存放着你的团队有史以来最详尽的工程决策记录,却没有任何人读过其中的一个字。每一个智能体会话 —— 无论是每一次 Claude Code 的运行、每一次 Cursor 对话,还是持续数小时的重构历程 —— 都会被记录成一份转录文本(transcript)。它包含了尝试过又被放弃的三种方案、导致产生这种丑陋临时方案的约束条件,以及你否决模型建议的时刻及其原因。然后会话结束,PR 带着一行 commit message 被合并,所有这些上下文都进入了一个永远不会被打开的 JSONL 文件。

以前,我们丢失这些信息是“理所当然”的。某个设计选择背后的推导过程只存在于某个人的脑子里,随着时间推移而淡忘,并在他们换工作时彻底流失。当时没有什么可以保存的,因为根本没有记录下来。这种借口已经不复存在了。现在的推导过程正被逐字逐句地记录下来,带有时间戳,机器可读 —— 而我们却将其视为随手可弃的废气。

两位写作者,一棵工作树:人机协同编辑的并发控制

· 阅读需 12 分钟
Tian Pan
Software Engineer

你正在重命名一个函数到一半,文件就在光标下重新加载了。你正在暂存的 diff 不再与工作树匹配。你的开发服务器无故热重载了两次,而十分钟前还通过的测试,现在却在你从未打开过的一个文件中报错了。没有崩溃,没有警告。你和你的编程 Agent 刚才一直在同时编辑同一个工作树,而你发现这一点的方式和大多数团队一样:通过那些莫名其妙的 diff。

数据库在五十年前就解决了这个问题,并给它起了一个名字 —— 并发控制 (concurrency control)。两个操作共享可变状态的写入者要么需要一个锁,一个隔离边界,要么需要一个合并协议,而在这些选项中做出选择是一个具有已知权衡的设计决策。然而,大多数采用编程 Agent 的工程团队从未明确做出这个决定。他们将第二个写入者直接扔进一个单一的工作树中,保留着单写入者世界的习惯,然后将产生的怪象归类为 “AI 不稳定”。这不是不稳定,这是一个竞态条件 (race condition),而你正是参赛者之一。

你的错误信息现在成了 Prompt:为 AI Agent 编写失败输出

· 阅读需 12 分钟
Tian Pan
Software Engineer

统计一下你的堆栈跟踪(stack traces)的阅读者。对于大多数内部工具,过去的答案通常是“偶尔有一位疲惫的工程师”。如今,你的错误输出的最大阅读者几乎肯定是一个处于重试循环中的语言模型。编程智能体(Coding agents)每天成千上万次地阅读你的 linter 警告、CLI 使用说明字符串、API 错误主体以及测试失败信息——频率远高于任何人类。而且与人类不同,智能体会字面理解每一个词。

这改变了错误信息的“本质”。它不再仅仅是失败的文档,而是注入到下一次尝试的上下文窗口中的指令——这是你几个月前编写的提示词,现在正引导着一群你从未见过的智能体集群。一个精确的错误能让循环在一次重试中收敛。而一个模糊或误导性的错误则会让智能体陷入恶性循环:错误的修复、--no-verify 的权宜之计、幻觉出来的参数标识、消耗殆尽的 token。如果你维护着一个工具、一项服务或一个构建系统,你其实已经在进行提示词工程(prompt engineering)了。你只是在错误字符串中进行的,而且很可能是无意为之。

你的内部框架是一种低资源语言

· 阅读需 10 分钟
Tian Pan
Software Engineer

让编程智能体(coding agent)构建一个 React 组件,它第一次尝试就能写出地道的、基于 Hook 的、带有无障碍标注的代码。让同一个智能体使用你公司的内部 ORM —— 那个平台团队维护了六年、拥有出色文档和上百个内部用户的框架 —— 它就会幻觉出不存在的方法,从其他库里发明配置选项,并自信地交付出基于它臆造的 API 编写的代码,而这些代码根本无法通过编译。

这种差异并非源于质量。你的 ORM 可能比模型能完美处理的一半开源库设计得都要好。差异在于训练数据。React 背后有数百万个公开仓库;而你的框架则一个都没有。在自然语言处理(NLP)的术语中,你的内部框架是一种低资源语言(low-resource language) —— NLP 研究人员针对低资源语言记录的每一个后果,现在都适用于你的代码库。

你的模型认为你的技术栈已过时 2 年

· 阅读需 12 分钟
Tian Pan
Software Engineer

有一类 AI 生成的 Bug 几乎每次都能通过代码审查,它既不是幻觉函数,也不是捏造的包。它是完美的地道代码——地道到符合模型训练数据冻结时你的技术栈版本。模型为运行 Tailwind v4 的项目编写 tailwind.config.js,在 Hooks 代码库中调用类组件的生命周期方法,或者调用一个在三个小版本前就被弃用、并在你的 lockfile 实际锁定的版本中已被删除的 API。代码看起来毫无破绽。它看起来就像出自某个备受推崇的教程。只是那个教程来自 2024 年。

称之为“训练截止日期 Bug”:这类缺陷的存在并非因为模型推理能力差,而是因为模型对你依赖项的了解带有时间戳,而你的 lockfile 并不在意。一项 ICSE 2025 对 8 个常用 Python 库、7 个代码模型的研究发现,在看似合理的补全代码中,弃用 API 的使用率高达 25–38%——当周围代码已包含过时模式时,这一比例会攀升至 70–90%。这些并非罕见的边缘情况。它们是要求一个冻结的产物为不断变化的目标编写代码时的默认失败模式。

像入职初级工程师一样入职 AI 智能体是一种范畴错误

· 阅读需 11 分钟
Tian Pan
Software Engineer

当一个智能体(agent)加入你的团队时,每个工程经理脑海中最接近的类比就是新员工。因此,应对策略显而易见:给它一个沙盒和只读日志,将最初的任务范围缩小,与其结对编程,预留一段磨合期,并随着信任的累积让它承担更重的工作。这听起来很负责任。这感觉就像是你把上一个初级工程师培养成高级工程师时那种耐心的管理方式。

这也是一个范畴错误(category error)——它不只是一个略显不完美的类比,而是一个错误的类比。初级工程师是一个还不太了解你系统的人。而智能体是一个无状态的函数,无论接触系统多少次,它永远都不会真正“了解”你的系统。这是两种完全不同的事物,适用于前者的管理直觉会在无形中让你错配注意力。

这之所以重要,是因为这个隐喻不仅会产生误导,还会让你把精力投在错误的地方。“培养智能体”并不是一种策略。智能体是固定的,你真正能改变的一切都存在于它之外。

代码专用 RAG:为什么通用检索在代码库中会失败

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数构建 AI 编程助手的团队都会采用与文档检索相同的现成 RAG 流水线:根据 token 数量对源文件进行分块(chunking),对块进行嵌入(embedding),将其存储在向量数据库中,并通过语义相似性进行查询。这种流水线在处理散文(prose)时表现良好。但在处理代码时,它会悄无声息地失败——而且这些失败很难在聚合指标中显现,因为检索到的代码块看起来似乎合情合理,直到模型生成了错误返回类型的代码、调用了签名错误的函数,或者遗漏了调用图中三层之后才存在的依赖项。

问题不在于嵌入模型或向量数据库,而在于分块策略。代码不是散文。它具有结构属性——依赖图、调用链、类型签名、作用域层级——而基于 token 的分块在检索器看到它们之前就破坏了这些属性。修复这个问题需要重新思考在进入嵌入步骤之前如何分解代码。

安静放弃模式:AI 参与度指标为何在说谎

· 阅读需 11 分钟
Tian Pan
Software Engineer

有一种特定的失效模式正在悄悄破坏 AI 产品的数据指标,却没有人察觉。你的仪表盘显示建议接受率为 34%、DAU 强劲、功能参与度持续增长。仪表盘没有显示的是:60% 被接受的建议随后被立即重写,参与度最高的用户正是那些点击 AI 输出、全选,然后自己重新输入的人;这个功能对下游任务完成率零可测影响。

这就是"安静放弃"模式:用户系统性地绕过 AI 功能,同时产生活跃用户的全部表面指标。他们不会禁用该功能——他们只是忽略其输出。在你的分析系统中,他们与最佳 AI 用户看起来完全相同。

专业知识悬崖:AI 编码智能体为何在成熟代码库中失效

· 阅读需 9 分钟
Tian Pan
Software Engineer

2025 年的一项对照实验让有经验的开发者使用了 AI 编码工具,并测量他们是否变得更快。开发者们预测效率会提升 24%。研究结束后,他们报告自己大约快了 20%。而客观测量显示,他们实际上慢了 19%

这并不是一个关于 AI 过度炒作的故事。这是一个关于隐性知识的故事——那种存在于每个成熟代码库中、仅靠阅读代码无法恢复的、无文档记录的"为什么"。AI 智能体在全新系统中生产效率出奇地高,正是因为那里几乎没有隐性知识可以违反。它们在成熟代码库中退步,原因完全相同。

IDE 插件即产品:当你的编程智能体超出了编辑器的插件 API 限制

· 阅读需 13 分钟
Tian Pan
Software Engineer

AI 编程工具的默认思维模型是 VS Code 内部的一个面板。一个对话框,几个行内建议,或许还有一个“应用差异(apply diff)”按钮。这种构想已经过时两年了。该领域的领先产品并不是 VS Code 扩展;它们是完整的编辑器,只是启动时碰巧看起来像 VS Code。Cursor 是一个分叉版本(fork)。Windsurf 是一个分叉版本。Zed 是一个从零开始构建的原生编辑器。这种模式并非巧合 —— 当智能体(agent)的覆盖面最终超过了宿主编辑器的插件 API 所能支持的范围时,必然会出现这种情况。

如果你正在构建一个编程智能体,并且仍然将“发布一个插件”视为理所当然的分发选择,那么你即将撞上那些领跑者在 2024 年左右遇到并选择翻越的那面墙。这面墙有个名字:插件 API 是为了给人类控制的编辑器添加功能而构建的,而不是为了托管一个想要控制编辑器的自主智能体。