チュートリアル 2: カスタムツールによる Issue トリアージボット
スクリプト: src/python/scripts/tutorials/02_issue_triage.py
学べること
@define_toolデコレータでカスタムツールを定義する方法- Pydantic モデルをツールの入出力スキーマとして使う方法
- GitHub Issue を分類・ラベル付けするツール呼び出しエージェントの構築方法
前提条件
copilotCLI がインストール済みかつ認証済み(はじめに を参照)github-copilot-sdkとpydanticがインストール済み
カスタムツールとは?
カスタムツールを使うと、Copilot エージェントに独自の関数へのアクセスを与えられます。エージェントはツールの説明に基づいて、いつ呼び出すかを判断します。定義するもの:
- ツールの名前と説明(LLM がいつ呼び出すかを判断するために使用)
- 入力スキーマ(Pydantic の
BaseModel) - 出力スキーマ(別の Pydantic の
BaseModel) - 実装(通常の Python 関数)
ステップ 1 — 入出力スキーマの定義
from pydantic import BaseModel
class ListIssuesInput(BaseModel):
pass # パラメータ不要
class IssueItem(BaseModel):
id: int
title: str
body: str
labels: list[str]
class ListIssuesOutput(BaseModel):
issues: list[IssueItem]
class LabelIssueInput(BaseModel):
issue_id: int
labels: list[str]
class LabelIssueOutput(BaseModel):
success: bool
issue_id: int
applied_labels: list[str]
明確で型付けされたスキーマにより、LLM はどのデータを渡し、何を期待すればよいかを理解できます。
ステップ 2 — @define_tool でツールを実装する
from copilot.tools import define_tool
@define_tool(
name="list_issues",
description="Return the list of open GitHub issues to triage.",
)
def list_issues(_input: ListIssuesInput) -> ListIssuesOutput:
return ListIssuesOutput(
issues=[IssueItem(**issue) for issue in SAMPLE_ISSUES]
)
@define_tool(
name="label_issue",
description="Apply one or more labels to a GitHub issue.",
)
def label_issue(input: LabelIssueInput) -> LabelIssueOutput:
# 実際のシナリオでは、ここで GitHub API を呼び出す
return LabelIssueOutput(
success=True,
issue_id=input.issue_id,
applied_labels=input.labels,
)
ヒント: 説明文字列は詳しく書きましょう。LLM はこれを基に各ツールをいつ呼び出すかを判断します。
ステップ 3 — セッションにツールを登録する
session = await client.create_session(
SessionConfig(
on_permission_request=approve_all,
tools=[list_issues, label_issue], # ← ここで登録
streaming=False,
system_message=SystemMessageReplaceConfig(
mode="replace",
content=(
"You are an expert GitHub issue triage assistant. "
"Use list_issues to fetch open issues, classify each one "
"as 'bug', 'enhancement', or 'documentation', then call "
"label_issue to apply the appropriate label."
),
),
)
)
SystemMessageReplaceConfig を使うと、デフォルトのシステムメッセージを完全に置き換え、エージェントに集中したペルソナを与えられます。
ステップ 4 — タスクプロンプトを送信する
reply = await session.send_and_wait(
MessageOptions(prompt="Please triage all open issues and apply the appropriate labels."),
timeout=300,
)
print(reply.data.content)
エージェントは以下を実行します:
list_issues()を呼び出して Issue を取得- 各 Issue を分析
- 各 Issue に対して適切なラベルで
label_issue()を呼び出す - サマリーを返す
スクリプトの実行
cd src/python
uv run python scripts/tutorials/02_issue_triage.py
uv run python scripts/tutorials/02_issue_triage.py --cli-url localhost:3000 # オプション: 起動済み CLI サーバーを利用
期待される出力:
[Tool] Calling: list_issues
[Tool] Calling: label_issue
[Tool] Calling: label_issue
[Tool] Calling: label_issue
=== Triage Summary ===
I've triaged all 3 open issues...
=== Applied Labels ===
[
{"id": 1, "labels": ["bug"]},
{"id": 2, "labels": ["enhancement"]},
{"id": 3, "labels": ["documentation"]}
]
まとめ
@define_tool(name, description)は関数を呼び出し可能なツールとして登録する- Pydantic の
BaseModelは強く型付けされた入出力コントラクトを定義する - ツールは
SessionConfig(tools=[...])でセッションごとに登録される - LLM はタスクと説明文字列に基づいていつツールを呼び出すかを判断する
SystemMessageReplaceConfigはエージェントにタスク専用のペルソナを与える