Docker Model Runner 是一款人工智能推理引擎,提供来自各类服务商的丰富模型。
Spring AI 通过复用已有的 OpenAI 对话客户端,实现了与 Docker Model Runner 的集成。使用时需将基础 URL 设置为 localhost:12434/engines,并选择提供的大语言模型之一。
可查看 DockerModelRunnerWithOpenAiChatModelIT.java 测试文件,了解 Spring AI 结合 Docker Model Runner 的使用示例。
前提条件
下载适用于 Mac 的 Docker Desktop 4.40.0 版本。
通过以下任一方式启用 Model Runner:
方式一:
执行命令启用 Model Runner:docker desktop enable model-runner --tcp 12434
将基础地址设置为:localhost:12434/engines
方式二:
执行命令启用 Model Runner:docker desktop enable model-runner
使用 Testcontainers,并按如下方式配置基础地址:
@Container
private static final DockerModelRunnerContainer DMR = new DockerModelRunnerContainer("alpine/socat:1.7.4.3-r0");
@Bean
public OpenAiApi chatCompletionApi() {
var baseUrl = DMR.getOpenAIEndpoint();
return OpenAiApi.builder().baseUrl(baseUrl).apiKey("test").build();
}你可以阅读《使用 Docker 本地运行大语言模型》技术博客,了解更多 Docker Model Runner 相关信息。
自动配置
自 1.0.0.M7 版本起,Spring AI 启动器模块的构件 ID 已重新命名。依赖名称需遵循更新后的命名规范,适用于模型、向量数据库和 MCP 启动器。更多信息请参考升级说明。
Spring AI 为 OpenAI 对话客户端提供 Spring Boot 自动配置。启用该功能需在项目的 Maven pom.xml 文件中添加以下依赖:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency>
或在 Gradle build.gradle 构建文件中添加:
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-openai'
}参考依赖管理章节,将 Spring AI 物料清单(BOM)添加到构建文件中。
对话属性配置
重试属性
spring.ai.retry 前缀用于配置 OpenAI 对话模型的重试机制。
| 属性 | 描述 | 默认值 |
|---|---|---|
| spring.ai.retry.max-attempts | 最大重试次数 | 10 |
| spring.ai.retry.backoff.initial-interval | 指数退避策略初始休眠时长 | 2秒 |
| spring.ai.retry.backoff.multiplier | 退避间隔乘数 | 5 |
| spring.ai.retry.backoff.max-interval | 最大退避时长 | 3分钟 |
| spring.ai.retry.on-client-errors | 若为 false,抛出 NonTransientAiException 异常,不重试 4xx 客户端错误 | false |
| spring.ai.retry.exclude-on-http-codes | 禁止触发重试的 HTTP 状态码列表 | 空 |
| spring.ai.retry.on-http-codes | 允许触发重试的 HTTP 状态码列表 | 空 |
连接属性
spring.ai.openai 前缀用于配置 OpenAI 连接参数。
| 属性 | 描述 | 默认值 |
|---|---|---|
| spring.ai.openai.base-url | 连接地址,必须设置为 hub.docker.com/u/ai | - |
| spring.ai.openai.api-key | 任意字符串即可 | - |
配置属性
现在通过顶级属性 spring.ai.model.chat 启用/禁用对话自动配置:
启用:spring.ai.model.chat=openai(默认启用)
禁用:spring.ai.model.chat=none(或其他不等于 openai 的值)
该修改支持在应用中配置多个模型。
spring.ai.openai.chat 前缀用于配置 OpenAI 对话模型。
| 属性 | 描述 | 默认值 |
|---|---|---|
| spring.ai.openai.chat.enabled(已移除,无效) | 启用 OpenAI 对话模型 | true |
| spring.ai.model.chat | 启用 OpenAI 对话模型 | openai |
| spring.ai.openai.chat.base-url | 可选覆盖基础地址,必须设置为 localhost:12434/engines | - |
| spring.ai.openai.chat.api-key | 可选覆盖 API 密钥 | - |
| spring.ai.openai.chat.options.model | 使用的大语言模型 | - |
| spring.ai.openai.chat.options.temperature | 采样温度,控制生成内容的创造性,值越高越随机,越低越精准 | 0.8 |
| spring.ai.openai.chat.options.frequencyPenalty | -2.0~2.0,正值降低重复语句概率 | 0.0f |
| spring.ai.openai.chat.options.maxTokens | 生成最大令牌数,受模型上下文长度限制 | - |
| spring.ai.openai.chat.options.n | 单条输入生成的结果数量,建议设为1节约成本 | 1 |
| spring.ai.openai.chat.options.presencePenalty | -2.0~2.0,正值提升新话题生成概率 | - |
| spring.ai.openai.chat.options.responseFormat | 输出格式,{"type": "json_object"} 启用 JSON 模式 | - |
| spring.ai.openai.chat.options.seed | 测试版功能,指定后尽力保证结果可复现 | - |
| spring.ai.openai.chat.options.stop | 最多4个停止生成的序列 | - |
| spring.ai.openai.chat.options.topP | 核采样,替代温度采样,建议只调整其一 | - |
| spring.ai.openai.chat.options.tools | 模型可调用的工具列表,目前仅支持函数 | - |
| spring.ai.openai.chat.options.toolChoice | 控制模型调用函数,none/auto/指定函数 | 无函数时为none,有函数时为auto |
| spring.ai.openai.chat.options.user | 终端用户唯一标识,用于监控滥用 | - |
| spring.ai.openai.chat.options.stream-usage | 仅流式,添加令牌用量统计分片 | false |
| spring.ai.openai.chat.options.tool-names | 单次请求启用的工具名称列表 | - |
| spring.ai.openai.chat.options.tool-callbacks | 向对话模型注册的工具回调 | - |
| spring.ai.openai.chat.options.internal-tool-execution-enabled | true:Spring AI 内部处理工具调用;false:交由客户端处理 | true |
所有 spring.ai.openai.chat.options 前缀的属性,均可在运行时通过为 Prompt 添加请求级运行时选项覆盖。
运行时选项
OpenAiChatOptions.java 提供模型、温度、频率惩罚等配置。
启动时可通过构造方法或配置文件设置默认选项。
运行时可覆盖默认配置,示例:
ChatResponse response = chatModel.call(
new Prompt(
"生成5位著名海盗的名字。",
OpenAiChatOptions.builder()
.model("ai/gemma3:4B-F16")
.build()
));除了模型专用的 OpenAiChatOptions,也可使用通用 ChatOptions。
函数调用
选择支持该功能的模型时,Docker Model Runner 支持工具/函数调用。
你可以向对话模型注册自定义 Java 函数,模型会智能选择输出 JSON 参数调用一个或多个注册函数,实现大语言模型与外部工具、API 的连接。
工具示例
Spring AI 结合 Docker Model Runner 函数调用的简单示例:
spring.ai.openai.api-key=test spring.ai.openai.base-url=http://localhost:12434/engines spring.ai.openai.chat.options.model=ai/gemma3:4B-F16
@SpringBootApplication
public class DockerModelRunnerLlmApplication {
public static void main(String[] args) {
SpringApplication.run(DockerModelRunnerLlmApplication.class, args);
}
@Bean
CommandLineRunner runner(ChatClient.Builder chatClientBuilder) {
return args -> {
var chatClient = chatClientBuilder.build();
var response = chatClient.prompt()
.user("阿姆斯特丹和巴黎的天气如何?")
.functions("weatherFunction") // 通过Bean名称引用
.call()
.content();
System.out.println(response);
};
}
@Bean
@Description("获取指定地点的天气")
public Function<WeatherRequest, WeatherResponse> weatherFunction() {
return new MockWeatherService();
}
public static class MockWeatherService implements Function<WeatherRequest, WeatherResponse> {
public record WeatherRequest(String location, String unit) {}
public record WeatherResponse(double temp, String unit) {}
@Override
public WeatherResponse apply(WeatherRequest request) {
double temperature = request.location().contains("Amsterdam") ? 20 : 25;
return new WeatherResponse(temperature, request.unit);
}
}
}示例中模型需要天气信息时,会自动调用 weatherFunction,预期返回:阿姆斯特丹当前气温20摄氏度,巴黎当前气温25摄氏度。
阅读 OpenAI 函数调用文档了解更多。
示例控制器
创建新 Spring Boot 项目,添加 spring-ai-starter-model-openai 依赖。
在 src/main/resources 下添加 application.properties 配置:
spring.ai.openai.api-key=test spring.ai.openai.base-url=http://localhost:12434/engines spring.ai.openai.chat.options.model=ai/gemma3:4B-F16 # Docker Model Runner 不支持嵌入向量,需禁用 spring.ai.openai.embedding.enabled=false
简单控制器示例:
@RestController
public class ChatController {
private final OpenAiChatModel chatModel;
@Autowired
public ChatController(OpenAiChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/ai/generate")
public Map generate(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message) {
return Map.of("generation", this.chatModel.call(message));
}
@GetMapping("/ai/generateStream")
public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return this.chatModel.stream(prompt);
}
}