当前位置: 首页 > news >正文

AI工程师系列——面向copilot编程

前言

笔者已经使用copilot协助开发有一段时间了,但一直没有总结一个协助代码开发的案例,特别是怎么问copilot,按照什么顺序问,哪些方面可以高效的生成需要的代码,这一次,笔者以IP解析需求为例,沉淀一个实践案例,供大家参考

当然,其实也不局限于copilot本身,类似的VsCode插件有很多,本文也只是拿chat的AI大模型做例子,只要是deepseek-v3就好

需求文档

为了聚焦,具体需求做了些抽象,简单的说,需要对系统一个IP解析功能进行更新:

1.以前使用了A库和B库进行解析,现在需要增加C库进行解析,

2.需要对三个库解析的结果进行优先级判断,确保把最优结果进行输出

前期准备

这一步很重要,因为很多时候当我们拿到需求文档的时候,希望直接给到IDE的AI助手,结果一般事与愿违,因为AI助手适合在一个限定范围内学习和给出高质量意见

所以要做一些简单前期工作——目的是让copilot学习尽量少的代码资料,从而减少幻觉的输出

1.写代码把C库加载进来

最好把三个库加载的代码先尽量写到一个文件中,比如:

func init() {slog.Info("loading A.dat file")if info, err := os.Stat("A.dat"); err == nil && !info.IsDir() {slog.Info("A.dat file loading from /data/A.dat")tobdb, err = ipcity.LoadV2("/data/A.dat")if err != nil {slog.Error("load /data/A.dat file fail")panic("cannot initialize A data")}} slog.Info("loading B.dat file")if info, err := os.Stat("B.dat"); err == nil && !info.IsDir() {slog.Info("B.dat file loading from /data/B.dat")tobdb, err = ipcity.LoadV2("/data/B.dat")if err != nil {slog.Error("load /data/B.dat file fail")panic("cannot initialize B data")}} slog.Info("loading C.dat file")if info, err := os.Stat("C.dat"); err == nil && !info.IsDir() {slog.Info("C.dat file loading from /data/C.dat")tobdb, err = ipcity.LoadV2("/data/C.dat")if err != nil {slog.Error("load /data/C.dat file fail")panic("cannot initialize C data")}} 
}

这里有两个注意的点:

(1) 以终为始:

我们是希望copilot能够准确的学习到这是三个库的加载方法,所以这里要写的教条一点:即三个函数相似度要高,而且要通过注释、日志反复增强对函数作用的说明,这样copilot会更准确的学习这里的业务逻辑

(2)日积月累:

如果前期代码就是这样“教条”的撰写风格,那么这段代码本身就可以用copilot生成

2.找到解析函数代码

IP解析函数中,要包含对A、B库的调用及综合算法

因为涉及综合算法,最好把综合算法放到一个文件中,这样copilot就可以读更少的文件

然后把确定输入代码的地方,写个注释,表示要在这里写

比如:

// ParseIP parse passed in ip string and return country, region, city, isp.
func ParseIP(clientIP string) (ip, country, region, city, isp string) {ip = clientIPswitch IPLibraryVersion {case "v1":、、、case "v2":// patch result from C// patch result from AresultA := A.Search(net.ParseIP(clientIP))if meta != nil {country = meta.Country()region = meta.Province()city = meta.City()isp = meta.ISP()}// patch result from B, espicially for ISPresultB := B.Search(net.ParseIP(clientIP))if resultB != nil {if country == "" || country == "未知" { // if cannot found country from A, then turn to Bcountry = resultB.Country()region = resultB.Province()city = resultB.City()isp = resultB.ISP()} else if (strings.HasPrefix(isp, "Error") && (B.ISP() != "未知" && B.ISP() != "")) || isp == "未知" || isp == "" { // if B's  ISP is prefix with 'Error', so replace it with tobdb's ISPisp = B.ISP()}}

这里也有两个注意的点:

(1)写好注释:

一般来说,写注释是研发同学最难以为继的事情,但随着copilot的到来,大家可以写完一个函数后,让copilot帮忙写注释,对于研发同学来说,甚至只需要输入“//”,然后等待copilot生成就好

(2)变量简单命名:

除了注释,变量名的清晰明了也是可以让copilot来更好的学习,同时,这里最好写的比较有规律,比如resultA、resultB,这样剩下的变量名也可以自助生成

3.把相关的文件放到copilot中,选择deepseek- v3模型

请在此添加图片描述

这里Copilot类似工具有很多,笔者用的是VSCode的IDE,大家可以随意选择,本质上是DeepSeek-v3模型就好

开始提效

这一步就需要把需求文档的内容,进行输入,当然,很多时候,需求充满着未添加的背景信息和口语的表述,作为一名研发,有时需要做一些逻辑转换用语

一、输入清晰的业务逻辑

这里可以看一个业务逻辑输入示例:

我想写一段逻辑,现在有三种数据源获取了country,region,city,isp四个数据,我希望A库的数据优先级最高,只有当A库的country识别不出来,或者country识别出来,但region的识别不出来的时候,才使用B库的数据;然后只有B库识别isp为“Error”打头时或者为空或者为“未知”,且C库识别isp不为空或者“未知”,才使用C库数据,如果三者都识别不出来,ISP如果有英文则用英文的版本,否则用A;其中一个重要逻辑是,最后使用的country,region,city,isp必须整体使用某一个数据源,且如果region识别为国内的广东等省必须加省后缀…

这是一个失败的表述,虽然可能完全来自与需求文档/会议结论/邮件输出,但对于copilot来说,逻辑十分的混乱

我们来分析下为什么混乱:

  1. 没有按照1、2、3标题,这让copilot难以分段
  2. 逻辑这里最终输出是if、while的类型,所以需要写清晰优先级
  3. “其中一个重要逻辑”,这种十分的口语,其实对于程序员也会难以理解
  4. 最后的特殊逻辑,太过于细节,可以在生成基础代码的基础上再进行“优化”

!17 “看到这里,很多读者可能也觉得这个逻辑十分混乱,但笔者想说的是,这是一个真实的业务内容,之所以大家觉得逻辑混乱是因为,撰写的人具备大量的背景知识,所以撰写者觉得清晰明了,但其他人和copilot完全不知所云!”!

那怎么才能写出清晰的业务逻辑输入呢?

笔者认为:清晰的逻辑输入需要清晰的输入格式

我重新梳理一下规则,1,代码实现在ParseIP的v2逻辑路径中;2.三个数据源分别来自resultA、resultB、resultC,最终要选择某一个的数据源来获取country,region,city,四个数据,3.第一优先级是获取resultA的数据,当resultA分析的country为空/未知或者region为空/未知时,才用resultB数据;4.第二优先级是获取resultB数据,当resultB分析的country为空/未知或者region为空/未知时,才使用resultC数据;5.如果三者都识别不出来,ISP如果有英文则用英文的版本,否则用A,帮我写下这个代码

这里对上述的问题进行了修正,同时增加几点优化:

  1. 而且明确了代码撰写在什么地方,更加限定了copilot的使用场景
  2. 描述逻辑时用了大量相似的语句,减少的copilot分析难度,即输入“教条”一些

我们看下结果:

case "v2":// 从三个数据源获取信息resultA := A.Search(net.ParseIP(clientIP))resultB := B.Search(net.ParseIP(clientIP))resultC := C.Search(net.ParseIP(clientIP))// 定义最终使用的数据源var finalSource *IPInfo// 第一优先级:resultAif resultA != nil && resultA.Country() != "" && resultA.Country() != "未知" &&resultA.Province() != "" && resultA.Province() != "未知" {finalSource = resultA} else {// 第二优先级:resultBif resultB != nil && resultB.Country() != "" && resultB.Country() 

相关文章:

  • 配电网运行状态综合评估方法研究
  • 使用 mutt 发送邮件:Linux 下轻量高效的命令行邮件工具
  • NV009NV010美光闪存颗粒NV011NV012
  • Java面试问题基础篇
  • BISS0001 PIR红外感应IC:高性能热释电信号处理解决方案
  • DNS服务搭建与配置详解
  • JS手写代码篇---手写Promise
  • 【NLP】基于JointBERT的意图识别
  • 基于JDBC的信息管理系统,那么什么是JDBC呢?什么又是DAO类?
  • DDI核心网络服务是什么意思?有什么用?
  • 模板初阶【C++】
  • drop tablespace XXX including contents and datafiles删除表空间后,磁盘空间不释放
  • LlamaIndex
  • 46页 @《人工智能生命体 新启点》中國龍 原创连载
  • 【209. 长度最小的子数组】
  • DL00988-稀疏增强数据transformer船舶AIS轨迹预测含完整数据集
  • 开源免费抓包工具:ProxyPin 的详细使用
  • [TCG] 01.QEMU TCG 概览
  • Oracle BUFFER CACHE内存不足的优化思路
  • 多线程(七)
  • 提供东莞网站制作公司/怎样才能在百度上发布信息
  • 做手机网站哪家好/百度搜索推广和信息流推广
  • 合肥网站制作联系方式/网络营销考试答案
  • 上海热线网站建设/爱站seo工具包下载
  • 网站不用域名需要备案吗/注册网站多少钱