☰
AI写代码总爱自作聪明?用AGENTS.md和Prompt工程治好它
2026/10/1 14:02:50 网站建设 项目流程

1. 为什么AI写代码总爱“自作聪明”

1.1 一个让所有开发者血压升高的场景

你让AI帮你写一个用户登录接口,它给你返回了整整两百行代码。你仔细一看,它顺手帮你加了JWT刷新逻辑、加了Redis缓存、加了请求频率限制、加了邮箱验证,甚至还贴心地引入了一个你项目里根本没装的第三方库。你只是想让它写个登录,它却给你造了一整套用户中心。

这不是段子,这是每天都在发生的事情。AI写代码时最大的毛病,不是写不出来,而是写太多、写太偏、写太“聪明”。你让它修一个空指针异常,它把整个模块重构了一遍;你让它加一个字段,它把数据库表结构改了;你让它写个工具函数,它给你整了个设计模式全家桶。

我见过最离谱的一次,同事让AI帮忙写一个简单的日期格式化函数,AI返回的代码里包含了时区处理、夏令时判断、闰年校验、国际化适配,还附带了单元测试和文档注释。代码本身没毛病,但问题是——项目里已经有现成的日期工具库了,而且团队规范明确要求统一使用那个库。

这种“自作聪明”带来的后果很直接:代码审查时间翻倍、引入不必要的依赖、破坏项目一致性、增加维护成本。更可怕的是,有些AI生成的代码看起来逻辑自洽,实际上隐藏着微妙的bug,你不仔细看根本发现不了。

1.2 问题的根源在哪里

AI之所以会“自作聪明”,核心原因有三个层面。

第一个层面是训练数据的偏差。AI模型在训练时接触了大量的开源项目、技术博客和教程代码。这些内容天然带有“展示性”——作者写教程时总想把功能做完整、把代码写漂亮,于是各种设计模式、边界处理、扩展性考虑全都堆上去。AI学到的就是这种“教科书式”的写法,它不知道你的真实项目里可能只需要一个能跑的最简实现。

第二个层面是缺乏项目上下文。当你打开一个对话窗口,粘贴一段需求描述,AI看到的只是这段文字。它不知道你的项目用了什么框架、遵循什么规范、有哪些现成的工具类、团队的技术栈偏好是什么。在信息缺失的情况下,AI会倾向于“过度补偿”——既然不知道你的约束条件,那就把所有可能的情况都考虑进去。

第三个层面是提示词本身的模糊性。大多数人给AI下指令时,说的是“帮我写一个登录功能”,而不是“在我现有的Express项目里,使用已有的User模型和bcrypt库,写一个POST /api/login路由处理函数,只做密码校验和token签发,不要引入新依赖”。前者给了AI无限的发挥空间,后者才是有效的工程指令。

1.3 解决思路的整体框架

要彻底治好AI的“自作聪明”,不能靠反复抽卡碰运气,而是要从三个维度同时下手:约束输入、规范输出、持续校准。

约束输入指的是在给AI下指令之前,先把项目上下文、技术约束、代码规范这些信息准备好,让AI在明确的边界内工作。规范输出指的是通过配置文件、提示词模板、代码审查清单等手段,让AI生成的代码符合项目要求。持续校准指的是在AI生成代码后,通过自动化检查和人工审查,及时发现偏差并反馈修正。

这三个维度对应到具体操作上,就是本文要重点讲的几个核心工具和方法:用AGENTS.md文件给AI建立项目认知、用结构化Prompt约束AI的输出范围、用代码规范检查工具做自动化兜底、用多轮对话策略逐步收敛结果。

2. AGENTS.md:给AI装上一本项目说明书

2.1 AGENTS.md到底是什么

AGENTS.md是一个放在项目根目录下的Markdown文件,它的作用是告诉AI这个项目的基本信息、技术栈、代码规范、目录结构、常用命令等。你可以把它理解成“给AI看的README”——README是给人看的,告诉人类开发者怎么上手这个项目;AGENTS.md是给AI看的,告诉AI在这个项目里写代码要遵守什么规则。

这个文件本身没有任何技术门槛,就是一个普通的文本文件。但它的存在与否,对AI生成代码的质量影响巨大。没有AGENTS.md的时候,AI只能根据你的对话内容来猜测项目情况;有了AGENTS.md之后,AI在每次生成代码前都会先读取这个文件,了解项目的约束条件,从而避免“自作聪明”。

我自己的项目里,加上AGENTS.md之后,AI生成代码的“跑偏率”大概从百分之六七十降到了百分之十几。剩下的百分之十几,通过后续的Prompt约束和代码审查也能兜住。

2.2 AGENTS.md应该写什么内容

一个实用的AGENTS.md不需要写得多漂亮,但必须包含以下几类信息。

第一类是项目概述。用两三句话说明这个项目是做什么的、面向什么用户、当前处于什么阶段。比如“这是一个面向中小企业的SaaS库存管理系统,目前处于MVP阶段,优先保证功能可用,暂不考虑大规模并发”。

第二类是技术栈声明。列出项目使用的前端框架、后端框架、数据库、缓存、消息队列、部署方式等。关键是要写明版本号,因为不同版本的API差异很大。比如“后端使用Express 4.18,数据库使用PostgreSQL 15,ORM使用Prisma 5.x,不要使用Sequelize或TypeORM”。

第三类是代码规范。这部分要写得具体,不能只说“遵循最佳实践”。要明确缩进用几个空格、字符串用单引号还是双引号、是否使用分号、函数命名用驼峰还是下划线、文件命名用短横线还是下划线。如果项目有ESLint或Prettier配置,直接说明“遵循项目根目录下的.eslintrc和.prettierrc配置”。

第四类是目录结构说明。告诉AI哪个目录放路由、哪个目录放模型、哪个目录放工具函数、哪个目录放测试。这样AI在生成新文件时就知道该往哪里放,不会把路由文件扔到utils目录里。

第五类是禁止事项。这是最重要的一部分。明确告诉AI不要做什么,比如“不要引入新的npm依赖,如需使用新库请先询问”、“不要修改数据库schema,所有变更通过migration文件处理”、“不要使用any类型,所有TypeScript代码必须有明确的类型标注”、“不要写console.log,使用项目统一的logger工具”。

第六类是常用命令。列出启动开发服务器、运行测试、执行lint、构建生产包的命令。这样AI在需要验证代码时就知道该跑什么命令。

2.3 一个真实的AGENTS.md示例

下面是我在一个Node.js后端项目里实际使用的AGENTS.md文件,做了脱敏处理,你可以直接参考这个结构。

# 项目说明 这是一个面向企业内部使用的工单管理系统后端API。 ## 技术栈 - Node.js 20 LTS - Express 4.18 - PostgreSQL 15 + Prisma 5.x - Redis 7.x(仅用于session存储) - Jest 29(测试框架) - ESLint + Prettier(代码规范) ## 代码规范 - 缩进:2个空格 - 字符串:单引号 - 分号:必须写 - 函数命名:驼峰式(camelCase) - 文件命名:短横线式(kebab-case) - 类型:TypeScript严格模式,禁止any ## 目录结构 - src/routes/:路由定义 - src/controllers/:业务逻辑 - src/models/:Prisma模型封装 - src/middlewares/:Express中间件 - src/utils/:工具函数 - src/types/:TypeScript类型定义 - tests/:测试文件 ## 禁止事项 - 不要引入新的npm依赖,如需使用请先说明理由 - 不要直接操作数据库,所有查询通过Prisma Client - 不要修改prisma/schema.prisma,如需变更请提供migration方案 - 不要使用console.log,使用src/utils/logger.ts - 不要写超过50行的函数,超过请拆分 ## 常用命令 - 开发:npm run dev - 测试:npm test - Lint:npm run lint - 构建:npm run build

这个文件大概一百多行,写一次之后,后续所有AI对话都会受益。你可以在对话开始时直接把AGENTS.md的内容粘贴给AI,或者如果使用的工具支持自动读取项目文件,AI会自动加载。

2.4 让AGENTS.md真正生效的技巧

光写一个AGENTS.md文件还不够,关键是要让AI在每次生成代码时都参考它。不同的AI编程工具对这个文件的支持程度不一样。有些工具会自动读取项目根目录下的AGENTS.md,有些需要你手动在对话中引用。

我的做法是在每次对话的第一条消息里,先粘贴AGENTS.md的内容,然后加上一句“请先阅读以上项目说明,后续所有代码生成都必须遵守这些约束”。这样相当于给AI设定了一个“系统提示”,后续的对话都会在这个框架内进行。

另外,AGENTS.md不是写完就一劳永逸的。项目在演进,技术栈在升级,规范在调整,AGENTS.md也要跟着更新。我一般每个月review一次,把最近踩过的坑、新增的约束补充进去。比如有一次AI反复在代码里写console.log,我就在禁止事项里加了一条“禁止使用console.log”,之后这个问题就再也没出现过。

还有一个细节:AGENTS.md里的禁止事项要写得具体,不能太笼统。说“不要写烂代码”没用,AI不知道什么叫烂代码。要说“不要写超过50行的函数”、“不要嵌套超过3层的if语句”、“不要使用for循环,用map/filter/reduce替代”。越具体,AI越容易遵守。

3. Prompt工程:把“帮我写代码”变成“按规范写代码”

3.1 为什么你的Prompt总是被AI误解

大多数人给AI写Prompt的方式,就像在餐厅点菜时说“随便来点好吃的”。厨师只能根据自己的理解做一道菜,端上来你可能不满意,但问题不在厨师,在于你没说清楚想吃什么。

AI编程也是同样的道理。“帮我写一个用户注册功能”这句话,包含了太多的模糊地带。注册需要哪些字段?密码要不要加密?要不要发验证邮件?要不要做频率限制?返回什么格式?错误怎么处理?这些AI都不知道,它只能按照自己的理解来补全。而AI的理解,往往来自那些“教学性质”的开源代码,于是各种边界处理、扩展性设计全来了。

有效的Prompt应该像一份需求规格说明书,把输入、输出、约束、异常处理都说清楚。你不需要写得很长,但关键信息不能少。

3.2 结构化Prompt的五个核心要素

我总结了一个在AI编程场景下比较通用的Prompt结构,包含五个要素:角色设定、上下文、任务描述、约束条件、输出格式。

角色设定是告诉AI以什么身份来写代码。比如“你是一个有五年经验的Node.js后端开发者,熟悉Express和Prisma”。这个设定会影响AI的代码风格和技术选型偏好。

上下文是告诉AI当前项目的情况。如果你已经提供了AGENTS.md,这部分可以简化,只需要补充本次任务相关的特殊背景。比如“当前项目已经有一个User模型,包含id、email、passwordHash、createdAt字段”。

任务描述是具体要做什么。要写得具体,但不要写成伪代码。比如“实现一个POST /api/register接口,接收email和password,校验邮箱格式和密码强度,检查邮箱是否已注册,创建用户记录,返回用户ID和创建时间”。

约束条件是告诉AI不要做什么。这是防止“自作聪明”的关键。比如“不要发送验证邮件”、“不要引入新的依赖”、“不要修改现有的User模型”、“密码哈希使用项目已有的bcrypt工具函数”。

输出格式是告诉AI返回什么。比如“只返回路由处理函数的代码,不要包含路由注册代码,不要包含测试代码,不要包含注释”。

把这五个要素组合起来,一个完整的Prompt大概长这样:

你是一个有五年经验的Node.js后端开发者。 当前项目使用Express 4.18 + Prisma 5.x + PostgreSQL 15。 已有的User模型包含字段:id, email, passwordHash, createdAt。 已有的工具函数:src/utils/hash.ts 提供 hashPassword 和 verifyPassword。 已有的中间件:src/middlewares/validate.ts 提供请求体校验。 任务:实现POST /api/register接口。 - 接收email和password - 校验邮箱格式(使用项目已有的validator工具) - 校验密码强度(至少8位,包含字母和数字) - 检查邮箱是否已注册 - 创建用户记录 - 返回用户ID和创建时间 约束: - 不要发送验证邮件 - 不要引入新的npm依赖 - 不要修改User模型 - 不要写console.log - 错误处理使用项目统一的AppError类 输出:只返回controller函数的代码,不要包含路由注册,不要包含测试。

这个Prompt大概两百字,但信息密度很高。AI拿到这样的指令,基本不会跑偏。

3.3 用“负面清单”锁死AI的发挥空间

在Prompt里,负面约束往往比正面描述更有效。因为AI的“自作聪明”主要表现为“多做了不该做的事”,而不是“少做了该做的事”。你告诉它要做什么,它可能会漏;但你告诉它不要做什么,它一般都会遵守。

我习惯在Prompt里加一个“禁止事项”段落,把常见的“自作聪明”行为都列出来。比如:

  • 不要添加额外的错误处理,除非我明确要求
  • 不要写注释,除非逻辑特别复杂
  • 不要重构现有代码,只做我要求的最小改动
  • 不要引入新的依赖
  • 不要修改函数签名
  • 不要添加日志输出
  • 不要写单元测试,除非我要求
  • 不要使用设计模式,用最直白的写法

这个清单可以根据项目情况调整。比如有些项目要求必须写测试,那就把“不要写单元测试”去掉。有些项目鼓励使用设计模式,那就把最后一条去掉。

关键是让AI知道:在这个项目里,“少做”比“多做”好,“直白”比“优雅”好,“能跑”比“完美”好。

3.4 多轮对话的收敛策略

即使Prompt写得再好,AI第一次生成的代码也可能不完全符合要求。这时候不要直接放弃或者手动改,而是通过多轮对话逐步收敛。

第一轮:让AI生成初版代码。不要期望一次就完美,先看整体方向对不对。

第二轮:指出具体问题。不要说“写得不好”,要说“第15行的错误处理不需要,请删除”、“第23行引入的lodash依赖项目里没有,请用原生方法实现”、“第30行的console.log请删除”。

第三轮:让AI根据反馈重新生成。这时候AI已经知道了你的偏好,生成的代码会明显更贴近要求。

第四轮:如果还有小问题,继续微调。一般三到四轮就能得到可用的代码。

这个过程中,最重要的是反馈要具体。说“第15行”比说“错误处理部分”更有效,说“删除console.log”比说“不要写日志”更有效。AI对具体的行号和操作指令理解得最准确。

我自己的经验是,第一轮生成后,大概需要两到三轮修正才能达到可提交的状态。虽然看起来多花了时间,但比起自己从头写或者反复抽卡,效率还是高很多。而且随着你对Prompt的打磨,第一轮的质量会越来越高,修正轮次会越来越少。

4. 代码规范检查:让机器做最后的守门人

4.1 为什么AI生成的代码必须过Lint

不管Prompt写得多好,AGENTS.md多完善,AI偶尔还是会写出不符合规范的代码。这不是AI故意捣乱,而是概率问题——大语言模型的输出本质上是概率采样,即使约束很明确,也有一定概率“采样”到不符合要求的token。

所以,AI生成的代码在提交之前,必须过一遍自动化检查。这不是不信任AI,而是工程上的必要防线。就像即使是最资深的开发者,代码也要过CI一样。

Lint工具在这里扮演的是“守门人”角色。它不关心代码是谁写的,只关心代码是否符合规则。AI写的代码和人类写的代码,在Lint面前一视同仁。这恰恰是我们需要的——用统一的、客观的标准来约束AI的输出。

4.2 ESLint + Prettier的配置要点

对于JavaScript和TypeScript项目,ESLint负责代码质量检查,Prettier负责代码格式化。两者配合使用,基本能覆盖大部分规范问题。

ESLint的配置重点在于规则的选择。默认的recommended规则集太宽松了,很多AI常犯的问题它不管。我建议在recommended基础上,额外开启以下规则:

  • no-console:禁止console.log,AI特别爱写这个
  • no-unused-vars:禁止未使用的变量,AI经常定义了一堆变量但没用
  • no-undef:禁止使用未定义的变量,防止AI引用不存在的全局变量
  • max-lines-per-function:限制函数最大行数,防止AI写出超长函数
  • max-depth:限制嵌套深度,防止AI写出多层嵌套
  • complexity:限制圈复杂度,防止AI写出过于复杂的逻辑
  • no-new-dependencies:这个不是ESLint内置规则,但可以通过自定义规则或CI检查来实现

Prettier的配置相对简单,主要是缩进、引号、分号、行宽这几个选项。关键是团队要统一,不要有的人用两个空格有的人用四个空格。

配置好之后,在package.json里加一个lint脚本:

{ "scripts": { "lint": "eslint src/ --ext .ts,.js", "lint:fix": "eslint src/ --ext .ts,.js --fix", "format": "prettier --write 'src/**/*.{ts,js,json}'" } }

每次AI生成代码后,先跑npm run lint,看看有没有报错。有报错就让AI根据报错信息修正,或者手动修正。修正完再跑npm run format统一格式。

4.3 用Git Hook做提交前检查

Lint脚本需要手动跑,容易忘记。更可靠的方式是通过Git Hook在提交前自动执行。

使用husky + lint-staged可以在每次git commit时自动对暂存区的文件执行lint和format。配置方式如下:

npm install --save-dev husky lint-staged npx husky install npx husky add .husky/pre-commit "npx lint-staged"

然后在package.json里配置lint-staged:

{ "lint-staged": { "*.{ts,js}": [ "eslint --fix", "prettier --write" ] } }

这样每次提交代码时,ESLint和Prettier会自动对修改的文件进行处理。如果ESLint报错且无法自动修复,提交会被阻止。这就强制保证了进入仓库的代码(包括AI生成的代码)都符合规范。

我自己的项目里,加上这个Hook之后,AI生成的代码基本不会出现console.log、未使用变量、格式混乱这些问题了。因为AI在生成代码时如果写了console.log,提交时会被ESLint拦下来,然后我会让AI修正,修正后的代码就干净了。

4.4 自定义规则拦截“自作聪明”行为

除了ESLint内置规则,还可以通过自定义规则来拦截一些项目特有的“自作聪明”行为。

比如,有些AI特别喜欢引入lodash。你可以在ESLint配置里加一条no-restricted-imports规则:

{ "rules": { "no-restricted-imports": ["error", { "paths": ["lodash", "underscore", "ramda"], "message": "项目禁止使用工具库,请用原生方法实现" }] } }

再比如,有些AI喜欢用any类型。可以加一条@typescript-eslint/no-explicit-any规则:

{ "rules": { "@typescript-eslint/no-explicit-any": "error" } }

还有,有些AI喜欢写console.log、debugger、alert这些调试语句。ESLint的no-console、no-debugger、no-alert规则可以全部开启。

这些规则加上之后,AI在生成代码时如果触发了这些规则,Lint会报错,你就知道AI又“自作聪明”了,可以针对性地修正。

5. 实操全流程:从需求到可提交代码

5.1 完整流程概览

把前面讲的几个模块串起来,一个完整的AI辅助编程流程大概是这样的:

第一步,准备AGENTS.md文件,放在项目根目录。如果项目还没有,花半小时写一个。

第二步,在AI对话开始时,粘贴AGENTS.md内容,并说明“请遵守以上项目规范”。

第三步,用结构化Prompt描述任务,包含角色、上下文、任务、约束、输出格式五个要素。

第四步,AI生成代码后,先肉眼扫一遍,看整体方向对不对。

第五步,把代码粘贴到项目里,跑npm run lint检查规范问题。

第六步,如果有Lint报错,把报错信息反馈给AI,让它修正。

第七步,修正后的代码再跑一次Lint,确认通过。

第八步,跑npm test确认功能正常。

第九步,提交代码,Git Hook会自动做最后的格式检查。

这个流程看起来步骤多,但实际操作起来很快。熟练之后,从下指令到代码可提交,一个中等复杂度的函数大概五到十分钟就能搞定。

5.2 一个完整的实操案例

假设我们要在一个Express项目里实现一个“获取当前用户信息”的接口。项目已经有JWT认证中间件,User模型包含id、email、nickname、avatar、createdAt字段。

第一步:准备Prompt

你是一个有五年经验的Node.js后端开发者。 项目使用Express 4.18 + Prisma 5.x + PostgreSQL 15。 已有JWT认证中间件 src/middlewares/auth.ts,会在req.user中注入用户ID。 已有User模型,包含字段:id, email, nickname, avatar, createdAt。 任务:实现GET /api/me接口,返回当前登录用户的信息。 - 从req.user中获取用户ID - 查询用户记录 - 返回id、email、nickname、avatar、createdAt - 如果用户不存在,返回404 约束: - 不要返回passwordHash字段 - 不要引入新依赖 - 不要写console.log - 错误处理使用项目统一的AppError类 - 不要写注释 输出:只返回controller函数的代码。

第二步:AI生成代码

AI返回了如下代码:

import { Request, Response, NextFunction } from 'express'; import { prisma } from '../lib/prisma'; import { AppError } from '../utils/AppError'; export async function getCurrentUser( req: Request, res: Response, next: NextFunction ): Promise<void> { try { const userId = req.user?.id; if (!userId) { throw new AppError('Unauthorized', 401); } const user = await prisma.user.findUnique({ where: { id: userId }, select: { id: true, email: true, nickname: true, avatar: true, createdAt: true, }, }); if (!user) { throw new AppError('User not found', 404); } res.json({ data: user }); } catch (error) { next(error); } }

第三步:代码审查

肉眼扫一遍,整体没问题。没有引入新依赖,没有console.log,没有返回passwordHash,错误处理用了AppError。select里明确列出了要返回的字段,没有用select: { passwordHash: false }这种写法,更安全。

第四步:Lint检查

把代码放到src/controllers/user.controller.ts,跑npm run lint。没有报错。

第五步:测试

跑npm test,已有的测试用例通过。手动用Postman测一下接口,返回数据正确。

第六步:提交

git add+git commit,Git Hook自动跑Prettier格式化,提交成功。

整个流程从写Prompt到提交,大概花了八分钟。如果不用AGENTS.md和结构化Prompt,AI可能会返回一个包含分页、缓存、字段过滤等额外功能的版本,审查和修正的时间至少要翻倍。

5.3 不同场景下的Prompt模板

根据任务类型的不同,Prompt的侧重点也不一样。下面给出几个常见场景的模板。

场景一:新增接口

重点是明确输入输出、错误处理、权限校验。约束里要强调不要添加额外的业务逻辑。

场景二:修改现有函数

重点是明确修改范围。约束里要强调“只修改指定的部分,不要重构其他代码”。

场景三:修复Bug

重点是提供错误信息和复现步骤。约束里要强调“只修复Bug,不要顺便优化代码”。

场景四:写测试

重点是明确测试框架、测试范围、断言风格。约束里要强调“不要测试框架本身的代码”。

场景五:重构

重点是明确重构目标和保持行为不变。约束里要强调“不要改变函数签名和返回值”。

每个场景的模板都可以在AGENTS.md的基础上做调整。核心原则不变:给足上下文、明确约束、指定输出格式。

6. 常见问题与排查技巧实录

6.1 AI反复引入不需要的依赖怎么办

这是最常见的问题。你明明说了“不要引入新依赖”,AI还是写了import _ from 'lodash'。

排查思路:首先确认AGENTS.md里有没有明确写“禁止引入新依赖”。如果没有,加上。如果有,检查Prompt里有没有重复强调。如果都有,那就是AI的“惯性”太强了,需要在Lint层面做拦截。

解决方法:在ESLint里配置no-restricted-imports规则,把常见的工具库都列进去。这样即使AI写了,Lint也会报错,你就能及时发现并让AI修正。

另外,可以在Prompt里加一句“如果你认为需要引入新依赖,请先停下来询问我,不要直接写import语句”。这样AI在想要引入依赖时会先问你,而不是直接写。

6.2 AI生成的代码总是“过度设计”怎么办

AI特别喜欢用设计模式。一个简单的数据转换,它要给你搞个策略模式;一个普通的CRUD,它要给你搞个Repository模式。

排查思路:检查Prompt里有没有明确说“用最直白的写法”。如果没有,加上。同时检查AGENTS.md里有没有“禁止使用设计模式”的约束。

解决方法:在Prompt里加一句“用最直白的写法实现,不要使用任何设计模式,不要为了扩展性而抽象”。另外,可以在Lint里加max-lines-per-function和complexity规则,函数太长或太复杂就报错,逼着AI写简单代码。

我自己的经验是,加上“不要使用设计模式”这条约束后,AI生成的代码明显简洁了很多。以前一个函数动辄上百行,现在基本都在三十行以内。

6.3 AI写的代码能跑但不符合项目风格怎么办

比如项目用单引号,AI用双引号;项目用两个空格缩进,AI用四个空格;项目用驼峰命名,AI用下划线。

排查思路:检查AGENTS.md里有没有写清楚代码规范。如果只写了“遵循ESLint配置”,AI可能不知道具体规则是什么。要把关键规则明确写出来。

解决方法:在AGENTS.md里把代码规范写具体,不要只说“遵循项目规范”,要说“缩进2空格、单引号、必须写分号、函数名用驼峰”。另外,Prettier配置要放在项目根目录,AI生成代码后跑一次npm run format就能统一格式。

如果AI反复在某个格式问题上出错,可以在Prompt里单独强调。比如“字符串必须用单引号,不要用双引号”。强调几次之后,AI一般就能记住。

6.4 AI生成的代码有隐藏Bug怎么发现

有些Bug很隐蔽,比如边界条件处理错误、异步操作没有await、变量作用域问题。这些Bug Lint查不出来,测试也可能覆盖不到。

排查思路:对于关键逻辑,不要完全信任AI。自己逐行读一遍,特别是条件判断、循环边界、异步操作这些容易出错的地方。

解决方法:让AI自己解释代码。在生成代码后,加一句“请逐行解释这段代码的逻辑,特别是边界条件的处理”。AI在解释的过程中,往往会自己发现一些问题。另外,可以让AI生成测试用例,通过测试来验证逻辑正确性。

我自己的习惯是,对于涉及金额计算、权限判断、数据过滤这些关键逻辑,AI生成的代码一定要自己读一遍。其他不太关键的代码,跑通测试就行。

6.5 常见问题速查表

问题现象可能原因排查方法解决措施
AI引入新依赖AGENTS.md未声明禁止检查AGENTS.md和Prompt加no-restricted-imports规则
代码过度设计Prompt未限制写法检查Prompt约束条件加“用最直白写法”约束
格式不符合规范规范未写具体检查AGENTS.md代码规范部分写具体规范+Prettier格式化
函数过长未限制函数行数检查Lint配置加max-lines-per-function规则
有console.log未禁止调试语句检查Lint配置加no-console规则
返回多余字段Prompt未明确字段检查Prompt输出描述明确列出要返回的字段
错误处理不一致未指定错误处理方式检查AGENTS.md明确使用项目统一错误类
异步未awaitAI疏忽人工审查加require-await规则

6.6 几个我踩过的坑

第一个坑:AGENTS.md写得太长。一开始我把所有能想到的规范都写进去,结果文件有五百多行。AI读取的时候反而抓不住重点,效果不好。后来精简到一百行左右,只保留最关键的约束,效果反而更好。

第二个坑:Prompt里约束太多。有一次我写了一个很长的Prompt,列了二十多条约束。结果AI顾此失彼,满足了这条忘了那条。后来我把约束分成“必须遵守”和“尽量遵守”两档,必须遵守的放在前面,尽量遵守的放在后面,效果好很多。

第三个坑:完全信任AI的测试代码。有一次让AI写测试,它写的测试全部通过,但后来发现测试本身有问题——断言写得太宽松,根本没测到关键逻辑。后来我要求AI写测试时,必须包含边界条件的测试用例,并且断言要具体。

第四个坑:忘记更新AGENTS.md。项目从JavaScript迁移到TypeScript后,AGENTS.md里还写着“使用JavaScript”。结果AI生成的代码全是JS,跟项目不匹配。后来养成了习惯,每次技术栈变更后第一件事就是更新AGENTS.md。

7. 让AI成为听话的助手而不是自作聪明的“专家”

7.1 心态上的调整

很多人对AI编程有一个误区,觉得AI应该“懂我”,应该能自动理解项目情况。但现实是,AI没有读心术,它只能根据你给的信息来工作。你给的信息越少,它就越需要“猜”,而猜的结果往往就是“自作聪明”。

所以,与其抱怨AI不听话,不如把精力花在如何给AI提供更好的上下文和更明确的约束上。这其实和带新人的逻辑是一样的——你不能指望一个新来的同事自动了解项目规范,你得写文档、做培训、Code Review。AI也是一样,AGENTS.md就是它的入职文档,Prompt就是它的任务工单,Lint就是它的Code Review。

7.2 持续优化的循环

治好AI的“自作聪明”不是一次性的工作,而是一个持续优化的循环。

每次AI生成代码后,如果发现“自作聪明”的行为,就把它记录下来。如果是AGENTS.md没写清楚的,补充进去;如果是Prompt没约束到的,下次加上;如果是Lint没拦截的,加条规则。

这样循环几轮之后,你会发现AI生成代码的质量越来越高,需要修正的地方越来越少。我自己的项目大概经过两个月的迭代,现在AI生成的代码有百分之七八十可以直接用,剩下的百分之二三十稍微改改就行。

7.3 一个实用的小技巧

最后分享一个我最近在用的技巧:在AGENTS.md里加一个“最近踩坑记录”段落,把最近AI犯过的错误记下来。比如“2024-01-15:AI在生成用户查询时没有过滤已删除用户,导致返回了软删除的数据。所有查询必须加where: { deletedAt: null }”。

这个段落不用很长,每次踩坑后加一行就行。AI在读取AGENTS.md时会看到这些记录,从而避免重复犯错。实测下来,这个技巧对减少重复性错误非常有效。

另外,如果你用的是支持多轮对话的AI工具,可以在对话结束时加一句“请总结本次对话中我强调的所有约束,以便后续对话参考”。AI会把这些约束整理出来,你可以直接复制到AGENTS.md里。这样相当于让AI帮你维护项目规范文档,省了不少事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询