|
1 | | -"""SOTA LLM Engine using Instructor and Pydantic for Strict Structured Outputs. |
2 | | -ENFORCES: Reproducibility (Seed 42, Temp 0.0) for scientific benchmarks. |
| 1 | +"""Omni-Provider LLM Engine for Absolute Flexibility. |
| 2 | +Supports: OpenAI, Anthropic, Gemini, Ollama, vLLM, Azure, etc. |
| 3 | +Enforces: Strict Pydantic JSON Schemas. |
3 | 4 | """ |
4 | | -import instructor |
5 | | -from openai import OpenAI |
6 | 5 | from pydantic import BaseModel |
7 | 6 | from loguru import logger |
8 | 7 | from tenacity import retry, stop_after_attempt, wait_exponential |
| 8 | +import instructor |
| 9 | +from litellm import completion |
9 | 10 |
|
10 | | -try: |
11 | | - client = instructor.from_openai(OpenAI()) |
12 | | -except Exception as e: |
13 | | - logger.warning(f"OpenAI client init failed (missing key?): {e}") |
14 | | - client = None |
| 11 | +def get_instructor_client(model: str): |
| 12 | + """Dynamically route the instructor client based on the model provider.""" |
| 13 | + import openai |
| 14 | + import anthropic |
| 15 | + import google.generativeai as genai |
| 16 | + |
| 17 | + if model.startswith("claude"): |
| 18 | + return instructor.from_anthropic(anthropic.Anthropic()) |
| 19 | + elif model.startswith("gemini"): |
| 20 | + return instructor.from_gemini(genai.GenerativeModel(model)) |
| 21 | + else: |
| 22 | + # Default to OpenAI / LiteLLM proxy / Ollama Local |
| 23 | + return instructor.from_openai(openai.OpenAI()) |
15 | 24 |
|
16 | 25 | @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10)) |
17 | 26 | def generate_structured( |
18 | 27 | messages: list, |
19 | 28 | response_model: type[BaseModel], |
20 | 29 | model: str = "gpt-4o-mini", |
21 | 30 | temperature: float = 0.0, |
22 | | - seed: int = 42 |
| 31 | + seed: int = 42, |
| 32 | + api_base: str = None |
23 | 33 | ) -> BaseModel: |
24 | 34 | """ |
25 | | - Research-Grade Extraction. |
26 | | - Enforces Temperature=0.0 and Seed=42 to guarantee deterministic, reproducible scientific output. |
| 35 | + Omni-Provider Structured Extraction. |
| 36 | + Allows passing ANY model (local Ollama, Claude, GPT, Groq). |
27 | 37 | """ |
28 | | - if not client: |
29 | | - raise ValueError("LLM Client is not initialized. Please set OPENAI_API_KEY.") |
30 | | - |
31 | 38 | try: |
32 | | - logger.debug(f"Initiating scientifically rigorous call to {model} [temp={temperature}, seed={seed}] for schema [{response_model.__name__}]...") |
33 | | - response = client.chat.completions.create( |
34 | | - model=model, |
35 | | - messages=messages, |
36 | | - response_model=response_model, |
37 | | - temperature=temperature, |
38 | | - seed=seed |
39 | | - ) |
| 39 | + logger.debug(f"Routing neural call to [{model}] for schema [{response_model.__name__}]...") |
| 40 | + |
| 41 | + # We use instructor's dynamic client routing |
| 42 | + client = get_instructor_client(model) |
| 43 | + |
| 44 | + kwargs = { |
| 45 | + "model": model, |
| 46 | + "messages": messages, |
| 47 | + "response_model": response_model, |
| 48 | + "temperature": temperature, |
| 49 | + } |
| 50 | + |
| 51 | + # Only inject seed if the provider supports it (like OpenAI) |
| 52 | + if "gpt" in model or "llama" in model: |
| 53 | + kwargs["seed"] = seed |
| 54 | + |
| 55 | + if api_base: # For Local Ollama or vLLM routing |
| 56 | + kwargs["base_url"] = api_base |
| 57 | + |
| 58 | + response = client.chat.completions.create(**kwargs) |
40 | 59 | return response |
| 60 | + |
41 | 61 | except Exception as e: |
42 | | - logger.error(f"SOTA LLM API Critical Failure: {str(e)}") |
| 62 | + logger.error(f"Omni-Provider API Failure for {model}: {str(e)}") |
43 | 63 | raise |
0 commit comments