注意
Copilot SDK 当前处于 技术预览版. 功能和可用性可能会发生更改。
自定义代理是附加到会话的轻型代理定义。 每个代理都有自己的系统提示、工具限制和可选的 MCP 服务器。 当用户的请求与某个代理的专业知识匹配时,Copilot 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 存储库。
配置参考
| 财产 | 类型 | 必需 | 说明 |
|---|---|---|---|
name | string | ✅ | 代理的唯一标识符 |
displayName | string | ||
| 事件中显示的人类可读名称 | |||
description | string | ||
| 代理的作用是帮助运行时环境选择它 | |||
tools |
`string[]` 或 `null` |
| 代理可以使用的工具的名称。
null 或省略表示所有工具 |
| prompt | string | ✅ | 代理的系统提示 |
| mcpServers | object |
| 特定于此代理的 MCP 服务器配置 |
| infer | boolean |
| 运行时是否可以自动选择此代理(默认值: true |
提示
一个好 description 方法有助于运行时将用户意向与正确的代理匹配。 具体介绍代理的专业知识和功能。
除了按代理配置,还可以在agent上设置****,以在会话启动时预先选择哪个自定义代理处于活动状态。
| 会话配置属性 | 类型 | 说明 |
|---|---|---|
agent | string | 在创建会话时预选择的自定义代理的名称。 必须与name中customAgents匹配。 |
在创建会话时选择代理
可以传入 agent 会话配置,以便预先选择会话启动时应处于活动状态的自定义代理。 该值必须与customAgents中定义的代理之一的name匹配。
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 存储库。
子代理委派的工作原理
向具有自定义代理的会话发送提示时,运行时将评估是否委托给子代理:
-
**意图匹配**—运行时会分析用户的提示以匹配每个代理的`name`和`description` -
**代理选择** - 如果找到匹配项且 `infer` 不等于 `false`,则运行时选择代理。 -
**独立执行** - 子代理使用自己的提示和受限工具集运行 -
**事件流式处理** - 生命周期事件(`subagent.started``subagent.completed`等)流式传输到父会话 -
**结果集成** - 子代理的输出合并到父代理的响应中
控制推理
默认情况下,所有自定义代理都可用于自动选择(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 存储库。
构建代理树用户界面
子代理事件包括 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
}
});