Skip to main content

Мультиарендные и серверные развертывания

Запускайте Copilot SDK в многопользовательских серверных развертываниях с изоляцией по сессии для состояния, аутентификации и инструментов.

Лучше всего для: SaaS-продукты, интеграции с партнёрами, внутренние платформы и бэкенд-сервисы, работающие с одновременно работающими пользователями.

Используйте это руководство, когда

Используйте это руководство при строительстве:

  • Многопользовательский SaaS-продукт, в котором встроены агенты на базе Copilot
  • Бэкенд для партнёрской интеграции, например, Copilot Studio или выкройка в стиле Fabric
  • Любой сервер, который обрабатывает одновременных пользователей, рабочие пространства, арендаторы или запросы
  • Общее время выполнения, где несколько SDK-клиентов подключаются к одному процессу Copilot

Это руководство является сестринским вариантом AUTOTITLE. Используйте это руководство для топологии, балансировки нагрузки и шаблонов хранения. Используйте это руководство для параметров на уровне SDK и выбора изоляции во время выполнения.

Ключевые опции SDK

ОпцияИспользуйте его дляNotes
mode: "empty"Отключение инструментов окружающей среды ОС и стандартных настроек CLIТребуется для многопользовательских или совместных сценариев.
sessionIdleTimeoutSecondsОчистка занятий холостого ходаУстановите тайм-аут на стороне сервера для долгосрочных процессов.
baseDirectoryИзоляция COPILOT_HOME каждого экземпляра во время выполненияИгнорируется при подключении к существующему runtime.
sessionFsМаршрутизация файловой системы сессии с локального дискаСопоставьте с провайдерами файловой системы для каждой сессии.
RuntimeConnection.forUri(url)Делюсь одним уже работающим временем выполненияНазвания языков различаются; См. примеры ниже.
За сессию gitHubTokenОпределение аутентификации для запрашивающего пользователяПредпочитаю этот токен, а не один общий пользовательский токен.

mode: "empty"

mode: "empty" по умолчанию отключает опциональное Copilot поведение CLI. В режиме многопользовательского сервера это безопасная база, потому что ваше приложение должно чётко определить, какие инструменты, MCP-серверы, навыки и пути рабочего пространства смогут использовать сессия.

Не используйте стандартные mode: "copilot-cli" настройки для общих серверов. Этот режим предназначен для агентов кодирования, похожих на CLI, и может раскрывать возможности фоновой файловой системы хоста.

TypeScript
import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";

// baseDirectory and sessionIdleTimeoutSeconds apply when the SDK spawns the
// runtime. With RuntimeConnection.forUri(...) configure COPILOT_HOME and the
// idle timeout on the runtime process itself.
const client = new CopilotClient({
    mode: "empty",
    connection: RuntimeConnection.forUri(process.env.COPILOT_RUNTIME_URL!),
});

const session = await client.createSession({
    sessionId: `user-${user.id}-${crypto.randomUUID()}`,
    model: "gpt-4.1",
    availableTools: ["custom:lookupOrder", "custom:createTicket"],
    gitHubToken: user.githubToken,
});
Python
from copilot import CopilotClient, RuntimeConnection
from copilot.session import PermissionHandler

client = CopilotClient(
    mode="empty",
    base_directory=f"/var/lib/my-app/copilot/{runtime_instance_id}",
    session_idle_timeout_seconds=900,
    connection=RuntimeConnection.for_uri(runtime_url),
)
await client.start()

session = await client.create_session(
    session_id=f"user-{user.id}-{request_id}",
    model="gpt-4.1",
    available_tools=["custom:lookupOrder", "custom:createTicket"],
    github_token=user.github_token,
    on_permission_request=PermissionHandler.approve_all,
)
Go
package main

import (
    "context"
    "fmt"

    copilot "github.com/github/copilot-sdk/go"
)

type appUser struct {
    ID          string
    GitHubToken string
}

func main() {
    ctx := context.Background()
    runtimeInstanceID := "instance-1"
    runtimeURL := "http://127.0.0.1:8080"
    requestID := "req-1"
    user := appUser{ID: "alice", GitHubToken: "YOUR_GITHUB_TOKEN"}

    client := copilot.NewClient(&copilot.ClientOptions{
        Mode:                      copilot.ModeEmpty,
        BaseDirectory:             fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
        SessionIdleTimeoutSeconds: 900,
        Connection:                copilot.URIConnection{URL: runtimeURL},
    })

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        SessionID:      fmt.Sprintf("user-%s-%s", user.ID, requestID),
        Model:          "gpt-4.1",
        AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
        GitHubToken:    user.GitHubToken,
    })
    _ = session
    _ = err
}
client := copilot.NewClient(&copilot.ClientOptions{
    Mode:                      copilot.ModeEmpty,
    BaseDirectory:             fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
    SessionIdleTimeoutSeconds: 900,
    Connection:                copilot.URIConnection{URL: runtimeURL},
})

session, err := client.CreateSession(ctx, &copilot.SessionConfig{
    SessionID:      fmt.Sprintf("user-%s-%s", user.ID, requestID),
    Model:          "gpt-4.1",
    AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
    GitHubToken:    user.GitHubToken,
})
.NET
using GitHub.Copilot;

var runtimeInstanceId = "instance-1";
var runtimeUrl = "http://127.0.0.1:8080";
var requestId = "req-1";
var user = new { Id = "alice", GitHubToken = "YOUR_GITHUB_TOKEN" };

var client = new CopilotClient(new CopilotClientOptions
{
    Mode = CopilotClientMode.Empty,
    BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
    SessionIdleTimeoutSeconds = 900,
    Connection = RuntimeConnection.ForUri(runtimeUrl),
});

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    SessionId = $"user-{user.Id}-{requestId}",
    Model = "gpt-4.1",
    AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
    GitHubToken = user.GitHubToken,
});
var client = new CopilotClient(new CopilotClientOptions
{
    Mode = CopilotClientMode.Empty,
    BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
    SessionIdleTimeoutSeconds = 900,
    Connection = RuntimeConnection.ForUri(runtimeUrl),
});

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    SessionId = $"user-{user.Id}-{requestId}",
    Model = "gpt-4.1",
    AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
    GitHubToken = user.GitHubToken,
});
Java
import java.util.List;
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.CopilotClientOptions;
import com.github.copilot.rpc.CopilotClientMode;
import com.github.copilot.rpc.SessionConfig;

public class MultiTenancyExample {
    record User(String id, String gitHubToken) {}

    public static void main(String[] args) throws Exception {
        String runtimeUrl = "http://localhost:4321";
        String requestId = "req-1";
        User user = new User("u1", "ghu_token");

        // setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
        // setCliUrl is used; configure those on the runtime process instead.
        var client = new CopilotClient(new CopilotClientOptions()
            .setMode(CopilotClientMode.EMPTY)
            .setCliUrl(runtimeUrl)
        );

        var session = client.createSession(new SessionConfig()
            .setSessionId("user-" + user.id() + "-" + requestId)
            .setModel("gpt-4.1")
            .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
            .setGitHubToken(user.gitHubToken())
        ).get();
    }
}
// setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
// setCliUrl is used; configure those on the runtime process instead.
var client = new CopilotClient(new CopilotClientOptions()
    .setMode(CopilotClientMode.EMPTY)
    .setCliUrl(runtimeUrl)
);

var session = client.createSession(new SessionConfig()
    .setSessionId("user-" + user.id() + "-" + requestId)
    .setModel("gpt-4.1")
    .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
    .setGitHubToken(user.gitHubToken())
).get();
Rust
use std::path::PathBuf;
use github_copilot_sdk::{Client, ClientOptions, Transport};
use github_copilot_sdk::mode::ClientMode;
use github_copilot_sdk::types::SessionConfig;

let client = Client::start(
    ClientOptions::new()
        .with_mode(ClientMode::Empty)
        .with_base_directory(PathBuf::from(format!(
            "/var/lib/my-app/copilot/{runtime_instance_id}"
        )))
        .with_session_idle_timeout_seconds(900)
        .with_transport(Transport::External {
            host: runtime_host.to_string(),
            port: runtime_port,
            connection_token: None,
        }),
).await?;

let session = client.create_session(
    SessionConfig::default()
        .with_session_id(format!("user-{}-{request_id}", user.id))
        .with_model("gpt-4.1")
        .with_available_tools(["custom:lookupOrder", "custom:createTicket"])
        .with_github_token(user.github_token),
).await?;

sessionIdleTimeoutSeconds

Настройте sessionIdleTimeoutSeconds серверы так, чтобы неактивные сессии очищались автоматически. Это предотвращает зомби-сессии в долгоработающих процессах и снижает нагрузку на память и файловую систему.

LanguageПубличная опция
TypeScriptsessionIdleTimeoutSeconds
Pythonsession_idle_timeout_seconds
GoSessionIdleTimeoutSeconds
.NETSessionIdleTimeoutSeconds
JavasetSessionIdleTimeoutSeconds(...)
Rustwith_session_idle_timeout_seconds(...)

Используйте значение, соответствующее продолжительности общения вашего продукта. Для чат-бэкендов обычно 15–30 минут — хороший старт. Для агентов рабочих процессов используйте более длительный тайм-аут и явное удаление после завершения процесса.

baseDirectory

baseDirectory устанавливает COPILOT_HOME для экземпляра во время выполнения. Используйте его для изоляции состояния runtime, учетных данных и сессионных данных по процессу, поду, работнику или арендатору.

const client = new CopilotClient({
    mode: "empty",
    baseDirectory: `/var/lib/my-app/copilot/runtime-${process.env.HOSTNAME}`,
    sessionIdleTimeoutSeconds: 900,
});

Состояние сессии во время выполнения хранит под настроенным COPILOT_HOME, включая session-state/{sessionId}. Если ваше приложение запускает несколько экземпляров во время выполнения, дайте каждому инстансу отдельную директорию, если только вы намеренно не используете общее хранилище.

Когда SDK подключается к уже запущенному runtime с RuntimeConnection.forUri(url), baseDirectory он игнорируется клиентом SDK. Настройте COPILOT_HOME на процессе выполнения вместо этого.

sessionFs

sessionFs регистрирует пользовательский сервер файловой системы сессии, чтобы ввод/вывод файлов с ограниченным графиком можно было маршрутизировать через хранилище приложений вместо локального диска среды выполнения. Используйте его, когда локальный диск эфемерен, когда состояние сессии должно оставаться в объектном хранилище, или когда платформе нужно навязывать пути хранения с учётом арендаторов.

const client = new CopilotClient({
    mode: "empty",
    sessionFs: {
        initialCwd: "/workspace",
        sessionStatePath: "/session-state",
        conventions: "posix",
    },
});

Для языков, предоставляющих обратный вызов провайдера, настройте sessionFs на уровне клиента и предоставляйте обработчик файловой системы для каждой сессии при создании или возобновлении сессии. См. Возобновление сессии и сохранение для концепций устойчивости и компромиссов при хранении.

Проверенные публичные поверхности SDK:

LanguageКонфигурация на уровне клиентаПровайдер на сессию
TypeScriptsessionFs
createSessionFsAdapter / обратные звонки провайдеров
Pythonsession_fscreate_session_fs_handler
GoSessionFSCreateSessionFSProvider
.NETSessionFsCreateSessionFsProvider
Rustwith_session_fs(...)with_session_fs_provider(...)

Java в настоящее время не показывает проверенный публичный вариант sessionFs, поэтому в этом руководстве не показано выборку Java sessionFs.

RuntimeConnection.forUri(url)

Используйте внешнее подключение для выполнения времени, когда несколько SDK-клиентов должны делить одну уже запущенную среду выполнения. Это часто встречается в бэкенд-сервисах, где процесс выполнения управляется отдельно от обработчиков запросов.

LanguageВнешнее подключение во время выполнения
TypeScriptRuntimeConnection.forUri(url)
PythonRuntimeConnection.for_uri(url)
Gocopilot.URIConnection{URL: url}
.NETRuntimeConnection.ForUri(url)
JavasetCliUrl(url)
RustTransport::External { host, port, connection_token }

Внешние серверы выполнения управляют собственной аутентификацией и хранением на уровне процесса. Передавайте токены за сессию на createSession или resumeSession когда нужна аутентификационная лицензия пользователя.

За сессию gitHubToken

Установите gitHubToken на каждой сессии так, чтобы GitHub аутентификации для запрашивающего пользователя. Это отличается от токена на уровне клиента, который аутентифицирует процесс выполнения.

const session = await client.createSession({
    sessionId: `user-${user.id}-support`,
    model: "gpt-4.1",
    availableTools: ["custom:*"],
    gitHubToken: user.githubToken,
});

Используйте токены за сессию для исключения контента, маршрутизации моделей, проверки квот и пользовательского доступа к Copilot. Избегайте совместного использования одного сервисного токена между пользователями, если только ваш продукт намеренно не использует семантику сервис-аккаунт.

Идентификатор интеграции

Партнёры, создающие брендированные агенты, могут устанавливать идентификатор интеграции для запросов в Центр управления полётом. Время выполнения читает GITHUB_COPILOT_INTEGRATION_ID и маркирует его как HTTP-заголовок Copilot-Integration-Id на каждом запросе Управления полётами.

GITHUB_COPILOT_INTEGRATION_ID=my-product-agent copilot --headless --port 4321

Идентификатор интеграции по умолчанию — copilot-developer-cli. Используйте стабильное значение, например my-product-agent для атрибуции и маршрутизации. Идентификатор интеграции в настоящее время настраивается только по переменной среды; это не первоклассный SDK.

Если SDK вызывает время выполнения, передайте переменную среды через опцию клиентской среды. Если вы подключитесь к RuntimeConnection.forUri(url), установите переменную окружения непосредственно на процессе выполнения.

Гарантии изоляции на уровне сессии

Изоляция на уровне сессии означает, что среда выполнения сохраняет пользовательскую информацию о модели и состояниях в рамках сессии, а не в глобальном общем состоянии.

SurfaceИзоляционное поведение
Кэш списка моделейЗа сессию. Поиск модели использует кэш списка моделей сессии.
Состояние сеансаИдентификатор сессии под COPILOT_HOME/session-state/{sessionId}.
GitHub идентичностьКаждую сессию, когда gitHubToken установлена сессия.
ToolsЯвно в mode: "empty"; амбиент в mode: "copilot-cli".
Файловая система хостаИспользуется процессом выполнения, если доступны хост-инструменты.

mode: "empty" именно это делает общие шаблоны выполнения жизнеспособными: ни один инструмент ОС не отображается, если ваше приложение не регистрирует или не разрешает их. При mode: "copilot-cli", доступ к файловой системе ОС осуществляется через хост-процесс, поэтому не используйте этот режим для многопользовательского сервера.

Состояние сессии хранится в COPILOT_HOME/session-state/{sessionId} , если только вы не направите его через sessionFs. Используйте уникальные идентификаторы сессий, которые включают границы вашего арендатора или пользователя, и обеспечивайте контроль доступа перед возобновлением или удалением сессий.

Сравнение узоров

PatternИспользуйте, еслиTrade-offs
Шаблон 1: изолированный CLI на пользователяВам нужна самая строгая граница изоляции или отдельные учетные данные процесса для каждого пользователя.Сильная изоляция; Более высокая стоимость ресурсов. См . раздел AUTOTITLE.
Шаблон 2: общий CLI с mode: "empty"Вам нужно, чтобы одна среда выполнения обслуживала многих пользователей, а ваше приложение управляло инструментами, аутентификацией и идентификаторами сессий.Эффективно; требуется тщательная регистрация инструментов, токены за сессию и проверка доступа на уровне приложения.
Шаблон 3: гибридВы перенаправляете работу с вычислительной нагрузкой в облачные сессии, а лёгкую — в локальные сессии.Гибкий; Требуется маршрутизация рабочей нагрузки и обработка политик. См . раздел AUTOTITLE.

Шаблон 2: общий CLI с mode: "empty"

В этом шаблоне все пользователи подключаются через ваш бэкенд к одному пулу runtime. Приложение выполняет аутентификацию пользователя, выбирает идентификатор сессии, передаёт токен GitHub пользователя на сессию и предоставляет явный список разрешений инструментов.

Диаграмма: блок-схема, показывающая описанный процесс.

Используйте следующие правила:

  • Всегда запускайте клиент или время выполнения в mode: "empty".
  • Используйте уникальные идентификаторы сессий и храните метаданные владения в базе данных приложений.
  • Проверьте владение перед resumeSession, deleteSessionили любое действие интерфейса, ссылающееся на идентификатор сессии.
  • Пропускайте gitHubToken каждую сессию, когда запросы должны выполняться от пользователя.
  • Регистрируйте только те инструменты, которые нужны сессии, и предпочитайте квалифицированные по источнику списки разрешений, такие как custom:* или mcp:search_docs.
  • Устанавливайте sessionIdleTimeoutSeconds и удаляйте завершённые сессии рабочего процесса явно.

Распространенные ловушки

  • Забывая mode: "empty". Режим по умолчанию copilot-cli демонстрирует поведение в стиле CLI и может раскрывать файловую систему хоста с помощью окружающих инструментов.
  • Не устанавливаю sessionIdleTimeoutSeconds. Долгосрочные серверы могут накапливать простою, если не очищать их.
  • Обмен одним gitHubToken между пользователями вместо передачи токена за сессию.
  • Доверие к идентификаторам сессий, предоставленным клиентом, без проверки собственности на вашем бэкенде.
  • Настройка baseDirectory клиента, который подключается к существующему runtime, и ожидание перемещения хранилища во время выполнения. Настройте процесс выполнения вместо этого.
  • Разрешить общие шаблоны инструментов, например builtin:* , без проверки, подходит ли каждый из них вашим пользователям.

См. также