我最近半年有一个很明显的感受:以前我做工程,是打开IDE就开始劈里啪啦写代码;现在我做工程,第一件事反而是打开AI助手,描述需求、贴出报错、让它生成一段改动。工具变了很多,但有一件事一直让我难受——AI生成的代码经常跟我的项目格格不入,它看不懂我项目的结构,也摸不清我的代码风格,很多时候我反而要花双倍时间给它擦屁股。直到有一次,我让AI帮我重构一个老模块,它完全无视了项目里已有的工具函数,自己另起炉灶写了一套风格迥异的实现,那一刻我意识到:问题不在AI,在我的项目对AI太不友好了。
于是我花了大概两个月时间,系统性地探索了“AI友好型工程”这件事。它不是多写几句提示词,也不是把所有代码都甩给AI,而是一整套让AI能够像人类同事一样理解代码库、参与开发流程、并且可以被测试衡量的工程实践。这篇文章就是我这段探索过程的完整记录,包括我在代码库结构、Agent工作流、测试体系和工具链上的具体改动,也有一些翻车现场。适合那些天天用AI写代码但又总觉得别扭的人,以及正在评估要不要让AI Agent进入正式项目的工程团队。
1. 什么是AI友好型工程:别再让AI读天书
1.1 从“人能看懂”到“AI能看懂”
传统软件工程的所有规范,本质上都在服务一个目标:让人更容易读懂代码。命名要有语义、函数要短、注释要解释为什么、架构要分层。这些规则在过去二十年里被反复验证,但它们默认的读者是“人类工程师”。
但今天代码的读者变了。除了人之外,还有一堆大模型在阅读你的仓库:代码补全插件要读你当前文件, Codex 和 Copilot 这类工具要读整个项目才能回答问题,你自建的Agent要读文档才能执行任务。AI没有你脑中的上下文,它只能从仓库里的文本推断出这个项目在干什么、有哪些约定、哪些东西不能动。如果仓库本身写得模棱两可、强依赖隐式知识,AI就会疯狂猜,然后猜错。
AI友好型工程,就是主动把项目仓库改造成“AI可推断”的状态。它不是一个独立的技术栈,也不是某种新框架,而是一组叠加在现有工程实践之上的额外规范:让结构更显式、让依赖更可见、让规则变成机器可读的文本。
1.2 我现在判断一个项目AI友好度的三把尺
在探索过程中,我总结出三个比较实用的判断标准。它们都能量化,适合团队用来评估一个仓库是否已经准备好接受AI协作。
第一把尺:一个完全不了解这个项目的AI,能不能在30分钟内定位到一个指定bug。我会随便写一个bug描述,比如“登录后用户头像不刷新”,然后看AI能不能依靠代码搜索和仓库结构找到出错的文件。如果AI总是被带到无关的地方,说明项目的领域边界不清晰。
第二把尺:AI生成的代码和现有代码的融合度。我让AI修改一个函数或新增一个模块,然后看它产出是不是遵循了项目已有的模式:它有没有引用项目里的工具函数?有没有按照目录约定放文件?还是又自创了一套写法?融合度差的项目,说明没有给AI提供足够的“模式参照物”。
第三把尺:AI改动能被自动化测试捕捉的比例。我故意让AI做一次有风险的重构,然后看现有测试能不能兜住它引入的问题。如果测试覆盖率低、断言颗粒度粗,AI犯的错就会跑到生产环境里。这三把尺里,第三把最容易被忽视,但也最致命。
有了这三把尺,我就能在动手改造前先给项目打个分,然后针对性地处理。下面我讲讲具体怎么改。
2. 让AI听懂你的代码库:五个立竿见影的改造动作
2.1 依赖与入口:AI最容易迷路的地方
我踩过最惨的一个坑,是让AI分析一个老旧的PHP项目。那个项目没有composer,没有统一的入口文件,数据库连接靠全局变量,配置散落在十几个文件里。AI试了几次都无法判断数据从哪里来,最后给出的方案完全是凭空想象的。后来我花了半天时间只做了一件事:写了一个README.md,把项目启动方式、目录说明、配置位置、常用命令全部写清楚。效果立竿见影,AI的准确率立刻上来了。
这件事给我的启发是:AI读项目的路径和人一样,通常从入口开始。README就是它的第一站。如果你的README只有一句话,或者连启动命令都不完整,AI就只能去猜。对AI友好的项目,先把依赖声明和入口说清楚:
- 使用标准的依赖管理文件,
package.json、pyproject.toml、go.mod,并保证install和run命令真实可用。 - 在
README开头用三句话说明项目是干什么的、技术栈是什么、如何本地启动。 - 把环境变量和配置项集中在一个文件,并在文档里列出每个配置的含义和示例值。
- 所有脚本命令(build、test、deploy)统一放在
Makefile或package.json scripts里,AI通过执行命令来验证它的改动,比纯靠读代码强得多。
这里有个反直觉的点:很多人担心README写得太详细会增加维护成本,但实际上AI能帮你维护——只要它上下文里有这份文档,它改代码时就倾向于同步更新文档,反而形成了正向循环。
2.2 命名与结构:给AI铺一条显式路径
代码命名这件事,对AI的影响比对人大得多。人看代码还能靠IDE跳转、调试器追踪,但AI通常只能靠文本相关性来理解语义。如果变量叫data1、temp、list,AI完全无法推测它代表什么,生成的代码里也会充斥着这种无意义命名。我见过一个项目,过量用了data这个词,最后AI的补全结果里全是DataContainer、DataManager、DataUtil,看得人头皮发麻。
改造时我遵循一个朴素的规则:从AI视角审视每个名字,看它是否传达了“我在这个系统中的角色”。具体做法是:
- 类名和函数名采用“做什么”而非“是什么”。
handleOrderPayment比OrderHandler更友好。 - 布尔变量用
is*、has*、can*前缀,让AI一眼知道取值。 - 目录结构按业务域组织,不按技术类型组织。
/services/payment/比/services/加/models/加/utils/更容易让AI定位。 - 保持模块接口小而清晰。如果AI只需了解五个函数就能改好一个模块,它会比面对二十个纠缠不清的函数可靠得多。
结构上还有一个容易被忽略的点:重复代码。如果一个逻辑在三个地方各写一遍,AI无法确定改哪一处才是“正确”的,它可能会全部改,也可能只改一处。公共逻辑抽出来,AI就不用做选择题了。
2.3 注释与文档:写给人看的,也要写给模型看
我过去很信奉“好代码不需要注释”这句话,直到发现AI读我的代码时频繁猜错。打个比方:你让一个新人维护一段代码,让他通过读代码看出“这个函数为什么返回负数”是可能的,但对AI来说,它只能看出返回值被取反了,看不出背后的业务原因。注释的真正价值是给AI提供它无法从代码本身推断出的背景约束。
具体做法上,我不要求团队写一堆文档,只需要在三个地方做补充:
- 文件头写一段“此模块职责与边界”,特别是这种模块与其他系统的关系。
- 复杂函数只注释“为什么这么做”,不注释“做什么”,前一个AI猜不到,后一个它自己能看。
- 项目级文档
docs/architecture.md里画一张纯文本的模块关系图,写清楚数据流向。AI特别擅长读这种结构化文本,比看图强得多。
这里有个技巧我在后面还会提到:单独为AI写一份ai_context.md文件,把项目里那些“隐形规则”写进去,比如“所有数据库时间使用UTC”“错误码需要先注册再使用”。这些规则写进代码注释会很啰嗦,但写在独立文件里,AI就能作为上下文直接引用。
2.4 上下文压缩:控制token成本的核心技巧
大模型读代码不是免费的,上下文越长,成本越高、响应越慢、准确率还可能下降。很多团队在试点AI时,发现AI经常在一个超大仓库里迷失,根本问题就是上下文管理失控。
我的做法是引入“检索式上下文”而不是“全量上下文”。AI只读取它当前任务需要的片段,而不是整个仓库都在prompt里。具体工具上,我用过多种,最实用的是在仓库里维护一个ai_context.md作为索引文件,里面按模块列出“要改这个模块,先看哪个文件、避开哪些坑”。AI在执行任务时,先读索引,再根据索引按需读取文件。这个思路和我们记忆里“先查目录再翻页”一模一样,token消耗能降一个数量级。
除了索引,还有两个小技巧:一是把代码库按模块拆小,确保单个文件尽量不超过300行,这样AI一次扫描就能吃透;二是把大型配置数据(比如超长JSON)抽成独立资源文件,不要在代码里内嵌太长的字面量。上下文越干净,AI的回答越稳。
2.5 从一次重构看AI行为变化
把前面几个动作做完之后,我拿一个真实项目做了一次对比。改造前,AI在修复同一个bug时生成的代码跟项目风格完全脱节,甚至自己 import 了一个项目里根本不存在的库。改造后,同一个AI(模型版本没变)在同样的需求下,生成的代码能自动使用项目里的工具函数、按照services/payment/结构放置文件、并在PR描述里引用了我要求的issue编号。这种改变不是因为AI变聪明了,而是因为项目的“可推断性”变高了。
有一点需要提醒:AI友好化改造本身也有成本,不要一上来就重构全部历史代码。我的策略是“新人友好区”优先——选择团队最活跃、改动最频繁的几个模块做改造,让AI在这些区域发挥价值,然后再逐步扩散。没人动的老代码,AI也基本不会去碰,没必要花精力。
3. 把AI从问答工具变成工程执行者:Agent工作流实战
3.1 提示词工程的边界:它解决不了结构化问题
很多团队刚接触AI时,把全部希望寄托在提示词上,觉得“提示词写得好,AI就能干活”。提示词确实能让单次任务的效果变好,但它有两个硬边界。
第一个边界是上下文限制。一个Agent要完成“修复bug + 写测试 + 更新文档”,需要调用多个工具、读取多个文件,这些中间状态拼在一起很容易超过模型窗口。第二个边界是流程控制。提示词本身没有“重试”“校验”“回滚”的概念,你无法靠一段话让AI在执行到第三步失败时自动回到第二步。
所以Agent工程化的第一步,是接受一个现实:大模型只是整个执行链路里的一个计算节点,真正可靠的执行需要围绕它搭建流程骨架。这个骨架包含任务拆解、工具调用、结果验证、失败重试四层。
3.2 本地函数调用与Agent工作流设计
我在实际项目里试过两种Agent模式。一种是最轻量的:让AI作为代码助手,人负责拆任务,AI负责执行单个步骤。另一种是自主Agent:定义好目标和工具,AI自己决定先做什么后做什么。前者我目前用得很稳,后者复杂很多,需要小心设计。
轻量模式下,函数调用(Function Calling)是关键。我不让AI直接改文件、跑命令,而是给它暴露一组白名单函数:read_file、edit_file、run_test、search_symbol。每个函数都带清晰的参数说明和限制。这样AI的所有操作都可以被记录、被审计,而且出错时可以在单步回滚。
自主Agent就复杂了。我目前采用“计划-执行-校验”三步循环:
- AI收到任务后,先输出一个结构化计划,说明它打算调用哪些工具、期望得到什么结果。
- 执行阶段按计划逐步调用函数,过程中如果发现计划有偏差,需要说明原因。
- 最后必须运行校验脚本(比如构建和测试),校验通过才算执行成功。
这套流程看起来像传统CI,但有一个区别:AI的每一步决策都是概率性的,所以计划里必须包含“不确定性检查点”——如果某个函数返回的异常信息AI无法理解,它应该停下来问人,而不是硬着头皮继续。
3.3 AI Agent扛并发:任务队列是必须品
“AI Agent怎么扛并发”这个问题,我一开始天真地以为就是开多线程。实测下来发现,真正的瓶颈不在算力,而在状态管理。
一个Agent任务通常要执行几十步,每一步都可能失败或需要重试。如果并发执行,就必须管理每步的状态,否则两个任务会互相踩踏——A任务改了一个文件,B任务又改了同一文件,结果谁都不知道最终版本是什么。最简单可靠的方案是把任务做成“可重入的队列”:任务提交到队列,由执行器逐个处理;每个任务内部步骤可以并发(比如并行跑测试),但任务之间的写操作必须串行化。
我在实践中用Redis做任务队列,用产品化的Agent框架处理内部步骤,整体结构类似queue -> worker -> agent -> tool。任务状态机包含pending、running、blocked、done、failed五种状态。这里最容易偷懒省略的是blocked状态:当Agent需要人工确认时,必须能让任务挂起并等待,而不是AIIO自动化重试。没有blocked状态的Agent系统,在真实场景里一定会因为误解需求而走偏。
3.4 多AI协作:不同模型各司其职
既然每个模型各有长处,那让一个模型从头干到尾其实不是最优解。我最近在尝试“多AI协作”的架构,目前效果还不错的是三模型分工:生成模型、审查模型、测试模型。
生成模型负责写代码,优先看生成速度和风格适配;审查模型只做CodeReview,它的提示词被设定成“找茬模式”,只看潜在bug和边界问题,不给详细修改建议;测试模型则自己阅读代码和需求,生成测试用例并运行,判断覆盖率是否足够。这就像团队里的开发、评审、测试各司其职,每个模型的角色都极度聚焦,反而比一个全能模型处理全部任务要更稳定。
多AI协作的关键是它们之间的通信格式要严格。我让它们统一使用结构化JSON协议,{意图, 文件路径, 建议, 严重程度}。生成模型输出的代码、审查模型的意见都走这个协议,这样可以避免一个模型的自然语言输出直接污染另一个模型的上下文。当前阶段我不建议让多个Agent自由对话完成任务,容易出现不可控的偏航,至少在我这里,结构化协议更可靠。
4. 面向AI的测试与质量保障:别让模型裸奔上线
4.1 传统测试覆盖不了AI的“随机性”
如果你用过AI写代码,你肯定遇到过这种情况:同样一个prompt,这次生成的代码能用,下次生成的却有个隐蔽的边界问题。这就是概率性模型的本质——它的输出不是确定的。传统测试建立在“代码行为是确定性”的假设上,所以当AI作为代码生成器被接入工程流程时,我们不能完全用老办法保障质量。
我的思路是把AI当成团队里一个能力很强、但偶尔会犯蠢的新人。传统的单元测试和集成测试必须保留,这是底线。但除此之外,还要增加一套面向AI行为的测试体系,重点覆盖三个风险点:
- 生成结果的稳定性(同一需求多次生成,核心逻辑是否一致)。
- 代码风格和API约定的一致性。
- 对边界条件的覆盖是否完整,AI很容易“忘记”处理空值、超时、并发冲突这类情况。
4.2 黄金样本集:AI回归测试的压舱石
我建立了一个“黄金样本集”,大概三四十个有代表性的任务描述,覆盖项目里的核心功能。每次我更换模型版本、修改系统提示词,或者调整代码库结构之后,都会把这套样本集跑一遍,对比AI生成结果的质量。质量评估不只看能不能运行,还要看是否符合项目规范、测试是否通过、有没有引入新的依赖。
这里有个实践细节:黄金样本集的任务描述要尽量贴近真实业务,不要为了测试而编造过度简化的需求。比如我问“增加一个优惠券过期提醒功能”,比“写一个定时器”更能暴露AI对项目上下文的理解程度。每次跑完样本集,我会把原始生成结果存下来,作为下个版本对比的基线。这样当AI行为“变好”或“变差”时,我能说出具体是哪个改动引起的,而不是凭感觉。
样本集数量不必多,关键在于覆盖面。我通常会涵盖:新增一个小模块、修改已有函数、重构不改变行为、修复带复现步骤的bug、写单元测试、更新文档。六类各几条就够了。
4.3 可观测性:记录AI的每一步决策
AI进生产环境之后,最怕的不是它出错,而是出了错你不知道它是怎么走到那一步的。人写的代码还有日志可以看,AI生成的代码如果不做观测,那排查问题就像在黑箱里抓盲鱼。
我给Agent执行链路加了三个维度的日志:
- Prompt日志:记录每次调用模型的完整输入,包括系统提示词、用户输入、注入的上下文文件。
- 行为日志:记录Agent调用了哪些工具、传了什么参数、返回了什么结果。
- 结果日志:记录最终产出的代码、测试结果、以及对比基线的差异。
这三个日志配合起来,基本能还原AI每一步的决策过程。有一次一个Agent错误地修改了数据库连接池配置,我靠行为日志很快定位到它是被一段旧的README误导的,回头我把那份README更新掉,问题就不再发生了。观测日志不是给AI用的,是给人排查用的,但它的存在本身也能约束AI的行为——因为“行为透明”会让鲁莽的操作减少。
4.4 灰度与回滚:给AI换一条安全带
AI生成的功能上线,我强烈建议走灰度。不是因为它比人写的代码更容易出错,而是因为AI错误的模式和人不同,人容易在逻辑复杂处犯错,AI则在“看似简单但需要背景知识”的地方犯错。灰度可以在问题影响扩散之前拦截掉。
我的标准流程是:AI生成的改动先开PR,由人做一次轻量审查,然后合并到开发分支;在测试环境跑一整天黄金样本集和现有回归;确认没问题后,用一个feature flag把该功能包起来,先放5%流量观察三天;观察日志里的错误率和用户反馈;稳定后逐步放量到100%。整个过程里,feature flag是必须的,没有它,回滚就变成了一次紧急发布,风险剧增。
另一个容易被忽略的是“AI改动统计”。我维护了一张表,记录每次AI生成的改动行数、人工修正行数、测试发现bug数。这张表能直观看出AI在哪个环节表现好、哪个环节需要干预。数据会告诉你该不该继续加大AI投入,而不是凭感觉。
5. 我踩过的几个坑,以及现在值得试的工具链
5.1 三个真实教训:上下文爆炸、过度信任、缺回滚
第一个教训是上下文爆炸。我之前尝试让AI理解整个仓库,把目录树、核心文件、配置全部塞进提示词,结果token消耗涨了十倍,AI生成质量反而下降了。后来我才明白,AI的注意力是稀缺资源,给它太多无关信息等于让它“分心”。现在我只注入当前任务相关的模块文件和项目级约定,效果反而更好。
第二个教训是过度信任。有一次AI生成了一段看似完美的Shell脚本,我甚至没有仔细看就准备执行。幸亏做了一个diff检查,发现脚本里rm -rf的目标路径少了一级目录,如果直接跑,后果不堪设想。从此我立了一个规矩:AI生成的所有命令必须有一道人工确认,且命令执行前打印完整参数,方便审计。这个规矩如今也写进了团队的Agent工具配置里。
第三个教训是没有给AI操作留回滚。最初我让Agent直接修改源码文件,改错了只能靠Git恢复,但Git恢复之后,Agent的状态机器并不知道操作失败,继续在旧状态上执行,导致一连串连锁错误。后来我在工具层加了一个“操作前快照”机制:Agent每次写文件之前,系统自动备份原文件,写完后记录版本号。一旦校验失败,可以直接回滚到快照,Agent任务状态也同步重置。
5.2 当前值得尝试的AI工程工具链清单
这半年我试了不少工具,不吹不黑,我只分享自己实际用过且觉得有效的东西。
首先是代码编辑器的AI插件。我用JetBrains系比较多,装了一个叫Fitten Code的插件,它在代码补全和对话式操作上表现不错,日常写重复代码、改样板结构时帮助明显。它对我项目里已有代码风格的理解比其他通用补全工具要精细一些,可能是插件读取本地仓库上下文比较到位。另一类就是大家常说的AI编程工具,比如OpenAI的Codex,它在自主解决一些明确定义的任务上表现很好,适合跑批量代码生成,但它的付费价格不便宜,适合团队评估后按需采购。
然后是Agent编排框架。如果要搭自主执行的Agent,可以参考LangGraph这类流程控制库,它把状态机的概念引入Agent流程,支持并行分支和人工介入点。这正好解决了前面说的“任务状态管理”问题。我在评估过程中也看过一些机器人系统把Agent接入传感器控制的案例,比如OpenClaw结合ROS让AI代理操作实体设备,这属于AI向物理世界延伸的方向,虽然我还没有直接在工业场景落地,但它的工程思路是一致的:Agent的每一步决策都必须可追踪、可中断、可回滚。
其他我还要重点推荐两类工具:一类是prompt管理和测试类的,用来管理你的提示词版本,并在模型升级时做回归测试;另一类是devops测的AI网关,用来统一管控模型API的调用、限流、刻度和审计。前者适合从个人尝鲜过渡到团队协作,后者是进入生产环境的必备件。
5.3 一个可落地的团队试点方案
最后给团队提供一个我们正在用的试点方案,不算复杂,但每一步都有明确的交付物。
第一步,选一个非核心、低风险的内部服务(比如定时报表、告警聚合),作为AI试点对象。不要第一个就选用户交易链路,风险太大,无法积累信任。
第二步,按照本文第二章的内容,为这个服务的代码库做一次AI友好化改造。优先保证README完整、目录结构清晰、公共逻辑单一、增加ai_context.md索引文件。
第三步,给这个服务搭建测试基线。在原有单测基础上补几条核心路径的单元测试和集成测试,然后建立节四章说的黄金样本集,确保每次AI改动都能被自动验证。
第四步,配置一个Agent流程,让AI能把“从Issue到PR”的流程走通。人工做最后的code review和合并。这个阶段可以采集AI生成代码的修正率和测试通过率数据。
第五步,等连续两周AI生成的PR通过率稳定在90%以上,再把试点范围扩大到第二个服务。那时团队已经有经验模板,复制起来会快很多。
这套路径我从个人项目一路用到小团队,最大的感受是:AI友好型工程的收益不会在第一天显现,它更像是对项目做持续投资。每当你改一份文档、抽一个公共函数、配置一个黄金样本,都在降低AI后续行为的“没擦率”,等队友慢慢积累起信任,后续的收益是指数级的。
最后分享一个小技巧:在仓库根目录放一个ai_context.md,用纯文本写清楚这个项目的“隐性规则”——比如目录功能划分、错误码注册流程、命名约定、测试命令、哪些文件是生成不该动的。我做了这件事之后,AI生成代码的风格一致性和可用性提升非常明显。它的原理也简单:人会觉得这些规则“显而易见”,但AI全都不知道。如果你不告诉它,它只能在一次次的试错中慢慢摸索。这大概就是AI友好型工程最核心的心态:不要假设AI懂你的项目,不如把它当成一个刚入职的聪明新人,花十分钟写一封欢迎信,它会回报你整个协作周期的顺利。