Recipe: Search the Vector Store
The Problem
"Once our documents are embedded, we need our agent to actually query the vector store when answering a question — falling back to keyword matching for exact terms (error codes, product names) and semantic search for conceptual questions, ideally through one tool the agent can call."
Ingredients
- A populated vector store (see Create & Ingest Embeddings)
KnowledgeBaseSearchTool(recommended for agents), or the direct client search methods (vector_search,hybrid_search,keyword_search) for scripts
The Recipe
1. Recommended: register KnowledgeBaseSearchTool on your agent
from caip_agents_sdk.tools import KnowledgeBaseSearchTool
kb_tool = KnowledgeBaseSearchTool(
client=client,
vector_store_id=vector_store_id,
)
@agent.tool_plain
async def search_docs(query: str) -> str:
"""Search product documentation."""
return await kb_tool.search(query=query, search_type="hybrid", top_k=5)
response = await agent.run("How do I authenticate API requests?")
The tool automatically generates query embeddings, formats results for LLM consumption, and handles errors/retries — no manual embedding step needed.
Production recommendation: keep tool description explicit and scoped so the model learns when to call retrieval versus when to answer directly.
2. Choose a search strategy
| Your Need | search_type |
|---|---|
| General questions (default) | "hybrid" ⭐ — semantic + keyword |
| Conceptual questions ("What are authentication methods?") | "vector" — semantic similarity |
| Exact terms, error codes, identifiers | "keyword" — exact/fuzzy text match |
3. Filter for precision
@agent.tool_plain
async def search_v2_auth(query: str) -> str:
"""Search only v2 authentication docs."""
return await kb_tool.search(
query=query,
search_type="hybrid",
document_id="api/authentication/", # prefix match on document ID
metadata_filter={"version": "v2"}, # match on stored metadata
top_k=5,
)
4. Alternative: direct client methods (scripts, pipelines, no agent)
query_embedding = await client.text_to_embedding(
text="What are authentication methods?",
vector_store_id=vector_store_id,
)
search_results = await client.vector_search(
vector_store_id=vector_store_id,
search_request={
"queryEmbedding": query_embedding,
"limit": 10,
"scoreThreshold": 0.0,
"includeEmbeddings": False,
},
)
results = search_results.results if hasattr(search_results, "results") else []
Use this when you need direct API access without an agent — e.g. a data pipeline. hybrid_search() and keyword_search() follow the same shape (see the Search & Filtering reference).
5. Troubleshooting: no results found
# 1. Check the vector store actually has embeddings
embeddings = await client.list_embeddings(vector_store_id)
print(f"Total embeddings: {len(embeddings)}")
# 2. Lower the score threshold
await kb_tool.search(query=query, score_threshold=0.5)
# 3. Remove filters temporarily
await kb_tool.search(query=query, metadata_filter=None, document_id=None)
# 4. Try hybrid search if you were using vector/keyword only
await kb_tool.search(query=query, search_type="hybrid")
Enterprise Response Pattern
To reduce hallucinations, require answer grounding:
- If retrieval returns no relevant context, instruct the agent to say it cannot verify from approved sources.
- Include source snippets or document IDs in final responses for auditability.
- Keep business-critical actions behind deterministic tools, not free-form generation.
Enterprise Hardening Checklist
- Use
hybridsearch as default; tune with evaluation data, not intuition. - Add metadata filters for tenant, product, region, and version isolation.
- Track retrieval hit rate, empty-result rate, and citation coverage.
- Add fallback behavior for retrieval failure (degraded mode + user-safe response).
- Run regression checks when corpus, embedding model, or chunking strategy changes.
Related Recipes
- Create & Ingest Embeddings — populate the store this recipe searches
- Need custom search logic instead of the prebuilt tool? See Custom RAG Search Tool
- Full reference: Search & Filtering, Best Practices & Troubleshooting