RAG¶
Locus's RAG stack is built around Oracle Database 26ai as the default
backend. The 26ai engine ships native VECTOR(N, FLOAT32) columns, the
VECTOR_DISTANCE SQL function, and the in-database
DBMS_VECTOR_CHAIN primitives for embedding generation and chunking —
so the full retrieve-augment loop can live inside the database next to
the source data, without copying vectors out to a sidecar service.
OpenSearch, pgvector, and the in-memory store are also supported as
alternates; the BaseVectorStore / BaseEmbedding contracts are
identical across backends so you can swap stores with a one-line import
change.
Oracle 26ai¶
The Oracle-native path. OracleVectorStore opens an async pool against
an Autonomous Database wallet, auto-creates a VECTOR(N, FLOAT32)
table on first use, and serves cosine / dot / Euclidean similarity via
VECTOR_DISTANCE. OracleInDBEmbeddings and OracleInDBChunker run
the embedding and chunking entirely inside the database via
DBMS_VECTOR_CHAIN, eliminating the round-trip to an external embed
service. OracleADBLoader ingests documents directly from ADB tables.
OracleVectorStore ¶
OracleVectorStore(dsn: str | None = None, user: str = 'admin', password: str | SecretStr = '', host: str | None = None, port: int = 1521, service_name: str | None = None, dimension: int = 1024, distance_metric: str = 'COSINE', **kwargs: Any)
Bases: BaseModel, BaseVectorStore
Oracle 26ai Vector Store with native VECTOR support.
Uses Oracle Database 23ai/26ai's native VECTOR data type for efficient similarity search. Supports cosine, dot product, and Euclidean distance metrics.
Production setup — use a least-privileged schema, not ADMIN.
Using ADMIN against an Autonomous Database is an Oracle security
anti-pattern: every connection runs with full DBA privileges, so a
compromised credential or a malformed query has unbounded blast
radius. Create a dedicated application schema with only the
privileges this store needs. Run once as ADMIN to provision::
-- Create a least-privileged owner for Locus's vector tables.
CREATE USER locus_app IDENTIFIED BY "<strong-password>";
GRANT CONNECT, RESOURCE TO locus_app;
ALTER USER locus_app QUOTA 1G ON DATA;
-- (Optional) pre-create the table yourself so locus runs with
-- DML-only privileges. See ``auto_create_table=False`` below.
CREATE TABLE locus_app.locus_documents (
id VARCHAR2(255) PRIMARY KEY,
content CLOB,
embedding VECTOR(1024, FLOAT32),
metadata CLOB DEFAULT '{}' CHECK (metadata IS JSON)
);
CREATE VECTOR INDEX idx_locus_documents_vec
ON locus_app.locus_documents (embedding)
ORGANIZATION NEIGHBOR PARTITIONS
WITH DISTANCE COSINE;
Then connect as the app user — never ADMIN — at application startup.
Table provisioning: auto vs. pre-create.
auto_create_table=True (the default) issues CREATE TABLE and
CREATE VECTOR INDEX on first use. Convenient for demos and
notebooks; requires DDL privileges on the schema. For production
workloads use auto_create_table=False and pre-create the table
out-of-band (DDL above) so the application user can be restricted
to INSERT / SELECT / UPDATE on the table only.
Example with DSN (least-privileged app schema): >>> store = OracleVectorStore( ... dsn="mydb_high", ... user="locus_app", ... password=os.environ["LOCUS_DB_PASSWORD"], ... wallet_location="~/.oci/wallets/mydb", ... dimension=1024, ... ) >>> await store.add(document) >>> results = await store.search(query_embedding, limit=5)
Example with host/service_name + pre-created table: >>> store = OracleVectorStore( ... host="adb.us-ashburn-1.oraclecloud.com", ... port=1522, ... service_name="xxx_high.adb.oraclecloud.com", ... user="locus_app", ... password=os.environ["LOCUS_DB_PASSWORD"], ... auto_create_table=False, # locus_app has DML only ... dimension=1024, ... )
Example attaching to an existing langchain_oracledb-formatted table
(column names differ, no created_at column, table already
exists):
>>> store = OracleVectorStore(
... dsn="mydb_low",
... user="locus_app",
... password=os.environ["LOCUS_DB_PASSWORD"],
... wallet_location="~/.oci/wallets/mydb",
... table_name="VECTOR_DOCUMENTS",
... content_column="text",
... created_at_column=None,
... auto_create_table=False, # don't try to CREATE TABLE
... dimension=1536, # match the existing column
... )
Source code in src/locus/rag/stores/oracle.py
build_index
async
¶
Create (or rebuild) the vector index on demand.
Use this when you set auto_create_table=False and want to
provision the index out-of-band, or when you've changed
index_type / tuning knobs after data has already been loaded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rebuild
|
bool
|
When True, drop the existing index (if any) before creating it. Lets you switch from IVF to HNSW on a populated table without DROP TABLE. |
False
|
Source code in src/locus/rag/stores/oracle.py
add
async
¶
Add a document with embedding.
Source code in src/locus/rag/stores/oracle.py
add_batch
async
¶
Add multiple documents.
Source code in src/locus/rag/stores/oracle.py
get
async
¶
Get a document by ID.
Source code in src/locus/rag/stores/oracle.py
delete
async
¶
Delete a document.
Source code in src/locus/rag/stores/oracle.py
search
async
¶
search(query_embedding: list[float], limit: int = 10, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None, *, mmr: bool = False, mmr_lambda: float = 0.5, mmr_candidate_pool: int | None = None) -> list[SearchResult]
Search for similar documents using vector similarity.
Uses Oracle's VECTOR_DISTANCE function for efficient similarity search.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query_embedding
|
list[float]
|
Query vector. |
required |
limit
|
int
|
Top-N to return. |
10
|
threshold
|
float | None
|
Optional minimum similarity score (post-MMR if enabled). |
None
|
metadata_filter
|
dict[str, Any] | None
|
Mongo-style filter dict (see :meth: |
None
|
mmr
|
bool
|
When True, apply Maximal Marginal Relevance re-ranking
to the candidate pool — fetches |
False
|
mmr_lambda
|
float
|
Trade-off in |
0.5
|
mmr_candidate_pool
|
int | None
|
Candidate pool size when MMR is on.
Defaults to |
None
|
Source code in src/locus/rag/stores/oracle.py
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | |
ensure_text_index
async
¶
Create an Oracle Text CONTEXT index on the content column.
Required only when calling :meth:hybrid_search with
use_text_index=True. The index is named idx_<table>_txt
and provides BM25-style relevance scoring via SCORE(label)
on top of CONTAINS() queries. Costs disk space and adds
index-maintenance overhead on writes — skip it if your corpus
is small enough that the LIKE fallback is fast enough.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
drop_existing
|
bool
|
When True, drop the existing index first so the call is idempotent across reconfigurations. |
False
|
Source code in src/locus/rag/stores/oracle.py
hybrid_search
async
¶
hybrid_search(query_text: str, query_embedding: list[float], *, limit: int = 10, alpha: float = 0.5, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None, use_text_index: bool = False) -> list[SearchResult]
Blend vector similarity with lexical relevance on the same row.
Each row's final score is::
alpha * vector_score + (1 - alpha) * lexical_score
where both legs are normalised to [0, 1]. alpha=1.0
collapses to pure vector search, alpha=0.0 to pure
lexical. Ranges:
vector_score:1 - distance/2for COSINE,(distance + 1) / 2for DOT,1 / (1 + distance)for EUCLIDEAN — same scoring as :meth:search.lexical_score: whenuse_text_index=True, the normalised Oracle TextSCORE(...)divided by 100 (Oracle returns 0..100). When False, the fraction of whitespace-split tokens fromquery_textthat appear as a case-insensitive substring of the content (0..1).
The text index path requires :meth:ensure_text_index to have
provisioned a CTXSYS.CONTEXT index on the content column.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query_text
|
str
|
Natural-language query string (used for the lexical leg). |
required |
query_embedding
|
list[float]
|
Query vector for the dense leg. |
required |
limit
|
int
|
Top-N to return. |
10
|
alpha
|
float
|
Blend weight in |
0.5
|
threshold
|
float | None
|
Optional minimum blended score. |
None
|
metadata_filter
|
dict[str, Any] | None
|
Same shape as :meth: |
None
|
use_text_index
|
bool
|
Drive the lexical leg through Oracle Text
instead of LIKE. Set True after calling
:meth: |
False
|
Source code in src/locus/rag/stores/oracle.py
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 | |
count
async
¶
Count documents in store.
Source code in src/locus/rag/stores/oracle.py
clear
async
¶
Delete all documents.
Source code in src/locus/rag/stores/oracle.py
OracleInDBEmbeddings ¶
OracleInDBEmbeddings(*, model_name: str, dimension: int, dsn: str | None = None, user: str = 'admin', password: str | SecretStr = '', wallet_location: str | None = None, wallet_password: str | SecretStr | None = None, host: str | None = None, port: int = 1521, service_name: str | None = None, min_pool_size: int = 1, max_pool_size: int = 5, use_batch_function: bool = False)
Bases: BaseEmbedding
Oracle 23ai/26ai in-database embedding generator.
Calls DBMS_VECTOR_CHAIN.UTL_TO_EMBEDDING /
UTL_TO_EMBEDDINGS over an async oracledb pool, parses
the VECTOR_SERIALIZE text representation into list[float],
and returns :class:EmbeddingResult for parity with the rest of
the locus embedding providers.
Example::
emb = OracleInDBEmbeddings(
model_name="ALL_MINILM_L12_V2",
dimension=384,
dsn="mydb_low",
user="locus_app",
password="...",
wallet_location="~/.oci/wallets/mydb",
)
vec = await emb.embed("hello world")
# vec.embedding is list[float] of length 384
See module docstring for prerequisite DB grants and ONNX model loading.
Source code in src/locus/rag/embeddings/oracle_indb.py
config
property
¶
Embedding configuration.
dimension is supplied by the caller (it's known a priori
for any ONNX model loaded into the DB). max_tokens /
batch_size use generic safe defaults — the DB itself
truncates per the model's tokenizer.
capabilities
property
¶
Capabilities for the in-DB embedder.
supports_batching flips with use_batch_function — when
the batch SQL is disabled the wrapper still implements
:meth:embed_batch but it loops single calls internally.
embed
async
¶
Embed a single text via UTL_TO_EMBEDDING.
Returns an :class:EmbeddingResult with the parsed vector,
the original text, and the model name. tokens is left
None because the DB doesn't surface a token count via
this call path.
Source code in src/locus/rag/embeddings/oracle_indb.py
embed_batch
async
¶
Embed multiple texts.
Uses UTL_TO_EMBEDDINGS when use_batch_function is True
(default). Falls back to a sequential loop of
UTL_TO_EMBEDDING calls when the batch function is unavailable
on the target DB (older 23ai patch levels) — still cheaper than
opening a fresh connection per text because the loop reuses one
pool connection.
Source code in src/locus/rag/embeddings/oracle_indb.py
embed_query
async
¶
Embed a query — alias of :meth:embed.
In-DB ONNX embedding models don't differentiate query vs document spaces; the same SQL path is used for both.
Source code in src/locus/rag/embeddings/oracle_indb.py
close
async
¶
embed_documents
async
¶
Embed documents. Override if model has document-specific embeddings.
OracleInDBChunker ¶
OracleInDBChunker(*, dsn: str | None = None, user: str = 'admin', password: str | SecretStr = '', wallet_location: str | None = None, wallet_password: str | SecretStr | None = None, host: str | None = None, port: int = 1521, service_name: str | None = None, max_tokens: int = 100, overlap: int = 0, by: str = 'words', split: str = 'recursively', normalize: str = 'all', **kwargs: Any)
Bases: BaseModel
Split text into chunks using DBMS_VECTOR_CHAIN.UTL_TO_CHUNKS.
Two call shapes:
- :meth:
chunk_text— pass a Python string, get back a list of chunks (each{chunk_id, text, offset, length}). - :meth:
chunk_column— point at an existing(table, id_col, text_col)and stream chunks of every row, no Python round-trip for the source text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_tokens
|
int
|
Soft cap per chunk in the unit of |
100
|
overlap
|
int
|
Token overlap between adjacent chunks (0 by default). |
0
|
by
|
str
|
Tokenisation unit. |
'words'
|
split
|
str
|
Boundary strategy. |
'recursively'
|
normalize
|
str
|
|
'all'
|
Source code in src/locus/rag/chunkers/oracle_indb.py
chunk_text
async
¶
Split a Python string into chunks, returning structured rows.
Each row carries chunk_id (1-based index from
UTL_TO_CHUNKS), the chunk text, byte offset into
the original document, and length.
Source code in src/locus/rag/chunkers/oracle_indb.py
chunk_column
async
¶
chunk_column(*, table_name: str, text_column: str, id_column: str = 'id', where: str | None = None) -> Any
Stream chunks of every row in table_name, no Python round-trip.
Yields {source_id, chunk_id, text, offset, length} per chunk.
Set where to a parameter-less SQL fragment to restrict the
scan; the chunker doesn't bind into where, so callers MUST
ensure it's free of user input (or pre-bind separately).
Source code in src/locus/rag/chunkers/oracle_indb.py
OracleADBLoader ¶
OracleADBLoader(sql: str, content_column: str, bind_params: dict[str, Any] | None = None, id_column: str | None = None, metadata_columns: list[str] | None = None, fetch_arraysize: int = 100, dsn: str | None = None, user: str = 'admin', password: str | SecretStr = '', wallet_location: str | None = None, wallet_password: str | SecretStr | None = None, host: str | None = None, port: int = 1521, service_name: str | None = None, **kwargs: Any)
Bases: BaseModel
Stream rows out of an Oracle Autonomous Database as Documents.
Example
loader = OracleADBLoader( ... dsn="mydb_low", ... user="locus_app", ... password=os.environ["LOCUS_DB_PASSWORD"], ... wallet_location="~/.oci/wallets/mydb", ... sql="SELECT id, body, author, created FROM articles WHERE topic = :topic", ... bind_params={"topic": "oracle"}, ... content_column="body", ... id_column="id", ... metadata_columns=["author", "created"], ... ) async for doc in loader.lazy_load(): ... print(doc.id, doc.content[:80]) await loader.close()
Column-to-field mapping:
content_column→ :attr:Document.content(required, must be one of the SELECTed column names — validated lazily at fetch time, since the SQL is taken verbatim).id_column→ :attr:Document.id(optional; falls back to a generated UUID hex when omitted or when the row value is NULL).metadata_columns→ :attr:Document.metadatakeyed by column name. When omitted, all non-content/non-id columns end up in metadata — matching langchain-oracle's default.
CLOB / NCLOB columns are awaited via .read() before being
placed into the Document (Oracle 26ai returns LOB locator objects
in thin mode; calling code that doesn't read them will see the
locator stringified, not the content).
Source code in src/locus/rag/loaders/oracle.py
lazy_load
async
¶
Stream rows from the SQL as Document instances.
Yields one Document per row. The cursor's arraysize is set to
:attr:fetch_arraysize so the driver bulk-fetches in batches
without us pulling everything into Python memory.
Source code in src/locus/rag/loaders/oracle.py
load
async
¶
Eagerly materialise :meth:lazy_load into a list.
Convenience wrapper for callers that don't need streaming —
e.g. small reference tables, or sync code paths that just want
to feed a vector store add_batch.
Source code in src/locus/rag/loaders/oracle.py
Retriever¶
The unified interface — combines an embedder and a store into the
retrieve() call that returns ranked, optionally reranked results.
RAGRetriever ¶
Bases: BaseModel
RAG Retriever combining embedding and vector store.
Provides a unified interface for: - Adding documents (with automatic embedding) - Retrieving relevant context for queries - Chunking large documents
Example
from locus.rag import RAGRetriever, OCIEmbeddings, OracleVectorStore
retriever = RAGRetriever( ... embedder=OCIEmbeddings(model_id="cohere.embed-english-v3.0"), ... store=OracleVectorStore(dsn="..."), ... )
Add documents¶
await retriever.add_documents( ... [ ... "Python is a programming language.", ... "Oracle Database supports vectors.", ... ] ... )
Retrieve relevant context¶
results = await retriever.retrieve("What is Python?", limit=3) for r in results.documents: ... print(f"{r.score:.2f}: {r.document.content[:50]}...")
Example with chunking
retriever = RAGRetriever( ... embedder=embedder, ... store=store, ... chunk_size=500, ... chunk_overlap=50, ... ) await retriever.add_document(long_document, metadata={"source": "manual"})
add_document
async
¶
add_document(content: str, doc_id: str | None = None, metadata: dict[str, Any] | None = None, chunk: bool = True) -> list[str]
Add a document, optionally chunking it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
Document text |
required |
doc_id
|
str | None
|
Optional document ID (auto-generated if not provided) |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata |
None
|
chunk
|
bool
|
Whether to chunk large documents |
True
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of document IDs (multiple if chunked) |
Source code in src/locus/rag/retriever.py
add_documents
async
¶
add_documents(contents: list[str], metadata: dict[str, Any] | None = None, chunk: bool = True) -> list[str]
Add multiple documents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contents
|
list[str]
|
List of document texts |
required |
metadata
|
dict[str, Any] | None
|
Optional metadata (applied to all) |
None
|
chunk
|
bool
|
Whether to chunk large documents |
True
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of all document IDs |
Source code in src/locus/rag/retriever.py
add_file
async
¶
add_file(file_path: str | Path, doc_id: str | None = None, metadata: dict[str, Any] | None = None, chunk: bool = True) -> list[str]
Add a file (text, PDF, image, or audio).
Automatically detects content type and processes accordingly: - PDFs: Extracts text (with OCR fallback for scanned docs) - Images: OCR text extraction + optional description - Audio: Speech-to-text transcription - Text: Direct processing
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
str | Path
|
Path to the file |
required |
doc_id
|
str | None
|
Optional document ID |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata |
None
|
chunk
|
bool
|
Whether to chunk large documents |
True
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of document IDs |
Example
await retriever.add_file("manual.pdf") await retriever.add_file("diagram.png") await retriever.add_file("meeting.mp3")
Source code in src/locus/rag/retriever.py
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | |
add_image
async
¶
add_image(image: bytes | str | Path, doc_id: str | None = None, metadata: dict[str, Any] | None = None, use_ocr: bool = True) -> str
Add an image document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
bytes | str | Path
|
Image bytes, base64 string, or file path |
required |
doc_id
|
str | None
|
Optional document ID |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata |
None
|
use_ocr
|
bool
|
Whether to use OCR for text extraction |
True
|
Returns:
| Type | Description |
|---|---|
str
|
Document ID |
Source code in src/locus/rag/retriever.py
add_pdf
async
¶
add_pdf(pdf: bytes | str | Path, doc_id: str | None = None, metadata: dict[str, Any] | None = None, chunk: bool = True) -> list[str]
Add a PDF document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pdf
|
bytes | str | Path
|
PDF bytes, base64 string, or file path |
required |
doc_id
|
str | None
|
Optional document ID |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata |
None
|
chunk
|
bool
|
Whether to chunk the document |
True
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of document IDs (multiple if chunked) |
Source code in src/locus/rag/retriever.py
add_audio
async
¶
add_audio(audio: bytes | str | Path, doc_id: str | None = None, metadata: dict[str, Any] | None = None) -> str
Add an audio/voice document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
audio
|
bytes | str | Path
|
Audio bytes, base64 string, or file path |
required |
doc_id
|
str | None
|
Optional document ID |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata |
None
|
Returns:
| Type | Description |
|---|---|
str
|
Document ID |
Source code in src/locus/rag/retriever.py
retrieve
async
¶
retrieve(query: str, limit: int = 5, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None) -> RetrievalResult
Retrieve relevant documents for a query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
Query text |
required |
limit
|
int
|
Maximum documents to return |
5
|
threshold
|
float | None
|
Minimum similarity score (0.0-1.0) |
None
|
metadata_filter
|
dict[str, Any] | None
|
Filter by metadata fields |
None
|
Returns:
| Type | Description |
|---|---|
RetrievalResult
|
RetrievalResult with ranked documents |
Source code in src/locus/rag/retriever.py
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | |
retrieve_text
async
¶
retrieve_text(query: str, limit: int = 5, threshold: float | None = None, separator: str = '\n\n---\n\n', spotlight: bool = True) -> str
Retrieve and concatenate relevant documents as text.
Convenience method for injecting context into prompts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
Query text |
required |
limit
|
int
|
Maximum documents to return |
5
|
threshold
|
float | None
|
Minimum similarity score |
None
|
separator
|
str
|
Text to join documents |
'\n\n---\n\n'
|
spotlight
|
bool
|
When True (default), wrap each document in
|
True
|
Returns:
| Type | Description |
|---|---|
str
|
Concatenated document contents. |
Security note
Retrieved content is untrusted data — a poisoned document can attempt an indirect prompt-injection. The spotlight wrappers let you instruct the model (in the system prompt) to treat anything inside those tags as data only, never as instructions, and to refuse to perform tool calls whose arguments are quoted verbatim from retrieved content.
Source code in src/locus/rag/retriever.py
delete_document
async
¶
clear
async
¶
count
async
¶
close
async
¶
as_tool ¶
Create a tool function for agent use.
Returns a tool that can be registered with an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Tool name |
'search_knowledge'
|
description
|
str | None
|
Tool description |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
Tool function decorated with @tool |
Source code in src/locus/rag/retriever.py
RetrievalResult
dataclass
¶
Result from RAG retrieval.
Attributes:
| Name | Type | Description |
|---|---|---|
documents |
list[SearchResult]
|
Retrieved documents sorted by relevance |
query |
str
|
Original query text |
total_results |
int
|
Total number of matches (may be > len(documents)) |
Embeddings¶
OCIEmbeddings is the default external embedder against OCI GenAI's
Cohere V3 (1024 dims, English) and V4 (multilingual) endpoints.
OpenAIEmbeddings covers the text-embedding-3-* family. For
production on Oracle 26ai prefer OracleInDBEmbeddings (above) so the
vectors stay in the database.
Providers¶
OCIEmbeddings ¶
OCIEmbeddings(model_id: str = OCIEmbeddingModel.COHERE_EMBED_ENGLISH_V3.value, compartment_id: str = '', profile_name: str = 'DEFAULT', auth_type: str = 'api_key', service_endpoint: str | None = None, **kwargs: Any)
Bases: BaseModel, BaseEmbedding
OCI GenAI Embeddings using Cohere models.
Uses Oracle Cloud Infrastructure GenAI service which hosts Cohere embedding models with enterprise-grade reliability.
Example
embedder = OCIEmbeddings( ... model_id="cohere.embed-english-v3.0", ... profile_name="DEFAULT", ... auth_type="security_token", ... ) result = await embedder.embed("Hello world") print(len(result.embedding)) # 1024
Example with compartment
embedder = OCIEmbeddings( ... model_id="cohere.embed-multilingual-v3.0", ... compartment_id="ocid1.compartment.oc1..xxx", ... )
Source code in src/locus/rag/embeddings/oci.py
config
property
¶
Get embedding configuration.
Dimension resolution: detected from first embed response if available, otherwise the fast-path hint for known models, otherwise a sensible default. The OCI Cohere family covers 384/1024/1536-dim variants.
capabilities
property
¶
OCI Cohere embeddings: native batching (96), separate
SEARCH_QUERY vs SEARCH_DOCUMENT input types, image-capable
variants for cohere.embed-*-image-v3.0.
embed
async
¶
embed_batch
async
¶
Embed multiple texts.
Source code in src/locus/rag/embeddings/oci.py
embed_query
async
¶
Embed a query for retrieval.
Uses SEARCH_QUERY input type for Cohere models.
Source code in src/locus/rag/embeddings/oci.py
embed_documents
async
¶
Embed documents for storage.
Uses SEARCH_DOCUMENT input type for Cohere models.
Source code in src/locus/rag/embeddings/oci.py
OpenAIEmbeddings ¶
OpenAIEmbeddings(model: str = 'text-embedding-3-small', api_key: str | None = None, dimensions: int | None = None, base_url: str | None = None, **kwargs: Any)
Bases: BaseEmbedding
OpenAI Embeddings provider.
Uses OpenAI's text-embedding models for generating embeddings.
Example
embedder = OpenAIEmbeddings( ... model="text-embedding-3-small", ... api_key="sk-...", ... ) result = await embedder.embed("Hello world") print(len(result.embedding)) # 1536
Initialize OpenAI embeddings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
OpenAI embedding model ID |
'text-embedding-3-small'
|
api_key
|
str | None
|
API key (defaults to OPENAI_API_KEY env var) |
None
|
dimensions
|
int | None
|
Output dimensions (for supported models) |
None
|
base_url
|
str | None
|
Custom base URL |
None
|
**kwargs
|
Any
|
Additional configuration |
{}
|
Source code in src/locus/rag/embeddings/openai.py
capabilities
property
¶
OpenAI embeddings: text-only, native batching, no separate query/doc spaces (text-embedding-3-* use the same space).
embed
async
¶
Embed a single text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Text to embed |
required |
Returns:
| Type | Description |
|---|---|
EmbeddingResult
|
EmbeddingResult with vector and metadata |
Source code in src/locus/rag/embeddings/openai.py
embed_batch
async
¶
Embed multiple texts in a single request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
texts
|
list[str]
|
List of texts to embed |
required |
Returns:
| Type | Description |
|---|---|
list[EmbeddingResult]
|
List of EmbeddingResult, one per input text |
Source code in src/locus/rag/embeddings/openai.py
close
async
¶
embed_query
async
¶
embed_documents
async
¶
Embed documents. Override if model has document-specific embeddings.
Embeddings base contract¶
BaseEmbedding ¶
Bases: ABC
Abstract base class for embedding providers.
Provides default implementations for common methods. Subclasses
override :meth:capabilities to advertise optional features, and
override :meth:embed_query/:meth:embed_documents only if
supports_query_vs_doc is True.
capabilities
property
¶
Advertised capabilities. Default is text-only, no batching, and no query/doc differentiation — override in subclasses.
embed
abstractmethod
async
¶
embed_batch
async
¶
Embed multiple texts. Override for batch optimization.
Source code in src/locus/rag/embeddings/base.py
embed_query
async
¶
embed_documents
async
¶
Embed documents. Override if model has document-specific embeddings.
EmbeddingConfig
dataclass
¶
Configuration for embedding providers.
Attributes:
| Name | Type | Description |
|---|---|---|
dimension |
int
|
Vector dimension size |
max_tokens |
int
|
Maximum tokens per request |
batch_size |
int
|
Maximum texts per batch |
EmbeddingProvider ¶
Bases: Protocol
Protocol for embedding providers.
Embedding providers convert text into dense vectors that capture semantic meaning, enabling similarity search.
Example
embedder = OCIEmbeddings(model_id="cohere.embed-english-v3.0") result = await embedder.embed("Hello world") print(len(result.embedding)) # 1024
capabilities
property
¶
Advertised capabilities. See :class:EmbeddingCapabilities.
embed
async
¶
Embed a single text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Text to embed |
required |
Returns:
| Type | Description |
|---|---|
EmbeddingResult
|
EmbeddingResult with vector and metadata |
embed_batch
async
¶
Embed multiple texts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
texts
|
list[str]
|
List of texts to embed |
required |
Returns:
| Type | Description |
|---|---|
list[EmbeddingResult]
|
List of EmbeddingResult, one per input text |
embed_query
async
¶
Embed a query for retrieval.
Some models use different embeddings for queries vs documents. Default implementation calls embed().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
Query text to embed |
required |
Returns:
| Type | Description |
|---|---|
EmbeddingResult
|
EmbeddingResult optimized for query |
Source code in src/locus/rag/embeddings/base.py
embed_documents
async
¶
Embed documents for storage.
Some models use different embeddings for queries vs documents. Default implementation calls embed_batch().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
documents
|
list[str]
|
Document texts to embed |
required |
Returns:
| Type | Description |
|---|---|
list[EmbeddingResult]
|
List of EmbeddingResult optimized for storage |
Source code in src/locus/rag/embeddings/base.py
EmbeddingResult
dataclass
¶
Result from embedding operation.
Attributes:
| Name | Type | Description |
|---|---|---|
embedding |
list[float]
|
The embedding vector |
text |
str
|
Original text that was embedded |
model |
str
|
Model used for embedding |
tokens |
int | None
|
Number of tokens used (if available) |
Vector stores¶
Alternate backends¶
Use these when you can't run on Oracle 26ai — otherwise prefer the
OracleVectorStore block above.
OpenSearchVectorStore ¶
OpenSearchVectorStore(hosts: list[str] | None = None, http_auth: tuple[str, str] | None = None, use_ssl: bool = False, index_name: str = 'locus_vectors', dimension: int = 1024, distance_metric: str = 'cosinesimil', **kwargs: Any)
Bases: BaseModel, BaseVectorStore
OpenSearch vector store with k-NN plugin.
Uses OpenSearch's k-NN plugin for efficient approximate nearest neighbor search. Supports hybrid search combining vectors with full-text search.
Example
store = OpenSearchVectorStore( ... hosts=["localhost:9200"], ... index_name="my_vectors", ... dimension=1024, ... ) await store.add(document) results = await store.search(query_embedding, limit=5)
Example with authentication
store = OpenSearchVectorStore( ... hosts=["search.example.com:443"], ... http_auth=("admin", "password"), ... use_ssl=True, ... )
Source code in src/locus/rag/stores/opensearch.py
add
async
¶
Add a document.
Source code in src/locus/rag/stores/opensearch.py
add_batch
async
¶
Add multiple documents using bulk API.
Source code in src/locus/rag/stores/opensearch.py
get
async
¶
Get a document by ID.
Source code in src/locus/rag/stores/opensearch.py
delete
async
¶
Delete a document.
Source code in src/locus/rag/stores/opensearch.py
search
async
¶
search(query_embedding: list[float], limit: int = 10, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None) -> list[SearchResult]
Search for similar documents using k-NN.
Source code in src/locus/rag/stores/opensearch.py
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | |
count
async
¶
Count documents.
clear
async
¶
Delete all documents.
Source code in src/locus/rag/stores/opensearch.py
PgVectorStore ¶
PgVectorStore(dsn: str | None = None, host: str = 'localhost', port: int = 5432, database: str = 'postgres', user: str = 'postgres', password: str | SecretStr = '', table_name: str = 'locus_vectors', dimension: int = 1536, distance_metric: str = 'cosine', **kwargs: Any)
Bases: BaseModel, BaseVectorStore
PostgreSQL pgvector store.
pgvector adds vector similarity search to PostgreSQL with: - IVFFlat and HNSW indexing - Cosine, L2, and inner product distance - Integration with existing PostgreSQL data - ACID transactions
Prerequisites
- Install pgvector extension: CREATE EXTENSION vector;
- Install asyncpg: pip install asyncpg
Example (DSN): >>> store = PgVectorStore( ... dsn="postgresql://user:pass@localhost:5432/mydb", ... table_name="documents", ... dimension=1536, ... ) >>> await store.add(document) >>> results = await store.search(query_embedding, limit=5)
Example (Individual params): >>> store = PgVectorStore( ... host="localhost", ... database="mydb", ... user="postgres", ... password="secret", ... dimension=1536, ... )
Note
The pgvector extension must be installed in your PostgreSQL database. Run: CREATE EXTENSION IF NOT EXISTS vector;
Source code in src/locus/rag/stores/pgvector.py
add
async
¶
Add a document.
Source code in src/locus/rag/stores/pgvector.py
add_batch
async
¶
Add multiple documents.
Source code in src/locus/rag/stores/pgvector.py
get
async
¶
Get a document by ID.
Source code in src/locus/rag/stores/pgvector.py
delete
async
¶
Delete a document.
Source code in src/locus/rag/stores/pgvector.py
search
async
¶
search(query_embedding: list[float], limit: int = 10, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None) -> list[SearchResult]
Search for similar documents.
Source code in src/locus/rag/stores/pgvector.py
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | |
count
async
¶
Count documents.
Source code in src/locus/rag/stores/pgvector.py
clear
async
¶
Delete all documents.
Source code in src/locus/rag/stores/pgvector.py
create_index
async
¶
Create vector index for faster similarity search.
Should be called after loading data. IVFFlat indexes require data to determine optimal list assignments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index_type
|
str | None
|
Override index type ("ivfflat" or "hnsw") |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if index was created, False if already exists |
Example
await store.add_batch(documents) await store.create_index() # Now create the index
Source code in src/locus/rag/stores/pgvector.py
has_index
async
¶
Check if vector index exists.
Source code in src/locus/rag/stores/pgvector.py
InMemoryVectorStore ¶
Bases: BaseVectorStore
In-memory vector store for testing and development.
Fast but not persistent - data is lost when process exits.
Example
store = InMemoryVectorStore(dimension=1024) await store.add(document) results = await store.search(query_embedding, limit=5)
Source code in src/locus/rag/stores/memory.py
add
async
¶
add_batch
async
¶
get
async
¶
delete
async
¶
search
async
¶
search(query_embedding: list[float], limit: int = 10, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None) -> list[SearchResult]
Search for similar documents.
Source code in src/locus/rag/stores/memory.py
count
async
¶
clear
async
¶
Vector store base contract¶
BaseVectorStore ¶
Bases: ABC
Abstract base class for vector stores.
Provides default implementations for common methods.
add
abstractmethod
async
¶
add_batch
async
¶
Add multiple documents. Override for batch optimization.
get
abstractmethod
async
¶
delete
abstractmethod
async
¶
search
abstractmethod
async
¶
search(query_embedding: list[float], limit: int = 10, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None) -> list[SearchResult]
Search for similar documents.
Source code in src/locus/rag/stores/base.py
count
async
¶
clear
async
¶
VectorStore ¶
Bases: Protocol
Protocol for vector stores.
Vector stores persist documents with embeddings and enable fast similarity search.
Example
store = OracleVectorStore(dsn="...") await store.add(doc) results = await store.search(query_embedding, limit=5)
add
async
¶
Add a document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
Document with embedding |
required |
Returns:
| Type | Description |
|---|---|
str
|
Document ID |
add_batch
async
¶
Add multiple documents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
documents
|
list[Document]
|
Documents with embeddings |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
List of document IDs |
get
async
¶
Get a document by ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc_id
|
str
|
Document identifier |
required |
Returns:
| Type | Description |
|---|---|
Document | None
|
Document or None if not found |
delete
async
¶
Delete a document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc_id
|
str
|
Document identifier |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if deleted, False if not found |
search
async
¶
search(query_embedding: list[float], limit: int = 10, threshold: float | None = None, metadata_filter: dict[str, Any] | None = None) -> list[SearchResult]
Search for similar documents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query_embedding
|
list[float]
|
Query vector |
required |
limit
|
int
|
Maximum results |
10
|
threshold
|
float | None
|
Minimum similarity score (0.0-1.0) |
None
|
metadata_filter
|
dict[str, Any] | None
|
Filter by metadata fields |
None
|
Returns:
| Type | Description |
|---|---|
list[SearchResult]
|
List of SearchResult sorted by similarity |
Source code in src/locus/rag/stores/base.py
count
async
¶
clear
async
¶
VectorStoreConfig
dataclass
¶
Configuration for vector stores.
Attributes:
| Name | Type | Description |
|---|---|---|
dimension |
int
|
Expected embedding dimension |
distance_metric |
str
|
Distance metric (cosine, l2, dot_product) |
index_type |
str
|
Index type (flat, ivf, hnsw) |
Document
dataclass
¶
Document(id: str, content: str, embedding: list[float] | None = None, metadata: dict[str, Any] = dict(), created_at: datetime = (lambda: datetime.now(UTC))(), content_type: str = 'text', raw_content: bytes | None = None)
A document with optional embedding.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique document identifier |
content |
str
|
Document text content (or extracted text for multimodal) |
embedding |
list[float] | None
|
Optional embedding vector |
metadata |
dict[str, Any]
|
Optional metadata for filtering |
created_at |
datetime
|
Creation timestamp |
content_type |
str
|
Type of content (text, image, pdf, audio) |
raw_content |
bytes | None
|
Original binary content for multimodal documents |
to_dict ¶
Convert to dictionary.
Source code in src/locus/rag/stores/base.py
from_dict
classmethod
¶
Create from dictionary.
Source code in src/locus/rag/stores/base.py
SearchResult
dataclass
¶
Result from similarity search.
Attributes:
| Name | Type | Description |
|---|---|---|
document |
Document
|
The matching document |
score |
float
|
Similarity score (0.0 to 1.0, higher is more similar) |
distance |
float | None
|
Raw distance metric (interpretation depends on distance type) |
Reranker¶
Re-score candidates after the initial vector search. Cohere V4 rerank
is the production default; the Reranker Protocol lets you plug in any
scorer.
Reranker ¶
Bases: ABC
Cross-encoder reranker over retriever candidates.
Implementations score each SearchResult.document.content against
the query string and return the candidates reordered (and optionally
truncated). The SearchResult.score field is replaced with the
reranker's relevance score (typically 0.0-1.0, higher = more relevant).
Two contracts every implementation honours:
- Empty input → empty output.
rerank("...", [])returns[]without making an API call. - No mutation of input. The original list is left untouched; a
new list of new
SearchResultinstances is returned. Safe to call from concurrent contexts.
Example::
from locus.rag.reranker import CohereReranker
reranker = CohereReranker(model="cohere.rerank-v3.5", top_n=5)
top = await reranker.rerank("hepcidin role in iron", candidates)
rerank
abstractmethod
async
¶
Return candidates reordered (and optionally truncated) by
relevance to query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The query string to score candidates against. |
required |
candidates
|
list[SearchResult]
|
The retriever's hits, typically wide (top-K=50). |
required |
Returns:
| Type | Description |
|---|---|
list[SearchResult]
|
A new list of |
list[SearchResult]
|
length ≤ |
list[SearchResult]
|
Each returned |
list[SearchResult]
|
relevance score in |
list[SearchResult]
|
is preserved on |
Source code in src/locus/rag/reranker/base.py
CohereReranker ¶
CohereReranker(*, model: str = DEFAULT_COHERE_RERANK_MODEL, compartment_id: str | None = None, profile_name: str = 'DEFAULT', auth_type: str | None = None, config_file: str = '~/.oci/config', service_endpoint: str | None = None, region: str = 'us-chicago-1', top_n: int | None = None, max_chunks_per_document: int | None = None, max_tokens_per_document: int | None = None, _client: Any = None)
Bases: Reranker
Reranker backed by OCI Generative AI Cohere rerank_text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
OCI Cohere rerank model id. Defaults to
|
DEFAULT_COHERE_RERANK_MODEL
|
compartment_id
|
str | None
|
OCI compartment OCID for the inference call. Required unless the OCI config profile carries one (most profiles do — auto-derived from the profile's tenancy when unset). |
None
|
profile_name
|
str
|
OCI config profile name. Defaults to |
'DEFAULT'
|
config_file
|
str
|
Path to the OCI config file. Defaults to
|
'~/.oci/config'
|
service_endpoint
|
str | None
|
Override the service endpoint URL. Default is
derived from |
None
|
region
|
str
|
OCI region (default |
'us-chicago-1'
|
top_n
|
int | None
|
Trim the reranked output to the top N candidates. |
None
|
max_chunks_per_document
|
int | None
|
Pass-through to the OCI request; limits
how many overlapping windows each document is split into for
scoring. |
None
|
max_tokens_per_document
|
int | None
|
Pass-through to the OCI request; truncates each candidate before scoring. |
None
|
Notes
The OCI SDK call is sync; the reranker dispatches it to a
threadpool via :func:asyncio.to_thread so callers can await
it from the same async retriever context as the embedding +
vector-store calls.
Source code in src/locus/rag/reranker/cohere_oci.py
rerank
async
¶
See :meth:Reranker.rerank.
Source code in src/locus/rag/reranker/cohere_oci.py
Multimodal processing¶
Convert non-text inputs (PDF text + OCR, image OCR, audio
transcription) into the same Document shape the retriever consumes.
ContentType ¶
Bases: str, Enum
Supported content types.
MultimodalProcessor ¶
Unified processor for all content types.
Example
processor = MultimodalProcessor() result = await processor.process(Path("doc.pdf")) print(result.text)
result = await processor.process(image_bytes, content_type=ContentType.IMAGE)
Source code in src/locus/rag/multimodal.py
detect_content_type ¶
Detect content type from content or path.
Source code in src/locus/rag/multimodal.py
process
async
¶
process(content: bytes | str | Path, content_type: ContentType | None = None, **kwargs: Any) -> ProcessedContent
Process content of any supported type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
bytes | str | Path
|
Content to process (bytes, string, or path) |
required |
content_type
|
ContentType | None
|
Explicit content type (auto-detected if None) |
None
|
**kwargs
|
Any
|
Additional processor options |
{}
|
Returns:
| Type | Description |
|---|---|
ProcessedContent
|
ProcessedContent with extracted text |
Source code in src/locus/rag/multimodal.py
ProcessedContent
dataclass
¶
ProcessedContent(text: str, content_type: ContentType, metadata: dict[str, Any] = dict(), chunks: list[str] | None = None, raw_content: bytes | None = None)
Result of content processing.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
Extracted/generated text for embedding |
content_type |
ContentType
|
Original content type |
metadata |
dict[str, Any]
|
Additional metadata from processing |
chunks |
list[str] | None
|
If content was chunked, the individual chunks |
raw_content |
bytes | None
|
Original binary content (for storage) |
process_content
async
¶
process_content(content: bytes | str | Path, content_type: ContentType | None = None, **kwargs: Any) -> ProcessedContent
Process any content type and extract text for embedding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
bytes | str | Path
|
Content to process |
required |
content_type
|
ContentType | None
|
Optional content type hint |
None
|
Returns:
| Type | Description |
|---|---|
ProcessedContent
|
ProcessedContent with extracted text |
Example
result = await process_content(Path("document.pdf")) embeddings = await embedder.embed(result.text)
Source code in src/locus/rag/multimodal.py
Tool wiring¶
Expose a retriever as an agent tool so the model can call it like any
other function. Use create_rag_tool for a one-shot retrieval call
and create_rag_context_tool when you want the agent to inject
retrieved context into its own response.
RAGToolkit ¶
Collection of RAG tools for comprehensive knowledge access.
Provides multiple tools for different retrieval patterns: - search: Find specific documents with scores - context: Get formatted context for prompts - lookup: Find a specific document by ID
Example
toolkit = RAGToolkit(retriever) agent = Agent( ... model=model, ... tools=toolkit.get_tools(), ... )
Source code in src/locus/rag/tools.py
get_tools ¶
search_tool ¶
context_tool ¶
lookup_tool ¶
Get the lookup tool.
Source code in src/locus/rag/tools.py
create_rag_tool ¶
create_rag_tool(retriever: RAGRetriever, name: str = 'search_knowledge', description: str | None = None, limit: int = 5, threshold: float | None = 0.5) -> Any
Create a RAG search tool for agent use.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
retriever
|
RAGRetriever
|
RAGRetriever instance |
required |
name
|
str
|
Tool name |
'search_knowledge'
|
description
|
str | None
|
Tool description |
None
|
limit
|
int
|
Default number of results |
5
|
threshold
|
float | None
|
Default similarity threshold |
0.5
|
Returns:
| Type | Description |
|---|---|
Any
|
Decorated tool function |
Example
retriever = RAGRetriever(embedder=embedder, store=store) tool = create_rag_tool(retriever)
agent = Agent( ... model=model, ... tools=[tool], ... )
Source code in src/locus/rag/tools.py
create_rag_context_tool ¶
create_rag_context_tool(retriever: RAGRetriever, name: str = 'get_context', description: str | None = None, limit: int = 3) -> Any
Create a RAG tool that returns context as formatted text.
This is useful when you want the agent to receive context directly without processing individual results.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
retriever
|
RAGRetriever
|
RAGRetriever instance |
required |
name
|
str
|
Tool name |
'get_context'
|
description
|
str | None
|
Tool description |
None
|
limit
|
int
|
Number of documents to include |
3
|
Returns:
| Type | Description |
|---|---|
Any
|
Decorated tool function |