Примечание.
Второй пилот 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.