LangChain#

pip install "needtoknow[langchain]"

A permission-aware LangChain retriever#

NeedToKnowRetriever is a LangChain BaseRetriever, so it works anywhere a retriever does: chains, agents and LangGraph tools.

from needtoknow import MetadataACLAuthorizer, PermissionedRetriever, Subject
from needtoknow.langchain import NeedToKnowRetriever

retriever = NeedToKnowRetriever(retriever=PermissionedRetriever(backend, MetadataACLAuthorizer()), k=4)

docs = retriever.invoke("What changed in Q3 pricing?", subject=Subject("bob", ["sales"]))

Pass the subject on each call, or bind one with for_subject, which returns a copy:

bobs_retriever = retriever.for_subject(Subject("bob", ["sales"]))
docs = bobs_retriever.invoke("What changed in Q3 pricing?")

A call with no subject raises ValueError instead of returning unfiltered results. Each returned Document carries the chunk’s metadata plus relevance_score. ainvoke uses aretrieve.

In an agent: bind the subject, do not expose it#

An agent’s tool arguments are chosen by the model. If the subject were one of them, a prompt could change whose documents are searched. Build the tool per session with the subject already bound:

from langchain_core.tools import tool


def tools_for(session):
    retriever = NeedToKnowRetriever(retriever=permissioned).for_subject(session.subject)

    @tool
    def search_documents(query: str) -> str:
        """Search the company documents the current user may read."""
        return "\n\n".join(doc.page_content for doc in retriever.invoke(query))

    return [search_documents]

Any LangChain vector store as a backend#

LangChainVectorStoreBackend goes the other way: it lets a LangChain VectorStore act as a needtoknow backend.

from needtoknow.langchain import LangChainVectorStoreBackend

backend = LangChainVectorStoreBackend(vectorstore, id_key="chunk_id")
retriever = PermissionedRetriever(backend, authorizer)  # post-filtered

Filter syntax differs from store to store, so this backend post-filters. Every document needs an id: Document.id, or the metadata field named by id_key. Scores follow the store’s ranking (1 / (1 + rank)), since stores disagree on what their raw scores mean. For pre-filtering, use a native backend such as pgvector or Chroma.