Langchain Part 12 — Retrievers
What are Retrievers
Langchain Part 12 — Retrievers
What are Retrievers
A Retriever is a component in a langchain that fetches relevant documents from a data source in response to a user’s query
All retrievers in Langchain are runnables

Retriever is like a function which takes user_query as input and gives multiple document objects relevan to the user query as output. It is like a search engine which gives us relevant results based on the user query
There are multiple types of retrievers
Types of Retrievers
We can divide retrievers in 2 categories
1. Classification by Data Source
These retrievers are specialized based on where the information lives.
- Vector Store-Based Retrievers: The most common type. They search through a vector database (like Chroma or Pinecone) where your documents have been converted into mathematical embeddings.
- Wikipedia Retriever: A specialized tool that connects directly to the Wikipedia API to fetch summaries or full articles in real-time.
- Arxiv Retriever: Designed for researchers, this fetches scholarly papers and pre-prints from the Arxiv physics and computer science repository.
2. Classification by Search Strategy
These retrievers depends on how the search is performed to obtain the relevant documents
Multi-Query Retrieval:
- The Logic: An LLM rewrites the user’s single query into 4–5 different versions.
- The Goal: It searches all versions simultaneously to ensure that even if the user used “slang,” the system finds the technical match.
Maximum Marginal Relevance (MMR):
- The Logic: Instead of just picking the top 5 most similar chunks, it picks chunks that are both relevant to the query and diverse from each other.
- The Goal: To prevent the AI from getting five chunks that all say the exact same thing, giving it a broader view of the topic.
Contextual Compression Retrieval:
- The Logic: It retrieves the relevant documents and then uses an LLM to “shrink” them, extracting only the specific sentences that answer the question.
- The Goal: To save tokens and remove unwanted information before passing the data to the final answering model.
Wikipedia Retriever
A Wikipedia Retriever is a retriever that queries the Wikipedia API to fetch relevant content for a given query.
How It Works
- You give it a query (e.g., “Albert Einstein”)
- It sends the query to Wikipedia’s API
- It retrieves the most relevant articles
- It returns them as Langchain
Documentobjects
Although it looks like a document loader, the Wikipedia Retriever only fetches the specific information you ask for. Instead of downloading all of Wikipedia upfront, it waits for your query and then pulls only the top k most relevant articles from the web in real-time. This keeps our system lightweight because it never stores a massive database; it simply grabs the best-matching chapters on the fly and converts them into a format the AI can read
from langchain_community.retrievers import WikipediaRetriever
# Initialize the retriever (optional: set language and top_k)
retriever = WikipediaRetriever(top_k_results=2, lang="en")
# Define your query
query = "the geopolitical history of india and pakistan from the perspective of a chinese"
# Get relevant Wikipedia documents
docs = retriever.invoke(query)
# Print retrieved content
for i, doc in enumerate(docs):
print(f"\n--- Result {i+1} ---")
print(f"Content:\n{doc.page_content}...") # truncate for display
Vector Store Retriever
A Vector Store Retriever in Langchain is the most common type of retriever that lets you search and fetch documents from a vector store based on semantic similarity using vector embeddings.
How It Works
- You store your documents in a vector store (like FAISS, Chroma, Weaviate) (Here a “document” almost always refers to a chunk of text rather than an entire book or file.)
- Each document is converted into a dense vector using an embedding model
- When the user enters a query:
- It’s also turned into a vector
- The retriever compares the query vector with the stored vectors
- It retrieves the top-k most similar ones
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
# Step 1: Your source documents
documents = [
Document(page_content="LangChain helps developers build LLM applications easily."),
Document(page_content="Chroma is a vector database optimized for LLM-based search."),
Document(page_content="Embeddings convert text into high-dimensional vectors."),
Document(page_content="OpenAI provides powerful embedding models."),
]
# Step 2: Initialize embedding model
embedding_model = OpenAIEmbeddings()
# Step 3: Create Chroma vector store in memory
vectorstore = Chroma.from_documents(
documents=documents,
embedding=embedding_model,
collection_name="my_collection"
)
# Step 4: Convert vectorstore into a retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# If I wish to change another search strategy for retrieval
# Fetches a larger pool of chunks (fetch_k) and picks the most diverse top 2 (k)
'''
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={'k': 2, 'fetch_k': 10}
)
'''
query = "What is Chroma used for?"
results = retriever.invoke(query)
for i, doc in enumerate(results):
print(f"\n--- Result {i+1} ---")
print(doc.page_content)
# Using vector store similarity_search to find the relevant documents
results = vectorstore.similarity_search(query, k=2)
for i, doc in enumerate(results):
print(f"\n--- Result {i+1} ---")
print(doc.page_content)
'''OUTPUT:
--- Result 1 ---
Chroma is a vector database optimized for LLM-based search.
--- Result 2 ---
LangChain helps developers build LLM applications easily.
--- Result 1 ---
Chroma is a vector database optimized for LLM-based search.
--- Result 2 ---
LangChain helps developers build LLM applications easily.
'''
As we can see from the above code, a Vector Store already does semantic search and gives us the documents most similar to the user query, then why do we need a Retriever for vector store?
- While a Vector Store is great for basic similarity searches, a Retriever acts as a powerful upgrade layer.
- Think of the Vector Store as the “storage unit” and the Retriever as the “smart assistant” who knows the best way to find what you need.
- A standard Vector Store only offers one basic search algorithm, but a Retriever allows you to apply advanced search strategies like MMR (for diversity) or Multi-Query (for better coverage) to get more accurate results.
- Additionally, because retrievers are built as Runnables, they are “plug-and-play” components that you can easily drop into a larger Langchain sequence or automated chain.
MMR (Maximal Marginal Relevance)
“How can we pick results that are not only relevant to the query but also different from each other?”
MMR is an information retrieval algorithm designed to reduce redundancy in the retrieved results while maintaining high relevance to the query.
Why MMR Retriever?
In regular similarity search, you may get documents that are:
- All very similar to each other
- Repeating the same info
- Lacking diverse perspectives
MMR Retriever avoids that by:
- Picking the most relevant document first
- Then picking the next most relevant and least similar to already selected docs
- And so on…
This helps especially in RAG pipelines where:
- You want your context window to contain diverse but still relevant information
- Especially useful when documents are semantically overlapping

Suppose, the user query is “what are the reasons of climate change?”. We have 5 documents in our vector store to help us with this query as shown in the above image.
If we use a retriever (without MMR) there are high chances it will give doc1, doc2 and doc3 as the most relevant documents for this query. But if we observe, doc1 and doc2 are talking about the same thing that is “Arctic glaciers melting”
Ideally it would have been better if the retriever gave us doc1, doc4, doc5 document objects. As these docs gives us a diverse perspective and reduce redundancy
And this is what exactly MMR helps with
from langchain_community.vectorstores import FAISS
# Sample documents
docs = [
Document(page_content="LangChain makes it easy to work with LLMs."),
Document(page_content="LangChain is used to build LLM based applications."),
Document(page_content="Chroma is used to store and search document embeddings."),
Document(page_content="Embeddings are vector representations of text."),
Document(page_content="MMR helps you get diverse results when doing similarity search."),
Document(page_content="LangChain supports Chroma, FAISS, Pinecone, and more."),
]
# Initialize OpenAI embeddings
embedding_model = OpenAIEmbeddings()
# Step 2: Create the FAISS vector store from documents
vectorstore = FAISS.from_documents(
documents=docs,
embedding=embedding_model
)
# Enable MMR in the retriever
retriever = vectorstore.as_retriever(
search_type="mmr", # <-- This enables MMR
search_kwargs={"k": 3, "lambda_mult": 0.5} # k = top results, lambda_mult = relevance-diversity balance (value ranges from 0 to 1), if value is 1 -> mmr acts as a similarity search, if value is 0, mmr gives us diverse results
)
query = "What is langchain?"
results = retriever.invoke(query)
for i, doc in enumerate(results):
print(f"\n--- Result {i+1} ---")
print(doc.page_content)
'''OUTPUT:
--- Result 1 ---
LangChain is used to build LLM based applications.
--- Result 2 ---
Embeddings are vector representations of text.
--- Result 3 ---
LangChain supports Chroma, FAISS, Pinecone, and more.
'''
Multi-query Retriever
Sometimes the user query can be ambiguous
For example: Query: “How can I stay healthy?”
This query could mean that the user is asking:
- What should he eat?
- How often should he exercise?
- How can he manage stress?
Given the user query, it is difficult to understand what the user actually wants
A simple similarity search might miss documents that talk about these questions but don’t use the word “healthy.”
How it works
- Takes your original query
- Uses an LLM (e.g., GPT-3.5) to generate multiple semantically different versions of that query
- Performs retrieval for each sub-query
- Combines and deduplicates the results

We first send the user query to the LLM.
The LLM now generates multiple queries from this user query like shown in the image above (lets say from the user query, 3 queries are generated by the LLM)
So all these 3 queries will then be sent to the retriever
Then, we will assume for now that we will get 3 documents from each of the retreivals.
Then we will merge all these 9 documents, and if any duplicates are found, we will delete those, and then display top5 or top3 results as per asked
If we have asked the retrieval to return us the top 5 documents relevant to our query, how will we filter out the top 5 documents from the top 9 documents which address different variations of the user query
When you use a Multi-Query Retriever, you run into a classic “too much of a good thing” problem: you have 9 high-quality, unique documents, but your LLM’s context window (or your specific k setting) only wants 5.
LangChain handles this selection through a process called Reciprocal Rank Fusion (RRF) or simple Ranking Aggregation. Here is how those final 5 are picked:
1. The Scoring System (Ranking)
The retriever doesn’t just look at the documents; it looks at where they appeared in the original search results.
- If a document was the #1 result for “What should I eat?”, it gets a very high score.
- If another document was only the #5 result for “How often should I exercise?”, it gets a much lower score.
2. Reciprocal Rank Fusion (RRF)
This is the “fairness” algorithm. It calculates a score for every document based on its position across all queries.
- A document that appeared as #2 for Query A and #3 for Query B will likely jump to the #1 overall spot because it proved to be relevant to multiple ways of asking the question.
- A document that only appeared once at the bottom of a list will likely be dropped.
3. The Final Cut
Once the RRF scores are calculated, the documents are sorted from highest to lowest.
- The retriever takes the Top 5 from this new, “fused” list.
- These 5 are the ones that the algorithm determines are the most “universally” relevant across all the different perspectives the LLM generated.
Summary of the Selection Flow:
- Generate: 3 queries → 15 total documents.
- Deduplicate: Merge identical documents → 10 unique documents.
- Score: Assign points based on how high they ranked in their original searches.
- Sort: Rank the 10 documents based on their combined “fusion” score.
- Trim: Take only the Top 5 and send them to the LLM.
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
# Relevant health & wellness documents
all_docs = [
Document(page_content="Regular walking boosts heart health and can reduce symptoms of depression.", metadata={"source": "H1"}),
Document(page_content="Consuming leafy greens and fruits helps detox the body and improve longevity.", metadata={"source": "H2"}),
Document(page_content="Deep sleep is crucial for cellular repair and emotional regulation.", metadata={"source": "H3"}),
Document(page_content="Mindfulness and controlled breathing lower cortisol and improve mental clarity.", metadata={"source": "H4"}),
Document(page_content="Drinking sufficient water throughout the day helps maintain metabolism and energy.", metadata={"source": "H5"}),
Document(page_content="The solar energy system in modern homes helps balance electricity demand.", metadata={"source": "I1"}),
Document(page_content="Python balances readability with power, making it a popular system design language.", metadata={"source": "I2"}),
Document(page_content="Photosynthesis enables plants to produce energy by converting sunlight.", metadata={"source": "I3"}),
Document(page_content="The 2022 FIFA World Cup was held in Qatar and drew global energy and excitement.", metadata={"source": "I4"}),
Document(page_content="Black holes bend spacetime and store immense gravitational energy.", metadata={"source": "I5"}),
]
# Initialize OpenAI embeddings
embedding_model = OpenAIEmbeddings()
# Create FAISS vector store
vectorstore = FAISS.from_documents(documents=all_docs, embedding=embedding_model)
# Create retrievers
similarity_retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 5})
multiquery_retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(search_kwargs={"k": 5}),
llm=ChatOpenAI(model="gpt-3.5-turbo") # Internally which LLM we want to use to generate multiple queries from user query
)
# Query
query = "How to improve energy levels and maintain balance?"
# Retrieve results
similarity_results = similarity_retriever.invoke(query)
multiquery_results= multiquery_retriever.invoke(query)
for i, doc in enumerate(similarity_results):
print(f"\n--- Result {i+1} ---")
print(doc.page_content)
print("*"*150)
for i, doc in enumerate(multiquery_results):
print(f"\n--- Result {i+1} ---")
print(doc.page_content)
'''OUTPUT:
--- Result 1 ---
Drinking sufficient water throughout the day helps maintain metabolism and energy.
--- Result 2 ---
Mindfulness and controlled breathing lower cortisol and improve mental clarity.
--- Result 3 ---
Regular walking boosts heart health and can reduce symptoms of depression.
--- Result 4 ---
Deep sleep is crucial for cellular repair and emotional regulation.
--- Result 5 ---
The solar energy system in modern homes helps balance electricity demand.
******************************************************************************************************************************************************
--- Result 1 ---
Drinking sufficient water throughout the day helps maintain metabolism and energy.
--- Result 2 ---
Mindfulness and controlled breathing lower cortisol and improve mental clarity.
--- Result 3 ---
Regular walking boosts heart health and can reduce symptoms of depression.
--- Result 4 ---
Consuming leafy greens and fruits helps detox the body and improve longevity.
--- Result 5 ---
Deep sleep is crucial for cellular repair and emotional regulation.
'''
Question
multiquery_retriever = MultiQueryRetriever.from_llm( retriever=vectorstore.as_retriever(search_kwargs={“k”: 5}), llm=ChatOpenAI(model=”gpt-3.5-turbo”) ) So when I write this code, it means to produce different variations of the user query we are using gpt-3.5-turbo model,
- Question 1 — Where are we defining how many variations of the user query we want here
- Second the retrievers which will give us relevant documents related to my variations of the user query, are they the ones defined by this line retriever=vectorstore.as_retriever(search_kwargs={“k”: 5}), meaning each retriever will produce top 5 docs for the variation of the query
- Then where are we defining that at the end we want top 5, what if I want top 8 at the end but only top 5 for each variation of the user query
Where are we defining the number of variations for user query?
By default, you aren’t. If you don’t provide a custom prompt, the MultiQueryRetriever uses a pre-defined internal prompt that specifically asks the LLM to generate 3 variations of the user query.
If you want to change this (e.g., you want 5 variations), you have to pass a prompt argument to the .from_llm() method. You would write a custom prompt template that explicitly says: "Generate 5 different versions of the following user query..."
from langchain.prompts import PromptTemplate
from langchain_community.retrievers import MultiQueryRetriever
from langchain_openai import ChatOpenAI
# 1. Define your custom prompt asking for 5 variations
QUERY_PROMPT = PromptTemplate(
input_variables=["question"],
template="""You are an AI language model assistant. Your task is to generate 5
different versions of the given user question to retrieve relevant documents from a vector
database. By generating multiple perspectives on the user goal, your goal is to help
the user overcome some of the limitations of the distance-based similarity search.
Original question: {question}""",
)
# 2. Setup the LLM
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 3. Initialize the retriever with the custom prompt
retriever_from_llm = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(search_kwargs={"k": 5}),
llm=llm,
prompt=QUERY_PROMPT # This is where you define the '5 variations' logic
)
# 4. Usage
unique_docs = retriever_from_llm.get_relevant_documents(query="How can I stay healthy?")
Does each retriever produce top k=5?
Yes. The retriever argument you passed acts as the "template" for every sub-search.
- If the LLM generates 3 variations, LangChain will run 3 separate searches.
- Each of those 3 searches will use your
vectorstore.as_retriever(search_kwargs={"k": 5})settings. - This means you will initially have 15 total documents (3 queries x 5 text) before any deduplication happens.
How do we get top 8 at the end?
This is the tricky part: The standard MultiQueryRetriever in LangChain is designed to perform a Unique Union. It takes all the documents from the sub-queries, removes duplicates, and passes all of them to the chain.
It does not have a built-in “final k” parameter in the basic .from_llm constructor.
How to control the final count: If you want exactly 8 documents at the end, you usually handle this in one of two ways:
- The Manual Way: You don’t use the high-level
MultiQueryRetrieverclass. Instead, you build a small chain that generates queries, fetches docs, and then you manually slice the list:final_docs = unique_docs[:8]. - The Reranker Way: You retrieve a large pool (like your 15 docs) and then pass them through a LongContextReorder or a Cohere Rerank step, which sorts them by relevance and trims them down to your desired “final 8.”
Contextual Compression Retriever
The Contextual Compression Retriever is an advanced retriever in LangChain that improves retrieval quality by compressing documents after retrieval — keeping only the relevant content based on the user’s query.
❓ Query: “What is photosynthesis?”
📄 Retrieved Document (by a traditional retriever): “The Grand Canyon is a famous natural site. Photosynthesis is how plants convert light into energy. Many tourists visit every year.”
❌ Problem:
- The retriever returns the entire paragraph
- Only one sentence is actually relevant to the query
- The rest is irrelevant noise that wastes context window and may confuse the LLM
How it solves the problem
Instead of passing the entire “noisy” chunk to the LLM, the Contextual Compression Retriever uses a base retriever to find the documents and then passes them through a Document Compressor.
This compressor analyzes the text and the query together, stripping away the “Grand Canyon” and “tourist” sentences, leaving only:
“Photosynthesis is how plants convert light into energy.”
Question
Why will we have this kind of document in our vector store where it contains information about 2 topics
It is highly possible we might get these kind of documents. When we are working with big documents and apply text splitter, we don’t exactly get full control on how the text is getting split
It might happen that 2 paragraphs (where one para is tallking about topic A and another is talking about topic B) is split into 3 chunks, and in that situation we might get a chunk where it contains information about more than 2 topics.
So in those kind of situation context retrieval compression helps us
Lets us now look at its working
The user query is sent to a normal retreiver. We want 2 relevant documents based on the user query. So this retreiver gives us 2 documents lets say D1 and D2. Now both these documents individually will be sent to the LLM along with this query and an additional prompt will be given like “Based on the user’s query remove unwanted information from the document”, the LLM will then get us filtered documents D1 and D2 which has information only related to the query

How It Works
- Base Retriever (e.g., FAISS, Chroma) retrieves $N$ documents.
- A compressor (usually an LLM) is applied to each document.
- The compressor keeps only the parts relevant to the query.
- Irrelevant content is discarded.
When to use this retriever
- Your documents are long and contain mixed information, making them noisy for a standard retriever.
- You want to reduce context length for LLMs to save on token costs and speed up response times.
- You need to improve answer accuracy in RAG pipelines by preventing the LLM from getting distracted by irrelevant details.
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.retrievers.contextual_compression import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain_core.documents import Document
# Recreate the document objects from the previous data
docs = [
Document(page_content=(
"""The Grand Canyon is one of the most visited natural wonders in the world.
Photosynthesis is the process by which green plants convert sunlight into energy.
Millions of tourists travel to see it every year. The rocks date back millions of years."""
), metadata={"source": "Doc1"}),
Document(page_content=(
"""In medieval Europe, castles were built primarily for defense.
The chlorophyll in plant cells captures sunlight during photosynthesis.
Knights wore armor made of metal. Siege weapons were often used to breach castle walls."""
), metadata={"source": "Doc2"}),
Document(page_content=(
"""Basketball was invented by Dr. James Naismith in the late 19th century.
It was originally played with a soccer ball and peach baskets. NBA is now a global league."""
), metadata={"source": "Doc3"}),
Document(page_content=(
"""The history of cinema began in the late 1800s. Silent films were the earliest form.
Thomas Edison was among the pioneers. Photosynthesis does not occur in animal cells.
Modern filmmaking involves complex CGI and sound design."""
), metadata={"source": "Doc4"})
]
# Create a FAISS vector store from the documents
embedding_model = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embedding_model)
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# Set up the compressor using an LLM
llm = ChatOpenAI(model="gpt-3.5-turbo")
compressor = LLMChainExtractor.from_llm(llm)
# Create the contextual compression retriever
compression_retriever = ContextualCompressionRetriever(
base_retriever=base_retriever,
base_compressor=compressor
)
# Query the retriever
query = "What is photosynthesis?"
compressed_results = compression_retriever.invoke(query)
for i, doc in enumerate(compressed_results):
print(f"\n--- Result {i+1} ---")
print(doc.page_content)
'''OUTPUT:
--- Result 1 ---
Photosynthesis is the process by which green plants convert sunlight into energy.
--- Result 2 ---
The chlorophyll in plant cells captures sunlight during photosynthesis.
'''
When you use the **ContextualCompressionRetriever, the "logic" for what to keep and what to throw away is handled by the `base_compressor`**.
If your base_compressor is an LLM-based one (like LLMChainExtractor), it uses a pre-defined internal prompt that instructs the LLM to:
- Look at the user’s specific query.
- Scan each document retrieved by the
base_retriever. - Extract only the sentences or snippets that directly answer or relate to that query.
- Discard the rest.
You don’t have to tell it how to compress; the class is designed to handle the “filtering” out of the box. It essentially tells the LLM: “Here is a question and here is a document. Give me only the relevant parts.”
Can you change the prompt?
Yes. Just like the Multi-Query Retriever, if you find the default compression is too aggressive (cutting out too much) or too lazy (leaving too much noise), you can initialize the compressor with a custom prompt.
There are several other retrievers in Langchain, some of them are listed below. In this blog we have studied some of them.
1. Hybrid & Smart Search
- BM25Retriever (Sparse Retriever): Unlike vector stores that use “meaning,” BM25 uses keyword matching (it’s the industry standard for traditional search). It’s excellent for finding specific names, product IDs, or rare technical terms that an embedding model might overlook.
- EnsembleRetriever: This is the “best of both worlds” tool. It combines results from multiple retrievers (e.g., BM25 + FAISS) and uses Reciprocal Rank Fusion (RRF) to re-rank them. It ensures you get results that are both semantically relevant and keyword-accurate.
- SelfQueryRetriever: This retriever is “metadata-aware.” It uses an LLM to look at a user’s query and decide if it should apply a filter.
- Query: “Show me documents about AI from 2023.”
- Action: It creates a vector search for “AI” AND a metadata filter for
year == 2023.
2. Context-Optimized Retrievers
- ParentDocumentRetriever: This solves the “Goldilocks” problem of chunking.
- It splits documents into small chunks for high-precision search.
- When a small chunk is found, it retrieves the entire parent document (or a larger section) to provide the LLM with full context.
- MultiVectorRetriever: Similar to the Parent retriever, but more flexible. It allows you to create multiple vectors for a single document, such as:
- A vector for the summary.
- A vector for hypothetical questions the document answers.
- A vector for smaller chunks.
3. Specialized Logic
- TimeWeightedVectorRetriever: Perfect for “memory” systems. It calculates a score based on Semantic Similarity + Recency. As time passes, the “relevance” of a document decays unless it is accessed frequently.
- ArxivRetriever: A specific integration that allows your chain to search and retrieve scientific papers directly from the Arxiv open-access archive.
When building a RAG application, to increase the performance we experiment with different retrievers, as they offer advanced search algorithms to get us the relevant documents for our query
메타데이터
- post_id
- b435ae8f4ea7
- slug
- langchain-part-12-retrievers-b435ae8f4ea7
- url
- https://medium.com/@abhishekjainindore24/langchain-part-12-retrievers-b435ae8f4ea7
- canonical_url
- https://medium.com/@abhishekjainindore24/langchain-part-12-retrievers-b435ae8f4ea7
- author_url
- https://medium.com/@abhishekjainindore24
- status
- ok
- fetched_at
- 2026-06-12 18:14:10