Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions src/retrievers/csv_chroma.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,32 @@
from nltk.tokenize import word_tokenize
from pydantic import ConfigDict

chroma_settings = chromadb.config.Settings(anonymized_telemetry=False)

def chroma_settings() -> chromadb.config.Settings:
"""A *fresh* Settings object for every Chroma store.

Not a shared constant, which is what this was. `langchain_chroma` mutates
whatever it is handed:

client_settings.persist_directory = (
persist_directory or client_settings.persist_directory
)

so one shared instance means the last store constructed rewrites the
persist directory for every earlier one, and chromadb hands back a client
keyed on those settings. With only the reactome bundle installed nothing
showed, because every store pointed at the same tree. Installing the user
guide bundle gave them different trees, and a reactome question started
looking for its collection inside the user guide directory:

PermissionError: [Errno 13] Permission denied:
'/app/embeddings/.../userguide/Release95/sections/9c574827-...'

-- Chroma trying to create a segment folder for a collection that is not
there, in a bundle it should never have opened.
"""
return chromadb.config.Settings(anonymized_telemetry=False)


multi_query_prompt = PromptTemplate(
input_variables=["question"],
Expand Down Expand Up @@ -274,7 +299,7 @@ def from_subdirectory(
vectordb = Chroma(
persist_directory=str(embeddings_directory / subdirectory),
embedding_function=embedding,
client_settings=chroma_settings,
client_settings=chroma_settings(),
)
vector_retriever = vectordb.as_retriever(
search_kwargs={"k": RESULTS_PER_RETRIEVER * VECTOR_OVERFETCH}
Expand Down
2 changes: 1 addition & 1 deletion src/retrievers/userguide/retriever.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ def create_userguide_retriever(
vectordb = Chroma(
persist_directory=str(chroma_path),
embedding_function=embedding,
client_settings=chroma_settings,
client_settings=chroma_settings(),
)
return vectordb.as_retriever(search_kwargs={"k": k})
48 changes: 48 additions & 0 deletions tests/retrievers/test_chroma_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Each Chroma store needs its own Settings object.

`langchain_chroma` mutates whatever settings it is handed:

client_settings.persist_directory = (
persist_directory or client_settings.persist_directory
)

so a shared instance means the last store constructed rewrites the persist
directory for every earlier one, and chromadb returns a client keyed on those
settings.

With only the reactome bundle installed this was invisible -- every store
pointed into the same tree. Installing the user guide bundle gave them
different trees, and a *reactome* question went looking for its collection
inside the *user guide* directory:

PermissionError: [Errno 13] Permission denied:
'/app/embeddings/.../userguide/Release95/sections/9c574827-...'

Found on beta, in the deployed container, by asking "What does CDK5
phosphorylate in Alzheimer disease?" after a user guide question.
"""

from retrievers.csv_chroma import chroma_settings


def test_each_call_returns_a_distinct_object() -> None:
first, second = chroma_settings(), chroma_settings()
assert first is not second, (
"a shared Settings object is mutated by langchain_chroma, so two stores "
"would end up pointing at one directory"
)


def test_mutating_one_does_not_reach_another() -> None:
"""This is the exact mutation langchain_chroma performs."""
first = chroma_settings()
first.persist_directory = "/bundles/userguide/sections"

second = chroma_settings()
assert second.persist_directory != "/bundles/userguide/sections"


def test_telemetry_stays_off() -> None:
# The reason this object existed in the first place; do not lose it while
# fixing the sharing.
assert chroma_settings().anonymized_telemetry is False
Loading