Skip to main content

扩展 Copilot SDK 的部署

设计 GitHub Copilot SDK 部署,以便为多个用户提供服务,处理并发会话,并在基础架构中实现水平扩展。

谁可以使用此功能?

GitHub Copilot SDK 适用于所有 Copilot 计划。

注意

          Copilot SDK 当前处于 技术预览版. 功能和可用性可能会发生更改。

考虑 CLI 会话的不同隔离模式,以及如何在实现应用程序时管理并发会话和资源。

          **最适合:** 平台开发人员、SaaS 构建者和任何为多个并发用户提供服务的部署。

会话隔离模式

在选择模式之前,请考虑三个维度:

  • 隔离:谁可以查看哪些会话?
  • 并发:可以同时运行多少个会话?
  • 持久性:会话持续多长时间?

显示 Copilot SDK 部署的三个缩放维度的关系图:隔离、并发和持久性。

模式 1:每个用户的独立 CLI

每个用户获取自己的 CLI 服务器实例。 这是最强的隔离 - 用户的会话、内存和进程完全分离。

显示每用户隔离 CLI 模式的关系图,其中,每个用户都拥有一个专用的 CLI 服务器实例。

          **何时使用**:
  • 在多租户 SaaS 中,数据隔离至关重要。
  • 具有不同身份验证凭据的用户。
  • 符合性要求,如 SOC 2 或 HIPAA。
// CLI pool manager—one CLI per user
class CLIPool {
    private instances = new Map<string, { client: CopilotClient; port: number }>();
    private nextPort = 5000;

    async getClientForUser(userId: string, token?: string): Promise<CopilotClient> {
        if (this.instances.has(userId)) {
            return this.instances.get(userId)!.client;
        }

        const port = this.nextPort++;

        // Spawn a dedicated CLI for this user
        await spawnCLI(port, token);

        const client = new CopilotClient({
            cliUrl: `localhost:${port}`,
        });

        this.instances.set(userId, { client, port });
        return client;
    }

    async releaseUser(userId: string): Promise<void> {
        const instance = this.instances.get(userId);
        if (instance) {
            await instance.client.stop();
            this.instances.delete(userId);
        }
    }
}

模式 2:共享 CLI,带有会话隔离

多个用户共享一个 CLI 服务器,但通过唯一会话 ID 隔离会话。 它对资源的需求较低,但提供的隔离较弱。

图示 CLI 共享模式,其中多个用户通过隔离会话共享一个 CLI 服务器。

          **何时使用**:
  • 具有受信任用户的内部工具。
  • 资源约束的环境。
  • 降低隔离要求。
const sharedClient = new CopilotClient({
    cliUrl: "localhost:4321",
});

// Enforce session isolation through naming conventions
function getSessionId(userId: string, purpose: string): string {
    return `${userId}-${purpose}-${Date.now()}`;
}

// Access control: ensure users can only access their own sessions
async function resumeSessionWithAuth(
    sessionId: string,
    currentUserId: string
): Promise<Session> {
    const [sessionUserId] = sessionId.split("-");
    if (sessionUserId !== currentUserId) {
        throw new Error("Access denied: session belongs to another user");
    }
    return sharedClient.resumeSession(sessionId);
}

模式 3:共享会话(协作)

多个用户与同一会话进行交互,例如与 Copilot 的共享聊天室。 此模式需要应用程序级会话锁定。

显示共享会话模式的关系图,其中多个用户通过消息队列和会话锁与同一会话进行交互。

          **何时使用**:
  • 团队协作工具。
  • 共享代码评审会话。
  • 配对编程助手。

注意

SDK 不提供内置会话锁定。 必须序列化访问权限,以防止并发写入同一会话。

import Redis from "ioredis";

const redis = new Redis();

async function withSessionLock<T>(
    sessionId: string,
    fn: () => Promise<T>,
    timeoutSec = 300
): Promise<T> {
    const lockKey = `session-lock:${sessionId}`;
    const lockId = crypto.randomUUID();

    // Acquire lock
    const acquired = await redis.set(lockKey, lockId, "NX", "EX", timeoutSec);
    if (!acquired) {
        throw new Error("Session is in use by another user");
    }

    try {
        return await fn();
    } finally {
        // Release lock only if we still own it
        const currentLock = await redis.get(lockKey);
        if (currentLock === lockId) {
            await redis.del(lockKey);
        }
    }
}

// Serialize access to a shared session
app.post("/team-chat", authMiddleware, async (req, res) => {
    const result = await withSessionLock("team-project-review", async () => {
        const session = await client.resumeSession("team-project-review");
        return session.sendAndWait({ prompt: req.body.message });
    });

    res.json({ content: result?.data.content });
});

隔离模式比较

每个用户一个独立的 CLI共享 CLI + 会话隔离共享会话
隔离已完成Logical共享
资源使用情况高(每个用户的命令行界面)低(一个 CLI)低(一个命令行接口 (CLI) 和会话)
复杂性中等高 (需要锁定)
身份验证灵活性每用户令牌服务令牌服务令牌
最适用于多租户软件即服务内部工具协作

水平缩放

负载均衡器后面的多个 CLI 服务器

若要为更多并发用户提供服务,请在负载均衡器后面运行多个 CLI 服务器实例。 会话状态必须位于 共享存储 上,因此任何 CLI 服务器都可以恢复任何会话。

显示负载均衡器后面具有共享存储(用于会话状态)的多个 CLI 服务器的示意图。

// Route sessions across CLI servers
class CLILoadBalancer {
    private servers: string[];
    private currentIndex = 0;

    constructor(servers: string[]) {
        this.servers = servers;
    }

    // Round-robin selection
    getNextServer(): string {
        const server = this.servers[this.currentIndex];
        this.currentIndex = (this.currentIndex + 1) % this.servers.length;
        return server;
    }

    // Sticky sessions: same user always hits same server
    getServerForUser(userId: string): string {
        const hash = this.hashCode(userId);
        return this.servers[hash % this.servers.length];
    }

    private hashCode(str: string): number {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            hash = (hash << 5) - hash + str.charCodeAt(i);
            hash |= 0;
        }
        return Math.abs(hash);
    }
}

const lb = new CLILoadBalancer([
    "cli-1:4321",
    "cli-2:4321",
    "cli-3:4321",
]);

app.post("/chat", async (req, res) => {
    const server = lb.getServerForUser(req.user.id);
    const client = new CopilotClient({ cliUrl: server });

    const session = await client.createSession({
        sessionId: `user-${req.user.id}-chat`,
        model: "gpt-4.1",
    });

    const response = await session.sendAndWait({ prompt: req.body.message });
    res.json({ content: response?.data.content });
});

粘滞会话与共享存储

比较 Copilot SDK 部署扩展中的粘滞会话和共享存储方法的图表。

          **粘性会话** 将每个用户绑定到特定的 CLI 服务器。 不需要共享存储,但如果用户流量显著变化,负载分布可能会不均衡。

          **共享存储** 允许任何 CLI 处理任何会话。 负载分布更均匀,但需要网络存储。`~/.copilot/session-state/`

纵向扩展

优化单个 CLI 服务器

单个 CLI 服务器可以处理多个并发会话。 关键是管理会话生命周期,以避免资源耗尽:

显示垂直缩放的资源维度的关系图:CPU、内存、磁盘 I/O 和网络。

// Limit concurrent active sessions
class SessionManager {
    private activeSessions = new Map<string, Session>();
    private maxConcurrent: number;

    constructor(maxConcurrent = 50) {
        this.maxConcurrent = maxConcurrent;
    }

    async getSession(sessionId: string): Promise<Session> {
        // Return existing active session
        if (this.activeSessions.has(sessionId)) {
            return this.activeSessions.get(sessionId)!;
        }

        // Enforce concurrency limit
        if (this.activeSessions.size >= this.maxConcurrent) {
            await this.evictOldestSession();
        }

        // Create or resume
        const session = await client.createSession({
            sessionId,
            model: "gpt-4.1",
        });

        this.activeSessions.set(sessionId, session);
        return session;
    }

    private async evictOldestSession(): Promise<void> {
        const [oldestId] = this.activeSessions.keys();
        const session = this.activeSessions.get(oldestId)!;
        // Session state is persisted automatically—safe to disconnect
        await session.disconnect();
        this.activeSessions.delete(oldestId);
    }
}

临时会话与永久性会话

比较 Copilot SDK 部署的临时会话和持久性会话的关系图。

          **临时会话** 按请求创建,并在使用后销毁。 它们非常适合一次性任务和无状态 API。

          **持久会话** 是可以命名的,在重启后能够继续存在,并且可以恢复。 它们非常适合多轮对话和长工作流。

临时会话

app.post("/api/analyze", async (req, res) => {
    const session = await client.createSession({
        model: "gpt-4.1",
    });

    try {
        const response = await session.sendAndWait({
            prompt: req.body.prompt,
        });
        res.json({ result: response?.data.content });
    } finally {
        await session.disconnect();
    }
});

持久会话

// Start a conversation
app.post("/api/chat/start", async (req, res) => {
    const sessionId = `user-${req.user.id}-${Date.now()}`;

    const session = await client.createSession({
        sessionId,
        model: "gpt-4.1",
        infiniteSessions: {
            enabled: true,
            backgroundCompactionThreshold: 0.80,
        },
    });

    res.json({ sessionId });
});

// Continue the conversation
app.post("/api/chat/message", async (req, res) => {
    const session = await client.resumeSession(req.body.sessionId);
    const response = await session.sendAndWait({ prompt: req.body.message });

    res.json({ content: response?.data.content });
});

// Clean up when done
app.post("/api/chat/end", async (req, res) => {
    await client.deleteSession(req.body.sessionId);
    res.json({ success: true });
});

容器部署

具有持久性存储的 Kubernetes

以下示例部署三个共享 CLI PersistentVolumeClaim 副本,以便任何副本可以恢复任何会话。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: copilot-cli
spec:
  replicas: 3
  selector:
    matchLabels:
      app: copilot-cli
  template:
    metadata:
      labels:
        app: copilot-cli
    spec:
      containers:
        - name: copilot-cli
          image: ghcr.io/github/copilot-cli:latest
          args: ["--headless", "--port", "4321"]
          env:
            - name: COPILOT_GITHUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: copilot-secrets
                  key: github-token
          ports:
            - containerPort: 4321
          volumeMounts:
            - name: session-state
              mountPath: /root/.copilot/session-state
      volumes:
        - name: session-state
          persistentVolumeClaim:
            claimName: copilot-sessions-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: copilot-cli
spec:
  selector:
    app: copilot-cli
  ports:
    - port: 4321
      targetPort: 4321

显示 Kubernetes 部署的图示,其中有多个 CLI 服务器 Pod 共享同一个持久卷声明用于会话状态。

生产核对清单

关注建议
会话清理运行定期清理以删除早于 TTL 的会话。
运行状况检查定期 Ping CLI 服务器;如果无响应,请重启。
存储装载持久卷~/.copilot/session-state/
机密使用平台的机密管理器(保管库、Kubernetes Secrets 等)。
监控跟踪活动会话计数、响应延迟和错误率。
Locking使用 Redis 或类似工具访问共享会话。
关机****停止 CLI 服务器之前,请清空活动会话。

局限性

限度详细信息
无内置会话锁定实现并发访问的应用程序级锁定。
无内置负载均衡使用外部负载均衡器或服务网格。
会话状态基于文件多服务器设置需要一个共享文件系统。
30 分钟空闲超时不带活动的会话由 CLI 自动清除。
CLI 是单进程通过添加更多 CLI 服务器实例而不是线程进行缩放。

后续步骤