Skip to main content

Makes any LLM behave like a regular REST API. Define the contract, specllm enforces it.

Project description

specllm

The production framework for spec-first LLM APIs.

Define a REST API spec. specllm turns it into a live service where every response is powered by an LLM — validated, cached, and retried automatically. The caller never knows an LLM is involved.

┌──────────┐       ┌─────────────────────────────────────┐       ┌─────────┐
│ Your App │──────▶│ specllm                             │──────▶│   LLM   │
│          │◀──────│ (validates, retries, caches, serves)│◀──────│(any LLM)│
└──────────┘ JSON  └─────────────────────────────────────┘ JSON  └─────────┘
from specllm import SpecLLM

app = SpecLLM.from_openapi("./api.yaml")  # provider inferred from spec
app.serve(port=8080)

Install

pip install specllm
pip install specllm[anthropic]  # for Claude
pip install specllm[openai]     # for GPT-4

How It Works

Request → [Input Validation] → [Resolve Constraints] → [Cache Check] → [Build Prompt] → [Call LLM]
                                                                                              ↓
Response ← [Cache Store] ← [Output Validation] ←──── Valid? ←──── [LLM Response]
                                                       ↓ No
                                              [Retry with feedback] (up to 3x)
                                                       ↓ Still invalid
                                              [422 structured error]

Bad input → instant 400 (zero LLM cost). Invalid output → retry with error feedback. Still invalid → structured 422. Valid → cache and return.

Features

Model Selection via Spec

Specify the model in your spec. specllm infers the provider:

info:
  x-specllm-model: claude-sonnet-4-20250514   # default for all endpoints

paths:
  /v1/fast-route:
    post:
      x-specllm-model: claude-haiku-4          # override: cheap/fast

Built-in providers: Anthropic (claude-*) and OpenAI (gpt-*, o1-*, o3-*). Custom providers just implement one method:

class MyProvider(LLMProvider):
    def call(self, prompt: str, system_prompt=None) -> str:
        ...  # return raw text or dict — pipeline handles JSON extraction

Dynamic Response Constraints (x-constrain-from)

Let the caller control what the LLM can return — per request:

intent:
  type: string
  x-constrain-from: "intents"    # enum pulled from request body field "intents"

score:
  type: integer
  x-constrain-from:
    minimum: "min_score"          # range pulled from request body
    maximum: "max_score"

If the LLM picks outside the caller's options, specllm retries with feedback automatically.

Configuration (optional overrides)

app = SpecLLM.from_openapi("./api.yaml", config={
    "timeout_seconds": 30,
    "fallback_provider": backup_provider,
    "cost_limit_daily": 50.0,
    "cache_ttl": 3600,
})

Custom Validation & Prompts

@app.validate("/v1/route-ticket")
def only_enterprise(body):
    if body.get("customer_tier") != "enterprise":
        return "Only enterprise tickets accepted"

@app.prompt("/v1/answer")
def grounded_prompt(body):
    return (
        f"Answer ONLY from the following context. If the answer is not in the context, say so.\n\n"
        f"Context:\n{body['context']}\n\n"
        f"Question: {body['question']}"
    )

Observability

Every response includes headers: X-SpecLLM-Request-Id, X-SpecLLM-Latency-Ms, X-SpecLLM-Tokens-Used, X-SpecLLM-Retries, X-SpecLLM-Cache-Hit.

Testing (no LLM credentials needed)

from specllm.testing.record_replay import RecordReplayProvider

# Record locally, replay in CI:
provider = RecordReplayProvider(provider=real_provider, cassette="tests/tape.json")

Error Handling

Scenario HTTP Code
Bad input 400 INPUT_VALIDATION_FAILED
Output failed after retries 422 OUTPUT_SCHEMA_VIOLATION
Provider down/timeout 503/504 PROVIDER_UNAVAILABLE / PROVIDER_TIMEOUT
Cost limit hit 503 COST_LIMIT_REACHED

All errors return structured JSON with code, status, message, request_id, timestamp.

Architecture

specllm (zero required dependencies)

├── spec/         → OpenAPI parser + $ref resolution + JSON Schema validator
├── pipeline/     → Request orchestration, cache, retry, constraints, JSON extraction
├── llm/          → Provider ABC + Anthropic + OpenAI + MockProvider
├── server/       → ThreadingHTTPServer + async server
└── testing/      → Record/replay

Roadmap

  • ⬜ Redis cache backend
  • ⬜ Prometheus metrics + OpenTelemetry tracing

License

Apache License 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

specllm-0.1.1.tar.gz (29.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

specllm-0.1.1-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file specllm-0.1.1.tar.gz.

File metadata

  • Download URL: specllm-0.1.1.tar.gz
  • Upload date:
  • Size: 29.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for specllm-0.1.1.tar.gz
Algorithm Hash digest
SHA256 2e1174b049cf262d0f89d40344c6f519a64fa241e22ffe080ed9a7fca26331d4
MD5 416d0dd06b07e2d85351eded731fbf48
BLAKE2b-256 27650480de29daaacf047035cc3f6aca8b6a5cd947c55076c000f6668868c6b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for specllm-0.1.1.tar.gz:

Publisher: publish.yml on prj1991/specllm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file specllm-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: specllm-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 24.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for specllm-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 06370282c32b5131019dddf4630798437d60f8aa8abca472659680f1b3a01ccf
MD5 1f905e780b14420267c8f34c4e34b196
BLAKE2b-256 69fd61ae39507268c5fb9b4b13af37904e64423fdf48825af07d4ea98c726865

See more details on using hashes here.

Provenance

The following attestation bundles were made for specllm-0.1.1-py3-none-any.whl:

Publisher: publish.yml on prj1991/specllm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page