Skip to main content

Provider-agnostic SDK for LLMs with async support and plugin providers.

Project description

llm-sdk

Provider-agnostic Python SDK for Large Language Models (LLMs) with a production-ready async architecture, strong typing, unified errors, retries, logging, and a plugin system based on Python entry points.


Table of Contents


Overview

llm-sdk is the core package that provides:

  • A unified API for multiple LLM providers
  • Async-first design (AsyncSDK)
  • A provider registry that loads providers via plugins
  • Domain models (requests/responses) independent of providers
  • Unified error model
  • Retries, timeouts, and structured logging

This package intentionally does not ship provider implementations directly. Providers are installed as separate packages, for example:

  • llm-sdk-provider-gemini
  • llm-sdk-provider-openai (future)
  • llm-sdk-provider-ollama (future)

Architecture

Core design principles

  • Provider-agnostic domain layer (no vendor types leak into the SDK)
  • Open/Closed Principle: providers are added via entry points, without modifying core code
  • SOLID:
    • AsyncSDK orchestrates only
    • Providers implement only provider calls
    • Registry handles discovery
    • Domain models validate input/output
  • DRY/KISS: minimal abstractions, strong conventions

Key components

  • AsyncSDK: main entrypoint (sdk.chat, sdk.embed, sdk.stream_chat)
  • ProviderRegistry: discovers provider plugins via entry points
  • ProviderFactory: plugin contract (spec() + create(settings))
  • Domain models: ChatRequest, ChatResponse, EmbeddingRequest, etc.
  • Unified errors: ProviderError, ValidationError, TimeoutError
  • Retries: async retry policy with exponential backoff + jitter
  • Settings: SDKSettings (Pydantic Settings)

Features

  • Async-first API
  • Provider plugins via entry points
  • Chat completions
  • Embeddings
  • Streaming chat (provider-dependent)
  • Strong typing (mypy-friendly)
  • Unified error handling
  • Retry policies with jitter
  • Structured logging support
  • Configuration via environment variables
  • Provider + model resolution at runtime

Installation

Install core SDK

pip install llm-sdk

Install at least one provider plugin

Example (Gemini):

pip install llm-sdk-provider-gemini

Usage

Async Quickstart

import asyncio
from llm_sdk.async_sdk import AsyncSDK


async def main() -> None:
    sdk = AsyncSDK.default()

    # IMPORTANT: load provider plugins (entry points)
    sdk.registry.load_plugins()

    resp = await sdk.chat(
        provider="gemini",
        model="gemini-2.5-flash",
        messages=[("user", "Hola, ¿cómo estás?")],
    )

    print(resp.content)


if __name__ == "__main__":
    asyncio.run(main())

Streaming chat

import asyncio
from llm_sdk.async_sdk import AsyncSDK


async def main() -> None:
    sdk = AsyncSDK.default()
    sdk.registry.load_plugins()

    async for ev in sdk.stream_chat(
        provider="gemini",
        model="gemini-2.5-flash",
        messages=[("user", "Explica qué es un Transformer en 5 puntos.")],
    ):
        print(ev.delta, end="", flush=True)

    print("\n[done]")


if __name__ == "__main__":
    asyncio.run(main())

Embeddings

import asyncio
from llm_sdk.async_sdk import AsyncSDK


async def main() -> None:
    sdk = AsyncSDK.default()
    sdk.registry.load_plugins()

    resp = await sdk.embed(
        provider="gemini",
        model="text-multilingual-embedding-002",
        input=["Hola mundo", "Hello world"],
    )

    print(len(resp.vectors), "vectors")
    print("dim:", len(resp.vectors[0]))


if __name__ == "__main__":
    asyncio.run(main())

Listing installed providers (debug)

from llm_sdk.providers.async_registry import ProviderRegistry

reg = ProviderRegistry()
reg.load_plugins()

print(reg.available())

Configuration

llm-sdk uses Pydantic Settings.

Example environment variables

export LLM_SDK_DEFAULT_PROVIDER="gemini"
export LLM_SDK_DEFAULT_MODEL="gemini-2.5-flash"

Typical config options

  • Default provider
  • Default model
  • Retry policy (max attempts, delays)
  • Timeouts
  • Provider-specific settings (usually defined in provider plugin packages)

Project Structure

Typical structure:

llm-sdk/
├─ src/
│  └─ llm_sdk/
│     ├─ async_sdk.py
│     ├─ sync_sdk.py
│     ├─ settings.py
│     ├─ typing.py
│     ├─ timeouts.py
│     ├─ exceptions.py
│     ├─ retries.py
│     ├─ plugin_loader.py
│     ├─ lifecycle.py
│     ├─ context.py
│     ├─ domain/
│       ├─ chat.py
│       ├─ embeddings.py
│       └─ models.py
│     └─ providers/
│        ├─ async_base.py
│        ├─ sync_base.py
│        ├─ async_registry.py
│        ├─ sync_registry.py
│        └─ __main__.py
├─ tests/
│  ├─ test_registry.py
│  ├─ test_retries.py
│  └─ test_contracts.py
├─ pyproject.toml
└─ README.md

Setup

Development

python -m venv venv
source venv/bin/activate

pip install -U pip
pip install -e ".[dev]"

Install a provider plugin in editable mode

Example:

pip install -e ../llm-sdk-provider-gemini

Testing

pytest -q

Notes

  • Core tests should not require any provider network access
  • Provider plugins are tested independently in their own packages

Deployment

Build package

python -m build

Upload to TestPyPI

python -m twine upload --repository testpypi dist/*

Upload to PyPI

python -m twine upload dist/*

Roadmap

  • Sync SDK wrapper (LLM) built on top of AsyncSDK

  • More providers (OpenAI, Ollama, Anthropic, etc.)

  • Built-in observability hooks (OpenTelemetry)

  • Tool calling abstraction

  • Response caching

  • Rate limiting middleware

  • First-class tracing


Contributing

PRs are welcome.

Recommended workflow:

  1. Fork the repo
  2. Create a feature branch
  3. Add tests for changes
  4. Run pytest
  5. Submit PR

License

MIT License


Contact

Author: Esteban Flores

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

llm_sdk_core-0.1.0.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

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

llm_sdk_core-0.1.0-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file llm_sdk_core-0.1.0.tar.gz.

File metadata

  • Download URL: llm_sdk_core-0.1.0.tar.gz
  • Upload date:
  • Size: 13.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for llm_sdk_core-0.1.0.tar.gz
Algorithm Hash digest
SHA256 72563e5343c141beaa9db535b647e0181bdcbd297d6d61339582b594a9e449f6
MD5 0e9ff0b3dd9a735cdad7361d0e161df8
BLAKE2b-256 272797ed29e44cae4edc748613f3e0e8cdcd04fc16dd286ad0f95d7d4da1c363

See more details on using hashes here.

File details

Details for the file llm_sdk_core-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: llm_sdk_core-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for llm_sdk_core-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1bc1b52b677fea6bdffa823f0e4d5112b1fa6678bb45ac46b0fc04b9d3ee8756
MD5 117b24096f1cb4ea0564af9fd74bc561
BLAKE2b-256 42ce9627cdf1e318c9c0c2e4ea745d6dcba50bcae9d4a0a63fca1ed7305f3160

See more details on using hashes here.

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