Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -46,7 +46,7 @@
*/
public class OllamaChatAutoConfigurationIT extends BaseOllamaIT {

private static final String MODEL_NAME = OllamaModel.LLAMA3_2.getName();
private static final String MODEL_NAME = OllamaModel.QWEN_2_5_3B.getName();

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withPropertyValues(
// @formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

public final class OllamaImage {

public static final String DEFAULT_IMAGE = "ollama/ollama:0.5.7";
public static final String DEFAULT_IMAGE = "ollama/ollama:0.10.1";

private OllamaImage() {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,7 @@
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.ollama.api.OllamaModel;
import reactor.core.publisher.Flux;

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

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

private static final String MODEL_NAME = "qwen2.5:3b";
private static final String MODEL_NAME = OllamaModel.QWEN_2_5_3B.getName();

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withPropertyValues(
// @formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.ollama.api.OllamaModel;
import reactor.core.publisher.Flux;

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

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

private static final String MODEL_NAME = "qwen2.5:3b";
private static final String MODEL_NAME = OllamaModel.QWEN_2_5_3B.getName();

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withPropertyValues(
// @formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ public static Builder builder() {

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


private static final String DEFAULT_BASE_URL = "http://localhost:11434";

private final RestClient restClient;

private final WebClient webClient;
Expand All @@ -80,22 +77,18 @@ public static Builder builder() {
* @param responseErrorHandler Response error handler.
*/
private OllamaApi(String baseUrl, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) {


Consumer<HttpHeaders> defaultHeaders = headers -> {
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
};


this.restClient = restClientBuilder
.clone()
.baseUrl(baseUrl)
.defaultHeaders(defaultHeaders)
.defaultStatusHandler(responseErrorHandler)
.build();


this.webClient = webClientBuilder
.clone()
.baseUrl(baseUrl)
Expand Down Expand Up @@ -260,15 +253,20 @@ public Flux<ProgressResponse> pullModel(PullModelRequest pullModelRequest) {
* @param content The content of the message.
* @param images The list of base64-encoded images to send with the message.
* Requires multimodal models such as llava or bakllava.
* @param toolCalls The relevant tool call.
* @param toolCalls The list of tools that the model wants to use.
* @param toolName The name of the tool that was executed to inform the model of the result.
* @param thinking The model's thinking process. Requires thinking models such as qwen3.
*/
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Message(
@JsonProperty("role") Role role,
@JsonProperty("content") String content,
@JsonProperty("images") List<String> images,
@JsonProperty("tool_calls") List<ToolCall> toolCalls) {
@JsonProperty("tool_calls") List<ToolCall> toolCalls,
@JsonProperty("tool_name") String toolName,
@JsonProperty("thinking") String thinking
) {

public static Builder builder(Role role) {
return new Builder(role);
Expand Down Expand Up @@ -317,11 +315,19 @@ public record ToolCall(
*
* @param name The name of the function.
* @param arguments The arguments that the model expects you to pass to the function.
* @param index The index of the function call in the list of tool calls.
*/
@JsonInclude(Include.NON_NULL)
public record ToolCallFunction(
@JsonProperty("name") String name,
@JsonProperty("arguments") Map<String, Object> arguments) {
@JsonProperty("arguments") Map<String, Object> arguments,
@JsonProperty("index") Integer index
) {

public ToolCallFunction(String name, Map<String, Object> arguments) {
this(name, arguments, null);
}

}

public static class Builder {
Expand All @@ -330,6 +336,8 @@ public static class Builder {
private String content;
private List<String> images;
private List<ToolCall> toolCalls;
private String toolName;
private String thinking;

public Builder(Role role) {
this.role = role;
Expand All @@ -350,8 +358,18 @@ public Builder toolCalls(List<ToolCall> toolCalls) {
return this;
}

public Builder toolName(String toolName) {
this.toolName = toolName;
return this;
}

public Builder thinking(String thinking) {
this.thinking = thinking;
return this;
}

public Message build() {
return new Message(this.role, this.content, this.images, this.toolCalls);
return new Message(this.role, this.content, this.images, this.toolCalls, this.toolName, this.thinking);
}
}
}
Expand All @@ -367,6 +385,7 @@ public Message build() {
* @param tools List of tools the model has access to.
* @param options Model-specific options. For example, "temperature" can be set through this field, if the model supports it.
* You can use the {@link OllamaOptions} builder to create the options then {@link OllamaOptions#toMap()} to convert the options into a map.
* @param think Think controls whether thinking/reasoning models will think before responding.
*
* @see <a href=
* "https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion">Chat
Expand All @@ -382,7 +401,8 @@ public record ChatRequest(
@JsonProperty("format") Object format,
@JsonProperty("keep_alive") String keepAlive,
@JsonProperty("tools") List<Tool> tools,
@JsonProperty("options") Map<String, Object> options
@JsonProperty("options") Map<String, Object> options,
@JsonProperty("think") Boolean think
) {

public static Builder builder(String model) {
Expand Down Expand Up @@ -455,6 +475,7 @@ public static class Builder {
private String keepAlive;
private List<Tool> tools = List.of();
private Map<String, Object> options = Map.of();
private Boolean think;

public Builder(String model) {
Assert.notNull(model, "The model can not be null.");
Expand Down Expand Up @@ -499,8 +520,13 @@ public Builder options(OllamaOptions options) {
return this;
}

public Builder think(Boolean think) {
this.think = think;
return this;
}

public ChatRequest build() {
return new ChatRequest(this.model, this.messages, this.stream, this.format, this.keepAlive, this.tools, this.options);
return new ChatRequest(this.model, this.messages, this.stream, this.format, this.keepAlive, this.tools, this.options, this.think);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,30 @@
*/
public enum OllamaModel implements ChatModelDescription {

QWEN_2_5_3B("qwen2.5:3b"),

/**
* Qwen 2.5
*/
QWEN_2_5_7B("qwen2.5"),

/**
* Flagship vision-language model of Qwen and also a significant leap from the
* previous Qwen2-VL.
*/
QWEN2_5_VL("qwen2.5vl"),

/**
* Qwen3 is the latest generation of large language models in Qwen series, offering a
* comprehensive suite of dense and mixture-of-experts (MoE) models.
*/
QWEN3_7B("qwen3:7b"),

/**
* Qwen3 4B
*/
QWEN3_4B("qwen3:4b"),

/**
* QwQ is the reasoning model of the Qwen series.
*/
Expand Down Expand Up @@ -139,6 +158,11 @@ public enum OllamaModel implements ChatModelDescription {
*/
GEMMA("gemma"),

/**
* The current, most capable model that runs on a single GPU.
*/
GEMMA3("gemma3"),

/**
* Uncensored Llama 2 model
*/
Expand Down
Loading