본문으로 건너뛰기
cccskills
무료GitHub에 공개한국어 소개

instructor

텍스트에서 필요한 정보를 추출하고 Pydantic으로 자료형과 값을 검증합니다. 언어 모델 출력을 정해진 구조로 정리하며 검증 실패 시 재시도와 생성 중 결과 수신도 다룹니다.

원문원문 설명 보기

Structured LLM outputs validated with Pydantic.

연동 도구OpenAI
AI 평가90점/ 100설치 방법 보기

이럴 때 유용합니다

  • 텍스트에서 연락처나 기업 정보를 추출합니다
  • 기사를 정해진 범주로 분류합니다
  • 리뷰 분석의 항목을 통일합니다
  • 생성 중인 결과를 순서대로 표시합니다

한국어 소개

할 수 있는 일

텍스트에서 이름, 연락처, 기업 정보 등을 추출해 정해진 항목을 가진 데이터로 만드는 구현을 돕습니다. Pydantic으로 항목의 자료형과 허용 범위를 정의하고 언어 모델 출력을 자동으로 검증합니다. 검증에 실패하면 오류를 모델에 전달해 재시도합니다. 중첩 데이터, 선택지를 제한한 분류, 생성 중인 결과를 순차적으로 받는 처리도 다룹니다.

이럴 때 유용합니다

자유로운 형식의 텍스트를 앱이 처리할 수 있는 형식으로 바꾸거나, 기사 분류와 리뷰 분석 결과의 항목을 통일할 때 유용합니다. 누락된 정보를 선택 항목으로 처리하는 설계와 여러 텍스트에서 정보를 추출하는 처리에도 도움이 됩니다.

사용 예시

  • “이 텍스트에서 이름, 나이, 이메일 주소를 추출하고 형식을 검증하는 코드를 작성해 주세요.”
  • “리뷰를 긍정, 부정, 중립으로 분류하고 장점과 개선 제안을 별도 항목으로 정리해 주세요.”

주의 사항

Python 라이브러리 instructor와 pydantic, 이용할 서비스에 맞는 SDK가 필요합니다. OpenAI와 Anthropic 예시에서는 API 키를 설정합니다. 로컬 Ollama 연결 예시도 있습니다. 이 스킬의 라이선스는 MIT입니다.

이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.

객관 평가

AI가 SKILL.md의 내용만을 근거로 4가지 관점에서 판정했습니다. 스타 수나 인기도는 판정에 넣지 않았습니다.

지시의 명확성언제 쓰고 무엇을 하는지 알 수 있는가
A양호구조화된 추출, Pydantic 검증, 재시도, 부분 결과 수신 용도를 명시합니다.
절차의 구체성절차·입출력·예시가 구체적으로 적혀 있는가
A양호항목 정의, 검증 조건, max_retries, 부분 결과 수신의 코드 예시가 있습니다.
안전성전송·삭제·명령 실행 등을 명시하고 있는가
B일부 부족이름과 이메일을 외부 모델에 보내는 예시가 있지만 전송 전 확인 절차는 없습니다.
도입의 용이성필요한 도구나 API 키가 적고 적혀 있는가
A양호pip 설치 명령, 서비스별 추가 패키지, API 키 설정 예시가 있습니다.

총점은 각 항목을 A=25점, B=15점, C=5점으로 더한 값입니다. 2026년 10월 19일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.

평가가 다르다고 생각되면 재검토를 요청하기

어느 항목이 왜 다르다고 생각하는지 적어 주세요. 로그인은 필요 없습니다. SKILL.md와 대조해 평가를 다시 만들고 이곳에 반영합니다.

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

포함된 파일(4)

  • SKILL.md16.3 KB
  • references/examples.md2.3 KB
  • references/providers.md1.3 KB
  • references/validation.md14.9 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Instructor: Structured LLM Outputs

When to Use This Skill

Use Instructor when you need to:

  • Extract structured data from LLM responses reliably
  • Validate outputs against Pydantic schemas automatically
  • Retry failed extractions with automatic error handling
  • Parse complex JSON with type safety and validation
  • Stream partial results for real-time processing
  • Support multiple LLM providers with consistent API

GitHub Stars: 15,000+ | Battle-tested: 100,000+ developers

Installation

# Base installation
pip install instructor

# With specific providers
pip install "instructor[anthropic]"  # Anthropic Claude
pip install "instructor[openai]"     # OpenAI
pip install "instructor[all]"        # All providers

Quick Start

Basic Example: Extract User Data

import instructor
from pydantic import BaseModel
from anthropic import Anthropic

# Define output structure
class User(BaseModel):
    name: str
    age: int
    email: str

# Create instructor client
client = instructor.from_anthropic(Anthropic())

# Extract structured data
user = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "John Doe is 30 years old. His email is john@example.com"
    }],
    response_model=User
)

print(user.name)   # "John Doe"
print(user.age)    # 30
print(user.email)  # "john@example.com"

With OpenAI

from openai import OpenAI

client = instructor.from_openai(OpenAI())

user = client.chat.completions.create(
    model="gpt-4o-mini",
    response_model=User,
    messages=[{"role": "user", "content": "Extract: Alice, 25, alice@email.com"}]
)

Core Concepts

1. Response Models (Pydantic)

Response models define the structure and validation rules for LLM outputs.

Basic Model

from pydantic import BaseModel, Field

class Article(BaseModel):
    title: str = Field(description="Article title")
    author: str = Field(description="Author name")
    word_count: int = Field(description="Number of words", gt=0)
    tags: list[str] = Field(description="List of relevant tags")

article = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "Analyze this article: [article text]"
    }],
    response_model=Article
)

Benefits:

  • Type safety with Python type hints
  • Automatic validation (word_count > 0)
  • Self-documenting with Field descriptions
  • IDE autocomplete support

Nested Models

class Address(BaseModel):
    street: str
    city: str
    country: str

class Person(BaseModel):
    name: str
    age: int
    address: Address  # Nested model

person = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "John lives at 123 Main St, Boston, USA"
    }],
    response_model=Person
)

print(person.address.city)  # "Boston"

Optional Fields

from typing import Optional

class Product(BaseModel):
    name: str
    price: float
    discount: Optional[float] = None  # Optional
    description: str = Field(default="No description")  # Default value

# LLM doesn't need to provide discount or description

Enums for Constraints

from enum import Enum

class Sentiment(str, Enum):
    POSITIVE = "positive"
    NEGATIVE = "negative"
    NEUTRAL = "neutral"

class Review(BaseModel):
    text: str
    sentiment: Sentiment  # Only these 3 values allowed

review = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "This product is amazing!"
    }],
    response_model=Review
)

print(review.sentiment)  # Sentiment.POSITIVE

2. Validation

Pydantic validates LLM outputs automatically. If validation fails, Instructor retries.

Built-in Validators

from pydantic import Field, EmailStr, HttpUrl

class Contact(BaseModel):
    name: str = Field(min_length=2, max_length=100)
    age: int = Field(ge=0, le=120)  # 0 <= age <= 120
    email: EmailStr  # Validates email format
    website: HttpUrl  # Validates URL format

# If LLM provides invalid data, Instructor retries automatically

Custom Validators

from pydantic import field_validator

class Event(BaseModel):
    name: str
    date: str
    attendees: int

    @field_validator('date')
    def validate_date(cls, v):
        """Ensure date is in YYYY-MM-DD format."""
        import re
        if not re.match(r'\d{4}-\d{2}-\d{2}', v):
            raise ValueError('Date must be YYYY-MM-DD format')
        return v

    @field_validator('attendees')
    def validate_attendees(cls, v):
        """Ensure positive attendees."""
        if v < 1:
            raise ValueError('Must have at least 1 attendee')
        return v

Model-Level Validation

from pydantic import model_validator

class DateRange(BaseModel):
    start_date: str
    end_date: str

    @model_validator(mode='after')
    def check_dates(self):
        """Ensure end_date is after start_date."""
        from datetime import datetime
        start = datetime.strptime(self.start_date, '%Y-%m-%d')
        end = datetime.strptime(self.end_date, '%Y-%m-%d')

        if end < start:
            raise ValueError('end_date must be after start_date')
        return self

3. Automatic Retrying

Instructor retries automatically when validation fails, providing error feedback to the LLM.

# Retries up to 3 times if validation fails
user = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "Extract user from: John, age unknown"
    }],
    response_model=User,
    max_retries=3  # Default is 3
)

# If age can't be extracted, Instructor tells the LLM:
# "Validation error: age - field required"
# LLM tries again with better extraction

How it works:

  1. LLM generates output
  2. Pydantic validates
  3. If invalid: Error message sent back to LLM
  4. LLM tries again with error feedback
  5. Repeats up to max_retries

4. Streaming

Stream partial results for real-time processing.

Streaming Partial Objects

from instructor import Partial

class Story(BaseModel):
    title: str
    content: str
    tags: list[str]

# Stream partial updates as LLM generates
for partial_story in client.messages.create_partial(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "Write a short sci-fi story"
    }],
    response_model=Story
):
    print(f"Title: {partial_story.title}")
    print(f"Content so far: {partial_story.content[:100]}...")
    # Update UI in real-time

Streaming Iterables

class Task(BaseModel):
    title: str
    priority: str

# Stream list items as they're generated
tasks = client.messages.create_iterable(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "Generate 10 project tasks"
    }],
    response_model=Task
)

for task in tasks:
    print(f"- {task.title} ({task.priority})")
    # Process each task as it arrives

Provider Configuration

Anthropic Claude

import instructor
from anthropic import Anthropic

client = instructor.from_anthropic(
    Anthropic(api_key="your-api-key")
)

# Use with Claude models
response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[...],
    response_model=YourModel
)

OpenAI

from openai import OpenAI

client = instructor.from_openai(
    OpenAI(api_key="your-api-key")
)

response = client.chat.completions.create(
    model="gpt-4o-mini",
    response_model=YourModel,
    messages=[...]
)

Local Models (Ollama)

from openai import OpenAI

# Point to local Ollama server
client = instructor.from_openai(
    OpenAI(
        base_url="http://localhost:11434/v1",
        api_key="ollama"  # Required but ignored
    ),
    mode=instructor.Mode.JSON
)

response = client.chat.completions.create(
    model="llama3.1",
    response_model=YourModel,
    messages=[...]
)

Common Patterns

Pattern 1: Data Extraction from Text

class CompanyInfo(BaseModel):
    name: str
    founded_year: int
    industry: str
    employees: int
    headquarters: str

text = """
Tesla, Inc. was founded in 2003. It operates in the automotive and energy
industry with approximately 140,000 employees. The company is headquartered
in Austin, Texas.
"""

company = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": f"Extract company information from: {text}"
    }],
    response_model=CompanyInfo
)

Pattern 2: Classification

class Category(str, Enum):
    TECHNOLOGY = "technology"
    FINANCE = "finance"
    HEALTHCARE = "healthcare"
    EDUCATION = "education"
    OTHER = "other"

class ArticleClassification(BaseModel):
    category: Category
    confidence: float = Field(ge=0.0, le=1.0)
    keywords: list[str]

classification = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "Classify this article: [article text]"
    }],
    response_model=ArticleClassification
)

Pattern 3: Multi-Entity Extraction

class Person(BaseModel):
    name: str
    role: str

class Organization(BaseModel):
    name: str
    industry: str

class Entities(BaseModel):
    people: list[Person]
    organizations: list[Organization]
    locations: list[str]

text = "Tim Cook, CEO of Apple, announced at the event in Cupertino..."

entities = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": f"Extract all entities from: {text}"
    }],
    response_model=Entities
)

for person in entities.people:
    print(f"{person.name} - {person.role}")

Pattern 4: Structured Analysis

class SentimentAnalysis(BaseModel):
    overall_sentiment: Sentiment
    positive_aspects: list[str]
    negative_aspects: list[str]
    suggestions: list[str]
    score: float = Field(ge=-1.0, le=1.0)

review = "The product works well but setup was confusing..."

analysis = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": f"Analyze this review: {review}"
    }],
    response_model=SentimentAnalysis
)

Pattern 5: Batch Processing

def extract_person(text: str) -> Person:
    return client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": f"Extract person from: {text}"
        }],
        response_model=Person
    )

texts = [
    "John Doe is a 30-year-old engineer",
    "Jane Smith, 25, works in marketing",
    "Bob Johnson, age 40, software developer"
]

people = [extract_person(text) for text in texts]

Advanced Features

Union Types

from typing import Union

class TextContent(BaseModel):
    type: str = "text"
    content: str

class ImageContent(BaseModel):
    type: str = "image"
    url: HttpUrl
    caption: str

class Post(BaseModel):
    title: str
    content: Union[TextContent, ImageContent]  # Either type

# LLM chooses appropriate type based on content

Dynamic Models

from pydantic import create_model

# Create model at runtime
DynamicUser = create_model(
    'User',
    name=(str, ...),
    age=(int, Field(ge=0)),
    email=(EmailStr, ...)
)

user = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[...],
    response_model=DynamicUser
)

Custom Modes

# For providers without native structured outputs
client = instructor.from_anthropic(
    Anthropic(),
    mode=instructor.Mode.JSON  # JSON mode
)

# Available modes:
# - Mode.ANTHROPIC_TOOLS (recommended for Claude)
# - Mode.JSON (fallback)
# - Mode.TOOLS (OpenAI tools)

Context Management

# Single-use client
with instructor.from_anthropic(Anthropic()) as client:
    result = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[...],
        response_model=YourModel
    )
    # Client closed automatically

Error Handling

Handling Validation Errors

from pydantic import ValidationError

try:
    user = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[...],
        response_model=User,
        max_retries=3
    )
except ValidationError as e:
    print(f"Failed after retries: {e}")
    # Handle gracefully

except Exception as e:
    print(f"API error: {e}")

Custom Error Messages

class ValidatedUser(BaseModel):
    name: str = Field(description="Full name, 2-100 characters")
    age: int = Field(description="Age between 0 and 120", ge=0, le=120)
    email: EmailStr = Field(description="Valid email address")

    class Config:
        # Custom error messages
        json_schema_extra = {
            "examples": [
                {
                    "name": "John Doe",
                    "age": 30,
                    "email": "john@example.com"
                }
            ]
        }

Best Practices

1. Clear Field Descriptions

# ❌ Bad: Vague
class Product(BaseModel):
    name: str
    price: float

# ✅ Good: Descriptive
class Product(BaseModel):
    name: str = Field(description="Product name from the text")
    price: float = Field(description="Price in USD, without currency symbol")

2. Use Appropriate Validation

# ✅ Good: Constrain values
class Rating(BaseModel):
    score: int = Field(ge=1, le=5, description="Rating from 1 to 5 stars")
    review: str = Field(min_length=10, description="Review text, at least 10 chars")

3. Provide Examples in Prompts

messages = [{
    "role": "user",
    "content": """Extract person info from: "John, 30, engineer"

Example format:
{
  "name": "John Doe",
  "age": 30,
  "occupation": "engineer"
}"""
}]

4. Use Enums for Fixed Categories

# ✅ Good: Enum ensures valid values
class Status(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"

class Application(BaseModel):
    status: Status  # LLM must choose from enum

5. Handle Missing Data Gracefully

class PartialData(BaseModel):
    required_field: str
    optional_field: Optional[str] = None
    default_field: str = "default_value"

# LLM only needs to provide required_field

Comparison to Alternatives

FeatureInstructorManual JSONLangChainDSPy
Type Safety✅ Yes❌ No⚠️ Partial✅ Yes
Auto Validation✅ Yes❌ No❌ No⚠️ Limited
Auto Retry✅ Yes❌ No❌ No✅ Yes
Streaming✅ Yes❌ No✅ Yes❌ No
Multi-Provider✅ Yes⚠️ Manual✅ Yes✅ Yes
Learning CurveLowLowMediumHigh

When to choose Instructor:

  • Need structured, validated outputs
  • Want type safety and IDE support
  • Require automatic retries
  • Building data extraction systems

When to choose alternatives:

  • DSPy: Need prompt optimization
  • LangChain: Building complex chains
  • Manual: Simple, one-off extractions

Resources

See Also

  • references/validation.md - Advanced validation patterns
  • references/providers.md - Provider-specific configuration
  • references/examples.md - Real-world use cases

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

1password

무료요약 있음AI 평가 100점

1Password에 저장한 비밀번호와 API 키를 명령과 설정 템플릿에 사용합니다. CLI 설치와 인증부터 비밀 값 조회 및 환경 변수 전달까지 안내합니다.

  • 1Password CLI 설치와 설정
  • 저장된 API 키로 명령 실행
  • 설정 템플릿에 비밀 값 삽입
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

3-statement-model

무료요약 있음AI 평가 90점

손익계산서·재무상태표·현금흐름표를 수식으로 연결한 Excel 모델을 만듭니다. 실적과 예측 가정을 입력하고 시나리오를 비교하며 세 재무제표의 일관성을 단계별로 확인합니다.

  • 재무 템플릿에 실적 입력
  • 세 재무제표가 연동되는 예측 작성
  • 기본·상향·하향 시나리오 비교
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

Adapt existing PyTorch training scripts to use multiple GPUs or machines with limited code changes. The skill guides configuration, launch commands, mixed precision, which uses lower-precision numbers, and DeepSpeed or FSDP settings for distributing training work and memory.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Move a single-GPU training script to multiple GPUs
  • Configure mixed precision training
  • Set up DeepSpeed or FSDP to reduce memory use
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

Configure Hermes to run AI models through Actual Computer on your own hardware. Set up either the hosted relay or a local connection, select models, verify responses, and troubleshoot request errors or empty output.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Connecting Hermes with an Actual inference key
  • Running models through a local Actual daemon
  • Downloading and loading local models
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

adversarial-ux-test

무료요약 있음AI 평가 80점

기술에 익숙하지 않고 쉽게 불만을 느끼는 사용자로 앱을 시험합니다. 혼란스러운 조작과 이탈 원인을 찾고, 개선 과제와 개인적 불만을 나눠 수정안을 정리합니다.

  • 출시나 시연 전에 사용성을 확인합니다
  • 신규 사용자의 경험을 점검합니다
  • 가입과 결제 과정의 어려움을 찾습니다
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

agent-merge-conflict-arbiter

무료요약 있음AI 평가 100점

두 에이전트가 각각 수정한 브랜치의 Git 충돌을 양쪽 변경 내용과 의도에 따라 중립적으로 해결합니다. 충돌별 판단 이유를 기록하고 빌드나 테스트로 통합 결과를 확인합니다.

  • 두 에이전트의 브랜치 충돌 해결
  • 병렬 worktree의 변경 내용 통합
  • 충돌하는 설계 판단의 이유 확인
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

NousResearch의 스킬 모두 보기

이 스킬의 문제 신고