· 软件工程

关于在正式项目中使用 AI 编程工具提升效率

在企业级项目中使用 AI 编程工具的实践经验:工程维护、推荐工作流、模型策略与避坑指南。

BB BB

TL;DR

  • AI 编程工具(主要有补全和生成两种模式)能显著加速小工具和脚本开发,但在企业级项目中若无节制地大量生成代码,会迅速产生技术债和不一致的设计,需谨慎使用。
  • 必备工程维护:在 README 中写明技术栈、启动/测试命令、代码结构和领域概念,并维护专门的 AI 指导文件(例如 CLAUDE.md / Cursor Rules),规定代码规范、异常处理与禁用项。
  • 推荐工作流:把任务拆成小块逐步交给 AI;测试与业务代码分开会话;提供详尽上下文与文件路径;频繁用 Git/Checkpoint 保存;严格人工 Review,并禁止 AI 擅自改动测试。
  • 工具与模型策略:优先使用工具推荐的强模型,注意上下文/Token 限制与跨会话一致性,遇到“死胡同”及时重开会话或重构以恢复可控性。

1. 前言

过去一年多来,我尝试过多种 AI 编程工具,代表性的有 GitHub Copilot、Cursor、Claude Code 等。我在企业级项目、个人项目和临时脚本/小工具中使用它们,工具在不少场景下确实提高了效率,但也带来了很多问题。写这篇博客是想分享踩过的坑以及我认为有效的工作流。

有两点先说明:

  1. 我不会使用“Vibe Coding”这个概念——它过于新颖且含义尚不稳定,容易引起歧义。
  2. AI 辅助编程的工具和技术变化很快,几个月前有效的方法可能很快失效,所以我在标题中标注了时间。

2. 工作模式

我用过的 AI 编程工具主要有两种工作模式:代码补全和代码生成。大多数 IDE 插件或独立的 AI IDE 都支持两者,但像 Claude Code 这样的 CLI 工具更侧重代码生成。下面的表格列出我尝试过的工具及其支持的模式。后续的问题与工作流讨论也会基于这两种模式展开。

工具代码补全代码生成
GitHub Copilot✅✅
Cursor✅✅
Windsurf✅✅
Cline✅✅
Gemini CLI
✅
Claude Code
✅

3. 问题

AI 辅助编程工具的效果既受 LLM 模型能力影响,也受工具方设计的提示词和工作流影响。因此及时切换到更好的模型和工具,往往能解决许多问题。一般建议优先使用工具推荐的模型,不要随意用规模更小或能力更差的模型替换。

例如 Claude Code:相同提示词在其他模型上的表现通常不如默认的 Claude Sonnet 4 或 Opus 4.1。模型提供者会根据训练数据调整提示策略,这些策略不一定能在所有模型上平滑迁移,甚至可能引发意外。做过 Agent 开发的同仁应该不会反对这一点。

3.1. 代码补全

在 Cursor 出现之前,代码补全一直是我常用的模式。综合下来,这种模式对效率提升有限,遇到的问题主要有:

  1. 常见的补全触发键是 Tab。连续按 Tab 时,尤其以 Python 为例,容易误改缩进,导致一些难以察觉但愚蠢的问题,比如不小心把语句缩进到循环体内。
  2. AI 补全常生成大段代码片段,而非单行,这会增加开发者审查成本——无论是技术上还是心理上。谁愿意在“爽快地写代码”时停下来逐行核验 AI 生成的长段代码?这会提高出错概率,尤其是在上下文复杂或变量命名混淆时。
  3. 补全模式本质上仍是人在编写代码,节省的敲键时间往往被阅读和验证时间抵消,难以带来质的提升。

3.2. 代码生成

在 Cursor、CodeX、Claude Code 等工具普及后,大量生成代码的模式变得流行。对脚本、小工具或简单网页来说,AI 生成往往能满足需求。但在企业级项目里,这种策略难以奏效:你无法通过几次对话就完成成熟的开发,需求频繁变化,代码需要具备健壮性和良好设计以应对演进。如果不加控制,项目会以惊人的速度变成难以维护的“屎山”。技术债一开始可能不明显,后来要么隐蔽难察,要么像房间里的大象一样明显却无人愿意处理。

印象深刻的问题包括:

  1. 默认情况下 AI 对异常处理往往不健康,滥用 try/catch 很常见,埋下业务风险。
  2. 不同 Agent 的设计会导致代码风格和设计偏好差异明显,频繁切换工具会带来一致性问题,除非有详尽的统一指导文件(如 CLAUDE.md 或 Cursor Rules)。
  3. 受限于上下文和 token 策略,AI 在寻找参考时常出现缺失,导致实现偏离预期。
  4. AI 生成会出现“死胡同”——遇到无法解决的问题时,反复尝试往往只会越做越糟。
  5. 目前还没有让我完全满意的长期记忆系统,跨会话一致性和连续性表现不足。
  6. 通过对话生成代码时,上下文长度的限制很明显,尽管工具有压缩策略,但长时间工作仍会出现“降智”。
  7. 跨会话开发可能破坏设计一致性,例如我的某个项目里,不同模块的设计模式渐行渐异,模块边界变得模糊,很多轮子被重复造了多次。

4. 方法

在多个持续性项目中实践后,我逐步形成了一套行之有效的方法,以 AI 代码生成为主,快速推动工程和业务开发,同时保持架构一致性和简洁性。对新项目可以一开始就打好基础;对已有项目则根据实际情况补充必要内容。方法分为两部分:工程维护与与 AI 的沟通方式。

4.1. 工程维护

类似于 DDD 里建立通用业务语言,为了让 AI 更好理解工程和业务,必须提供清晰说明。我倾向于在 README 中简洁维护这些基础信息,包括:

  1. 技术栈、工具链及各种入口(启动命令、测试命令等),并备注常见注意点(例如 Python 工程在运行工具前最好先激活虚拟环境)。
  2. 测试策略:单测开发规范、测试框架命令,以及如何设计和运行集成测试用例。
  3. 代码结构:说明代码的组织逻辑,例如按业务模块划分包,每个包内部按 MVC 分层等。
  4. 非通用概念的定义:对 Manager、Helper、Proxy、Actor、Delegate 等术语在本工程中的含义与边界做出说明,以免 AI 按默认理解产生偏差。
  5. 领域概念和业务模型的简要澄清,防止 AI 误解需求。
  6. 静态代码维护工具:说明格式化器、静态检查工具等,使 AI 可以按这些工具规范产出。

此外,一定要维护一份 AI 指导文件(如 CLAUDE.md 或 Cursor Rules)。我不会过度利用 Agent 的角色扮演属性去写大量文档,但会维护一份通用的指导文件,内容通常包括:

  1. 工作流程与检查清单:例如开始前先阅读 README、变更结束时运行静态检查、定位并运行受影响的单元测试并分析结果等。
  2. 代码规范:强调遵守项目首选的开发模式(例如 Python 中 async/await 的使用规则),遵循 DRY、SOLID 等设计原则。
  3. 异常处理原则:说明异常应在哪一层统一处理、是否有统一异常定义等,以减少 AI 生成混乱的异常处理。
  4. 测试失败处理原则:强调在测试失败时必须分析原因并输出日志,不得擅自改动测试以掩盖问题。AI 有时会通过修改测试来掩盖 Bug,这点必须禁止。
  5. 业务场景的特殊流程:对特定业务(如工作流开发)说明规则,并提供样例供 AI 参考,提高生成质量。
  6. 禁止项:列出不允许 AI 使用或修改的工具、脚本或代码区域,防止踩雷。

指导文件应随着使用结果持续优化。写这些文档的工作也可以交给 AI 来辅助,但最好由人最终审核并确认。

4.2. 交互

与 AI 交互时,我通常不会一次性把大功能交给 AI 完成。即便 AI 能做到,为了可控与降低 Review 负担,我会把任务拆解并逐步交付。例如实现 MVC 架构中的新接口时,我会先拆出需要的模型定义、Service 层功能、Controller 层逻辑,然后逐步交付给 AI。是否采用 TDD 留给团队或个人决策(据说 TDD 更可靠,但我的实践中差异不大)。

如果涉及数据模型或交互协议设计,会单独开一个会话与 AI 讨论:先说明业务背景,让 AI 设计初版数据模型;若协议复杂,先让 AI 写协议说明文档,确认无误后再据此设计数据结构。

我在交代某个子任务时,通常会先写一段较长的说明,包含:

  1. 业务背景和功能需求概要;
  2. 涉及的数据结构;
  3. 相关模块及各自的职责边界;
  4. 详细的开发任务描述(例如实现某个 Service 方法或 Controller 接口);
  5. 若为单元测试,明确需要的 Mock 桩和断言条件;
  6. 尽量提供完整的相对文件路径、类名、函数名,减少 AI 在项目中搜索耗费的 token 和误差;
  7. 必要时先写好代码框架和空的定义并用 TODO 指示细节;
  8. 对于 CLI 工具(如 Claude Code)我倾向于先在记事本里构思好文字再粘贴输入。

尽管 LLM 的上下文尺度较大,代码生成仍非常耗费上下文,描述得越详细通常越省事,能减少不必要的函数调用和 token 输出。与基于 LLM 的 Agent 开发相关的提示技巧仍然有效,包括避免在上下文中混入“有毒”内容(如大段 Base64)、使用关键词强调、注意指令的位置效应和指令复写等。

4.3. 其他技巧

无论采用 TDD 还是顺序开发,建议将测试用例和业务代码的生成会话分开:把相同的业务需求和设计逻辑分别提供给 AI,用不同会话开发测试和业务代码。这样可以避免 AI 在测试与实现之间“妥协”。当测试失败时,尽量分析原因并与人交互;让 AI 擅自修改代码以通过测试通常不可靠。

及时保存工作成果非常重要。无论使用 Cursor 的 Checkpoint、基于 MCP 的工具,还是传统的 Git,每次让 AI 完成一块任务并确认无误后马上保存,能避免回溯修复的巨大成本。我个人主要用 Git,因为我习惯这种工作流。

把一个功能拆成独立模块来让 AI 开发还有个好处:当 AI 进入“死胡同”时,影响范围有限。可以选择重开会话、全盘重来或临时修补并在未来重构。即使是最好的模型,也可能在几次失败后无法自我纠正,这种情况下重开会话往往更有效。

代码 Review 必不可少。即便有详尽的说明和限制,AI 写的代码仍可能与工程的架构风格或规范不一致。及时发现并修正这些问题,是防止工程劣化的最有效方式。

5. 感受

在使用 Claude Code 几个月后,它给我的感觉接近一个称职的实习开发者:能产出可运行的代码,但对混乱的工程结构、冗余设计、概念定义不清或“一句话”需求,表现并不稳定。和真实团队一样,良好的产品或技术管理能稳定地传达需求;清晰维护的工程和适度的文档能让 AI 更舒服、更稳定地工作。

相比管理一个真实开发团队,管理 AI 生成代码的难度略小。AI 缺少人类开发者那种“灵光一闪”的创造力,但更加可控,能按既定基调输出一致的代码,前提是这些基调被明确定义。

总体来说,AI 编程工具能提升开发效率,但也对开发者提出更高要求——这些要求以前通常落在团队中高级工程师或技术负责人身上。如果仅掌握一两门语言和常规框架的基础用法,部分价值确实会被 AI 侵蚀。就像工业革命中的珍妮机,确实让一些手摇纺车的工人失业,但布匹产量和市场扩大,也增加了对布匹设计师等高附加值岗位的需求。

在需要严肃对待的项目里,保证可控性是关键。代码可读性与代码量并无绝对关系:结构清晰、模型简单的工程,即使代码量大,只要配合必要文档,也能保持高可读性。在 AI 尚未达到像编译器那样稳定把自然语言转成可运行软件的阶段,我倾向于用 AI 快速输出“我也会这么写”的代码,然后由人负责设计、审核与维护。