Skip to main content

apicol

Couche d'abstraction Python pour appeler un LLM via plusieurs backends interchangeables. Une interface unifiée au format OpenAI pour parler à : API Anthropic native (avec caching, thinking, citations), LiteLLM (qui route vers OpenAI, Gemini, Mistral, Ollama, vLLM, LM Studio, OpenRouter et 100+ providers), et Claude Code CLI (claude -p, usage dev local uniquement).

Sélection du backend par variables d'environnement ou par objet Client configurable. Plusieurs backends peuvent cohabiter dans le même process (bench, fallback applicatif, comparaison).

Statut

v0.1.0 — alpha. Implémentation complète des trois backends (Anthropic natif, LiteLLM, claude -p dev-only), surface publique stable, ≥95 % de couverture. Streaming et tool calls reportés à v0.2/v0.3. Documentation associée :

  • README.md — ce fichier
  • CLAUDE.md — instructions pour Claude Code travaillant sur ce repo
  • ARCHITECTURE.md — décisions techniques structurantes
  • SPEC.md — contrat d'API publique
  • CHANGELOG.md — historique des versions
  • pyproject.toml — métadonnées du package
  • docs/prd/ — PRD-001 (architecture deux niveaux), PRD-002 (séparation claude -p), PRD-003 (multi-backend simultané)

Pourquoi cette lib

LiteLLM résout déjà 90 % du problème (interface unifiée, 100+ providers, format OpenAI partout). apicol ajoute deux choses que LiteLLM ne fait pas bien :

  1. Un chemin Anthropic natif préservé. Le compatibility layer OpenAI d'Anthropic ne supporte ni le prompt caching ni le détail du thinking. Pour les usages long-context avec caching agressif, il faut le SDK Anthropic natif. apicol expose explicitement cette voie quand APICOL_TYPE=anthropic, via une méthode client.anthropic_native().
  2. Un backend claude -p pour le dev local interactif. Strictement marqué « dev only » et exposé via une fonction séparée — pas routé dans l'interface unifiée — pour éviter toute confusion avec un usage programmatique qui violerait les TOS Anthropic (voir PRD-002).

Le reste (OpenAI, Gemini, modèles locaux, OpenRouter) est délégué à LiteLLM sans réinventer la roue.

Installation

Depuis PyPI (cible v0.1.0)

pip install apicol

Depuis le repo Git (phase alpha)

# Dernière version de main
pip install git+https://github.com/JP/apicol.git

# Tag spécifique
pip install git+https://github.com/JP/apicol.git@v0.1.0

# Branche dev
pip install git+https://github.com/JP/apicol.git@dev

Installation editable (dev local)

git clone https://github.com/JP/apicol.git
cd apicol
pip install -e ".[dev]"  # base + outils dev (pytest, ruff, mypy)

Ajout en dépendance d'un projet tiers

Dans pyproject.toml (par exemple celui d'Athanor) :

[project]
dependencies = [
    "apicol>=0.1.0",
    # OU depuis git en phase alpha
    "apicol @ git+https://github.com/JP/apicol.git@main",
]

Dans requirements.txt :

apicol>=0.1.0

Avec uv :

uv add apicol
# ou depuis git
uv add "apicol @ git+https://github.com/JP/apicol.git"

Dépendances installées

apicol installe automatiquement :

  • anthropic (SDK natif pour le backend Anthropic et l'échappatoire native)
  • litellm (délégation pour tous les autres backends)

Python ≥ 3.10 requis.

Variables d'environnement

Variable Valeurs Rôle
APICOL_TYPE anthropic, litellm Backend par défaut (utilisé par les fonctions globales chat, achat)
APICOL_KEY string Clé d'API par défaut
APICOL_MODEL string Modèle par défaut (ex. claude-opus-4-7, openai/gpt-5, ollama/qwen3:32b)
APICOL_URL URL (optionnel) Endpoint custom (vLLM local, LM Studio, gateway, etc.)

Pour claude_cli_chat() aucune variable n'est requise.

Pour un usage multi-backend simultané, ces variables ne sont pas suffisantes — on construit des Client explicites (voir Usage ci-dessous).

Usage

Mode simple — fonctions globales et env vars

import os
import apicol

os.environ["APICOL_TYPE"]  = "anthropic"
os.environ["APICOL_KEY"]   = "sk-ant-..."
os.environ["APICOL_MODEL"] = "claude-opus-4-7"

response = apicol.chat(
    messages=[{"role": "user", "content": "Bonjour"}],
    reasoning_effort="medium",
)
print(response["choices"][0]["message"]["content"])

Bascule de backend sans toucher au code applicatif :

export APICOL_TYPE=litellm
export APICOL_MODEL=openai/gpt-5
export APICOL_KEY=sk-...

Mode async — achat

import asyncio, apicol

async def main():
    response = await apicol.achat(
        messages=[{"role": "user", "content": "Bonjour"}],
    )
    return response

asyncio.run(main())

Mode multi-backend — objet Client

Pour avoir plusieurs configurations actives simultanément dans le même process (bench, fallback applicatif, comparaison) :

import apicol

claude = apicol.Client(
    backend="anthropic",
    api_key="sk-ant-...",
    model="claude-opus-4-7",
)

gpt = apicol.Client(
    backend="litellm",
    api_key="sk-...",
    model="openai/gpt-5",
)

qwen_local = apicol.Client(
    backend="litellm",
    model="ollama/qwen3:32b",
    base_url="http://localhost:11434",
)

prompt = [{"role": "user", "content": "Explique la relativité en 3 phrases"}]

# Bench parallèle
for name, client in [("claude", claude), ("gpt", gpt), ("qwen", qwen_local)]:
    response = client.chat(prompt)
    print(f"\n=== {name} ===\n{response['choices'][0]['message']['content']}")

Un Client est immutable après construction. Pour changer de configuration, on crée un nouveau client. Cette rigidité simplifie le raisonnement multi-instance.

Mode multi-backend async — AsyncClient

import asyncio, apicol

claude = apicol.AsyncClient(backend="anthropic", api_key="...", model="claude-opus-4-7")
gpt    = apicol.AsyncClient(backend="litellm",   api_key="...", model="openai/gpt-5")

async def bench():
    return await asyncio.gather(
        claude.chat(prompt),
        gpt.chat(prompt),
    )

claude_resp, gpt_resp = asyncio.run(bench())

Accès au SDK Anthropic natif (features avancées)

Pour le prompt caching avec breakpoints fins, les citations, le PDF input, le batch API, ou tout autre feature non-portable :

import apicol

# Via un Client
claude = apicol.Client(backend="anthropic", api_key="...", model="claude-opus-4-7")
native = claude.anthropic_native()  # → anthropic.Anthropic préconfiguré

response = native.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    system=[
        {
            "type": "text",
            "text": gros_document,
            "cache_control": {"type": "ephemeral"},
        }
    ],
    messages=[{"role": "user", "content": "Question sur le document"}],
)
# À partir d'ici, tu utilises le SDK Anthropic avec TOUTES ses features.

# Variante depuis les env vars (alias rétrocompatible)
native = apicol.anthropic_client()  # équivalent à Client().anthropic_native()

Backend dev only — claude_cli_chat

⚠️ Dev only. Cette fonction est destinée à un usage personnel interactif (un script local que tu lances toi-même). Elle n'est pas destinée à servir une charge programmatique routée selon coût/dispo — un tel usage enfreint les TOS de Claude Pro/Max. Voir PRD-002 pour le détail.

import apicol

# Aucune variable APICOL_* requise — utilise le `claude` CLI authentifié localement
response = apicol.claude_cli_chat(
    messages=[{"role": "user", "content": "Résume CHANGELOG.md du dossier courant"}],
)
print(response["choices"][0]["message"]["content"])

Cette fonction est volontairement séparée des fonctions globales chat() / achat() et des objets Client / AsyncClient : aucun chemin de routage ne mène automatiquement vers claude -p.

Paramètres unifiés (niveau 1)

Les méthodes Client.chat(), AsyncClient.chat() et les fonctions globales chat(), achat() acceptent tous les paramètres suivants :

Paramètre Type Comportement
messages list[dict] Format OpenAI standard
model str | None Override du modèle du Client / des env vars
temperature float | None 0.0 à 2.0, sémantique OpenAI
max_tokens int | None Default 4096
reasoning_effort "none" | "low" | "medium" | "high" Mappé selon backend (voir SPEC)
extra_body dict Passthrough silencieux vers le SDK sous-jacent (ex. cache_control Anthropic)

Détails complets et table de mapping reasoning_effortthinking dans SPEC.md.

Hors périmètre

  • Pas de cost tracking, virtual keys, rate limiting, dashboard. Utiliser le proxy LiteLLM standalone pour ça.
  • Pas de routage automatique avec fallback/loadbalance au niveau de la lib. Pour ces patterns, l'application orchestre ses Client à la main.
  • Pas de support des modalités exotiques (audio, embeddings, fine-tuning) en v0.1. Chat completion uniquement.
  • Pas de streaming en v0.1 (reporté à v0.2 — interface d'events unifiée à concevoir).
  • Pas de support des tool calls en v0.1 (reporté à v0.3).
  • Pas de routage automatique vers claude -p. Volontaire — voir PRD-002.

Licence

À définir (MIT probablement).

Release files for apicol 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for apicol 0.1.0
File Size Uploaded
apicol-0.1.0.tar.gz 270.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for apicol 0.1.0
File Interpreter ABI Platform
apicol-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 287.5 kB

Release files / apicol-0.1.0.tar.gz

Download URL apicol-0.1.0.tar.gz
Size 270.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f8e0bcefa25210f43a01a39613036cd4d9358c8e85cdf7c9e9a4d8bbeac255bd
BLAKE2b-256 checksum
How to use checksums
7722b42b4143ac39b7ba134f7b5fabef23d63235bce25e883e6af04330544c49
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 14, 2026.

Transparency log

Release files / apicol-0.1.0-py3-none-any.whl

Download URL apicol-0.1.0-py3-none-any.whl
Size 16.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
258dd5e96b361daa84c7c99f2339812b6a041cd803cd63d9701a2fef15f32728
BLAKE2b-256 checksum
How to use checksums
254eb0c282790e6b011ce552f12ac9ec9e722142daa9ca31e1c2af62c74de519
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page