LangChain
Write LangChain Documents to GoodMem, retrieve with metadata filters and optional reranking, and give agents a search tool.
The integration connects LangChain Documents and tools to GoodMem. GoodMem handles chunking, embedding and retrieval; an optional reranker improves ordering without requiring an LLM.
Upgrading from 0.1
Version 0.2 intentionally breaks compatibility with 0.1. See the migration notes for changed tool arguments and return values.
Install and configure
pip install --upgrade langchain-goodmem
export GOODMEM_BASE_URL="http://localhost:8080"
export GOODMEM_API_KEY="your-api-key"
export GOODMEM_SPACE_ID="your-space-uuid"Use a running GoodMem server and a space configured with an embedder.
GOODMEM_SPACE_ID is used by the examples below. Retrievers and tools accept explicit
space_ids or space_id arguments; they do not select a space automatically.
import os
from goodmem import Goodmem
from langchain_core.documents import Document
from langchain_goodmem import GoodMemRetriever, add_documents
client = Goodmem(
base_url=os.environ["GOODMEM_BASE_URL"],
api_key=os.environ["GOODMEM_API_KEY"],
)
space_id = os.environ["GOODMEM_SPACE_ID"]Keep a supplied SDK client open while components use it; close it when your application shuts
down. Without client=, retrievers and tools use GOODMEM_BASE_URL and GOODMEM_API_KEY and
manage their own connections. They also accept goodmem_base_url, goodmem_api_key,
goodmem_timeout, and goodmem_verify_ssl as constructor settings.
Write LangChain Documents
Pass Documents from a LangChain loader or splitter, or construct them directly:
memory_ids = add_documents(client, space_id, [
Document(
page_content="Project Cobalt's launch owner is Ada.",
metadata={
"source": "https://example.org/cobalt",
"title": "Cobalt launch",
"team": "blue",
},
),
Document(
page_content="Project Coral's launch owner is Sam.",
metadata={"source": "https://example.org/coral", "team": "red"},
),
])The helper uses the SDK batch API and preserves each Document's metadata. It returns memory
IDs and waits for indexing by default, so subsequent retrieval can find the new content.
The space's chunking configuration applies: one input Document may produce several retrieved
chunks. This is a document ingestion path, not a LangChain VectorStore implementation.
Optional Document.id values become GoodMem memory UUIDs; existing IDs produce conflicts.
For background ingestion, pass wait=False and call wait_for_memory(client, memory_id) when
readiness matters. If a batch partly fails or indexing times out,
GoodMemIngestionError.created_memory_ids identifies known successful writes. They are not
rolled back or automatically retried.
Retrieve Documents with metadata filters
retriever = GoodMemRetriever(
client=client,
space_ids=[space_id],
k=5,
filter="CAST(val('$.team') AS TEXT) = 'blue'",
)
documents = retriever.invoke("Who owns the launch?", k=1)
for document in documents:
print(document.page_content, document.metadata["source"])filter is a GoodMem filter expression, applied on the
server to every configured space before vector retrieval and reranking. Omit it to search
all memories in those spaces. For string comparisons, cast val(...) to TEXT, as above:
val(...) returns JSON rather than a plain text value.
Each result is a LangChain Document containing chunk text and joined memory metadata.
Metadata includes memory_id, chunk_id, space_id, and the server's score; Document.id
is the chunk ID. Source information comes from stored metadata or the original content
reference, with the memory ID as a fallback.
The retriever works with LCEL, callbacks, batch, abatch, and ainvoke. Async currently uses
LangChain's thread executor with the synchronous SDK. Search runs once: an empty result is
returned immediately, and incomplete retrieval raises an exception.
Rerank without an LLM
reranked = GoodMemRetriever(
client=client,
space_ids=[space_id],
filter="CAST(val('$.team') AS TEXT) = 'blue'",
reranker_id="your-reranker-uuid",
fetch_k=20,
k=5,
)fetch_k controls vector candidates; k limits the returned Documents. Reranking requires a
configured GoodMem reranker and does not require an LLM registration or a chat-model call.
Give an agent a search tool
Use LangChain's standard factory:
from langchain_core.tools import create_retriever_tool
search = create_retriever_tool(
retriever,
"search_project_records",
"Search project records for factual answers.",
response_format="content_and_artifact",
)Pass search to a LangChain agent or LangGraph ToolNode. The model supplies only the query;
spaces and filters remain configured by the developer. Retrieved Documents remain available
in ToolMessage.artifact for citation handling.
Other tools
The package also provides space and memory management tools.
GoodMemCreateSpace accepts a name, embedder ID, and optional labels; it creates a new space
using SDK chunking defaults. Select existing spaces explicitly or configure custom chunking
through the SDK before giving an agent access.
GoodMemRetrieveMemories exposes SDK retrieval events, preserving chunks, summaries, and
statuses together. Its inputs include message, a list of space_ids, requested_size,
reranker_id, max_results, and optional llm_id/llm_temp for summarization. Inspect status
events when using this lower-level tool. It does not classify results into success/partial.
Tools return SDK-shaped dictionaries or lists with snake_case fields. They use LangChain
ToolException handling; configure handle_tool_error when the agent should receive errors
as tool messages. There is no legacy JSON success envelope or empty-search polling.
See the package README and examples for development and validation commands. The integration runs LangChain's standard tool and retriever suites, including an opt-in live retriever suite.