Using the SQLite Store
SQLiteVectorStore persists documents and vectors in a local SQLite database file. It uses exact cosine similarity, which is appropriate for local small-to-medium indexes.
Create an index
from pyaistack import RAG
from pyaistack.chunking import TextChunker
from pyaistack.loaders import DirectoryLoader
from pyaistack.vectorstores import SQLiteVectorStore
documents = DirectoryLoader("/path/to/knowledge/", file_type="text").load()
rag = RAG(
vector_store=SQLiteVectorStore("knowledge.db"),
chunker=TextChunker(),
)
rag.add_documents(documents)
Reuse an index ask()
Create a new RAG instance with the same database path and embedding model. Do not add the documents again.
from pyaistack import RAG
from pyaistack.vectorstores import SQLiteVectorStore
rag = RAG(
embedding_model="embeddinggemma",
llm_model="gemma3:4b",
vector_store=SQLiteVectorStore("knowledge.db"),
)
answer = rag.ask("What information is available?")
print(answer.text)
Retrieve chunks with search()
Use search() when you need the matching chunks, their metadata, and similarity
scores without calling the LLM. This is useful for inspecting retrieval results
or building a custom response flow.
results = rag.search("What information is available?", top_k=3)
for result in results:
print(result.score)
print(result.document.metadata)
print(result.document.text)
ask() vs search()
Use ask() when you want PyAIStack to retrieve the chunks and generate a
grounded natural-language answer. Use search() when you only need retrieval.
| Aspect | rag.search() | rag.ask() |
|---|---|---|
| Purpose | Retrieves relevant chunks only | Retrieves chunks and generates an LLM answer |
| Calls embedding model | Yes | Yes |
| Calls chat/LLM model | No | Yes |
| Return value | tuple[SearchResult, ...] |
RAGAnswer |
| Includes score | Yes, per result | Available in answer.sources |
| Includes metadata | Yes, per result | Available in answer.sources |
Has .text answer |
No | Yes, via answer.text |
| Best for | Debugging retrieval, custom UI, source inspection | Normal user-facing question answering |
| Example | results = rag.search("budget planning") | answer = rag.ask("How should I plan a budget?") |
Filter by metadata
Pass metadata_filter to either search() or ask() to limit retrieval to
documents with matching metadata. Every supplied key/value must match. A scalar
filter matches a scalar value exactly or one value in stored list metadata; a
list filter requires every requested value to be present. Filtering happens
before cosine scoring.
finance_results = rag.search(
"How should a monthly budget be reviewed?",
metadata_filter={"category": "finance"},
)
answer = rag.ask(
"How should a monthly budget be reviewed?",
metadata_filter={"category": "finance", "audience": "general"},
)
print(answer.text)
Add metadata while indexing
Metadata filters can only match fields stored during indexing. Add them with
LoadedDocument(metadata={"category": "finance"}) or
rag.add(..., metadatas=[...]).
No metadata indexed
if no Metadata available or indexed then result will not found even if it is present.
The store binds itself to the first embedding model and vector dimension. To use a different embedding model, clear and rebuild the index:
For hundreds of thousands of chunks or more, use a dedicated indexed vector database in a future PyAIStack adapter.