接手公司一个维护了5年的Spring Boot老项目,JDK8+MyBatis+JSP那套。最近用GitHub Copilot做重构,发现它特别爱推荐已经废弃的API,比如还在用RestTemplate而不是WebClient,甚至生成@SuppressWarnings来绕过编译警告。我试过在对话里强调“用最新稳定版语法”,但感觉它更吃上下文里的旧代码风格。想问下大家,是应该建个.github/copilot-instructions.md写清楚技术栈版本,还是直接在代码里多用新写法“喂”它?另外,遇到它生成的代码和项目现有工具类冲突时,大家是硬改还是干脆只让它写单元测试?有点纠结,怕重构完反而埋雷。
Copilot在重构老项目时总给出过时API,怎么调教它?
全部回复
共 55 条copilot确实特别吃上下文,你项目里旧代码多它就容易照着老路子走,我试过在instructions里写死“禁止使用RestTemplate”和JDK版本,效果比对话里强调强不少。另外我建议你重构到哪个文件就顺手把新写法多铺几处,喂几次它就能学过来,比硬改快。至于冲突,我一般是让它生成独立的新类,不直接动老工具类,最后再手动替换,省得它越改越乱。
说实话instructions那个文件我建了,但感觉它优先级没那么高,有时候还是按上下文来。我现在干脆把老代码里关键部分先注释掉,逼着它只能看新写的逻辑,效果反而好。冲突的话,我基本只让它写单测,业务代码自己改,毕竟它不懂你们项目里的坑。
我试过写copilot-instructions.md,但感觉它更认你当前打开文件里的风格,所以我现在重构前会先把目标文件里老API全手动标废,再让它补全,这样它给的方案基本都是新的。工具类冲突直接改吧,别指望它自己处理,我上次让它“适配现有工具类”,它给我写了个四不像的包装层,还不如自己改两行。
两个都试过,copilot-instructions.md管点用,但不如你手写几个新API示例来得直接,冲突代码我一般硬改。
这问题太真实了,Copilot就是个上下文复读机,你项目里全是RestTemplate它肯定照着写。我试过在instructions里写死“禁止使用已废弃API”,效果比对话里喊话强点,但遇到工具类冲突还是得靠自己。我的做法是让它生成独立的小函数或测试用例,涉及老代码改造的部分干脆手写,不然改它的错误比重写还累。
说实话我更建议双管齐下,instructions文件得写清楚JDK版本和禁用列表,但代码里喂新写法也真有用,我试过把老接口逐个替换成新API之后,Copilot的推荐明显靠谱多了。至于工具类冲突,我一般直接让它生成完再手动改,毕竟硬改有时候反而破坏它后续的上下文理解。另外你可以试试在prompt里贴一段新写法的示例代码,比单纯说“用最新版”管用得多。
两个法子都得用,instructions写清楚版本,代码里新写法喂多了它自然就改过来了,冲突时直接让它写测试最省心。
俩办法我都试过,copilot-instructions.md确实管用,但得写得很细,光写技术栈版本不够,最好把禁用的API和替代方案直接列出来。另外你得接受它就是个“上下文复读机”,老项目里旧代码太多,它就默认你活在五年前,所以我会先把新写法在关键文件里铺一遍再让它干活。至于冲突,我一般让它生成独立方法,自己写胶水层去适配,硬改它的代码太费劲,不如控制边界来得省心。
说实话两种方法都得试,但我觉得copilot-instructions.md优先级更高,毕竟它吃的是项目全局配置,比你在对话里喊两嗓子管用多了。另外我踩过的坑是,老项目里工具类冲突这问题无解,硬改成本太高,我现在基本只让它生成测试和SQL,生产代码还是自己动手改,省得它拿旧写法糊弄我。
我最近也踩过这坑,同款老项目重构,后来发现光靠对话提示没用,得在项目根目录放个copilot-instructions.md,把JDK版本、禁止用的API列表全写进去,它立马老实多了。至于冲突代码,我一般只让它写测试和DTO,核心逻辑还是自己改,不然越重构越乱。另外你试试把新写的WebClient代码多贴几段给它看,喂几次它就学乖了。
建议直接写copilot-instructions.md锁死版本,再配合代码里新写法喂它,双管齐下比光靠对话强多了。
遇到冲突别硬改,让它生成工具类方法,项目里做适配层,省得越重构越乱。
两个都试试,但copilot-instructions.md优先级更高,喂代码见效慢得憋屈。
我这边是直接让它写测试,重构逻辑自己来,省得跟它的老毛病较劲。
个人经验是两条腿走路:先在项目根目录放copilot-instructions.md,把JDK版本、禁用的API列表写清楚,它立刻老实很多。另外重构时我会故意先写几个新语法的示例代码,让Copilot跟着学,比口头强调管用。至于冲突,我一般让它生成独立工具类,自己再手动适配老代码,硬改容易埋雷。你试试把老接口先标记@Deprecated,它也会收敛些。
这问题我太有同感了,Copilot在旧代码库里确实会“学坏”,因为它最大的权重来自你当前文件的上下文,你项目里全是RestTemplate,它当然觉得这就是“标准答案”。我个人试下来,.github/copilot-instructions.md比对话里强调版本号管用得多,但别指望它一次就听话,得把“禁止使用RestTemplate,统一用WebClient”这种硬性规则写进去,甚至可以把常用工具类的包路径也列上,它生成的冲突代码会少一大截。至于和现有工具类打架这事,我现在的策略是让它写纯逻辑和测试,涉及到项目基建的代码就自己动手改,毕竟老项目的坑有时候连人都不一定看得全,更别说AI了。还有个小技巧,就是重构时故意在关键文件开头留几行新写法的示例,相当于给它“投喂”正确的风格,比单纯骂它管用。你试过给它看你们项目里最新的某个controller吗?有时候把新代码作为参考片段贴进对话,比写一堆规则更直接。
这问题我太有同感了,Copilot对旧代码库的“路径依赖”确实严重。我之前试过在对话里反复强调版本,效果还不如直接在项目里加一个copilot-instructions.md,把关键依赖的版本号和禁用API列表写清楚,它至少不会再主动生成RestTemplate这种了。不过说实话,指望它完全靠指令改掉习惯不现实,老项目里那些JSP和MyBatis的写法它学得太根深蒂固了,我后来是直接在重构的新类里手写一遍WebClient的模板,让它照着这个模板生成其他部分,比纯文字约束管用得多。至于和现有工具类冲突,我的原则是能改它的生成结果就改,别硬掰它去理解你的封装,毕竟它只认标准库和常见框架,自定义的Util它永远猜不透,这时候让它专注写单测反而省心——但前提是你得把测试框架和断言风格也写在instructions里,不然它连Mockito的老写法都给你搬出来。另外提个歪招,你可以把项目依赖里那些废弃类的警告级别调成error,这样Copilot生成的代码编译不过去,它自己就会被迫换新API,比人肉监督效率高,就是一开始会烦到爆炸。
我之前也踩过这坑,后来发现copilot-instructions.md确实管用,但得写得很具体,比如直接列“禁止RestTemplate,用WebClient”这种硬规则。不过更关键的是,你喂给它的代码片段得是最新的,它才会模仿,否则光靠描述它根本抓不住重点。至于冲突,我一般是让它单独出工具类,不碰现有代码,完了自己手动缝合,省得改来改去出bug。你试过在prompt里直接贴一段你想要的写法范例吗,那招对我最有效。
试过类似情况,光靠对话提示真的没用,上下文污染太严重了。建议两条腿走路,copilot-instructions.md里把禁用的API和替代方案写死,同时重构到哪个文件就先手动改一两处新写法,让它跟着学。至于工具类冲突,我一般直接让它生成独立方法,自己再包一层适配,硬改它的代码太费时间了。另外可以试试把老依赖版本临时升级到最新,它反而会收敛很多。
我踩过这坑,光写instructions没用,得靠代码里新写法硬掰它的习惯,冲突就硬改别惯着。
强烈建议直接建copilot-instructions.md把版本钉死,比喂代码省心多了,我试过有效。
你这个问题我太有同感了,老项目里全是历史包袱,Copilot确实容易学坏。我试过在项目根目录放copilot-instructions.md,把JDK版本和禁用API列表写清楚,比对话里强调管用得多。另外,遇到工具类冲突我一般直接让它写单测,业务代码还是自己改,毕竟它不理解你们内部封装的历史原因。还有个野路子,把新写的WebClient示例代码多放几个在附近文件里,它有时候能“偷师”成功。
两个都试过,最后还是靠instructions文件把版本钉死,比在代码里喂它快多了。至于冲突代码,我直接改成让它写测试,省心不吵架。
我最近也在折腾类似的事,老项目里Spring 4升5的时候Copilot确实爱拿旧习惯往代码里套,感觉它更像在模仿你当前文件里的上下文,而不是全局理解项目意图。你提到的copilot-instructions.md我试过,有点用但别指望它能完全扭转,尤其是碰到那种藏在工具类里的隐式约定时,它照样会忽略。后来我学乖了,先把要重构的模块里那几个核心类手动改成新写法,让Copilot“看见”新风格再让它补剩下的,效果比对话里吼它强多了。至于工具类冲突,我现在基本不改它生成的代码,只让它产出单元测试——测试逻辑简单,就算它写歪了也容易修,但业务代码硬改反而容易把老坑带出来,不如自己直接重写省心。另外提醒一下,RestTemplate这玩意在5.x里其实没被标废弃,只是Spring官方推荐WebClient,Copilot分不清“过时”和“不推荐”的区别,你可以在instructions里明确写“仅使用Spring 5.3+的推荐API,禁止引用已标记@Deprecated的类”,它至少会少抽风一半。