Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:16:46 +08:00
commit 3d2cb201f0
33 changed files with 2911 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
{
"name": "api-tools",
"description": "Tools for leveraging Anthropic API features like structured outputs",
"version": "0.0.0-2025.11.28",
"author": {
"name": "Connor",
"email": "noreply@claudex.dev"
},
"skills": [
"./skills/structured-outputs-advisor",
"./skills/json-outputs-implementer",
"./skills/strict-tool-implementer"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# api-tools
Tools for leveraging Anthropic API features like structured outputs

160
plugin.lock.json Normal file
View File

@@ -0,0 +1,160 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:cskiro/claudex:api-tools",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "32a4af94f0baa6026847245149f66c1391f87b4e",
"treeHash": "6f7e48c29523e2b49125ed742e7d35d377d96024f74d43f3e60bc3d9dbc218a9",
"generatedAt": "2025-11-28T10:15:48.350047Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "api-tools",
"description": "Tools for leveraging Anthropic API features like structured outputs"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "78cfc39342cb9dfc3064f3345c6e3b27f9e13307b9ed932de049f1e3ef11e371"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "54b255b37a844cebf4d83019eaec594b5aa6e566adef43be9ddcd4c91ca473c0"
},
{
"path": "skills/json-outputs-implementer/CHANGELOG.md",
"sha256": "86c6eb2979a4e46e962f58b15a3e826e8d97e9bb363cc54c6074ec99feb602f0"
},
{
"path": "skills/json-outputs-implementer/README.md",
"sha256": "935fa93d89d903442908af54745a222860a705fe544aad27cb5d491e21f8daed"
},
{
"path": "skills/json-outputs-implementer/SKILL.md",
"sha256": "5a2a9f5faeab4caac92fc1fb6db4b5a644709e9ac87413198affc1265650fc22"
},
{
"path": "skills/json-outputs-implementer/examples/invoice-extraction.py",
"sha256": "9df74a95f69296053017d5937ddc71ad4dbd6ca00aed6a97e2c3a8813f8abd53"
},
{
"path": "skills/json-outputs-implementer/examples/contact-extraction.py",
"sha256": "cf920c2efadbd182d390a2df2d115df8c2757d26b7733bc6d56b2d4726c9a3a2"
},
{
"path": "skills/json-outputs-implementer/workflow/phase-1-schema-design.md",
"sha256": "a9b8f67cfbedb9ae7a01e3fb1a39edafb41ac19964d3403b8b4c578b6072057f"
},
{
"path": "skills/json-outputs-implementer/workflow/phase-2-sdk-integration.md",
"sha256": "6e7ec79a9243a798fc2f257bbfaa3ddcb8fa4b17462feffc3f2e547c1bcf3aba"
},
{
"path": "skills/json-outputs-implementer/workflow/phase-3-error-handling.md",
"sha256": "245086dfd11f373de5518e2b5adc85b821873fabddbcb67e9bc840dad6a440a9"
},
{
"path": "skills/json-outputs-implementer/workflow/phase-5-production.md",
"sha256": "3309d9209908d42a7a132e5318e16a1f545adb5a5e96aa275a13599107a8bc27"
},
{
"path": "skills/json-outputs-implementer/workflow/phase-4-testing.md",
"sha256": "e400fdb32a2195068d4307fa44bad257f2e3ce74aaeb61b3dc02d971e94227a8"
},
{
"path": "skills/json-outputs-implementer/reference/.gitkeep",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "skills/json-outputs-implementer/reference/schema-limitations.md",
"sha256": "4083a194732b6e4b6845e49a5b66484325d5b6df4ec247b8bce52a645b9dcb2a"
},
{
"path": "skills/json-outputs-implementer/reference/use-cases.md",
"sha256": "d6909ea7cead37dddcb80ea8c3a9be48193125371c2c9e2633828c75d1e7a2d4"
},
{
"path": "skills/strict-tool-implementer/CHANGELOG.md",
"sha256": "fc4f5ba2ec3a7d11e0ab335bf75cdf35ce0fa13fe361fc9f948f9306d9c0e583"
},
{
"path": "skills/strict-tool-implementer/README.md",
"sha256": "f981cc68c997db219f73064946f0da84ed0730b6c2c70eb1a0071888b22e007b"
},
{
"path": "skills/strict-tool-implementer/SKILL.md",
"sha256": "1891b1d5a673286ffb25e7cec0863bfa8eb28f722faeead07138168928dc1ab5"
},
{
"path": "skills/strict-tool-implementer/examples/travel-booking-agent.py",
"sha256": "74fe96fd5928e0e5e4fe33fecc5cf7f38b056b7123118a230c20b31b8eadd092"
},
{
"path": "skills/strict-tool-implementer/workflow/phase-1-schema-design.md",
"sha256": "cb9e2574cbc20481a5c8bb7a957b1291f4af7d943b44549ec0fa8ecb8d64a461"
},
{
"path": "skills/strict-tool-implementer/workflow/phase-2-implementation.md",
"sha256": "6df3dbf3a4f5a37a639ee291e227ddb7b9c19ff2c9dfc09206df687f8344cc91"
},
{
"path": "skills/strict-tool-implementer/workflow/phase-3-error-handling.md",
"sha256": "00ec291acb1bdb30d7fcb0116bf9aafda5f658fc13ad4d995d0e879bfd51641a"
},
{
"path": "skills/strict-tool-implementer/workflow/phase-5-production.md",
"sha256": "453e311d46f215a2f57bde62b84c4bbc7abd4b656117971f6e9201bfd82603c6"
},
{
"path": "skills/strict-tool-implementer/workflow/phase-4-testing.md",
"sha256": "41a69b32a1ea99592c92decbb19a45d1e84dea1efcacdc6273cf03a0008a34b2"
},
{
"path": "skills/strict-tool-implementer/reference/success-criteria.md",
"sha256": "943784fc9456649f25eb11ae3b34e099c8bfd0c4f18615313dc11cc4ea249821"
},
{
"path": "skills/strict-tool-implementer/reference/.gitkeep",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "skills/strict-tool-implementer/reference/common-patterns.md",
"sha256": "0f313193fb1ed90f102a614288ecb834650688fd61beb86ea5ebe446888d4644"
},
{
"path": "skills/structured-outputs-advisor/CHANGELOG.md",
"sha256": "8c9273bf04b8c9a3cae56ebe2e7c9671c0c3998eb945e1bd86991bf9a73683f4"
},
{
"path": "skills/structured-outputs-advisor/README.md",
"sha256": "7fa0c089b7b696f231992d301f50b328b3d847eedc9ccb9e94e6c0623f715381"
},
{
"path": "skills/structured-outputs-advisor/SKILL.md",
"sha256": "e1ba71fce7858b696e5eb18908be188614acc807892891c2304b51be842002d2"
},
{
"path": "skills/structured-outputs-advisor/examples/mode-selection-examples.md",
"sha256": "3ae282b847a6f656bc6c52cda303daa7c288ca8bea88649efdf443fd681a166b"
},
{
"path": "skills/structured-outputs-advisor/reference/.gitkeep",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
],
"dirSha256": "6f7e48c29523e2b49125ed742e7d35d377d96024f74d43f3e60bc3d9dbc218a9"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,16 @@
# Changelog
## 0.2.0
- Refactored to Anthropic progressive disclosure pattern
- Updated description with "Use PROACTIVELY when..." format
- Removed version/author/category/tags from frontmatter
## 0.1.0
- Initial release of JSON Outputs Implementer skill
- Complete workflow covering schema design, SDK integration, testing, and production
- Pydantic and Zod integration patterns
- Error handling for refusals, token limits, and validation failures
- Performance optimization guidance (grammar caching, token management)
- Contact and invoice extraction examples

View File

@@ -0,0 +1,90 @@
# JSON Outputs Implementer
Specialized skill for implementing JSON outputs mode with guaranteed schema compliance.
## Purpose
This skill handles **end-to-end implementation** of JSON outputs mode (`output_format`), ensuring Claude's responses strictly match your JSON schema. Covers schema design, SDK integration, testing, and production deployment.
## Use Cases
- **Data Extraction**: Pull structured info from text/images
- **Classification**: Categorize content with guaranteed output format
- **API Formatting**: Generate API-ready JSON responses
- **Report Generation**: Create structured reports
- **Database Operations**: Ensure type-safe inserts/updates
## Prerequisites
- Routed here by `structured-outputs-advisor`
- Model: Claude Sonnet 4.5 or Opus 4.1
- Beta header: `structured-outputs-2025-11-13`
## Quick Start
**Python with Pydantic:**
```python
from pydantic import BaseModel
from anthropic import Anthropic
class Contact(BaseModel):
name: str
email: str
client = Anthropic()
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Extract contact..."}],
output_format=Contact,
)
contact = response.parsed_output # Guaranteed valid
```
**TypeScript with Zod:**
```typescript
import { z } from 'zod';
const ContactSchema = z.object({
name: z.string(),
email: z.string().email(),
});
const response = await client.beta.messages.parse({
model: "claude-sonnet-4-5",
betas: ["structured-outputs-2025-11-13"],
output_format: betaZodOutputFormat(ContactSchema),
messages: [...]
});
```
## What You'll Learn
1. **Schema Design** - Respecting JSON Schema limitations
2. **SDK Integration** - Pydantic/Zod helpers
3. **Error Handling** - Refusals, token limits, validation
4. **Production Optimization** - Caching, monitoring, cost tracking
5. **Testing** - Comprehensive validation strategies
## Examples
- [contact-extraction.py](./examples/contact-extraction.py) - Extract contact info
- [invoice-extraction.py](./examples/invoice-extraction.py) - Complex nested schemas
## Related Skills
- [`structured-outputs-advisor`](../structured-outputs-advisor/) - Choose the right mode
- [`strict-tool-implementer`](../strict-tool-implementer/) - For tool validation
## Reference Materials
- [JSON Schema Limitations](../reference/json-schema-limitations.md)
- [Best Practices](../reference/best-practices.md)
- [API Compatibility](../reference/api-compatibility.md)
## Version
Current version: 0.1.0
See [CHANGELOG.md](./CHANGELOG.md) for version history.

View File

@@ -0,0 +1,93 @@
---
name: json-outputs-implementer
description: >-
Use PROACTIVELY when extracting structured data from text/images, classifying content, or formatting API responses with guaranteed schema compliance.
Implements Anthropic's JSON outputs mode with Pydantic/Zod SDK integration.
Covers schema design, validation, testing, and production optimization.
Not for tool parameter validation or agentic workflows (use strict-tool-implementer instead).
---
# JSON Outputs Implementer
## Overview
This skill implements Anthropic's JSON outputs mode for guaranteed schema compliance. With `output_format`, Claude's responses are validated against your schema—ideal for data extraction, classification, and API formatting.
**What This Skill Provides:**
- Production-ready JSON schema design
- SDK integration (Pydantic for Python, Zod for TypeScript)
- Validation and error handling patterns
- Performance optimization strategies
- Complete implementation examples
**Prerequisites:**
- Decision made via `structured-outputs-advisor`
- Model: Claude Sonnet 4.5 or Opus 4.1
- Beta header: `structured-outputs-2025-11-13`
## When to Use This Skill
**Use for:**
- Extracting structured data from text/images
- Classification tasks with guaranteed categories
- Generating API-ready responses
- Formatting reports with fixed structure
- Database inserts requiring type safety
**NOT for:**
- Validating tool inputs → `strict-tool-implementer`
- Agentic workflows → `strict-tool-implementer`
## Response Style
- **Schema-first**: Design schema before implementation
- **SDK-friendly**: Leverage Pydantic/Zod when available
- **Production-ready**: Consider performance, caching, errors
- **Example-driven**: Provide complete working code
- **Limitation-aware**: Respect JSON Schema constraints
## Workflow
| Phase | Description | Details |
|-------|-------------|---------|
| 1 | Schema Design | → [workflow/phase-1-schema-design.md](workflow/phase-1-schema-design.md) |
| 2 | SDK Integration | → [workflow/phase-2-sdk-integration.md](workflow/phase-2-sdk-integration.md) |
| 3 | Error Handling | → [workflow/phase-3-error-handling.md](workflow/phase-3-error-handling.md) |
| 4 | Testing | → [workflow/phase-4-testing.md](workflow/phase-4-testing.md) |
| 5 | Production Optimization | → [workflow/phase-5-production.md](workflow/phase-5-production.md) |
## Quick Reference
### Python Template
```python
from pydantic import BaseModel
from anthropic import Anthropic
class MySchema(BaseModel):
field: str
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[...],
output_format=MySchema,
)
result = response.parsed_output # Validated!
```
### Supported Schema Features
✅ Basic types, enums, format strings, nested objects/arrays, required fields
❌ Recursive schemas, min/max constraints, string length, complex regex
## Reference Materials
- [Common Use Cases](reference/use-cases.md)
- [Schema Limitations](reference/schema-limitations.md)
## Related Skills
- `structured-outputs-advisor` - Choose the right mode
- `strict-tool-implementer` - For tool validation use cases

View File

@@ -0,0 +1,138 @@
"""
Contact Information Extraction Example
Extracts structured contact information from unstructured text (emails, messages, etc.)
using JSON outputs mode with Pydantic schema validation.
"""
from pydantic import BaseModel, Field, EmailStr
from typing import Optional, List
from anthropic import Anthropic
import os
# Initialize client
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Define schema with Pydantic
class ContactInfo(BaseModel):
"""Structured contact information extracted from text."""
name: str = Field(description="Full name of the contact person")
email: EmailStr = Field(description="Email address")
phone: Optional[str] = Field(
None, description="Phone number in any format"
)
company: Optional[str] = Field(
None, description="Company or organization name"
)
plan_interest: Optional[str] = Field(
None, description="Product plan or tier they're interested in"
)
demo_requested: bool = Field(
False, description="Whether they requested a product demo"
)
tags: List[str] = Field(
default_factory=list,
description="Relevant tags or categories"
)
def extract_contact(text: str) -> Optional[ContactInfo]:
"""
Extract contact information from unstructured text.
Args:
text: Unstructured text containing contact information
Returns:
ContactInfo object with extracted data, or None if request refused
"""
try:
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
max_tokens=1024,
betas=["structured-outputs-2025-11-13"],
messages=[{
"role": "user",
"content": f"Extract contact information from the following text:\n\n{text}"
}],
output_format=ContactInfo,
)
# Handle different stop reasons
if response.stop_reason == "refusal":
print(f"⚠️ Request refused for safety reasons")
return None
if response.stop_reason == "max_tokens":
print(f"⚠️ Response truncated - increase max_tokens")
return None
# Return validated contact info
return response.parsed_output
except Exception as e:
print(f"❌ Error extracting contact: {e}")
raise
def main():
"""Run contact extraction examples."""
examples = [
# Example 1: Complete contact info
"""
Hi, I'm John Smith from Acme Corp. You can reach me at john.smith@acme.com
or call me at (555) 123-4567. I'm interested in your Enterprise plan and
would love to schedule a demo next week.
""",
# Example 2: Minimal info
"""
Contact: jane.doe@example.com
""",
# Example 3: Informal message
"""
Hey! Bob here. Email me at bob@startup.io if you want to chat about
the Pro plan. Thanks!
""",
# Example 4: Multiple contacts (extracts first/primary)
"""
From: alice@company.com
CC: support@company.com
Hi, I'm Alice Johnson, VP of Engineering at TechCo.
We're evaluating your platform for our team of 50 developers.
""",
]
print("=" * 70)
print("Contact Extraction Examples")
print("=" * 70)
for i, text in enumerate(examples, 1):
print(f"\n📧 Example {i}:")
print(f"Input: {text.strip()[:100]}...")
contact = extract_contact(text)
if contact:
print(f"\n✅ Extracted Contact:")
print(f" Name: {contact.name}")
print(f" Email: {contact.email}")
print(f" Phone: {contact.phone or 'N/A'}")
print(f" Company: {contact.company or 'N/A'}")
print(f" Plan Interest: {contact.plan_interest or 'N/A'}")
print(f" Demo Requested: {contact.demo_requested}")
print(f" Tags: {', '.join(contact.tags) if contact.tags else 'None'}")
else:
print(f"\n❌ No contact extracted")
print("-" * 70)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,160 @@
"""
Invoice Data Extraction Example
Extracts structured invoice data from text using JSON outputs with nested schemas.
Demonstrates handling complex nested structures (line items, tax breakdown).
"""
from pydantic import BaseModel, Field
from typing import List
from decimal import Decimal
from anthropic import Anthropic
import os
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Nested schema for line items
class LineItem(BaseModel):
"""Individual line item on an invoice."""
description: str = Field(description="Item description")
quantity: int = Field(description="Quantity ordered")
unit_price: float = Field(description="Price per unit in USD")
total: float = Field(description="Total for this line (quantity * unit_price)")
class Invoice(BaseModel):
"""Complete invoice structure."""
invoice_number: str = Field(description="Invoice ID (format: INV-XXXXX)")
date: str = Field(description="Invoice date in YYYY-MM-DD format")
due_date: str = Field(description="Payment due date in YYYY-MM-DD format")
customer_name: str = Field(description="Customer or company name")
customer_email: str = Field(description="Customer email address")
line_items: List[LineItem] = Field(
description="List of items on the invoice"
)
subtotal: float = Field(description="Subtotal before tax in USD")
tax_rate: float = Field(description="Tax rate as decimal (e.g., 0.08 for 8%)")
tax_amount: float = Field(description="Tax amount in USD")
total_amount: float = Field(description="Final total amount in USD")
notes: str = Field(
default="",
description="Additional notes or payment instructions"
)
def extract_invoice(invoice_text: str) -> Optional[Invoice]:
"""Extract structured invoice data."""
try:
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
max_tokens=2048, # Higher for complex nested structures
betas=["structured-outputs-2025-11-13"],
messages=[{
"role": "user",
"content": f"Extract all invoice data from:\n\n{invoice_text}"
}],
output_format=Invoice,
)
if response.stop_reason != "end_turn":
print(f"⚠️ Unexpected stop reason: {response.stop_reason}")
return None
return response.parsed_output
except Exception as e:
print(f"❌ Error: {e}")
raise
def main():
"""Run invoice extraction example."""
invoice_text = """
INVOICE
Invoice Number: INV-2024-00123
Date: 2024-01-15
Due Date: 2024-02-15
Bill To:
Acme Corporation
John Smith, CFO
john.smith@acme.com
ITEMS:
1. Cloud Hosting - Pro Plan (x3 servers)
Quantity: 3
Unit Price: $299.00
Total: $897.00
2. Database Storage - 500GB
Quantity: 500
Unit Price: $0.50
Total: $250.00
3. API Calls - Premium Tier
Quantity: 1,000,000
Unit Price: $0.001
Total: $1,000.00
4. Support - Enterprise Level
Quantity: 1
Unit Price: $500.00
Total: $500.00
Subtotal: $2,647.00
Tax (8.5%): $224.99
TOTAL: $2,871.99
Payment Terms: Net 30
Please remit payment to accounts@cloudprovider.com
"""
print("=" * 70)
print("Invoice Extraction Example")
print("=" * 70)
invoice = extract_invoice(invoice_text)
if invoice:
print(f"\n✅ Invoice Extracted Successfully\n")
print(f"Invoice #: {invoice.invoice_number}")
print(f"Customer: {invoice.customer_name} ({invoice.customer_email})")
print(f"Date: {invoice.date}")
print(f"Due: {invoice.due_date}")
print(f"\nLine Items:")
for i, item in enumerate(invoice.line_items, 1):
print(f" {i}. {item.description}")
print(f" Qty: {item.quantity} × ${item.unit_price:.2f} = ${item.total:.2f}")
print(f"\nSubtotal: ${invoice.subtotal:.2f}")
print(f"Tax ({invoice.tax_rate * 100:.1f}%): ${invoice.tax_amount:.2f}")
print(f"TOTAL: ${invoice.total_amount:.2f}")
if invoice.notes:
print(f"\nNotes: {invoice.notes}")
# Validation checks
print(f"\n🔍 Validation:")
calculated_subtotal = sum(item.total for item in invoice.line_items)
print(f" Subtotal matches: {abs(calculated_subtotal - invoice.subtotal) < 0.01}")
calculated_tax = invoice.subtotal * invoice.tax_rate
print(f" Tax calculation matches: {abs(calculated_tax - invoice.tax_amount) < 0.01}")
calculated_total = invoice.subtotal + invoice.tax_amount
print(f" Total matches: {abs(calculated_total - invoice.total_amount) < 0.01}")
else:
print("❌ Failed to extract invoice")
if __name__ == "__main__":
from typing import Optional
main()

View File

@@ -0,0 +1,47 @@
# JSON Schema Limitations Reference
## Supported Features
- ✅ All basic types (object, array, string, integer, number, boolean, null)
-`enum` (primitives only)
-`const`, `anyOf`, `allOf`
-`$ref`, `$def`, `definitions` (local)
-`required`, `additionalProperties: false`
- ✅ String formats: date-time, time, date, email, uri, uuid, ipv4, ipv6
-`minItems: 0` or `minItems: 1` for arrays
## NOT Supported
- ❌ Recursive schemas
- ❌ Numerical constraints (minimum, maximum, multipleOf)
- ❌ String constraints (minLength, maxLength, pattern with complex regex)
- ❌ Array constraints (beyond minItems 0/1)
- ❌ External `$ref`
- ❌ Complex types in enums
## SDK Transformation
Python and TypeScript SDKs automatically remove unsupported constraints and add them to descriptions.
## Success Criteria
- [ ] Schema designed with all required fields
- [ ] JSON Schema limitations respected
- [ ] SDK helper integrated (Pydantic/Zod)
- [ ] Beta header included in requests
- [ ] Error handling for refusals and token limits
- [ ] Tested with representative examples
- [ ] Edge cases covered (missing fields, invalid data)
- [ ] Production optimization considered (caching, tokens)
- [ ] Monitoring in place (latency, costs)
- [ ] Documentation provided
## Important Reminders
1. **Use SDK helpers** - `client.beta.messages.parse()` auto-validates
2. **Respect limitations** - No recursive schemas, no min/max constraints
3. **Add descriptions** - Helps Claude understand what to extract
4. **Handle refusals** - Don't retry safety refusals
5. **Monitor performance** - Watch for cache misses and high latency
6. **Set `additionalProperties: false`** - Required for all objects
7. **Test thoroughly** - Edge cases often reveal schema issues

View File

@@ -0,0 +1,86 @@
# Common Use Cases
## Use Case 1: Data Extraction
**Scenario**: Extract invoice data from text/images
```python
from pydantic import BaseModel
from typing import List
class LineItem(BaseModel):
description: str
quantity: int
unit_price: float
total: float
class Invoice(BaseModel):
invoice_number: str
date: str
customer_name: str
line_items: List[LineItem]
subtotal: float
tax: float
total_amount: float
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
max_tokens=2048,
messages=[{"role": "user", "content": f"Extract invoice:\n{invoice_text}"}],
output_format=Invoice,
)
invoice = response.parsed_output
# Insert into database with guaranteed types
db.insert_invoice(invoice.model_dump())
```
## Use Case 2: Classification
**Scenario**: Classify support tickets
```python
class TicketClassification(BaseModel):
category: str # "billing", "technical", "sales"
priority: str # "low", "medium", "high", "critical"
confidence: float
requires_human: bool
suggested_assignee: Optional[str] = None
tags: List[str]
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": f"Classify:\n{ticket}"}],
output_format=TicketClassification,
)
classification = response.parsed_output
if classification.requires_human or classification.confidence < 0.7:
route_to_human(ticket)
else:
auto_assign(ticket, classification.category)
```
## Use Case 3: API Response Formatting
**Scenario**: Generate API-ready responses
```python
class APIResponse(BaseModel):
status: str # "success" or "error"
data: dict
errors: Optional[List[dict]] = None
metadata: dict
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": f"Process: {request}"}],
output_format=APIResponse,
)
# Directly return as JSON API response
return jsonify(response.parsed_output.model_dump())
```

View File

@@ -0,0 +1,92 @@
# Phase 1: Schema Design
**Objective**: Create a production-ready JSON schema respecting all limitations
## Steps
### 1. Define Output Structure
Ask the user:
- "What fields do you need in the output?"
- "Which fields are required vs. optional?"
- "What are the data types for each field?"
- "Are there nested objects or arrays?"
### 2. Choose Schema Approach
**Option A: Pydantic (Python) - Recommended**
```python
from pydantic import BaseModel
from typing import List, Optional
class ContactInfo(BaseModel):
name: str
email: str
plan_interest: Optional[str] = None
demo_requested: bool = False
tags: List[str] = []
```
**Option B: Zod (TypeScript) - Recommended**
```typescript
import { z } from 'zod';
const ContactInfoSchema = z.object({
name: z.string(),
email: z.string().email(),
plan_interest: z.string().optional(),
demo_requested: z.boolean().default(false),
tags: z.array(z.string()).default([]),
});
```
**Option C: Raw JSON Schema**
```json
{
"type": "object",
"properties": {
"name": {"type": "string", "description": "Full name"},
"email": {"type": "string", "description": "Email address"},
"plan_interest": {"type": "string", "description": "Interested plan"},
"demo_requested": {"type": "boolean"},
"tags": {"type": "array", "items": {"type": "string"}}
},
"required": ["name", "email", "demo_requested"],
"additionalProperties": false
}
```
### 3. Apply JSON Schema Limitations
**✅ Supported Features:**
- All basic types: object, array, string, integer, number, boolean, null
- `enum` (strings, numbers, bools, nulls only)
- `const`
- `anyOf` and `allOf` (limited)
- `$ref`, `$def`, `definitions` (local only)
- `required` and `additionalProperties: false`
- String formats: date-time, time, date, email, uri, uuid, ipv4, ipv6
- Array `minItems` (0 or 1 only)
**❌ NOT Supported (SDK can transform these):**
- Recursive schemas
- Numerical constraints (minimum, maximum)
- String constraints (minLength, maxLength)
- Complex array constraints
- External `$ref`
### 4. Add AI-Friendly Descriptions
```python
class Invoice(BaseModel):
invoice_number: str # Field(description="Invoice ID, format: INV-XXXXX")
date: str # Field(description="Invoice date in YYYY-MM-DD format")
total: float # Field(description="Total amount in USD")
items: List[LineItem] # Field(description="Line items on the invoice")
```
Good descriptions help Claude understand what to extract.
## Output
Production-ready schema following Anthropic's limitations.

View File

@@ -0,0 +1,100 @@
# Phase 2: SDK Integration
**Objective**: Implement using SDK helpers for automatic validation
## Python Implementation
**Recommended: Use `client.beta.messages.parse()`**
```python
from pydantic import BaseModel, Field
from typing import List, Optional
from anthropic import Anthropic
class ContactInfo(BaseModel):
name: str = Field(description="Full name of the contact")
email: str = Field(description="Email address")
plan_interest: Optional[str] = Field(
None, description="Plan tier they're interested in"
)
demo_requested: bool = Field(
False, description="Whether they requested a demo"
)
client = Anthropic()
def extract_contact(text: str) -> ContactInfo:
"""Extract contact information from text."""
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
max_tokens=1024,
betas=["structured-outputs-2025-11-13"],
messages=[{
"role": "user",
"content": f"Extract contact information from: {text}"
}],
output_format=ContactInfo,
)
# Handle edge cases
if response.stop_reason == "refusal":
raise ValueError("Claude refused the request")
if response.stop_reason == "max_tokens":
raise ValueError("Response truncated - increase max_tokens")
# Automatically validated
return response.parsed_output
# Usage
contact = extract_contact("John Smith (john@example.com) wants Enterprise plan")
print(contact.name, contact.email) # Type-safe access
```
## TypeScript Implementation
```typescript
import Anthropic from '@anthropic-ai/sdk';
import { z } from 'zod';
import { betaZodOutputFormat } from '@anthropic-ai/sdk/helpers/beta/zod';
const ContactInfoSchema = z.object({
name: z.string().describe("Full name of the contact"),
email: z.string().email().describe("Email address"),
plan_interest: z.string().optional().describe("Plan tier interested in"),
demo_requested: z.boolean().default(false).describe("Demo requested"),
});
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function extractContact(text: string) {
const response = await client.beta.messages.parse({
model: "claude-sonnet-4-5",
max_tokens: 1024,
betas: ["structured-outputs-2025-11-13"],
messages: [{
role: "user",
content: `Extract contact information from: ${text}`
}],
output_format: betaZodOutputFormat(ContactInfoSchema),
});
if (response.stop_reason === "refusal") {
throw new Error("Claude refused the request");
}
if (response.stop_reason === "max_tokens") {
throw new Error("Response truncated - increase max_tokens");
}
return response.parsed_output;
}
// Usage
const contact = await extractContact("John Smith (john@example.com)...");
console.log(contact.name, contact.email); // Fully typed
```
## Output
Working implementation with SDK validation.

View File

@@ -0,0 +1,53 @@
# Phase 3: Error Handling
**Objective**: Handle refusals, token limits, and validation errors
## Key Error Scenarios
### 1. Safety Refusals (`stop_reason: "refusal"`)
```python
if response.stop_reason == "refusal":
logger.warning(f"Request refused: {input_text}")
# Don't retry - respect safety boundaries
return None # or raise exception
```
### 2. Token Limit Reached (`stop_reason: "max_tokens"`)
```python
if response.stop_reason == "max_tokens":
# Retry with higher limit
return extract_with_higher_limit(text, max_tokens * 1.5)
```
### 3. Schema Validation Errors (SDK raises exception)
```python
from pydantic import ValidationError
try:
result = response.parsed_output
except ValidationError as e:
logger.error(f"Schema validation failed: {e}")
# Should be rare - indicates schema mismatch
raise
```
### 4. API Errors (400 - schema too complex)
```python
from anthropic import BadRequestError
try:
response = client.beta.messages.parse(...)
except BadRequestError as e:
if "too complex" in str(e).lower():
# Simplify schema
logger.error("Schema too complex, simplifying...")
raise
```
## Output
Robust error handling for production deployments.

View File

@@ -0,0 +1,56 @@
# Phase 4: Testing
**Objective**: Validate schema works with representative data
## Test Coverage
```python
import pytest
@pytest.fixture
def extractor():
return ContactExtractor()
def test_complete_contact(extractor):
"""Test with all fields present."""
text = "John Smith (john@example.com) interested in Enterprise plan, wants demo"
result = extractor.extract(text)
assert result.name == "John Smith"
assert result.email == "john@example.com"
assert result.plan_interest == "Enterprise"
assert result.demo_requested is True
def test_minimal_contact(extractor):
"""Test with only required fields."""
text = "Contact: jane@example.com"
result = extractor.extract(text)
assert result.email == "jane@example.com"
assert result.name is not None # Claude should infer or extract
assert result.plan_interest is None # Optional field
assert result.demo_requested is False # Default
def test_invalid_input(extractor):
"""Test with insufficient data."""
text = "This has no contact information"
# Depending on requirements, might raise or return partial data
result = extractor.extract(text)
# Define expected behavior
def test_refusal_scenario(extractor):
"""Test that refusals are handled."""
# Test with potentially unsafe content
# Verify graceful handling without crash
pass
def test_token_limit(extractor):
"""Test with very long input."""
text = "..." * 10000 # Very long text
# Verify either succeeds or raises appropriate error
pass
```
## Output
Comprehensive test suite covering edge cases.

View File

@@ -0,0 +1,78 @@
# Phase 5: Production Optimization
**Objective**: Optimize for performance, cost, and reliability
## 1. Grammar Caching Strategy
The first request compiles a grammar from your schema (~extra latency). Subsequent requests use cached grammar (24-hour TTL).
**Cache Invalidation Triggers:**
- Schema structure changes
- Tool set changes (if using tools + JSON outputs together)
- 24 hours of non-use
**Best Practices:**
```python
# ✅ Good: Finalize schema before production
CONTACT_SCHEMA = ContactInfo # Reuse same schema
# ❌ Bad: Dynamic schema generation
def get_schema(include_phone: bool): # Different schemas = cache misses
if include_phone:
class Contact(BaseModel):
phone: str
...
...
```
## 2. Token Cost Management
Structured outputs add tokens via system prompt:
```python
# Monitor token usage
response = client.beta.messages.parse(...)
print(f"Input tokens: {response.usage.input_tokens}")
print(f"Output tokens: {response.usage.output_tokens}")
# Optimize descriptions for token efficiency
# ✅ Good: Concise but clear
name: str = Field(description="Full name")
# ❌ Excessive: Too verbose
name: str = Field(description="The complete full name of the person including first name, middle name if available, and last name")
```
## 3. Monitoring
```python
import time
from dataclasses import dataclass
@dataclass
class StructuredOutputMetrics:
latency_ms: float
input_tokens: int
output_tokens: int
cache_hit: bool # Infer from latency
stop_reason: str
def track_metrics(response, start_time) -> StructuredOutputMetrics:
latency = (time.time() - start_time) * 1000
return StructuredOutputMetrics(
latency_ms=latency,
input_tokens=response.usage.input_tokens,
output_tokens=response.usage.output_tokens,
cache_hit=latency < 500, # Heuristic: fast = cache hit
stop_reason=response.stop_reason,
)
# Track in production
metrics = track_metrics(response, start_time)
if metrics.latency_ms > 1000:
logger.warning(f"Slow structured output: {metrics.latency_ms}ms")
```
## Output
Production-optimized implementation with caching and monitoring.

View File

@@ -0,0 +1,16 @@
# Changelog
## 0.2.0
- Refactored to Anthropic progressive disclosure pattern
- Updated description with "Use PROACTIVELY when..." format
- Removed version/author/category/tags from frontmatter
## 0.1.0
- Initial release of Strict Tool Implementer skill
- Complete workflow covering tool schema design, multi-tool agents, and production deployment
- Multi-tool agent implementation patterns
- Error handling for tool failures and refusals
- Testing strategies for agentic workflows
- Travel booking agent example (multi-tool workflow)

View File

@@ -0,0 +1,81 @@
# Strict Tool Implementer
Specialized skill for implementing strict tool use mode with guaranteed parameter validation.
## Purpose
This skill handles **end-to-end implementation** of strict tool use mode (`strict: true`), ensuring tool input parameters strictly follow your schema. Essential for building reliable agentic workflows with type-safe tool execution.
## Use Cases
- **Multi-Tool Agents**: Travel booking, research assistants, etc.
- **Validated Function Calls**: Ensure parameters match expected types
- **Complex Tool Schemas**: Tools with nested properties
- **Critical Operations**: Financial transactions, booking systems
- **Tool Composition**: Sequential and parallel tool execution
## Prerequisites
- Routed here by `structured-outputs-advisor`
- Model: Claude Sonnet 4.5 or Opus 4.1
- Beta header: `structured-outputs-2025-11-13`
## Quick Start
**Python:**
```python
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Search for flights..."}],
tools=[{
"name": "search_flights",
"description": "Search for available flights",
"strict": True, # Enable strict validation
"input_schema": {
"type": "object",
"properties": {
"origin": {"type": "string"},
"destination": {"type": "string"},
"travelers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6]}
},
"required": ["origin", "destination", "travelers"],
"additionalProperties": False
}
}]
)
# Tool inputs GUARANTEED to match schema
for block in response.content:
if block.type == "tool_use":
execute_tool(block.name, block.input) # Type-safe!
```
## What You'll Learn
1. **Tool Schema Design** - With `strict: true` and proper validation
2. **Multi-Tool Workflows** - Sequential and parallel tool execution
3. **Agent Patterns** - Stateful agents, retry logic, validation
4. **Error Handling** - Tool failures, refusals, edge cases
5. **Production Deployment** - Monitoring, testing, reliability
## Examples
- [travel-booking-agent.py](./examples/travel-booking-agent.py) - Multi-tool agent workflow
## Related Skills
- [`structured-outputs-advisor`](../structured-outputs-advisor/) - Choose the right mode
- [`json-outputs-implementer`](../json-outputs-implementer/) - For data extraction
## Reference Materials
- [JSON Schema Limitations](../reference/json-schema-limitations.md)
- [Best Practices](../reference/best-practices.md)
- [API Compatibility](../reference/api-compatibility.md)
## Version
Current version: 0.1.0
See [CHANGELOG.md](./CHANGELOG.md) for version history.

View File

@@ -0,0 +1,92 @@
---
name: strict-tool-implementer
description: >-
Use PROACTIVELY when building multi-step agentic workflows with validated tool parameters.
Implements Anthropic's strict tool use mode for guaranteed schema compliance.
Covers tool schema design, multi-tool agent workflows, error handling, testing, and production patterns.
Not for data extraction or classification tasks (use json-outputs-implementer instead).
---
# Strict Tool Implementer
## Overview
This skill implements Anthropic's strict tool use mode for reliable agentic systems. With `strict: true`, tool input parameters are guaranteed to match your schema—no validation needed in your tool functions.
**What This Skill Provides:**
- Production-ready tool schema design
- Multi-tool workflow patterns
- Agentic system architecture
- Validation and error handling
- Complete agent implementation examples
**Prerequisites:**
- Decision made via `structured-outputs-advisor`
- Model: Claude Sonnet 4.5 or Opus 4.1
- Beta header: `structured-outputs-2025-11-13`
## When to Use This Skill
**Use for:**
- Building multi-step agentic workflows
- Validating function call parameters
- Ensuring type-safe tool execution
- Complex tools with nested properties
- Critical operations requiring guaranteed types
**NOT for:**
- Extracting data from text/images → `json-outputs-implementer`
- Formatting API responses → `json-outputs-implementer`
- Classification tasks → `json-outputs-implementer`
## Response Style
- **Tool-focused**: Design tools with clear, validated schemas
- **Agent-aware**: Consider multi-tool workflows and composition
- **Type-safe**: Guarantee parameter types for downstream functions
- **Production-ready**: Handle errors, retries, and monitoring
- **Example-driven**: Provide complete agent implementations
## Workflow
| Phase | Description | Details |
|-------|-------------|---------|
| 1 | Tool Schema Design | → [workflow/phase-1-schema-design.md](workflow/phase-1-schema-design.md) |
| 2 | Multi-Tool Agent Implementation | → [workflow/phase-2-implementation.md](workflow/phase-2-implementation.md) |
| 3 | Error Handling & Validation | → [workflow/phase-3-error-handling.md](workflow/phase-3-error-handling.md) |
| 4 | Testing Agent Workflows | → [workflow/phase-4-testing.md](workflow/phase-4-testing.md) |
| 5 | Production Agent Patterns | → [workflow/phase-5-production.md](workflow/phase-5-production.md) |
## Quick Reference
### Schema Template
```python
{
"name": "tool_name",
"description": "Clear description",
"strict": True,
"input_schema": {
"type": "object",
"properties": {...},
"required": [...],
"additionalProperties": False
}
}
```
### Supported Schema Features
✅ Basic types, enums, format strings, nested objects/arrays, required fields
❌ Recursive schemas, min/max constraints, string length, complex regex
## Reference Materials
- [Common Agentic Patterns](reference/common-patterns.md)
- [Success Criteria](reference/success-criteria.md)
## Related Skills
- `structured-outputs-advisor` - Choose the right mode
- `json-outputs-implementer` - For data extraction use cases

View File

@@ -0,0 +1,289 @@
"""
Travel Booking Agent Example
Multi-tool agent using strict tool use mode for guaranteed parameter validation.
Demonstrates validated tool inputs in agentic workflows.
"""
from anthropic import Anthropic
from typing import Dict, Any, List
import json
import os
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Define tools with strict mode
TOOLS = [
{
"name": "search_flights",
"description": "Search for available flights between two cities",
"strict": True, # Enable strict parameter validation
"input_schema": {
"type": "object",
"properties": {
"origin": {
"type": "string",
"description": "Departure city (e.g., 'San Francisco, CA')"
},
"destination": {
"type": "string",
"description": "Arrival city (e.g., 'Paris, France')"
},
"departure_date": {
"type": "string",
"format": "date",
"description": "Departure date in YYYY-MM-DD format"
},
"return_date": {
"type": "string",
"format": "date",
"description": "Return date in YYYY-MM-DD format (optional for one-way)"
},
"travelers": {
"type": "integer",
"enum": [1, 2, 3, 4, 5, 6],
"description": "Number of travelers"
}
},
"required": ["origin", "destination", "departure_date", "travelers"],
"additionalProperties": False # Required for strict mode
}
},
{
"name": "book_flight",
"description": "Book a selected flight",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"flight_id": {
"type": "string",
"description": "Flight identifier from search results"
},
"passenger_names": {
"type": "array",
"items": {"type": "string"},
"description": "Full names of all passengers"
},
"contact_email": {
"type": "string",
"format": "email",
"description": "Contact email for booking confirmation"
}
},
"required": ["flight_id", "passenger_names", "contact_email"],
"additionalProperties": False
}
},
{
"name": "search_hotels",
"description": "Search for hotels in a city",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name"
},
"check_in": {
"type": "string",
"format": "date",
"description": "Check-in date in YYYY-MM-DD format"
},
"check_out": {
"type": "string",
"format": "date",
"description": "Check-out date in YYYY-MM-DD format"
},
"guests": {
"type": "integer",
"enum": [1, 2, 3, 4],
"description": "Number of guests"
}
},
"required": ["city", "check_in", "check_out", "guests"],
"additionalProperties": False
}
}
]
# Mock tool implementations
def search_flights(origin: str, destination: str, departure_date: str,
travelers: int, return_date: str = None) -> Dict:
"""Mock flight search - would call real API."""
print(f"🔍 Searching flights: {origin}{destination}")
print(f" Departure: {departure_date}, Travelers: {travelers}")
return {
"flights": [
{
"id": "FL123",
"airline": "Air France",
"departure": f"{departure_date} 10:00",
"arrival": f"{departure_date} 23:00",
"price": 850.00,
"class": "Economy"
},
{
"id": "FL456",
"airline": "United",
"departure": f"{departure_date} 14:30",
"arrival": f"{departure_date} 03:30+1",
"price": 920.00,
"class": "Economy"
}
]
}
def book_flight(flight_id: str, passenger_names: List[str],
contact_email: str) -> Dict:
"""Mock flight booking - would call real API."""
print(f"✈️ Booking flight {flight_id}")
print(f" Passengers: {', '.join(passenger_names)}")
print(f" Email: {contact_email}")
return {
"confirmation": "ABC123XYZ",
"status": "confirmed",
"total_price": 850.00 * len(passenger_names)
}
def search_hotels(city: str, check_in: str, check_out: str, guests: int) -> Dict:
"""Mock hotel search - would call real API."""
print(f"🏨 Searching hotels in {city}")
print(f" Check-in: {check_in}, Check-out: {check_out}, Guests: {guests}")
return {
"hotels": [
{
"id": "HTL789",
"name": "Grand Hotel Paris",
"rating": 4.5,
"price_per_night": 200.00,
"amenities": ["WiFi", "Breakfast", "Gym"]
},
{
"id": "HTL101",
"name": "Budget Inn",
"rating": 3.5,
"price_per_night": 80.00,
"amenities": ["WiFi"]
}
]
}
# Tool registry
TOOL_FUNCTIONS = {
"search_flights": search_flights,
"book_flight": book_flight,
"search_hotels": search_hotels,
}
def run_travel_agent(user_request: str, max_turns: int = 10):
"""
Run travel booking agent with strict tool validation.
With strict mode enabled, all tool inputs are GUARANTEED to match
the schema - no validation needed in tool functions!
"""
messages = [{"role": "user", "content": user_request}]
print("=" * 70)
print(f"User Request: {user_request}")
print("=" * 70)
for turn in range(max_turns):
print(f"\n🤖 Agent Turn {turn + 1}")
response = client.beta.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
betas=["structured-outputs-2025-11-13"],
messages=messages,
tools=TOOLS,
)
# Check stop reason
if response.stop_reason == "end_turn":
# Agent finished
final_text = ""
for block in response.content:
if hasattr(block, "text"):
final_text += block.text
print(f"\n✅ Agent Complete:")
print(f"{final_text}")
return final_text
if response.stop_reason == "tool_use":
# Execute tools
tool_results = []
for block in response.content:
if block.type == "text":
print(f"\n💭 Agent: {block.text}")
elif block.type == "tool_use":
tool_name = block.name
tool_input = block.input # GUARANTEED to match schema!
print(f"\n🔧 Tool Call: {tool_name}")
print(f" Input: {json.dumps(tool_input, indent=2)}")
# Execute tool with validated inputs
tool_function = TOOL_FUNCTIONS[tool_name]
result = tool_function(**tool_input) # Type-safe!
print(f" Result: {json.dumps(result, indent=2)}")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result)
})
# Add to conversation
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
print(f"⚠️ Unexpected stop reason: {response.stop_reason}")
break
print("\n⚠️ Max turns reached without completion")
return None
def main():
"""Run travel agent examples."""
examples = [
"Book a round trip from San Francisco to Paris for 2 people, "
"departing May 15, 2024 and returning May 22, 2024. "
"Passengers are John Smith and Jane Doe. "
"Email confirmation to john.smith@example.com. "
"Also find a hotel in Paris for those dates.",
"Find flights from New York to London for 1 traveler on June 1, 2024.",
"Search for hotels in Tokyo for 2 guests, checking in July 10 "
"and checking out July 15.",
]
for i, request in enumerate(examples, 1):
print(f"\n\n{'='*70}")
print(f"EXAMPLE {i}")
print(f"{'='*70}")
run_travel_agent(request)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,48 @@
# Common Agentic Patterns
## Pattern 1: Sequential Workflow
Tools execute in sequence (search → book → confirm):
```python
# User: "Book a flight to Paris"
# Agent executes:
1. search_flights(origin="SF", destination="Paris", ...)
2. book_flight(flight_id="F1", passengers=[...])
3. send_confirmation(confirmation_id="ABC123")
```
## Pattern 2: Parallel Tool Execution
Multiple independent tools (flights + hotels):
```python
# User: "Find flights and hotels for Paris trip"
# Agent can call in parallel (if your implementation supports it):
1. search_flights(destination="Paris", ...)
2. search_hotels(city="Paris", ...)
```
## Pattern 3: Conditional Branching
Tool selection based on context:
```python
# User: "Plan my trip"
# Agent decides which tools to call based on conversation:
if budget_conscious:
search_flights(class="economy")
else:
search_flights(class="business")
```
## Important Reminders
1. **Always set `strict: true`** - This enables validation
2. **Require `additionalProperties: false`** - Enforced by strict mode
3. **Use enums for constrained values** - Better than free text
4. **Clear descriptions matter** - Claude uses these to decide when to call tools
5. **Tool inputs are guaranteed valid** - No validation needed in tool functions
6. **Handle tool execution failures** - External APIs can fail
7. **Test multi-step workflows** - Edge cases appear in tool composition
8. **Monitor agent behavior** - Track tool usage patterns and failures

View File

@@ -0,0 +1,23 @@
# Success Criteria
## Implementation Checklist
- [ ] Tool schemas designed with `strict: true`
- [ ] All tools have `additionalProperties: false`
- [ ] Clear descriptions for tools and parameters
- [ ] Required fields properly specified
- [ ] Multi-tool workflow implemented
- [ ] Error handling for tool failures
- [ ] Refusal scenarios handled
- [ ] Agent tested with realistic scenarios
- [ ] Production patterns applied (retry, validation)
- [ ] Monitoring in place
## Official Documentation
https://docs.anthropic.com/en/docs/build-with-claude/structured-outputs
## Related Skills
- `structured-outputs-advisor` - Choose the right mode
- `json-outputs-implementer` - For data extraction use cases

View File

@@ -0,0 +1,125 @@
# Phase 1: Tool Schema Design
**Objective**: Design validated tool schemas for your agent
## Steps
### 1. Identify Required Tools
Ask the user:
- "What actions should the agent be able to perform?"
- "What external systems will the agent interact with?"
- "What parameters does each tool need?"
**Example agent**: Travel booking
- `search_flights` - Find available flights
- `book_flight` - Reserve a flight
- `search_hotels` - Find hotels
- `book_hotel` - Reserve accommodation
### 2. Design Tool Schema with `strict: true`
**Template:**
```python
{
"name": "tool_name",
"description": "Clear description of what this tool does",
"strict": True, # ← Enables strict mode
"input_schema": {
"type": "object",
"properties": {
"param_name": {
"type": "string",
"description": "Clear parameter description"
}
},
"required": ["param_name"],
"additionalProperties": False # ← Required
}
}
```
**Example: Flight Search Tool**
```python
{
"name": "search_flights",
"description": "Search for available flights between two cities",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"origin": {
"type": "string",
"description": "Departure city (e.g., 'San Francisco, CA')"
},
"destination": {
"type": "string",
"description": "Arrival city (e.g., 'Paris, France')"
},
"departure_date": {
"type": "string",
"format": "date",
"description": "Departure date in YYYY-MM-DD format"
},
"return_date": {
"type": "string",
"format": "date",
"description": "Return date in YYYY-MM-DD format (optional)"
},
"travelers": {
"type": "integer",
"enum": [1, 2, 3, 4, 5, 6],
"description": "Number of travelers"
},
"class": {
"type": "string",
"enum": ["economy", "premium", "business", "first"],
"description": "Flight class preference"
}
},
"required": ["origin", "destination", "departure_date", "travelers"],
"additionalProperties": False
}
}
```
### 3. Apply JSON Schema Limitations
**✅ Supported:**
- All basic types (object, array, string, integer, number, boolean)
- `enum` for constrained values
- `format` for strings (date, email, uri, uuid, etc.)
- Nested objects and arrays
- `required` fields
- `additionalProperties: false` (required!)
**❌ NOT Supported:**
- Recursive schemas
- Numerical constraints (minimum, maximum)
- String length constraints
- Complex regex patterns
### 4. Add Clear Descriptions
Good descriptions help Claude:
- Understand when to call the tool
- Know what values to provide
- Format parameters correctly
```python
# ✅ Good: Clear and specific
"origin": {
"type": "string",
"description": "Departure city and state/country (e.g., 'San Francisco, CA')"
}
# ❌ Vague: Not helpful
"origin": {
"type": "string",
"description": "Origin"
}
```
## Output
Well-designed tool schemas ready for implementation.

View File

@@ -0,0 +1,222 @@
# Phase 2: Multi-Tool Agent Implementation
**Objective**: Implement agent with multiple validated tools
## Python Implementation
```python
from anthropic import Anthropic
from typing import Dict, Any, List
client = Anthropic()
# Define tools
TOOLS = [
{
"name": "search_flights",
"description": "Search for available flights",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"origin": {"type": "string", "description": "Departure city"},
"destination": {"type": "string", "description": "Arrival city"},
"departure_date": {"type": "string", "format": "date"},
"travelers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6]}
},
"required": ["origin", "destination", "departure_date", "travelers"],
"additionalProperties": False
}
},
{
"name": "book_flight",
"description": "Book a selected flight",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"flight_id": {"type": "string", "description": "Flight identifier"},
"passengers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"passport": {"type": "string"}
},
"required": ["name", "passport"],
"additionalProperties": False
}
}
},
"required": ["flight_id", "passengers"],
"additionalProperties": False
}
},
{
"name": "search_hotels",
"description": "Search for hotels in a city",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"},
"check_in": {"type": "string", "format": "date"},
"check_out": {"type": "string", "format": "date"},
"guests": {"type": "integer", "enum": [1, 2, 3, 4]}
},
"required": ["city", "check_in", "check_out", "guests"],
"additionalProperties": False
}
}
]
# Tool execution functions
def search_flights(origin: str, destination: str, departure_date: str, travelers: int) -> Dict:
"""Execute flight search - calls actual API."""
# Implementation here
return {"flights": [...]}
def book_flight(flight_id: str, passengers: List[Dict]) -> Dict:
"""Book the flight - calls actual API."""
# Implementation here
return {"confirmation": "ABC123", "status": "confirmed"}
def search_hotels(city: str, check_in: str, check_out: str, guests: int) -> Dict:
"""Search hotels - calls actual API."""
# Implementation here
return {"hotels": [...]}
# Tool registry
TOOL_FUNCTIONS = {
"search_flights": search_flights,
"book_flight": book_flight,
"search_hotels": search_hotels,
}
# Agent loop
def run_agent(user_request: str, max_turns: int = 10):
"""Run agent with tool validation."""
messages = [{"role": "user", "content": user_request}]
for turn in range(max_turns):
response = client.beta.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
betas=["structured-outputs-2025-11-13"],
messages=messages,
tools=TOOLS,
)
# Process response
if response.stop_reason == "end_turn":
# Agent finished
return extract_final_answer(response)
if response.stop_reason == "tool_use":
# Execute tools
tool_results = []
for block in response.content:
if block.type == "tool_use":
# Tool input is GUARANTEED to match schema
tool_name = block.name
tool_input = block.input # Already validated!
# Execute tool
tool_function = TOOL_FUNCTIONS[tool_name]
result = tool_function(**tool_input) # Type-safe!
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(result)
})
# Add assistant response and tool results to conversation
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
raise Exception(f"Unexpected stop reason: {response.stop_reason}")
raise Exception("Max turns reached")
# Usage
result = run_agent("Book a flight from SF to Paris for 2 people, departing May 15")
print(result)
```
## TypeScript Implementation
```typescript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const TOOLS: Anthropic.Tool[] = [
{
name: "search_flights",
description: "Search for available flights",
strict: true,
input_schema: {
type: "object",
properties: {
origin: { type: "string", description: "Departure city" },
destination: { type: "string", description: "Arrival city" },
departure_date: { type: "string", format: "date" },
travelers: { type: "integer", enum: [1, 2, 3, 4, 5, 6] }
},
required: ["origin", "destination", "departure_date", "travelers"],
additionalProperties: false
}
},
// ... other tools
];
async function runAgent(userRequest: string, maxTurns: number = 10) {
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: userRequest }
];
for (let turn = 0; turn < maxTurns; turn++) {
const response = await client.beta.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 2048,
betas: ["structured-outputs-2025-11-13"],
messages,
tools: TOOLS,
});
if (response.stop_reason === "end_turn") {
return extractFinalAnswer(response);
}
if (response.stop_reason === "tool_use") {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === "tool_use") {
// Input guaranteed to match schema!
const result = await executeTool(block.name, block.input);
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result)
});
}
}
messages.push({ role: "assistant", content: response.content });
messages.push({ role: "user", content: toolResults });
}
}
throw new Error("Max turns reached");
}
```
## Output
Working multi-tool agent with validated tool schemas.

View File

@@ -0,0 +1,58 @@
# Phase 3: Error Handling & Validation
**Objective**: Handle errors and edge cases in agent workflows
## Key Error Scenarios
### 1. Tool Execution Failures
```python
def execute_tool_safely(tool_name: str, tool_input: Dict) -> Dict:
"""Execute tool with error handling."""
try:
tool_function = TOOL_FUNCTIONS[tool_name]
result = tool_function(**tool_input)
return {"success": True, "data": result}
except Exception as e:
logger.error(f"Tool {tool_name} failed: {e}")
return {
"success": False,
"error": str(e),
"message": "Tool execution failed. Please try again."
}
```
### 2. Safety Refusals
```python
if response.stop_reason == "refusal":
logger.warning("Agent refused request")
# Don't retry - respect safety boundaries
return {"error": "Request cannot be completed"}
```
### 3. Max Turns Exceeded
```python
if turn >= max_turns:
logger.warning("Agent exceeded max turns")
return {
"error": "Task too complex",
"partial_progress": extract_progress(messages)
}
```
### 4. Invalid Tool Name
```python
# With strict mode, tool names are guaranteed valid
# But external factors can cause issues
if tool_name not in TOOL_FUNCTIONS:
logger.error(f"Unknown tool: {tool_name}")
return {"error": f"Tool {tool_name} not implemented"}
```
## Output
Robust error handling for production agent workflows.

View File

@@ -0,0 +1,81 @@
# Phase 4: Testing Agent Workflows
**Objective**: Validate agent behavior with realistic scenarios
## Test Strategy
```python
import pytest
from unittest.mock import Mock, patch
@pytest.fixture
def mock_tool_functions():
"""Mock external tool functions."""
return {
"search_flights": Mock(return_value={"flights": [{"id": "F1", "price": 500}]}),
"book_flight": Mock(return_value={"confirmation": "ABC123"}),
"search_hotels": Mock(return_value={"hotels": [{"id": "H1", "price": 150}]}),
}
def test_simple_flight_search(mock_tool_functions):
"""Test agent handles simple flight search."""
with patch.dict('agent.TOOL_FUNCTIONS', mock_tool_functions):
result = run_agent("Find flights from SF to LA on May 15 for 2 people")
# Verify search_flights was called
mock_tool_functions["search_flights"].assert_called_once()
call_args = mock_tool_functions["search_flights"].call_args[1]
# Strict mode guarantees these match schema
assert call_args["origin"] == "San Francisco, CA" # or similar
assert call_args["destination"] == "Los Angeles, CA"
assert call_args["travelers"] == 2
assert "2024-05-15" in call_args["departure_date"]
def test_multi_step_booking(mock_tool_functions):
"""Test agent completes multi-step booking."""
with patch.dict('agent.TOOL_FUNCTIONS', mock_tool_functions):
result = run_agent(
"Book a round trip from SF to Paris for 2 people, "
"May 15-22, and find a hotel"
)
# Verify correct tool sequence
assert mock_tool_functions["search_flights"].called
assert mock_tool_functions["book_flight"].called
assert mock_tool_functions["search_hotels"].called
def test_tool_failure_handling(mock_tool_functions):
"""Test agent handles tool failures gracefully."""
mock_tool_functions["search_flights"].side_effect = Exception("API down")
with patch.dict('agent.TOOL_FUNCTIONS', mock_tool_functions):
result = run_agent("Find flights to Paris")
# Should handle error gracefully
assert "error" in result or "failed" in str(result).lower()
def test_parameter_validation():
"""Test that strict mode guarantees valid parameters."""
# With strict mode, parameters are guaranteed to match schema
# This test verifies the guarantee holds
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Search flights for 2 people"}],
tools=TOOLS,
)
for block in response.content:
if block.type == "tool_use":
# These assertions should NEVER fail with strict mode
assert isinstance(block.input, dict)
assert "travelers" in block.input
assert isinstance(block.input["travelers"], int)
assert block.input["travelers"] in [1, 2, 3, 4, 5, 6]
```
## Output
Comprehensive test coverage for agent workflows.

View File

@@ -0,0 +1,98 @@
# Phase 5: Production Agent Patterns
**Objective**: Production-ready agent architectures
## Pattern 1: Stateful Agent with Memory
```python
class StatefulTravelAgent:
"""Agent that maintains state across interactions."""
def __init__(self):
self.conversation_history: List[Dict] = []
self.booking_state: Dict[str, Any] = {}
def chat(self, user_message: str) -> str:
"""Process user message and return response."""
self.conversation_history.append({
"role": "user",
"content": user_message
})
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
max_tokens=2048,
messages=self.conversation_history,
tools=TOOLS,
)
# Process tools and update state
final_response = self._process_response(response)
self.conversation_history.append({
"role": "assistant",
"content": final_response
})
return final_response
def _process_response(self, response) -> str:
"""Process tool calls and maintain state."""
# Implementation...
pass
# Usage
agent = StatefulTravelAgent()
print(agent.chat("I want to go to Paris"))
print(agent.chat("For 2 people")) # Remembers context
print(agent.chat("May 15 to May 22")) # Continues booking
```
## Pattern 2: Tool Retry Logic
```python
def execute_tool_with_retry(
tool_name: str,
tool_input: Dict,
max_retries: int = 3
) -> Dict:
"""Execute tool with exponential backoff retry."""
import time
for attempt in range(max_retries):
try:
tool_func = TOOL_FUNCTIONS[tool_name]
result = tool_func(**tool_input)
return {"success": True, "data": result}
except Exception as e:
if attempt == max_retries - 1:
return {"success": False, "error": str(e)}
wait_time = 2 ** attempt # Exponential backoff
logger.warning(f"Tool {tool_name} failed, retrying in {wait_time}s")
time.sleep(wait_time)
```
## Pattern 3: Tool Result Validation
```python
def validate_tool_result(tool_name: str, result: Any) -> bool:
"""Validate tool execution result."""
validators = {
"search_flights": lambda r: "flights" in r and len(r["flights"]) > 0,
"book_flight": lambda r: "confirmation" in r,
"search_hotels": lambda r: "hotels" in r,
}
validator = validators.get(tool_name)
if validator:
return validator(result)
return True # No validator = assume valid
```
## Output
Production-ready agent patterns with state management, retry logic, and validation.

View File

@@ -0,0 +1,16 @@
# Changelog
## 0.2.0
- Refactored to Anthropic progressive disclosure pattern
- Updated description with "Use PROACTIVELY when..." format
- Removed version/author/category/tags from frontmatter
## 0.1.0
- Initial release of Structured Outputs Advisor skill
- Requirements gathering workflow
- Mode selection logic (JSON outputs vs strict tool use)
- Decision matrix for common scenarios
- Delegation patterns to specialized skills
- Mode selection examples covering 8 common scenarios

View File

@@ -0,0 +1,59 @@
# Structured Outputs Advisor
Expert advisor skill for choosing between JSON outputs and strict tool use modes in Anthropic's structured outputs feature.
## Purpose
This skill serves as the **entry point** for implementing structured outputs. It analyzes your requirements and recommends the right mode:
- **JSON Outputs** (`output_format`) - For data extraction, classification, API formatting
- **Strict Tool Use** (`strict: true`) - For agentic workflows, validated tool parameters
Then delegates to specialized implementation skills.
## When to Use
Invoke this skill when you need:
- Guaranteed JSON schema compliance
- Validated tool input parameters
- Structured data extraction
- Type-safe API responses
- Reliable agentic workflows
## Quick Start
**Trigger phrases:**
- "implement structured outputs"
- "need guaranteed JSON schema"
- "extract structured data from..."
- "build reliable agent with validated tools"
The advisor will ask questions to understand your use case and recommend the appropriate mode.
## Workflow
1. **Requirements gathering** - Understand what you're building
2. **Mode selection** - JSON outputs vs strict tool use
3. **Delegation** - Hand off to specialized skill for implementation
## Related Skills
- [`json-outputs-implementer`](../json-outputs-implementer/) - Implements JSON outputs mode
- [`strict-tool-implementer`](../strict-tool-implementer/) - Implements strict tool use mode
## Examples
See [mode-selection-examples.md](./examples/mode-selection-examples.md) for detailed scenarios.
## Documentation
- [Official Structured Outputs Docs](https://docs.anthropic.com/en/docs/build-with-claude/structured-outputs)
- [JSON Schema Limitations](../reference/json-schema-limitations.md)
- [Best Practices](../reference/best-practices.md)
- [API Compatibility](../reference/api-compatibility.md)
## Version
Current version: 0.1.0
See [CHANGELOG.md](./CHANGELOG.md) for version history.

View File

@@ -0,0 +1,283 @@
---
name: structured-outputs-advisor
description: Use PROACTIVELY when users need guaranteed schema compliance or validated tool inputs from Anthropic's structured outputs feature. Expert advisor for choosing between JSON outputs (data extraction/formatting) and strict tool use (agentic workflows). Analyzes requirements, explains trade-offs, and delegates to specialized implementation skills. Not for simple text responses or unstructured outputs.
---
# Structured Outputs Advisor
## Overview
This skill serves as the entry point for implementing Anthropic's structured outputs feature. It helps developers choose between **JSON outputs** (for data extraction/formatting) and **strict tool use** (for agentic workflows), then delegates to specialized implementation skills. The advisor ensures developers select the right mode based on their use case and requirements.
**Two Modes Available:**
1. **JSON Outputs** (`output_format`) - Guaranteed JSON schema compliance for responses
2. **Strict Tool Use** (`strict: true`) - Validated tool parameters for function calls
**Specialized Implementation Skills:**
- `json-outputs-implementer` - For data extraction, classification, API formatting
- `strict-tool-implementer` - For agentic workflows, validated function calls
## When to Use This Skill
**Trigger Phrases:**
- "implement structured outputs"
- "need guaranteed JSON schema"
- "extract structured data from [source]"
- "validate tool inputs"
- "build reliable agentic workflow"
- "ensure type-safe responses"
- "help me with structured outputs"
**Use Cases:**
- Data extraction from text/images
- Classification with guaranteed output format
- API response formatting
- Agentic workflows with validated tools
- Type-safe database operations
- Complex tool parameter validation
## Response Style
- **Consultative**: Ask questions to understand requirements
- **Educational**: Explain both modes and when to use each
- **Decisive**: Recommend the right mode based on use case
- **Delegating**: Hand off to specialized skills for implementation
- **Concise**: Keep mode selection phase quick (<5 questions)
## Core Workflow
### Phase 1: Understand Requirements
**Questions to Ask:**
1. **What's your goal?**
- "What kind of output do you need Claude to produce?"
- Examples: Extract invoice data, validate function parameters, classify tickets
2. **What's the data source?**
- Text, images, API calls, user input, etc.
3. **What consumes the output?**
- Database, API endpoint, function call, agent workflow, etc.
4. **How critical is schema compliance?**
- Must be guaranteed vs. generally reliable
### Phase 2: Mode Selection
**Use JSON Outputs (`output_format`) when:**
- ✅ You need Claude's **response** in a specific format
- ✅ Extracting structured data from unstructured sources
- ✅ Generating reports, classifications, or API responses
- ✅ Formatting output for downstream processing
- ✅ Single-step operations
**Examples:**
- Extract contact info from emails → CRM database
- Classify support tickets → routing system
- Generate structured reports → API endpoint
- Parse invoices → accounting software
**Use Strict Tool Use (`strict: true`) when:**
- ✅ You need validated **tool input parameters**
- ✅ Building multi-step agentic workflows
- ✅ Ensuring type-safe function calls
- ✅ Complex tools with many/nested properties
- ✅ Critical operations requiring guaranteed types
**Examples:**
- Travel booking agent (flights + hotels + activities)
- Database operations with strict type requirements
- API orchestration with validated parameters
- Complex workflow automation
### Phase 3: Delegation
**After determining the mode, delegate to the specialized skill:**
**For JSON Outputs:**
```
I recommend using JSON outputs for your [use case].
I'm going to invoke the json-outputs-implementer skill to help you:
1. Design a production-ready JSON schema
2. Implement with SDK helpers (Pydantic/Zod)
3. Add validation and error handling
4. Optimize for production
[Launch json-outputs-implementer skill]
```
**For Strict Tool Use:**
```
I recommend using strict tool use for your [use case].
I'm going to invoke the strict-tool-implementer skill to help you:
1. Design validated tool schemas
2. Implement strict mode correctly
3. Build reliable agent workflows
4. Test and validate tool calls
[Launch strict-tool-implementer skill]
```
**For Both Modes (Hybrid):**
```
Your use case requires both modes:
- JSON outputs for [specific use case]
- Strict tool use for [specific use case]
I'll help you implement both, starting with [primary mode].
[Launch appropriate skill first, then the second one]
```
## Decision Matrix
| Requirement | JSON Outputs | Strict Tool Use |
|-------------|--------------|-----------------|
| Extract structured data | ✅ Primary use case | ❌ Not designed for this |
| Validate function parameters | ❌ Not designed for this | ✅ Primary use case |
| Multi-step agent workflows | ⚠️ Possible but not ideal | ✅ Designed for this |
| API response formatting | ✅ Ideal | ❌ Unnecessary |
| Database inserts (type safety) | ✅ Good fit | ⚠️ If via tool calls |
| Complex nested schemas | ✅ Supports this | ✅ Supports this |
| Classification tasks | ✅ Perfect fit | ❌ Overkill |
| Tool composition/chaining | ❌ Not applicable | ✅ Excellent |
## Feature Availability
**Models Supported:**
- ✅ Claude Sonnet 4.5 (`claude-sonnet-4-5`)
- ✅ Claude Opus 4.1 (`claude-opus-4-1`)
**Beta Header Required:**
```
anthropic-beta: structured-outputs-2025-11-13
```
**Incompatible Features:**
- ❌ Citations (with JSON outputs)
- ❌ Message Prefilling (with JSON outputs)
**Compatible Features:**
- ✅ Batch Processing (50% discount)
- ✅ Token Counting
- ✅ Streaming
- ✅ Both modes together in same request
## Common Scenarios
### Scenario 1: "I need to extract invoice data"
**Analysis**: Data extraction from unstructured text
**Mode**: JSON Outputs
**Delegation**: `json-outputs-implementer`
**Reason**: Single-step extraction with structured output format
### Scenario 2: "Building a travel booking agent"
**Analysis**: Multi-tool workflow (flights, hotels, activities)
**Mode**: Strict Tool Use
**Delegation**: `strict-tool-implementer`
**Reason**: Multiple validated tools in agent workflow
### Scenario 3: "Classify customer support tickets"
**Analysis**: Classification with guaranteed categories
**Mode**: JSON Outputs
**Delegation**: `json-outputs-implementer`
**Reason**: Single classification result, structured response
### Scenario 4: "Validate database insert parameters"
**Analysis**: Type-safe database operations
**Mode**: JSON Outputs (if direct) OR Strict Tool Use (if via tool)
**Delegation**: Depends on architecture
**Reason**: Both work - choose based on system architecture
### Scenario 5: "Generate API-ready responses"
**Analysis**: Format responses for API consumption
**Mode**: JSON Outputs
**Delegation**: `json-outputs-implementer`
**Reason**: Output formatting is primary goal
## Quick Start Examples
### JSON Outputs Example
```python
# Extract contact information
from pydantic import BaseModel
from anthropic import Anthropic
class Contact(BaseModel):
name: str
email: str
plan: str
client = Anthropic()
response = client.beta.messages.parse(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Extract contact info..."}],
output_format=Contact,
)
contact = response.parsed_output # Guaranteed schema match
```
### Strict Tool Use Example
```python
# Validated tool for agent workflow
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Book a flight..."}],
tools=[{
"name": "book_flight",
"strict": True, # Guarantees schema compliance
"input_schema": {
"type": "object",
"properties": {
"destination": {"type": "string"},
"passengers": {"type": "integer"}
},
"required": ["destination"],
"additionalProperties": False
}
}]
)
# Tool inputs guaranteed to match schema
```
## Success Criteria
- [ ] Requirements clearly understood
- [ ] Data source identified
- [ ] Output consumer identified
- [ ] Correct mode selected (JSON outputs vs strict tool use)
- [ ] Reasoning for mode selection explained
- [ ] Appropriate specialized skill invoked
- [ ] User understands next steps
## Important Reminders
1. **Ask before assuming** - Don't guess the mode, understand requirements first
2. **One mode is usually enough** - Most use cases need only one mode
3. **Delegate quickly** - Keep advisor phase short, let specialists handle implementation
4. **Both modes work together** - Can use both in same request if needed
5. **Model availability** - Confirm Sonnet 4.5 or Opus 4.1 is available
6. **Beta feature** - Requires beta header in API requests
## Next Steps After Mode Selection
Once mode is selected and you've delegated to the specialized skill, that skill will handle:
- ✅ Schema design (respecting JSON Schema limitations)
- ✅ SDK integration (Pydantic/Zod helpers)
- ✅ Implementation with error handling
- ✅ Testing and validation
- ✅ Production optimization
- ✅ Complete examples and documentation
---
**Official Documentation**: https://docs.anthropic.com/en/docs/build-with-claude/structured-outputs
**Related Skills**:
- `json-outputs-implementer` - Implement JSON outputs mode
- `strict-tool-implementer` - Implement strict tool use mode

View File

@@ -0,0 +1,234 @@
# Mode Selection Examples
Real-world scenarios showing how the advisor helps choose between JSON outputs and strict tool use.
## Example 1: Invoice Data Extraction
**User Request:**
> "I need to extract invoice data from PDF documents and store it in our PostgreSQL database. The invoices contain line items, tax information, and customer details."
**Advisor Analysis:**
- **Goal:** Extract structured data from documents
- **Source:** PDF documents (unstructured)
- **Consumer:** PostgreSQL database (needs type-safe inserts)
- **Complexity:** Single-step extraction
**Recommended Mode:** JSON Outputs
**Reasoning:**
- This is a data extraction task (primary use case for JSON outputs)
- Single-step operation (extract → database)
- No multi-step agent workflow needed
- Schema compliance ensures database insert succeeds
**Next Step:**
Delegate to `json-outputs-implementer` to design invoice schema with line items, tax calculations, and customer info fields.
---
## Example 2: Travel Booking Agent
**User Request:**
> "Build an agent that can help users book complete travel itineraries. It should search for flights, compare options, book the chosen flight, find hotels near their destination, and book accommodation."
**Advisor Analysis:**
- **Goal:** Multi-step booking workflow
- **Source:** User conversation
- **Consumer:** Multiple external APIs (flights, hotels, booking systems)
- **Complexity:** Multi-tool agent workflow with sequential dependencies
**Recommended Mode:** Strict Tool Use
**Reasoning:**
- Multi-step workflow (search → compare → book → search → book)
- Multiple tools that need validated parameters
- Tool composition (flight booking influences hotel search location)
- Type-safe API calls are critical (booking with wrong parameters could charge cards incorrectly)
**Next Step:**
Delegate to `strict-tool-implementer` to design tool schemas for `search_flights`, `book_flight`, `search_hotels`, `book_hotel` with strict parameter validation.
---
## Example 3: Support Ticket Classification
**User Request:**
> "We receive thousands of support tickets daily. I need to automatically classify them by category (billing, technical, sales), priority level, and route them to the right team."
**Advisor Analysis:**
- **Goal:** Classification with routing
- **Source:** Support ticket text
- **Consumer:** Routing system + metrics dashboard
- **Complexity:** Single classification operation
**Recommended Mode:** JSON Outputs
**Reasoning:**
- Classification task (perfect for JSON outputs)
- Fixed output schema (category, priority, team, confidence)
- Single-step operation
- No tool execution needed (just classification output)
**Next Step:**
Delegate to `json-outputs-implementer` to design classification schema with enums for category/priority, confidence scoring, and routing metadata.
---
## Example 4: Database Query Agent
**User Request:**
> "I want an agent that can answer questions about our sales data. It should translate natural language questions into SQL, execute the queries safely, and return formatted results."
**Advisor Analysis:**
- **Goal:** Natural language → SQL query execution
- **Source:** User questions in natural language
- **Consumer:** Database + user (formatted results)
- **Complexity:** Tool execution with type-safe parameters + structured output
**Recommended Mode:** Both (Hybrid Approach)
**Reasoning:**
- Tool use for SQL execution: Need `execute_sql` tool with validated query parameters (prevent SQL injection)
- JSON outputs for response: Want structured results formatted consistently
- Two distinct phases: query generation/execution → result formatting
**Next Step:**
1. First: Delegate to `strict-tool-implementer` for `execute_sql` tool with strict validation
2. Then: Delegate to `json-outputs-implementer` for result formatting schema
---
## Example 5: Resume Parser
**User Request:**
> "Parse resumes in various formats (PDF, DOCX, plain text) and extract structured information: personal details, work experience, education, skills. Store in our ATS database."
**Advisor Analysis:**
- **Goal:** Extract structured data from documents
- **Source:** Resume documents (various formats)
- **Consumer:** ATS (Applicant Tracking System) database
- **Complexity:** Single extraction operation
**Recommended Mode:** JSON Outputs
**Reasoning:**
- Data extraction from unstructured documents
- Well-defined output schema (resume has standard sections)
- No tool execution needed
- Database insertion requires type-safe data
**Next Step:**
Delegate to `json-outputs-implementer` to design resume schema with nested objects for work experience, education, and skills arrays.
---
## Example 6: API Response Formatter
**User Request:**
> "Our API needs to return consistent JSON responses. Sometimes Claude generates the response data, and I need it formatted exactly to our API spec with status, data, errors, and metadata fields."
**Advisor Analysis:**
- **Goal:** Format API responses consistently
- **Source:** Claude-generated content
- **Consumer:** API clients (web/mobile apps)
- **Complexity:** Response formatting
**Recommended Mode:** JSON Outputs
**Reasoning:**
- Response formatting task
- Fixed API schema that must be followed exactly
- No tool execution
- Consistency is critical for API clients
**Next Step:**
Delegate to `json-outputs-implementer` to design API response schema matching the spec, with proper error handling structure.
---
## Example 7: Research Assistant Agent
**User Request:**
> "Build an agent that researches topics by searching the web, reading articles, extracting key facts, cross-referencing sources, and generating a comprehensive research report."
**Advisor Analysis:**
- **Goal:** Multi-step research workflow
- **Source:** Web (via search tools, article fetchers)
- **Consumer:** User (research report)
- **Complexity:** Multi-tool workflow with sequential and parallel steps + structured output
**Recommended Mode:** Both (Hybrid Approach)
**Reasoning:**
- Research phase: Need tools (`search_web`, `fetch_article`, `extract_facts`) with strict validation
- Report phase: Need structured report output (JSON outputs)
- Complex workflow with multiple stages
**Next Step:**
1. First: Delegate to `strict-tool-implementer` for research tools
2. Then: Delegate to `json-outputs-implementer` for final report schema
---
## Example 8: Form Data Extraction
**User Request:**
> "Users upload scanned forms (insurance claims, applications, etc.). Extract all form fields into a structured format for processing."
**Advisor Analysis:**
- **Goal:** Extract form data
- **Source:** Scanned form images
- **Consumer:** Processing system
- **Complexity:** Single extraction
**Recommended Mode:** JSON Outputs
**Reasoning:**
- Image data extraction
- Form has known structure (predefined fields)
- No tool execution
- Type-safe data needed for downstream processing
**Next Step:**
Delegate to `json-outputs-implementer` to design form schema matching the expected fields with proper types.
---
## Decision Patterns Summary
| Scenario Type | Recommended Mode | Key Indicator |
|---------------|------------------|---------------|
| Data extraction | JSON Outputs | "Extract X from Y" |
| Classification | JSON Outputs | "Classify/categorize X" |
| API formatting | JSON Outputs | "Format response as X" |
| Report generation | JSON Outputs | "Generate report with X structure" |
| Multi-tool workflow | Strict Tool Use | "Search, then book, then..." |
| Agent with tools | Strict Tool Use | "Agent that can call X, Y, Z" |
| Type-safe function calls | Strict Tool Use | "Validate parameters for X" |
| Complex agents | Both | "Research then report" / "Query then format" |
---
## Common Misconceptions
### ❌ "I need reliable JSON, so I should use strict tool use"
**Correction:** Use JSON outputs for reliable JSON responses. Strict tool use is for tool **parameters**, not Claude's response format.
### ❌ "My agent just needs one tool, so I should use JSON outputs"
**Correction:** Even a single-tool agent benefits from strict tool use if the tool needs parameter validation. Mode choice is about **what** you're validating, not **how many** tools.
### ❌ "I can use both modes for the same thing"
**Correction:** Each mode has a specific purpose:
- JSON outputs: Claude's response format
- Strict tool use: Tool input validation
They solve different problems and can be combined when you need both.
---
**See Also:**
- [JSON Outputs Implementer Examples](../../json-outputs-implementer/examples/)
- [Strict Tool Implementer Examples](../../strict-tool-implementer/examples/)