⚡ A lightweight, modular microframework for complete AI applications.
PyAIStack helps you build RAG, agents, agentic tools, AI features, and provider integrations faster. The current release provides a production-oriented foundations with local Ollama and Gemma models by default.
✨ Start simple
from pyaistack import RAG
rag = RAG(
embedding_model="embeddinggemma",
llm_model="gemma3:4b",
)
rag.add([
"AWS Lambda is a serverless compute service.",
"Amazon S3 is an object storage service.",
])
answer = rag.ask("Which service runs code without managing servers?")
print(answer.text)
📁 Load, chunk, and persist local knowledge
Load a directory of UTF-8 .txt files, split documents before indexing, and retain the index in one SQLite file:
from pyaistack import RAG
from pyaistack.chunking import TextChunker
from pyaistack.loaders import DirectoryLoader
from pyaistack.vectorstores import SQLiteVectorStore
documents = DirectoryLoader("knowledge", file_type="text").load()
rag = RAG(
vector_store=SQLiteVectorStore("knowledge.db"),
chunker=TextChunker(chunk_size=1_000, chunk_overlap=150),
)
rag.add_documents(documents)
file_type is required. This release implements only text; PDF, DOCX, Markdown, and web loaders will be added only when implemented. SQLiteVectorStore uses exact cosine search and is intended for local, small-to-medium indexes.
New in 0.2.2: optional hybrid retrieval
Combine SQLite FTS5 keywords with vector ranking while keeping the default local Ollama setup:
from pyaistack import RAG, RAGConfig
from pyaistack.vectorstores import SQLiteVectorStore
with SQLiteVectorStore("knowledge.db") as store:
rag = RAG(vector_store=store, config=RAGConfig(
retrieval_mode="hybrid", candidate_k=20, top_k=5, include_sources=True,
))
# Reuse an index built with the same embedding model.
answer = rag.ask("What does policy FIN-042 require?")
print(answer.text)
For a complete fresh demo, run python examples/hybrid_index.py, then
python examples/hybrid_question.py. See the
hybrid guide and
benchmark report.
Hybrid is opt-in; quality and latency depend on your corpus.
Project links
🧠 Requirements
- Python 3.10+
- Ollama running locally
- Ollama version compatible with
embeddinggemma(the Ollama model page currently specifies v0.11.10+)
Pull the default models:
ollama pull embeddinggemma
ollama pull gemma3:4b
🚀 Install
python -m venv .venv
source .venv/bin/activate
pip install pyaistack
For development:
pip install -e ".[dev]"
▶️ Run
python examples/basic.py
How it works
documents
│
▼
OllamaEmbeddingProvider
│
▼
InMemoryVectorStore
question
│
▼
embedding
│
▼
cosine retrieval
│
▼
Top-K sources
│
▼
context builder
│
▼
OllamaChatProvider
│
▼
RAGAnswer(text + sources)
🔧 Change the embedding model
Only configuration changes:
rag = RAG(
embedding_model="qwen3-embedding:0.6b",
llm_model="gemma3:4b",
)
or:
rag = RAG(
embedding_model="nomic-embed-text",
llm_model="gemma3:4b",
)
Note: Do not change embedding models while an index contains vectors. Different models may produce different vector dimensions and, more importantly, incompatible vector spaces. Clear/rebuild the index when changing the embedding model.
✍️ Add application instructions
You can append instructions specific Prompt sufix to your application:
rag = RAG(system_prompt_suffix="Answer with concise bullet points.")
🌐 Configure Ollama host
rag = RAG(
embedding_model="embeddinggemma",
llm_model="gemma3:4b",
ollama_host="http://192.168.1.20:11434",
)
🔎 Access retrieval results without generating
results = rag.search("serverless compute", top_k=3)
for result in results:
print(result.score)
print(result.document.text)
print(result.document.metadata)
🏷️ Add metadata
rag.add(
["Leave policy text", "Travel policy text"],
metadatas=[
{"file": "leave-policy.pdf", "page": 3},
{"file": "travel-policy.pdf", "page": 7},
],
)
Use normalized metadata filtering with either retrieval or answer generation. When stored metadata is a list, a scalar filter matches one list value:
results = rag.search(
"What is the leave policy?",
metadata_filter={"department": "engineering"},
)
answer = rag.ask(
"What is the leave policy?",
metadata_filter={"department": "engineering"},
)
LLMMetadataFactory stores generated values as normalized lists, for example
{"category": ["sustainability"], "language": ["en"]}.
For large text directories, generate metadata automatically with
FolderMetadataFactory from folder names, CSVMetadataFactory from a
metadata manifest, or LLMMetadataFactory from a bounded file sample. Use
DirectoryLoader.iter_load() with
rag.add_documents([document]) to process one file at a time. See
loaders and chunking.
⚙️ Configure retrieval
from pyaistack import RAG, RAGConfig
rag = RAG(
config=RAGConfig(
top_k=5,
min_score=0.25,
max_context_chars=20_000,
include_sources=True,
)
)
💬 Friendly errors
Use format_error at your application entry point to show the relevant application line without PyAIStack implementation frames:
from pyaistack import RAG, format_error
from pyaistack.exceptions import ProviderError
rag = RAG()
try:
rag.add(["A document to index."])
except ProviderError as error:
print(format_error(error))
For example, a missing embedding model is displayed as:
Traceback (most recent call last):
File "/path/to/app.py", line 8, in <module>
rag.add(["A document to index."])
pyaistack.exceptions.ProviderError: Model "embeddinggemma" is not available.
Run: ollama pull embeddinggemma
📄 License
Apache License 2.0. See LICENSE.
Release files for pyaistack 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyaistack-0.2.2.tar.gz | 37.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyaistack-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 75.6 kB
Release files / pyaistack-0.2.2.tar.gz
| Download URL | pyaistack-0.2.2.tar.gz |
|---|---|
| Size | 37.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a0c2cdca3975c2654cdef266b281a72eee1000f4c3f7013546b690b2e422a6be
|
|
BLAKE2b-256 checksum How to use checksums |
ef91919cda65288045b49480e0250ef678f8a955e9fc7ac8ace938a4b82377f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / pyaistack-0.2.2-py3-none-any.whl
| Download URL | pyaistack-0.2.2-py3-none-any.whl |
|---|---|
| Size | 38.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
453fee6576ca8194f5e913f8a7126067f1a5d8310745a7dcb98c6dd7360e456d
|
|
BLAKE2b-256 checksum How to use checksums |
8d810000f341692401f71c8e08b061b5ce39fb123de11ff28af38d603f4f0712
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|