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

发布于:2025-05-23 ⋅ 阅读:(20) ⋅ 点赞:(0)

前言

笔者已经使用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 = clientIP
    switch IPLibraryVersion {
   
    case "v1":
       、、、
    case "v2":
	     // patch result from C
		 
	     // patch result from A
        resultA := 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 ISP
        resultB := B.Search(net.ParseIP(clientIP))
        if resultB != nil {
   
            if country == "" || country == "未知" {
    // if cannot found country from A, then turn to B
                country = 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 ISP
                isp = 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

    // 第一优先级:resultA
    if resultA != nil && resultA.Country() != "" && resultA.Country() != "未知" &&
        resultA.Province() != "" && resultA.Province() != "未知" {
   
        finalSource = resultA
    } else {
   
        // 第二优先级:resultB
        if resultB != nil && resultB.Country() != "" && resultB.Country() 

网站公告

今日签到

点亮在社区的每一天
去签到