Files
567-labs--instructor/github_issue.md
T
wehub-resource-sync 97e91a83f3
Ruff / Ruff (push) Waiting to run
Test / Core Tests (push) Waiting to run
Test / Offline Coverage Tests (Python 3.10) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.11) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.12) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.13) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.9) (push) Waiting to run
Test / Full Coverage (Python 3.11) (push) Waiting to run
Test / Core Provider Tests (OpenAI) (push) Blocked by required conditions
Test / Core Provider Tests (Anthropic) (push) Blocked by required conditions
Test / Core Provider Tests (Google) (push) Blocked by required conditions
Test / Core Provider Tests (Other) (push) Blocked by required conditions
Test / Anthropic Tests (push) Blocked by required conditions
Test / Gemini Tests (push) Blocked by required conditions
Test / Google GenAI Tests (push) Blocked by required conditions
Test / Vertex AI Tests (push) Blocked by required conditions
Test / OpenAI Tests (push) Blocked by required conditions
Test / Writer Tests (push) Blocked by required conditions
Test / Auto Client Tests (push) Blocked by required conditions
ty / type-check (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:36:38 +08:00

112 lines
4.3 KiB
Markdown

# Refactor OpenAISchema class methods to standalone functions
## Summary
Currently, schema generation for different LLM providers requires models to inherit from `OpenAISchema` or be wrapped with the `@openai_schema` decorator. This creates an unnecessary inheritance requirement and couples schema generation to class-based patterns.
We should refactor the schema generation logic into standalone, provider-agnostic functions.
## Current State Analysis
**Current usage pattern**: `response_model.openai_schema` (where response_model inherits from OpenAISchema)
**Affected files with usage counts**:
- `instructor/utils/` (12 calls across cerebras.py, writer.py, fireworks.py, openai.py, mistral.py)
- `instructor/process_response.py` (11 calls)
- `instructor/dsl/parallel.py` (3 calls - handles parallel tools)
- `instructor/distil.py` (1 call)
- `instructor/function_calls.py` (13 calls - method definitions and internal usage)
- `instructor/utils/core.py` (1 call - decorator application)
- `instructor/utils/anthropic.py` (1 call - anthropic_schema)
- `instructor/utils/google.py` (1 call - gemini_schema)
- Examples and tests (20+ calls)
**Total**: ~60 usages across codebase
## Proposed Solution
### 1. Create `instructor/schema_utils.py` with standalone functions:
```python
from __future__ import annotations
import functools
from typing import Any, Type
from docstring_parser import parse
from pydantic import BaseModel
@functools.lru_cache(maxsize=256)
def generate_openai_schema(model: Type[BaseModel]) -> dict[str, Any]:
"""Generate OpenAI function schema from Pydantic model."""
# Move logic from OpenAISchema.openai_schema here
def generate_anthropic_schema(model: Type[BaseModel]) -> dict[str, Any]:
"""Generate Anthropic tool schema from Pydantic model."""
# Move logic from OpenAISchema.anthropic_schema here
def generate_gemini_schema(model: Type[BaseModel]) -> Any:
"""Generate Gemini function schema from Pydantic model."""
# Move logic from OpenAISchema.gemini_schema here
```
### 2. Update OpenAISchema class to delegate to new functions:
```python
class OpenAISchema(BaseModel):
@classproperty
def openai_schema(cls):
return generate_openai_schema(cls)
@classproperty
def anthropic_schema(cls):
return generate_anthropic_schema(cls)
@classproperty
def gemini_schema(cls):
return generate_gemini_schema(cls)
```
### 3. Migration path:
**Phase 1**: Add new functions, maintain backward compatibility
- All existing `response_model.openai_schema` calls continue working
- New code can use `generate_openai_schema(response_model)` directly
**Phase 2**: Internal migration
- Replace internal usage in utils/ and process_response.py
- Update parallel tools handling in dsl/parallel.py
**Phase 3**: Deprecation
- Mark `@openai_schema` decorator as deprecated
- Encourage users to migrate to standalone functions
## Benefits
1. **No inheritance requirement** - Any Pydantic model can generate schemas
2. **Provider-agnostic** - Clean separation of schema generation logic
3. **Better testability** - Functions are easier to unit test
4. **Performance** - LRU cache maintains current performance characteristics
5. **Backward compatibility** - Zero breaking changes during transition
6. **Cleaner API** - More functional approach vs class-based inheritance
## Implementation Checklist
- [ ] Create `instructor/schema_utils.py` with standalone functions
- [ ] Update `OpenAISchema` class to delegate to new functions
- [ ] Add comprehensive tests comparing old vs new output
- [ ] Update internal usage in utils/ (12 locations)
- [ ] Update process_response.py (11 locations)
- [ ] Update parallel tools handling in dsl/parallel.py
- [ ] Update distil.py usage
- [ ] Mark decorator as deprecated with warning
- [ ] Update documentation and examples
- [ ] Run full test suite to ensure no regressions
## Special Considerations
- **Parallel tools**: `dsl/parallel.py` uses both `openai_schema(model).openai_schema` and `openai_schema(model).anthropic_schema` patterns
- **Caching**: Current `@classproperty` provides implicit memoization - maintain with `@lru_cache`
- **Error handling**: Preserve current validation and error behavior
- **Provider compatibility**: Ensure schema output remains identical for all providers
This refactoring will modernize the schema generation approach while maintaining full backward compatibility.