❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

这篇具有很好参考价值的文章主要介绍了❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

总览

你是否好奇 GitHub Copilot 如何知道你想写的内容?有时候它聪明得甚至好像读过你项目里其他文件一样,不要怀疑,它确实读过。这篇文章记录了我阅读一个对 Copilot 的逆向工程的笔记,一言以蔽之,Copilot 使用了 Jaccard 相似度获取用户最近访问过的页面里与当前编辑内容最相似的代码片段,并将其作为注释内容加入 prompt 中送给代码生成模型,以下是更加展开的讲解:

总体来说,copilot 分为两个部分:

  • 客户端:VS Code 扩展收集你键入的任何内容,拼装成 prompt,并将其发送到类似 Codex 的模型。无论模型返回什么,它都会显示在编辑器中。
  • 模型端:类似 Codex (现在或许是更先进的版本)的模型接受提示并返回完成提示的建议。

prompt 工程

prompt 示例

先看一个拼装好的 prompt 示例:

{
  "prefix": "# Path: codeviz\app.py\n# Compare this snippet from codeviz\predictions.py:\n# import json\n# import sys\n# import ti...,
  "suffix": "if __name__ == '__main__':\r\n    app.run(debug=True)",
  "isFimEnabled": true,
  "promptElementRanges": [
    { "kind": "PathMarker", "start": 0, "end": 23 },
    { "kind": "SimilarFile", "start": 23, "end": 2219 },
    { "kind": "BeforeCursor", "start": 2219, "end": 3142 }
  ]
}
  • 一个实际的案例如上图所示

    • 如果有后缀(suffix), 那么会启用插入模式 (模型使用 fill-in-middle 任务的 prompt),否则就是向后补全的模式

      • 根据 codex 官方:插入模式需要使用特殊 token 组装成正确的 prompt 格式,需要更大的 max_length,需要较大温度多采样几次直到 stop_reason 是 'stop',以便更好地连接到后缀代码
    • 可以看到,前缀(prefix)中除了当前光标之前的文档内容,还包含着项目中另一个文件的代码,该 # Compare this snippet from codeviz\\predictions.py: 行及其后续行指代的是与当前文档内容相似的代码片段。模型也就是通过这些相似片段加深对代码上下文的理解https://thakkarparth007.github.io/copilot-explorer/posts/prompt-full

    • ❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

🌟 准备 prompt 的过程

那么 prompt 是如何生成的呢,我们一步步来看看:

  1. Entry point:对给定文档和光标位置提取 prompt。 prompt 生成的主要入口点是 extractPrompt(ctx, doc, insertPos)
  2. 从 VSCode 查询当前文档的相对路径和语言 ID getPromptForRegularDoc(ctx, doc, insertPos).

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  1. 获取相关文档:借助 VSCode 的插件 API 等能力,拿到最近访问的 20 个相同语言的文件,参阅 getPromptHelper(ctx, docText, insertOffset, docRelPath, docUri, docLangId)

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  1. 设置一些选项:

    1. suffixPercent:百分之多少的 token 用于后缀
    2. fimFuffixLengthThreshold:启用 fill-in-middle 的最小后缀长度,默认 -1,也就是后缀里面有字符就会启用
  2. 前缀计算:创建一个 Wishlist,添加不同的“元素”及其优先级,发生在 getPrompt(fs, curFile, promptOpts = {}, relevantDocs = [])

    1. 六种不同的元素:BeforeCursor, AfterCursor, SimilarFile, ImportedFile, LanguageMarker, PathMarker 

      1. languageMarker:e.g., #!/usr/bin/env python3 for python, or Language:

      2. PathMarker:当前文件的 path

      3. ImportedFile:add local import context to the wishlist (似乎只对 typescript 使用)

      4. similarFile:Compare this snippet from path/to/file:

        1. getNeighborSnippers:找出符合条件的片段
        2. addSnippersToWishlist:遍历前者,加入 Wishlist
      5. ❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  1. Wishlist 会按优先级和插入顺序排序,将元素添加到 prompt 中直到达到输入 token 数量限制 PromptWishlist.fulfill(tokenBudget)
  2. 一些选项,例如,NeighboringTabsOption 控制从其他文件中提取片段的力度。某些选项仅针对某些语言定义,如 LocalImportContextOption 仅针对 Typescript 定义。
  3. 后缀计算,只需要用光标后缀 token 填充到 token budget

🌟 片段提取,Jaccard 评分

继续往里看,重要模块:jaccard-scorer、window-matcher

从最近文档提取片段

getNeighborSnipates 主要的处理流程:忽略太长或空的文件 ➡️ 选最近 20 个文件 ➡️ 切片找出所有匹配的片段 (默认使用 bestMatch ,即每个文件找一个最匹配的片段) (注意:nbrMatcher 代表着正在键入的文件的类,每次和一个 curRelFile (相关文件)去匹配出代码片段 snippets 列表和分数)➡️ 滤掉分数低于阈值的 ➡️ 按分数排序 ➡️ 取分数最高的 n 个 matches ➡️ 格式化

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

nbrMatcher

默认情况下,nbrMatcher 使用 “Fixed window Jaccard matcher”,将给定文件(要从中提取片段)切成固定大小的滑动窗口。然后,它会计算每个窗口和参考文件(用户正在键入的文件,存在 this.referenceTokens中)之间的 Jaccard 相似性。仅从每个“相关文件”返回最佳窗口(尽管存在返回前 K 代码段的规定,但从未使用过)。默认情况下,窗口大小是 60 行。

  • 使用的 nbrMatcher 类默认是 fixedxxxxxmatcher,构建该类时,使用用户当前键入的文件生成分词器和词元集合,以供 Jarccard 相似度计算;注意 getWindowsDelineadtions 输入的是文件内容列表,每行是一个列表元素,输出的也是列表,每个元素表示窗口的开始位置和结束位置,后面会用到;

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  • fixedxxxxxmatcher 继承的原始类型,默认使用 findBestMatch,输入 e (待匹配的相关文件),按行切分成列表,另一边通过 retrieveAllSnippets 将 相关文件 切分成固定窗口的片段,按相似度得分降序排列,最后输出相似度最高的片段

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  • 切分片段,计算相似度,并排序的代码如下,首先尝试获取缓存中的代码片段,如果缓存为空,对每行代码分词存入 u。注意外面的 e 和里面的 e 意义不一样(折磨。。。)

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  • 分词类,缓存类

❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记

  • 计算 Jaccard 相似性
function computeScore(e, t) {
  const n = new Set();
  e.forEach((e) => {
    if (t.has(e)) {
      n.add(e);
    }
  });
  return n.size / (e.size + t.size - n.size);
}

Jaccard分数(Jaccard score),也称为Jaccard相似系数(Jaccard similarity coefficient),是一种用于比较两个集合相似性的度量指标。它衡量的是两个集合中共有元素占总元素数量的比例。

Jaccard分数的计算方法如下:

1. 定义两个集合的交集为共有元素的集合,定义两个集合的并集为两个集合中所有不重复的元素的集合。

2. Jaccard分数等于交集的大小除以并集的大小。

数学公式表示为:

Jaccard分数 = |A ∩ B| / |A ∪ B|

Jaccard分数的取值范围是0到1之间,其中0表示两个集合没有共有元素,1表示两个集合完全相同。分数越高表示两个集合越相似。

  • 另一个似乎未使用过的类:“Indentation based Jaccard Matcher”

模型调用

使用两个 UI 提供补全, (a) Inline/GhostText and (b) Copilot Panel

Inline/GhostText

Main module

  • 提供少量建议(1-3)快速响应
  • 清除快速输入时的抖动
  • ❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记
  • 限制某些情况下的请求:如果用户位于一行中间,则仅当光标右侧的字符为空格、右大括号等时,才会发送请求。

通过 Contextual Filter 防止 poor requests

prompt 生成后,该模块会检查 prompt 是否足够好“good enough”决定是否发出请求调用模型。该模块会计算基于一个简单逻辑回归模型计算“contextual filter score”,如果分数低于阈值(默认为 15%),则不会发出请求。模型有 11 个简单特征,例如语言、以前的建议是否被接受/拒绝、先前接受/拒绝之间的持续时间、提示中最后一行的长度、光标前的最后一个字符等。模型权重包含在扩展代码本身中。included in the extension code itself.

例如,以右括号结尾的 prompt 得分就远低于以左括号结尾的 prompt,因为前者一般是用户输入完成了,不希望模型还进行补全。(在插件里还使用了一个机器学习模型也是挺让人惊讶的的)

Copilot Panel

Main module, Core logic 1, Core logic 2.

不显示无帮助的补全

  1. 如果输出重复,建议被丢弃 repeatitive
  2. 如果用户已经输入建议了,丢弃该建议 already typed

遥测

copilot 说:目前有 40% 的代码都是在 ai 帮助下写的?这是怎么测的呢?

如何评测哪些建议被接受?

在插入后的不同时间长度中检查被接受的建议是否存在于代码中;

精确搜索过于严格,因此测量编辑距离,如果插入和串口之间的单词级别编辑距离小于 50%,则建议被视为仍在代码中;

参考

https://thakkarparth007.github.io/copilot-explorer/posts/copilot-internals#secret-sauce-1-prompt-engineering文章来源地址https://www.toymoban.com/news/detail-650556.html

到了这里,关于❤️ GitHub Copilot 读心术揭秘,Copilot 逆向工程笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解决xorm逆向工程问题

    问题 xorm : 无法将“xorm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 今天在用xorm做逆向工程的时候碰到了一个普遍问题,xorm : 无法将“xorm”项识别为 cmdlet、函数、脚本文件或可运行程序的名

    2024年02月05日
    浏览(50)
  • Android 逆向工程,反编译心得

    apk的反编译是我们在Android开发中绕不开的一个坎,对于反编译这门技术,我们应该抱着学习的态度,学的越多,也越能防备别人反编译我们,这就是所谓的知己知彼吧,哈哈 Apktool ,解包和重新打包都需要它 dex-tools ,可以直接把apk中的classes.dex文件反编译为.jar文件 jd-gui ,

    2024年02月06日
    浏览(166)
  • ARM软件逆向工程入门 00

    ARM指令集是一种低功耗、小尺寸和低成本的指令集,它具有以下特点: ARM指令集具有良好的可移植性,可以在不同的架构上运行; ARM指令集支持32位和64位,减少指令的数量,提高运行效率; ARM指令集支持硬件加速,可以更有效的利用处理器的资源; ARM指令集可以节省系统

    2024年02月07日
    浏览(51)
  • MyBatis --- 缓存、逆向工程、分页插件

    一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问 使一级缓存失效的四种情况: 1、不同的SqlSession对应不同的一级缓存 2、同一个SqlSession但是查询条件不同 3、同一个SqlSession两次查询期

    2023年04月09日
    浏览(43)
  • NO.08 MyBatis创建逆向工程

    目录 1、前言 2、添加依赖和插件  3、创建MyBatis的核心配置文件  4、创建逆向工程的配置文件  5、执行MBG插件的generate目标 工程的创建有正向工程和逆向工程之分。正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表,如Hibernate是支持正向工程的。 逆向工程:

    2024年02月11日
    浏览(45)
  • SpringBoot项目中使用mybatis逆向工程

    mybatis逆向工程,即利用现有的数据表结构,生成对应的model实体类、dao层接口,以及对应的mapper.xml映射文件。借助mybatis逆向工程,我们无需手动去创建这些文件。 下面是使用Java代码的方式来实现逆向工程,生成文件(也可以使用插件来生成): 首先,导入需要的依赖包:

    2024年02月08日
    浏览(51)
  • AIGC:Prompt逆向工程简介及使用

    很多同学都会写爬虫。但如果想把爬虫写得好,那一定要掌握一些逆向技术,对网页的JavaScript和安卓App进行逆向,从而突破签名或者绕过反爬虫限制。最近半年,大语言模型异军突起,越来越多的公司基于GPT3.5、GPT-4或者其他大语言模型实现了各种高级功能。在使用大语言模

    2024年02月11日
    浏览(47)
  • 小程序逆向工程:这个开源的小程序逆向工具真不错,2023年亲测成功

    安全部门的大哥又双叒叕报了一个小程序的高危漏洞,他使用逆向工程破解了加密信心,用抓包修改了请求参数。又是头疼的一天… 想成为一名微信小程序的开发者,前端思路的学习和安全意识是非常有必要的,故务必掌握小程序反编译技能。 这里用到了2个工具《解密》与

    2023年04月19日
    浏览(61)
  • 【Spring】SpringBoot整合MybatisPlusGernerator,MybatisPlus逆向工程

       📝个人主页:哈__ 期待您的关注  在我们写项目的时候,我们时常会因为需要创建很多的项目结构而头疼。项目中的表很多的时候,我们连实体类都创建不完,这时候就需要我们的逆向工程来帮助我们生成我们的框架结构。这些结构都差不多,实体类,表现层,业务层和

    2024年04月15日
    浏览(48)
  • 【MyBatis】五、MyBatis的缓存机制与逆向工程

    MyBatis的一级缓存是默认开启的,是基于SqlSession级别的缓存,也就是说,只要是同一个sqlSession,只要执行的语句相同,则不会去数据库中进行查找,而是会从缓存中找到对应的结果。 使用了不同的sqlsession对象 同一个sqlsession对象,但查询条件不同 两次查询之间进行了增删改

    2024年02月09日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包