ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AI编程提速却致项目混乱?工程闭环与AST去重实战

AI编程提速却致项目混乱?工程闭环与AST去重实战 1. 为什么AI写代码越快项目反而越乱这两年跟不少团队聊过大家都有同一个感受AI编程工具确实让写代码这件事变快了但项目本身的混乱程度也在同步上升。以前一个功能模块可能要写两三天现在用AI辅助半天就能跑通。问题是跑通之后呢三个月后回头看你会发现同一个日期格式化函数在项目里出现了七个版本每个版本的参数顺序还不一样。这不是个别现象。我见过一个中等规模的后端项目光是“用户信息校验”这个逻辑在六个不同的service文件里各写了一遍。问起来原因也很简单每次让AI生成代码它都会根据当前上下文重新造一个。AI没有记忆它不知道你上周已经写过类似的东西。你给它一个需求它就老老实实给你生成一份完整的实现至于这份实现跟项目里已有的东西是否重复它不关心。核心矛盾在于AI的生成速度远超人工整理的速度。以前人工写代码写的时候顺手就抽了个公共方法因为人脑有惰性不想写重复的东西。但AI没有这种惰性它每次都是从零开始生成而且生成得飞快。结果就是代码量膨胀的速度远远超过重构的速度项目结构迅速腐化。这个问题在团队协作场景下更严重。张三用AI生成了一个工具类李四不知道又用AI生成了一个功能类似的。两个人的命名风格还不一样一个叫DateUtils一个叫TimeHelper。等到要统一的时候发现已经有几十个文件引用了这两个类改起来牵一发动全身。所以真正的问题不是“AI能不能写代码”而是“AI写完代码之后怎么保证项目结构不崩”。这就需要一套工程闭环来兜底。所谓工程闭环说白了就是让AI生成的代码在进入项目之前先过一遍自动化的检查、去重、归档流程确保它不会成为新的技术债。这套闭环的核心思路不复杂但落地的时候有很多细节要注意。下面我会从整体设计、关键技术点、实操流程、常见问题几个方面展开把我在实际项目中踩过的坑和总结的经验都倒出来。2. 工程闭环的整体设计与核心思路2.1 闭环的三个核心环节一套能跑通的工程闭环至少包含三个环节生成前的上下文注入、生成中的实时校验、生成后的自动归档与去重。生成前的上下文注入意思是你在让AI写代码之前先把项目里已有的相关组件信息喂给它。比如你要写一个日期处理功能那就先把项目里已有的日期工具类、相关的常量定义、命名规范都作为上下文传进去。这样AI生成的时候就会优先复用已有的东西而不是重新造一个。生成中的实时校验是指在AI生成代码的过程中或者生成完成后立即触发检查。这个检查包括几个层面语法检查、风格检查、重复度检查。语法和风格检查比较成熟用ESLint、Pylint这类工具就能搞定。重复度检查是重点需要用AST抽象语法树来做结构化的比对而不是简单的文本匹配。生成后的自动归档与去重是指当AI生成的代码通过校验后自动把它归入项目的组件库中并更新组件索引。下次再有类似需求时AI可以直接从索引中找到可复用的组件而不是重新生成。这三个环节串起来就形成了一个闭环上下文注入 → 生成 → 校验 → 归档 → 更新上下文 → 下一次生成。每循环一次组件库就更丰富一点重复造轮子的概率就更低一点。2.2 为什么选AST而不是文本匹配很多人第一反应是用文本相似度来做去重比如计算两个文件的余弦相似度超过阈值就认为是重复。这个方法在简单场景下能用但在真实项目里误报率很高。举个例子两个函数def format_date(dt): return dt.strftime(%Y-%m-%d) def format_time(dt): return dt.strftime(%H:%M:%S)文本相似度很高因为结构几乎一样但功能完全不同不应该合并。反过来def get_user_name(user): return user[name] def fetch_user_name(u): return u.get(name, )文本相似度不高但功能高度重叠应该合并。AST的好处在于它能理解代码的结构。上面第一组例子AST会识别出strftime的参数不同判定为不同功能。第二组例子AST会识别出两者都是“从字典中取name字段”判定为可合并。具体来说AST比对的核心是提取代码的“结构指纹”。对于函数来说指纹包括参数数量、参数类型如果能推断、返回类型、调用的方法名、控制流结构。把这些特征提取出来做比对准确率比文本匹配高一个数量级。2.3 CI在闭环中的角色CI持续集成在这套闭环里扮演的是“守门人”的角色。每次AI生成的代码提交到仓库时CI流水线自动触发跑一遍完整的检查流程。如果检查不通过代码就进不了主分支。这样做的好处是把问题拦截在入口处。以前是代码合进去之后过几个月才发现重复那时候清理成本已经很高了。现在是在提交时就发现当场解决成本最低。CI流水线的设计也有讲究。不能把所有检查都放在一个阶段那样反馈太慢。合理的做法是分阶段快速检查语法、风格放在前面几秒钟出结果重量级检查AST比对、依赖分析放在后面几十秒出结果。这样大部分低级问题能在第一时间被拦截不用等完整流程跑完。另外CI的检查规则需要定期更新。项目在演进组件的命名规范、目录结构都可能变化检查规则也要跟着调整。我一般建议每个月review一次CI规则把误报率高的规则调松把漏报率高的规则调紧。3. 核心细节解析与实操要点3.1 上下文注入的具体做法上下文注入的关键是“喂什么”和“怎么喂”。喂少了AI还是会重复造轮子喂多了token消耗大而且可能干扰AI的判断。我的经验是分三层注入第一层是组件索引。把项目里所有可复用组件的名称、功能描述、所在路径整理成一个索引文件。这个文件不需要包含完整代码只需要包含签名和一句话描述。比如- formatDate(date: Date, format: string): string — 格式化日期支持自定义格式 - parseDate(str: string): Date — 解析日期字符串为Date对象 - isValidDate(date: any): boolean — 判断是否为有效日期这个索引文件放在项目根目录每次AI生成代码前自动读取并注入到prompt中。第二层是相关组件的完整代码。当AI要生成的功能跟某个已有组件高度相关时把那个组件的完整代码也注入进去。比如AI要写一个“格式化日期范围”的功能那就把formatDate的完整实现注入进去让AI知道可以复用。第三层是命名规范和目录结构。把项目的命名约定、目录组织方式也注入进去确保AI生成的代码在风格上跟项目一致。这三层注入的内容加起来大概控制在2000-4000 token之间。太少不够用太多浪费。注意上下文注入的内容需要定期更新。如果组件索引跟实际代码不一致AI会基于错误的信息做判断反而更容易出问题。我一般会在CI里加一个检查确保索引文件跟实际组件同步。3.2 AST比对的实现细节AST比对的实现不同语言有不同的工具。JavaScript/TypeScript用babel/parserPython用内置的ast模块Java用javaparser。核心流程是一样的把源代码解析成AST遍历AST提取函数级别的结构特征把特征向量化计算相似度超过阈值就标记为疑似重复特征提取是关键。我一般提取以下几类特征函数签名参数数量、参数名、返回类型调用的方法函数体内调用了哪些方法按调用顺序排列控制流有多少个if/else、循环、try/catch字面量函数体内出现的字符串、数字常量把这些特征拼成一个向量然后用余弦相似度计算。阈值一般设在0.85左右。超过0.85的标记为“高度疑似重复”需要人工确认0.7到0.85之间的标记为“可能重复”在CI里给出警告但不阻断。这里有个坑不同语言的AST结构差异很大特征提取的逻辑需要分别实现。我见过有人想用一套通用的特征提取逻辑覆盖所有语言结果准确率惨不忍睹。老老实实按语言分别实现虽然工作量大一点但效果靠谱得多。3.3 CI流水线的分阶段设计CI流水线我一般分成三个阶段阶段一快速检查目标时间 10秒语法检查代码风格检查ESLint/Pylint提交信息格式检查这个阶段跑得飞快基本上提交后几秒钟就能出结果。大部分低级错误在这里就被拦截了。阶段二结构检查目标时间 60秒AST比对检测重复代码依赖分析检测循环依赖组件索引同步检查这个阶段稍微慢一点但也就一分钟左右。如果发现重复代码CI会给出具体的重复位置和建议的合并方案。阶段三集成检查目标时间 5分钟单元测试集成测试构建产物检查这个阶段最慢但也是最全面的。只有前面两个阶段都通过了才会进入这个阶段。分阶段的好处是反馈快。大部分问题在前两个阶段就解决了不用等完整的测试跑完。开发者的体验好很多不会因为一个拼写错误等五分钟。3.4 组件归档的自动化流程当AI生成的代码通过所有检查后需要自动归档到组件库中。这个流程包括自动分类根据代码的功能自动归入对应的目录。比如日期相关的归入utils/date/字符串相关的归入utils/string/。自动生成索引条目提取函数的签名和描述追加到组件索引文件中。自动生成测试用例如果AI生成的代码没有附带测试自动生成一个基础的测试用例确保至少有基本的覆盖。自动更新文档如果项目有自动生成的API文档触发文档重新生成。这个流程用CI的post-build钩子来实现。每次主分支有新的提交就自动跑一遍归档流程。实操心得归档流程一定要做成幂等的。也就是说同一个组件重复归档多次结果应该是一样的。否则CI重跑的时候会产生重复的索引条目。我一般会在归档前先检查索引里是否已存在同名组件存在就跳过。3.5 命名规范与目录结构的约束AI生成的代码最容易出问题的地方就是命名。同一个功能AI可能这次叫formatDate下次叫dateFormat再下次叫formatDateString。如果不加约束组件库很快就会变得混乱不堪。我的做法是在项目里定义一个命名规范文件然后在CI里强制检查。规范包括函数名统一用驼峰式动词开头工具类统一放在utils/目录下按功能分子目录常量统一用大写加下划线类型定义统一放在types/目录下CI检查的时候如果发现命名不符合规范直接阻断提交并给出修改建议。这样虽然一开始有点烦但坚持一段时间后整个项目的命名一致性会好很多。另外目录结构也需要约束。我一般会在项目根目录放一个.structure文件定义允许的目录层级和每个目录的用途。CI检查时如果发现文件放在了不该放的目录下也会阻断提交。4. 实操过程与核心环节实现4.1 环境准备与工具选型先说一下我用的工具栈这套组合在多个项目里验证过比较稳工具用途选型理由ESLint / Pylint语法和风格检查成熟稳定规则可定制Babel Parser / Python astAST解析社区活跃文档齐全GitLab CI流水线编排跟GitLab深度集成配置简单Docker构建环境隔离保证CI环境一致性Redis组件索引缓存加速索引查询GitLab CI的配置我一般放在.gitlab-ci.yml里分三个阶段stages: - quick-check - structure-check - integration-check quick-check: stage: quick-check script: - npm run lint - npm run style-check only: - merge_requests structure-check: stage: structure-check script: - npm run ast-compare - npm run dependency-check only: - merge_requests integration-check: stage: integration-check script: - npm run test - npm run build only: - main这个配置的意思是快速检查和结构检查只在合并请求时触发集成检查只在主分支合并时触发。这样日常开发时反馈快主分支合并时检查全。4.2 AST比对脚本的实现AST比对脚本我用Node.js写了一个核心逻辑大概两百行。关键部分如下const parser require(babel/parser); const traverse require(babel/traverse).default; function extractFeatures(code) { const ast parser.parse(code, { sourceType: module, plugins: [typescript, jsx] }); const features []; traverse(ast, { FunctionDeclaration(path) { const params path.node.params.map(p p.name); const returnType path.node.returnType ? path.node.returnType.typeAnnotation.type : unknown; const calls []; path.traverse({ CallExpression(innerPath) { if (innerPath.node.callee.name) { calls.push(innerPath.node.callee.name); } } }); features.push({ name: path.node.id.name, params, returnType, calls, paramCount: params.length }); } }); return features; } function cosineSimilarity(vecA, vecB) { const dotProduct vecA.reduce((sum, a, i) sum a * vecB[i], 0); const magA Math.sqrt(vecA.reduce((sum, a) sum a * a, 0)); const magB Math.sqrt(vecB.reduce((sum, b) sum b * b, 0)); return dotProduct / (magA * magB); }这个脚本会遍历项目里所有的JS/TS文件提取每个函数的特征然后两两比对找出相似度超过阈值的函数对。实际跑的时候一个中等规模的项目大概500个文件跑完大概需要30秒左右。如果项目更大可以考虑用Worker线程并行处理。注意AST解析对代码的语法要求比较严格。如果项目里有语法错误的文件解析会直接报错。所以快速检查阶段一定要先跑语法检查确保所有文件都能正常解析。4.3 组件索引的生成与维护组件索引我用一个JSON文件来维护结构如下{ version: 1.0, lastUpdated: 2025-01-15T10:30:00Z, components: [ { name: formatDate, path: utils/date/formatDate.ts, signature: formatDate(date: Date, format: string): string, description: 格式化日期支持自定义格式, tags: [date, format], usageCount: 23 } ] }这个文件由CI自动生成和维护。每次主分支有新的组件归档时CI会自动更新这个文件。生成索引的脚本逻辑是遍历utils/目录下所有的文件用AST解析提取函数签名和JSDoc注释然后生成索引条目。function generateIndex(dir) { const files glob.sync(${dir}/**/*.ts); const components []; files.forEach(file { const code fs.readFileSync(file, utf-8); const ast parser.parse(code, { sourceType: module, plugins: [typescript] }); traverse(ast, { ExportNamedDeclaration(path) { if (path.node.declaration path.node.declaration.type FunctionDeclaration) { const fn path.node.declaration; components.push({ name: fn.id.name, path: file, signature: extractSignature(fn), description: extractJSDoc(code, fn.id.name), tags: extractTags(file) }); } } }); }); return { version: 1.0, lastUpdated: new Date().toISOString(), components }; }这个索引文件在AI生成代码前会被读取并注入到prompt中。注入的时候只取name、signature、description三个字段控制token消耗。4.4 上下文注入的prompt模板上下文注入的prompt模板我调了很多版最终稳定下来的版本大概长这样你正在为一个已有的项目生成代码。项目里已经有一些可复用的组件请优先使用这些组件不要重复造轮子。 已有的组件索引 {{componentIndex}} 命名规范 - 函数名用驼峰式动词开头 - 工具类放在utils/目录下 - 常量用大写加下划线 目录结构 - utils/date/ — 日期相关工具 - utils/string/ — 字符串相关工具 - utils/array/ — 数组相关工具 请根据以下需求生成代码 {{requirement}}这个模板的关键是把约束条件放在需求前面。这样AI在理解需求之前先知道了有哪些可复用的东西生成的时候就会优先考虑复用。实测下来用了这个模板之后重复代码的产生率大概降低了70%左右。当然不能完全消除但已经好很多了。4.5 CI流水线的完整配置完整的GitLab CI配置我放在下面可以直接抄image: node:18 stages: - quick-check - structure-check - integration-check - archive variables: COMPONENT_INDEX: component-index.json quick-check: stage: quick-check script: - npm ci - npx eslint src/ --ext .ts,.tsx - npx prettier --check src/ rules: - if: $CI_PIPELINE_SOURCE merge_request_event structure-check: stage: structure-check script: - npm ci - node scripts/ast-compare.js --threshold 0.85 - node scripts/dependency-check.js - node scripts/index-sync-check.js rules: - if: $CI_PIPELINE_SOURCE merge_request_event integration-check: stage: integration-check script: - npm ci - npm run test - npm run build rules: - if: $CI_COMMIT_BRANCH main archive: stage: archive script: - npm ci - node scripts/generate-index.js - node scripts/update-docs.js - git add $COMPONENT_INDEX - git commit -m chore: update component index [skip ci] - git push rules: - if: $CI_COMMIT_BRANCH main这个配置里archive阶段会在主分支合并后自动更新组件索引并提交。提交信息里加了[skip ci]避免触发新的流水线形成死循环。实操心得archive阶段的git push需要配置好权限。我一般用一个专门的CI token只给仓库的写权限不给其他权限。这样即使token泄露影响也可控。4.6 实际效果与数据这套闭环在一个大概30人的前端团队里跑了半年效果还是比较明显的指标上线前上线后重复组件数量47个12个平均组件复用率23%68%代码审查中重复代码相关评论35%8%新功能开发平均耗时3.2天2.1天重复组件数量从47降到12剩下的12个是历史遗留正在逐步清理。组件复用率从23%提升到68%意味着大部分新功能都能找到可复用的组件不用重新写。代码审查中关于重复代码的评论从35%降到8%审查者的负担轻了很多。新功能开发平均耗时从3.2天降到2.1天主要省在“找有没有现成的”和“写重复代码”这两件事上。当然这套东西不是银弹。它解决的是“重复造轮子”的问题但解决不了“轮子本身设计得不好”的问题。如果组件库里的组件质量参差不齐复用反而会引入新的问题。所以组件库本身的质量把控也很重要这个后面会讲。5. 常见问题与排查技巧实录5.1 AST比对误报怎么办AST比对最常见的误报是“结构相似但功能不同”。比如两个函数都是“从对象里取某个字段”但取的字段不同功能上不应该合并。解决方法是在特征提取时加入字段名。上面那个例子如果特征里包含了字段名namevsemail相似度就会降下来。另一个误报来源是“包装函数”。比如function getUserName(user) { return user.name; } function getUserEmail(user) { return user.email; }这两个函数结构完全一样只是字段名不同。如果特征里不包含字段名相似度会很高误报为重复。我的做法是在特征向量里加入“访问的属性名”这一维度。这样name和email会被识别为不同的特征相似度自然就降下来了。5.2 CI流水线太慢怎么优化CI流水线慢是常见问题。我一般从几个方面优化第一缓存依赖。npm ci每次都要重新下载依赖很慢。用GitLab CI的cache功能把node_modules缓存起来第二次跑就快很多。cache: key: ${CI_COMMIT_REF_SLUG} paths: - node_modules/第二并行执行。快速检查和结构检查可以并行跑不用串行。GitLab CI里用parallel关键字就能实现。第三增量检查。只检查本次提交改动的文件而不是全量检查。用git diff找出改动的文件只对这些文件跑AST比对。CHANGED_FILES$(git diff --name-only origin/main...HEAD | grep -E \.(ts|tsx)$) node scripts/ast-compare.js --files $CHANGED_FILES这三个优化做完CI流水线的总耗时能从5分钟降到1分钟左右。5.3 组件索引跟实际代码不同步组件索引跟实际代码不同步是个很烦的问题。索引里说有个formatDate组件实际去找发现已经被删了。或者索引里没有某个组件但实际上代码里有。解决方法是在CI里加一个同步检查。每次合并请求时自动比对索引文件和实际代码发现不一致就阻断提交。function checkIndexSync() { const index JSON.parse(fs.readFileSync(component-index.json, utf-8)); const actualComponents scanComponents(utils/); const indexNames new Set(index.components.map(c c.name)); const actualNames new Set(actualComponents.map(c c.name)); const missingInIndex [...actualNames].filter(n !indexNames.has(n)); const missingInCode [...indexNames].filter(n !actualNames.has(n)); if (missingInIndex.length 0 || missingInCode.length 0) { console.error(索引与代码不同步); console.error(索引中缺失, missingInIndex); console.error(代码中缺失, missingInCode); process.exit(1); } }这个检查跑得很快几秒钟就能出结果。加上之后索引和代码基本不会再出现不同步的情况。5.4 AI生成的代码质量不稳定AI生成的代码质量不稳定是另一个常见问题。同一个需求这次生成的代码很规范下次生成的就很随意。解决方法是在prompt里加入更多的约束。除了命名规范和目录结构还可以加入必须写JSDoc注释必须处理边界情况null、undefined、空数组必须写单元测试函数长度不超过50行这些约束写进prompt后AI生成的代码质量会稳定很多。当然不能保证100%符合但至少大部分情况下是OK的。另外CI里的检查也要跟上。如果AI生成的代码没有写测试CI直接阻断。这样倒逼AI或者说使用AI的人把测试补上。5.5 团队成员的接受度问题这套闭环刚上线的时候团队里是有抵触的。主要原因是“太麻烦了每次提交都要等CI跑完”。我的应对策略是先在小范围试点用数据说话。先在一个小组里跑一个月把重复代码减少的数据、开发效率提升的数据拿出来然后在团队会议上分享。数据摆在那里抵触情绪就少了很多。另外CI的反馈速度一定要快。如果每次提交都要等五分钟谁都会烦。把快速检查控制在10秒以内大部分问题几秒钟就能发现体验就好很多。还有一个技巧是把CI检查结果可视化。在GitLab的合并请求页面里直接显示“本次提交发现3处疑似重复代码”并附上具体的文件位置和建议的合并方案。这样开发者一眼就能看到问题不用去翻CI日志。5.6 常见问题速查表问题可能原因解决方法AST比对误报率高特征提取不够细加入字段名、字面量等特征CI流水线太慢全量检查、无缓存增量检查、缓存依赖、并行执行索引与代码不同步缺少同步检查CI里加索引同步检查AI生成代码质量不稳定prompt约束不够加入更多约束条件团队成员抵触反馈慢、看不到价值加快反馈、用数据说话组件归档重复归档流程非幂等归档前检查是否已存在命名不一致缺少强制检查CI里加命名规范检查目录结构混乱缺少结构约束定义.structure文件并检查6. 组件库质量把控与持续演进6.1 组件入库的质量门槛组件库不是垃圾桶不能什么代码都往里扔。我一般设三道门槛第一道是功能完整性。组件必须能独立完成一个明确的功能不能是半成品。比如一个日期格式化组件必须支持常见的格式不能只支持YYYY-MM-DD一种。第二道是测试覆盖率。组件的单元测试覆盖率必须达到80%以上。没有测试的组件不允许入库因为没法保证它的行为在后续修改中保持不变。第三道是文档完整性。组件必须有JSDoc注释说明参数、返回值、使用示例。没有文档的组件别人不知道怎么用复用率自然就低。这三道门槛在CI里自动检查。不满足的组件CI直接阻断不允许归档。6.2 组件的版本管理与废弃机制组件库是活的会不断有新组件加入也会有旧组件被废弃。如果没有版本管理和废弃机制组件库会越来越臃肿。我的做法是给每个组件加一个status字段取值包括active、deprecated、removed。新组件默认是active。当某个组件被更好的组件替代时标记为deprecated并在文档里说明替代方案。再过一段时间如果确认没有地方引用了标记为removed从索引里移除。CI里加一个检查如果代码里引用了deprecated的组件给出警告如果引用了removed的组件直接阻断。function checkDeprecatedUsage(code) { const index JSON.parse(fs.readFileSync(component-index.json, utf-8)); const deprecated index.components.filter(c c.status deprecated); const removed index.components.filter(c c.status removed); deprecated.forEach(c { if (code.includes(c.name)) { console.warn(警告使用了已废弃的组件 ${c.name}建议替换为 ${c.replacement}); } }); removed.forEach(c { if (code.includes(c.name)) { console.error(错误使用了已移除的组件 ${c.name}); process.exit(1); } }); }6.3 定期review与规则调优这套闭环不是一劳永逸的。项目在演进团队在变化规则也需要跟着调整。我一般每个月做一次review内容包括检查CI规则的误报率和漏报率调整阈值检查组件库的使用情况找出复用率低的组件分析原因检查命名规范和目录结构是否还适用必要时调整收集团队成员的反馈看看哪里可以优化review的结果会更新到CI配置和prompt模板里。这样闭环本身也在不断进化越来越贴合项目的实际需求。6.4 从组件库到领域模型的演进当组件库积累到一定规模后可以考虑往领域模型的方向演进。所谓领域模型就是把组件按业务领域组织形成更高层次的抽象。比如日期相关的组件可以进一步抽象成“时间轴”、“日程”、“周期”等领域概念。字符串相关的组件可以抽象成“文本解析”、“模板渲染”等领域概念。这样做的好处是AI在生成代码时不仅知道有哪些底层组件可用还知道有哪些领域概念可以复用。生成的代码会更贴近业务而不是一堆底层组件的堆砌。当然这一步的难度比较大需要对业务有深入的理解。我一般建议先把组件库跑稳积累半年到一年的数据再考虑往领域模型演进。7. 一些踩过的坑和最后的建议这套闭环我在三个项目里落地过踩的坑不少挑几个印象深刻的说说。第一个坑是过度设计。一开始我想做一套很完美的系统支持多语言、支持自定义规则、支持可视化配置。结果做了两个月还没上线。后来砍掉了一半功能只保留最核心的AST比对和CI检查一周就上线了。上线之后根据实际反馈再逐步加功能反而更顺利。所以我的建议是先跑通最小闭环再逐步完善。第二个坑是忽略了人的因素。技术方案再好如果团队成员不愿意用也是白搭。我一开始只关注技术实现没考虑开发者的体验。结果CI太慢、误报太多大家怨声载道。后来把CI速度优化到10秒以内误报率降到5%以下大家的接受度就高了很多。所以技术方案的设计一定要考虑使用者的体验。第三个坑是索引更新不及时。有一次一个核心组件被重构了但索引没更新。结果AI基于旧的索引生成代码引用了已经不存在的接口导致构建失败。后来加了索引同步检查这个问题就没再出现过。所以索引的同步检查是必须的不能省。第四个坑是阈值设得太死。AST比对的阈值一开始设的是0.9结果漏报很多。后来调到0.85又误报很多。最后发现不同语言的阈值应该不一样JS/TS设0.85Python设0.8Java设0.88。所以阈值需要按语言分别调优不能一刀切。最后分享一个小技巧在prompt里加入“如果你发现已有组件可以复用请直接引用不要重新实现”这句话。这句话看起来很简单但效果很明显。AI看到这句话后会主动去索引里找可复用的组件而不是直接生成新代码。实测下来重复代码的产生率又降低了大概15%。这套闭环说到底就是一件事让AI生成的代码在进入项目之前先过一遍自动化的检查、去重、归档流程。技术本身不复杂难的是坚持执行和持续调优。但只要跑起来了效果是实实在在的。
返回列表