Использование
Руководства и подходы для работы с TypeSafe Python SDK.
Вызов API System One
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,
)Типизированные ответы system_one
Можно передать модель ответа в system_one, чтобы использовать ответ более типобезопасно:
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)Пользовательские типы ответов
Также можно определить совершенно новую модель ответа, не наследуясь от SystemOneResponse:
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Выбор модели
Просмотрите доступные модели:
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())Выберите модель при создании клиента:
client = AsyncTypeSafeClient(model="jev")client = TypeSafeClient(model="jev")Подробности см. в справочнике по ресурсу Models.
Настройка базового URL
Чтобы использовать SDK с другим URL API, задайте base_url в клиенте или переменную окружения TYPESAFE_BASE_URL. Для этого альтернативный API должен соответствовать спецификации TypeSafe OpenAPI.
Например, подключитесь через AI-шлюз, используя его ключ API и идентификатор модели.
Используйте ключ API OpenRouter и идентификатор модели OpenRouter:
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)Совместимый с TypeSafe API от Vercel можно использовать с SDK:
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)Используйте ключ API Pydantic AI Gateway:
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))Повторы
Передайте пользовательскую RetryPolicy как retry в клиенте или на отдельный вызов. Недопустимые ключи API вызывают TypeSafeError при создании клиента, до любого запроса или повтора.
В клиенте:
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))На вызов:
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)
)Обработка ошибок
Обработайте исключения, возбуждаемые SDK:
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)Логирование
SDK пишет в логгер typesafe_sdk. Настройте его согласно руководству по стандартному логированию:
import logging
logging.getLogger("typesafe_sdk").setLevel(logging.DEBUG)
Или задайте TYPESAFE_LOG_LEVEL одно из значений debug, info, warning, error или off перед импортом SDK.
info пишет одну строку-сводку на запрос; debug дополнительно пишет заголовки и тела запросов и ответов. Секретные заголовки — авторизация, ключи API, cookies и любой заголовок, имя которого содержит token или secret, — вырезаются из вывода логов. Тела запросов и ответов не вырезаются.
Переменные окружения
SDK читает и использует следующие переменные окружения:
| Переменная | Настраивает | По умолчанию |
|---|---|---|
TYPESAFE_API_KEY |
Ключ API (обязательно) | — |
TYPESAFE_BASE_URL |
Базовый URL API | https://api.typesafe.ai |
TYPESAFE_DEFAULT_MODEL |
Модель по умолчанию | jev-latest |
TYPESAFE_LOG_LEVEL |
уровень логгера typesafe_sdk, применяется один раз при импорте |
не задано |
Значения по умолчанию SDK см. в справочнике по константам.
У ключей API, переданных через api_key или TYPESAFE_API_KEY, удаляются начальные и конечные пробелы, включая переводы строк из файлов ключей. Пустые ключи, внутренние пробелы, управляющие символы и символы, не входящие в ASCII, отклоняются до отправки запроса. Явно пустой ключ не берётся из окружения.
Прямая совместимость
SDK продолжает работать по мере развития API TypeSafe, поэтому вы можете начать использовать новые возможности API до того, как выпуск SDK добавит их полноценную поддержку.
Дополнительные поля запроса
Отправляйте дополнительные поля запроса API через extra_body. Поле beam_width ниже приведено для примера; отправляйте только поля, поддерживаемые API.
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},
)Необработанные словари вопросов
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}},
)Неизвестные виды ответов
SDK пишет предупреждение и пропускает нераспознанные виды ответов. Используйте raw_http_response, чтобы изучить полный ответ API, включая такие ответы:
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"]Неизвестные поля ответа
Неизвестные дополнительные поля в распознанных ответах игнорируются.