# Spring AI 1.x → 2.0: complete breaking-change reference Compiled from the official upgrade notes and verified against `spring-ai-bom:2.0.0` on Spring Boot 4.1.0 / JDK 25. Items marked **[tested]** are asserted in [`ChatMemoryMigrationTest`](../src/test/java/com/ankurm/ai/ChatMemoryMigrationTest.java). --- ## 0. Platform — do this first, it gates everything | | 1.x | 2.0 | |---|---|---| | Spring Boot | 3.x | **4.x only** | | Jackson | 2 (`com.fasterxml.jackson`) | **3 (`tools.jackson`)** | | Java | 17 | 17 minimum, **21+ recommended** | **Spring AI 2.0 is built on the Boot 4 dependency model and cannot be loaded in a Boot 3 context.** There is no partial upgrade: you migrate Boot 3 → 4 first, or not at all. Spring AI is **not** managed by the Spring Boot BOM. Import its own: ```xml org.springframework.ai spring-ai-bom 2.0.0 pom import ``` The Jackson 2 → 3 move is the biggest hidden cost. It changes the default date format and property order, so anything that snapshot-tests JSON, or persists serialized model output, needs full integration testing rather than a compile check. ## 1. Artifact and module changes | Change | Action | |---|---| | `spring-ai-core` ended at `1.0.0-M6` | The project is split into focused modules — `spring-ai-model`, `spring-ai-client-chat`, etc. Depend on what you use. | | `spring-ai-advisors-vector-store` → **`spring-ai-vector-store-advisor`** | Rename the dependency. | | `spring-ai-spring-cloud-bindings` **removed** | Configure credentials with normal Boot property sources. | | MCP transports `mcp-spring-webflux` / `mcp-spring-webmvc` moved out of the MCP Java SDK **into Spring AI** | Update coordinates; they are now Spring AI artifacts. | | OCI GenAI **removed** from the main repository | Migrate to the separate OCI GenAI integration repo. | | Minimax dedicated support **removed** | Use the Anthropic support, per Minimax's own recommendation. Minimax **embeddings are no longer supported at all.** | ## 2. Options: setters are gone, builders only Every `setX(...)` on options classes is deprecated or removed: ```java // Before OpenAiChatOptions options = new OpenAiChatOptions(); options.setTemperature(0.7); // no longer compiles // After OpenAiChatOptions options = OpenAiChatOptions.builder() .temperature(0.7) .build(); ``` Two more renames in the same area: - `N()` → **`n()`** in `*Options` builders and configuration properties, to match Java conventions. - `spring.ai.ollama.chat.think-option` → **`spring.ai.ollama.chat.think`**. `ChatClient` no longer accepts a pre-built `ChatOptions` instance. Use the builder lambda form. ## 3. Configuration properties - **The `.options` prefix is gone** for every non-chat model type — embedding, image, audio, moderation, OCR. `spring.ai.openai.embedding.options.model` becomes `spring.ai.openai.embedding.model`. - Default values are **no longer duplicated** in `*Properties` classes; they live at the options level. If you were reading a default off a `*Properties` bean, it may now be `null`. - `spring.ai..chat.internal-tool-execution-enabled` — **removed** (see §4). - The `streamToolCallResponses` properties on the tool-calling advisors — **removed** (see §4). ## 4. Tool calling — the largest semantic change **`internalToolExecutionEnabled` has been removed** from `ToolCallingChatOptions` and every provider-specific options class. - `.internalToolExecutionEnabled(false)` no longer compiles. - `.internalToolExecutionEnabled(true)` no longer compiles **and the behaviour it named no longer exists** — per-model internal tool execution has been removed from all `ChatModel` implementations. This is not a rename. If you relied on the model driving the tool-call loop itself, that loop is gone and the orchestration moves up into the advisor layer. Also removed: - **`streamToolCallResponses`** from `ToolCallingAdvisor.Builder`, `ToolCallAdvisor.Builder` and `ToolSearchToolCallingAdvisor.Builder`. The upgrade notes are unusually direct about why: the design flaw behind it could not be fixed without a breaking change to `ChatClientResponse`, so the option was removed outright rather than patched. - **`SpringBeanToolCallbackResolver`**, and with it the whole pattern of declaring bare `Function` / `Supplier` / `Consumer` beans and referencing them by name. - **`toolNames()`** from all chat options classes and from `ChatClient`. Migrate name-based tool wiring to explicit `ToolCallback` instances. ## 5. Chat memory — **[tested]** Three changes that interact, and the reason this repository exists: | Change | Effect | |---|---| | `ChatMemory.DEFAULT_CONVERSATION_ID` **removed** | no more implicit `"default"` conversation | | Conversation ID **no longer optional** for `MessageChatMemoryAdvisor` / `VectorStoreChatMemoryAdvisor` | must be supplied per request | | `.conversationId(String)` **removed** from those builders | cannot be set at construction time | | `PromptChatMemoryAdvisor` **removed** | use `MessageChatMemoryAdvisor` | ```java // After — the id is a per-request advisor param client.prompt() .user("what is my name?") .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-42")) .call() .content(); ``` > **Do not "fix" the compile error by reaching for `ChatMemory.CONVERSATION_ID` as a value.** > `CONVERSATION_ID` survives, but it is the *metadata key* used to pass an id. The removed > `DEFAULT_CONVERSATION_ID` was the *value* `"default"`. Same prefix, opposite meaning — and > substituting one for the other restores exactly the shared-conversation behaviour that removing it > was meant to take away. **What actually changed.** Explicit per-request conversation IDs are not new — they were introduced during the 1.x line and were already the recommended approach. 2.0 removes the *alternatives*: the default-ID constant and the builder-based configuration path. The explicit per-request form is now the only way to do it, which makes it the migration target. That matters because the default-ID path was easy to lean on. Omitting the id in 1.x compiled and ran, with everything landing in a single shared `"default"` conversation — fine for a demo, wrong for anything multi-user. Removing the fallback converts "I forgot" from silent behaviour into a compile error. The test suite asserts that two conversation IDs cannot see each other. `PromptChatMemoryAdvisor` → `MessageChatMemoryAdvisor` is also not cosmetic: the removed advisor injected history into the **system prompt as text**, the replacement adds **real `Message` objects**. Providers treat those differently, so expect prompt shape and token counts to change. ### Chat memory repositories Messages read from a `ChatMemoryRepository` (JDBC, Cassandra, MongoDB, Neo4j, Redis) now carry a **creation timestamp in metadata**. Consequence: a retrieved message is **not** `equals()` to an otherwise-identical message constructed in code. Anything comparing messages by value, or keying a `Set`/`Map` on them, changes behaviour. ## 6. Structured output / `BeanOutputConverter` - Kotlin properties optional in their primary constructor (nullable or defaulted) are **no longer** in the JSON Schema `required` array. - Properties annotated `@JsonProperty(required = false)` — **including** `@JsonProperty` without an explicit `required` — are no longer treated as required. - **`BeanOutputConverter.postProcessSchema(JsonNode)` removed.** Subclasses overriding it will not compile. The first two change the schema you send to the model, which can change model behaviour without any error. If you rely on the model populating a field, mark it required explicitly. ## 7. `ModelOptionsUtils` and MCP - Several `ModelOptionsUtils` members are **removed**, because model options no longer depend on Jackson directly. - MCP `elicit(…)` overloads on `McpAsyncRequestContext` / `McpSyncRequestContext` that took `tools.jackson.core.type.TypeReference` now take **`org.springframework.core.ParameterizedTypeReference`**. ## 8. Migration order that works 1. **Boot 3 → Boot 4** on its own, with Spring AI still on 1.1.x. Land it. 2. Bump the Spring AI BOM to 2.0.0 and fix compile errors: options builders, `toolNames()`, `internalToolExecutionEnabled`, module renames. 3. Fix chat memory — every advisor call site needs a conversation ID. Grep for `DEFAULT_CONVERSATION_ID` and for advisor construction. 4. Re-test structured output against the real model. Schema changes are silent. 5. Integration-test anything that serializes: Jackson 3 changes date format and property order. Steps 4 and 5 are the ones that do not announce themselves. Everything before them is a compiler error, which is the easy kind of breakage.