How LangChain Implements Self Querying

Nov 16, 20234 min read

LangChain is a super popular open-source library for LLM orchestration. Recently, they added the “Self Query” retriever. The “Self Query” retriever allows you to use LangChain to query a vector database like Milvus. Let’s take a look at how this self-query retriever is implemented. We cover lines 189 to 233 of the base.py file in the self-query folder. This post also covers from_llm, the only class method.

In this post, we’ll cover:

  • The Self Query Class Method Definition
  • Parsing the Self-Query Parameters
  • Creating the LLM Chain
  • Returning a Self Query Retriever

Self query class method definition

The only class method for the self query base class is from_llm. There are eight specified parameters and one to allow us to pass keyword arguments (kwargs). You may notice that the first “parameter” of the class is cls. If you don't have formal training in Python, the difference between cls and self is simply a matter of style and usage, according to PEP8.

There are four required parameters for creating a self query class: llm, vectorstore, document_contents, and metadata_field_info.

  • llm is for passing a language model.
  • vectorstore is used to pass a vector store like Milvus.
  • The name of the document_contents parameter is a bit misleading. It doesn’t refer to the actual contents of the stored documents but rather a short description of them.
  • metadata_field_info is a sequence of AttributeInfo objects, dictionaries containing information about the data in the vector database.

After the required parameters come the optional parameters. There are four of them as well: structured_query_translator, chain_kwargs, enable_limit, and use_original_query. The first two default to None, and the second to False.

The structured_query_translator parameter lets us pass in a translator. Translators convert expressions into filter statements for each vector database. These filter statements get passed into chain_kwargs as “allowed_comparators” or “allowed_operators,” depending on their usage. Each vector store has unique comparators and operators. For example, these are the allowed boolean expressions for Milvus.

Using the enable_limit parameter, we can decide whether to enable the limit operator. This operator is a native feature of LangChain that restricts the number of documents to be retrieved. The final parameter is use_original_query, which determines whether we want to utilize our original query or the one generated by LLM.

       @classmethod
       def from_llm(
           cls,
           llm: BaseLanguageModel,
           vectorstore: VectorStore,
           document_contents: str,
           metadata_field_info: Sequence[Union[AttributeInfo, dict]],
           structured_query_translator: Optional[Visitor] = None,
           chain_kwargs: Optional[Dict] = None,
           enable_limit: bool = False,
           use_original_query: bool = False,
           **kwargs: Any,
       ) -> "SelfQueryRetriever":

Parsing the self query parameters

Let me explain how we handle the parameters. Based on the parameters passed in, we use a series of if statements to determine what to do.

First, we check if there is an already defined structured query translator. If not, we use the built-in translator for the defined vector store.

Next, we check the chain keyword arguments. We can set them to the values passed in or remain in an empty dictionary. We continue to check these arguments for the following two if statements. The two keys we look for are the allowed comparators and operators. These keys determine how we can write the filter expressions.

           if structured_query_translator is None:
               structured_query_translator = _get_builtin_translator(vectorstore)
           chain_kwargs = chain_kwargs or {}
           if (
               "allowed_comparators" not in chain_kwargs
               and structured_query_translator.allowed_comparators is not None
           ):
               chain_kwargs[
                   "allowed_comparators"
               ] = structured_query_translator.allowed_comparators
           if (
               "allowed_operators" not in chain_kwargs
               and structured_query_translator.allowed_operators is not None
           ):
               chain_kwargs[
                   "allowed_operators"
               ] = structured_query_translator.allowed_operators

Creating the LLM chain

With everything defined, we can now create our query constructor. In this step, we make a callout to the load_query_constructor_runnable function from query constructors. We’ll dive deeper into this step in another article.

We need to pass in the LLM, document content description, metadata fields, whether or not we want to enable the limit, and the keyword arguments to pass to the chain. After we have defined all these elements, the function returns a Runnable object, which allows us to execute a specified script.

           query_constructor = load_query_constructor_runnable(
               llm,
               document_contents,
               metadata_field_info,
               enable_limit=enable_limit,
               **chain_kwargs,
           )

Returning a self query retriever

At the end of this class method, we need to return the self query retriever. This method returns an instance of the self query class. We pass in the query constructor we just defined, along with the passed-in vector store, whether or not to use the original query, the translator, and a list of keyword arguments.

           return cls(
               query_constructor=query_constructor,
               vectorstore=vectorstore,
               use_original_query=use_original_query,
               structured_query_translator=structured_query_translator,
               **kwargs,
           )

Summary of how LangChain implements self querying

In this article, we’ve covered how LangChain implements a concept they label “self-querying.” It is a way to build a simple retrieval augmented generation (RAG) application. It uses all the same components: an LLM, a vector database, and some prompts to interface with the LLM.

Self querying is quite a large block of code in LangChain, but this article specifically covers the class method from_llm. This method allows us to create an RAG app by passing only four required fields. The LLM, the vector database, a description of the documents, and the metadata information. Want to learn more about LLMs and vector databases? Come chat with us on Discord.

Updated on Jul 09, 2026