| title | Retrieval-augmented generation (RAG) |
|---|
Build a semantic knowledge base and answer questions grounded in it, using the
ai/embed connector, a pgvector table, and ai/completion. Two example
workflows tie it together:
rag-ingest— embed a document and store it in the vector store.rag-ask— embed a question, find the nearest documents by cosine distance, and have an LLM answer grounded in them (with citations).
This is semantic retrieval — matches are by meaning, not keywords. For a simpler keyword-only variant with no extensions, see the office-assistant MVP, which uses Postgres full-text search.
- Credentials: an
openaicredential (referenced asopenai) forai/embedandai/completion, and apostgrescredential (referenced askb-db) for the vector store. - A Postgres database with the pgvector
extension. Apply the schema from
rag-kb-schema.sql:
psql "$KB_DATABASE_URL" -f packages/site/src/content/examples/rag-kb-schema.sqlApply both workflows:
mantle apply packages/site/src/content/examples/rag-ingest.yaml
mantle apply packages/site/src/content/examples/rag-ask.yamlai/embed returns each embedding both as a float array (output.embedding) and
as a pgvector text literal (output.vector, e.g. "[0.1,0.2,...]"). The
literal binds straight into a ::vector column, so storing and querying vectors
needs no special encoding:
# ingest
args:
- "{{ inputs.content }}"
- "{{ steps['embed'].output.vector }}" # → $2::vector-- ask: nearest neighbours by cosine distance (<=> is pgvector's operator)
SELECT content, 1 - (embedding <=> $1::vector) AS similarity
FROM kb_documents
ORDER BY embedding <=> $1::vector
LIMIT 5The retrieved rows are passed to ai/completion as JSON context, and the model
answers using only those passages.
mantle run rag-ingest \
--input title="Client C integration" \
--input source="confluence/12345" \
--input content="Team A connects to Client C via the X integration; Team B uses the direct API."For a long document, split it into chunks and run rag-ingest once per chunk.
Re-ingesting identical content is a no-op (the schema dedupes on md5(content)).
mantle run rag-ask \
--input question="Who works with Client C and how?" \
--output jsonThe answer step's output.text is the grounded response (the CLI prints step
outputs with --output json or -v).
- Embedding dimension must match the model. The schema uses
vector(1536)fortext-embedding-3-small; usevector(3072)fortext-embedding-3-large. Embed queries and documents with the same model. - Provider support:
ai/embedsupportsopenai(and OpenAI-compatible endpoints like Azure OpenAI or local servers viabase_url) andbedrockwith the Amazon Titan text-embedding models (amazon.titan-embed-text-v2:0,amazon.titan-embed-text-v1). To use Bedrock, setprovider: bedrock, aregion, and anawscredential; adjust the schema'svector(...)dimension to match (Titan v2 defaults to 1024). Cohere Bedrock models are a follow-up. - No native chunking or
kb/*convenience steps yet. You compose RAG fromai/embed+postgres/query+ai/completiontoday; native chunking andkb/upsert/kb/queryconnectors are tracked by #153.