Skip to main content
Skip to content

Multi-tenancy and server deployments多租户与服务器部署

Multi-user server mode means running the Copilot SDK from backend code that serves more than one human, tenant, workspace, or integration account. In this setup, the application owns request routing and authorization, while the SDK and runtime provide per-session state, per-session authentication, and explicit tool registration so one user's session does not inherit another user's tools or identity.多用户服务器模式是指在后端代码中运行 Copilot SDK,为多个用户、租户、工作区或集成账户提供服务。在这种设置下,应用程序负责请求路由和授权,而 SDK 和运行时则提供会话级状态、会话级身份验证以及显式的工具注册,以确保一个用户的会话不会继承另一个用户的工具或身份。

Best for: SaaS products, partner integrations, internal platforms, and backend services that handle concurrent users.适用场景:SaaS 产品、合作伙伴集成、内部平台以及处理并发用户的后端服务。

Use this guide when何时使用本指南

Use this guide when you are building:当您在构建以下内容时,请参考本指南:

  • A multi-user SaaS product that embeds Copilot-powered agents嵌入了 Copilot 驱动的代理的多用户 SaaS 产品
  • A backend for a partner integration, such as a Copilot Studio or Fabric-style pattern合作伙伴集成的后端,例如 Copilot Studio 或 Fabric 风格的模式
  • Any server that handles concurrent users, workspaces, tenants, or requests任何处理并发用户、工作区、租户或请求的服务器
  • A shared runtime where multiple SDK clients connect to one Copilot runtime process一个共享运行时,其中多个 SDK 客户端连接到一个 Copilot 运行时进程

This guide is a sister to Scaling and multi-tenancy. Use that guide for topology, load-balancing, and storage patterns. Use this guide for SDK-level options and runtime isolation choices.本指南是《扩展与多租户》的姊妹篇。请参考该指南了解拓扑、负载均衡和存储模式。本指南侧重于 SDK 级别的选项和运行时隔离选择。

Key SDK options关键 SDK 选项

OptionUse it forNotes
mode: "empty"Disabling ambient OS tools and CLI defaultsRequired for multi-user or shared scenarios.
sessionIdleTimeoutSecondsCleaning idle sessionsSet a server-side timeout for long-running processes.
baseDirectoryIsolating COPILOT_HOME per runtime instanceIgnored when connecting to an existing runtime.
sessionFsRouting session filesystem storage off local diskPair with per-session filesystem providers.
RuntimeConnection.forUri(url)Sharing one already-running runtimeLanguage names vary; see samples below.
Per-session gitHubTokenScoping auth to the requesting userPrefer this over a single shared user token.

mode: "empty"mode: "empty"

mode: "empty" disables optional Copilot CLI behavior by default. In multi-user server mode, this is the safe baseline because your application must explicitly decide which tools, MCP servers, skills, and workspace paths a session can access.mode: "empty" 默认禁用可选的 Copilot CLI 行为。在多用户服务器模式下,这是安全的基准,因为您的应用程序必须明确决定会话可以访问哪些工具、MCP 服务器、技能和工作区路径。

Do not use the default mode: "copilot-cli" for shared servers. That mode is intended for CLI-like coding agents and can expose ambient host filesystem capabilities.请勿在共享服务器上使用默认的 mode: "copilot-cli"。该模式旨在用于类似 CLI 的编码代理,可能会暴露环境主机文件系统的功能。

Code languages navigation代码语言导航

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-5.4",
    availableTools: ["custom:lookupOrder", "custom:createTicket"],
    gitHubToken: user.githubToken,
});

sessionIdleTimeoutSecondssessionIdleTimeoutSeconds

Set sessionIdleTimeoutSeconds on servers so inactive sessions are cleaned up automatically. This prevents zombie sessions in long-running processes and reduces memory and filesystem pressure.在服务器上设置 sessionIdleTimeoutSeconds,以便自动清理不活动的会话。这可以防止长运行进程中出现僵尸会话,并减少内存和文件系统的压力。

LanguagePublic option
TypeScriptsessionIdleTimeoutSeconds
Pythonsession_idle_timeout_seconds
GoSessionIdleTimeoutSeconds
.NETSessionIdleTimeoutSeconds
JavasetSessionIdleTimeoutSeconds(...)
Rustwith_session_idle_timeout_seconds(...)

Use a value that matches your product's conversation lifetime. For chat backends, 15 to 30 minutes is usually a good starting point. For workflow agents, use a longer timeout and explicit deletion when the workflow completes.使用与您产品对话生命周期相匹配的值。对于聊天后端,15 到 30 分钟通常是一个好的起点。对于工作流代理,请使用更长的超时时间,并在工作流完成时显式删除。

baseDirectorybaseDirectory

baseDirectory sets COPILOT_HOME for a runtime instance. Use it to isolate runtime state, credentials, and session data per process, pod, worker, or tenant boundary.baseDirectory 为运行时实例设置 COPILOT_HOME。使用它来隔离每个进程、Pod、工作线程或租户边界的运行时状态、凭据和会话数据。

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

The runtime stores session state under the configured COPILOT_HOME, including session-state/{sessionId}. If your app runs multiple runtime instances, give each instance a distinct directory unless you intentionally use shared storage.运行时将会话状态存储在配置的 COPILOT_HOME 下,包括 session-state/{sessionId}。如果您的应用程序运行多个运行时实例,请为每个实例指定一个不同的目录,除非您有意使用共享存储。

When the SDK connects to an already-running runtime with RuntimeConnection.forUri(url), baseDirectory is ignored by the SDK client. Configure COPILOT_HOME on the runtime process instead.当 SDK 使用 RuntimeConnection.forUri(url) 连接到已运行的运行时实例时,SDK 客户端会忽略 baseDirectory。请改为在运行时进程上配置 COPILOT_HOME。

sessionFssessionFs

sessionFs registers a custom session filesystem provider so session-scoped file I/O can be routed through application storage instead of the runtime's local disk. Use it when local disk is ephemeral, when session state needs to live in object storage, or when a platform needs to enforce tenant-aware storage paths.sessionFs 注册一个自定义会话文件系统提供程序,以便会话范围内的文件 I/O 可以通过应用程序存储进行路由,而不是通过运行时的本地磁盘。当本地磁盘是临时的、会话状态需要驻留在对象存储中,或者平台需要强制执行租户感知存储路径时,请使用此选项。

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

For languages that expose a provider callback, configure sessionFs at the client level and provide a per-session filesystem handler when creating or resuming a session. See Session resume and persistence for persistence concepts and storage trade-offs.对于公开提供程序回调的语言,请在客户端级别配置 sessionFs,并在创建或恢复会话时提供每个会话的文件系统处理程序。有关持久化概念和存储权衡,请参阅“会话恢复与持久化”。

Verified public SDK surfaces:已验证的公共 SDK 表面:

LanguageClient-level configPer-session provider
TypeScriptsessionFscreateSessionFsAdapter / provider callbacks
Pythonsession_fscreate_session_fs_handler
GoSessionFSCreateSessionFSProvider
.NETSessionFsCreateSessionFsProvider
Rustwith_session_fs(...)with_session_fs_provider(...)

Java does not currently expose a verified public sessionFs option, so this guide does not show a Java sessionFs sample.Java 目前未公开验证过的公共 sessionFs 选项,因此本指南不提供 Java sessionFs 示例。

RuntimeConnection.forUri(url)RuntimeConnection.forUri(url)

Use an external runtime connection when multiple SDK clients should share one already-running runtime. This is common in backend services where the runtime process is managed separately from request handlers.当多个 SDK 客户端需要共享一个已运行的运行时实例时,请使用外部运行时连接。这在后端服务中很常见,即运行时进程与请求处理程序分开管理。

LanguageExternal runtime connection
TypeScriptRuntimeConnection.forUri(url)
PythonRuntimeConnection.for_uri(url)
Gocopilot.URIConnection{URL: url}
.NETRuntimeConnection.ForUri(url)
JavasetCliUrl(url)
RustTransport::External { host, port, connection_token }

External runtimes manage their own process-level authentication and storage. Pass per-session tokens on createSession or resumeSession when you need user-specific auth.外部运行时管理其自身的进程级身份验证和存储。当您需要特定于用户的身份验证时,请在 createSession 或 resumeSession 时传递会话令牌。

Per-session gitHubToken会话级 gitHubToken

Set gitHubToken on each session to scope GitHub auth to the requesting user. This is different from a client-level token, which authenticates the runtime process.在每个会话上设置 gitHubToken,以将 GitHub 身份验证限制在请求用户范围内。这与用于验证运行时进程的客户端级令牌不同。

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

Use per-session tokens for content exclusion, model routing, quota checks, and user-specific Copilot access. Avoid sharing one service token across users unless your product intentionally uses service-account semantics.将会话级令牌用于内容排除、模型路由、配额检查和特定于用户的 Copilot 访问。除非您的产品有意使用服务账户语义,否则请避免在用户之间共享同一个服务令牌。

Integration ID集成 ID

Partners building branded agents can set an integration ID for agent session requests. The runtime reads GITHUB_COPILOT_INTEGRATION_ID and stamps it as the Copilot-Integration-Id HTTP header on every agent session request.构建品牌代理的合作伙伴可以为代理会话请求设置集成 ID。运行时会读取 GITHUB_COPILOT_INTEGRATION_ID,并将其作为每个代理会话请求上的 Copilot-Integration-Id HTTP 标头进行标记。

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

The default integration ID is copilot-developer-cli. Use a stable value such as my-product-agent for attribution and routing. The integration ID is currently configured by environment variable only; it is not a first-class SDK option.默认集成 ID 为 copilot-developer-cli。请使用诸如 my-product-agent 之类的稳定值进行归因和路由。集成 ID 目前仅通过环境变量配置;它不是一等 SDK 选项。

If the SDK spawns the runtime, pass the environment variable through the client environment option. If you connect with RuntimeConnection.forUri(url), set the environment variable on the runtime process itself.如果 SDK 生成了运行时,请通过客户端环境选项传递环境变量。如果您使用 RuntimeConnection.forUri(url) 连接,请在运行时进程本身上设置环境变量。

Session-level isolation guarantees会话级隔离保证

Session-level isolation means the runtime keeps user-specific model and state information scoped to a session, not in global shared state.会话级隔离意味着运行时将特定于用户的模型和状态信息限制在会话范围内,而不是存储在全局共享状态中。

SurfaceIsolation behavior
Model list cachePer-session. Model lookup uses the session's model list cache.
Session statePer session ID under COPILOT_HOME/session-state/{sessionId}.
GitHub identityPer-session when gitHubToken is set on the session.
ToolsExplicit in mode: "empty"; ambient in mode: "copilot-cli".
Host filesystemShared by the runtime process if host tools are available.

mode: "empty" is what makes shared runtime patterns viable: no ambient OS tools are exposed unless your application registers or allows them. With mode: "copilot-cli", OS filesystem access is shared through the host process, so do not use that mode for multi-user server mode.mode: "empty" 是共享运行时模式可行的关键:除非您的应用程序显式注册或允许,否则不会暴露任何环境 OS 工具。使用 mode: "copilot-cli" 时,OS 文件系统访问是通过主机进程共享的,因此请勿在多用户服务器模式下使用该模式。

Session state is stored under COPILOT_HOME/session-state/{sessionId} unless you route it through sessionFs. Use unique session IDs that include your own tenant or user boundary, and enforce access control before resuming or deleting sessions.除非通过 sessionFs 路由,否则会话状态存储在 COPILOT_HOME/session-state/{sessionId} 下。请使用包含您自己的租户或用户边界的唯一会话 ID,并在恢复或删除会话之前强制执行访问控制。

Pattern comparison模式比较

PatternUse whenTrade-offs
Pattern 1: isolated CLI per userYou need the strongest isolation boundary or separate process credentials per user.Strong isolation; higher resource cost. See Scaling and multi-tenancy.
Pattern 2: shared CLI with mode: "empty"You want one runtime to serve many users while your app controls tools, auth, and session IDs.Efficient; requires careful tool registration, per-session tokens, and application-level access checks.
Pattern 3: hybridYou route compute-heavy work to cloud sessions and light work to local sessions.Flexible; requires workload routing and policy handling. See Cloud sessions.

Pattern 2: shared CLI with mode: "empty"模式 2:使用 mode: "empty" 的共享 CLI

In this pattern, all users connect through your backend to one runtime pool. The application performs user authentication, chooses a session ID, passes the user's GitHub token on the session, and provides an explicit tool allowlist.在这种模式下,所有用户都通过您的后端连接到一个运行时池。应用程序执行用户身份验证,选择会话 ID,在会话上传递用户的 GitHub 令牌,并提供显式的工具允许列表。

Diagram: Flowchart showing the described process.

Use these rules:遵循以下规则:

  • Always start the client or runtime in mode: "empty".始终以 mode: "empty" 启动客户端或运行时。
  • Use unique session IDs and store ownership metadata in your application database.使用唯一的会话 ID,并在您的应用程序数据库中存储所有权元数据。
  • Check ownership before resumeSession, deleteSession, or any UI action that references a session ID.在执行 resumeSession、deleteSession 或任何引用会话 ID 的 UI 操作之前,检查所有权。
  • Pass gitHubToken per session when requests should run as the user.当请求应以用户身份运行时,请为每个会话传递 gitHubToken。
  • Register only the tools the session needs, and prefer source-qualified allowlists such as custom:* or mcp:search_docs.仅注册会话所需的工具,并优先使用源限定的允许列表,例如 custom:* 或 mcp:search_docs。
  • Set sessionIdleTimeoutSeconds and delete completed workflow sessions explicitly.设置 sessionIdleTimeoutSeconds 并显式删除已完成的工作流会话。

Common pitfalls常见陷阱

  • Forgetting mode: "empty". The default copilot-cli mode exposes CLI-style behavior and may expose the host filesystem through ambient tools.忘记使用 mode: "empty"。默认的 copilot-cli 模式会暴露 CLI 风格的行为,并可能通过环境工具暴露主机文件系统。
  • Not setting sessionIdleTimeoutSeconds. Long-running servers can accumulate idle sessions if they do not clean them up.未设置 sessionIdleTimeoutSeconds。如果长运行服务器不清理空闲会话,它们可能会堆积。
  • Sharing one gitHubToken across users instead of passing a per-session token.在用户之间共享同一个 gitHubToken,而不是传递会话级令牌。
  • Trusting client-provided session IDs without checking ownership in your backend.在后端未检查所有权的情况下,信任客户端提供的会话 ID。
  • Setting baseDirectory on a client that connects to an existing runtime and expecting it to move runtime storage. Configure the runtime process instead.在连接到现有运行时的客户端上设置 baseDirectory,并期望它能移动运行时存储。请改为配置运行时进程。
  • Allowing broad tool patterns such as builtin:* without reviewing whether each tool is appropriate for your users.允许广泛的工具模式(如 builtin:*),而未审查每个工具是否适合您的用户。

See also另请参阅

  • Scaling and multi-tenancy: deployment topologies, storage patterns, and isolation comparisons扩展与多租户:部署拓扑、存储模式和隔离比较
  • Backend services setup: running the runtime in headless server mode后端服务设置:以无头服务器模式运行运行时
  • BYOK (bring your own key): using your own model provider credentialsBYOK(自带密钥):使用您自己的模型提供程序凭据
  • Cloud sessions: routing selected work to cloud sessions云会话:将选定的工作路由到云会话
  • Session resume and persistence: managing resumable session state会话恢复与持久化:管理可恢复的会话状态
  • Features: tools, events, hooks, and advanced SDK features功能:工具、事件、钩子和高级 SDK 功能