Skip to main content

Пользовательские агенты и оркестровка субагентов

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

Кто может использовать эту функцию?

GitHub Copilot SDK Доступна со всеми Copilot тарифными планами.

Примечание.

          Второй пилот SDK в настоящее время находится в Technical Preview. Функциональность и доступность могут меняться.

Кастомные агенты — это лёгкие определения агента, которые вы прикрепляете к сессии. У каждого агента есть собственный системный запрос, ограничения инструментов и опциональные MCP-серверы. Когда запрос пользователя совпадает с экспертизой агента, Второй пилот SDK среда выполнения автоматически делегирует данные этому агенту как подагенту — запуская его в изолированном контексте и транслируя события жизненного цикла обратно в родительскую сессию. Для визуального обзора процесса делегирования см. репозиторийgithub/copilot-sdk.

КонцепцияОписание
          **Таможенный агент** | Конфиг именованного агента с собственной подсказкой и набором инструментов |

| Субагент | Пользовательский агент, вызванный временем выполнения для обработки части задачи | | Вывод | Возможность работы автоматически выбирать агент на основе намерений пользователя | | Родительская сессия | Сессия, породившая субагента; принимает все события жизненного цикла |

Определение пользовательских агентов

Проходите customAgents при создании сессии. Минимум каждому агенту нужно и name``prompt.

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

const client = new CopilotClient();
await client.start();

const session = await client.createSession({
    model: "gpt-4.1",
    customAgents: [
        {
            name: "researcher",
            displayName: "Research Agent",
            description: "Explores codebases and answers questions using read-only tools",
            tools: ["grep", "glob", "view"],
            prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
        },
        {
            name: "editor",
            displayName: "Editor Agent",
            description: "Makes targeted code changes",
            tools: ["view", "edit", "bash"],
            prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
        },
    ],
    onPermissionRequest: async () => ({ kind: "approved" }),
});

Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.

Справочник по конфигурации

НедвижимостьТипОбязательныйОписание
namestringУникальный идентификатор агента
displayNamestring
Имя, читаемое человеком в событиях
descriptionstring
То, что делает агент — помогает процессу выполнения выбрать его
tools
          `string[]` или `null` |

| Названия инструментов, которые агент может использовать. null или опущено = все инструменты | | prompt | string | ✅ | Системный запрос для агента | | mcpServers | object | | Конфигурации серверов MCP, специфичные для этого агента | | infer | boolean | | Может ли среда выполнения автоматически выбирать этот агент (по умолчанию: true) |

Совет

Хороший description помогает во время выполнения сопоставить пользовательские намерения с нужным агентом. Будьте конкретны в отношении экспертизы и возможностей агента.

Помимо настройки для каждого агента, вы можете заранее agent выбрать в конфигурации сессии заранее выбрать, какой пользовательский агент будет активен при старте сессии.

Свойство конфигурации сессииТипОписание
agentstringИмя пользовательского агента для предварительного выбора при создании сессии. Должно совпадать с a name в customAgents.

Выбор агента при создании сессии

Вы можете ввести agent конфигурацию сессии, чтобы предопределить, какой пользовательский агент должен быть активен при старте сессии. Значение должно совпадать name с значением одного из агентов, определённых в customAgents.

const session = await client.createSession({
    customAgents: [
        {
            name: "researcher",
            prompt: "You are a research assistant. Analyze code and answer questions.",
        },
        {
            name: "editor",
            prompt: "You are a code editor. Make minimal, surgical changes.",
        },
    ],
    agent: "researcher", // Pre-select the researcher agent
});

Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.

Как работает делегирование субагентов

Когда вы отправляете запрос в сессию с пользовательскими агентами, среда выполнения оценивает, стоит ли делегировать подагенту:

  1.        **Сопоставление намерений** — Runtime анализирует подсказки пользователя по сравнению с запросами `name` каждого агента и `description`
    
  2.        **Выбор агента** — если совпадение найдено, `infer` но нет `false`, время выполнения выбирает агента
    
  3.        **Изолированное выполнение** — подагент работает со своим собственным подсказкой и набором ограниченных инструментов
    
  4.        **Потоковая трансляция событий** — события жизненного цикла (`subagent.started`, `subagent.completed`и т.д.) возвращаются в родительскую сессию
    
  5.        **Интеграция результатов** — выход субагента интегрируется в ответ родительского агента
    

Контролирующий вывод

По умолчанию все пользовательские агенты доступны для автоматического выбора (infer: true). Настройте infer: false так, чтобы предотвращать автоматический выбор агента во время выполнения — полезно для агентов, которые вы хотите вызвать только через явные пользовательские запросы:

{
    name: "dangerous-cleanup",
    description: "Deletes unused files and dead code",
    tools: ["bash", "edit", "view"],
    prompt: "You clean up codebases by removing dead code and unused files.",
    infer: false, // Only invoked when user explicitly asks for this agent
}

Прослушивание событий субагентов

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

Типы событий

EventИзлучается, когдаДанные
subagent.selectedRuntime выбирает агента для задачи
          `agentName`, , `agentDisplayName``tools` |

| subagent.started | Субагент начинает исполнение | toolCallId, , agentName``agentDisplayName``agentDescription | | subagent.completed | Субагент успешно завершает | toolCallId, , agentName``agentDisplayName | | subagent.failed | Субагент сталкивается с ошибкой | toolCallId, , agentName``agentDisplayName``error | | subagent.deselected | Runtime переключается от субагента | — |

Подписка на события

session.on((event) => {
    switch (event.type) {
        case "subagent.started":
            console.log(`▶ Sub-agent started: ${event.data.agentDisplayName}`);
            console.log(`  Description: ${event.data.agentDescription}`);
            console.log(`  Tool call ID: ${event.data.toolCallId}`);
            break;

        case "subagent.completed":
            console.log(`✅ Sub-agent completed: ${event.data.agentDisplayName}`);
            break;

        case "subagent.failed":
            console.log(`❌ Sub-agent failed: ${event.data.agentDisplayName}`);
            console.log(`  Error: ${event.data.error}`);
            break;

        case "subagent.selected":
            console.log(`🎯 Agent selected: ${event.data.agentDisplayName}`);
            console.log(`  Tools: ${event.data.tools?.join(", ") ?? "all"}`);
            break;

        case "subagent.deselected":
            console.log("↩ Agent deselected, returning to parent");
            break;
    }
});

const response = await session.sendAndWait({
    prompt: "Research how authentication works in this codebase",
});

Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.

Создание интерфейса дерева агентов

События субагента включают toolCallId поля, позволяющие восстановить дерево исполнения. Вот схема отслеживания активности агентов:

interface AgentNode {
    toolCallId: string;
    name: string;
    displayName: string;
    status: "running" | "completed" | "failed";
    error?: string;
    startedAt: Date;
    completedAt?: Date;
}

const agentTree = new Map<string, AgentNode>();

session.on((event) => {
    if (event.type === "subagent.started") {
        agentTree.set(event.data.toolCallId, {
            toolCallId: event.data.toolCallId,
            name: event.data.agentName,
            displayName: event.data.agentDisplayName,
            status: "running",
            startedAt: new Date(event.timestamp),
        });
    }

    if (event.type === "subagent.completed") {
        const node = agentTree.get(event.data.toolCallId);
        if (node) {
            node.status = "completed";
            node.completedAt = new Date(event.timestamp);
        }
    }

    if (event.type === "subagent.failed") {
        const node = agentTree.get(event.data.toolCallId);
        if (node) {
            node.status = "failed";
            node.error = event.data.error;
            node.completedAt = new Date(event.timestamp);
        }
    }

    // Render your UI with the updated tree
    renderAgentTree(agentTree);
});

Инструменты для определения обхвата для каждого агента

Используйте tools это свойство, чтобы ограничить, к какому инструменту может получить доступ агент. Это важно для безопасности и для поддержания концентрации агентов:

const session = await client.createSession({
    customAgents: [
        {
            name: "reader",
            description: "Read-only exploration of the codebase",
            tools: ["grep", "glob", "view"],  // No write access
            prompt: "You explore and analyze code. Never suggest modifications directly.",
        },
        {
            name: "writer",
            description: "Makes code changes",
            tools: ["view", "edit", "bash"],   // Write access
            prompt: "You make precise code changes as instructed.",
        },
        {
            name: "unrestricted",
            description: "Full access agent for complex tasks",
            tools: null,                        // All tools available
            prompt: "You handle complex multi-step tasks using any available tools.",
        },
    ],
});

Примечание.

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

Подключение MCP-серверов к агентам

Каждый пользовательский агент может иметь собственные серверы MCP (Model Context Protocol), что даёт доступ к специализированным источникам данных:

const session = await client.createSession({
    customAgents: [
        {
            name: "db-analyst",
            description: "Analyzes database schemas and queries",
            prompt: "You are a database expert. Use the database MCP server to analyze schemas.",
            mcpServers: {
                "database": {
                    command: "npx",
                    args: ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"],
                },
            },
        },
    ],
});

Шаблоны и рекомендации

Объедините исследователя с редактором

Распространённый шаблон — определить агент-исследователь только для чтения и агент редактора с способностью записи. В процессе выполнения задачи по исследованию поручены исследователю, а задачи по модификации — редактору:

customAgents: [
    {
        name: "researcher",
        description: "Analyzes code structure, finds patterns, and answers questions",
        tools: ["grep", "glob", "view"],
        prompt: "You are a code analyst. Thoroughly explore the codebase to answer questions.",
    },
    {
        name: "implementer",
        description: "Implements code changes based on analysis",
        tools: ["view", "edit", "bash"],
        prompt: "You make minimal, targeted code changes. Always verify changes compile.",
    },
]

Держите описание агентов конкретными

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

// ❌ Too vague — runtime can't distinguish from other agents
{ description: "Helps with code" }

// ✅ Specific — runtime knows when to delegate
{ description: "Analyzes Python test coverage and identifies untested code paths" }

Корректная обработка сбоев

Субагенты могут провалиться. Всегда прислушивайтесь к subagent.failed событиям и решайте их в вашем приложении:

session.on((event) => {
    if (event.type === "subagent.failed") {
        logger.error(`Agent ${event.data.agentName} failed: ${event.data.error}`);
        // Show error in UI, retry, or fall back to parent agent
    }
});