LangChain4j 1.19 Switches to Stateless Streamable HTTP and Adds Hybrid Milvus Search
LangChain4j 1.19 drops SSE support in favor of a stateless Streamable HTTP protocol, introduces a Milvus‑v2 module that combines dense vector similarity with BM25 keyword matching for hybrid retrieval, and bundles dozens of bug fixes and new integrations across agents, HTTP clients, vector stores, and document parsers.
MCP SSE Retirement and Stateless Streamable HTTP
Version 1.19 removes the old HTTP+SSE transport from the MCP client, making the server communicate exclusively via the new Streamable HTTP protocol. The previous SSE approach required a GET endpoint for a long‑lived connection and a separate POST endpoint for messages, which caused complications for gateways, load balancers, and WAFs. The new protocol eliminates the session‑based GET stream endpoint, deletes protocol‑level sessions, and requires callers to pass an explicit handle parameter when state must be preserved across calls.
Hybrid Search Support via Milvus‑v2
The release adds a Milvus‑v2 module that implements the hybrid search pattern described by Milvus as “混合检索”. It runs dense vector similarity for semantic matching and BM25 for keyword matching, then fuses the two result sets for final ranking. The builder example below shows how to enable hybrid search, set the ranker to RRF with k=60, and select BM25 as the sparse mode.
EmbeddingStore<TextSegment> store = MilvusV2EmbeddingStore.builder()
.host("localhost")
.port(19530)
.collectionName("my_collection")
.dimension(768)
.searchMode(SearchMode.HYBRID) // enable hybrid search
.ranker(MilvusV2Ranker.rrf(60)) // RRF ranking, k=60
.sparseMode(MilvusSparseMode.BM25) // use Milvus built‑in BM25 for sparse vectors
.build();
Embedding queryEmbedding = embeddingModel.embed(query).content();
MilvusV2EmbeddingSearchRequest request = MilvusV2EmbeddingSearchRequest.milvusBuilder()
.queryEmbedding(queryEmbedding) // semantic vector
.query(query) // keyword, server runs BM25 automatically
.maxResults(10)
.build();
EmbeddingSearchResult<TextSegment> result = store.search(request);During a search, the query supplies both a dense vector (semantic) and a plain text query (keyword). The dense vector captures meaning, while the keyword component ensures exact term coverage.
Other Notable Changes (5 items)
Added AnthropicBatchChatModel to support Anthropic’s Message Batches API.
Agentic tool‑action compensation introduced for more reliable tool execution.
Exposed tool execution metadata via ToolExecutionResult.attributes() and the _meta field.
Added watsonx.ai model gateway support and a dedicated deployment chat model.
Google‑genai module now supports a “thinking” capability.
Vector Database Improvements
CassandraEmbeddingStore now respects the configured similarity metric instead of hard‑coding COSINE.
CassandraEmbeddingStore stops double‑normalising relevance scores.
ChromaEmbeddingStore validates that ids, embeddings, and textSegments have matching sizes.
ElasticsearchContentRetriever default maxResults changed to 3 to align with documentation.
Pinecone fixes metadata handling for retained text keys.
Agent & AI Services Enhancements
Parallel agent failures now throw AgentInvocationException instead of a generic RuntimeException.
Agentic proxies support equals for proper identity checks.
Empty input to parallel mapper agents returns an empty collection.
Asynchronous agents returning null no longer cause NPEs.
AgenticScope deserialization restricts to known registered classes.
HTTP Client and Network Adjustments
ApacheHttpClient disables automatic retry by default.
Fixed mapping of connectTimeout to the actual connection‑establishment timeout.
OkHttp streaming paths no longer consume the response body.
Utility Utils.readBytes now decodes gzip/deflate responses.
SSE error bodies are read as UTF‑8 without re‑assembling line separators.
Document Parsing and Loading
Added a builder and configurable text extraction to DoclingDocumentParser.
Metadata key conflicts and skipped documents are now visible during loading.
Miscellaneous Fixes
Masked sensitive AWS authentication headers. Utils.merge made null‑safe, never returns null.
Dynamic tool refresh avoids NoSuchElementException when user messages are evicted. LanguageModelQueryRouter no longer NPEs on unknown retriever IDs.
OnnxScoringBertCrossEncoder now supports 3‑D logit output.
Various serialization, null‑handling, and builder‑copy issues were resolved across the codebase.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
