Spring AI 2.1.0-M1 Available Now

TL;DR · AI 摘要
Title: Spring AI 2.1.0-M1 Available Now URL Source: Markdown Content: On behalf of the Spring AI team and everyone who h...
核心要点
- 主题聚焦:Spring AI 2.1.0-M1 Available Now
- 来源:Spring Blog,建议结合原文判断细节。
- AI 分析暂不可用,本条为保底评分与摘要。

On behalf of the Spring AI team and everyone who has contributed, I'm happy to announce that Spring AI 2.1.0-M1 has been released and is now available from Maven Central!
Release notes | Upgrade notes | Reference documentation
2.1.0-M1 is the first milestone of the 2.1 line. It builds on everything that shipped in 2.0.1, moves the baseline to Spring Boot 4.2 (this milestone is built against 4.2.0-M2), and introduces three new capabilities: initial support for a structured, ordered model for message content, support for the OpenAI Responses API, and a way to write pre-computed embeddings into a vector store.
As with any milestone, the new APIs are ready to try but may still change before GA. Your feedback now is what shapes them.
New in this release
Message Parts
Until now, a Spring AI message was a text plus side lists of tool calls and media. That shape cannot represent what current models actually return: reasoning interleaved with tool calls, text between images, or provider-specific blocks that must be sent back verbatim on the next turn.
AssistantMessage, UserMessage, and ToolResponseMessage now hold their content as an ordered list of `MessagePart` entries: TextPart, ReasoningPart, ToolCallPart, ToolResultPart, MediaPart, and UnknownPart. Parts keep the order the provider produced them in, so a conversation round-trips faithfully. A ReasoningPart or ToolCallPart can carry an OpaquePayload, which holds data such as an Anthropic thinking signature or a Gemini thought signature that has to be replayed unchanged. UnknownPart keeps the raw JSON of any block an adapter does not model yet, so nothing is silently dropped.
The familiar accessors (getText(), getMedia(), getToolCalls(), and the new getReasoning()) are now views over the parts, and existing constructors and builders keep producing them in the legacy order. To control the order yourself, add parts directly:
UserMessage question = UserMessage.builder()
.part(TextPart.of("What changed between these two charts?"))
.part(MediaPart.of(firstChart))
.part(MediaPart.of(secondChart))
.build();
AssistantMessage answer = chatModel.call(new Prompt(question)).getResult().getOutput();
for (ReasoningPart reasoning : answer.getReasoning()) {
System.out.println("Reasoning: " + reasoning.text());
}
System.out.println(answer.getText());Streaming models can now deliver a part in increments: chunks carry indexed partial parts and a response id, and MessageAggregator rebuilds the complete parts from them. Subscribers that only read getText() see the same text deltas as before, and tool calls are still buffered and delivered once as a complete call. See the Message Parts section of the reference documentation.
This is initial message part support: only the new
OpenAiResponsesChatModelproduces and consumes parts natively. The otherChatModelimplementations will be refactored to use them in 2.1.0-RC1.
OpenAI Responses API
The new OpenAiResponsesChatModeltalks to OpenAI's `/v1/responses` endpoint, alongside the existing Chat Completions-based OpenAiChatModel. The main reason to use it is correctness: starting with GPT-5.4, Chat Completions does not support tool calling combined with a reasoning effort other than none, while Responses does. If you are building an agent on a current OpenAI flagship model, this is the endpoint to use.
Switching is a single property, and the rest of the spring.ai.openai connection settings stay where they are:
# chat-completions (default) | responses
spring.ai.openai.chat.api=responsesThe model is built on message parts. Each item in a Responses reply becomes one part, in order, and the encrypted reasoning content is carried in a ReasoningPart and handed back verbatim across tool calls, so the model keeps its train of thought through a tool loop. OpenAiResponsesChatModel is deliberately stateless: every call sends the whole Prompt, so ChatMemory, advisors, and RAG work exactly as they do with OpenAiChatModel.
OpenAiResponsesChatOptions exposes reasoning effort and reasoning summaries, verbosity, structured output, and image and PDF input. HostedTool enables the tools OpenAI runs on its side: web search, file search, code interpreter, remote MCP, and image generation. Observability and auto-configuration are included. The OpenAI Responses reference page covers the configuration properties and when to pick which endpoint.
Chat memory repositories do not persist message parts yet, so only
InMemoryChatMemoryRepositorypreserves reasoning across conversation turns. The conversation still works with the others, but the model reasons from scratch on each turn. Persistent repository support is planned for 2.1.0-RC1.
Writing pre-computed Embeddings
VectorStore.add() always computes embeddings using the store's own embedding model. Sometimes you already have the vectors: a provider's batch API computed them overnight at a discount, another team owns the embedding pipeline, a multimodal model embedded an image, or you are migrating from a system that exports text and vectors together.
The new `VectorStore.upsert()` takes an EmbeddedDocument, pairing a Document with its float[] vector, and stores the vector as given:
float[] embedding = ...; // computed elsewhere
Document document = new Document("8f14e45f-ceea-467a-9a3e-5b1c2d6f7a90", "some text",
Map.of("source", "manual"));
vectorStore.upsert(List.of(new EmbeddedDocument(document, embedding)));As the name says, writing the same id again replaces the row, so an ingestion job with stable ids can be re-run safely after a failure. Every batch is checked against the index width before anything is written. pgvector, Redis, Elasticsearch, and Qdrant support upsert in this milestone; other stores throw until they opt in. A new DocumentMetadata.CONTENT_REF key lets you point to content kept outside the store, for rows whose vector came from an image or a file too large to inline. See Writing User-Supplied Embeddings.
Smaller additions
- Stateless MCP servers can now be tuned with `McpStatelessSyncServerCustomizer` and `McpStatelessAsyncServerCustomizer` beans, mirroring the customizers the stateful servers already had. Previously, you had to exclude and re-declare the whole server bean.
- The Redis vector store auto-configuration accepts custom metadata fields contributed as a bean.
- The vector store filter parser parses out-of-range integer literals as `Long` instead of failing with a
NumberFormatException.
Fixes
spring.ai.openai.timeoutandspring.ai.openai.chat.timeoutare honored again. Since 2.0.1, every request carried a 60-second per-call timeout that overrode the configured value, which aborted streaming turns longer than a minute withOpenAIIoException: Stream failed.- OpenAI strict mode tool schemas are backfilled with `additionalProperties: false` at every object level. This fixes strict mode for schemas that do not come from Spring AI's own generator, such as MCP tool schemas or hand-written input schemas.
- Bedrock user messages that carry media but no text no longer send an empty text block, which the Converse API rejected with a 400 error.
TextReadercloses the resource stream it reads from, instead of leaking a file descriptor per document.InMemoryChatMemoryRepositorycopies the message list on save, so later changes to the caller's list no longer alter the stored conversation.MariaDBVectorStoreschema validation works when no schema name is configured, rather than reporting an existing table as missing from schemanull.- Empty OpenAI image responses are reported as a failed generation instead of an unrelated exception.
Documentation, dependencies, and build
The MCP client documentation gained a section on client scope and session boundaries (what the auto-configured beans share, and how to get per-user isolation when you need it), and the guidance on MCP and local tool name collisions was refined. The OpenAI reasoning effort property is now documented.
Spring AI now tracks Spring Boot 4.2, and the Anthropic Java SDK moves to 2.64.0. The build is now configured for reproducible builds, and tests that assumed Unix line endings were fixed so the project builds on Windows.
Contributors
Thank you to everyone who worked on this release:
@CryoThrust, @JamesBLewis, @Lubaoshuai, @chabinhwang, @chensishang, @dimitarproynov, @dlwldn30, @fatan, @herder, @ilayaperumalg, @jhpark1227, @kezhenxu94, @martin-grofcik, @pengmoubuaixuexi, @sdeleuze, @sobychacko, and @tzolov
- [Spring AI TypeSafe Jev](https://github.com/spring-ai-community/spring-ai-typesafe) 0.2.0 follows up on this week's introduction of fast, structured decisions with TypeSafe Jev. The model-as-a-judge gains code criteria, typed input, conditional criteria and self-refine fixes, and an experimental
JevChatModel. See the reference documentation. - [MCP Security](https://github.com/spring-ai-community/mcp-security)[0.1.14](https://github.com/spring-ai-community/mcp-security/releases/tag/v0.1.14) hardens MCP servers with Origin header validation, a
401response for a missing API key, and issuer URL validation in the CIMD flow. - [Spring AI Agent Utils](https://github.com/spring-ai-community/spring-ai-agent-utils) shipped two releases. 0.11.0 adds Auto-Dream memory consolidation with cross-session recall. 0.12.0 adds a pluggable
ExecBackendwith a Docker backend for sandboxed command execution, aWorkspaceabstraction, directory confinement for the search tools, andInterruptAdvisorandToolCallListenerfor controlling the agent loop. - [Spring AI Session](https://github.com/spring-ai-community/spring-ai-session)0.7.0 and 0.8.0 make
appendEventidempotent, add keyword and pattern search across sessions throughCrossSessionRecallTools, and stop duplicated prompt history when the memory advisor runs inside a tool-calling loop. - [Spring AI AgentCore](https://github.com/spring-ai-community/spring-ai-agentcore) 2.2.0 adds Spring AI Session API support for AgentCore memory and AgentCore identity.
What's next
Work on 2.1.0-RC1 has started. Message parts are the foundation for most of it:
- Spring AI Agents. We plan to release the new agentic support in Novembe 2026 as a separate project under Spring Projects Experimental, with the plan to merge it into Spring AI 3.0 mid next year.
- Message parts across all providers. We will refactor the existing
ChatModelimplementations to produce and consumeMessagePartcontent natively, while preserving backward compatibility for code that uses the current accessors. - Session management in core. We are bringing the key parts of Spring AI Session into Spring AI itself. Along with advanced conversation history management, compaction and recall, its
SessionRepositoryimplementations will persist the fullMessagePartstructure. Reasoning will then survive across conversation turns with persistent storage too, not only with the in-memory repository. - MCP 2026-07-28. Work on support for the MCP 2026-07-28 specification is in progress, both in the MCP Java SDK and in the Spring AI MCP abstractions and annotations built on top of it.
Get started
Try the milestone in an existing application, or start a new one on start.spring.io. The message parts model and the Responses API are exactly the kind of changes we want feedback on before GA — open an issue if something is broken, or start a discussion to tell us what you would like to see next.
Cheers!