Dokumentation

Verwendung

Anleitungen und Muster für die Arbeit mit dem TypeSafe Python SDK.

Die System One-API aufrufen

import asyncio

from typesafe_sdk import AsyncTypeSafeClient, Choice, Noul, Score

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        result = await client.system_one(
            "I was charged twice. Please help ASAP.",
            {
                "billing": Noul(instructions="Is this about billing?"),
                "tone": Choice(
                    instructions="What is the tone?",
                    criteria={"calm": None, "angry": None},
                ),
                "urgency": Score(
                    instructions="How urgent is this?",
                    criteria=["low", "medium", "high"],
                ),
            },
        )
        print(
            result.nouls["billing"].noul,
            result.choices["tone"].choice,
            result.scores["urgency"].score,
        )

asyncio.run(main())
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

client = TypeSafeClient()
state = "I was charged twice. Please help ASAP."
questions = {
    "billing": Noul(instructions="Is this about billing?"),
    "tone": Choice(
        instructions="What is the tone?", criteria={"calm": None, "angry": None}
    ),
    "urgency": Score(
        instructions="How urgent is this?", criteria=["low", "medium", "high"]
    ),
}
result = client.system_one(state, questions)
print(
    result.nouls["billing"].noul,
    result.choices["tone"].choice,
    result.scores["urgency"].score,
)

Typisierte system_one-Antworten

Es ist möglich, system_one ein Antwortmodell bereitzustellen, damit die Verwendung der Antwort typsicherer wird:

import asyncio

from typesafe_sdk import AsyncTypeSafeClient, Noul, NoulAnswer, SystemOneResponse

class BillingResponse(SystemOneResponse):
    billing: NoulAnswer

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        result = await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="Is this about billing?")},
            response_model=BillingResponse,
        )
        assert 0 <= result.billing.noul <= 1
        assert result.billing == result.nouls["billing"]
        print(result.request_id)

asyncio.run(main())
from typesafe_sdk import Noul, NoulAnswer, SystemOneResponse, TypeSafeClient

class BillingResponse(SystemOneResponse):
    billing: NoulAnswer

with TypeSafeClient() as client:
    result = client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="Is this about billing?")},
        response_model=BillingResponse,
    )
    assert 0 <= result.billing.noul <= 1
    assert result.billing == result.nouls["billing"]
    print(result.request_id)

Benutzerdefinierte Antworttypen

Es ist auch möglich, ein völlig neues Antwortmodell zu definieren, ohne von SystemOneResponse zu erben:

import asyncio

from pydantic import BaseModel

from typesafe_sdk import AsyncTypeSafeClient, Noul, NoulAnswer

class BillingAnswers(BaseModel):
    billing: NoulAnswer

class BillingResponse(BaseModel):
    answers: BillingAnswers

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        result = await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="Is this about billing?")},
            response_model=BillingResponse,
        )
        assert 0 <= result.answers.billing.noul <= 1

asyncio.run(main())
from pydantic import BaseModel

from typesafe_sdk import Noul, NoulAnswer, TypeSafeClient

class BillingAnswers(BaseModel):
    billing: NoulAnswer

class BillingResponse(BaseModel):
    answers: BillingAnswers

result = TypeSafeClient().system_one(
    "I was charged twice.",
    {"billing": Noul(instructions="Is this about billing?")},
    response_model=BillingResponse,
)
assert 0 <= result.answers.billing.noul <= 1

Ein Modell auswählen

Sieh dir die verfügbaren Modelle an:

import asyncio

from typesafe_sdk import AsyncTypeSafeClient

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        print(await client.models.list())

asyncio.run(main())
from typesafe_sdk import TypeSafeClient

print(TypeSafeClient().models.list())

Wähle das Modell beim Erstellen eines Clients aus:

client = AsyncTypeSafeClient(model="jev")
client = TypeSafeClient(model="jev")

Siehe die Referenz zur Ressource Models für Details.

Die Basis-URL konfigurieren

Um das SDK mit einer anderen API-URL zu verwenden, setze base_url am Client oder die Umgebungsvariable TYPESAFE_BASE_URL. Dies setzt voraus, dass die alternative API die TypeSafe OpenAPI-Spezifikation befolgt.

Verbinde dich zum Beispiel über ein KI-Gateway mit dessen API-Schlüssel und Modell-ID.

Verwende einen OpenRouter-API-Schlüssel und eine OpenRouter-Modell-ID:

import asyncio
import os

from typesafe_sdk import AsyncTypeSafeClient, Noul

async def main() -> None:
    async with AsyncTypeSafeClient(
        api_key=os.environ["OPENROUTER_API_KEY"],
        base_url="https://openrouter.ai/api",
        model="~typesafe/jev-latest",
    ) as client:
        result = await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="Is this about billing?")},
        )
        print(result.nouls["billing"].noul)

asyncio.run(main())
import os

from typesafe_sdk import Noul, TypeSafeClient

with TypeSafeClient(
    api_key=os.environ["OPENROUTER_API_KEY"],
    base_url="https://openrouter.ai/api",
    model="~typesafe/jev-latest",
) as client:
    result = client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="Is this about billing?")},
    )
    print(result.nouls["billing"].noul)

Vercels TypeSafe-kompatible API kann mit dem SDK verwendet werden:

import asyncio
import os

from typesafe_sdk import AsyncTypeSafeClient, Noul

async def main() -> None:
    async with AsyncTypeSafeClient(
        api_key=os.environ["AI_GATEWAY_API_KEY"],
        base_url="https://ai-gateway.vercel.sh/typesafe",
        model="typesafe-ai/jev",
    ) as client:
        result = await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="Is this about billing?")},
        )
        print(result.nouls["billing"].noul)

asyncio.run(main())
import os

from typesafe_sdk import Noul, TypeSafeClient

with TypeSafeClient(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh/typesafe",
    model="typesafe-ai/jev",
) as client:
    result = client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="Is this about billing?")},
    )
    print(result.nouls["billing"].noul)

Verwende einen Pydantic AI Gateway-API-Schlüssel:

import asyncio
import os

from typesafe_sdk import AsyncTypeSafeClient, Noul

async def main() -> None:
    async with AsyncTypeSafeClient(
        api_key=os.environ["PYDANTIC_AI_GATEWAY_API_KEY"],
        base_url="https://gateway-us.pydantic.dev/proxy/typesafe",
        model="jev-latest",
    ) as client:
        result = await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="Is this about billing?")},
        )
        print(result.nouls["billing"].noul)

asyncio.run(main())
import os

from typesafe_sdk import Noul, TypeSafeClient

with TypeSafeClient(
    api_key=os.environ["PYDANTIC_AI_GATEWAY_API_KEY"],
    base_url="https://gateway-us.pydantic.dev/proxy/typesafe",
    model="jev-latest",
) as client:
    result = client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="Is this about billing?")},
    )
    print(result.nouls["billing"].noul)

HTTP/2

import httpx2

from typesafe_sdk import AsyncTypeSafeClient

client = AsyncTypeSafeClient(http_client=httpx2.AsyncClient(http2=True))
import httpx2

from typesafe_sdk import TypeSafeClient

client = TypeSafeClient(http_client=httpx2.Client(http2=True))

Wiederholungen

Übergib eine benutzerdefinierte RetryPolicy als retry am Client oder pro Aufruf. Ungültige API-Schlüssel lösen bei der Client-Erstellung einen TypeSafeError aus, bevor eine Anfrage oder Wiederholung erfolgt.

Auf dem Client:

from typesafe_sdk import AsyncTypeSafeClient, RetryPolicy

client = AsyncTypeSafeClient(
    retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0)
)
from typesafe_sdk import RetryPolicy, TypeSafeClient

client = TypeSafeClient(retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0))

Pro Aufruf:

import asyncio

from typesafe_sdk import AsyncTypeSafeClient, RetryPolicy

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        await client.system_one(
            state,
            questions,
            retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0),
        )

asyncio.run(main())
from typesafe_sdk import RetryPolicy

client.system_one(
    state, questions, retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0)
)

Fehlerbehandlung

Behandle Ausnahmen, die vom SDK ausgelöst werden:

import asyncio

from typesafe_sdk import AsyncTypeSafeClient, TypeSafeAPIError

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        try:
            await client.system_one(state, questions)
        except TypeSafeAPIError as error:
            print(error.status, error.request_id)

asyncio.run(main())
from typesafe_sdk import TypeSafeAPIError

try:
    client.system_one(state, questions)
except TypeSafeAPIError as error:
    print(error.status, error.request_id)

Protokollierung

Das SDK protokolliert in den Logger typesafe_sdk. Konfiguriere ihn gemäß der Anleitung zur Standardprotokollierung:

import logging

logging.getLogger("typesafe_sdk").setLevel(logging.DEBUG)

Oder setze TYPESAFE_LOG_LEVEL vor dem Importieren des SDK auf einen der Werte debug, info, warning, error oder off.

info protokolliert eine Zusammenfassungszeile pro Anfrage; debug protokolliert zusätzlich die Header und Bodys von Anfragen und Antworten. Geheime Header – Autorisierung, API-Schlüssel, Cookies und jeder Header, dessen Name token oder secret enthält – werden aus der Protokollausgabe entfernt. Anfrage- und Antwort-Bodys werden nicht entfernt.

Umgebungsvariablen

Das SDK liest und verwendet die folgenden Umgebungsvariablen:

Variable Konfiguriert Standard
TYPESAFE_API_KEY API-Schlüssel (erforderlich) —
TYPESAFE_BASE_URL API-Wurzel-URL https://api.typesafe.ai
TYPESAFE_DEFAULT_MODEL Standardmodell jev-latest
TYPESAFE_LOG_LEVEL Grad des Loggers typesafe_sdk, einmal beim Import angewendet nicht gesetzt

Siehe die Referenz zu Konstanten für die SDK-Standardwerte.

API-Schlüssel, die über api_key oder TYPESAFE_API_KEY übergeben werden, werden von führenden und abschließenden Leerzeichen befreit, einschließlich Zeilenumbrüchen aus Schlüsseldateien. Leere Schlüssel, interne Leerzeichen, Steuerzeichen und Nicht-ASCII-Zeichen werden vor dem Senden einer Anfrage abgelehnt. Ein ausdrücklich leerer Schlüssel greift nicht auf die Umgebung zurück.

Vorwärtskompatibilität

Das SDK funktioniert weiter, während sich die TypeSafe-API weiterentwickelt, sodass du neue API-Funktionen übernehmen kannst, bevor eine SDK-Version erstklassige Unterstützung dafür hinzufügt.

Zusätzliche Anfragefelder

Sende zusätzliche API-Anfragefelder mit extra_body. Das Feld beam_width unten ist illustrativ; sende nur Felder, die von der API unterstützt werden.

import asyncio

from typesafe_sdk import AsyncTypeSafeClient, Noul

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="About billing?")},
            extra_body={"beam_width": 4},
        )

asyncio.run(main())
from typesafe_sdk import Noul, TypeSafeClient

with TypeSafeClient() as client:
    client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="About billing?")},
        extra_body={"beam_width": 4},
    )

Rohe Fragewörterbücher

import asyncio

from typesafe_sdk import AsyncTypeSafeClient

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        await client.system_one(
            "I was charged twice.",
            {
                "billing": {
                    "type": "noul",
                    "instructions": "About billing?",
                    "weight": 2,
                }
            },
        )

asyncio.run(main())
from typesafe_sdk import TypeSafeClient

with TypeSafeClient() as client:
    client.system_one(
        "I was charged twice.",
        {"billing": {"type": "noul", "instructions": "About billing?", "weight": 2}},
    )

Unbekannte Antwortarten

Das SDK protokolliert eine Warnung und überspringt nicht erkannte Antwortarten. Verwende raw_http_response, um die vollständige API-Antwort einschließlich dieser Antworten zu untersuchen:

import asyncio

from typesafe_sdk import AsyncTypeSafeClient, Noul

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        result = await client.system_one(
            "I was charged twice.",
            {"billing": Noul(instructions="Is this about billing?")},
        )
        print(result.raw_http_response.json()["answers"])

asyncio.run(main())
from typesafe_sdk import Noul, TypeSafeClient

result = TypeSafeClient().system_one(
    "I was charged twice.",
    {"billing": Noul(instructions="Is this about billing?")},
)
raw_answers = result.raw_http_response.json()["answers"]

Unbekannte Antwortfelder

Unbekannte zusätzliche Felder in erkannten Antworten werden ignoriert.