ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

pydantic-ai 接入 Crusoe Serverless Inference:跨厂商开源模型统一调用与结构化输出实战

pydantic-ai 接入 Crusoe Serverless Inference:跨厂商开源模型统一调用与结构化输出实战 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 [openai3.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_KEYyour-api-keyCRUSOE_API_KEY的读取逻辑位于 providers/crusoe.pyCrusoeProvider初始化时优先使用显式传入的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:为前缀的模型名创建 Agentfrom 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 profileCrusoe 在一个端点后同时服务多家实验室的开源权重模型模型名因此带有实验室前缀——如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-llamameta_model_profileMeta Llamadeepseek-aideepseek_model_profileDeepSeekqwenqwen_model_profileQwengooglegoogle_model_profileGoogle Gemmaopenaiharmony_model_profile用于 Crusoe 上的 gpt-oss 模型OpenAImoonshotaimoonshotai_model_profileMoonshot Kimizaizai_model_profileZ.ai GLM解析逻辑为将模型名小写后按/拆分取厂商前缀查表把剩余部分交给对应 profile 工厂生成ModelProfile随后通过merge_profile与OpenAIModelProfile(json_schema_transformerOpenAIJsonSchemaTransformer)以及ModelProfile(supports_json_schema_outputTrue, supports_json_object_outputTrue)合并。这意味着即使厂商前缀无法识别如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 与 openaigpt-oss命中OpenAIJsonSchemaTransformer等细节。结构化输出guided decoding 全覆盖Crusoe 对目录中的每个模型都启用 guided decoding因此NativeOutput在整个模型目录中都可用——包括那些经由其自家厂商接入时不支持原生结构化输出的模型家族。其底层机制在 providers/crusoe.py 中有明确注释merge_profile最后合并的ModelProfile(supports_json_schema_outputTrue, supports_json_object_outputTrue)无条件生效因此无论模型家族自己的 profile 是否声明支持response_format都能正常工作。例如zai_model_profile本身不声明原生结构化输出支持但通过 Crusoe 接入时依然可用。test_crusoe_native_output 验证了这一点用CrusoeModel(zai/GLM-5.2)搭配NativeOutput(City)向模型询问埃菲尔铁塔位置成功得到City(cityParis, countryFrance)的结构化结果若缺少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 的CrusoeProviderfrom pydantic_ai import Agent from pydantic_ai.models.crusoe import CrusoeModel from pydantic_ai.providers.crusoe import CrusoeProvider model CrusoeModel(zai/GLM-5.2, providerCrusoeProvider(api_keyyour-api-key)) agent Agent(model) ...CrusoeProvider的构造签名见 providers/crusoe.py支持三种互斥的配置方式CrusoeProvider() # 仅依赖 CRUSOE_API_KEY 环境变量 CrusoeProvider(api_key..., http_clientcustom_client) # 显式 API Key可选自定义 HTTP 客户端 CrusoeProvider(openai_clientopenai.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(timeout30) model CrusoeModel( zai/GLM-5.2, providerCrusoeProvider(api_keyyour-api-key, http_clientcustom_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_contentCrusoeProvider无需为此配置任何内容ThinkingPart即可被自动还原为 pydantic-ai 的思考消息。tests/models/test_crusoe.py 中的test_crusoe_model_simple给出了完整证据对zai/GLM-5.2提问What is 2 2?返回消息包含ThinkingPart(idreasoning, provider_namecrusoe)与TextPart(content2 2 4.)且用量统计中带有output_reasoning_tokens108的思考 token 明细。流式输出与工具调用流式输出test_crusoe_model_streamingtests/models/test_crusoe.py用meta-llama/Llama-3.3-70B-Instruct配合agent.run_stream(...).stream_text(deltaTrue)逐 delta 拼接成功得到1, 2, 3, 4, 5说明流式能力与 OpenAI 基类完全一致。工具调用test_crusoe_tool_callingtests/models/test_crusoe.py展示了完整的多轮往返模型先返回ThinkingPartToolCallPartget_weather({city: Paris})Agent 注入ToolReturnPart后模型再次返回思考与最终文本第二轮请求还体现出 prompt 缓存cache_read_tokens64。内部地址脱敏一个值得注意的实现细节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]依赖openai3.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_clienthttpx2.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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进