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.2.0.tar.gz (13.8 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.2.0-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: llm_sdk_core-0.2.0.tar.gz
  • Upload date:
  • Size: 13.8 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.2.0.tar.gz
Algorithm Hash digest
SHA256 00aefeebef0dc0e57a138b423e2d6ff8c3a3127f89655680ac8c09eba97ac61a
MD5 71330ba440a02a90ea0199df91810f0c
BLAKE2b-256 e6713c9750b8dad5ea81beb4716704ed051a9fa88fb8fff66fadf48d34031013

See more details on using hashes here.

File details

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

File metadata

  • Download URL: llm_sdk_core-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 22.8 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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ee2c446df496f0581f1a4c1c18da2065e2151f87d7bee8ddecb159aa06f7b5d
MD5 0a28eeaf6a4a9e5d45bba9d09156cd11
BLAKE2b-256 d6d552e7fa4063633d15edd2385be80d443fe08b9b185ff6144214615384a4df

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