Skip to content

Conversation

@sharrajesh
Copy link

Intent

Upgrade langchain-elasticsearch to support LangChain 1.x (released October 2025)
while maintaining backward compatibility with LangChain 0.3.x. This unblocks
downstream projects (like aiq_llm_apps) from upgrading to the latest LangChain
ecosystem.


Changes Made

  1. pyproject.toml

| Change | From | To | Why
|
|----------------------|-----------------|----------------|------------------------
-------------------------------------------------|
| Version bump | 0.4.0 | 0.5.0 | Semantic versioning -
breaking change due to Python version requirement |
| Python version | >=3.9,<4.0 | >=3.10,<4.0 | LangChain 1.x requires
Python 3.10+ (Python 3.9 EOL Oct 2025) |
| langchain (test dep) | >=0.3.10,<1.0.0 | >=1.0.0,<2.0.0 | Enable testing against
LangChain 1.x |
| pytest-asyncio | ^0.21.1 | ^0.23.0 | Compatibility with
Python 3.10+ and newer pytest |

Note: langchain-core = ">=0.3.0,<2.0.0" was already compatible - no change needed.


  1. Test Fixes (4 files)

Files:

  • tests/unit_tests/_sync/test_cache.py
  • tests/unit_tests/_async/test_cache.py
  • tests/integration_tests/_sync/test_cache.py
  • tests/integration_tests/_async/test_cache.py

Problem: Tests imported from langchain.embeddings.cache import _value_serializer -
this private module was reorganized in LangChain 1.x and no longer exists at that
path.

Solution: Replaced the import with a local implementation:
import json
from typing import List

def _value_serializer(value: List[float]) -> bytes:
"""Serialize embedding values to bytes (replaces private langchain
function)."""
return json.dumps(value).encode()

Why this approach:

  • _value_serializer is a private function (underscore prefix) - not part of public API
  • The implementation is trivial (json.dumps(value).encode())
  • Avoids dependency on internal LangChain implementation details
  • More robust against future LangChain changes

  1. Import Path Fix (integration tests)

Change: from langchain.globals import set_llm_cache → from langchain_core.globals
import set_llm_cache

Why: langchain_core is the direct dependency of this package. Using
langchain.globals would require the full langchain package at runtime, but
langchain is only a test dependency. The langchain_core.globals path is the
canonical location.


  1. Async Client Cleanup Fixture (async integration test)

Added: _close_async_caches autouse fixture in
tests/integration_tests/_async/test_cache.py

Why: Ensures async Elasticsearch clients are properly closed after tests, avoiding
aiohttp "Unclosed client session" warnings. This is a best practice for async tests
using aiohttp-based clients.


What Didn't Need Changes

The source code in langchain_elasticsearch/ was already compatible with LangChain
1.x because it uses stable langchain_core APIs:

  • langchain_core.documents.Document
  • langchain_core.embeddings.Embeddings
  • langchain_core.vectorstores.VectorStore
  • langchain_core.retrievers.BaseRetriever
  • langchain_core.caches.BaseCache
  • langchain_core.stores.ByteStore

Gotchas Found

  1. Private API dependency in tests: The original tests depended on langchain.embeddings.cache._value_serializer, a private function. LangChain 1.x reorganized internal modules, breaking this import. Lesson: Avoid importing private APIs (underscore-prefixed) even in tests.
  2. langchain vs langchain_core imports: Integration tests were importing from langchain.globals but langchain is only a test dependency. The correct import path is langchain_core.globals since that's the actual dependency.
  3. Async client cleanup: Async Elasticsearch tests can leave unclosed aiohttp sessions if not properly cleaned up, causing warnings during test runs.
  4. Python 3.9 EOL: LangChain 1.x dropped Python 3.9 support. This is a breaking change for any users still on Python 3.9.

Test Results

======================== 69 passed, 4 warnings in 0.13s ========================

The 4 warnings are expected deprecation notices for legacy retrieval strategy
classes (ApproxRetrievalStrategy → DenseVectorStrategy, etc.) which are still
functional.


Breaking Changes for Users

  • Python 3.9 no longer supported - users must upgrade to Python 3.10+

  Intent

  Upgrade langchain-elasticsearch to support LangChain 1.x (released October 2025)
  while maintaining backward compatibility with LangChain 0.3.x. This unblocks
  downstream projects (like aiq_llm_apps) from upgrading to the latest LangChain
  ecosystem.

  ---
  Changes Made

  1. pyproject.toml

  | Change               | From            | To             | Why
                                                   |
  |----------------------|-----------------|----------------|------------------------
  -------------------------------------------------|
  | Version bump         | 0.4.0           | 0.5.0          | Semantic versioning -
  breaking change due to Python version requirement |
  | Python version       | >=3.9,<4.0      | >=3.10,<4.0    | LangChain 1.x requires
  Python 3.10+ (Python 3.9 EOL Oct 2025)           |
  | langchain (test dep) | >=0.3.10,<1.0.0 | >=1.0.0,<2.0.0 | Enable testing against
  LangChain 1.x                                    |
  | pytest-asyncio       | ^0.21.1         | ^0.23.0        | Compatibility with
  Python 3.10+ and newer pytest                        |

  Note: langchain-core = ">=0.3.0,<2.0.0" was already compatible - no change needed.

  ---
  2. Test Fixes (4 files)

  Files:
  - tests/unit_tests/_sync/test_cache.py
  - tests/unit_tests/_async/test_cache.py
  - tests/integration_tests/_sync/test_cache.py
  - tests/integration_tests/_async/test_cache.py

  Problem: Tests imported from langchain.embeddings.cache import _value_serializer -
  this private module was reorganized in LangChain 1.x and no longer exists at that
  path.

  Solution: Replaced the import with a local implementation:
  import json
  from typing import List

  def _value_serializer(value: List[float]) -> bytes:
      """Serialize embedding values to bytes (replaces private langchain
  function)."""
      return json.dumps(value).encode()

  Why this approach:
  - _value_serializer is a private function (underscore prefix) - not part of public
  API
  - The implementation is trivial (json.dumps(value).encode())
  - Avoids dependency on internal LangChain implementation details
  - More robust against future LangChain changes

  ---
  3. Import Path Fix (integration tests)

  Change: from langchain.globals import set_llm_cache → from langchain_core.globals
  import set_llm_cache

  Why: langchain_core is the direct dependency of this package. Using
  langchain.globals would require the full langchain package at runtime, but
  langchain is only a test dependency. The langchain_core.globals path is the
  canonical location.

  ---
  4. Async Client Cleanup Fixture (async integration test)

  Added: _close_async_caches autouse fixture in
  tests/integration_tests/_async/test_cache.py

  Why: Ensures async Elasticsearch clients are properly closed after tests, avoiding
  aiohttp "Unclosed client session" warnings. This is a best practice for async tests
   using aiohttp-based clients.

  ---
  What Didn't Need Changes

  The source code in langchain_elasticsearch/ was already compatible with LangChain
  1.x because it uses stable langchain_core APIs:
  - langchain_core.documents.Document
  - langchain_core.embeddings.Embeddings
  - langchain_core.vectorstores.VectorStore
  - langchain_core.retrievers.BaseRetriever
  - langchain_core.caches.BaseCache
  - langchain_core.stores.ByteStore

  ---
  Gotchas Found

  1. Private API dependency in tests: The original tests depended on
  langchain.embeddings.cache._value_serializer, a private function. LangChain 1.x
  reorganized internal modules, breaking this import. Lesson: Avoid importing private
   APIs (underscore-prefixed) even in tests.
  2. langchain vs langchain_core imports: Integration tests were importing from
  langchain.globals but langchain is only a test dependency. The correct import path
  is langchain_core.globals since that's the actual dependency.
  3. Async client cleanup: Async Elasticsearch tests can leave unclosed aiohttp
  sessions if not properly cleaned up, causing warnings during test runs.
  4. Python 3.9 EOL: LangChain 1.x dropped Python 3.9 support. This is a breaking
  change for any users still on Python 3.9.

  ---
  Test Results

  ======================== 69 passed, 4 warnings in 0.13s ========================

  The 4 warnings are expected deprecation notices for legacy retrieval strategy
  classes (ApproxRetrievalStrategy → DenseVectorStrategy, etc.) which are still
  functional.

  ---
  Breaking Changes for Users

  - Python 3.9 no longer supported - users must upgrade to Python 3.10+

  ---
sharrajesh and others added 4 commits November 28, 2025 16:58
Updated elasticsearch version constraint to support elasticsearch 9.x
while maintaining backwards compatibility with 8.x.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@demetere
Copy link

demetere commented Dec 2, 2025

Any timelines for this PR?

@rvargas42
Copy link

Please update this PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants