Skip to content

GitHub Copilot 程序化调用

关键问题

GitHub Copilot 作为 IDE 插件缺乏官方 API,但通过语言服务器或替代方案仍可实现程序化调用

问题陈述

开发人员在探索 GitHub Copilot 时面临核心挑战:如何通过代码自动化获取 Copilot 的代码建议,特别是捕获其生成的前三个候选建议。典型场景包括:

  • 在自动化脚本中批量获取 Copilot 对指定代码片段的建议
  • 将建议内容保存至文件进行后续分析
  • 集成 Copilot 到非 IDE 的自动化工作流中

核心障碍

GitHub 未提供官方 API 控制 Copilot,但其底层服务可通过非官方方式接入

解决方案

方案一:语言服务器接入(推荐)

GitHub 已发布官方 @github/copilot-language-server NPM 包实现程序化访问:

  1. 安装语言服务包
bash
npm install @github/copilot-language-server
  1. Node.js 客户端实现(完整示例)
js
const { spawn } = require("node:child_process");
const server = spawn("node", [
  "./node_modules/@github/copilot-language-server/dist/language-server.js",
  "--stdio",
  "true"
]);

// 初始化阶段
const initServer = async () => {
  await sendLSPRequest("initialize", {
    capabilities: { workspace: { workspaceFolders: true } }
  });
  sendLSPNotification("initialized", {});
};

// 发送代码片段获取建议
const getCopilotSuggestions = async (code) => {
  sendLSPNotification("textDocument/didOpen", {
    textDocument: {
      uri: "file:///test.js",
      languageId: "javascript",
      version: 0,
      text: code
    }
  });
  
  return await sendLSPRequest("getCompletions", {
    doc: {
      version: 0,
      uri: "file:///test.js",
      position: { line: 1, character: code.length }
    }
  });
};

// 执行示例
void (async () => {
  await initServer();
  const suggestions = await getCopilotSuggestions("function calculateSum(a, b) {");
  console.log("Top 3 建议:", suggestions.items.slice(0, 3));
})();

工作原理

  1. 语言服务器通信基于 LSP 协议
  2. getCompletions 请求返回所有建议(包含排名前三个)
  3. 需要提前完成 OAuth 登录流程(参考社区实现)

方案二:非官方 API

使用 copilot-api 项目实现自托管方案:

  1. 克隆仓库并启动服务
bash
git clone https://github.com/B00TK1D/copilot-api
cd copilot-api
npm install
node index.js
  1. Python 调用示例(通过 HTTP API)
python
import requests

response = requests.post(
    "http://localhost:8080/completion",
    json={
        "code": "def fibonacci(n):",
        "language": "python"
    }
)
top_3 = response.json()["completions"][:3]
print(f"前3条推荐: {top_3}")

优势:

  • 不依赖特定编辑器
  • 自动处理 OAuth 令牌刷新
  • 提供精简 HTTP 接口

方案三:日志拦截(适用于 Vim 用户)

适用场景

已安装 Copilot.vim 且需记录所有输入/输出时使用

  1. 创建代理脚本 agent.js
js
// 替换路径为实际插件位置
const AGENT_PATH = '/home/user/.vim/pack/github/start/copilot.vim/dist/agent.orig.js';

const fs = require('fs');
const { spawn } = require('child_process');
const agent = spawn('node', [AGENT_PATH]);

// 记录所有请求/响应
process.stdin.pipe(fs.createWriteStream('requests.log'));
agent.stdout.pipe(fs.createWriteStream('suggestions.log'));

process.stdin.pipe(agent.stdin);
agent.stdout.pipe(process.stdout);
  1. 替换插件入口
bash
mv dist/agent.js dist/agent.orig.js
cp agent.js dist/agent.js  # 使用新脚本
  1. 解析日志获取建议
python
import re
import json

def extract_suggestions(log_path):
    pattern = r'{"completions":\[.*?\].*\n'
    with open(log_path) as f:
        for match in re.findall(pattern, f.read()):
            data = json.loads(match)
            yield data["completions"][:3]

方案对比

方法复杂度维护性适用场景
官方语言服务器★★★★★★需要完整控制流程
非官方 API★★★★快速 HTTP 集成
日志拦截仅需记录 Vim 交互

重要限制

  1. Copilot 服务条款未明确允许程序化访问
  2. 频繁调用可能触发服务限制(设置合理的请求间隔)
  3. 接口变更可能导致方案失效