pydantic-ai 接入 Crusoe Serverless Inference:跨厂商开源模型统一调用与结构化输出实战
【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai
本指南面向使用 pydantic-ai 的开发者,完整讲解如何通过CrusoeModel接入 Crusoe Serverless Inference:一个以 OpenAI 兼容协议托管多家实验室开源权重模型的统一推理端点。读完本文,你将掌握依赖安装、API Key 配置、按名称解析模型、利用厂商前缀自动选择模型 profile,以及借助 Crusoe 的 guided decoding 实现跨目录结构化输出的完整实战方案。
概述:一个端点,多家模型
Crusoe Cloud 的 Serverless Inference 服务将来自多个实验室的开源权重模型(如zai/GLM-5.2、deepseek-ai/DeepSeek-V4-Pro、meta-llama/Llama-3.3-70B-Instruct、openai/gpt-oss-120b)统一托管在同一个 OpenAI 兼容端点之后。pydantic-ai 为此提供了专门的CrusoeModel与CrusoeProvider,实现代码位于 models/crusoe.py 与 providers/crusoe.py。
从源码结构看,CrusoeModel直接继承自OpenAIChatModel(见 models/crusoe.py),除__init__外全部方法均继承自基类——这意味着你在 OpenAI 模型文档 中掌握的流式、工具调用、思考过程等能力,在 Crusoe 上开箱即用。
安装依赖
使用CrusoeModel有两种安装方式:
- 安装完整版
pydantic-ai; - 安装精简版
pydantic-ai-slim并附带crusoe可选依赖组。
pip/uv-add "pydantic-ai-slim[crusoe]"crusoe可选组的实际依赖在 pydantic_ai_slim/pyproject.toml 中定义为crusoe = ["openai>=3.8.0"]——也就是说,该可选组会引入新版openaiSDK,因为CrusoeModel底层通过openai.AsyncOpenAI客户端访问 Crusoe 的 OpenAI 兼容 API(见 models/crusoe.py)。
配置与获取 API Key
要使用 Crusoe Serverless Inference,需先前往 Crusoe Cloud 控制台,进入 Models 页面点击Get API Key获取密钥。可用的模型列表以 Crusoe Serverless Inference 官方文档为准(docs.crusoecloud.com/serverless-inference/overview)。
拿到 API Key 后,将其设置为环境变量:
export CRUSOE_API_KEY='your-api-key'CRUSOE_API_KEY的读取逻辑位于 providers/crusoe.py:CrusoeProvider初始化时优先使用显式传入的api_key,否则读取该环境变量;若两者皆无且未传入现成的openai_client,会抛出UserError并提示Set the CRUSOE_API_KEY environment variable or pass it via CrusoeProvider(api_key=...)。这一行为在 tests/providers/test_crusoe.py 中有对应测试验证。
使用 CrusoeModel:两种初始化方式
方式一:按名称字符串创建 Agent
设置好环境变量后,直接以crusoe:为前缀的模型名创建 Agent:
from pydantic_ai import Agent agent = Agent('crusoe:zai/GLM-5.2') ...crusoe:前缀会触发模型解析机制,将字符串解析为CrusoeModel而非普通的OpenAIChatModel,这一点由 tests/providers/test_crusoe.py 中的test_infer_crusoe_model用例确认。
方式二:直接实例化 CrusoeModel
也可以显式导入CrusoeModel,仅传入模型名完成初始化:
from pydantic_ai import Agent from pydantic_ai.models.crusoe import CrusoeModel model = CrusoeModel('zai/GLM-5.2') agent = Agent(model) ...CrusoeModel.__init__的完整签名(见 models/crusoe.py)为:
CrusoeModel( model_name, # 必填,含厂商前缀的模型名,如 'zai/GLM-5.2' *, # 以下均为仅限关键字参数 provider: 'crusoe' | Provider[AsyncOpenAI] = 'crusoe', # 默认解析为 CrusoeProvider profile: ModelProfileSpec | None = None, # 默认由 provider 按模型名挑选 settings: ModelSettings | None = None, # 模型级默认设置 )其中provider默认为字符串'crusoe',内部会自动解析为CrusoeProvider;你也可以传入自定义Provider实例(见下文)。
内置模型名列表
源码中的LatestCrusoeModelNames(见 models/crusoe.py)列出了 pydantic-ai 当前已知的模型名,包括Qwen/Qwen3-235B-A22B-Instruct-2507、deepseek-ai/DeepSeek-V3-0324、deepseek-ai/DeepSeek-V4-Pro、google/gemma-4-31b-it、meta-llama/Llama-3.3-70B-Instruct、moonshotai/Kimi-K2.6、nvidia/NVIDIA-Nemotron-3-Super-120B-A12B、openai/gpt-oss-120b、zai/GLM-5.1、zai/GLM-5.2等。由于 Crusoe 的模型目录频繁更新,类型定义采用了CrusoeModelName = str | LatestCrusoeModelNames的宽松写法:既提供已知模型的类型提示,又允许传入任意模型名,最新目录以 Crusoe 官方文档为准。
模型名称:厂商前缀决定 model profile
Crusoe 在一个端点后同时服务多家实验室的开源权重模型,模型名因此带有实验室前缀——如zai/GLM-5.2、deepseek-ai/DeepSeek-V4-Pro、meta-llama/Llama-3.3-70B-Instruct、openai/gpt-oss-120b。这个前缀正是选择 model profile 的依据,因此请务必在模型名中保留前缀,而不要只传裸模型 ID。
CrusoeProvider.model_profile()的实现(见 providers/crusoe.py)维护了一张厂商到 profile 工厂的映射表:
| 厂商前缀 | 使用的 profile | 对应实验室 |
|---|---|---|
meta-llama | meta_model_profile | Meta Llama |
deepseek-ai | deepseek_model_profile | DeepSeek |
qwen | qwen_model_profile | Qwen |
google | google_model_profile | Google Gemma |
openai | harmony_model_profile(用于 Crusoe 上的 gpt-oss 模型) | OpenAI |
moonshotai | moonshotai_model_profile | Moonshot Kimi |
zai | zai_model_profile | Z.ai GLM |
解析逻辑为:将模型名小写后按/拆分,取厂商前缀查表,把剩余部分交给对应 profile 工厂生成ModelProfile;随后通过merge_profile与OpenAIModelProfile(json_schema_transformer=OpenAIJsonSchemaTransformer)以及ModelProfile(supports_json_schema_output=True, supports_json_object_output=True)合并。这意味着:
- 即使厂商前缀无法识别(如
unknown-vendor/unknown-model),仍会回退到OpenAIJsonSchemaTransformer,保证请求构造可用; - 若某模型家族自带
json_schema_transformer,家族 profile 优先,否则用 OpenAI 默认转换器; - 结构化输出相关标志在所有情况下都被强制置为支持(见下节)。
这一映射行为由 tests/providers/test_crusoe.py 中的test_crusoe_provider_model_profile逐一验证,包括 meta 命中InlineDefsJsonSchemaTransformer、google 命中GoogleJsonSchemaTransformer、deepseek 与 openai(gpt-oss)命中OpenAIJsonSchemaTransformer等细节。
结构化输出:guided decoding 全覆盖
Crusoe 对目录中的每个模型都启用 guided decoding,因此NativeOutput在整个模型目录中都可用——包括那些经由其自家厂商接入时不支持原生结构化输出的模型家族。
其底层机制在 providers/crusoe.py 中有明确注释:merge_profile最后合并的ModelProfile(supports_json_schema_output=True, supports_json_object_output=True)无条件生效,因此无论模型家族自己的 profile 是否声明支持,response_format都能正常工作。例如zai_model_profile本身不声明原生结构化输出支持,但通过 Crusoe 接入时依然可用。
test_crusoe_native_output 验证了这一点:用CrusoeModel('zai/GLM-5.2')搭配NativeOutput(City),向模型询问埃菲尔铁塔位置,成功得到City(city='Paris', country='France')的结构化结果;若缺少CrusoeProvider的设置,该用例会抛出UserError: Native structured output is not supported by this model。同时 tests/providers/test_crusoe.py 用参数化用例确认,无论模型家族是 zai、meta-llama 还是未知厂商,supports_json_schema_output与supports_json_object_output均为True。
provider 参数:自定义 Provider 与 HTTP 客户端
传入自定义 CrusoeProvider
如果你不想依赖环境变量,可以在创建CrusoeModel时显式传入携带 API Key 的CrusoeProvider:
from pydantic_ai import Agent from pydantic_ai.models.crusoe import CrusoeModel from pydantic_ai.providers.crusoe import CrusoeProvider model = CrusoeModel('zai/GLM-5.2', provider=CrusoeProvider(api_key='your-api-key')) agent = Agent(model) ...CrusoeProvider的构造签名(见 providers/crusoe.py)支持三种互斥的配置方式:
CrusoeProvider() # 仅依赖 CRUSOE_API_KEY 环境变量 CrusoeProvider(api_key='...', http_client=custom_client) # 显式 API Key,可选自定义 HTTP 客户端 CrusoeProvider(openai_client=openai.AsyncOpenAI(...)) # 复用现成的 AsyncOpenAI 客户端注意:若传入openai_client,则api_key与http_client必须为None。
自定义 httpx2.AsyncClient
你还可以用自定义的httpx2.AsyncClient定制CrusoeProvider的网络行为(如超时、连接池等):
from httpx2 import AsyncClient from pydantic_ai import Agent from pydantic_ai.models.crusoe import CrusoeModel from pydantic_ai.providers.crusoe import CrusoeProvider custom_http_client = AsyncClient(timeout=30) model = CrusoeModel( 'zai/GLM-5.2', provider=CrusoeProvider(api_key='your-api-key', http_client=custom_http_client), ) agent = Agent(model) ...从 providers/crusoe.py 可以看到,CrusoeProvider固定将请求发送至https://api.inference.crusoecloud.com/v1,且其client属性返回内部持有的openai.AsyncOpenAI实例(tests/providers/test_crusoe.py 验证了 base_url 与 api_key 的绑定关系)。
深度原理:Crusoe 的推理行为与测试佐证
思考过程(Thinking)的非标准返回字段
Crusoe 的服务栈会把模型的思考过程放在非标准字段reasoning中返回(DeepSeek 系列则是reasoning_content)。由于OpenAIChatModel在 profile 未指定字段名时会回退读取reasoning/reasoning_content,CrusoeProvider无需为此配置任何内容,ThinkingPart即可被自动还原为 pydantic-ai 的思考消息。
tests/models/test_crusoe.py 中的test_crusoe_model_simple给出了完整证据:对zai/GLM-5.2提问What is 2 + 2?,返回消息包含ThinkingPart(id='reasoning', provider_name='crusoe')与TextPart(content='2 + 2 = 4.'),且用量统计中带有output_reasoning_tokens=108的思考 token 明细。
流式输出与工具调用
- 流式输出:
test_crusoe_model_streaming(tests/models/test_crusoe.py)用meta-llama/Llama-3.3-70B-Instruct配合agent.run_stream(...).stream_text(delta=True)逐 delta 拼接,成功得到1, 2, 3, 4, 5,说明流式能力与 OpenAI 基类完全一致。 - 工具调用:
test_crusoe_tool_calling(tests/models/test_crusoe.py)展示了完整的多轮往返:模型先返回ThinkingPart+ToolCallPart(get_weather({"city": "Paris"})),Agent 注入ToolReturnPart后,模型再次返回思考与最终文本;第二轮请求还体现出 prompt 缓存(cache_read_tokens=64)。
内部地址脱敏
一个值得注意的实现细节:Crusoe 会用 prefill 与 decode pod 地址拼装 completion id(形如chatcmpl-___prefill_addr_...___decode_addr_..._<id>)。为避免在回放测试中泄露 Crusoe 内部集群拓扑,测试夹具在 tests/models/test_crusoe.py 中用正则将这类内部地址从录制的响应中抹除——这侧面说明录制回放(VCR)是该项目验证模型行为的标准手段。
小结
在 pydantic-ai 中接入 Crusoe Serverless Inference 的核心要点可归纳为:
- 安装
pydantic-ai-slim[crusoe](依赖openai>=3.8.0),或安装完整版pydantic-ai; - 在 Crusoe Cloud 控制台获取 API Key,配置
CRUSOE_API_KEY环境变量(或通过CrusoeProvider(api_key=...)显式传入); - 用
Agent('crusoe:zai/GLM-5.2')或CrusoeModel('zai/GLM-5.2')创建 Agent; - 始终保留模型名的厂商前缀,它是 pydantic-ai 选择 model profile 的关键依据;
- 由于 Crusoe 对全部模型启用 guided decoding,可以放心使用
NativeOutput做结构化输出,即便模型家族自身 profile 不支持; - 需要精细控制网络层时,通过
CrusoeProvider(http_client=httpx2.AsyncClient(...))注入自定义客户端。
更通用的 OpenAI 兼容端点技巧(如 model profile 的细粒度定制、系统消息合并等)可继续参考 OpenAI 模型文档,它与 Crusoe 的实现同属一条技术栈。
【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考