Skip to main content

사용자 정의 에이전트 및 하위 에이전트 오케스트레이션

범위가 지정된 도구 및 프롬프트를 사용하여 특수 에이전트를 정의하고 단일 세션 내에서 하위 에이전트로 오케스트레이션할 수 있습니다 Copilot .

누가 이 기능을 사용할 수 있나요?

GitHub Copilot SDK 는 모든 Copilot 계획에서 사용할 수 있습니다.

참고

          Copilot SDK가 현재 공개 미리 보기에 있습니다. 기능 및 가용성은 변경될 수 있습니다.

사용자 지정 에이전트는 세션에 연결하는 간단한 에이전트 정의입니다. 각 에이전트에는 고유한 시스템 프롬프트, 도구 제한 및 선택적 MCP 서버가 있습니다. 사용자의 요청이 에이전트의 전문 지식 Copilot SDK 과 일치하면 런타임은 자동으로 해당 에이전트를 하위 에이전트로 위임하여 수명 주기 이벤트를 부모 세션으로 다시 스트리밍하는 동안 격리된 컨텍스트에서 실행합니다. 위임 흐름의 시각적 개요는 리포지토리를github/copilot-sdk 참조하세요.

개념설명
          **사용자 지정 에이전트** | 고유한 프롬프트 및 도구 집합이 있는 명명된 에이전트 구성 |

| 하위 에이전트 | 태스크의 일부를 처리하기 위해 런타임에서 호출한 사용자 지정 에이전트 | | 유추 | 사용자의 의도에 따라 에이전트를 자동으로 선택하는 런타임의 기능 | | 부모 세션 | 하위 에이전트를 생성한 세션입니다. 는 모든 수명 주기 이벤트를 수신합니다. |

사용자 지정 에이전트 정의

세션을 만들 때 customAgents 를 전달합니다. 최소한 각 에이전트에는 nameprompt가 필요합니다.

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 참조하세요. Java의 경우 리포지토리를github/copilot-sdk-java 참조하세요.

구성 참조

재산유형필수설명
namestring에이전트의 고유 식별자
displayNamestring
이벤트에 표시된 사람이 읽을 수 있는 이름
descriptionstring
에이전트의 역할은 런타임의 에이전트 선택을 돕는 것입니다.
tools
          `string[]` 또는 `null` |

| 에이전트에서 사용할 수 있는 도구의 이름입니다. null 또는 생략됨 = 모든 도구 | | prompt | string | ✅ | 에이전트에 대한 시스템 프롬프트 | | mcpServers | object | | 이 에이전트와 관련된 MCP 서버 구성 | | infer | boolean | | 런타임에서 이 에이전트를 자동으로 선택할 수 있는지 여부(기본값: true) |

좋은 description 방법은 런타임이 사용자 의도를 올바른 에이전트와 일치시킬 수 있도록 도와줍니다. 에이전트의 전문 지식과 기능에 대해 자세히 설명합니다.

에이전트별 구성 외에도 agent을 설정 **** 하여 세션이 시작될 때 활성 상태인 사용자 지정 에이전트를 미리 선택할 수 있습니다.

세션 구성 속성유형설명
agentstring세션을 만들 때 미리 선택할 사용자 지정 에이전트의 이름입니다.
          `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 참조하세요. Java의 경우 리포지토리를github/copilot-sdk-java 참조하세요.

하위 에이전트 위임의 작동 방식

사용자 지정 에이전트를 사용하여 세션에 프롬프트를 보내면 런타임은 하위 에이전트에 위임할지 여부를 평가합니다.

  1.        **의도 일치** - 런타임은 사용자의 프롬프트를 각 에이전트의 `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
}

하위 에이전트 이벤트 수신 대기

하위 에이전트가 실행되면 부모 세션은 수명 주기 이벤트를 내보냅니다. 이러한 이벤트를 구독하여 에이전트 활동을 시각화하는 UI를 빌드합니다.

이벤트 유형

이벤트다음의 경우 내보냄데이터
subagent.selected런타임이 작업에 대한 에이전트를 선택합니다.
          `agentName`, `agentDisplayName`, `tools` |

| subagent.started | 하위 에이전트가 실행을 시작합니다. | toolCallId, agentName, , agentDisplayName, agentDescription | | subagent.completed | 하위 에이전트가 성공적으로 완료함 | toolCallId, agentName, agentDisplayName | | subagent.failed | 하위 에이전트에서 오류가 발생합니다. | toolCallId, agentName, , agentDisplayName, error | | subagent.deselected | 런타임이 하위 에이전트에서 다른 곳으로 전환됩니다. | — |

이벤트 구독

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 참조하세요. Java의 경우 리포지토리를github/copilot-sdk-java 참조하세요.

에이전트 트리 UI 빌드

하위 에이전트 이벤트에는 실행 트리를 다시 구성할 수 있는 필드가 포함 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(모델 컨텍스트 프로토콜) 서버가 있어 특수 데이터 원본에 액세스할 수 있습니다.

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
    }
});