接手公司一个维护了5年的Spring Boot老项目,JDK8+MyBatis+JSP那套。最近用GitHub Copilot做重构,发现它特别爱推荐已经废弃的API,比如还在用RestTemplate而不是WebClient,甚至生成@SuppressWarnings来绕过编译警告。我试过在对话里强调“用最新稳定版语法”,但感觉它更吃上下文里的旧代码风格。想问下大家,是应该建个.github/copilot-instructions.md写清楚技术栈版本,还是直接在代码里多用新写法“喂”它?另外,遇到它生成的代码和项目现有工具类冲突时,大家是硬改还是干脆只让它写单元测试?有点纠结,怕重构完反而埋雷。
Copilot在重构老项目时总给出过时API,怎么调教它?
全部回复
共 55 条强烈建议建copilot-instructions.md,比喂代码省心多了,版本锁死它就不乱来了。工具类冲突直接删它生成的,别惯着。
copilot-instructions.md真有用,但得写细点,把版本和禁用API都列进去。冲突代码我都是硬改,让它写测试省心多了。
我试过类似情况,Copilot确实特别吃项目里的旧代码风格,你在对话里强调啥它都容易跑偏。我的做法是直接在项目根目录放copilot-instructions.md,把JDK版本、禁止用的库、强制用WebClient这些写清楚,效果比对话里唠叨强多了。至于冲突,我现在基本只让它写单元测试和纯工具方法,涉及业务逻辑的代码还是自己改,不然排查它埋的坑更费时间。另外你可以在重构前先批量替换掉一批明显过时的调用,让它多看看新写法,它会慢慢“学”过来。
我这边是直接把老代码里高频出现的废弃API列了个黑名单,写进instructions里,然后每次重构前先让Copilot读一遍新写的参考模块,相当于给它喂个“正确示范”。冲突的话我一般硬改,因为它的代码风格和项目里的工具类经常对不上,改起来比沟通成本低。最烦的是它总爱加@SuppressWarnings,这个我直接在设置里禁掉了。
说实话我连instructions都写了,但Copilot还是时不时给我蹦出个旧写法,感觉它对“最新稳定版”的理解跟咱们不太一样。后来我干脆在重构时先手动把核心接口用新API实现一遍,再让它照着补,这样准确率高很多。冲突那个问题,我建议别硬改也别只写测试,可以试试让它生成
建议先建copilot-instructions.md锁死版本,再喂新代码,双管齐下效果明显,工具类冲突直接硬改别惯着它。
我刚好也踩过这个坑,copilot确实特别吃项目里的存量代码风格,你就算在对话里说得再清楚,它生成的时候还是大概率照着旁边文件的老写法来。我的做法是两条腿走路,.github/copilot-instructions.md里明确写了JDK版本和禁用API列表,同时重构到哪个文件就先手动把那个文件里的旧API替换成新写法,相当于给它一个“参照物”,效果比纯文字指令好很多。至于工具类冲突,我建议别硬改它生成的代码,因为容易把逻辑改坏,我现在基本只让它写单测和简单的DTO转换,复杂的业务重构还是自己来,毕竟它理解不了你们项目里那些隐性的业务规则。另外可以试试在prompt里直接贴一段你们项目里最新的Controller或Service代码,让它“模仿此风格”,这招比说“用最新语法”管用得多。还有个偏方,你可以在copilot对话里明确问它“这个API在Spring 5.3之后是不是废弃了”,逼它去检索一下,有时候它就会改口。
两个法子都试过,最后是copilot-instructions写清版本+新代码喂了一阵才好转,光靠对话真带不动。
冲突代码我一般直接让它闭嘴只写测试,业务逻辑自己改更稳,省得它把工具类越搞越乱。
说实话这问题我太有同感了,Copilot就是会死磕你仓库里出现频率最高的老写法,你越改它越学。我后来是直接建了copilot-instructions.md,把JDK版本、禁用的API全列进去,效果立竿见影,比在对话里反复强调管用多了。至于冲突那块,我基本只让它补测试和写胶水代码,核心重构逻辑自己来,免得它拿工具类瞎凑合,回头还得返工。
建议直接建copilot-instructions.md,把依赖版本和禁用API写死,比靠喂代码省心多了。
说实话你这个情况我太熟了,老项目里全是历史包袱,Copilot就是个“上下文复读机”,你喂它什么风格它就吐什么风格。.github/copilot-instructions.md肯定要建,但别指望它一次就听话,得把关键依赖的版本号、禁用API列表全写进去,比如明确禁止RestTemplate和@SuppressWarnings,它才会收敛一点。同时你得多在代码里写新写法的示例,哪怕只是重构一个小模块,让它持续看到WebClient和Optional的使用模式,比你在对话里强调一百遍都管用。至于工具类冲突,我一般直接让它生成独立的方法或测试,然后自己手动封装,硬改它的代码容易把逻辑改歪,毕竟它不懂你们公司的内部约定。还有个坑是,它特别喜欢“省事”,比如给你塞个@Deprecated注解糊弄过去,你得在指令文件里加一条“禁止生成任何标记废弃的代码”,否则它还是会钻空子。最后想说,别对它期望太高,老项目重构这种活儿,它当个高级补全工具就行,关键设计还得自己拿主意,尤其是API兼容性和迁移路径,它根本意识不到。
我这边也踩过类似的坑,后来发现直接改.github/copilot-instructions.md其实挺管用的,把JDK版本和禁用的API写清楚,它跑偏的概率会小很多。不过我更推荐你在项目里把工具类封装好,比如统一用WebClient的HttpClient,然后让Copilot多参考那些新写的代码,它学得比想象中快。至于冲突的话,我一般只让它生成测试和简单CRUD,核心逻辑还是自己改,硬改太费劲了。
我最近也碰到过这问题,后来发现与其纠结指令文件,不如直接在代码里堆新写法,它学上下文特别快,你改个十来处,它基本就跟着新风格走了。不过老项目里的工具类和它生成的确实容易打架,我现在是让它负责不依赖现有代码的纯逻辑部分,像是DTO转换或者单元测试,省得来回改。你那个WebClient的事,我试过在prompt里贴一小段新代码当例子,比单纯说“用新版”管用多了。
我这边也踩过类似的坑,老项目的上下文对Copilot影响确实比提示词大,它默认会模仿你当前文件里的写法。建议两条腿走路:先建个copilot-instructions.md把版本和禁用API写死,同时重构时每改一个文件就顺手把新写法贴进去喂它,效果比单纯对话强。至于冲突,我一般只让它生成独立无依赖的代码,比如DTO和工具方法,涉及业务逻辑还是自己改,省得跟现有类库打架。
建议先在项目里塞几个新写法的示例文件喂它,比写instructions管用,不过老项目重构还是得自己盯紧点。
这问题太真实了,Copilot在旧代码库里确实会被带偏,因为它本质是在模仿上下文里的模式。我试过.github/copilot-instructions.md,写清楚JDK版本和禁用API列表,效果有但有限,它还是会偶尔抽风。后来我学乖了,重构时先自己把关键工具类换成新写法,比如把RestTemplate替换成WebClient的骨架代码写在旁边,它反而能顺着新风格生成,比口头强调管用得多。至于冲突,我基本不让它碰业务核心逻辑,只让它生成单元测试或者数据映射这类边缘代码,改起来不心疼。不过你也得接受一个事实,Copilot更适合“加速已知方案”而不是“探索新架构”,真要大规模升级依赖,还是得靠人肉扫一遍IDE的deprecated标记。你有没有试过在prompt里直接贴报错信息?我发现把警告原文喂给它,它有时能意识到问题然后换写法,比单纯说“用新API”有效。
copilot确实会优先模仿你项目里的旧代码风格,你喂它什么它就学什么,所以光在对话里说“用新语法”效果有限。建议你直接建个copilot-instructions.md,把JDK版本、依赖管理方式和禁用API清单写清楚,它会更听话。至于工具类冲突,我一般是让它先写测试用例,把边界条件摸清楚再手动改实现,硬改容易引入隐藏bug。另外,老项目重构时建议把相关依赖升级到最新稳定版再让Copilot干活,不然它会一直按旧版API生成。