6.2 KiB
Basic RAG Cookbook
Build basic RAG functionality with Weaviate. For advanced strategies, see here.
Docs to reference if needed:
- Search patterns and basics in Weaviate: https://docs.weaviate.io/weaviate/search/basics
- Filters in Weaviate: https://docs.weaviate.io/weaviate/search/filters
- Vector search: https://docs.weaviate.io/weaviate/search/similarity
- Keyword search: https://docs.weaviate.io/weaviate/search/bm25
- Hybrid search: https://docs.weaviate.io/weaviate/search/hybrid
- Image search: https://docs.weaviate.io/weaviate/search/image
Core Rules
- Use a virtual environment via
venv - Use
uvfor Python project/dependency management. - Do not manually author
pyproject.tomloruv.lock; letuvgenerate/update them. - Use this install set:
uv add weaviate-client python-dotenv dspy - Customise this cookbook to the users specification, ask them for details if not given.
Assume the user has data already to be used, do not create data unless asked to.
Env Rules
Mandatory:
WEAVIATE_URLWEAVIATE_API_KEY
External provider keys:
- Fill only keys actually used by the target Weaviate collection setup.
Weaviate Client
import os
from weaviate import connect_to_weaviate_cloud
client = connect_to_weaviate_cloud(
cluster_url=os.getenv("WEAVIATE_URL", ""),
auth_credentials=os.getenv("WEAVIATE_API_KEY", ""),
headers={
"X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
},
)
If the user's collections require vectorizer provider keys, set the matching keys listed in environment_requirements.md.
Clients must be closed after completion. Wrap in try/finally blocks with client.close() (and client.connect() to reconnect if needed).
Multi-tenancy
Multi-tenancy should be checked via
config = await collection.config.get()
config.multi_tenancy_config.enabled # bool
e.g.
base_collection = client.collections.use(collection_name)
config = collection.config.get()
if config.multi_tenancy_config.enabled:
collection = base_collection.with_tenant("<tenant_name>")
else:
collection = base_collection
Tenant names can be obtained via
all_tenants = list(collection.tenants.get().keys())
Basic Retrieval
Use collections via
collection = client.collections.use("<collection_name>")
Weaviate can use vector, keyword or hybrid search.
collection.query.near_text # semantic (text)
collection.query.bm25 # keyword
collection.query.hybrid # blend of keyword and semantic
It can also do image search
collection.query.near_image(
near_image = ... # base 64 representation of image or Path object to image
)
Key Code Blocks
RAG should have 4 pieces of core functionality:
- Pre-retrieval
- Retrieval
- Post-retrieval
- Generation
These should all be separate functions and combined into a single function, leaving scope for later editing or for the user themselves to modify it, to keep it understandable.
Pre-retrieval
Transform the user question into a vector-database style (list of) query(ies). Basic RAG will provide no extra query transformations.
def query_transformation(query: str) -> list[str]:
return [query]
Retrieval
def retrieve(
query: str,
limit: int = 10, # optional
filters = [] # optional
# additional arguments if required can go here and passed down to the search strategy
) -> list[dict]:
# import client logic here
collection = client.collections.use("<collection_name>")
response = collection.query.near_text( # or hybrid, bm25, near_image
query=query,
limit=limit,
filters=filters if filters else None
)
return [
{
**obj.properties,
"uuid": obj.uuid
}
for obj in response.objects
]
Post-Retrieval
Modify the output of retrieve. Basic RAG will provide no extra post-processing. But you can consider adding uniqueness checks, formatting to remove properties, or more.
def process_retrieval_results(objects: list[dict]) -> list[dict]:
return objects
Generation
This step depends on your LLM framework, see below. Using DSPy:
import dspy
def generate(query: str, context: list[dict]) -> str:
lm = dspy.LM("<model_name>") # e.g. gpt-5.2, gpt-5-mini, claude-sonnet-4-5, etc.
answer = dspy.Predict("context, query -> answer") # inputs: context, query. outputs: answer
pred = answer(context=context, query=query, lm=lm)
return pred.answer # answer is then an attribute of pred
User-specific Customisations
If not specified ask the user about these points before implementing their respective strategies:
LLM Framework
You can use DSPy (works with all LiteLLM providers) or LiteLLM itself.
Alternatively, users can use a single model provider. What model provider will they use?
- OpenAI (https://platform.openai.com/docs/libraries)
- Anthropic (https://platform.claude.com/docs/)
- Google GenAI (https://ai.google.dev/gemini-api/docs/libraries)
- Other (such as locally hosted models), use best judgement
These may require additional installs.
Collections
Do collections already exist and what are they called? Does the user want to query multiple collections or just a single one? Does it need to be customisable?
What format is the data, images or text or something else? What vectoriser is the collection set up as? What API keys are needed?
Search strategy
Does the user want semantic, keyword or hybrid search?
Hybrid search has an alpha parameter, controlling tradeoff between keyword and semantic weights. alpha=1 is pure semantic, alpha=0 is pure keyword.
Troubleshooting
- Weaviate startup host errors: ensure
WEAVIATE_URLis fullhttps://...URL. - For any other issues, refer to the official library/package documentation and use web search extensively for troubleshooting.
Done Criteria
- Create test scripts to check each function works independently with test data. Tear down tests after completion, or create a proper test suite with pytest (requires install)
- User has completed specification of the app.