Agno's Knowledge(query_transformer=HyDE()) makes one model call per search, asking for a short passage that answers the question the way a reference document would. The vector database embeds that passage and looks for its neighbours.
Questions and answers rarely share wording. Ask "Why did revenue drop?" and the closest match is a policy note that says "revenue" twice, while the quarterly review that actually explains the drop talks about renewals and churn. A made-up answer reads like that review, so its embedding lands next to it. The passage never reaches the user and doesn't have to be right.

The transform only changes what the vector database searches for. Knowledge hands the reranker the original question, so relevance stays tied to what the user asked. Keyword search skips the transform, because lexical matching needs every term present and a generated passage would match nothing. On a hybrid store or page storage, set include_query=True to search with the question followed by the passage.
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.query_transformer import HyDE
from agno.models.openai import OpenAIResponses
from agno.vectordb.pgvector import PgVector
knowledge = Knowledge(
vector_db=PgVector(table_name="docs", db_url=db_url),
query_transformer=HyDE(model=OpenAIResponses(id="gpt-5.6-luna")),
)HyDE writes with its own model, so a small, fast one keeps the extra call cheap. Left unset, it defaults to OpenAIResponses(id="gpt-5.4"). max_characters caps the passage at 2000 characters by default and trims at a sentence break, and a custom prompt must contain {query}. When an agent searches through its knowledge tool, the HyDE call counts toward the run's metrics.
QueryTransformer is the hook underneath, and you can write your own. Implement transform(query, run_response=None) and return the string to search with. The async atransform runs it off the event loop unless you override it. We had no OpenAI key, so we wrote a transformer that returns a fixed hypothetical answer in place of the model call, plus a reranker that prints the query it receives. On pgvector with a local FastEmbed embedder and the cookbook's three notes:
from agno.knowledge.query_transformer import QueryTransformer
from agno.knowledge.reranker.base import Reranker
class CannedAnswer(QueryTransformer):
def transform(self, query, run_response=None):
return (
"Revenue fell because several large customers delayed their renewals "
"and more accounts churned than expected."
)
class ShowQuery(Reranker):
candidate_multiplier: int = 1
def rerank(self, query, documents, limit=None):
print(f" reranker scores against: {query!r}")
return documents
plain = Knowledge(vector_db=vector_db)
hyde = Knowledge(vector_db=vector_db, query_transformer=CannedAnswer(), reranker=ShowQuery())# real output
Searching with the question
1. revenue-policy
2. q3-review
3. hiring
Searching with a hypothetical answer
reranker scores against: 'Why did revenue drop?'
1. q3-review
2. revenue-policy
3. hiringThe same search with HyDE() and no API key logged HyDE could not generate a hypothetical answer, using the query as asked and returned the plain ranking.
See the cookbook, and learn more about query transformation in the documentation.
Frequently asked questions
HyDE is a query transformer you set on Knowledge. Before each search it asks a model for a short passage that would answer the question, and the vector database embeds that passage and searches with it. Users never see the passage, and it can be wrong as long as it reads like the documents you store.
The one you pass as HyDE(model=...). When you leave it unset, HyDE creates OpenAIResponses(id="gpt-5.4") on construction, the same default Agent and Team use. It does not borrow the model of the agent that runs the search.
No. Knowledge gives the reranker the question exactly as the caller asked it. The generated passage only steers the vector search.
HyDE logs a warning and returns the original question, so the search still runs with the raw query. A provider outage lowers result quality without breaking retrieval.





