08-05. Agent SDK で独自エージェントを作る
この回のゴール
- Claude Agent SDK が「Claude Code のコアを再利用するライブラリ」だと理解する
- 50 行程度の最小エージェントを実装し、第6章の ReAct ループとの繋がりを腹落ちする
- 「Claude Code を全部自作する」のではなく「特化型ツール作りに使う」立ち位置を理解する
1. 動機: なぜ独自エージェントが必要か?
Claude Code は素晴らしいが、すべての業務に最適ではない:
- 特化型ワークフロー: 「請求書 PDF を取り込んで仕訳に変換」のような 領域特化 タスクには汎用 Claude Code は重い
- CI/CD 組み込み: GitHub Actions で「PR ごとに自動レビュー」を走らせたい → ターミナル UI は不要、API 呼び出しだけ欲しい
- UI のカスタマイズ: 社内の Slack bot として動かしたい / 独自 Web UI に組み込みたい
- コスト最適化: 特定タスクは Haiku で十分、Sonnet を呼ばない設定にしたい
→ Claude Agent SDK = Claude Code が内部で使っているエージェントループを、自分のコードから呼び出せるライブラリ。
2. SDK の構成要素 (第6章との対応)
第6章で学んだ AI エージェントの 4 要素 と SDK の対応:
| 第6章で学んだ要素 | SDK での実装 |
|---|---|
| ツール定義 | Tool クラス / @tool デコレータ |
| 計画 (Reasoning) | messages.create(thinking={...}) を内蔵 |
| 行動 (Acting) | tool_use ブロック → tool 実行 → tool_result |
| 状態管理 | messages 履歴 + 任意の永続層 |
| 停止条件 | max_iterations / stop_reason == "end_turn" |
→ つまり、第6章で 手書きしたループ を 公式 SDK で書き直す のがこの回。
3. 最小エージェント (50 行)
# minimal_agent.py
import os
from anthropic import Anthropic
from dotenv import load_dotenv
load_dotenv()
client = Anthropic()
# --- ツール 3 つ ---
def read_file(path: str) -> str:
with open(path) as f:
return f.read()
def list_dir(path: str = ".") -> str:
import os
return "\n".join(os.listdir(path))
def run_python(code: str) -> str:
import subprocess
r = subprocess.run(["python", "-c", code], capture_output=True, text=True, timeout=10)
return f"stdout:\n{r.stdout}\nstderr:\n{r.stderr}"
TOOLS = [
{"name": "read_file", "description": "ファイルを読む", "input_schema": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}},
{"name": "list_dir", "description": "ディレクトリ一覧", "input_schema": {"type": "object", "properties": {"path": {"type": "string"}}}},
{"name": "run_python", "description": "Python コードを実行", "input_schema": {"type": "object", "properties": {"code": {"type": "string"}}, "required": ["code"]}},
]
TOOL_FUNCS = {"read_file": read_file, "list_dir": list_dir, "run_python": run_python}
# --- ReAct ループ ---
def run_agent(question: str, max_iter: int = 5):
messages = [{"role": "user", "content": question}]
for it in range(max_iter):
resp = client.messages.create(
model="claude-haiku-4-5",
max_tokens=2000,
tools=TOOLS,
messages=messages,
)
if resp.stop_reason == "end_turn":
return next((b.text for b in resp.content if b.type == "text"), "")
# tool 実行
tool_results = []
for b in resp.content:
if b.type == "tool_use":
fn = TOOL_FUNCS[b.name]
try:
result = fn(**b.input)
except Exception as e:
result = f"Error: {e}"
tool_results.append({"type": "tool_result", "tool_use_id": b.id, "content": str(result)})
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": tool_results})
return "(max iterations reached)"
if __name__ == "__main__":
print(run_agent("カレントディレクトリのファイル一覧を見て、Python ファイルがあれば最初の 1 つを読んで概要を 3 行で説明して"))
→ これが 第6章で学んだ ReAct ループの完全実装。Claude Code はこれを大規模化したもの。
4. SDK 公式ライブラリを使う場合
claude-agent-sdk (将来名前変わる可能性あり)を使うと、上記の Tool 定義 / loop / message 履歴管理がラップされる:
from claude_agent_sdk import Agent
agent = Agent(model="claude-haiku-4-5", system="あなたはコードを読む専門家です。")
agent.add_tool(read_file)
agent.add_tool(list_dir)
result = agent.run("カレントの Python ファイル概要を出して")
print(result)
(API は変動するので公式 docs を確認)
5. Headless mode (CI/CD 連携)
Claude Code 自体も --print フラグで非対話モードで動く:
claude --print "PR #123 のセキュリティ観点をレビューして" > review.md
→ Bash スクリプトや GitHub Actions から呼べる = Agent SDK 不要で簡易自動化。
GitHub Actions 例 (.github/workflows/pr-review.yml):
- name: Auto PR Review
run: |
npm install -g @anthropic-ai/claude-code
claude --print "diff を読んでセキュリティ観点で気になる点を Markdown で出して" > review.md
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- run: gh pr comment ${{ github.event.pull_request.number }} --body-file review.md
6. ハンズオン
- 上記の
minimal_agent.pyを自分で書いて動かす - ツールを 1 つ追加(例:
web_fetch(url) -> str) - SDK ラッパー版を試して、自前ループとどう違うか比較
claude --printで同じタスクを実行 → SDK 自作 / Headless / 手作業 のトレードオフ表を埋める
| 自前ループ | claude-agent-sdk | claude --print | Claude Code (対話) | |
|---|---|---|---|---|
| カスタマイズ性 | 高 | 中 | 低 | 低 |
| 実装工数 | 高 | 中 | 最小 | ゼロ |
| 適用先 | 教育・学習 | 業務組み込み | CI/CD | 個人開発 |
| デバッグの楽さ | 高(全部見える) | 中 | 低 | 高(対話で気づける) |
7. 章のまとめ
第8章を通じて学んだ階層構造:
┌──────────────────┐
│ Claude Code 本体 │
└─────────┬────────┘
┌──────────┐ ┌───────┐ ┌───────┐ │
│CLAUDE.md │ + │Skills │ + │Hooks │ →│ カスタマイズ
└──────────┘ └───────┘ └───────┘ │
↑ │
+「素の API」 │
↓ ▼
┌─────────────────┐ ┌─────────────────┐
│自前 ReAct ループ│ ← SDK → │ Agent SDK ラップ│
└─────────────────┘ └─────────────────┘
(第6章で学んだもの) (第8-05 で学んだもの)
これで「自分用の AI 相棒」を構築するすべての要素が揃った。
8. 次へ (notes に書く内容 + 章末への接続)
- 第8章: 道具を一式揃えた
- 第9章: その道具で 実際の業務タスクを解く ケーススタディに入る
- 6 ケース: リポジトリキャッチアップ / リファクタ自動化 / PR レビュー / 個人ナレッジ / データ分析 / Web サービス保守