この回のゴール
- JSON Schema の書き方を理解する
- なぜツール呼び出しに「スキーマ」が必要かを腹落ちさせる
- Claude の 構造化出力 (
output_config.format) と ツール入力 の両方で使えることを体感する - 次回の
tool_useで「なぜツール定義にスキーマが要るか」が納得できている状態になる
1. なぜスキーマが必要か
前回までの Claude とのやり取りは 自然言語 でした:
User: 明日のランチの予定を教えて
Claude: 明日は 12 時にアリスとイタリアンレストランです。
でも、LLM に 機械が解釈できる構造 で返してほしい場面があります:
- データ抽出(文章 → DB に入れる)
- API 呼び出し引数の生成(ツール入力)
- フォーム自動入力
そこで:
「この形式の JSON で返してね」と形式を指定する = JSON Schema
2. JSON Schema の基本
JSON Schema は「JSON の 形 を記述する JSON」です。
最小の例
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["name", "age"]
}
これは「オブジェクトで、name(文字列)と age(整数)が必須」という意味。
マッチする JSON 例
{"name": "Alice", "age": 30} ✅
{"name": "Alice"} ❌ age 欠けている
{"name": "Alice", "age": "三十"} ❌ age が文字列
3. 使える型(type)
| 型 | 例 |
|---|---|
"string" |
"hello" |
"integer" |
42 |
"number" |
3.14 |
"boolean" |
true |
"array" |
[1, 2, 3] |
"object" |
{"key": "val"} |
"null" |
null |
4. よく使う追加属性
description — LLM が一番見るところ
{
"type": "string",
"description": "ユーザーの氏名。姓と名のあいだは半角スペース。"
}
LLM は description を頼りに何を入れるか判断 します。これが一番大事。
enum — 有限の選択肢
{
"type": "string",
"enum": ["positive", "negative", "neutral"]
}
array + items
{
"type": "array",
"items": {"type": "string"}
}
ネスト(object の中の object)
{
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "email"]
}
},
"required": ["user"]
}
5. Claude での使い道 その 1 — 構造化出力
output_config.format を使えば、Claude の 応答全体 を JSON に強制できます:
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=512,
messages=[{"role": "user", "content": "Jane Doe (jane@co.com) は 30 歳です。情報を抽出して。"}],
output_config={
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"},
"age": {"type": "integer"},
},
"required": ["name", "email", "age"],
"additionalProperties": False,
}
}
}
)
応答の content[0].text が 必ず有効な JSON になる。
Pydantic でもっと楽に
from pydantic import BaseModel
class Contact(BaseModel):
name: str
email: str
age: int
response = client.messages.parse( # .parse を使うと自動 validate
model="claude-haiku-4-5",
max_tokens=512,
messages=[{"role": "user", "content": "..."}],
output_format=Contact,
)
contact: Contact = response.parsed_output # 👈 Pydantic インスタンスで返る
Python では Pydantic が定番です。スキーマとパースが 1 つのクラスで済む。
6. Claude での使い道 その 2 — ツール入力(次回!)
Claude API のツール定義:
tools = [{
"name": "calculator",
"description": "数式を評価する。電卓として使える。",
"input_schema": { # 👈 JSON Schema をここに書く
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "評価する数式。Python eval 互換。例: '3 * (4 + 5)'"
}
},
"required": ["expression"]
}
}]
input_schema が JSON Schema そのもの。Claude はここから:
- いつこのツールを使うべきか(
descriptionを見て) - 何を渡すべきか(
propertiesと各フィールドの説明)
を判断します。
7. スキーマ設計のコツ
| 悪い例 | 良い例 |
|---|---|
description: "名前" |
description: "ユーザーの氏名。フルネームを推奨。日本語可。" |
型が曖昧 (string だけ) |
enum で選択肢を絞る |
| 余計な field | タスクに必要な最小限 のフィールド |
required なしで全部 optional |
本当に必須 のものは required に |
👉 スキーマは LLM に読ませるドキュメント。明確に、具体的に書く。
まとめ
- JSON Schema = JSON の「形」を JSON で記述するメタ言語
type,properties,required,description,enumの 5 つで大半カバー- Claude では 2 つの用途: 構造化出力 (
output_config.format) と ツール入力 (input_schema) - 設計のカギは
descriptionを具体的に書く こと(LLM はここを見て判断する)
この回の限界(次への動機)
スキーマを書けるようになった。次は実際に Claude にツールを呼ばせる ループを動かす番。
👉 次回「電卓ツールを作る」で、tool_use / tool_result の 2 往復メッセージングを完全に実装します。