smolagents 模型层指南:Model 接口契约、内置模型与自定义 LLM 接入
【免费下载链接】smolagents🤗 smolagents: a barebones library for agents that think in code.项目地址: https://gitcode.com/gh_mirrors/smo/smolagents
本篇基于 smolagents 仓库中的模型参考文档(docs/source/zh/reference/models.md)与模型层核心实现(src/smolagents/models.py)整理。文章围绕 smolagents 的模型抽象展开:先讲清“什么对象可以充当 Agent 的模型”这一接口契约,再逐一拆解 TransformersModel、InferenceClientModel、LiteLLMModel、OpenAIModel、AzureOpenAIModel、MLXModel 等内置模型类,最后深入到 API 模型的限流与重试机制、参数优先级和序列化安全机制。读完后你可以直接选型内置模型驱动 CodeAgent,也能按契约快速接入任意自研 LLM。
需要说明的前提:smolagents 是一个实验性 API,官方文档明确提示其可能随时变化,底层 API 或模型变动都可能导致 Agent 结果不同;当前仓库版本为1.27.0.dev0(见 pyproject.toml)。
模型接口契约:任何可调用对象都能驱动 Agent
smolagents 对模型没有强绑定,你可以自由创建和使用自己的模型为智能体提供支持。文档给出的准入条件只有两条:
- 它遵循消息格式(
List[Dict[str, str]]),将其作为输入messages,并返回一个包含.content属性的对象,其中包含生成的文本; - 它在生成的序列到达
stop_sequences参数中指定的内容之前停止生成输出。
要定义你的 LLM,可以创建一个custom_model方法,它接受一个 messages 列表,并返回包含.content属性的对象。此可调用对象还需要接受一个stop_sequences参数,用于指示何时停止生成。文档给出的示例基于 Hugging Face InferenceClient:
from huggingface_hub import login, InferenceClient login("<YOUR_HUGGINGFACEHUB_API_TOKEN>") model_id = "meta-llama/Llama-3.3-70B-Instruct" client = InferenceClient(model=model_id) def custom_model(messages, stop_sequences=["Task"]): response = client.chat_completion(messages, stop=stop_sequences, max_tokens=1000) answer = response.choices[0].message return answer此外,custom_model还可以接受一个grammar参数。如果在智能体初始化时指定了grammar,则此参数将在调用模型时传递,以便进行约束生成,从而强制生成格式正确的智能体输出。
从源码结构看,这套契约的正式承载者是 models.py 中的Model基类:
- 所有模型实现必须实现
generate(messages, stop_sequences=None, response_format=None, tools_to_call_from=None, **kwargs),返回值是统一的ChatMessage数据类(见 ChatMessage 定义),其中content即生成文本,tool_calls、token_usage、raw分别承载工具调用、token 统计和原始响应; Model.__call__直接委托给generate,所以文档中“可调用对象”的写法与基类语义一致;- 基类还暴露了
tool_name_key(默认"name")与tool_arguments_key(默认"arguments"),用于从纯文本响应中解析工具调用(parse_tool_calls方法,models.py),这正是 CodeAgent 依赖“输出以Task等停止序列结束”这类文本协议的原因。
_prepare_completion_kwargs(models.py)是参数装配的中枢,值得注意两点:
- 参数优先级:文档化的优先级为“模型初始化时的
self.kwargs(最高)> 调用时显式传入的 kwargs > 具体参数(stop_sequences、response_format 等)”。测试 tests/test_models.py 专门验证了这一点:初始化时写Model(max_tokens=100)会覆盖调用时传入的max_tokens=50。 - REMOVE_PARAMETER 哨兵:把某个参数设为
REMOVE_PARAMETER可以从最终请求中移除该参数(同样有测试覆盖)。
另外,当传入tools_to_call_from时,默认tool_choice="required"(测试 tests/test_models.py 覆盖了required/auto/工具名/字典/显式None等组合),这保证了 API 模型在工具场景下倾向发出结构化 tool call。
消息格式与内部数据流
文档提到的消息格式List[Dict[str, str]]在仓库中由get_clean_message_list(models.py)统一清洗:它接受ChatMessage或 dict 混合列表,支持自定义role_conversions角色映射,可把图片编码为 base64 或image_url,并在flatten_messages_as_text=True时把相邻同角色消息合并为纯文本。默认的角色映射是tool_role_conversions = {TOOL_CALL: ASSISTANT, TOOL_RESPONSE: USER}。角色集合由MessageRole枚举定义:user、assistant、system、tool-call、tool-response(models.py)。
一个容易被忽略的实现细节是stop_sequences 的“事后截断”。部分推理模型(如 openai/o3、o4-mini、gpt-5 系列及部分 grok 模型)的 API 不支持stop参数,supports_stop_parameter(models.py)会根据model_id判断:不支持时不向 API 传stop,而在拿到响应后调用remove_content_after_stop_sequences把停止序列之后的内容切掉。测试 test_supports_stop_parameter 用大量模型 ID 覆盖了该正则(含带路径前缀、带日期后缀、o3-mini例外等边缘情况),test_stop_sequence_cutting_for_o4_mini 则验证了事后截断行为。
内置模型一:TransformersModel(本地推理)
TransformersModel为初始化时指定的model_id构建一个本地transformerspipeline 来实现上述功能:
from smolagents import TransformersModel model = TransformersModel(model_id="HuggingFaceTB/SmolLM-135M-Instruct") print(model([{"role": "user", "content": [{"type": "text", "text": "Ok!"}]}], stop_sequences=["great"]))>>> What a必须在机器上安装transformers和torch。如果尚未安装,请运行pip install 'smolagents[transformers]'(该 extra 实际还包含accelerate和 torch 依赖,见 pyproject.toml 的[project.optional-dependencies])。
结合 TransformersModel 源码 可以补充若干文档未展开的参数:
max_new_tokens默认4096,max_tokens是其别名且优先级更高;device_map不传时自动选择cuda(若可用)否则cpu;torch_dtype、trust_remote_code(Hub 上需要远程代码的模型须置True)、model_kwargs(透传给from_pretrained)、apply_chat_template_kwargs均可用;- 它会先尝试
AutoModelForImageTextToText加载视觉语言模型(配合AutoProcessor),失败且报错为 "Unrecognized configuration class" 时回退到AutoModelForCausalLM+AutoTokenizer——因此非视觉模型的消息会被展平为纯文本(flatten_messages_as_text由是否 VLM 自动决定); - 停止序列通过自定义
StoppingCriteria实现(逐 token 解码后检查流是否以任一 stop 字符串结尾),生成后仍会再做一次remove_content_after_stop_sequences截断兜底; - 它不支持
response_format(结构化输出),源码中直接抛出ValueError并提示“use VLLMModel for this”; - 额外提供
generate_stream,用TextIteratorStreamer在独立线程中逐 token 输出(测试 test_transformers_message_no_tool 验证了非流式与流式输出一致)。
内置模型二:InferenceClientModel(Hugging Face 推理网络)
InferenceClientModel封装了 huggingface_hub 的 InferenceClient 用于执行 LLM,支持 HF 的 Inference API 以及 Hub 上所有可用的 Inference Providers(Cerebras、Cohere、Fal、Fireworks、HF-Inference、Hyperbolic、Nebius、Novita、Replicate、SambaNova、Together 等):
from smolagents import InferenceClientModel messages = [ {"role": "user", "content": [{"type": "text", "text": "Hello, how are you?"}]} ] model = InferenceClientModel() print(model(messages))>>> Of course! If you change your mind, feel free to reach out. Take care!从 InferenceClientModel 源码 可见其关键参数与默认值:
model_id默认"Qwen/Qwen3-Next-80B-A3B-Thinking"(注释标明未来可能变更);provider默认"auto",即选取该模型可用的第一个 Provider;传入base_url时provider不生效;token与api_key二选一(api_key是为了对齐 OpenAI 客户端命名而设的别名),都不传时读取环境变量HF_TOKEN,否则回退到 HF CLI 本地配置;timeout默认 120 秒;- 支持
requests_per_minute限流(经由ApiModel,见下文“API 模型的公共机制”); - 结构化输出(
response_format)仅限STRUCTURED_GENERATION_PROVIDERS = ["cerebras", "fireworks-ai"]两个 provider,否则会抛出ValueError(有对应测试 test_structured_outputs_with_unsupported_provider); - 同样提供
generate_stream流式接口。
内置模型三:LiteLLMModel 与 LiteLLMRouterModel(100+ 提供商)
LiteLLMModel利用 LiteLLM 支持来自不同提供商的 100+ 个 LLM。你可以在模型初始化时传递kwargs,这些参数将在每次使用模型时被使用,例如下面的示例中传递了temperature:
from smolagents import LiteLLMModel messages = [ {"role": "user", "content": [{"type": "text", "text": "Hello, how are you?"}]} ] model = LiteLLMModel(model_id="anthropic/claude-3-5-sonnet-latest", temperature=0.2, max_tokens=10) print(model(messages))安装方式为pip install 'smolagents[litellm]'。从 LiteLLMModel 源码 补充:model_id缺省时默认anthropic/claude-3-5-sonnet-20240620(并给出将变为必传的未来警告);flatten_messages_as_text对ollama、groq、cerebras前缀的模型默认置True,其余默认False;图片内容会以image_url(data URL)形式传给 API。
LiteLLMRouterModel则继承 LiteLLM 的 Router,提供跨多部署的负载均衡、队列化、冷却/回退与指数退避重试等路由策略,适合把同一模型名挂到多个后端:
from smolagents import LiteLLMRouterModel messages = [ {"role": "user", "content": [{"type": "text", "text": "Hello, how are you?"}]} ] model = LiteLLMRouterModel( model_id="llama-3.3-70b", model_list=[ { "model_name": "llama-3.3-70b", "litellm_params": {"model": "groq/llama-3.3-70b", "api_key": os.getenv("GROQ_API_KEY")}, }, { "model_name": "llama-3.3-70b", "litellm_params": {"model": "cerebras/llama-3.3-70b", "api_key": os.getenv("CEREBRAS_API_KEY")}, }, ], client_kwargs={ "routing_strategy": "simple-shuffle", }, ) print(model(messages))测试 TestLiteLLMRouterModel 验证了model_list与client_kwargs会原样传给litellm.router.Router构造函数。
内置模型四:OpenAIModel 与 AzureOpenAIModel
OpenAIModel允许你调用任何 OpenAI 兼容(OpenAI Server)模型,可通过api_base指向其他服务器:
import os from smolagents import OpenAIModel model = OpenAIModel( model_id="gpt-4o", api_base="https://api.openai.com/v1", api_key=os.environ["OPENAI_API_KEY"], )需要安装pip install 'smolagents[openai]'。从 OpenAIModel 源码 看,它还有organization、project、client_kwargs(如max_retries)等参数,全部透传给openai.OpenAI客户端(测试 test_client_kwargs_passed_correctly 验证了透传);generate_stream支持流式 tool call 聚合(测试 test_streaming_tool_calls 覆盖了并行final_answer工具调用场景)。仓库中OpenAIServerModel是它的别名。
AzureOpenAIModel允许你连接到任何 Azure OpenAI 部署。下面是设置示例,请注意,如果已经设置了相应的环境变量,你可以省略azure_endpoint、api_key和api_version参数——环境变量包括AZURE_OPENAI_ENDPOINT、AZURE_OPENAI_API_KEY和OPENAI_API_VERSION。
请注意,OPENAI_API_VERSION没有AZURE_前缀,这是由于底层 openai 包的设计所致。
import os from smolagents import AzureOpenAIModel model = AzureOpenAIModel( model_id = os.environ.get("AZURE_OPENAI_MODEL"), azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"), api_key=os.environ.get("AZURE_OPENAI_API_KEY"), api_version=os.environ.get("OPENAI_API_VERSION") )实现上AzureOpenAIModel继承OpenAIModel,仅在create_client中改用openai.AzureOpenAI并把api_version、azure_endpoint注入客户端参数(models.py),测试 TestAzureOpenAIModel 验证了参数组装。
内置模型五:MLXModel(Apple Silicon 本地推理)
from smolagents import MLXModel model = MLXModel(model_id="HuggingFaceTB/SmolLM-135M-Instruct") print(model([{"role": "user", "content": "Ok!"}], stop_sequences=["great"]))>>> What a必须在机器上安装mlx-lm。如果尚未安装,请运行pip install 'smolagents[mlx-lm]'。从 MLXModel 源码 可补充:load_kwargs透传给mlx_lm.load,trust_remote_code默认False,apply_chat_template_kwargs默认带add_generation_prompt=True;mlx-lm 不支持视觉模型,消息一律展平为纯文本;流式生成中逐 token 检查 stop 序列并以text.rfind精确截断(测试 test_get_mlx_message_tricky_stop_sequence 专门覆盖了 stop 序列后紧跟其他字符的场景);MLX 不支持结构化输出,传response_format会报错。该测试仅在 macOS 上运行(skipif not darwin)。
模型注册表中的其他成员
除文档主体覆盖的模型外,模型注册表 MODEL_REGISTRY 还登记了VLLMModel(本地 vLLM 服务,pip install 'smolagents[vllm]',支持 JSON schema 结构化输出与model_kwargs/apply_chat_template_kwargs)和AmazonBedrockModel(pip install 'smolagents[bedrock]',基于 boto3bedrock-runtime的converse接口,默认把所有角色映射为user,且不支持response_format)。这两个类与上述模型一样通过from_dict参与模型序列化。
API 模型的公共机制:限流、重试与停止序列兜底
所有 API 系模型(InferenceClientModel、LiteLLMModel、OpenAIModel、AzureOpenAIModel、AmazonBedrockModel)都继承ApiModel(models.py),共享三套基础设施:
- 客户端注入:
client参数允许传入预配置的客户端实例,否则调用子类的create_client(); - 限流:
requests_per_minute参数经RateLimiter(utils.py)实现,按60/requests_per_minute秒的最小间隔节流,None时禁用; - 限流错误重试:
retry=True时,请求经由Retrying(utils.py)执行,最多RETRY_MAX_ATTEMPTS = 3次,基准等待RETRY_WAIT = 60秒、指数底数 2、带抖动(常量定义)。重试谓词is_rate_limit_error通过错误信息中是否含429、rate limit、too many requests、rate_limit判定。测试 test_retry_on_rate_limit_error 用 mock 验证了“两次 429 后成功、共调用 3 次”以及指数退避的耗时区间。
每次generate返回的ChatMessage都携带token_usage(input/output token 数)与raw原始响应,供记忆、监控(monitoring.py)与运行日志使用。
安装、依赖与模型序列化
结合 pyproject.toml,与模型相关的可选依赖(extras)如下:
| 模型类 | 安装命令 | 依赖要点 |
|---|---|---|
TransformersModel | pip install 'smolagents[transformers]' | accelerate+transformers>=4.0.0(排除 5.13.0)+ torch/torchvision/numpy |
InferenceClientModel | 核心依赖即可 | huggingface-hub已是基础依赖 |
LiteLLMModel/LiteLLMRouterModel | pip install 'smolagents[litellm]' | litellm>=1.60.2 |
OpenAIModel/AzureOpenAIModel | pip install 'smolagents[openai]' | openai>=1.58.1 |
AmazonBedrockModel | pip install 'smolagents[bedrock]' | boto3>=1.36.18 |
MLXModel | pip install 'smolagents[mlx-lm]' | mlx-lm |
VLLMModel | pip install 'smolagents[vllm]' | vllm>=0.10.2+ torch |
每个模型类在缺失对应依赖时会抛出带安装提示的ModuleNotFoundError(例如VLLMModel的检查见 models.py),可据此快速定位环境问题。
最后,模型实例可以安全地序列化进 Agent 存档:Model.to_dict(models.py)导出model_id与采样参数(temperature、max_tokens、provider、api_base、device_map等),但出于安全考虑不导出token/api_key,并打印提示需手动导出;反序列化时只允许MODEL_REGISTRY中登记的类名实例化,防止任意代码执行。这一机制配合from_dict使保存/恢复智能体成为可能。
小结
- 自定义模型只需满足两个条件:接受
messages(List[Dict[str, str]])+stop_sequences,返回带.content的对象;进阶可实现Model子类并支持grammar约束生成; - 参数传递遵循“初始化 kwargs 最高优先级”,可用
REMOVE_PARAMETER移除参数; - 停止序列在不支持的模型上会自动退化为事后截断,行为可预期(有完整测试矩阵);
- API 模型统一具备
requests_per_minute限流与 429 指数退避重试; - 选型建议:本地小模型用
TransformersModel/MLXModel/VLLMModel,托管推理用InferenceClientModel,多厂商统一接入用LiteLLMModel,多后端负载均衡用LiteLLMRouterModel,Azure/Bedrock 云部署用对应专属类。
更多 API 细节可直接查阅 模型参考文档 与 tests/test_models.py 中的用例。
【免费下载链接】smolagents🤗 smolagents: a barebones library for agents that think in code.项目地址: https://gitcode.com/gh_mirrors/smo/smolagents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考