
超越 Copilot Chat:用 SDK 打造专属 AI Agent(实战四场景)
前两篇我们从入门到架构,把 GitHub Copilot SDK 拆透了。这篇换个角度——直接上代码,用四个真实场景展示 SDK 能做什么,以及为什么这比 " 直接调 LLM" 更有意思。
为什么需要 Demo?
理论讲了很多:Client/Session 的职责分离、事件驱动模型、39 种事件类型……
但真正让你 感受到 SDK 价值的,是看到它在实际场景里怎么运作。
这四个场景来自我的 copilot-sdk-demo 仓库,从简单到复杂,每个场景都聚焦一个核心能力:
| 场景 | 核心能力 | 一句话描述 |
|---|---|---|
| 场景一 | 工具调用 | PR Code Review Bot |
| 场景二 | 多工具 + 输出保存 | 自动文档生成器 |
| 场景三 | 交互式对话循环 | kubectl 自然语言助手 |
| 场景四 | Skills 机制 | 带团队规范的 PR Review |
环境准备
# 克隆 demo 仓库
git clone https://github.com/addozhang/copilot-sdk-demo
cd copilot-sdk-demo
# 安装依赖
pip install -r requirements.txt
前置条件:已安装并登录 gh-copilot CLI(详见 入门篇)。
场景一:PR Code Review Bot
核心能力:工具调用(Tool Calling)
这是最经典的 Agent 模式:让 LLM " 决定 " 什么时候去调用外部函数,而不是在代码里硬编码调用顺序。
from copilot.tools import define_tool
from pydantic import BaseModel, Field
class GetPrDiffParams(BaseModel):
repo: str = Field(description="Repository in owner/repo format")
pr_number: int = Field(description="Pull request number")
@define_tool(description="Fetch the diff for a pull request")
def get_pr_diff(params: GetPrDiffParams) -> str:
# 实际项目里调用 GitHub API;demo 用硬编码 diff
return SAMPLE_DIFF
把工具注册到 Session:
session = await client.create_session(
model="claude-sonnet-4.6",
streaming=True,
tools=[get_pr_diff],
on_permission_request=lambda req, inv: PermissionRequestResult(kind="approved"),
)
await session.send_and_wait(
"Please review PR #42 in 'acme/backend'. "
"Use the get_pr_diff tool to fetch the diff, then provide a thorough code review."
)
发生了什么?
你没有告诉 LLM " 先调用 get_pr_diff,拿到结果再分析 “。你只是说 " 帮我 review PR #42”。LLM 根据工具描述自主判断需要先获取 diff,调用工具,拿到结果,再完成 review。
这就是工具调用的核心价值:LLM 做规划,你定义能力边界。
场景二:自动文档生成器
核心能力:工具调用 + 结果持久化
给定一个 Python 源文件,自动生成 README 文档并保存到磁盘。
@define_tool(description="Read the contents of a file from disk")
def read_file(params: ReadFileParams) -> str:
path = Path(params.filename)
if not path.exists():
return f"Error: file '{params.filename}' not found."
return path.read_text()
关键点在于流式输出的收集:
generated_chunks = []
def handle_event(event):
t = str(event.type)
if "ASSISTANT_MESSAGE_DELTA" in t:
if hasattr(event.data, "delta_content") and event.data.delta_content:
sys.stdout.write(event.data.delta_content)
sys.stdout.flush()
generated_chunks.append(event.data.delta_content) # 同时收集
session.on(handle_event)
await session.send_and_wait(
f"Read the file '{target_file}' using the read_file tool, "
"then generate a comprehensive README.md. Output only the markdown content."
)
# 流式输出完成后,拼接并保存
Path("README_generated.md").write_text("".join(generated_chunks))
一边流式输出给用户看,一边收集内容保存到文件——这是事件驱动模型带来的自然优势。用同步的请求 - 响应模式,你要等全部内容返回才能显示或保存。
场景三:kubectl 自然语言助手
核心能力:交互式对话循环 + System Prompt
这个场景最接近 " 真正的 AI 助手 “:多轮对话,每轮都能调用工具操作真实系统。
@define_tool(description="Execute a kubectl command and return the output")
def run_kubectl(params: RunKubectlParams) -> str:
result = subprocess.run(
f"kubectl {params.command}",
shell=True, capture_output=True, text=True, timeout=30,
)
return result.stdout or result.stderr or "(no output)"
注入系统提示词,塑造助手角色:
SYSTEM_PROMPT = """You are a Kubernetes assistant. Translate natural language
to kubectl commands, execute them, and explain the output.
If the request is potentially dangerous (deleting resources), ask for confirmation first."""
session = await client.create_session(
model="claude-sonnet-4.6",
streaming=True,
tools=[run_kubectl],
system_message={"mode": "append", "content": SYSTEM_PROMPT},
on_permission_request=lambda req, inv: PermissionRequestResult(kind="approved"),
)
交互循环:
while True:
user_input = input("\n> ").strip()
if user_input.lower() in ("exit", "quit"):
break
await session.send_and_wait(user_input)
运行效果:
> Show me all running pods in the default namespace
[Tool] Running: kubectl get pods --field-selector=status.phase=Running -n default
NAME READY STATUS RESTARTS AGE
nginx-7d9b8c4f9-xk2p9 1/1 Running 0 3d
api-server-6f8b9-mnp4 1/1 Running 2 5d
以上是 default namespace 中当前运行的 2 个 Pod...
这里有个设计细节值得注意:system_message 的 mode: "append" 意味着你的 System Prompt 是附加到 Copilot 内置 System Prompt 之后,而不是替换它。这样你既能保留 Copilot 的基础行为,又能叠加自己的角色定义。
场景四:带团队规范的 PR Review(Skills)
核心能力:Skills 机制
场景一和场景四 用的是完全一样的代码,只有一行区别:
# Scenario 1
session = await client.create_session(
model="claude-sonnet-4.6",
tools=[get_pr_diff],
...
)
# Scenario 4:增加 skill_directories
session = await client.create_session(
model="claude-sonnet-4.6",
tools=[get_pr_diff],
skill_directories=["./skills/code-review"], # 👈 这一行
...
)
skills/code-review/SKILL.md 的内容:
# Code Review Standards
When reviewing code, always check for:
1. Missing error handling (try/except for I/O, network, parsing)
2. Type hints on all function parameters and return values
3. Docstrings on all public functions and classes
4. No hardcoded credentials or secrets
5. Functions should be < 30 lines; suggest refactoring if longer
Output format:
- Start with a summary: APPROVED / NEEDS CHANGES / MAJOR ISSUES
- List each issue with: [SEVERITY: HIGH/MEDIUM/LOW] description
- End with specific suggestions
这个 Markdown 文件被 SDK 自动注入到 Session 上下文中,LLM 的输出格式会因此发生显著变化——不再是自由风格的 review,而是严格遵循团队规范的结构化报告。
Skills 的本质:一种轻量的 Prompt 工程封装机制。把团队规范、领域知识、输出模板写进 Markdown,通过目录路径注入,让不同的 Session 拥有不同的 " 专业背景 “。
对比 场景一和场景四 的输出就会发现:同样的代码 diff,同样的用户提问,加了 Skills 之后的 review 立刻变得更专业、更一致,而且更贴近你团队的实际需求。
四个场景的共同模式
回顾这四个 demo,你会发现一个固定的代码骨架:
# 1. 初始化客户端
client = CopilotClient()
await client.start()
# 2. 创建会话(注册工具、配置模型)
session = await client.create_session(
model="claude-sonnet-4.6",
tools=[your_tools],
...
)
# 3. 注册事件处理器(流式输出)
def handle_event(event):
if "ASSISTANT_MESSAGE_DELTA" in str(event.type):
sys.stdout.write(event.data.delta_content or "")
session.on(handle_event)
# 4. 发送消息
await session.send_and_wait("your prompt")
# 5. 清理
await client.stop()
这个骨架不变,变的是:
- 工具定义:你想给 LLM 哪些 " 手脚 “?
- System Prompt / Skills:你想给 LLM 什么 " 性格 " 和 " 背景 “?
- 对话模式:单轮还是多轮?
从 Demo 到生产
这四个场景是 " 最小可运行 " 版本,但核心模式已经够用了。走向生产时,你主要需要补充:
- 真实的工具实现:把
get_pr_diff里的硬编码 diff 换成真正的 GitHub API 调用 - 错误处理:工具调用失败时的重试和降级
- 权限控制:
on_permission_request里加真实的审批逻辑,而不是一律approved - 日志和可观测性:利用
TOOL_EXECUTION_*系列事件记录工具调用链路
总结
三篇文章,完整的学习路径:
- 入门篇:5 行代码启动 Agent,理解 SDK 与 CLI 的关系
- 架构篇:Client/Session 职责分离,事件驱动模型,39 种事件类型
- 本文(实战篇):四个场景,工具调用、交互循环、Skills 机制,从 demo 到生产
GitHub Copilot SDK 的价值不在于 " 它帮你调 LLM”,而在于它提供了一个生产验证过的 Agent 运行时——你只需要告诉它 " 能做什么 “(工具定义)和 " 怎么思考 “(系统提示词/Skills),剩下的规划和执行交给 Copilot。
完整代码:https://github.com/addozhang/copilot-sdk-demo



