Skip to content

Commit 3ee33c1

Browse files
ThomasVitalesobychacko
authored andcommitted
Update Ollama API to latest version
* Add missing fields to Ollama API classes * Deprecate Ollama options that are no longer supported * Update integration tests using Ollama 0.10.1 (latest version) and more performant models. Fixes #3969 Auto-cherry-pick to 1.0.x Signed-off-by: Thomas Vitale <[email protected]>
1 parent b95f822 commit 3ee33c1

File tree

18 files changed

+341
-114
lines changed

18 files changed

+341
-114
lines changed

auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/OllamaChatAutoConfigurationIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 the original author or authors.
2+
* Copyright 2023-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@
4646
*/
4747
public class OllamaChatAutoConfigurationIT extends BaseOllamaIT {
4848

49-
private static final String MODEL_NAME = OllamaModel.LLAMA3_2.getName();
49+
private static final String MODEL_NAME = OllamaModel.QWEN_2_5_3B.getName();
5050

5151
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withPropertyValues(
5252
// @formatter:off

auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/OllamaImage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
public final class OllamaImage {
2020

21-
public static final String DEFAULT_IMAGE = "ollama/ollama:0.5.7";
21+
public static final String DEFAULT_IMAGE = "ollama/ollama:0.10.1";
2222

2323
private OllamaImage() {
2424

auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/tool/FunctionCallbackInPromptIT.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 the original author or authors.
2+
* Copyright 2023-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import org.junit.jupiter.api.Test;
2424
import org.slf4j.Logger;
2525
import org.slf4j.LoggerFactory;
26+
import org.springframework.ai.ollama.api.OllamaModel;
2627
import reactor.core.publisher.Flux;
2728

2829
import org.springframework.ai.chat.messages.AssistantMessage;
@@ -44,7 +45,7 @@ public class FunctionCallbackInPromptIT extends BaseOllamaIT {
4445

4546
private static final Logger logger = LoggerFactory.getLogger(FunctionCallbackInPromptIT.class);
4647

47-
private static final String MODEL_NAME = "qwen2.5:3b";
48+
private static final String MODEL_NAME = OllamaModel.QWEN_2_5_3B.getName();
4849

4950
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withPropertyValues(
5051
// @formatter:off

auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/tool/OllamaFunctionToolBeanIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.junit.jupiter.api.Test;
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
27+
import org.springframework.ai.ollama.api.OllamaModel;
2728
import reactor.core.publisher.Flux;
2829

2930
import org.springframework.ai.chat.messages.AssistantMessage;
@@ -55,7 +56,7 @@ public class OllamaFunctionToolBeanIT extends BaseOllamaIT {
5556

5657
private static final Logger logger = LoggerFactory.getLogger(OllamaFunctionToolBeanIT.class);
5758

58-
private static final String MODEL_NAME = "qwen2.5:3b";
59+
private static final String MODEL_NAME = OllamaModel.QWEN_2_5_3B.getName();
5960

6061
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withPropertyValues(
6162
// @formatter:off

models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ public static Builder builder() {
6565

6666
private static final Log logger = LogFactory.getLog(OllamaApi.class);
6767

68-
69-
private static final String DEFAULT_BASE_URL = "http://localhost:11434";
70-
7168
private final RestClient restClient;
7269

7370
private final WebClient webClient;
@@ -80,22 +77,18 @@ public static Builder builder() {
8077
* @param responseErrorHandler Response error handler.
8178
*/
8279
private OllamaApi(String baseUrl, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) {
83-
84-
8580
Consumer<HttpHeaders> defaultHeaders = headers -> {
8681
headers.setContentType(MediaType.APPLICATION_JSON);
8782
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
8883
};
8984

90-
9185
this.restClient = restClientBuilder
9286
.clone()
9387
.baseUrl(baseUrl)
9488
.defaultHeaders(defaultHeaders)
9589
.defaultStatusHandler(responseErrorHandler)
9690
.build();
9791

98-
9992
this.webClient = webClientBuilder
10093
.clone()
10194
.baseUrl(baseUrl)
@@ -260,15 +253,20 @@ public Flux<ProgressResponse> pullModel(PullModelRequest pullModelRequest) {
260253
* @param content The content of the message.
261254
* @param images The list of base64-encoded images to send with the message.
262255
* Requires multimodal models such as llava or bakllava.
263-
* @param toolCalls The relevant tool call.
256+
* @param toolCalls The list of tools that the model wants to use.
257+
* @param toolName The name of the tool that was executed to inform the model of the result.
258+
* @param thinking The model's thinking process. Requires thinking models such as qwen3.
264259
*/
265260
@JsonInclude(Include.NON_NULL)
266261
@JsonIgnoreProperties(ignoreUnknown = true)
267262
public record Message(
268263
@JsonProperty("role") Role role,
269264
@JsonProperty("content") String content,
270265
@JsonProperty("images") List<String> images,
271-
@JsonProperty("tool_calls") List<ToolCall> toolCalls) {
266+
@JsonProperty("tool_calls") List<ToolCall> toolCalls,
267+
@JsonProperty("tool_name") String toolName,
268+
@JsonProperty("thinking") String thinking
269+
) {
272270

273271
public static Builder builder(Role role) {
274272
return new Builder(role);
@@ -317,11 +315,19 @@ public record ToolCall(
317315
*
318316
* @param name The name of the function.
319317
* @param arguments The arguments that the model expects you to pass to the function.
318+
* @param index The index of the function call in the list of tool calls.
320319
*/
321320
@JsonInclude(Include.NON_NULL)
322321
public record ToolCallFunction(
323322
@JsonProperty("name") String name,
324-
@JsonProperty("arguments") Map<String, Object> arguments) {
323+
@JsonProperty("arguments") Map<String, Object> arguments,
324+
@JsonProperty("index") Integer index
325+
) {
326+
327+
public ToolCallFunction(String name, Map<String, Object> arguments) {
328+
this(name, arguments, null);
329+
}
330+
325331
}
326332

327333
public static class Builder {
@@ -330,6 +336,8 @@ public static class Builder {
330336
private String content;
331337
private List<String> images;
332338
private List<ToolCall> toolCalls;
339+
private String toolName;
340+
private String thinking;
333341

334342
public Builder(Role role) {
335343
this.role = role;
@@ -350,8 +358,18 @@ public Builder toolCalls(List<ToolCall> toolCalls) {
350358
return this;
351359
}
352360

361+
public Builder toolName(String toolName) {
362+
this.toolName = toolName;
363+
return this;
364+
}
365+
366+
public Builder thinking(String thinking) {
367+
this.thinking = thinking;
368+
return this;
369+
}
370+
353371
public Message build() {
354-
return new Message(this.role, this.content, this.images, this.toolCalls);
372+
return new Message(this.role, this.content, this.images, this.toolCalls, this.toolName, this.thinking);
355373
}
356374
}
357375
}
@@ -367,6 +385,7 @@ public Message build() {
367385
* @param tools List of tools the model has access to.
368386
* @param options Model-specific options. For example, "temperature" can be set through this field, if the model supports it.
369387
* You can use the {@link OllamaOptions} builder to create the options then {@link OllamaOptions#toMap()} to convert the options into a map.
388+
* @param think Think controls whether thinking/reasoning models will think before responding.
370389
*
371390
* @see <a href=
372391
* "https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion">Chat
@@ -382,7 +401,8 @@ public record ChatRequest(
382401
@JsonProperty("format") Object format,
383402
@JsonProperty("keep_alive") String keepAlive,
384403
@JsonProperty("tools") List<Tool> tools,
385-
@JsonProperty("options") Map<String, Object> options
404+
@JsonProperty("options") Map<String, Object> options,
405+
@JsonProperty("think") Boolean think
386406
) {
387407

388408
public static Builder builder(String model) {
@@ -455,6 +475,7 @@ public static class Builder {
455475
private String keepAlive;
456476
private List<Tool> tools = List.of();
457477
private Map<String, Object> options = Map.of();
478+
private Boolean think;
458479

459480
public Builder(String model) {
460481
Assert.notNull(model, "The model can not be null.");
@@ -499,8 +520,13 @@ public Builder options(OllamaOptions options) {
499520
return this;
500521
}
501522

523+
public Builder think(Boolean think) {
524+
this.think = think;
525+
return this;
526+
}
527+
502528
public ChatRequest build() {
503-
return new ChatRequest(this.model, this.messages, this.stream, this.format, this.keepAlive, this.tools, this.options);
529+
return new ChatRequest(this.model, this.messages, this.stream, this.format, this.keepAlive, this.tools, this.options, this.think);
504530
}
505531
}
506532
}

models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaModel.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,30 @@
2727
*/
2828
public enum OllamaModel implements ChatModelDescription {
2929

30+
QWEN_2_5_3B("qwen2.5:3b"),
31+
3032
/**
3133
* Qwen 2.5
3234
*/
3335
QWEN_2_5_7B("qwen2.5"),
3436

37+
/**
38+
* Flagship vision-language model of Qwen and also a significant leap from the
39+
* previous Qwen2-VL.
40+
*/
41+
QWEN2_5_VL("qwen2.5vl"),
42+
43+
/**
44+
* Qwen3 is the latest generation of large language models in Qwen series, offering a
45+
* comprehensive suite of dense and mixture-of-experts (MoE) models.
46+
*/
47+
QWEN3_7B("qwen3:7b"),
48+
49+
/**
50+
* Qwen3 4B
51+
*/
52+
QWEN3_4B("qwen3:4b"),
53+
3554
/**
3655
* QwQ is the reasoning model of the Qwen series.
3756
*/
@@ -139,6 +158,11 @@ public enum OllamaModel implements ChatModelDescription {
139158
*/
140159
GEMMA("gemma"),
141160

161+
/**
162+
* The current, most capable model that runs on a single GPU.
163+
*/
164+
GEMMA3("gemma3"),
165+
142166
/**
143167
* Uncensored Llama 2 model
144168
*/

0 commit comments

Comments
 (0)