langchain-coalent New in v0.6.1 is Coalent as a LangChain-native freshness/reuse
layer — BYO-first by construction: your existing LangChain vector store (or retriever),
embeddings, and chat model become the substrate of a provenance-invalidated SemanticCache.
Nothing about how you built them changes.
pip install langchain-coalent
It depends only on coalent>=0.6 and langchain-core>=0.3 — no langchain-community,
no langgraph.
1. create_coalent_cache — one call over your stack
from langchain_coalent import create_coalent_cache
cache = create_coalent_cache(
my_vectorstore, # any VectorStore or BaseRetriever — unchanged
llm=my_chat_model, # any BaseChatModel, used as YOU configured it
embeddings=my_embeddings, # any Embeddings — keys the cache semantically
# ...every Coalent knob passes through:
# hit_threshold=..., serve_budget=..., key_floor=..., preset="multi_hop", ...
)
Recommended defaults are applied only where you left the knob unset:
read_path="pool"— the v0.6 measured operating point — whenever you supplied a semantic embedder (embeddings=, or a non-hashing Coalentembedder=). Without one the factory stays on the unit read path rather than guess.pool_header— per-source attribution headers on the pool path (pass your own callable for[title | source | date]richness — the measured best recipe).- Behavioral knobs (
residual_spans,query_keys, ...) stay opt-in, exactly as in Coalent itself.
Knob passthrough is total. **knobs forwards every SemanticCache constructor argument
unchanged — the integration adds no allowlist between you and the library, so new library
knobs work in create_coalent_cache the day they ship.
Your chat model is invoked as you configured it — the synthesizer's
model / max_tokens / temperature are not forwarded (there is no portable kwarg contract
across LangChain chat integrations). Temperature 0 on your model is recommended for the
strict-JSON synthesis contract.
2. CoalentRetriever — the cache as a LangChain retriever
A drop-in BaseRetriever for any chain that takes a retriever:
from langchain_coalent import CoalentRetriever
retriever = CoalentRetriever(cache=cache)
docs = retriever.invoke("what is our leave policy?")
docs[0].page_content # the served, attributed context payload
docs[0].metadata["read_id"] # -> cache.report_refusal() / report_success()
docs[0].metadata["sources"] # artifact ids behind the read (provenance)
docs[0].metadata["cache_hit"] # True == served with zero LLM spend
include_evidence=True additionally returns the retained raw evidence chunks as separate
Documents.
3. CoalentVectorStoreRetriever — your index as Coalent's substrate
Used internally by the factory; also available directly:
from langchain_coalent import CoalentVectorStoreRetriever
retriever = CoalentVectorStoreRetriever(my_vectorstore, k=6) # a Coalent Retriever
Document → Chunk mapping: page_content → Chunk.text; the artifact id (what
cache.source_changed(...) keys on) resolves as metadata["artifact_id"] →
metadata["source"] → Document.id → metadata["id"] → a deterministic
chunk:<sha1(text)[:12]> fallback. Give your documents a source so invalidation has a
stable identity. metadata["version"] → Chunk.version; other metadata is not carried
(Coalent's Chunk has no metadata dict).
4. The refusal loop — LangGraph-shaped
When your answerer refuses over a served payload, that refusal is evidence — hand the
read_id back and Coalent serves the verbatim source excerpts the extraction missed, then
confirms the recovery as a durable alternate key:
retrieve ──> synthesize ──(refused?)──> report_refusal ──> re-synthesize ──> report_success
^ └─(answered)──> done └─(still refused)──> done
As nodes and one conditional edge:
def synthesize(state):
doc = state["docs"][0]
answer = my_llm.invoke(prompt(doc.page_content, state["question"]))
return {**state, "answer": answer, "read_id": doc.metadata["read_id"]}
def on_refusal(state):
retry = cache.report_refusal(state["read_id"]) # attributed spans, or None
if retry is None:
return state
answer = my_llm.invoke(prompt(state["context"] + "\n\n" + retry, state["question"]))
if not is_refusal(answer):
cache.report_success(state["read_id"]) # -> durable query key
return {**state, "answer": answer}
examples/refusal_loop.py in the package is the runnable, fully offline demonstration — a
plain conditional loop implementing the identical LangGraph pattern; its docstring shows the
1:1 StateGraph mapping (langgraph is deliberately not a dependency).
Freshness — the reason this exists
# Your ingestion pipeline noticed a document changed:
cache.source_changed("policy.md", text=new_text) # surgical, provenance-keyed
# The very next retrieval that touches it rebuilds; untouched knowledge stays warm.
Compatibility
Tested against langchain-core 1.x; written against the stable core contracts
(BaseRetriever._get_relevant_documents, VectorStore.similarity_search,
Embeddings.embed_query/embed_documents, BaseChatModel.invoke), which are unchanged from
0.3 — so langchain-core>=0.3 is supported.
Next
- Claude Code & MCP — the same cache behind the Model Context Protocol.
- Example — Agents & LangGraph —
make_cognition_nodeand the wider agent story. - Context intelligence — the pool read path and the behavioral stack.