<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>软件架构 on 张欣耕的个人博客</title><description>Recent content in 软件架构 on 张欣耕的个人博客</description><link>https://shanechang.com/zh-cn/tags/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84/</link><language>zh-cn</language><lastBuildDate>Fri, 28 Nov 2025 00:00:00 GMT</lastBuildDate><atom:link href="https://shanechang.com/zh-cn/tags/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84/index.xml" rel="self" type="application/rss+xml"/><item><title>双代理法则: 开发新功能, 别被上下文淹没了</title><link>https://shanechang.com/zh-cn/p/two-agent-method-building-features-complex-codebase/</link><guid isPermaLink="true">https://shanechang.com/zh-cn/p/two-agent-method-building-features-complex-codebase/</guid><description>&lt;img src=&quot;https://shanechang.com/_astro/cover.BYQFEibf_1GaBcE.webp&quot; alt=&quot;Featured image of post 双代理法则: 开发新功能, 别被上下文淹没了&quot; /&gt;&lt;p&gt;用AI编程助手写点简单的小功能, 谁不会?可一旦要动点”大手术”——比如新功能开发, 系统集成——不少人就会陷入一种”我是不是智商税交多了”的无力感。&lt;/p&gt;
&lt;p&gt;本来目标很明确, AI一开始也挺聪明, 左看看右看看代码, 问几个问题, 甚至还给出点靠谱方案。可一到真动手写代码, 画风突变: 代码集成得四不像, 边界条件忘得一干二净, AI还一本正经提出些能直接把系统搞崩的改动建议。&lt;/p&gt;
&lt;p&gt;于是你发现, 自己不是在写功能, 而是在debug AI的迷之思路……&lt;/p&gt;
&lt;p&gt;其实, 问题不是AI不行, 而是我们用错了方法。别把AI当实习生, 什么都记得牢牢的。它们更像天赋异禀但记性极差的咨询顾问——短时记忆就那么点, 还经常”跑题”。&lt;/p&gt;
&lt;p&gt;明白这一点, 开发流程就该升级了。&lt;/p&gt;
&lt;h2 id=&quot;真正的难题-上下文越积越乱&quot;&gt;真正的难题: 上下文越积越乱&lt;/h2&gt;
&lt;p&gt;和AI助手聊得越久, 问题越大。每一次”走错路”, 每一个被推翻的假设, 每个查过的无关文件——对AI来说, 都是不可磨灭的”历史遗留”。不像人类能自我总结, 自动遗忘, AI只会越背越重, 还全都塞在短期记忆里。&lt;/p&gt;
&lt;p&gt;想象一下你专心写作时, 有个人把你所有草稿, 废话, 删掉的段落都大声朗读一遍。信噪比越来越低, 最后脑袋瓜子只剩”乱”。&lt;/p&gt;
&lt;p&gt;这也是为什么有时候你和AI规划得头头是道, 真到实现阶段却步步踩坑。AI虽然最后想明白了, 但所有的歧路亡羊都还”留在脑子里”——一不小心就又走回老路。&lt;/p&gt;
&lt;p&gt;解决办法不是少用AI, 而是让你的开发流程更适合AI的”脑回路”。&lt;/p&gt;
&lt;h2 id=&quot;双代理模式登场&quot;&gt;双代理模式登场&lt;/h2&gt;
&lt;p&gt;最靠谱的做法很简单: 一人 (代理) 负责探索, 一人 (代理) 专职实现, 各司其职, 分工明确。&lt;/p&gt;
&lt;p&gt;第一个AI代理, 姑且叫”探索者”: 它就像项目里的”侦查兵”, 专注于搞清楚代码结构, 问关键问题, 梳理集成点, 最后输出一份清晰明了的开发方案。这步的核心是”把问题想透, 把方案写清”。&lt;/p&gt;
&lt;p&gt;第二个AI代理, 叫”实现者”: 它啥都不带入, 只接受探索者的成果文档, 干净利落地写代码。没有历史包袱, 没有莫名其妙的上下文污染。&lt;/p&gt;
&lt;p&gt;其实, 这不就是高级工程师和开发小组的惯用套路吗?架构师负责搞清楚全局, 制定方案, 开发同学根据方案实现。哪怕同一个人, 方案和实现也是”两副面孔”——前半场思考, 后半场执行。&lt;/p&gt;
&lt;h2 id=&quot;第一阶段-带约束的探索&quot;&gt;第一阶段: 带约束的探索&lt;/h2&gt;
&lt;p&gt;首先, 你要清晰地描述清需求。别小看这一步, 后面一切的质量都靠它打地基。&lt;/p&gt;
&lt;p&gt;给探索者AI指明方向: 要查什么模块, 只看相关代码, 别瞎溜达。比如要给用户认证系统加OAuth, 就请它”专注查auth相关文件”, 别让它在全仓库里迷路, 把宝贵的上下文窗口全浪费在无关代码上。&lt;/p&gt;
&lt;p&gt;还得加一句”魔法提示”: “如果你有任何不确定, 先问清楚, 别自己脑补。”&lt;/p&gt;
&lt;p&gt;这句话的力量堪比”防脱发洗发水”——大模型如果不被约束, 最喜欢自作聪明地瞎猜, 但你明确要求它”有疑问就问”, 它反而会提出不少专业, 靠谱的问题。&lt;/p&gt;
&lt;p&gt;这些问题要认真答, 别怕麻烦。比如它问”软删除用户还能登陆吗”, 你别只回答”不行”, 而是把用户删除的整个生命周期讲透, 顺带把相关联的系统规则都说清楚。&lt;/p&gt;
&lt;p&gt;随着探索推进, AI会不断提问, 查代码, 细化理解。直到有一天, 它自信地宣布: “我明白了, 这就是完整方案。“&lt;/p&gt;
&lt;h2 id=&quot;关键交接点&quot;&gt;关键交接点&lt;/h2&gt;
&lt;p&gt;大部分人到这步就掉坑里了——一看到计划靠谱, 立刻喊: “好, 直接在这个对话里实现吧!”&lt;/p&gt;
&lt;p&gt;千万别!这一步是分水岭。&lt;/p&gt;
&lt;p&gt;你要让探索者AI不是写”操作指南”, 而是写”开发文档”给另一个开发者看。二者差别大得很。&lt;/p&gt;
&lt;p&gt;“操作指南”像是: “给User模型加个deleted_at字段, 把UserService.get_active_users()方法改成排除已删除用户。”&lt;/p&gt;
&lt;p&gt;“开发文档”则是: “models/user.py里的User模型, 当前没有软删除机制, delete()方法会直接删除。要做软删除, 可以加个deleted_at时间戳。services/user_service.py的UserService负责返回用户集合, 这里需要过滤掉已删除用户。admin/users.py是管理后台用户列表, 数据来源于UserService。”&lt;/p&gt;
&lt;p&gt;前者是”照做”, 后者是”指导思路”——既指出重点位置, 又保留实现灵活性, 方便后续开发者 (AI) 独立思考。&lt;/p&gt;
&lt;p&gt;交接文档里最好有:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相关文件路径和大致内容&lt;/li&gt;
&lt;li&gt;集成点以及原因&lt;/li&gt;
&lt;li&gt;可能的实现方案和权衡&lt;/li&gt;
&lt;li&gt;具体需求, 业务约束&lt;/li&gt;
&lt;li&gt;你的代码风格偏好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是”交接文档”。&lt;/p&gt;
&lt;h2 id=&quot;第二阶段-清爽实现&quot;&gt;第二阶段: 清爽实现&lt;/h2&gt;
&lt;p&gt;新开个对话, 把交接文档和最初的需求一起贴进去。&lt;/p&gt;
&lt;p&gt;你会看到有趣的变化:&lt;/p&gt;
&lt;p&gt;如果探索者AI的文档写得够好, 实现者AI通常会很快领会架构, 认认真真看了相关文件后说: “我可以开始写啦。”&lt;/p&gt;
&lt;p&gt;这句话其实是个”质量信号”: 能顺利开工, 说明文档清晰全面。如果还要追问一堆细节, 说明探索阶段还差点火候。&lt;/p&gt;
&lt;p&gt;此时实现者AI有如下优势:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;上下文极为干净, 只关注核心信息&lt;/li&gt;
&lt;li&gt;没有探索阶段的”杂音记忆”&lt;/li&gt;
&lt;li&gt;站在”局外人”的新视角, 容易发现集成盲点&lt;/li&gt;
&lt;li&gt;可以自主做实现决策&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通常写出来的代码, 更贴合现有架构, 风格一致, 集成自然。&lt;/p&gt;
&lt;h2 id=&quot;为什么这招真管用&quot;&gt;为什么这招真管用?&lt;/h2&gt;
&lt;p&gt;大模型不像人类”选择性遗忘”, 它会把上下文窗口里的每个token都平均权重地处理。你30条消息前的迷惑发言, 和刚刚描述的需求影响力几乎一样大。&lt;/p&gt;
&lt;p&gt;重置上下文, 不只是省点token, 更是把那些”误导信号”一锅端, 避免影响实现。&lt;/p&gt;
&lt;p&gt;这就像两种会议:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一种东拉西扯两小时, 每条歪路都讨论一遍, 最后还要带着一堆废话来做决策&lt;/li&gt;
&lt;li&gt;一种是有人拿一页纸, 清清楚楚总结了重点, 大家直接讨论执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后者的决策效率和质量, 自然高出一大截。&lt;/p&gt;
&lt;h2 id=&quot;实战举例&quot;&gt;实战举例&lt;/h2&gt;
&lt;p&gt;比如你要给数据平台做数据导出功能。系统里权限复杂, 数据格式多, 敏感信息边界一堆。&lt;/p&gt;
&lt;p&gt;“探索者”AI就要:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仔细梳理权限系统, 弄明白各项控制规则&lt;/li&gt;
&lt;li&gt;查现有导出代码, 保证风格一致&lt;/li&gt;
&lt;li&gt;找出敏感数据的过滤点&lt;/li&gt;
&lt;li&gt;问清导出需求: 格式?大小?异步还是同步?&lt;/li&gt;
&lt;li&gt;看看类似功能怎么做错误处理和日志&lt;/li&gt;
&lt;li&gt;最后出一份覆盖数据流, 权限, 格式转换, 异常处理的开发计划&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交接文档可能会写: “services/reports.py里的报表生成用的是Celery异步任务, 大数据集建议也用这个模式, 防止请求超时。权限校验在服务层, 不是在API层, 参照ReportService.get_report()。数据脱敏统一用utils/sanitize.py。”&lt;/p&gt;
&lt;p&gt;“实现者”AI看了文档和相关代码, 照着现有架构写导出功能: 用Celery做异步, 在服务层校验权限, 用统一的脱敏工具。&lt;/p&gt;
&lt;p&gt;如果让同一个AI从头到尾搞, 很容易出现风格错乱: 权限校验位置不对, 处理方式不统一, 同步异步混用……这些细节虽然不致命, 但积累多了, 代码库就会越来越难维护。&lt;/p&gt;
&lt;h2 id=&quot;什么时候适合用双代理&quot;&gt;什么时候适合用双代理?&lt;/h2&gt;
&lt;p&gt;不是所有需求都需要这么大阵仗。加个小工具函数, 修个显眼bug, 让AI单兵作战就够。&lt;/p&gt;
&lt;p&gt;这套流程特别适合:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;涉及多个系统模块的新功能&lt;/li&gt;
&lt;li&gt;集成比”单点突破”更重要&lt;/li&gt;
&lt;li&gt;需要新代码无缝融入既有体系&lt;/li&gt;
&lt;li&gt;对架构理解有要求&lt;/li&gt;
&lt;li&gt;你已经反复给AI补充上下文, 依然沟通不畅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个简单判断: 如果你觉得”这活儿最好有高级工程师先审设计”, 那就用双代理。&lt;/p&gt;
&lt;h2 id=&quot;模式变种&quot;&gt;模式变种&lt;/h2&gt;
&lt;p&gt;有些团队更”花哨”——&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Architect (架构师) 代理专门做方案评审&lt;/li&gt;
&lt;li&gt;Reviewer (评审员) 代理专门挑刺&lt;/li&gt;
&lt;li&gt;Documenter (文档员) 代理专门写用户文档&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;核心原则不变: 每个代理只关心自己那一块, 脑子越干净越好。&lt;/p&gt;
&lt;h2 id=&quot;隐藏的好处&quot;&gt;隐藏的好处&lt;/h2&gt;
&lt;p&gt;除了代码质量提升, 这个模式还有个隐形福利: 逼着你自己把需求想明白。&lt;/p&gt;
&lt;p&gt;要写出合格的交接文档, 自己必须先厘清思路。探索者AI问得越细, 你越不能蒙混过关, 反而提前发现了需求歧义和漏洞。&lt;/p&gt;
&lt;p&gt;很多bug其实不是AI写得差, 而是”设计阶段就没想明白”, 这个流程刚好把问题提前暴露了。&lt;/p&gt;
&lt;h2 id=&quot;实用建议&quot;&gt;实用建议&lt;/h2&gt;
&lt;p&gt;实际用的时候还有几点小窍门:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一开始就告诉探索者你的需求和相关目录, 别让它全仓库乱跑&lt;/li&gt;
&lt;li&gt;探索阶段AI问的问题一定要认真答, 哪怕看起来”很傻”, 有些问题其实暴露了隐含冲突&lt;/li&gt;
&lt;li&gt;交接文档不用长, 三四段就行, 重在清晰, 不必面面俱到&lt;/li&gt;
&lt;li&gt;如果实现者AI还追问很多细节, 说明探索阶段还欠火候, 可以考虑补充&lt;/li&gt;
&lt;li&gt;你的代码风格 (格式, 文档, 命名) 要明说, AI不会”耳濡目染”吸收&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;局限性&quot;&gt;局限性&lt;/h2&gt;
&lt;p&gt;这套方法不是万能的。实现者AI照样可能写出bug, 集成阶段也还是会有意外。代码评审依然必不可少。&lt;/p&gt;
&lt;p&gt;但它至少解决了”上下文污染”这个大难题, 让复杂功能开发变得可靠许多。&lt;/p&gt;
&lt;h2 id=&quot;拓展思路-不只有编程&quot;&gt;拓展思路: 不只有编程&lt;/h2&gt;
&lt;p&gt;只要是复杂任务, AI都适合用这个分阶段流程: 先调研/探索, 产出清晰文档, 再执行/实现。&lt;/p&gt;
&lt;p&gt;领域不同, 模式可变, 但核心铁律不会变——认知清晰, 远胜于”模型参数大”。一个”中等资质”模型, 拿着干净简洁的上下文, 往往能干掉”天赋型选手”却被上下文垃圾拖后腿的”天才”。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;(本文由人类原创, 并在部分环节借助AI润色。)&lt;/em&gt;&lt;/p&gt;</description><pubDate>Fri, 28 Nov 2025 00:00:00 GMT</pubDate></item><item><title>为什么AI无法成为工程师</title><link>https://shanechang.com/zh-cn/p/why-ai-cannot-engineer/</link><guid isPermaLink="true">https://shanechang.com/zh-cn/p/why-ai-cannot-engineer/</guid><description>&lt;img src=&quot;https://shanechang.com/_astro/cover.CTct8cc3_1GfOkr.webp&quot; alt=&quot;Featured image of post 为什么AI无法成为工程师&quot; /&gt;&lt;p&gt;上个月, 我让Claude帮我撸了一个客户后台。十分钟后, 漂亮的React组件摆在我面前, API结构清晰, 登录验证在我本地跑得飞快。那一刻我差点以为自己是哈利波特。&lt;/p&gt;
&lt;p&gt;两天后, 我们把这玩意儿给真实用户用, 灾难现场就上演了: API在并发下直接跪了, 登录令牌一半时间在用户操作中间就过期, 数据库查询在我测试数据只有10条时还很快, 真数据一上来, 30秒都查不出来。&lt;/p&gt;
&lt;p&gt;代码美得像艺术品。用?也能用——勉强算是。但本质上, 这就是定时炸弹, 我只能怪自己。需要建筑师的时候, 我却只找了个瓦匠。&lt;/p&gt;
&lt;h2 id=&quot;看起来像摩天大楼-没人敢住&quot;&gt;看起来像摩天大楼, 没人敢住&lt;/h2&gt;
&lt;p&gt;想象一下建一栋摩天大楼。你得有两波人:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;建筑师和结构工程师&lt;/strong&gt;负责设计。他们要琢磨承重墙放哪, 电线水管怎么绕, 什么材料能抗住高空风, 地震来了楼会不会晃歪。还得考虑消防通道, 电梯井, 甚至人怎么进出都要细细盘算。画一大堆图纸, 标一堆标准。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;施工队&lt;/strong&gt;才是真正搬砖的。他们会搅拌混凝土, 焊钢筋, 装玻璃窗。只要给他们详细蓝图, “这儿用几号钢筋, 间距6英寸, 混凝土48小时别动”, 他们就能盖出结实安全的楼。&lt;/p&gt;
&lt;p&gt;有意思的是, 施工队也懂点门道: 知道钢筋混凝土才牢靠, 承重墙不能乱打洞, 材料遇热会膨胀。虽然不会算具体受力, 但知道哪些事千万不能做。&lt;/p&gt;
&lt;p&gt;所以, 理论上, 如果你让施工队不用图纸直接干, 他们也能盖出个楼来: 墙能立起来, 水电能接, 屋顶也有。&lt;/p&gt;
&lt;p&gt;能撑一阵。&lt;/p&gt;
&lt;p&gt;但真有人住进去, 地震来了, 着火了, 你才发现——电路乱成一锅粥, 水压上不去, 消防门找不到, 风一吹楼就晃。外表像楼, 其实不结实, 不安全, 没法住, 是个”高价装修的危楼”。&lt;/p&gt;
&lt;p&gt;你真的需要工程师和建筑师。&lt;/p&gt;
&lt;h2 id=&quot;我们把两份工混成了一份&quot;&gt;我们把两份工混成了一份&lt;/h2&gt;
&lt;p&gt;回到软件圈。其实我们也有两种角色, 但现在大家已经傻傻分不清。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;软件工程师&lt;/strong&gt;应该主导系统设计, 琢磨扩展性, 可靠性, 安全性, 可维护性。定规范, 立规矩, 想各种情况: 一万用户同时访问会咋样?部分功能挂了怎么办?数据一致性怎么保证?凌晨3点出bug怎么排查?这些人给出”蓝图”, 决定你的代码到底能不能上线, 能不能扛住大场面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;程序员&lt;/strong&gt;则负责写代码。他们擅长语法, 算法, 设计模式, 能把需求转成具体实现。只要有好规范和架构, 他们能写出高质量, 维护方便的代码。&lt;/p&gt;
&lt;p&gt;但问题来了: 工程师也得写代码啊!不会写代码的建筑师, 设计出来的楼根本站不住。同理, 不懂代码运行原理的软件工程师, 也架不住”代码打脸”。&lt;/p&gt;
&lt;p&gt;于是, 两份工混成了一份: 大多数公司说”我们招软件工程师”, 其实是招”设计+实现一肩挑”的全能型选手。大家脑袋里画蓝图, 手上撸代码。这么搞了好多年, 竟然还行。&lt;/p&gt;
&lt;h2 id=&quot;欢迎ai程序员闪亮登场&quot;&gt;欢迎AI程序员闪亮登场&lt;/h2&gt;
&lt;p&gt;现在, 大语言模型 (LLM) 能写代码了。我的感受是: &lt;strong&gt;LLM是顶级程序员, 但完全不是工程师。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LLM像那位啥都能盖的施工大哥, 你说”给我做个Todo List”, 它立马给你写好。代码优雅, 结构清晰, 变量名感人, 跑起来贼顺溜。&lt;/p&gt;
&lt;p&gt;但工程的部分全没了:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不考虑负载&lt;/strong&gt;: 用内存数组存Todo, 测着快, 用户一多直接爆炸&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没处理异常&lt;/strong&gt;: 数据库断了咋办?代码八成直接挂&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全感人&lt;/strong&gt;: 有登录验证, 但防不住常见攻击, SQL注入一查一个准&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能盲点&lt;/strong&gt;: 每次都遍历所有用户的todo?等着内存爆炸吧&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运维无视&lt;/strong&gt;: 日志, 监控几乎没有, 出事了只能靠烧香&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码看起来像模像样, 规范也全对, 理想情况下能跑。但一旦遇到真实世界的幺蛾子——并发, 网络断, 奇葩输入, 恶意攻击——它就跟那座没人敢住的摩天楼一样, 外表光鲜, 里头一团糟。&lt;/p&gt;
&lt;h2 id=&quot;这事儿到底意味着啥&quot;&gt;这事儿到底意味着啥&lt;/h2&gt;
&lt;p&gt;以前我觉得”工程师”和”程序员”的区分纯粹是咬文嚼字。现在我明白了, 这区别比你想的要命。&lt;/p&gt;
&lt;p&gt;你让LLM”写个认证系统”, 其实就是让施工队”盖个楼”, 却没给任何要求。比如:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;楼里住几千人还是一户人家?&lt;/li&gt;
&lt;li&gt;抗不抗地震, 火灾?&lt;/li&gt;
&lt;li&gt;消防标准咋定?&lt;/li&gt;
&lt;li&gt;水电怎么布?&lt;/li&gt;
&lt;li&gt;预算多少?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LLM肯定给你盖出来点啥, 样子还挺唬人, 但根本不靠谱。因为, 没人做”工程师”的活。&lt;/p&gt;
&lt;p&gt;举个我司Empath Legal的真实例子。我们帮律师做陪审团筛选工具。我要是让LLM来: “写个API, 分析陪审员问卷, 给出洞察。”&lt;/p&gt;
&lt;p&gt;LLM能写出能用的东西:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;解析问卷&lt;/li&gt;
&lt;li&gt;调用LLM分析文本&lt;/li&gt;
&lt;li&gt;格式化结果返回&lt;/li&gt;
&lt;li&gt;代码结构合理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但它绝对不会主动考虑这些:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;业务需求&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;问卷50多页, 律师要30秒内出结果&lt;/li&gt;
&lt;li&gt;用户是律师, 一切都得有出处, 不能瞎编&lt;/li&gt;
&lt;li&gt;分析结果必须有确定性, 法庭上要靠得住&lt;/li&gt;
&lt;li&gt;按用量计费, 得严格追踪消耗&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;技术护栏&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;问卷得按章节分块, 不能随便拆&lt;/li&gt;
&lt;li&gt;得有流式输出, 不能让律师30秒看个空白&lt;/li&gt;
&lt;li&gt;需要缓存, 防止重复分析白烧钱&lt;/li&gt;
&lt;li&gt;LLM API偶尔抽风, 异常要兜底&lt;/li&gt;
&lt;li&gt;全链路审计, 合规要查&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;系统设计&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用同步还是异步? (异步, 30秒要求)&lt;/li&gt;
&lt;li&gt;LLM中途挂了怎么办? (幂等重试)&lt;/li&gt;
&lt;li&gt;LLM供应商限流咋办? (排队+背压)&lt;/li&gt;
&lt;li&gt;数据一致性怎么保证? (部分完成咋处理)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LLM能写”通路”, 但如果我不自己做工程设计, 梳理约束, 定架构, 那代码上线一秒钟就翻车。&lt;/p&gt;
&lt;h2 id=&quot;新的分工时代&quot;&gt;新的分工时代&lt;/h2&gt;
&lt;p&gt;这不是说LLM不行——它们太厉害了。但我们得搞清楚它们在干啥。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLM是超级程序员&lt;/strong&gt;: 给定明确需求和约束, 能写出一手好代码。会用模式, 能优化, 能调试, 能写文档。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;人类要做工程师&lt;/strong&gt;: 理解业务, 设计系统, 搭好护栏, 预判边界和异常。要问: “我们到底要解决什么?会出啥乱子?怎么扩展?”&lt;/p&gt;
&lt;p&gt;想开点: 繁琐的底层活可以丢给AI, 我们只用搞定”人性化需求, 系统设计, 架构取舍”这些有趣的活儿。&lt;/p&gt;
&lt;p&gt;但前提是: 你得先做工程师的活。如果只是”LLM, 给我造个X”, 不给上下文, 不提约束, 不画蓝图, 出来的就是只可远观的危楼。&lt;/p&gt;
&lt;h2 id=&quot;跟ai编程工具打交道的正确姿势&quot;&gt;跟AI编程工具打交道的正确姿势&lt;/h2&gt;
&lt;p&gt;我的经验:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;烂提示:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“给我写个SaaS的支付系统”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;优质提示:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“写个支付系统, 满足这些需求:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持按积分计费 (用户买积分, 功能扣积分)&lt;/li&gt;
&lt;li&gt;必须安全处理并发扣除 (两次API不能都扣成功, 积分只够一次)&lt;/li&gt;
&lt;li&gt;需要账单审计, 方便对账&lt;/li&gt;
&lt;li&gt;支付渠道挂了要优雅降级 (走缓存积分, 记录日志后续补算)&lt;/li&gt;
&lt;li&gt;性能要求: 每次扣积分延迟&amp;#x3C;50ms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数据库用PostgreSQL行级锁扣积分。操作需幂等, 重试不重复扣。全链路日志方便排查。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;第二种提示才是”工程师干的活”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务模型 (积分制)&lt;/li&gt;
&lt;li&gt;核心约束 (并发安全)&lt;/li&gt;
&lt;li&gt;合规要求 (审计)&lt;/li&gt;
&lt;li&gt;可靠性 (故障降级)&lt;/li&gt;
&lt;li&gt;性能指标 (延迟)&lt;/li&gt;
&lt;li&gt;技术方案 (PostgreSQL行锁)&lt;/li&gt;
&lt;li&gt;运维考虑 (可排查)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样, LLM才能写出上线无压力的代码, 因为你给了它”蓝图”。&lt;/p&gt;
&lt;h2 id=&quot;一点扎心的真相&quot;&gt;一点扎心的真相&lt;/h2&gt;
&lt;p&gt;很多老开发, 其实早就习惯了”脑中设计+手上实现”一条龙。每次写代码, 都是先做工程师, 再做程序员, 帽子换得飞快。&lt;/p&gt;
&lt;p&gt;但有了LLM, 编程部分AI包了。你如果不认真做工程师的活, 只会下”魔法提示”, 最后得到的, 是个只在demo里能用, 真环境就翻车的项目。&lt;/p&gt;
&lt;p&gt;扎心的是: &lt;strong&gt;很多自称工程师的, 其实只是程序员&lt;/strong&gt;。代码写得贼溜, 但从没真正搞过系统设计, 要么一直在实现别人的架构, 要么项目本身太小没啥复杂度。&lt;/p&gt;
&lt;p&gt;在LLM时代, 这个区别终于变得重要了。单纯的写代码技能正在被AI取代。真正有价值的是”工程思维”: 理解需求, 设计架构, 权衡取舍, 预判故障。&lt;/p&gt;
&lt;h2 id=&quot;该怎么进化你自己&quot;&gt;该怎么进化你自己&lt;/h2&gt;
&lt;p&gt;如果你正在学编程, 不要只学语法和框架。学会像工程师一样思考:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;写完功能, 问问: “一千个人同时用会咋样?”&lt;/li&gt;
&lt;li&gt;写代码前, 先想: “都有啥可能出错?每种情况该怎么兜底?”&lt;/li&gt;
&lt;li&gt;研究真实系统设计, 不要只看教科书里的小例子&lt;/li&gt;
&lt;li&gt;学会写别人能看懂, 能实现的详细需求说明&lt;/li&gt;
&lt;li&gt;不光要会”怎么做”, 更要懂”为什么这么做”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你已经在开发岗位, 注意分清自己干的是哪一头。只是对着规范写功能?那你就是程序员, 未来LLM会把这工作抢走。赶紧加强工程能力: 系统设计, 需求分析, 架构思维。&lt;/p&gt;
&lt;p&gt;如果你在面试招人, 别再考”能不能写FizzBuzz”, 改问”设计个URL短链系统, 能扛1000请求/秒, 故障咋办?”写代码的活儿越来越自动化了, 剩下的全靠脑子。&lt;/p&gt;
&lt;h2 id=&quot;最后的笑点&quot;&gt;最后的笑点&lt;/h2&gt;
&lt;p&gt;说个小秘密: 这篇文章, 其实是我和Claude合写的。不是我不会写, 而是Claude作为”写作程序员”比我还专业。我给它核心思路, 写作架构, 风格要求 (要有建筑比喻, 要举案例), 它写得比我快还顺。&lt;/p&gt;
&lt;p&gt;Claude写了优美的段落。但那些最关键的决定——讲什么, 怎么安排, 用什么例子, 读者能不能get到——全是”工程师”我来定的。&lt;/p&gt;
&lt;p&gt;未来的软件开发, 不会是”全自动无人区”。而是人类做擅长的事——理解复杂需求, 做取舍, 设计健壮系统;AI做擅长的事——把规范变成精美, 可靠的代码。&lt;/p&gt;
&lt;p&gt;但前提是: 你得记得自己是工程师。否则, 盖出来的, 还是那种没人敢住的高楼。&lt;/p&gt;
&lt;p&gt;这种故事, 咱都不想再听第二遍吧。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;你用AI编程工具踩过什么坑?你发现自己开始更多地思考工程问题, 还是还停留在”写个X就行”?欢迎留言分享——翻车现场往往比成功故事更有料!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(本文由人类原创, 部分内容参考AI协助优化。)&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate></item><item><title>12-Factor App: 用乐高积木思维打造云时代软件</title><link>https://shanechang.com/zh-cn/p/twelve-factor-app-lego-cloud-era/</link><guid isPermaLink="true">https://shanechang.com/zh-cn/p/twelve-factor-app-lego-cloud-era/</guid><description>&lt;img src=&quot;https://shanechang.com/_astro/cover.B0hq-9yw_Z1Q0puh.webp&quot; alt=&quot;Featured image of post 12-Factor App: 用乐高积木思维打造云时代软件&quot; /&gt;&lt;h2 id=&quot;开篇小剧场&quot;&gt;开篇小剧场&lt;/h2&gt;
&lt;p&gt;想象一下, 大半夜三点, 你的应用突然”爆红”, 访问量从100飙到10万。团队一半呼呼大睡, 另一半正在群里发疯。你的应用能像武林高手一样优雅应对, 还是一秒崩溃成渣?&lt;/p&gt;
&lt;p&gt;创业那会儿, 这种场景天天在我脑海飘——直到我偶然读到了12-Factor App方法论, 瞬间醍醐灌顶。从那之后我一直觉得, 我们这些后辈不过是在巨人的肩膀上眺望未来罢了。&lt;/p&gt;
&lt;p&gt;简单来说: **12-Factor App就像云时代的乐高积木。**你写的不是一个死板的”独立应用”, 而是一个随时可以拼装, 拆卸, 扩展, 迁移的模块。外部世界发生什么, 运行在哪, 怎么部署, 统统交给平台操心。你只专注做好自己的”积木”, 保证哪里需要就能安上, 怎么拼都顺滑——这才是真正的无限可扩展。&lt;/p&gt;
&lt;h2 id=&quot;三大支柱-拆解12-factor的架构思维&quot;&gt;三大支柱: 拆解12-Factor的架构思维&lt;/h2&gt;
&lt;p&gt;在灌输12条原则之前, 先给大家一个彩色脑图: 12-Factor App里, 所有事儿都能归到三大类:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;应用本身&lt;/strong&gt;: 核心逻辑, 无状态, 不可变&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接口&lt;/strong&gt;: 应用和外部世界沟通的桥梁&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平台&lt;/strong&gt;: 充当”调度大管家”, 决定一切如何运转&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你可以把应用想象成大厨。大厨 (应用) 有自己的绝活;厨房怎么布置, 食材从哪来, 菜端到哪去 (接口), 这些是厨房的活儿;而餐厅老板 (平台) 则决定哪个厨师上班, 雇多少人, 订单怎么分配。&lt;/p&gt;
&lt;p&gt;这种分工才是魔法的起点。下面我们一起来看看每个factor如何巩固这套体系。&lt;/p&gt;
&lt;h2 id=&quot;第一章-地基代码与依赖-先打牢&quot;&gt;第一章: 地基——代码与依赖, 先打牢&lt;/h2&gt;
&lt;h3 id=&quot;factor-1-唯一代码库-不再我这能跑&quot;&gt;Factor 1: 唯一代码库, 不再”我这能跑”&lt;/h3&gt;
&lt;p&gt;还记得那句”我这儿能跑啊!”吗?每次听到都想翻白眼。你花俩小时排查, 最后发现生产环境跑的是哪一版代码自己都说不清……&lt;/p&gt;
&lt;p&gt;12-Factor里, 代码库就像一张详细到每个房间门牌号的地图。X轴是版本, Y轴是部署环境。任何一份代码, 任何一个时刻都能精确定位。凌晨出事儿也不慌, 分分钟查出问题跑在哪。&lt;/p&gt;
&lt;p&gt;说来惭愧, 我大学时就盲目用github存代码 (以为这就是”云存储”), 后来和小伙伴协作才发现, 原来版本管理和踩地雷差不多, 踩错了就得挨一下。痛了才长记性。&lt;/p&gt;
&lt;h3 id=&quot;factor-23-依赖与配置把外部输入分清楚&quot;&gt;Factor 2&amp;#x26;3: 依赖与配置——把外部输入分清楚&lt;/h3&gt;
&lt;p&gt;这俩原则是一对”好基友”, 但各有分工。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;依赖&lt;/strong&gt;就像做菜的食材清单: Python包, Node模块, 系统库, 统统写清楚, 缺一不可。别再想着”环境里大概有吧”, 一切明明白白列出来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;配置&lt;/strong&gt;就像调音台上的旋钮。相同设备, 不同场合拧法不同。比如数据库地址, API密钥, 功能开关——这些会随环境变化, 但代码本身不变。&lt;/p&gt;
&lt;p&gt;关键点: **凡是部署时需要变的, 都是配置。**如果你现在把代码开源会把密码一起暴露, 说明配置和代码没分干净。&lt;/p&gt;
&lt;p&gt;我个人最喜欢的组合是Python的dotenv + dataclass: 简单, 好用, 又不失强大。&lt;/p&gt;
&lt;h3 id=&quot;factor-4-后端服务你的外挂资源&quot;&gt;Factor 4: 后端服务——你的”外挂资源”&lt;/h3&gt;
&lt;p&gt;数据库, 消息队列, 邮件服务……这些既是数据的入口, 也可能是出口。12-Factor的建议很简单: &lt;strong&gt;统统当作”外挂资源”看待。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你的应用不关心PostgreSQL是在本地, 机房, 还是云厂商的服务, 只要有个URL和凭证就行。这样哪天从自建数据库迁到云服务, 只是改个配置的事, 代码不用动。&lt;/p&gt;
&lt;p&gt;要命的事情从来不是代码写错, 而是新代码引入的新bug。哈哈, 谁懂谁痛。&lt;/p&gt;
&lt;h2 id=&quot;第二章-流水线从源码到上线-三步走&quot;&gt;第二章: 流水线——从源码到上线, 三步走&lt;/h2&gt;
&lt;h3 id=&quot;factor-5-构建-发布-运行三段式火箭&quot;&gt;Factor 5: 构建, 发布, 运行——三段式火箭&lt;/h3&gt;
&lt;p&gt;做面包的朋友有感触: 凌晨四点揉面 (构建), 九点开门前出炉一批 (发布), 白天顾客来买 (运行) 。小作坊能现做现卖, 但要是面包做砸了, 顾客就得等半天。要是提前批量做, 大家都开心。&lt;/p&gt;
&lt;p&gt;三阶段细拆:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;构建阶段&lt;/strong&gt;: 源码+依赖, 打包编译成可执行文件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发布阶段&lt;/strong&gt;: 上述产物+环境配置, 生成有编号的release&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行阶段&lt;/strong&gt;: 在生产环境部署并启动release&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个release都是”冻住”的快照, 既定构建+既定配置。v427出毛病?一秒回退到v426, 不用一边掉头发一边查diff。&lt;/p&gt;
&lt;p&gt;好处?构建阶段出错时开发还醒着, 运行阶段出事直接回滚, 不用凌晨三点生产上debug。&lt;/p&gt;
&lt;h3 id=&quot;factor-6-进程无状态-随时重启&quot;&gt;Factor 6: 进程——无状态, 随时”重启”&lt;/h3&gt;
&lt;p&gt;你的应用进程要像流水线上的工人, 手上不留活儿。数据要存?用数据库。临时缓存?上Redis。文件?丢S3。&lt;/p&gt;
&lt;p&gt;进程无状态, 就变得”可抛弃”。想启动, 想停止, 想扩容, 想宕掉都随意, 用户毫无察觉。说白了, 这才是真”自由身”。&lt;/p&gt;
&lt;h3 id=&quot;factor-7-端口绑定自带服务器的服务&quot;&gt;Factor 7: 端口绑定——自带”服务器”的服务&lt;/h3&gt;
&lt;p&gt;应用要自给自足, 通过端口对外暴露服务。别想着运行时再注入web服务器, 搞复杂容器。直接让你的Python应用带上Gunicorn, Ruby用Puma/Thin, Java打包Jetty。总之就是: 我监听5000端口, 想接入随时来。&lt;/p&gt;
&lt;p&gt;这样你的应用就像乐高积木, 今天是web服务, 明天可能就变成别的应用的后端资源。只要URL+端口, 怎么拼都行。&lt;/p&gt;
&lt;h2 id=&quot;第三章-运维野外生存的艺术&quot;&gt;第三章: 运维——野外生存的艺术&lt;/h2&gt;
&lt;h3 id=&quot;factor-8-并发横向扩容才王道&quot;&gt;Factor 8: 并发——横向扩容才王道&lt;/h3&gt;
&lt;p&gt;做本地应用时, 大家都想着多线程, 多连接池, 多event loop, 拼命榨干一台机器。12-Factor要你换思路: 应用保持简单, 一个进程搞定一件事, 真要抗压, 让平台多开几个进程。&lt;/p&gt;
&lt;p&gt;有点像开餐馆。传统思路是让一个厨师手脚更快, 炒更多锅, 12-Factor则是多雇厨师, 每人干好自己的活儿。要扩容?加人就行, 别把厨师累趴下。&lt;/p&gt;
&lt;h3 id=&quot;factor-9-可丢弃性秒启秒停-优雅下线&quot;&gt;Factor 9: 可丢弃性——秒启秒停, 优雅下线&lt;/h3&gt;
&lt;p&gt;你的进程要像凤凰, 随时准备”死而复生”。启动快, 关停要优雅 (做完手头活再退出) 。&lt;/p&gt;
&lt;p&gt;这种”生死看淡”的哲学, 才是现代部署的基石。滚动更新, 自动扩容, 自愈机制, 全靠进程说死就死, 说活就活。&lt;/p&gt;
&lt;h3 id=&quot;factor-10-开发-生产一致性缩小差距-别掉坑&quot;&gt;Factor 10: 开发-生产一致性——缩小差距, 别掉坑&lt;/h3&gt;
&lt;p&gt;老套路:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;时间差&lt;/strong&gt;: 代码今天写, 下个月上线&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人员差&lt;/strong&gt;: 开发写代码, 运维上线&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具差&lt;/strong&gt;: 本地用SQLite, 生产用PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;12-Factor的目标是: 这些差距都砍掉!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码写完几小时内上线&lt;/li&gt;
&lt;li&gt;开发亲自参与部署&lt;/li&gt;
&lt;li&gt;各环境用同一套后端服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;做多线程编程都知道mutex是防止”竞态条件”, 这里也是一样。你要把环境差距控制到最小, 才能保证每次上线都”有条不紊”, 而不是”天降bug”。&lt;/p&gt;
&lt;h2 id=&quot;第四章-可观测性日志与运维小黑屋&quot;&gt;第四章: 可观测性——日志与运维”小黑屋”&lt;/h2&gt;
&lt;h3 id=&quot;factor-11-日志专注输出-其他交给平台&quot;&gt;Factor 11: 日志——专注输出, 其他交给平台&lt;/h3&gt;
&lt;p&gt;日志该怎么写?就像写日记一样, 谁看不关心, 只管往stdout (标准输出) 里倒。&lt;/p&gt;
&lt;p&gt;一开始我也觉得这法子怪怪的, 后来发现真香!开发时日志直接出现在终端, 生产时平台负责收集, 转发, 分析, 爱存哪存哪, 爱送给谁送给谁, 应用本身完全不用操心。&lt;/p&gt;
&lt;p&gt;本质还是那句话: 应用只管”说”, 平台负责”听”。&lt;/p&gt;
&lt;h3 id=&quot;factor-12-一次性运维任务和应用同根同源&quot;&gt;Factor 12: 一次性运维任务——和应用同根同源&lt;/h3&gt;
&lt;p&gt;数据库迁移, 控制台调试, 数据修复脚本……这些运维任务必须在和正式应用一模一样的环境下跑。代码, 配置, 依赖都一致。&lt;/p&gt;
&lt;p&gt;为啥?因为最怕的是脚本在预发环境正常, 到线上就跪了。只要环境一致, “works on my machine”的锅就不会再甩来甩去了。&lt;/p&gt;
&lt;h2 id=&quot;终极启示-本质是契约精神&quot;&gt;终极启示: 本质是契约精神&lt;/h2&gt;
&lt;p&gt;其实12-Factor App的精髓从来不是那12条清单, 而是&lt;strong&gt;应用和平台之间的契约&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;应用承诺:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无状态, 可随时抛弃&lt;/li&gt;
&lt;li&gt;明确声明所有需求&lt;/li&gt;
&lt;li&gt;通过标准接口沟通&lt;/li&gt;
&lt;li&gt;日志只往stdout写&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;平台承诺:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供配置&lt;/li&gt;
&lt;li&gt;管理进程&lt;/li&gt;
&lt;li&gt;路由请求&lt;/li&gt;
&lt;li&gt;处理日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有了这份契约, 奇迹就发生了: 你的应用可以今天跑在Heroku, 明天跑在Kubernetes, 后天随便上什么新平台。用户量翻百倍也不怕, 代码一行不用改。就像乐高积木, 哪里需要就插哪里, 怎么拼都顺手, 这才是云时代软件的正确打开方式!&lt;/p&gt;</description><pubDate>Tue, 19 Aug 2025 00:00:00 GMT</pubDate></item></channel></rss>