GoodMemGoodMem
IntegrationsAgent Frameworks

LangChain

Write LangChain Documents to GoodMem, retrieve with metadata filters and optional reranking, and give agents a search tool.

Available (0.2)· Python (3.10+)

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.