0%

【由 ChatGPT 辅助翻译】

来源 URLhttps://addyo.substack.com/p/my-llm-coding-workflow-going-into
发布时间:2025-12-18T15:30:46+00:00


AI 编码助手在今年成为了颠覆性的工具,但要真正发挥它们的威力,需要技巧与结构化的方法。 这些工具显著提升了 LLM 在真实世界编码中的能力,许多开发者(包括我自己)都积极拥抱了它们。

以 Anthropic 为例,工程师对 Claude Code 的采用程度之高,以至于 今天 Claude Code 约 90% 的代码是由 Claude Code 自己编写的。然而,将 LLM 用于编程并不是一键魔法式的体验——它“困难且不直观”,要获得优秀的结果需要学习新的模式。批判性思维依然至关重要。经过一年多的项目实践,我逐渐收敛出一种与许多资深开发者相似的工作流:把 LLM 当作一个强大的结对程序员,而不是具备自主判断力的实体——它需要清晰的指令、充分的上下文以及持续的监督

在本文中,我将分享我在迈向 2026 时如何规划、编码并与 AI 协作,总结我个人经验以及社区集体学习中沉淀下来的技巧与最佳实践。这是一种更有纪律性的 “AI 辅助工程(AI-assisted engineering)” 方法——在积极利用 AI 的同时,依然自豪地对最终产出的软件负责

如果你对我更多的工作流细节感兴趣,可以参考《The AI-Native Software Engineer》;若不想深入了解,我们直接进入我学到的一些经验教训。


先制定清晰的计划(先有规格说明,再写代码)

不要只是把愿望丢给 LLM ——先定义问题并规划解决方案。

一个常见的错误是,用一个含糊的提示直接让 AI 生成代码。在我的工作流(以及许多人的实践)中,第一步是与 AI 一起头脑风暴并制定一份详细的规格说明,然后在编写任何实际代码之前,先列出一个逐步的计划。对于一个新项目,我会描述想法,并让 LLM 不断向我提问,直到我们把需求和边界情况都理清。最终,我们会将这些内容整理成一份完整的 spec.md,其中包含需求、架构决策、数据模型,甚至测试策略。这份规格说明构成了开发的基础。

接下来,我会把 spec 输入给一个具备推理能力的模型,并提示它生成一份项目计划:将实现拆解为逻辑清晰、易于消化的任务或里程碑。AI 实质上是在帮助我完成一份迷你的“设计文档”或项目计划。我通常会对这份计划反复迭代——编辑它、让 AI 批评或完善——直到它足够连贯且完整。只有在这之后,我才会进入编码阶段。前期的这种投入看起来可能有些慢,但回报极高。正如 Les Orchard 在这里所说,这就像是在 “15 分钟内做一次瀑布式开发”——一个快速而结构化的规划阶段,让后续编码顺畅得多。

有了清晰的规格和计划,当我们真正释放代码生成能力时,人和 LLM 都非常清楚要构建什么、以及为什么要这么做。简而言之,先规划能迫使你和 AI 达成共识,避免无谓的反复。这一步很多人容易跳过,但经验丰富的 LLM 开发者如今已经把健壮的规格/计划视为整个工作流的基石。


将工作拆分为小而可迭代的任务块

范围管理至关重要——给 LLM 可管理的任务,而不是一次性丢整个代码库。

我学到的一个关键经验是:避免让 AI 一次性产出庞大、整体化的结果。相反,我们应该把项目拆解成迭代的小步骤或工单,并逐个完成。这本来就是良好的软件工程实践,但在 AI 参与时尤为重要。LLM 在面对聚焦的问题时表现最好:一次实现一个函数、修复一个 bug、添加一个功能。举例来说,在完成规划后,我会对代码生成模型说:“好,我们来实现计划中的第 1 步。”我们完成这一步,测试它,然后进入第 2 步,如此往复。每个块都足够小,既在模型的上下文能力范围内,也便于你理解生成的代码。

这种方式能有效防止模型“跑偏”。如果你一次性要求太多,它很容易困惑,或者生成一个 “杂乱无章的混合体”,难以梳理。有开发者反馈,当他们试图让 LLM 生成大块应用代码时,最终得到的是不一致和重复——“就像 10 个开发者各干各的,却从不沟通”。我也深有体会;解决办法就是停下来、后退一步,把问题拆成更小的部分。每一轮迭代,我们都会带着已有的上下文继续构建。这也非常契合 测试驱动开发(TDD)——我们可以在过程中为每个模块编写或生成测试(稍后会详细谈测试)。

现在已有不少编码代理工具明确支持这种分块式工作流。例如,我经常生成一个结构化的 “prompt plan” 文件,里面包含每个任务对应的一系列提示,这样 Cursor 等工具就可以按顺序逐条执行。核心原则是:避免大跨度跳跃。通过小循环迭代,我们可以显著降低灾难性错误的概率,并快速纠偏。LLM 擅长快速、受控的小任务——善用这一点。


提供充分的上下文信息和指导

LLM 的能力取决于你提供的上下文——把相关代码、文档和约束展示给它。

在处理代码库时,我会确保把 AI 所需的全部信息都提供到位,包括它需要修改或参考的代码、项目的技术约束、以及已知的坑或偏好的实现方式。现代工具在这方面有所帮助:例如,Anthropic 的 Claude 在 “Projects” 模式下可以把整个 GitHub 仓库引入上下文;Cursor 或 Copilot 这类 IDE 助手会自动把当前打开的文件加入提示。但我往往会更进一步——如果我怀疑模型并不了解某些内容,我会使用像 Context7 这样的 MCP,或者手动把关键代码或 API 文档粘贴进对话。

资深 LLM 用户非常强调这种“上下文打包(context packing)”。例如,在编码前做一次**“脑内倾倒(brain dump)”**,把模型需要知道的一切都告诉它:高层目标与不变量、优秀方案的示例、以及应当避免的做法。如果我要让 AI 实现一个棘手的方案,我可能会提前说明哪些朴素解法太慢,或者给出一个外部参考实现。如果我使用的是冷门库或全新的 API,我会直接贴上官方文档或 README,避免模型“盲飞”。所有这些前置上下文都会显著提升输出质量,因为模型不再需要猜测——它掌握了事实与约束。

现在也有一些工具可以自动化上下文打包。我尝试过 gitingestrepo2txt,它们本质上是把代码库中相关部分“导出”为一个文本文件供 LLM 阅读。在处理大型项目时,这类工具非常救命——你生成一个 output.txt,把关键源文件打包给模型即可。原则很简单:不要让 AI 在信息不完整的情况下工作。如果修一个 bug 需要理解四个模块,就把这四个模块都给它。是的,需要关注 token 限制,但当前前沿模型的上下文窗口已经相当大(数万 token)。要明智地使用它们。我通常只选择性地包含与当前任务相关的代码,并明确告诉 AI 哪些内容不在范围内(以节省 token)。

我认为 Claude Skills 很有潜力,因为它们把原本脆弱、需要反复提示的流程,变成了可持久、可复用的能力模块——将指令、脚本和领域知识打包成 Skill,当请求匹配时由工具自动应用。这比泛泛的提示更可靠、更具上下文感知能力,也让我们从一次性互动,转向把可重复流程和团队知识编码进工作流中。社区里已经有不少整理好的 Skills 集合;我最喜欢的例子之一是 frontend-design skill,它可以“终结”LLM 生成 UI 中常见的紫色审美。在更多工具原生支持 Skills 之前,也有一些变通方案

最后,在提示中用注释和规则来引导 AI。我可能会在代码片段前写:“这是 X 的当前实现,我们需要扩展它以支持 Y,但要注意不要破坏 Z。”这些小提示非常有用。LLM 是字面主义者——它们会遵循指令,所以请给出详细、有上下文的说明。通过主动提供上下文和指导,我们可以最大限度减少幻觉和跑题建议,得到真正契合项目需求的代码。

选择合适的模型(必要时同时使用多个模型)

并非所有编码型 LLM 都是一样的——有意识地选择工具,并且不要害怕在过程中切换模型。

在 2025 年,我们已经拥有了多种能力强大的、面向代码的 LLM。我的工作流中有一项重要内容是:为不同任务选择最合适的模型或服务。有时,甚至同时让两个或更多 LLM 并行尝试同一个问题、交叉对比它们的思路,也非常有价值。

每个模型都有自己的“性格”。关键在于:如果某个模型卡住了,或者给出的结果平庸,就换一个试试。 我确实经常把同一个提示,从一个聊天窗口原封不动地复制到另一个服务中,看是否能得到更好的处理结果。这种“模型换座位(model musical chairs)”的做法,在你撞上某个模型的盲区时,往往能救场。

同时,务必确保你使用的是当前最好的版本。如果条件允许,就用最新的 “pro” 级模型——质量真的很重要。是的,这通常意味着要付费,但生产力的提升往往值得。归根结底,选择那个与你**“合拍”**的 AI 结对程序员。我认识一些人更偏好某个模型,仅仅是因为他们喜欢那个模型回答问题的“感觉”。这完全合理——当你几乎是在与 AI 持续对话时,交互体验和语气本身就会产生影响。

就我个人而言,最近我在很多编码工作中更偏向使用 Gemini,因为它的交互感觉更自然,而且往往一次就能理解我的需求。但如果需要,我会毫不犹豫地切换到其他模型;有时,第二个意见能让解决方案浮现出来。总结来说:为任务选择最合适的工具,并记住——你手中拥有一整套 AI 武器库。


在整个软件生命周期中充分利用 AI 编码能力

在整个 SDLC 中使用面向编码的 AI,全面强化你的工作流。

在命令行层面,新的 AI 代理已经出现。Claude Code、OpenAI 的 Codex CLI,以及 Google 的 Gemini CLI,都是可以直接在项目目录中对话的 CLI 工具——它们可以读取文件、运行测试,甚至执行多步骤修复。我也用过 Google 的 Jules 和 GitHub 的 Copilot Agent——这些是异步编码代理,它们会在云端 VM 中克隆你的仓库,在后台完成任务(编写测试、修复 bug),然后为你提交一个 PR。看到这一切发生其实有点诡异:你发出一个诸如“重构支付模块以支持 X”的命令,过一会儿就会收到一个包含代码变更且测试通过的拉取请求。我们确实活在未来。你可以在《从指挥到编排:未来的软件工程》中读到更多相关内容。

不过,这些工具并非万无一失,你必须理解它们的边界。它们极大地加速了编码中偏机械性的部分——生成样板代码、应用重复性修改、自动运行测试——但它们仍然非常依赖你的引导。例如,当我使用 Claude 或 Copilot 这类代理来实现功能时,通常会把前面步骤中的计划或待办清单一并提供给它,让它清楚每一步的执行顺序。如果代理支持,我会在下达执行指令前,把 spec.md 或 plan.md 加载进上下文,以确保它不跑偏。

我们还远未到可以完全放手让 AI 代理无人监督地完成整个功能,并指望它给出完美结果的阶段。 相反,我是以受监督的方式来使用这些工具:我会让它们生成并运行代码,但始终关注每一个步骤,一旦发现异常就及时介入。还有一些编排工具,比如 Conductor,允许你并行运行多个代理处理不同任务(本质上是扩展 AI 助手的规模)。一些工程师已经在尝试同时跑 3–4 个代理,分别负责不同功能。我也试过这种“高度并行”的方式——在短时间内完成大量工作时效果惊人,但同时监控多个 AI 线程在心理上也相当消耗精力!在大多数情况下,我仍然坚持一次只用一个主代理,必要时再加一个用于评审的辅助代理(下面会讲)。

记住,这些都是强力工具——扣动扳机和引导结果的,始终是你。


保持人工介入——对所有内容进行验证、测试和审查

**AI 会非常乐意生成“看起来合理”的代码,但你要为质量负责——始终审查并充分测试。**我最重要的一条原则之一是:绝不盲目信任 LLM 的输出。正如 Simon Willison 在这里所说,把 LLM 结对程序员看作是 **“过度自信、而且容易犯错”**的存在。它会用百分之百的笃定语气写代码——即使其中包含 bug 或胡言乱语——并且除非你发现问题,否则它不会主动告诉你哪里错了。因此,我会把每一段 AI 生成的代码,都当成来自一位初级工程师:逐行阅读、运行、并在需要时测试。你必须测试它写的东西——跑单元测试,或手动验证功能是否真的如它所说那样工作。更多内容可参考《“氛围式编码”并不是低质量工作的借口》。

事实上,我把测试直接织入了整个工作流。前期规划阶段通常就会包含每一步对应的测试列表或测试计划。如果我使用像 Claude Code 这样的工具,我会指示它在完成某个任务后运行测试套件,并在出现失败时自行调试。这种紧密的反馈循环(写代码 → 跑测试 → 修复)正是 AI 擅长的事情——前提是测试存在。因此,那些能最大化利用编码代理的人,往往也是测试实践非常扎实的人。对于像 Claude 这样的代理来说,一个完善的测试套件就像安全网;没有测试时,代理可能会轻率地认为“一切正常”,而实际上已经破坏了好几处。所以,投资测试——它会放大 AI 的价值,并增强你对结果的信心。

即便超越自动化测试,也要做代码评审——包括人工评审和 AI 辅助评审。我经常停下来,逐行审查目前生成的代码。有时我会开启第二个 AI 会话(或使用不同模型),让它去评审第一个模型生成的代码。例如,让 Claude 写代码,然后问 Gemini:“你能帮我检查这个函数是否有错误或改进空间吗?”这常常能发现细微问题。关键在于:不要因为代码是 AI 写的,就跳过评审。恰恰相反,AI 写的代码往往需要更多审查,因为它有时在表面上极具说服力,却隐藏着人类不容易第一时间察觉的缺陷。

我还使用了由我上一支团队构建的 Chrome DevTools MCP,作为调试与质量闭环的一部分,用来弥合静态代码分析与真实浏览器执行之间的鸿沟。它相当于“给 AI 装上眼睛”:允许我授权 AI 工具直接查看浏览器所看到的内容,检查 DOM,获取性能追踪、控制台日志或网络请求记录。这种集成消除了手动切换上下文的摩擦,使得通过 LLM 直接进行自动化 UI 测试成为可能,也让基于真实运行数据的高精度 bug 定位和修复成为现实。

忽视人工监督的严重后果已有记录。一位在赶项目时大量依赖 AI 生成代码的开发者描述最终产物是一个混乱不堪的系统——逻辑重复、方法命名不一致、架构支离破碎。他意识到自己只是不断“构建、构建、再构建”,却从未真正退后一步去理解 AI 编织出来的整体。修复它需要一次痛苦的重构,并发誓再也不让事情失控到这种程度。我对此深有感触。无论我使用多少 AI,我始终是那个负最终责任的工程师。

在实践中,这意味着:只有在我真正理解代码之后,才会合并或发布。如果 AI 生成了过于复杂的实现,我会让它加注释解释,或者干脆自己重写成更简单的形式。如果哪里感觉不对劲,我就会深入调查——就像对待一位人类同事提交的可疑代码一样。

一切归根结底是心态问题:LLM 是助手,而不是可以自主信赖的编码者。我是高级工程师;LLM 的职责是加速我,而不是替代我的判断。坚持这种立场不仅能产出更好的代码,也能保护你自身的成长。(有些人担心过度依赖 AI 会让技能退化——我认为只要你始终在回路中,积极审查并理解每一行代码,你实际上是在以更高速度打磨直觉。)总之:保持警惕,频繁测试,始终评审。 到最后,这仍然是你的代码库。

经常提交代码,并将版本控制作为安全保障。切勿提交自己无法解释的代码。

频繁提交就是你的存档点——它们让你能够撤销 AI 的失误,并理解发生了哪些变化。

当你与一个能够快速生成大量代码的 AI 一起工作时,事情很容易偏离正轨。我通过采用极其细粒度的版本控制习惯来缓解这一问题。我会尽早、并且频繁地提交代码,甚至比正常手写代码时还要频繁。每完成一个小任务,或每一次成功的自动化修改之后,我都会创建一次带有清晰提交信息的 git commit。这样一来,如果 AI 的下一条建议引入了 bug 或者造成了混乱的改动,我就能回退到最近的检查点(或者从中 cherry-pick),而不会丢掉数小时的工作。一位实践者把这种做法比作把提交当成**“游戏里的存档点”**——如果一次 LLM 会话走偏了,你总是可以回滚到上一个稳定的提交。我发现这个建议极其有用。当你知道必要时可以用 git reset 撤销改动时,去尝试一次大胆的 AI 重构就不那么有压力了。

恰当的版本控制在与 AI 协作时同样非常有帮助。由于我不能指望 AI 记住它做过的所有事情(上下文窗口的限制等等),git 历史就成了一份宝贵的日志。我经常浏览最近的提交,向 AI(或向我自己)说明发生了哪些变化。事实上,只要你把提交历史提供给 LLM,它们本身也能利用这些信息——我曾把 git diff 或提交日志直接粘贴到提示词里,让 AI 知道哪些代码是新的,或者之前的状态是什么。有趣的是,LLM 在解析 diff 以及使用诸如 git bisect 之类的工具来定位 bug 引入位置方面真的非常擅长。它们有着无限的耐心去遍历提交历史,这可以极大增强你的调试能力。但前提是:你一开始就要有一份整洁的提交历史。

还有一个好处:带有良好提交信息的小提交,本质上记录了开发过程,这在做代码审查(无论是 AI 还是人类)时非常有帮助。如果一个 AI 一次性做了五个改动,然后某处坏了,把这些改动分散在不同提交中,就更容易定位到底是哪个提交导致了问题。反之,如果所有内容都塞进一个名为“AI changes”的巨大提交里,那就自求多福吧。我因此严格要求自己:完成任务,运行测试,提交。 这也与前面关于把工作拆分成小块的建议非常契合——每一个小块最终都会成为一个独立的提交或 PR。

最后,不要害怕使用分支或 worktree来隔离 AI 实验。我采用的一种进阶工作流(灵感来自 Jesse Vincent 等人)是:为一个新特性或子项目创建一个全新的 git worktree。这样我就可以在同一个仓库上并行运行多个 AI 编码会话而互不干扰,之后再把改动合并回来。这有点像让每个 AI 任务都待在自己的沙箱分支里。如果某个实验失败了,我就直接丢弃那个 worktree,主分支不会受到任何影响;如果成功了,再把它合并进来。当我一边让 AI 实现特性 A,一边由我自己(或另一个 AI)实现特性 B 时,这种方式尤为关键。正是版本控制让这种协同成为可能。简而言之:频繁提交,用分支组织工作,并拥抱 git,把它作为控制机制,来让 AI 生成的改动保持可控且可逆。

通过规则和示例来定制 AI 的行为

通过提供风格指南、示例,甚至“规则文件”来引导你的 AI 助手——前期做一点调校,就能显著提升输出质量。

我学到的一点是:你不必接受 AI 的默认风格或做事方式——只要给它一些明确的指引,就可以对其行为产生很强的影响。举例来说,我维护了一个会定期更新的 CLAUDE.md 文件,其中包含希望 Claude(Anthropic 的模型)遵循的流程规则和偏好(使用 Gemini CLI 时也有类似的 GEMINI.md)。这些内容包括诸如“按照我们项目的代码风格编写代码、遵循我们的 lint 规则、不使用某些函数、偏好函数式而非 OOP”等。当我开始一个会话时,会把这个文件提供给 Claude,使其与我们的约定保持一致。正如 Jesse Vincent 在其文章中提到的,这种方式在让模型“保持正轨”方面效果出奇地好——它能显著降低 AI 偏离脚本或引入我们不希望出现的模式的概率。

即便没有花哨的规则文件,你也可以通过自定义指令或 system prompt 来定调。GitHub Copilot 和 Cursor 都引入了相关功能,允许你在项目层面全局配置 AI 的行为。我就充分利用了这一点,写了一小段关于我们编码风格的说明,例如:“使用 4 空格缩进,在 React 中避免使用箭头函数,偏好描述性变量名,代码需通过 ESLint。”在这些指令就位之后,AI 的建议就会更加贴近人类队友的写法。Ben Congdon 在文章中提到,他很惊讶竟然很少有人使用 Copilot 的自定义指令,因为它们的效果非常显著——只要提前提供一些示例和偏好,他就能引导 AI 输出完全符合团队习惯的代码。我对此深有同感:花点时间教会 AI 你的期望。

另一个非常强大的技巧是提供行内示例,明确你想要的输出格式或实现方式。如果我希望 AI 以一种非常特定的方式来编写函数,我可能会先给它看代码库中已有的类似函数:“这是我们实现 X 的方式,请用类似的方法实现 Y。”如果我想要某种特定的注释风格,我甚至会先自己写一条注释,然后让 AI 按这种风格继续。本质上,这是在对模型进行 预热(prime),让它知道要遵循的模式。LLM 非常擅长模仿——给它一两个例子,它就会沿着同样的路子往下写。

社区中也出现了不少富有创意的“规则集”,用来驯服 LLM 的行为。你可能听说过 “Big Daddy” 规则,或者在提示词中加入“禁止幻觉 / 禁止欺骗”的条款。这些本质上都是在提醒 AI 要保持真实,不要过度编造并不存在的代码。例如,我有时会在提示词前加上一句:“如果你对某些事情不确定,或者缺少代码库上下文,请先请求澄清,而不是编造答案。”这能有效减少幻觉。另一条我常用的规则是:“在修复 bug 时,始终在注释中简要说明你的推理过程。”这样一来,当 AI 生成修复方案时,也会留下类似这样的注释:“// Fixed: Changed X to Y to prevent Z (as per spec).”这对后续审查非常有价值。

总而言之,不要把 AI 当成一个黑箱——要对它进行调校。通过配置 system 指令、共享项目文档,或明确写下规则,你可以把 AI 打造成团队中一个更加专业化的开发者。这就像新员工入职一样:你一定会给他风格指南和一些入门建议,对吧?同样地对待你的 AI 结对编程伙伴即可。投入产出比非常高——你会得到需要更少修改、并且能更顺畅地融入现有代码库的输出。

将测试和自动化视为放大效率的关键杠杆

善用 CI/CD、代码规范检查器和代码审查机器人——AI 在能够自动捕获错误的环境中表现最好。

这是“保持人在回路中并持续提供上下文”的一个自然延伸:一条运转良好的开发流水线会显著提升 AI 的生产力。我会确保所有大量使用 AI 编码的代码仓库,都具备一套健全的持续集成(CI)体系。这意味着:每次提交或 PR 都会自动运行测试,强制执行代码风格检查(如 ESLint、Prettier 等),并且理想情况下,每个新分支都能部署到一个可用的 staging 环境。为什么要这样做?因为我可以让 AI 主动触发这些流程,并据此评估结果。

例如,如果 AI 通过 Jules 或 GitHub Copilot Agent 之类的工具发起了一个 pull request,我们的 CI 就会自动运行测试并报告失败信息。我可以把这些失败日志再喂回给 AI:“集成测试在 XYZ 处失败了,我们来一起调试。”这样一来,修 bug 就变成了一个快速反馈的协作循环,而 AI 非常擅长处理这种模式(它提出修复方案,我们再次运行 CI,然后继续迭代)。

自动化的代码质量检查(如 linter、类型检查器)同样可以对 AI 起到引导作用。我有时甚至会把 linter 的输出直接放进提示词里。如果 AI 写的代码没有通过我们的规范检查,我就把错误信息复制到对话中,说一句:“请解决这些问题。”模型立刻就知道该做什么了。这就像有一位严格的老师在盯着 AI 写代码。根据我的经验,一旦 AI 看到了某个工具的输出(比如测试失败或 lint 警告),它就会非常努力地去修正——毕竟它“想要”给出正确的答案。这再次呼应了“提供上下文”的原则:把环境对其行为的反馈(测试失败等)提供给 AI,它就能从中学习和调整。

AI 编码代理本身也在越来越多地集成自动化钩子。有些代理在所有测试通过之前,甚至不会宣称某个代码任务“完成”——这正是你希望看到的那种严谨态度。代码审查机器人(无论是 AI 还是非 AI)则充当了另一道过滤器——我会把它们的反馈当作额外的改进提示。例如,如果 CodeRabbit 或其他审查者评论说:“这个函数在做 X,这并不理想”,我就会直接问 AI:“你能根据这个反馈进行重构吗?”

当你把 AI 与自动化工具结合起来时,就会形成一个良性循环:AI 写代码,自动化工具发现问题,AI 修复问题,如此反复,而你则把控整体方向。这种感觉就像是拥有一位速度极快的初级开发者,而他的每一次提交都会立刻被一位不知疲倦的 QA 工程师检查。但要记住,是你 搭建了这个环境。如果你的项目缺乏测试或任何自动化检查,AI 的工作就可能夹带着细微的 bug 或质量问题,一直潜伏到很晚才被发现。

因此,展望 2026,我的一个目标就是进一步强化 AI 代码贡献周围的质量门禁:更多测试、更多监控,甚至可能引入“AI 审 AI”的代码评审。听起来或许有些悖论(让 AI 去审查 AI),但我已经见过这种方式抓住了某个模型遗漏的问题。归根结底:一个对 AI 友好的工作流,必然具备强大的自动化——用这些工具来约束并校验 AI 的行为。

持续学习并不断适应(AI 会放大你的技能)

把每一次 AI 编码会话都当作一次学习机会——你知道得越多,AI 就越能帮到你,从而形成一个良性循环。

使用 LLM 进行开发过程中,最令我兴奋的一点在于:在这个过程中学到的东西实在太多了。AI 并没有取代我“需要懂”的那些知识,反而把我带入了一些我原本可能不会主动尝试的新语言、框架和技术领域。

这种模式具有普遍性:如果你具备扎实的软件工程基础,AI 会以成倍的效果放大你的生产力;如果缺乏这种基础,AI 可能只会放大混乱。许多经验丰富的开发者都观察到,LLM 会“奖励既有的最佳实践”——清晰的需求说明、完善的测试、规范的代码评审等等,在引入 AI 之后都会变得更加有威力。以我的经验来看,AI 让我能够在更高的抽象层级上工作(专注于设计、接口和架构),而把样板代码的生成交给它;但前提是,我必须先具备这些高层次能力。正如 Simon Willison 所指出的,几乎所有定义一名资深工程师的能力(系统设计、复杂度管理、判断哪些该自动化、哪些该手写)正是如今使用 AI 获得最佳效果的关键。因此,使用 AI 反而促使我提升自己的工程水准——我在规划上更加严谨,在架构上更加自觉,因为我实际上是在“管理”一位速度极快但略显天真的程序员(也就是 AI)。

对于那些担心使用 AI 会削弱自身能力的人,我的看法恰恰相反——前提是用对方式。通过审阅 AI 写的代码,我接触到了新的惯用写法和解决思路;通过调试 AI 的错误,我加深了对语言本身以及问题领域的理解。我经常要求 AI 解释它的代码或修复背后的理由——有点像不断让候选人讲解自己的代码——而我也能从它的回答中获得启发。我还把 AI 当作研究助理:当我对某个库或某种方案不确定时,就让它列举选项、比较取舍。这就像随时有一位百科全书式的导师待命。所有这些,都让我成为了一个更有知识深度的程序员。

从宏观来看,AI 工具是在放大你的专业能力。展望 2026 年,我并不担心它们“抢走我的工作”——相反,我很期待它们把我从繁琐重复的劳动中解放出来,让我能把更多时间投入到软件工程中更具创造性、更复杂的部分。但我也清醒地认识到,对于没有扎实基础的人来说,AI 可能会把“邓宁–克鲁格效应”放大到极致(你可能 感觉 自己做出了很棒的东西,直到它彻底崩塌)。因此,我的建议是:持续打磨你的基本功,并用 AI 来加速这一过程;同时,也要有意识地定期在不使用 AI的情况下编码,以保持原始技能的敏锐度。最终,“开发者 + AI”的组合远比任何一方单独行动更强大,而这个组合中的开发者那一半,必须足够可靠。

结论

随着我们迈入 2026 年,我已经在开发工作流中全面拥抱了 AI——但这是以一种深思熟虑、由专家驱动的方式进行的。我的方法本质上是 “AI 增强的软件工程”,而非 AI 自动化的软件工程。

我学到的一点是:当你在 AI 协作中运用经典的软件工程纪律时,效果最佳。事实证明,我们辛苦积累的所有实践——先设计再编码、编写测试、使用版本控制、维持标准——不仅仍然适用,而且在 AI 编写一半代码时显得更加重要。

我对未来充满期待。工具在不断改进,而我的工作流也必将随之演进。也许完全自主的“AI 开发实习生”将承担更多重复性工作,而我们专注于更高层次的任务;也许会出现新的调试和代码探索范式。不管怎样,我计划始终保持 在回路中——引导 AI、向它们学习,并负责任地放大我的生产力。

对我而言的核心结论是:AI 编码助手是令人难以置信的倍增器,但人类工程师仍是整个流程的导演。

在此,祝大家在 2026 年构建顺利!🚀

我很高兴地分享,我已经与 O’Reilly 一起发布了一本新的 AI 辅助工程书籍。书籍网站上也有一些免费的实用技巧,感兴趣的可以查看。

最近读到一篇介绍 Pydantic 生态的文章,提到 pydantic-settings 库除了可以简化应用配置外,还可以用来创建命令行应用。在参阅了相关文档后,我完成了一个简单的示例,体验相当不错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# /// script
# requires-python = ">=3.13"
# dependencies = ["pydantic-settings"]
# ///
import logging
from typing import Annotated, Literal

from pydantic import AliasChoices, Field, BeforeValidator
from pydantic_settings import BaseSettings, CliApp


class Settings(
BaseSettings, cli_parse_args=True, cli_prog_name="sum", cli_enforce_required=True
):
"""A simple CLI app to sum numbers."""

num: Annotated[list[int], Field(description="Numbers to sum")]
verbose: Annotated[
Literal[0, 1],
Field(
default=0,
validation_alias=AliasChoices("v", "verbose"),
description="Enable verbose output",
),
BeforeValidator(lambda v: int(v)),
]

def cli_cmd(self):
if self.verbose:
logging.basicConfig(level=logging.DEBUG, format="%(message)s")
logging.debug("Calculating sum of numbers %s", self.num)
print(sum(self.num))


if __name__ == "__main__":
CliApp.run(Settings)

可以直接使用 uv 运行该脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 自动生成帮助信息

➜ uv run --script cli.py --help
usage: sum [-h] --num list[int] [-v {0,1}]

A simple CLI app to sum numbers.

options:
-h, --help show this help message and exit
--num list[int] Numbers to sum (required)
-v, --verbose {0,1} Enable verbose output (default: 0)

# 必填参数检查(开启 cli_enforce_required)

➜ uv run --script cli.py
usage: sum [-h] --num list[int] [-v {0,1}]
sum: error: the following arguments are required: --num

# 传入参数

➜ uv run --script cli.py --num 1 --num 2 --num 3
6

# 修改默认参数

➜ uv run --script cli.py --num 1 --num 2 --num 3 -v 1
Calculating sum of numbers [1, 2, 3]
6

# 传入 JSON 格式的参数

➜ uv run --script cli.py --num="[1,2,3]"
6

为什么我不看好豆包手机

想象一下你拥有一台自带 AI 助手的手机,想让它帮你用微信发送最近拍摄的合同照片给张总。

若是像以豆包手机为典型的基于屏幕内容读取和模拟点击操作的 AI 手机,大概会按照以下步骤来操作:

  1. 打开相册应用,使用 OCR 技术或多模态大语言模型分析每一张最近拍摄的照片,找到所需的合同照片。
  2. 调用相册应用的分享功能,使用微信分享。
  3. 在微信分享页面通过搜索好友昵称或翻看好友列表的方式,找到张总的账号,输入备注(“张总,这是上次的合同照片”之类)完成分享。

过程中可能会弹出多次授权请求,让用户同意 AI 打开并操作相册、微信等应用。当然不讲究的用户可能在首次配置 AI 手机的时候就永久授予了大部分常见应用的操作权限。

期间 AI 助手会分析识别手机相册中的近期照片(其中可能有家人近照,证件照等敏感照片),获取你的微信好友列表(以及经常互相分享的亲密联系人),给微信好友发消息。并且由于分析照片内容会消耗不少时间,总耗时可能也会长达一分钟以上。

简单来说,这些行为是对隐私和信息安全的极大侵犯,而且并未明显为用户节省时间。

侵犯隐私,安全隐患,效率低下,这就是我对目前讨论火热的豆包手机的看法。

问题的根源在于,若 AI 助手依赖通过读取屏幕内容的方式获取上下文信息,不可避免地需要频繁通过 AI 模型分析手机屏幕上的所有元素。

手机屏幕上往往不只是 AI 助手当前任务需要的信息。比如在上文提的示例中,AI 助手会读取多张图片的内容,直到它找到了合同的照片。并且 AI 助手在微信分享的联系人列表中找到张总之前,可能已经读取了用户大部分的联系人微信昵称和头像,毕竟按拼音排序张总大概率在列表的很后面的位置。同理,在让 AI 帮你在淘宝购买商品的场景下,AI 会获取你的首页推荐商品列表,最近订单,收货地址等隐私信息。即使用的是不联网的端侧模型,我也对 AI 手机们能否妥善处理这些隐私信息持怀疑态度。

当前 AI 模型识别图片需要的时间明显要长于人类,对于普通人来说从相册内的一堆图片中中找到合同照片轻而易举,而 AI 模型不可避免地要一张一张照片的读取并识别(大概率不会同时分析多张照片,端侧模型来不具有满足此类功能需求的性能,对于远程 AI 接口来说这样做成本会相当高)。对人类来说不到十秒的操作,AI 可能需要花费十分钟才能完成,期间用户还不能正常使用手机,实在不是多么优秀的体验。

此外 AI 手机可能还会出现误删除重要文件,发送错误信息给联系人等危险操作。毕竟作为相对很成熟 AI 编程领域,行业领先的 Google Gemini 3.0 Pro 都犯过删除用户整个磁盘文件的错误。尤其是当 AI 手机完成简单的日常操作十分优秀,用户为了省事不再逐一仔细检查 AI 手机的行为默认授权后,往往会有潜在的巨大安全隐患。

综上,不论豆包手机在二手平台炒到到了几万元的高级,它终究不是我理想中的 AI 手机的最佳形态。

我最近使用 Github Copilot Agent 模式的频率大幅增加,在接近月底的时候已经达到了 80%的高级请求使用额度,有必要准备一个备用的 AI 开发工具。
目前比较流行的终端 AI 开发工具非 Claude Code 莫属了(OpenAI 的 Codex 我有使用过,有点倾向于埋头几分钟进行一堆更改,可控性没有 Claude Code 高),但国内环境使用 Claude 模型比较困难,此时可以选择在 Claude Code 中使用国产模型,比如GLM 4.6MinMax M2,只需要修改 claude code 的默认配置就好了。。

.claude/settings.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"env": {
"ANTHROPIC_BASE_URL": "https://api.minimaxi.com/anthropic",
"ANTHROPIC_AUTH_TOKEN": "Your API Key",
"API_TIMEOUT_MS": "3000000",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1,
"ANTHROPIC_MODEL": "MiniMax-M2",
"ANTHROPIC_SMALL_FAST_MODEL": "MiniMax-M2",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "MiniMax-M2",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "MiniMax-M2"
}
}

引言

Python 3.13 版本引入了 (No-GIL 模式),彻底解决了长期存在的并发性能瓶颈问题。随着Python 3.14的发布,Non-GIL 模式更加稳定。本文通过一个计算密集型任务的实际测试,对比 GIL 模式和 No-GIL 模式的性能差异,展示 Python 3.14 在多线程场景下的显著提升。

测试环境

  • 操作系统: Ubuntu 24.04 (WSL 环境)
  • Python 版本:
    • GIL 模式: Python 3.14
    • No-GIL 模式: Python 3.14t (Thread-Free)
  • 执行工具: uv (高性能 Python 包安装器和解析器)
  • 硬件配置: ThinkBook 14 , i5-13500H (2.60 GHz), 32GB RAM

测试方案设计

我们设计了一个计算密集型任务:计算 1 到 1,000,000 的平方和。通过以下方式验证并行性能:

  1. 任务分解:

    • 将数据集划分为与 CPU 核心数相等的块
    • 每个线程处理一个数据块
  2. 计算函数:

1
2
def sum_of_squares(numbers: list[int]):
return reduce(lambda x, y: x + y**2, numbers)
  1. 并发框架:
    • 使用 ThreadPoolExecutor 实现线程池
    • 每次测试运行 10 次取平均值

测试代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from concurrent.futures import ThreadPoolExecutor
from functools import reduce
from time import perf_counter
import os

def sum_of_squares(numbers: list[int]):
"""计算数字列表的平方和"""
return reduce(lambda x, y: x + y**2, numbers)

if __name__ == "__main__":
MAX_WORKERS = os.cpu_count()
print(f"Using {MAX_WORKERS} threads")

# 创建测试数据集 (1-1,000,000)
numbers = list(range(1, 1000001))

# 数据分块
chunk_size = len(numbers) // MAX_WORKERS
chunks = [numbers[i : i + chunk_size] for i in range(0, len(numbers), chunk_size)]

total_time = 0
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
for _ in range(10): # 运行10次取平均
start = perf_counter()
results = list(executor.map(sum_of_squares, chunks))
end = perf_counter()
total_time += end - start

average_time = total_time / 10
print(f"Average time over 10 runs: {average_time:.4f} seconds")
Read more »

Context7 是专为解决 AI 编码助手“知识滞后”痛点设计的革新工具,通过实时抓取最新、版本特定的官方网页与代码示例,直接注入 LLM 的上下文环境,彻底告别过时 API 调用与“幻觉代码”。其核心优势在于:

  1. 精准性:基于 MCP 协议动态解析库版本,确保生成代码与开发环境完全匹配,减少 80% 以上的调试成本;
  2. 高效性:仅需在提示中添加 use context7,即可自动调用最新网页,避免开发者反复切换工具验证信息;
  3. 扩展性:支持超 6000 个主流库(如 React、Next.js、FastAPI),并兼容 Cursor、Claude、VS Code 等多平台,无缝融入现有开发流程。

对于追求代码质量与开发效率的团队及个人开发者,Context7 以免费开源的形式提供企业级网页管理能力,是 AI 编程时代不可或缺的“智能外脑”。

Code Buddy是腾讯推出的 AI 编程助手,提供 IDE 拓展和独立 IDE。最近腾讯又推出了命令行工具Code Buddy Code,类似 Claude Code 和 Gemini CLI。我简单体验了一下,开发了一个网页版的Mermaid 编辑器,总体体验比阿里推出的 Qwen Code 要好一点(可能是因为 Code Buddy Code 的海外版默认使用的 Claude 4 模型比 Qwen3 Coder 还是要强上一线)。

【由DeepSeek辅助翻译】

原文链接:https://blog.logrocket.com/typescript-go-pragmatic-choice/
发布时间:2025年4月16日 14:51:38(UTC时间)

关于这次移植的技术细节已有大量报道,本文不再赘述。这里呈现的是TypeScript社区两位成员的思考:

  • John Reilly是软件工程师,TypeScript早期采用者。他参与维护Definitely Typed——这个高质量类型定义库实现了TypeScript与JavaScript的集成。John撰写了Definitely Typed发展史,并出现在TypeScript纪录片中。他还开发维护了ts-loader这个webpack的TypeScript加载器。目前他在南非Investec银行伦敦分部工作。在他看来,伦敦是地球上最伟大的城市
  • Ashley Claymore是软件工程师,居住地距John不远,常与他晨间散步讨论TypeScript。他从TypeScript 1.8版本开始使用,深度参与了语言演进。曾为TypeScript贡献代码,现就职于彭博社JavaScript基础设施与工具团队。文中观点仅代表个人

本文将自由呈现我们的反应与期待。准备好迎接观点、思考和感受的碰撞吧。

移植是否必要?

难道之前不够好吗?是,但也不尽然。

近年来JavaScript/TypeScript生态中,越来越多支持JS开发的工具改用其他语言编写:esbuild(Go)、SWC(Rust)、Bun(Zig)、Deno(Rust)。这些工具都带来了显著的性能提升,而TypeScript始终用自身编写。虽然团队持续优化性能,但改进始终是渐进式的。

社区开始涌现自行实现TypeScript加速的尝试。最著名的是SWC作者DongYoon Kang,他先实现了TypeScript转译功能,又尝试构建类型检查器——最初用Rust后改用Go,最终回归Rust。虽然项目未成功,但这些尝试印证了市场对性能的强烈需求。移植已成必然——若非官方出手,整个生态将陷入困境。而现在,我们迎来了Go版的TypeScript。

性能变革

Go移植对TypeScript意味着什么?根据Josh Goldberg的框架,TypeScript包含四个维度:

  • 语言规范
  • 类型检查器
  • 编译器
  • 语言服务

语言规范不受移植影响,语法保持不变。您仍可照常使用typeinterface。类型检查规则也维持原样,原有错误提示依然有效:

const i: number = "非数字值"; 
// ts报错:类型'string'不能赋值给类型'number'

真正的变化始于类型检查器、编译器和语言服务——它们将获得数量级的提速。

谁不关心性能?显然没人。当工具卡顿打断工作流时,这种体验令人难以忽视。TypeScript团队始终重视性能,特别是开发工具响应速度。联合创始人Anders Hejlsberg多次强调语言服务器必须提供毫秒级反馈。

这将如何影响生态?简而言之:更快的VS Code和构建流程。

以John所在的Investec银行为例,众多使用VS Code的工程师将获得更流畅的开发体验:项目加载时语言服务启动更快、重构响应更迅捷、”红色波浪线”出现更及时。构建过程同样受益——无论是本地还是持续集成环境,TypeScript编译都将显著加速。这种提升将惠及全球所有TypeScript开发者。

Read more »

【本文由DeepSeek R1辅助编写完成】
PEP750

引言

在 Python 的字符串处理领域,f-strings 自推出以来因其简洁高效广受开发者喜爱。但 f-strings 的即时求值特性在某些场景下显得力不从心,特别是在需要预处理的场景(如安全转义、结构化日志记录)中。PEP 750 提出的**模板字符串(Template Strings)**通过引入 t 前缀和延迟处理机制,为这一难题提供了优雅的解决方案。本文将深入解析这一提案的核心思想,并通过实际案例展示其强大能力。


一、模板字符串的核心特性

1.1 语法与基本使用

模板字符串使用 t 前缀定义,语法与 f-strings 完全兼容:

1
2
from string.templatelib import Template
template = t"Hello {name}!"

与 f-strings 不同,模板字符串不会直接求值为字符串,而是生成 Template 对象,包含静态字符串片段插值表达式信息

1.2 Template 对象结构

1
2
3
4
5
6
7
class Template:
strings: tuple[str, ...] # 静态字符串片段(数量=插值数+1)
interpolations: tuple[Interpolation, ...] # 插值列表

@property
def values(self) -> tuple[object, ...]: # 插值求值结果
...

1.3 Interpolation 对象

每个插值表达式对应一个 Interpolation 实例:

1
2
3
4
5
class Interpolation:
value: object # 表达式求值结果
expression: str # 原始表达式文本
conversion: str | None # 转换符(!r/!s/!a)
format_spec: str # 格式规范

二、应用场景解析

2.1 安全内容生成

传统 f-strings 在生成 HTML 时容易引发 XSS 漏洞:

1
2
user_input = "<script>alert('XSS')</script>"
dangerous_html = f"<div>{user_input}</div>" # 危险!

模板字符串解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
def safe_html(template: Template) -> str:
parts = []
for item in template:
if isinstance(item, Interpolation):
# 自动转义 HTML 特殊字符
escaped = html.escape(str(item.value))
parts.append(escaped)
else:
parts.append(item)
return "".join(parts)

template = t"<div>{user_input}</div>"
print(safe_html(template)) # <div>&lt;script&gt;...&lt;/script&gt;</div>

2.2 结构化日志记录

传统日志记录丢失结构化数据:

1
logger.info(f"User {username} logged in")  # 无法提取 username 值

模板字符串解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class StructuredMessage:
def __init__(self, template: Template):
self.template = template

@property
def message(self) -> str:
return "".join(str(item) for item in self.template)

@property
def context(self) -> dict:
return {
item.expression: item.value
for item in self.template.interpolations
}

logger.info(StructuredMessage(t"User {username} logged in"))
# 输出:User alice logged in >>> {"username": "alice"}
Read more »

【由DeepSeek辅助编写】

MCP Run Python 是由 PydanticAI 提供的 MCP 服务器,能够在安全、隔离的沙盒环境中执行 Python 代码。它基于 PyodideDeno 技术栈,通过 WebAssembly 实现代码隔离,确保主机系统不受执行代码的影响。

核心特性

  • 安全执行:在沙盒化的 WebAssembly 环境中运行 Python 代码
  • 依赖管理:自动检测并安装代码所需的依赖包
  • 完整输出:捕获标准输出、标准错误及返回值
  • 异步支持:原生支持异步代码执行
  • 错误处理:提供详细的错误报告,便于调试

快速开始

推荐使用 Deno 运行(替代原 npm/npx 方案):

deno run -N -R=node_modules -W=node_modules --node-modules-dir=auto jsr:@pydantic/mcp-run-python stdio

支持三种运行模式:

  • stdio:通过标准输入输出通信(适合本地子进程)
  • sse:基于 HTTP 的服务器推送模式(支持远程连接)
  • warmup:预加载 Python 标准库

使用示例

通过 Python MCP 客户端调用:

from mcp import ClientSession
from mcp.client.stdio import stdio_client

code = """
import numpy as np
arr = np.array([1, 2, 3])
print(arr)
arr
"""

async with ClientSession(...) as session:
    result = await session.call_tool('run_python_code', {'python_code': code})
    print(result.content[0].text)  # 输出执行结果

依赖管理

支持两种依赖声明方式:

  1. 自动推断:通过分析代码中的 import 语句
  2. 元数据注释:遵循 PEP 723 规范
# /// script
# dependencies = ["pydantic", "email-validator"]
# ///

适用场景

  • 需要安全执行用户提交代码的 SaaS 平台
  • 教育类应用的代码评测系统
  • 自动化工作流中的动态脚本执行

MCP Run Python 现已作为 JSR 包 发布,更多用法参考 官方文档