实现在线版Copilot

3,305 阅读3分钟

前言

得益于大模型的发展,新版VScode内置了copilot,而且免费使用,想必jym应该都有用过吧,但是在web端很少见到类似copilot功能的代码编辑器,所以尝试自己实现一下。

本文主要讲述了Copilot插件 的功能作用,并讲解如何将这种生成代码的形式复刻在Monaco Editor代码编辑器当中,实现了在线网页版的Copilot

Copilot

作为程序员的你可能已经听说或者正在使用像Copilot这样的IDE插件。

具体来说,它可以在当前光标处自动生成补全代码,包括但不限于以下几种场景:

  • 根据光标所处的上下文,自动生成补全代码并在编辑器中显示
  • 根据写的注释,自动生成相应代码;
  • 根据已有代码生成测试代码image.png

除了Copilot,还有很多类似的产品,如CodeWhispererCodeGeeX通义灵码iFlyCode

我自己使用Copilot进行开发确实能提高日常工作效率。它能够减少开发过程中的心智负担,让我能更专注于业务分析和需求开发。

我实现的Copilot

体验一下我实现的在线版copilot : codeagle.codeasily.net

iShot_2025-02-07_15.47.06.gif

实现Copilot代码补全

实现代码补全的关键分为两个部分:

  1. 编辑器展示出灰色的补充代码,并支持Tab键插入补全代码;

    这个功能很好处理,就是利用Monaco Editor 提供的API:monaco.languages.registerInlineCompletionsProvider 以及provideInlineCompletions 就能实现代码提示,与VSCode 体验一致

    可以打开官网playground示例Monaco Editor (microsoft.github.io) 进行调试,把左边的代码框替换成以下代码可以实时查看效果:

    monaco.languages.registerInlineCompletionsProvider("javascript", {
    	provideInlineCompletions: async function (model, position, context, token) {
    		return Promise.resolve({
    			items: [
    				{
    					insertText: "cument.addEventListener('",
    					range: new monaco.Range(position.lineNumber, 3, position.lineNumber, "cument.addEventListener('".length)
    				},
    			]
    		})
    	},
    	freeInlineCompletions(arg) {
    	}
    });
    
    const myEditor = monaco.editor.create(document.getElementById("container"), {
    	value: '//start type "doc"\n',
    	language: "javascript",
    	wordBasedSuggestions: false,
    	inlineSuggest: {
    		enabled: true,
    		showToolbar: 'onHover',
    		mode: 'subword',
    		suppressSuggestions: false,
    	},
    });
    

    效果如图:

    image.gif
  2. 补全代码的API

    有两种方案:

    1. 利用现有的大模型api(通义千问、OpenAI、DeepSeek等),制定prompt引导生成想要的返回形式,可以按照角色-能力-任务-示例 这样的prompt模板让大模型理解自己的角色描述和指定范围的数据格式,我选择的是阿里云百炼的智能体应用api,在阿里云百炼控制台里的我的应用里自己训练一个代码补全应用,方便调试且方便调用 image.png

    2. 使用开源模型自己部署再进行训练微调,推荐模型:CodeGenCodeGeeX,这种方法就比较费时费力和费钱了,但好处是私有化数据相对安全。

实现Copilot对话框

iShot_2025-02-07_15.54.44.gif

实现对话框也是分为两个关键部分:

  1. 对话输出打字机效果 大模型一般按token逐个生成,所以大模型的回复一般都是逐字显示犹如打字机效果的输出形式,这个功能很多jy都有些相关的教程,我简单概括一下步骤:

    1. 首先需要确保大模型api启用了stream模式,响应头为content-type: text/event-stream
    2. 然后客户端解析响应流,通过res.body.getReader()读取响应流内容
    3. 再得到数据拼接到内容数据中,更新视图
    4. 得到的内容一般是markdown语法,所以得用第三方库markdown-it解析渲染出带样式的内容
  2. 核心的大模型对话api 这部分也是跟之前的代码补全api大差不差,用prompt预训练一个用于代码问答方面的应用,再训练一些特定指令(/comment是为代码生成注释、/explain是解释代码、/fixbug是修复代码、/test是生成单元测试)让模型处理特定场景即可。