ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI辅助编程:游击战与阵地战的战术选择与切换之道

AI辅助编程:游击战与阵地战的战术选择与切换之道

最近大半年,我在好几个团队里都看到同一种分裂:一部分人借助AI写代码的速度已经快到让人怀疑人生,一天能产出几百行甚至上千行,改起需求来像换衣服一样随意;另一部分人却越写越慢,先画架构图、再定接口、再写设计文档,一个接口可能就要磨上一周。两边经常互相看不懂,前者觉得后者是效率的敌人,后者觉得前者是在给生产环境埋地雷。

我把这两种状态分别叫作“游击战”和“阵地战”。这不是贬义,而是两种在AI时代都非常重要的编程范式。“游击战”强调小股力量、快速穿插、打了就跑,适合用AI去试探未知、验证假设、完成一次性任务;“阵地战”强调稳固防线、纵深配置、长期经营,适合用AI去维护复杂系统、治理历史包袱、支撑多年迭代的产品。问题的关键从来不是哪种打法更高级,而是什么时候用哪一种,以及如何在不互相打架的前提下让两种打法共存。这也是我这篇文章想讲清楚的事。无论你是刚入行的新手,还是带团队的技术负责人,只要你的日常已经离不开AI辅助编程,这篇文章都值得看完。

1. 我观察到的两种AI编码流派:一天能出几百行的人和一周只写一个接口的人

1.1 高效但难以收场的“游击式”开发

先说说第一种人。他们的典型画像是:打开编辑器,旁边挂着一个AI对话窗口,需求到手先不建工程,先让AI“给我一个能跑的Demo”。三十分钟后,Demo已经能在本地跑起来了,界面、接口、数据流全都有,虽然粗糙,但确实能点。

这种打法在外部看来极度高效。它背后的逻辑是:用AI的低边际成本对冲需求的高不确定性。传统开发里,需求从“模糊”到“清晰”要经历漫长的沟通、设计、评审,而这些环节恰恰是AI可以瞬间完成的——你只需要把模糊的描述变成提示词,AI就能帮你生成一个可交互的“靶子”,让业务方在这个靶子上继续校准需求。

但这种打法有一个致命的软肋:很难收场。Demo跑得越爽,积累的技术债就越隐蔽。没有模块划分,没有错误处理,没有测试,所有的逻辑全部堆在一个入口文件里,AI生成的代码像拼图一样互相咬合,改一处功能可能引发三处连锁崩溃。等到产品经理说“这个功能要上线”时,游击队员傻眼了——他手里拿的是一块陶土捏出来的模型,而不是一栋能住人的房子。

1.2 稳定但启动缓慢的“阵地式”开发

第二种人则完全相反。他们接手任何任务,第一反应不是写代码,而是问“这个功能属于哪个域”“上游依赖谁”“下游谁会消费我”“接口的兼容性怎么保证”。他们会花大量时间画时序图、定义数据模型、写接口文档,然后在框架的约束下慢慢填充实现。

这种打法的价值在长期维护中体现得淋漓尽致。代码库稳定,职责清晰,新人上手快,线上问题容易定位。但其代价也很明显:启动速度极慢。在业务方向还一片混沌的早期,阵地式开发很容易陷入“过度设计”——你花两周设计出来的架构,可能在下一次需求变更中就推倒重来。

更有意思的是,在AI辅助编程普及之后,阵地式开发者的处境反而变得更微妙了。他们发现自己精心设计的架构边界,在AI生成代码的“暴力美学”面前显得不堪一击——隔壁游击队员已经用AI把功能跑通了,自己还在画第三版流程图。这种反差会让阵地派产生自我怀疑:是不是我太守旧了?

1.3 为什么这个话题现在值得认真对待

我之所以想把这两种范式拎出来认真聊,是因为AI正在把编程活动的“两极分化”推向极端。以前,一个开发者的能力长板决定了他是偏探索还是偏工程,团队可以通过分工来互补。但现在,AI让“探索”的边际成本降到了几乎为零,任何一个普通开发者都可以在十分钟内完成过去需要一整天的探索性编码。

这带来一个全新的问题:当“试探成本”无限趋近于零时,试探的边界在哪里?如果所有团队都一股脑地选择游击战,代码库会变成一片无法维护的战场废墟;如果所有团队都死守阵地战,又会错失AI时代最大的效率红利。我认为,正确的心态不是二选一,而是把这两种范式看作两套可随时切换的“战术包”,根据任务的本质属性灵活调用。

2. “游击战”的核心逻辑:用AI当侦察兵,而不是把AI当工程队

2.1 游击战的三板斧:原型验证、一次性脚本、探索性重构

在我自己的实践中,AI辅助的游击战主要落在三种场景里,这三板斧用好了,效率提升是立竿见影的。

第一板斧是原型验证。比如团队想引入一个新的检索方案,与其花三天搭完整环境,不如把需求拆成提示词丢给AI,让它基于示例数据生成一个最小可用的检索Demo。如果效果不达标,整个投入也就是一个下午;如果效果达标,再决定要不要把Demo推倒重建。这种打法的核心是“先花小钱验证风险最大的技术点”,而不是把技术选型押注在文档和PPT上。

第二板斧是一次性脚本。数据迁移、日志清理、批量重命名、临时统计……这些任务的特点是“做完即弃”,不需要架构设计,不需要单元测试,只要结果正确。这类工作我几乎全部甩给AI,提示词写清楚输入输出和边界要求,生成后人工肉眼审一遍,跑完就删。

第三板斧是探索性重构。遇到一个完全陌生的代码库时,我会让AI先通读一遍目录结构,帮我梳理模块依赖和核心数据流。这一步看似简单,实际上能帮人节省大量通读源码的时间。你也可以直接提问:“这个项目中异常处理是怎么组织的?有没有统一的地方?给我列出所有抛异常的位置。”AI能快速给出一个待办清单,让你在全面重构前做到心里有数。

2.2 一套好用的游击式AI提示词打法

很多同学觉得AI生成代码“不可控”,生成的东西要么跑不动,要么不敢用。我自己的经验是,问题和AI没关系,是提问方式有问题。游击战场景下,我有一套固定句式:

帮我写一个Python脚本,读取某个目录下所有CSV文件,按文件名里的日期排序,合并输出成一个Parquet文件。脚本要能处理文件编码不一致的情况,遇到坏行打日志跳过。不需要类封装,直接函数式写法,注释少一点,关键步骤写清楚。

这段提示词里有几个关键要素:明确的目标、清晰的输入输出、边界条件(坏行)、风格约束(函数式、注释少)、细节约束(编码)。如果你只说“给我写个合并文件的脚本”,AI给出的代码大概率覆盖不了真实世界的复杂度。

迭代也很重要。AI生成第一版后,我通常不会直接拿去用,而是继续追问:“如果某个文件只有一行,你的代码会怎么处理?”“这里如果内存爆了怎么办?”这种追问式迭代是游击战的精髓——它不是让AI一次性交付一个完美方案,而是让AI充当一个反应迅速的侦察兵,用几轮对话把问题边界摸透。

2.3 游击战红线:哪些代码绝对不能只打游击

游击战好用的前提是“懂边界”。我给自己定了几条红线,踩线的代码无论AI生成得多么丝滑,我都不会让它留在项目里:

  • 不能进入主干分支。游击战产出的代码只能在独立分支、实验目录或者本地环境横跳,绝不能直接合入主干。
  • 不能碰真实业务数据。所有的验证都要用样例数据或者沙盒环境,一旦涉及生产环境的数据读写,就必须切换打法。
  • 不能改变对外接口。API签名、消息结构、数据库表结构,任何一行相关改动都不允许由游击战产出。
  • 生命周期不能超过一天。今天生成的探索性代码,要么在当天内被清理,要么转成交付级代码,不允许拖到第二天还躺在工作区里。

这四条红线听起来简单,实际执行起来很容易破功。因为AI生成的代码“看起来太正常了”,人会下意识地降低防备心,一不留神就把它当成了生产代码。所以我现在的习惯是,游击战代码统一在文件头加一个experimental注释,并配套一个定时清理计划。

3. “阵地战”的本质:把AI改代码的成本变成可计算的确定性

3.1 阵地战不是拒绝AI,而是给AI划定作战半径

很多阵地派在AI时代感到焦虑,觉得“架构设计会被AI取代”。我的观点恰恰相反:AI越强,架构设计的价值越大。游击战的本质是用低成本的试探去换取高密度的信息;而阵地战的本质,是把这些试探获得的“战果”固化成一整套确定性系统。

但阵地战绝不是“不用AI”。恰恰相反,我认为阵地战更需要AI,只是AI的角色从“侦察兵”变成了“工程队”——它不是去开路,而是在你画好的图纸上施工。具体来说,阵地战的AI使用方式是在明确的架构边界内,生成符合规范的实现代码。

举一个最简单的例子。假设我们在做一个支付系统,核心的金额计算逻辑、状态机转换、幂等控制这三类代码,无论AI怎么建议,我都要求手写并经过严格评审。但是周边的DTO定义、数据库访问层的基础CRUD、单元测试模板、配置文件,这些机械化程度高的代码,完全可以交给AI批量生成。问题不在于“用不用AI”,而在于“AI改的是哪一块”。

我在某团队推行过一个“作战半径”制度,用一个文件把项目里的模块分成三类:

  • 红区:核心业务逻辑,AI只能提建议,不能直接生成代码。
  • 黄区:通用基础设施,AI可以生成初稿,但必须经过架构师评审。
  • 绿区:样板式代码,AI全权生成,人工只做抽查。

这个制度推行之前,团队对AI的态度两极分化严重;推行之后,两边终于找到了共识:AI不是洪水猛兽,也不是万能许愿机,它是一支需要被指定战场的工程队。

3.2 阵地战必备的四个作战工事

确定了AI的使用边界之后,要想让阵地战真正稳固,还需要几样“工事”来保证AI生成的代码不会悄悄越界。我自己最常用的有四个:

第一是架构约束测试。这类测试不是验证业务功能,而是验证代码结构。比如“Controller层不得直接操作数据库”“Service层必须经过领域层接口”,这些规则可以直接写成单元测试,AI生成的代码无论如何飞舞,只要测试跑不过,就合不进主干。这比任何代码评审都硬核。

第二是契约测试。对于任何对外暴露的接口,都要求保留契约测试,确保接口签名和数据结构的变更会被显式捕获。AI在“黄区”里折腾实现细节时,契约测试像一条看不见的警戒线,防止它无意中破坏了API兼容性。

第三是全自动的规范检查。格式化、lint、类型检查、复杂度检查,全部接入CI流水线,不让任何“带病”的代码进入评审环节。AI擅长生成“看似规范”的代码,但很多隐患隐藏在命名风格不一致、魔法数字散落、函数过长这些细节里,自动化检查是兜底。

第四是一套针对AI生成代码的人工检查清单。这个清单很朴素:是否处理了异常?是否记录了日志?是否设置了超时?是否有并发隐患?是否硬编码了配置?每次评审AI生成代码时,评审人必须逐项打勾。别嫌它麻烦,AI生成的代码在“平均分”上很高,真正会咬人的往往是那些平均分掩盖下的极端角落。

3.3 一张表看清两种打法的成本结构差异

很多人纠结“该用哪种打法”,本质上是因为没有把成本结构看清楚。我用一组对比来辅助判断:

对比维度游击战阵地战
启动成本极低,一个提示词即可较高,需要设计边界与文档
信息反馈速度高,分钟级低,可能要以天计
变更灵活性高,随时推翻重来低,变更需要评估影响面
长期维护成本高,代码质量靠运气低,结构清晰可控
风险分布集中在上线前的收尾阶段分散在设计过程中的每个决策
核心武器AI的即时生成能力人的架构判断与纪律
适合的任务生命周期小时级到周级月级到年级

这张表告诉我们,两种打法的成本结构恰好互补:游击战前便宜后贵,阵地战前贵后便宜。聪明的做法不是死守一种,而是在不同生命周期阶段,主动把代码从一种打法“移交”给另一种打法。

4. 选择打法的判据:变更半径、存活周期与依赖深度

4.1 四个核心判据

那怎么判断眼前这个任务到底该用游击战还是阵地战?我总结了四个判据,每次动手前先过一遍,能省下大量对应付错打法的后悔时间。

判据一:变更频率。这个功能未来三个月会被频繁改动吗?如果答案是“会”,请直接选择阵地战。因为高变更频率意味着每一次改动都要重新理解代码、重新评估影响面,游击战产出的代码在这种场景下会迅速劣化为看不懂的泥潭。反之,如果这个功能做完就定型了,游击战完全够用。

判据二:存活周期。这段代码是要跑一次就丢,还是要在生产环境里活很多年?一次性脚本天然适合游击战;核心业务模型天然需要阵地战。最危险的是一些“四不像”任务——看起来是一次性的,做完之后却被反复复用,这种时候要尽早主动转入阵地战。

判据三:副作用范围。改动会波及多少其他模块?如果只触及一个函数内部,游击战没问题;如果涉及数据库结构、消息队列、对外接口、分布式事务,这些全局副作用会让游击战的低质量成本无限放大,必须阵地战。

判据四:可测试性。代码的正确性能否在短时间内被自动化验证?如果可以用单测快速覆盖,头铁一点打游击也没关系;但如果逻辑要在复杂的分布式环境里才能验证,没有完备的设计和测试,直接上会极其危险。

4.2 从判据到决策:三个典型场景推演

只看理论容易晕,我拿三个真实场景做过拆解,方便你直接套用。

场景A是“给内部数据平台加一个CSV导出功能”。判据走一遍:变更频率中低,存活周期中(内部工具能用挺久),副作用范围小(只涉及一个接口和查询逻辑),可测试性中等。结论:游击战为主,但做一点轻量的参数校验和日志,收敛好边界,就可以交出去。

场景B是“电商核心订单模块的支付超时处理”。变更频率高,存活周期长,副作用范围极大(涉及订单状态、库存、支付流程、对账),可测试性复杂。结论:必须阵地战。这种模块连AI的单行建议都要经过严格讨论,更不可能允许AI整段生成。

场景C是“清历史遗留的技术债”。这类任务比较微妙:探索阶段需要对存量代码做大量信息收集,这明显是游击战的强项;但重构阶段一旦形成方案,就要立刻切换成阵地战。我看到的案例中,凡是“一边探索一边顺手改”的,基本都翻车了——因为探索期的战术动作和人说了算,极容易越改越乱。

4.3 团队规模如何影响打法选择

除了任务本身的属性,团队规模也会影响打法权重。一两百人的团队,代码库庞大、人员流动率高,阵地战的比例应该显著高于游击战——因为代码的“可交接性”重于“冲刺速度”。三人小团队做内部工具,则可以大胆偏向游击战,快速试错的价值远超架构优雅性。

还要注意一个很多人会忽略的变量:团队里AI使用能力的分布。如果大部分成员能熟练驾驭AI,阵地战和游击战的切换就能更平滑;如果只有少数人在用AI,其他人还在传统模式,那么过度偏向前者会制造巨大的认知落差。我发现最稳妥的做法是,先让团队在小范围内跑通“游击转阵地”的完整流程,再逐步扩大AI应用的范围。

5. 实战组合拳:游击开路、阵地收编的完整流程

5.1 一个中型模块的完整作战记录

光讲理论没有说服力,我复盘一个自己做过的实际模块,让大家看看两种打法怎么在同一个项目里无缝衔接。

这个模块是某企业内部数据分析平台的“指标自定义计算”,业务方提出了新需求,我们希望支持用户通过一个表达式引擎,在界面上自定义新的统计指标。这个需求方向明确,但表达式的语法、优先级、性能特性全都不明朗,直接上阵地战设计架构风险很大。

第一步,游击战原型验证。我先让AI基于一个简化版的表达式解析器生成原型,目标是支持“加法、减法、乘法、除法、括号”五种能力,并且跑通一组性能测试。AI大概花了二十分钟生成了初版,我在本地跑了一遍,发现解析器的性能在表达式层级嵌套过深时会指数级劣化。这个信息非常关键,直接决定了后续架构选型:必须限制表达式深度,并引入预编译方案。

第二步,原型隔离。我把这版原型连同测试数据全部放到experiments/expression-engine目录下,在README里写清楚“这是一个探索性原型,2024年某月某日之前必须转正或被删除”。这个目录被明确排除在CI之外,任何人都能拉下来跑,但任何人都不能把它当库引用。

第三步,启动阵地战。基于原型验证的结论,我画出了目标架构:一个分层的表达式编译模块,包括解析层、AST变换层、字节码生成层、运行时层。然后把接口契约写死:词法器输入字符串、输出Token流;解析器输入Token流、输出AST;编译模块输入AST、输出可执行对象。边界定了之后,AI的活就来了。

第四步,让AI在边界内干活。我让AI分别生成两个Token类型的定义、AST节点的lambda访问器、一个基础的常量折叠优化器。这些任务各自独立、边界清晰,AI生成的代码经过单元测试和代码评审后并入主线。真正的核心部分——表达式求值器——我手写,并且配了超过60个边界测试。

第五步,契约与架构测试收编。模块完成后,我补上了契约测试和架构约束测试,明确禁止后续任何人绕过Compiler接口直接调用Parser内部方法。这一步做完,这个模块才算从“游击队的顺手杰作”正式变成了“阵地里的固定工事”。

5.2 转换时机的信号与动作

这次经历让我总结出了几个“该从游击转阵地”的明确信号。只要出现任意一条,就不要再犹豫,立刻启动转换流程。

  • 原型的某个函数开始被第二个功能复用。当一个代码片段从“验证假设”变成“被依赖的公共能力”时,它就已经不是原型了,它在事实上已经进入了生产系统的范畴。
  • 原型逻辑开始被复制粘贴到其他文件。复制粘贴是代码腐烂的起点,如果这种情况发生,说明原型的抽象边界已经撑不住了。
  • 修改一个功能需要同步改动三个以上文件。这意味着改动成本已经超过了重新设计的成本,原地修补只会继续叠加复杂度。
  • 其他同事开始问“这段代码是干嘛的”。这标志着代码的可读性已经无法支撑团队协作。

一旦决定转换,我的固定动作是:建新目录、写设计文档、定义接口、把原有代码切成碎片、在边界内重新组装。这个过程的纪律要求很高,因为AI可以在十分钟内帮你“平滑迁移”,但那样迁移之后代码仍然是一团浆糊。正确姿势是“先破坏,再重建”,虽然阵痛,但转换完成后的稳定性是值得的。

5.3 让AI同时服务两种打法的协作规范

同一个项目里两种打法共存,最怕的就是互相污染。我设计过一套很朴素的协作规范,如今已经在团队里跑顺了。

代码库的目录结构从顶层就按“作战区域”划分:experiments/目录专门放游击战产物,默认不合并、不参与部署;core/目录是红区,任何进入这里的AI生成代码都需要架构师显式批准;infra/目录是黄区和绿区,AI可以批量生成,但提交时必须附带自测结果。

其次,所有涉及AI生成的PR,标题都会有统一前缀[AI-gen],方便评审人第一时间知道这坨代码是“机器施工”的,需要额外关注风格与逻辑一致性。《AI生成代码审查清单》挂在PR模板里,评审人必须逐项勾选。

这两个约定看起来不起眼,但极大地降低了团队协作时的认知负担。游击队员知道自己的玩具不会被误当成生产代码,阵地队员知道自己的核心模块不会漂移,AI工具也能在清晰的战区内发挥最大价值。

6. 我在切换打法中踩过的坑:三种最容易翻车的打法错配

6.1 把阵地战打成游击战:架构重构随手交给AI

第一次严重翻车事故发生在一次核心流程重构上。当时我负责梳理一个老系统的订单状态转换流程,旧代码里嵌套了大量if-else,逻辑分支多到人脑无法梳理。我当时的想法很天真:“让AI帮我把它重构成状态机模式,效率肯定高。”于是我把整个文件丢给AI,要求生成新版状态机代码。

AI很快就生成了看起来异常工整的状态机实现,测试也跑通了,我信心满满地提交。结果上线第二周就出了事故:一个极老的订单在某种边缘时序下走入了错误的转换分支,导致订单状态从“已完成”倒退回“待支付”。排查了一整天才发现,AI在重构时“自作聪明”地合并了两个语义不同的状态,因为它们在代码层面看起来过于相似。

这次事故让我彻底明白了:状态机、并发控制、金额计算这类“魔鬼在细节里”的领域,不管AI如何自信,都必须打阵地战。重构这类高危模块,正确做法是先把状态转移矩阵手工画出来,让AI只负责填充无关紧要的分支逻辑,核心矩阵必须由人来敲定。

6.2 把游击战打成阵地战:原型代码被直接推进生产

另一类翻车是反过来:原型代码被“顺手”推上了生产。当时团队里有个A同学,习惯让AI生成工具脚本。有一次他写了一个配置解析脚本,本意是临时用一下,结果这个脚本被集成到一个自动化部署流程里,还因为“跑得没问题”而上了生产。

三个月后,这个脚本的缺陷集中爆发了:没有处理配置文件编码的兼容性、没有打印日志、错误处理直接吞异常。最要命的是,它硬编码了一个临时目录路径,上线后一换环境就报错。A同学自己都忘了这段代码是怎么写的了,因为AI生成后他就没细看。最后整整花了两天去回溯所有历史提交,才把这段“僵尸代码”从部署流水线里挖出来。

这个案例的教训是:原型代码进入生产必须走一次“脱胎换骨”的过程,而不是“包一层壳”。你可以在原型上快速验证假设,但验证完之后,必须重新按照阵地战标准重写一遍——哪怕AI告诉你“可以直接用”,也要人为制造一次“推倒重来”的仪式感。这不是流程繁文缛节,而是给那些草率的生成代码一个官方的“审查刑场”。

6.3 两种打法互相污染:团队里没有明确的边界共识

最后一类翻车最隐蔽,属于“慢性病”。团队一开始没有明确的区域划分,AI生成代码满天飞,一开始看没毛病,代码量上去了之后,问题开始呈现:有的目录写着核心服务,里面的代码却是AI现场生成的“野路子”;有的实验脚本被其他模块当成依赖引入,一删就牵连爆炸。

我接手过一次这样的烂摊子,花了两个迭代才把代码库结构重新理顺。后来推行了作战区域划分和PR标签约定,情况才逐步好转。现在回看,最根本的问题不在代码,而在于团队没有就“什么代码可以被AI随意生成”达成共识。有人觉得AI写的能跑就行,有人觉得“我的模块必须全手写”,两边互相扯皮,最终形成了一片灰色地带。

如果你也发现自己所在的项目出现了“AI生成的代码密度过高且没有人说得清责任边界”,那就是需要在团队层面定规矩的信号。这个规矩不是限制AI,恰恰是为了让AI能在有边界的地方跑得更快——就像阵地战的价值不是拒绝敌军的冲锋,而是让我军的防线能承受住更猛烈的攻击。

我在实际切换打法的时候,最深的体会是:两种打法并不是非此即彼的阵营,而是同一张作战地图上的不同战术状态。真正成熟的团队,不是分成“游击队”和“阵地派”两拨人,而是能够让同一个人、在同一个项目里,上午用游击战验证一个接口的可行性,下午用阵地战把它固化到可维护的架构里。AI时代给我们的不是一套更省事的编程方式,而是一种更频繁地在两种范式之间切换的能力。这种能力本身,才是这个时代稀缺的方法论资产。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进