# 構造化抽出

Source: https://aiand-docs-staging.pages.dev/ja/cookbook/extraction/

請求書、メール、議事録、スクレイピングしたページなどの自由形式テキストから構造化レコードを取り出します。strict な JSON Schema を使えば、出力は毎回クリーンにパースできます。

## 例: 連絡先情報の抽出

```python
from openai import OpenAI

client = OpenAI(base_url="https://api.aiand.com/v1", api_key="sk-...")

text = """
From: Jane Doe <jane@example.com>
Re: Coffee next week
Phone: +1 555-123-4567
"""

response = client.chat.completions.create(
    model="google/gemma-4-31b-it",
    messages=[
        {"role": "system", "content": "Extract contact info from the user's text."},
        {"role": "user", "content": text},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "contact",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                    "phone": {"type": ["string", "null"]},
                },
                "required": ["name", "email", "phone"],
                "additionalProperties": False,
            },
        },
    },
)

import json
contact = json.loads(response.choices[0].message.content)
print(contact)
# {'name': 'Jane Doe', 'email': 'jane@example.com', 'phone': '+1 555-123-4567'}
```

## Pydantic と併用 (Python)

OpenAI Python SDK は Pydantic モデルからスキーマを自動生成できます:

```python
from pydantic import BaseModel
from typing import Optional

class Contact(BaseModel):
    name: str
    email: str
    phone: Optional[str]

response = client.chat.completions.parse(
    model="google/gemma-4-31b-it",
    messages=[
        {"role": "system", "content": "Extract contact info."},
        {"role": "user", "content": text},
    ],
    response_format=Contact,
)

contact = response.choices[0].message.parsed
print(contact.name, contact.email)
```

## Tips

- すべてのフィールドを `required` にし、任意項目は `["string", "null"]` で表現 — strict モードは欠落を拒否しますが nullable は許可します。
- `additionalProperties: false` を指定して余計なフィールドを防ぐ。
- 複数件 (例: 複数の連絡先) は `{"type": "array", "items": {...}}` で外側オブジェクトにラップ。

<Aside type="note">
  `response_format: json_schema` はモデル側で処理されます。[カタログ](/ja/models/catalog/) で `tool_calling` を持つモデルは概ね strict な JSON Schema を受け付けます。拒否された場合は `{"type": "json_object"}` にフォールバックして、クライアント側で検証してください。
</Aside>
