惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
腾讯CDC
Y
Y Combinator Blog
L
LangChain Blog
B
Blog
U
Unit 42
P
Proofpoint News Feed
G
Google Developers Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
WordPress大学
WordPress大学
月光博客
月光博客
Vercel News
Vercel News
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 叶小钗

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Self Querying Retrieval
Rushank Sava · 2026-05-02 · via DEV Community

🧠 The Concept

In standard RAG, the system is a bit "dumb."
If you ask for "Romantic movies from the 90s", a standard vector search just looks for the words "Romantic", "movies", and "90s".
It doesn't actually understand that "90s" is a date range or a category.

Self-Querying Retrieval changes this by giving the LLM a "Search Bar" and "Filters".

1. The Analysis: The LLM looks at your query first.

2. The Translation: It separates the semantic meaning from the query (the "facts" like date, rating, or category).

3. The Structured Search: It writes a formal database query to filter the results before doing the vector search.


📝 Example-based explanation:

Imagine your company has thousands of policy documents stored in a Vector DB. Each document has Metadata attached to it:

Department: (Sales, Engineering, HR)
Year: (2022, 2023, 2024)
Type: (Benefit, Conduct, Salary)

User Query: "What were the maternity leave benefits for Engineering staff in 2023?"

Standard RAG (The "Basic" Way):
It searches for the entire sentence. It might find a 2024 policy for Sales because the word "maternity" appeared frequently there. It’s a "blurry" search.

Self-Querying RAG:
The LLM acts as a translator first. It creates two parts:

1. The Semantic Query: "maternity leave benefits"
2. The Filter: Department == 'Engineering' AND Year == 2023


⚙️ Practical Implementation:

To implement Self-Querying Retrieval, you need two things:

  • Vector Store that supports metadata filtering (like Chroma).
  • LLM that understands how to translate natural language into structured filters.

Following code uses langchain's in-built libraries for easier execution:

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model
from langchain_huggingface import HuggingFaceEndpointEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_classic.retrievers import SelfQueryRetriever
from langchain_classic.chains.query_constructor.schema import AttributeInfo ## meta-data schema for llm to understand

from dotenv import load_dotenv
load_dotenv()
llm_groq = init_chat_model("openai/gpt-oss-120b", model_provider = 'groq', temperature = 0)


# --- STEP 1: Document Loading ---
# Imagine 'products.txt' contains raw paragraphs about different electronics
with open("./RAG/Retrieval_techniques/products.txt", "w") as f:
    f.write("""
    The HP ProBook 15 is a professional laptop priced at 1200 dollars. It has a stellar 4.5 rating.
    The Acer Aspire is a basic student laptop. It is very affordable at 400 dollars but has a 3.8 rating.
    The Razer Blade is a high-end gaming laptop for 2500 dollars, boasting a near-perfect 4.9 rating.
    The LG UltraWide is a 4K monitor. It costs 600 dollars and is rated 4.2 by experts.
    """)

loader = TextLoader("./RAG/Retrieval_techniques/products.txt")
raw_documents = loader.load()


# --- STEP 2: Chunking ---
# We split by double newlines to keep each product description together
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
chunks = text_splitter.split_documents(raw_documents)


# --- STEP 3: Automated Metadata Enrichment (The LLM Part) ---
class ProductSchema(BaseModel):
    """Schema for extracting product details from text."""
    category: str = Field(description="laptop, monitor, or other electronics")
    price: int = Field(description="The price as an integer")
    brand: str = Field(description="The brand name")
    rating: float = Field(description="The numerical rating 0-5")

# Initialize LLM with structured output
llm_structured = llm_groq.with_structured_output(ProductSchema)

print("--- Starting Automated Enrichment ---")
enriched_chunks = []

for chunk in chunks:
    # LLM reads the chunk content and generates the structured data
    extracted = llm_structured.invoke(chunk.page_content)

    # Update the chunk's metadata dictionary
    chunk.metadata.update(extracted.model_dump()) ## adding new metadata in chunks
    enriched_chunks.append(chunk)
    print(f"Processed: {chunk.metadata['brand']} - ${chunk.metadata['price']}")


# --- STEP 4: Vector Store ---
embedding_model = HuggingFaceEndpointEmbeddings(
    model="sentence-transformers/all-MiniLM-L6-v2", ## this model returns 384 sized vector
    task="feature-extraction",
)
vectorstore = Chroma.from_documents(enriched_chunks, embedding_model)


# --- STEP 5: Define Metadata for the "Self-Query" Brain ---
# AttributeInfo: A schema object that defines the name, description, and data type of your metadata fields.
# Under-the-Hood: It serves as the system prompt for the LLM. It tells the model: 
# "Here are the 'columns' available in our database. When a user mentions price, "
# "use the field 'price' and treat it as an integer." 
# Without this, the LLM wouldn't know which keys exist in your VectorDB metadata.
metadata_field_info = [
    AttributeInfo(name="category", description="The type of product", type="string"),
    AttributeInfo(name="price", description="The cost in USD", type="integer"),
    AttributeInfo(name="brand", description="The brand name", type="string"),
    AttributeInfo(name="rating", description="The customer rating 0-5", type="float"),
]
document_content_description = "Product descriptions from the store catalog"


# --- STEP 6: The Self-Querying Retriever ---
retriever = SelfQueryRetriever.from_llm(
    llm_groq, # to make a structured query
    vectorstore, # where chunks are stored
    document_content_description, # description for llm's understanding
    metadata_field_info, # meta-data schema for llm's understanding
    verbose=True 
) 
# Under-the-Hood SelfQueryRetriever:
# It sends the user's prompt + metadata_field_info to the llm_groq
# User: "Laptops under $1000" ; llm converts it to: { "price": 1000, "category": "laptop" }
# LangChain takes that structured query and translates it into the native filtering language of your specific VectorDB (e.g., Chroma's where clause or Pinecone's filter syntax)
# It performs a search where it first discards all chunks that don't match the metadata filter and then performs a semantic vector search on the remaining chunks.

# --- STEP 7: Testing ---
query = "Show me laptops cheaper than 1500 with at least a 4 star rating"
results = retriever.invoke(query)

for doc in results:
    print(f"Result: {doc.page_content} | Metadata: {doc.metadata}")

Enter fullscreen mode Exit fullscreen mode


🚧 Cons of Self Query Retrieval

  • The entire system relies on the LLM’s ability to correctly translate a natural language sentence into a precise filter.

  • If you add new documents with a new metadata field (like color), the retriever won't know it exists until you manually update the AttributeInfo list in your code. It is not "plug-and-play" with dynamic data.

  • Standard RAG is one step: Query -> Vector Search
    Self-Querying RAG is three steps:
    Query -> LLM (to generate the filter)
    Filter -> Vector DB (to prune the data)
    Filtered Results -> Vector Search

  • You have to build a separate "Ingestion Pipeline" that uses an LLM to extract metadata from every single chunk before it goes into the database.

Possible Solutions:

Challenge Strategy to Overcome
Logic Errors Few-Shot Prompting to show the LLM examples of correct query translations.
Latency Use a smaller, faster model for query construction
Schema Drift Pydantic model to validate metadata during both ingestion and retrieval.

🎯 Conclusion

In modern architectures, we often use Hybrid Self-Querying.
The LLM generates a filter, but we apply it "softly"—giving higher weight to matches that meet the criteria, rather than deleting everything else.