Refactor Ollama implementation and improve documentation
- Enhance OllamaModelPuller with configurable retry timeout - Update test cases to use LLAMA3_1 instead of LLAMA3_2 - Improve Ollama documentation with clearer prerequisites and model pulling instructions - Update Spring AI introduction page with new logo and diagram - Remove unnecessary main method from OllamaModelPuller
This commit is contained in:
@@ -35,8 +35,15 @@ public class OllamaModelPuller {
|
||||
|
||||
private OllamaApi ollamaApi;
|
||||
|
||||
private final long pullRetryTimeoutMs;
|
||||
|
||||
public OllamaModelPuller(OllamaApi ollamaApi) {
|
||||
this(ollamaApi, 5000);
|
||||
}
|
||||
|
||||
public OllamaModelPuller(OllamaApi ollamaApi, long retryTimeoutMs) {
|
||||
this.ollamaApi = ollamaApi;
|
||||
this.pullRetryTimeoutMs = retryTimeoutMs;
|
||||
}
|
||||
|
||||
public boolean isModelAvailable(String modelName) {
|
||||
@@ -56,35 +63,24 @@ public class OllamaModelPuller {
|
||||
return this.ollamaApi.deleteModel(new DeleteModelRequest(modelName)).getStatusCode().equals(HttpStatus.OK);
|
||||
}
|
||||
|
||||
public String pullModel(String modelName, boolean reTry) {
|
||||
public String pullModel(String modelName, boolean enablePullRetry) {
|
||||
String status = "";
|
||||
do {
|
||||
logger.info("Start Pulling model: {}", modelName);
|
||||
var progress = this.ollamaApi.pullModel(new PullModelRequest(modelName));
|
||||
status = progress.status();
|
||||
logger.info("Pulling model: {} - Status: {}", modelName, status);
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
Thread.sleep(this.pullRetryTimeoutMs);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
while (reTry && !status.equals("success"));
|
||||
while (enablePullRetry && !status.equals("success"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
var utils = new OllamaModelPuller(new OllamaApi());
|
||||
|
||||
System.out.println(utils.isModelAvailable("orca-mini:latest"));
|
||||
|
||||
String model = "hf.co/bartowski/Llama-3.2-3B-Instruct-GGUF:Q8_0";
|
||||
|
||||
if (!utils.isModelAvailable(model)) {
|
||||
utils.pullModel(model, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ public class BaseOllamaIT {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseOllamaIT.class);
|
||||
|
||||
// Toggle for running tests locally on native Ollama for a faster feedback loop.
|
||||
private static final boolean useTestcontainers = false;
|
||||
private static final boolean useTestcontainers = true;
|
||||
|
||||
public static final OllamaContainer ollamaContainer;
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class OllamaChatModelFunctionCallingIT extends BaseOllamaIT {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OllamaChatModelFunctionCallingIT.class);
|
||||
|
||||
private static final String MODEL = OllamaModel.LLAMA3_2.getName();
|
||||
private static final String MODEL = OllamaModel.LLAMA3_1.getName();
|
||||
|
||||
@Autowired
|
||||
ChatModel chatModel;
|
||||
|
||||
@@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@DisabledIf("isDisabled")
|
||||
public class OllamaApiToolFunctionCallIT extends BaseOllamaIT {
|
||||
|
||||
private static final String MODEL = OllamaModel.LLAMA3_2.getName();
|
||||
private static final String MODEL = OllamaModel.LLAMA3_1.getName();
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OllamaApiToolFunctionCallIT.class);
|
||||
|
||||
@@ -64,13 +64,11 @@ public class OllamaApiToolFunctionCallIT extends BaseOllamaIT {
|
||||
public void toolFunctionCall() {
|
||||
// Step 1: send the conversation and available functions to the model
|
||||
var message = Message.builder(Role.USER)
|
||||
// .withContent("What's the weather like in San Francisco, Tokyo, and Paris?
|
||||
// Perform multiple function calls for each location.")
|
||||
.withContent("What's the weather like in San Francisco, Tokyo, and Paris?")
|
||||
.withContent("What's the weather like in San Francisco, Tokyo, and Paris? Return temperature in Celsius.")
|
||||
.build();
|
||||
|
||||
var functionTool = new OllamaApi.ChatRequest.Tool(new OllamaApi.ChatRequest.Tool.Function("getCurrentWeather",
|
||||
"Get the weather in location. Return temperature in Celsius.", ModelOptionsUtils.jsonToMap("""
|
||||
"Get the weather in location like city names.", ModelOptionsUtils.jsonToMap("""
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 212 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 227 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
@@ -1,22 +1,19 @@
|
||||
= Ollama Chat
|
||||
|
||||
With https://ollama.ai/[Ollama] you can run various Large Language Models (LLMs) locally and generate text from them.
|
||||
Spring AI supports the Ollama text generation capabilities with the `OllamaChatModel` API.
|
||||
Spring AI supports the Ollama chat completion capabilities with the `OllamaChatModel` API.
|
||||
|
||||
TIP: Ollama offers an OpenAI API compatible endpoint as well.
|
||||
Check the xref:_openai_api_compatibility[OpenAI API compatibility] section to learn how to use the xref:api/chat/openai-chat.adoc[Spring AI OpenAI] project to talk to an Ollama server.
|
||||
The xref:_openai_api_compatibility[OpenAI API compatibility] section explains how to use the xref:api/chat/openai-chat.adoc[Spring AI OpenAI] to connect to an Ollama server.
|
||||
|
||||
== Prerequisites
|
||||
|
||||
You first need to run Ollama on your local machine.
|
||||
Refer to the official Ollama project link:https://github.com/ollama/ollama[README] to get started running models on your local machine.
|
||||
You first need to xref:https://ollama.com/download[Download and install Ollama] on your local machine.
|
||||
|
||||
=== Add Repositories and BOM
|
||||
Also you can pull the models you want to use from the xref:https://ollama.com/library[Ollama model repository]: `ollama pull <desired model name>`.
|
||||
Alternatively, you can enable the `pullMissingModel` option to automatically download missing models: xref:auto-pulling-models[Auto-pulling Models].
|
||||
|
||||
Spring AI artifacts are published in Spring Milestone and Snapshot repositories.
|
||||
Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system.
|
||||
|
||||
To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system.
|
||||
TIP: you can also pull, by name, any of the thousands, free, xref:https://huggingface.co/models?library=gguf&sort=trending[GGUF HuggingFace Models]
|
||||
|
||||
== Auto-configuration
|
||||
|
||||
@@ -132,6 +129,7 @@ ChatResponse response = chatModel.call(
|
||||
|
||||
TIP: In addition to the model specific link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaOptions.java[OllamaOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()].
|
||||
|
||||
[[auto-pulling-models]]
|
||||
=== Auto-pulling Models
|
||||
|
||||
The `pullMissingModel` option allows you to automatically download and use models that are not currently available on your local Ollama instance.
|
||||
@@ -147,6 +145,8 @@ OllamaOptions options = OllamaOptions.builder()
|
||||
.build();
|
||||
----
|
||||
|
||||
TIP: you can also pull, by name, any of the thousands, free, xref:https://huggingface.co/models?library=gguf&sort=trending[GGUF HuggingFace Models]
|
||||
|
||||
You can also configure this option using the following property: `spring.ai.ollama.chat.options.pull-missing-model=true`
|
||||
|
||||
When `pullMissingModel` is set to `true`, the system will attempt to download the specified model if it's not already available locally. This process may take some time depending on the size of the model and your internet connection speed.
|
||||
|
||||
@@ -5,12 +5,16 @@ An embedding is a vector (list) of floating point numbers.
|
||||
The distance between two vectors measures their relatedness.
|
||||
Small distances suggest high relatedness and large distances suggest low relatedness.
|
||||
|
||||
The `OllamaEmbeddingModel` implementation lerverages the Ollama https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings[Embeddings API] endpoint.
|
||||
The `OllamaEmbeddingModel` implementation leverages the Ollama https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings[Embeddings API] endpoint.
|
||||
|
||||
TIP: you can also pull, by name, any of the thousands, free, xref:https://huggingface.co/models?library=gguf&sort=trending[GGUF HuggingFace Models]
|
||||
|
||||
== Prerequisites
|
||||
|
||||
You first need to run Ollama on your local machine.
|
||||
Refer to the official Ollama project link:https://github.com/ollama/ollama[README] to get started running models on your local machine.
|
||||
You first need to xref:https://ollama.com/download[Download and install Ollama] on your local machine.
|
||||
|
||||
Also you can pull the models you want to use from the https://ollama.com/search?c=embedding[Ollama Embedding Models]: `ollama pull <selected embedding model name>`.
|
||||
Alternatively, you can enable the `pullMissingModel` option to automatically download missing models: xref:auto-pulling-models[Auto-pulling Models].
|
||||
|
||||
== Auto-configuration
|
||||
|
||||
@@ -124,6 +128,7 @@ EmbeddingResponse embeddingResponse = embeddingModel.call(
|
||||
.build());
|
||||
----
|
||||
|
||||
[[auto-pulling-models]]
|
||||
=== Auto-pulling Models
|
||||
|
||||
The `pullMissingModel` option allows you to automatically download and use models that are not currently available on your local Ollama instance.
|
||||
@@ -142,6 +147,8 @@ EmbeddingResponse embeddingResponse = embeddingModel
|
||||
.build()));
|
||||
----
|
||||
|
||||
TIP: you can also pull, by name, any of the thousands, free, xref:https://huggingface.co/models?library=gguf&sort=trending[GGUF HuggingFace Models]
|
||||
|
||||
You can also configure this option using the following property: `spring.ai.ollama.embedding.options.pull-missing-model=true`
|
||||
|
||||
When `pullMissingModel` is set to `true`, the system will attempt to download the specified model if it's not already available locally. This process may take some time depending on the size of the model and your internet connection speed.
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[[introduction]]
|
||||
= Spring AI
|
||||
|
||||
image::spring_ai_logo_with_text.svg[Integration Problem, width=400, align="left"]
|
||||
|
||||
The `Spring AI` project aims to streamline the development of applications that incorporate artificial intelligence functionality without unnecessary complexity.
|
||||
|
||||
The project draws inspiration from notable Python projects, such as LangChain and LlamaIndex, but Spring AI is not a direct port of those projects.
|
||||
The project was founded with the belief that the next wave of Generative AI applications will not be only for Python developers but will be ubiquitous across many programming languages.
|
||||
|
||||
> At its core, Spring AI addresses the fundamental challenge of AI integration: `Connecting your enterprise Data and APIs with the AI Models`.
|
||||
NOTE: Spring AI addresses the fundamental challenge of AI integration: `Connecting your enterprise Data and APIs with the AI Models`.
|
||||
|
||||
// image::spring-ai-integrationproblem.png[Integration Problem, width=300, align="center"]
|
||||
image::spring-ai-integration-diagram.svg[Integration Problem, width=500, align="center"]
|
||||
image::spring-ai-integration-diagram2.svg[Integration Problem, width=500, align="center"]
|
||||
|
||||
Spring AI provides abstractions that serve as the foundation for developing AI applications.
|
||||
These abstractions have multiple implementations, enabling easy component swapping with minimal code changes.
|
||||
|
||||
@@ -50,7 +50,7 @@ public class FunctionCallbackInPromptIT extends BaseOllamaIT {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FunctionCallbackInPromptIT.class);
|
||||
|
||||
private static final String MODEL_NAME = OllamaModel.LLAMA3_2.getName();
|
||||
private static final String MODEL_NAME = OllamaModel.LLAMA3_1.getName();
|
||||
|
||||
static String baseUrl;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class FunctionCallbackWrapperIT extends BaseOllamaIT {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FunctionCallbackWrapperIT.class);
|
||||
|
||||
private static final String MODEL_NAME = OllamaModel.LLAMA3_2.getName();
|
||||
private static final String MODEL_NAME = OllamaModel.LLAMA3_1.getName();
|
||||
|
||||
static String baseUrl;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user