Примечание.
Второй пилот SDK в настоящее время находится в Technical Preview. Функциональность и доступность могут меняться.
Рассмотрите различные схемы изоляции для CLI-сессий и то, как вы хотите управлять параллельными сессиями и ресурсами при реализации приложения.
Лучше всего для: Разработчики платформы, SaaS-конструкторы и любое развертывание, обслуживающее более нескольких одновременных пользователей.
Шаблоны изоляции сессий
Перед выбором узора рассмотрим три измерения:
- Изоляция: кто может видеть какие сеансы?
- Параллельность: сколько сессий может проходить одновременно?
- Упорство: как долго длятся сессии?

Шаблон 1: Изолированный 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-сервер, но имеют изолированные сессии через уникальные идентификаторы сессий. Это меньше ресурсов, но обеспечивает более слабую изоляцию.

Когда следует использовать:
- Внутренние инструменты с надёжными пользователями.
- Среды с ограниченными ресурсами.
- Более низкие требования к изоляции.
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 + изоляция сессии | Общие сеансы | |
|---|---|---|---|
| Изоляция | Завершено | Логичный | Общее |
| Использование ресурсов | Высокий (CLI на пользователя) | Низкий (один CLI) | Низкий уровень (один CLI и сессия) |
| Сложность | Средний | Low | Высокий (требует блокировки) |
| Гибкость аутентификации | Токены на пользователя | Сервисный токен | Сервисный токен |
| лучше всего подходит для | Многопользовательский SaaS | Внутренние инструменты | Сотрудничество |
Горизонтальное масштабирование
Несколько 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 });
});
Закреплённые сессии против общего хранилища

Закреплённые сессии привязывают каждого пользователя к конкретному CLI-серверу. Общее хранилище не требуется, но распределение нагрузки может быть неравномерным, если пользовательский трафик сильно варьируется.
Общее хранилище позволяет любому CLI обрабатывать любую сессию. Распределение нагрузки более равномерное, но требует сетевого хранения для ~/.copilot/session-state/.
Вертикальное масштабирование
Настройка одного CLI-сервера
Один CLI-сервер может обрабатывать множество одновременных сессий. Главное — управлять жизненным циклом сессии, чтобы избежать истощения ресурсов:

// 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);
}
}
Эфемерные и постоянные сессии

Эфемерные сессии создаются по запросу и уничтожаются после использования. Они идеально подходят для одноразовых задач и безсостоятельных 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, которые объединяют A 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

Контрольный список рабочей среды
| Беспокойство | Recommendation |
|---|---|
| Уборка сессии | Запускайте периодическую очистку, чтобы удалять сессии старше вашего TTL. |
| Медицинские проверки | Периодически пингуйте CLI-сервер; Если не реагирует, перезапустите. |
| Хранение | Монтировать постоянные тома для ~/.copilot/session-state/. |
| Секреты | Используйте менеджер секретов вашей платформы (Vault, Kubernetes Secrets и т.д.). |
| Monitoring | Отслеживайте количество активных сессий, задержку ответа и уровень ошибок. |
| Locking | Используйте Redis или подобные для общего доступа к сессиям. |
| Завершение работы | Спустите активные сессии перед закрытием CLI-серверов. |
Ограничения
| Ограничение | Сведения |
|---|---|
| Нет встроенной блокировки сессии | Реализовать блокировку на уровне приложения для одновременного доступа. |
| Нет встроенной балансировки нагрузки | Используйте внешний балансировщик нагрузки или сервисную сетку. |
| Состояние сессии основано на файлах | Требуется общая файловая система для многосерверных настроек. |
| 30-минутный тайм-аут на холостом ходу | Сессии без активности автоматически очищаются CLI. |
| CLI — это однопроцессный процесс | Масштабируйтесь, добавляя больше экземпляров CLI-сервера, а не потоков. |
Дальнейшие действия
- Для основной настройки на стороне сервера см. Настройка Copilot SDK для бэкенд-сервисов.
- Для многопользовательской аутентификации см. Использование GitHub OAuth с Copilot SDK.
- Для установки и вашего первого сообщения смотрите Начало работы с Copilot SDK.