TS TypeSafe 文档中文版 原文 ↗

用法

使用 TypeSafe Python SDK 的指南与模式。

调用 System One API

python
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())
 
python
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 提供一个响应模型,使响应在使用时更类型安全:

python
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:

python
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
 

选择模型

查看可用的模型:

python
from typesafe_sdk import TypeSafeClient
 
print(TypeSafeClient().models.list())
 

在构造客户端时选择模型:

python
client = TypeSafeClient(model="jev")
 

详情参见 Models 资源参考。

配置 base URL

若要配合其他 API url 使用该 SDK,请在客户端上设置 base_url,或设置 TYPESAFE_BASE_URL 环境变量。

例如,使用某个 AI 网关的 API key 和模型 ID 通过它连接:

使用 OpenRouter API key 和一个 OpenRouter 模型 ID:

skip: next

python
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)
 

Vercel 的 TypeSafe 兼容 API 可与该 SDK 一起使用:

skip: next

python
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 遵循 TypeSafe OpenAPI 规范。

重试

可以在客户端上或每次调用时以 retry 传入自定义的 RetryPolicy。无效的 API key 会在创建客户端时抛出 TypeSafeError,早于任何请求或重试。

python
from typesafe_sdk import RetryPolicy, TypeSafeClient
 
client = TypeSafeClient(retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0))
 
python
from typesafe_sdk import RetryPolicy
 
client.system_one(
    state, questions, retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0)
)
 

错误处理

处理 SDK 抛出的异常:

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

日志

SDK 会记录到 typesafe_sdk logger。请按标准日志指南进行配置:

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

或者在导入 SDK 之前,将 TYPESAFE_LOG_LEVEL 设为 debug、info、warning、error 或 off 之一。

info 会为每个请求记录一行摘要;debug 还会记录请求和响应的头部与正文。机密头部 — authorization、API key、cookie,以及名称中包含 token 或 secret 的任何头部 — 会在日志输出中被隐去。请求和响应正文不会被隐去。

环境变量

SDK 会读取并使用以下环境变量:

变量 配置项 默认值
TYPESAFE_API_KEY API key(必需) —
TYPESAFE_BASE_URL API 根 URL https://api.typesafe.ai
TYPESAFE_DEFAULT_MODEL 默认模型 jev-latest
TYPESAFE_LOG_LEVEL typesafe_sdk logger 级别,在导入时应用一次 未设置

SDK 的默认值参见常量参考。

通过 api_key 或 TYPESAFE_API_KEY 提供的 API key 会被去除首尾空白,包括来自 key 文件的换行符。空 key、内部空白、控制字符和非 ASCII 字符会在发送请求之前被拒绝。显式传入的空 key 不会回退到环境变量。

向前兼容

随着 TypeSafe API 的演进,SDK 会持续可用,因此你可以在某个 SDK 版本为其提供一等支持之前就采用新的 API 特性。

额外的请求字段

通过 extra_body 发送额外的 API 请求字段。下面的 beam_width 字段仅作示例;请只发送 API 支持的字段。

skip: next

python
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},
    )
 

原始问题字典

python
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。

未知的答案种类

SDK 会记录一条警告并跳过无法识别的答案种类。使用 raw_http_response 可以检查完整的 API 响应,其中包含那些答案:

python
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"]
 

未知的响应字段

已识别响应上的未知额外字段会被忽略。