Ollama 聊天

藉助 Ollama,您可以在本地執行各種大語言模型 (LLM) 並從中生成文字。Spring AI 透過 OllamaChatModel API 支援 Ollama 的聊天補全功能。

Ollama 也提供了相容 OpenAI API 的端點。 OpenAI API 相容性 部分解釋瞭如何使用 Spring AI OpenAI 連線到 Ollama 伺服器。

先決條件

您首先需要訪問一個 Ollama 例項。有幾種選項,包括以下幾種

您可以從 Ollama 模型庫 中拉取您想在應用程式中使用的模型

ollama pull <model-name>

您還可以拉取成千上萬個免費的 GGUF Hugging Face 模型 中的任何一個

ollama pull hf.co/<username>/<model-repository>

或者,您可以啟用自動下載所需模型的選項:自動拉取模型

自動配置

Spring AI 自動配置、starter 模組的 artifact 名稱發生了重大變化。有關更多資訊,請參閱升級說明

Spring AI 為 Ollama 聊天整合提供了 Spring Boot 自動配置。要啟用它,請將以下依賴項新增到您的專案的 Maven pom.xml 或 Gradle build.gradle 構建檔案中

  • Maven

  • Gradle

<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-ollama'
}
請參考依賴管理部分,將 Spring AI BOM 新增到您的構建檔案中。

基礎屬性

字首 spring.ai.ollama 是用於配置 Ollama 連線的屬性字首。

屬性

描述

預設值

spring.ai.ollama.base-url

Ollama API 伺服器執行的基礎 URL。

localhost:11434

以下是用於初始化 Ollama 整合和自動拉取模型的屬性。

屬性

描述

預設值

spring.ai.ollama.init.pull-model-strategy

是否以及如何在啟動時拉取模型。

never

spring.ai.ollama.init.timeout

等待模型拉取完成的最長時間。

5m

spring.ai.ollama.init.max-retries

模型拉取操作的最大重試次數。

0

spring.ai.ollama.init.chat.include

在初始化任務中包含此型別的模型。

true

spring.ai.ollama.init.chat.additional-models

除了透過預設屬性配置的模型之外,還需要初始化的其他模型。

[]

聊天屬性

聊天自動配置的啟用和停用現在透過字首為 spring.ai.model.chat 的頂層屬性進行配置。

啟用:spring.ai.model.chat=ollama (預設已啟用)

停用:spring.ai.model.chat=none (或任何不匹配 ollama 的值)

此更改是為了支援配置多個模型。

字首 spring.ai.ollama.chat.options 是用於配置 Ollama 聊天模型的屬性字首。它包括 Ollama 請求(高階)引數,例如 modelkeep-aliveformat,以及 Ollama 模型的 options 屬性。

以下是 Ollama 聊天模型的高階請求引數

屬性

描述

預設值

spring.ai.ollama.chat.enabled (已移除且不再有效)

啟用 Ollama 聊天模型。

true

spring.ai.model.chat

啟用 Ollama 聊天模型。

ollama

spring.ai.ollama.chat.options.model

要使用的受支援模型的名稱。

mistral

spring.ai.ollama.chat.options.format

返回響應的格式。目前,唯一接受的值是 json

-

spring.ai.ollama.chat.options.keep_alive

控制模型在請求後保持載入到記憶體中的時長

5m

剩餘的 options 屬性基於Ollama 有效引數和值以及Ollama 型別。預設值基於Ollama 型別預設值

屬性

描述

預設值

spring.ai.ollama.chat.options.numa

是否使用 NUMA。

false

spring.ai.ollama.chat.options.num-ctx

設定用於生成下一個 token 的上下文視窗大小。

2048

spring.ai.ollama.chat.options.num-batch

spring.ai.ollama.chat.options.num-batch

512

提示詞處理最大批次大小。

spring.ai.ollama.chat.options.num-gpu

-1

傳送到 GPU 的層數。在 macOS 上,預設為 1 以啟用 metal 支援,0 為停用。這裡的 1 表示應動態設定 NumGPU

spring.ai.ollama.chat.options.main-gpu

0

當使用多個 GPU 時,此選項控制哪個 GPU 用於小張量,對於這些張量,將計算拆分到所有 GPU 的開銷不值得。該 GPU 將使用稍微更多的 VRAM 來儲存臨時結果的暫存緩衝區。

-

false

spring.ai.ollama.chat.options.low-vram

-

true

spring.ai.ollama.chat.options.f16-kv

spring.ai.ollama.chat.options.logits-all

-

返回所有 token 的 logits,而不僅僅是最後一個。要使補全能夠返回 logprobs,此值必須為 true。

spring.ai.ollama.chat.options.vocab-only

-

僅載入詞彙表,不載入權重。

spring.ai.ollama.chat.options.use-mmap

預設情況下,模型被對映到記憶體中,這使得系統可以根據需要僅載入模型的必要部分。然而,如果模型大於您的總 RAM 量,或者您的系統可用記憶體不足,使用 mmap 可能會增加頁面換出的風險,從而對效能產生負面影響。停用 mmap 會導致載入時間變慢,但如果您不使用 mlock,可能會減少頁面換出。請注意,如果模型大於總 RAM 量,關閉 mmap 將完全阻止模型載入。

null

spring.ai.ollama.chat.options.use-mlock

false

鎖定模型在記憶體中,防止在記憶體對映時被換出。這可以提高效能,但透過需要更多 RAM 來執行以及模型載入到 RAM 時可能降低載入速度,從而犧牲了記憶體對映的一些優勢。

spring.ai.ollama.chat.options.num-thread

0

設定計算期間使用的執行緒數。預設情況下,Ollama 會檢測以獲得最佳效能。建議將此值設定為系統物理 CPU 核心數(而不是邏輯核心數)。0 = 讓執行時決定

-

4

spring.ai.ollama.chat.options.num-keep

設定用於生成的隨機數種子。將其設定為特定數字後,模型對於相同的提示將生成相同的文字。

-1

spring.ai.ollama.chat.options.seed

設定用於生成的隨機數種子。將其設定為特定數字將使模型對相同的提示生成相同的文字。

-1

spring.ai.ollama.chat.options.num-predict

生成文字時預測的最大 token 數。(-1 = 無限生成,-2 = 填充上下文)

40

spring.ai.ollama.chat.options.top-k

降低生成胡言亂語的機率。值越高(例如 100),答案越多樣化,而值越低(例如 10),答案越保守。

0.9

spring.ai.ollama.chat.options.top-p

與 top-k 協同工作。值越高(例如 0.95),文字越多樣化,而值越低(例如 0.5),生成的文字越集中和保守。

0.0

spring.ai.ollama.chat.options.min-p

是 top_p 的替代方案,旨在確保質量和多樣性的平衡。引數 p 表示相對於最可能 token 的機率,一個 token 被考慮的最小機率。例如,當 p=0.05 且最可能 token 的機率為 0.9 時,值小於 0.045 的 logits 將被過濾掉。

1.0

spring.ai.ollama.chat.options.tfs-z

-

1.0

使用無尾取樣 (Tail-free sampling) 來減少低機率 token 對輸出的影響。值越高(例如 2.0),影響減少得越多,而值為 1.0 則停用此設定。

spring.ai.ollama.chat.options.typical-p

64

spring.ai.ollama.chat.options.temperature

spring.ai.ollama.chat.options.repeat-last-n

0.8

設定模型向前看多少個 token 以防止重複。(預設值:64,0 = 停用,-1 = num_ctx)

spring.ai.ollama.chat.options.temperature

1.1

模型溫度。提高溫度將使模型回答更具創造性。

-

0.0

spring.ai.ollama.chat.options.repeat-penalty

-

0.0

設定對重複項的懲罰強度。值越高(例如 1.5),懲罰重複項越強,而值越低(例如 0.9),越寬鬆。

spring.ai.ollama.chat.options.presence-penalty

0

spring.ai.ollama.chat.options.frequency-penalty

spring.ai.ollama.chat.options.mirostat

5.0

啟用 Mirostat 取樣以控制困惑度。(預設值:0,0 = 停用,1 = Mirostat,2 = Mirostat 2.0)

spring.ai.ollama.chat.options.mirostat-tau

0.1

控制輸出的連貫性和多樣性之間的平衡。值越低,文字越集中和連貫。

-

true

spring.ai.ollama.chat.options.mirostat-eta

影響演算法對生成文字反饋的響應速度。較低的學習率會導致調整變慢,而較高的學習率將使演算法更具響應性。

-

spring.ai.ollama.chat.options.penalize-newline

spring.ai.ollama.chat.options.stop

-

設定要使用的停止序列。當遇到此模式時,LLM 將停止生成文字並返回。可以透過在 modelfile 中指定多個單獨的停止引數來設定多個停止模式。

spring.ai.ollama.chat.options.functions

false

要為單個提示請求中的函式呼叫啟用的函式列表,按其名稱標識。具有這些名稱的函式必須存在於 functionCallbacks 登錄檔中。

spring.ai.ollama.chat.options.proxy-tool-calls

如果為 true,Spring AI 將不會在內部處理函式呼叫,而是將它們代理到客戶端。然後由客戶端負責處理函式呼叫,將它們分派給適當的函式,並返回結果。如果為 false(預設值),Spring AI 將在內部處理函式呼叫。僅適用於支援函式呼叫的聊天模型

所有以 spring.ai.ollama.chat.options 為字首的屬性都可以在執行時透過向 Prompt 呼叫新增請求特定的執行時選項來覆蓋。

執行時選項

ChatResponse response = chatModel.call(
    new Prompt(
        "Generate the names of 5 famous pirates.",
        OllamaOptions.builder()
            .model(OllamaModel.LLAMA3_1)
            .temperature(0.4)
            .build()
    ));
OllamaOptions.java 類提供了模型配置,例如要使用的模型、溫度等。

在啟動時,可以使用 OllamaChatModel(api, options) 建構函式或 spring.ai.ollama.chat.options.* 屬性配置預設選項。

在執行時,您可以透過向 Prompt 呼叫新增新的、特定於請求的選項來覆蓋預設選項。例如,為特定請求覆蓋預設模型和溫度

除了模型特定的 OllamaOptions 外,您還可以使用可移植的 ChatOptions 例項,該例項使用 ChatOptionsBuilder#builder() 建立。

自動拉取模型

  • 當您的 Ollama 例項中沒有模型時,Spring AI Ollama 可以自動拉取模型。此功能對於開發、測試以及將應用程式部署到新環境特別有用。

  • 您還可以按名稱拉取成千上萬個免費的 GGUF Hugging Face 模型 中的任何一個。

  • 有三種拉取模型策略

always (在 PullModelStrategy.ALWAYS 中定義):始終拉取模型,即使它已經可用。這對於確保您正在使用最新版本的模型很有用。

when_missing (在 PullModelStrategy.WHEN_MISSING 中定義):僅當模型不可用時才拉取。這可能導致使用較舊版本的模型。

spring:
  ai:
    ollama:
      init:
        pull-model-strategy: always
        timeout: 60s
        max-retries: 1
never (在 PullModelStrategy.NEVER 中定義):從不自動拉取模型。

由於下載模型可能存在延遲,不建議在生產環境中使用自動拉取。建議提前評估並預下載必要的模型。

spring:
  ai:
    ollama:
      init:
        pull-model-strategy: always
        chat:
          additional-models:
            - llama3.2
            - qwen2.5

透過配置屬性和預設選項定義的所有模型都可以在啟動時自動拉取。您可以使用配置屬性配置拉取策略、超時和最大重試次數

spring:
  ai:
    ollama:
      init:
        pull-model-strategy: always
        chat:
          include: false

應用程式將不會完成初始化,直到 Ollama 中所有指定的模型都可用。根據模型大小和網路連線速度,這可能會顯著減慢應用程式的啟動時間。

您可以在啟動時初始化其他模型,這對於在執行時動態使用的模型很有用

如果您只想將拉取策略應用於特定型別的模型,可以從初始化任務中排除聊天模型

此配置將對除聊天模型之外的所有模型應用拉取策略。

函式呼叫

您可以向 OllamaChatModel 註冊自定義 Java 函式,並讓 Ollama 模型智慧選擇輸出一個包含引數的 JSON 物件,以呼叫一個或多個已註冊的函式。這是一種將 LLM 功能與外部工具和 API 連線的強大技術。閱讀更多關於Ollama 函式呼叫的資訊。

您需要 Ollama 0.2.8 或更高版本才能使用函式呼叫功能,需要 Ollama 0.4.6 或更高版本才能在流模式下使用它們。

多模態

多模態是指模型能夠同時理解和處理來自各種源(包括文字、影像、音訊和其他資料格式)的資訊的能力。

Ollama 中一些支援多模態的模型包括 LLaVABakLLaVA (參見完整列表)。更多詳情,請參閱LLaVA:大語言和視覺助手

var imageResource = new ClassPathResource("/multimodal.test.png");

var userMessage = new UserMessage("Explain what do you see on this picture?",
        new Media(MimeTypeUtils.IMAGE_PNG, this.imageResource));

ChatResponse response = chatModel.call(new Prompt(this.userMessage,
        OllamaOptions.builder().model(OllamaModel.LLAVA)).build());

Ollama 訊息 API 提供了一個“images”引數,用於在訊息中包含 base64 編碼影像列表。

Multimodal Test Image

Spring AI 的 Message 介面透過引入 Media 型別來促進多模態 AI 模型。此型別包含訊息中媒體附件的資料和詳細資訊,利用 Spring 的 org.springframework.util.MimeTypeorg.springframework.core.io.Resource 來處理原始媒體資料。

The image shows a small metal basket filled with ripe bananas and red apples. The basket is placed on a surface,
which appears to be a table or countertop, as there's a hint of what seems like a kitchen cabinet or drawer in
the background. There's also a gold-colored ring visible behind the basket, which could indicate that this
photo was taken in an area with metallic decorations or fixtures. The overall setting suggests a home environment
where fruits are being displayed, possibly for convenience or aesthetic purposes.

下面是一個簡單的程式碼示例,摘自 OllamaChatModelMultimodalIT.java,演示了使用者文字與影像的融合。

該示例展示了一個模型以 multimodal.test.png 影像作為輸入

以及文字訊息“解釋您在這張圖片上看到了什麼?”,並生成如下響應

結構化輸出

Ollama 提供自定義的 結構化輸出 API,確保您的模型生成的響應嚴格符合您提供的 JSON Schema。除了現有的 Spring AI 模型無關的 結構化輸出轉換器 外,這些 API 提供了增強的控制和精度。

配置

String jsonSchema = """
        {
            "type": "object",
            "properties": {
                "steps": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "explanation": { "type": "string" },
                            "output": { "type": "string" }
                        },
                        "required": ["explanation", "output"],
                        "additionalProperties": false
                    }
                },
                "final_answer": { "type": "string" }
            },
            "required": ["steps", "final_answer"],
            "additionalProperties": false
        }
        """;

Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
        OllamaOptions.builder()
            .model(OllamaModel.LLAMA3_2.getName())
            .format(new ObjectMapper().readValue(jsonSchema, Map.class))
            .build());

ChatResponse response = this.ollamaChatModel.call(this.prompt);

Spring AI 允許您使用 OllamaOptions 構建器以程式設計方式配置響應格式。

使用聊天選項構建器

record MathReasoning(
    @JsonProperty(required = true, value = "steps") Steps steps,
    @JsonProperty(required = true, value = "final_answer") String finalAnswer) {

    record Steps(
        @JsonProperty(required = true, value = "items") Items[] items) {

        record Items(
            @JsonProperty(required = true, value = "explanation") String explanation,
            @JsonProperty(required = true, value = "output") String output) {
        }
    }
}

var outputConverter = new BeanOutputConverter<>(MathReasoning.class);

Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
        OllamaOptions.builder()
            .model(OllamaModel.LLAMA3_2.getName())
            .format(outputConverter.getJsonSchemaMap())
            .build());

ChatResponse response = this.ollamaChatModel.call(this.prompt);
String content = this.response.getResult().getOutput().getText();

MathReasoning mathReasoning = this.outputConverter.convert(this.content);
您可以使用 OllamaOptions 構建器以程式設計方式設定響應格式,如下所示

與 BeanOutputConverter 工具整合

您可以利用現有的 BeanOutputConverter 工具從您的領域物件自動生成 JSON Schema,然後將結構化響應轉換為特定領域的例項

Ollama OpenAI API compatibility

確保使用 @JsonProperty(required = true,…​) 註解來生成準確標記欄位為 required 的 schema。雖然這對 JSON Schema 是可選的,但建議使用它以使結構化響應正常工作。

OpenAI API 相容性

Ollama 相容 OpenAI API,您可以使用 Spring AI OpenAI 客戶端與 Ollama 通訊並使用工具。為此,您需要將 OpenAI 基礎 URL 配置為您的 Ollama 例項:spring.ai.openai.chat.base-url=https://:11434,並選擇其中一個 Ollama 模型:spring.ai.openai.chat.options.model=mistral

spring.ai.ollama.chat.options.model=hf.co/bartowski/gemma-2-2b-it-GGUF
spring.ai.ollama.init.pull-model-strategy=always

Ollama 可以直接訪問所有 GGUF Hugging Face 聊天模型。您可以透過名稱拉取這些模型中的任何一個:ollama pull hf.co/<username>/<model-repository> 或配置自動拉取策略:自動拉取模型

spring.ai.ollama.chat.options.model:指定要使用的 Hugging Face GGUF 模型

spring.ai.ollama.init.pull-model-strategy=always:(可選)在啟動時啟用自動模型拉取。對於生產環境,您應該預下載模型以避免延遲:ollama pull hf.co/bartowski/gemma-2-2b-it-GGUF

spring:
  ai:
    ollama:
      base-url: https://:11434
      chat:
        options:
          model: mistral
          temperature: 0.7
示例 Controller

建立一個新的 Spring Boot 專案,並將 spring-ai-starter-model-ollama 新增到您的 pom(或 gradle)依賴項中。

@RestController
public class ChatController {

    private final OllamaChatModel chatModel;

    @Autowired
    public ChatController(OllamaChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/ai/generate")
    public Map<String,String> generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", this.chatModel.call(message));
    }

    @GetMapping("/ai/generateStream")
	public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return this.chatModel.stream(prompt);
    }

}

src/main/resources 目錄下新增一個 application.yaml 檔案,以啟用和配置 Ollama 聊天模型

base-url 替換為您的 Ollama 伺服器 URL。

這將建立一個 OllamaChatModel 實現,您可以將其注入到您的類中。這裡是一個簡單的 @RestController 類示例,它使用聊天模型進行文字生成。

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-ollama'
}
請參考依賴管理部分,將 Spring AI BOM 新增到您的構建檔案中。
手動配置

如果您不想使用 Spring Boot 自動配置,您可以在應用程式中手動配置 OllamaChatModelOllamaChatModel 實現了 ChatModelStreamingChatModel 介面,並使用低階 OllamaApi 客戶端連線到 Ollama 服務。

var ollamaApi = OllamaApi.builder().build();

var chatModel = OllamaChatModel.builder()
                    .ollamaApi(ollamaApi)
                    .defaultOptions(
                        OllamaOptions.builder()
                            .model(OllamaModel.MISTRAL)
                            .temperature(0.9)
                            .build())
                    .build();

ChatResponse response = this.chatModel.call(
    new Prompt("Generate the names of 5 famous pirates."));

// Or with streaming responses
Flux<ChatResponse> response = this.chatModel.stream(
    new Prompt("Generate the names of 5 famous pirates."));

要使用它,請將 spring-ai-ollama 依賴項新增到您的專案的 Maven pom.xml 或 Gradle build.gradle 構建檔案中

spring-ai-ollama 依賴項還提供了對 OllamaEmbeddingModel 的訪問。有關 OllamaEmbeddingModel 的更多資訊,請參閱Ollama 嵌入模型部分。

接下來,建立一個 OllamaChatModel 例項並使用它傳送文字生成請求

OllamaOptions 提供了所有聊天請求的配置資訊。

OllamaApi Chat Completion API Diagram
低階 OllamaApi 客戶端

OllamaApi 提供了一個輕量級的 Java 客戶端,用於訪問 Ollama 聊天補全 API Ollama 聊天補全 API

OllamaApi ollamaApi = new OllamaApi("YOUR_HOST:YOUR_PORT");

// Sync request
var request = ChatRequest.builder("orca-mini")
    .stream(false) // not streaming
    .messages(List.of(
            Message.builder(Role.SYSTEM)
                .content("You are a geography teacher. You are talking to a student.")
                .build(),
            Message.builder(Role.USER)
                .content("What is the capital of Bulgaria and what is the size? "
                        + "What is the national anthem?")
                .build()))
    .options(OllamaOptions.builder().temperature(0.9).build())
    .build();

ChatResponse response = this.ollamaApi.chat(this.request);

// Streaming request
var request2 = ChatRequest.builder("orca-mini")
    .ttream(true) // streaming
    .messages(List.of(Message.builder(Role.USER)
        .content("What is the capital of Bulgaria and what is the size? " + "What is the national anthem?")
        .build()))
    .options(OllamaOptions.builder().temperature(0.9).build().toMap())
    .build();

Flux<ChatResponse> streamingResponse = this.ollamaApi.streamingChat(this.request2);