Skip to content

Commit c842d69

Browse files
authored
Merge pull request #1843 from are-ces/lcore-1426-byok-config-refactoring
LCORE-1426: RAG Config refactoring
2 parents 262629e + 8f705bb commit c842d69

41 files changed

Lines changed: 2532 additions & 1629 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/devel_doc/openapi.json

Lines changed: 270 additions & 160 deletions
Large diffs are not rendered by default.

docs/user_doc/byok_guide.md

Lines changed: 163 additions & 120 deletions
Large diffs are not rendered by default.

docs/user_doc/rag_guide.md

Lines changed: 98 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,36 @@ Both strategies can be enabled independently via the `rag` section of `lightspee
3737

3838
For **runtime-created** vector stores (`POST /v1/vector-stores`), configure
3939
[`vector_store`](#configure-dynamic-vector-store-providers) instead of
40-
`byok_rag`. BYOK registers static corpora with a fixed `vector_db_id`; dynamic
40+
`rag.byok.stores`. BYOK registers static corpora with a fixed `vector_db_id`; dynamic
4141
providers only declare capacity (provider id, storage, default embeddings).
4242

43+
### Inline RAG chunk flow
44+
45+
```mermaid
46+
flowchart TD
47+
subgraph Sources["Source Fetching"]
48+
B1["BYOK Store 1"] --> BPool
49+
B2["BYOK Store 2"] --> BPool
50+
BN["BYOK Store N"] --> BPool
51+
BPool["BYOK Pool\ncapped at rag.byok.max_chunks"]
52+
OKP["OKP (Solr)\ncapped at rag.okp.max_chunks"]
53+
end
54+
55+
BPool --> Pool["Merged Pool\n(all chunks, sorted by score)"]
56+
OKP --> Pool
57+
58+
Pool --> Decision{Reranker\nenabled?}
59+
60+
Decision -->|Yes| Rerank["Cross-Encoder Rerank\n+ BYOK score boost"]
61+
Decision -->|No| Cut
62+
63+
Rerank --> Cut["Top K cut\nrag.retrieval.inline.max_chunks"]
64+
65+
Cut --> Context["Final Inline RAG Context"]
66+
```
67+
68+
Each BYOK store is queried in parallel, and the merged BYOK results are capped at `rag.byok.max_chunks` total. OKP fetches up to `rag.okp.max_chunks`. Together these form the reranking pool. If the reranker is enabled, the full pool is reranked with a cross-encoder and BYOK score boosts are applied. The result is capped at `rag.retrieval.inline.max_chunks`.
69+
4370
The **Embedding Model** is used to convert queries and documents into vector representations for similarity matching.
4471

4572
> [!NOTE]
@@ -63,32 +90,28 @@ Use the [`rag-content`](https://github.com/lightspeed-core/rag-content) reposito
6390
Download a local embedding model such as `sentence-transformers/all-mpnet-base-v2` by using the script in [`rag-content`](https://github.com/lightspeed-core/rag-content) or manually download and place in your desired path.
6491

6592
> [!NOTE]
66-
> The embedding model can also be downloaded automatically at first start-up (which will be slower). In the `byok_rag` section of `lightspeed-stack.yaml`, specify a supported model name as `embedding_model` instead of a local path. The model will be downloaded to the `~/.cache/huggingface/hub` folder.
93+
> The embedding model can also be downloaded automatically at first start-up (which will be slower). In the `rag.byok.stores` section of `lightspeed-stack.yaml`, specify a supported model name as `embedding_model` instead of a local path. The model will be downloaded to the `~/.cache/huggingface/hub` folder.
6794
6895
---
6996

7097
## Configure BYOK Knowledge Sources
7198

72-
> [!WARNING]
73-
> **Deprecated in 0.7.0**: The top-level `byok_rag`, `rag`, `okp`, and `reranker` sections
74-
> are deprecated. In 0.7.0, all RAG-related configuration is unified under a single `rag`
75-
> section: stores move to `rag.byok.stores` (with `backend` instead of `rag_type`),
76-
> retrieval strategies move to `rag.retrieval.inline`/`rag.retrieval.tool`, OKP moves to
77-
> `rag.okp`, and the reranker moves to `rag.retrieval.inline.reranker`.
78-
> See the [v0.7.0 Migration Guide](migrations/v0.7.0.md) for full details and examples.
7999

80-
BYOK knowledge sources are configured in the `byok_rag` section of `lightspeed-stack.yaml`. The required configuration is automatically generated at startup when using `make run`, `make run-stack`, `docker-compose`, or library mode — no manual enrichment is needed.
100+
101+
BYOK knowledge sources are configured in the `rag.byok.stores` section of `lightspeed-stack.yaml`. The required configuration is automatically generated at startup when using `make run`, `make run-stack`, `docker-compose`, or library mode — no manual enrichment is needed.
81102

82103
### FAISS example
83104

84105
```yaml
85-
byok_rag:
86-
- rag_id: custom-index
87-
rag_type: inline::faiss
88-
embedding_model: sentence-transformers/all-mpnet-base-v2 # or path to local model
89-
embedding_dimension: 768
90-
vector_db_id: vs_8c94967b-81cc-4028-a294-9cfac6fd9ae2 # Generated by rag-content during index creation
91-
db_path: <path-to-vector-index> # e.g. /home/USER/vector_db/faiss_store.db
106+
rag:
107+
byok:
108+
stores:
109+
- rag_id: custom-index
110+
backend: faiss
111+
embedding_model: sentence-transformers/all-mpnet-base-v2 # or path to local model
112+
embedding_dimension: 768
113+
vector_db_id: vs_8c94967b-81cc-4028-a294-9cfac6fd9ae2 # Generated by rag-content during index creation
114+
db_path: <path-to-vector-index> # e.g. /home/USER/vector_db/faiss_store.db
92115
```
93116
94117
Where:
@@ -117,17 +140,19 @@ Each pgvector-backed table follows this schema:
117140
> The `vector_store_id` (e.g. `rhdocs`) is used to point to the table named `vector_store_rhdocs` in the specified database, which stores the vector embeddings.
118141

119142
```yaml
120-
byok_rag:
121-
- rag_id: pgvector-example
122-
rag_type: remote::pgvector
123-
embedding_model: sentence-transformers/all-mpnet-base-v2
124-
embedding_dimension: 768
125-
vector_db_id: rhdocs # becomes PostgreSQL table 'vector_store_rhdocs'
126-
host: ${env.POSTGRES_HOST}
127-
port: ${env.POSTGRES_PORT}
128-
db: ${env.POSTGRES_DATABASE}
129-
user: ${env.POSTGRES_USER}
130-
password: ${env.POSTGRES_PASSWORD}
143+
rag:
144+
byok:
145+
stores:
146+
- rag_id: pgvector-example
147+
backend: pgvector
148+
embedding_model: sentence-transformers/all-mpnet-base-v2
149+
embedding_dimension: 768
150+
vector_db_id: rhdocs # becomes PostgreSQL table 'vector_store_rhdocs'
151+
host: ${env.POSTGRES_HOST}
152+
port: ${env.POSTGRES_PORT}
153+
db: ${env.POSTGRES_DATABASE}
154+
user: ${env.POSTGRES_USER}
155+
password: ${env.POSTGRES_PASSWORD}
131156
```
132157

133158
> [!NOTE]
@@ -302,21 +327,23 @@ The OKP (Offline Knowledge Portal) Solr Vector IO is a read-only vector search p
302327

303328
```yaml
304329
rag:
305-
inline:
306-
- okp # inject OKP context before the LLM request
307-
tool:
308-
- okp # expose OKP as the file_search tool
309-
310-
okp:
311-
rhokp_url: ${env.RH_SERVER_OKP} # OKP base URL (env var or literal URL)
312-
offline: true # true = use parent_id for source URLs (offline mode)
313-
# false = use reference_url (online mode)
330+
retrieval:
331+
inline:
332+
sources:
333+
- okp # inject OKP context before the LLM request
334+
tool:
335+
sources:
336+
- okp # expose OKP as the file_search tool
337+
okp:
338+
rhokp_url: ${env.RH_SERVER_OKP} # OKP base URL (env var or literal URL)
339+
offline: true # true = use parent_id for source URLs (offline mode)
340+
# false = use reference_url (online mode)
314341
```
315342

316-
Set `rhokp_url` to the base URL of your OKP server. Use `${env.RH_SERVER_OKP}` to read the URL from the environment; when omitted or empty, a default from the application constants is used.
343+
Set `rhokp_url` to the base URL of your OKP server under `rag.okp`. Use `${env.RH_SERVER_OKP}` to read the URL from the environment; when omitted or empty, a default from the application constants is used.
317344

318345
> [!NOTE]
319-
> When `okp` is listed in `rag.inline` or `rag.tool`, Lightspeed Stack automatically enriches
346+
> When `okp` is listed in `rag.retrieval.inline.sources` or `rag.retrieval.tool.sources`, Lightspeed Stack automatically enriches
320347
> the underlying configuration at startup with the required `vector_io` provider and `registered_resources`
321348
> entries for the OKP vector store. No manual registration is needed.
322349

@@ -342,14 +369,15 @@ curl -sX POST http://localhost:8080/v1/query \
342369
343370
**Query Filtering:**
344371
345-
To further filter the OKP context, set the `chunk_filter_query` field in the `okp` section of
372+
To further filter the OKP context, set the `chunk_filter_query` field in the `rag.okp` section of
346373
`lightspeed-stack.yaml`. Filters follow the OKP key:value format and are applied as a static
347374
`fq` parameter on every OKP search request.
348375
349376
```yaml
350-
okp:
351-
rhokp_url: ${env.RH_SERVER_OKP}
352-
chunk_filter_query: "product:*openshift*"
377+
rag:
378+
okp:
379+
rhokp_url: ${env.RH_SERVER_OKP}
380+
chunk_filter_query: "product:*openshift*"
353381
```
354382

355383
Per-request filtering is also available on all inference endpoints via request field **`solr`**: `mode` (`semantic`, `hybrid`, or `lexical`) and `filters` (key:value format). Legacy payloads that omit `mode`/`filters` and send filter key:value pairs at the top level still work with `mode` set to `hybrid`.
@@ -368,28 +396,24 @@ Example:
368396

369397
**Prerequisites:**
370398

371-
- The OKP server must be running and accessible at the URL given in `okp.rhokp_url` (or `${env.RH_SERVER_OKP}`).
399+
- The OKP server must be running and accessible at the URL given in `rag.okp.rhokp_url` (or `${env.RH_SERVER_OKP}`).
372400
For instructions on how to pull and run the OKP image, visit: https://github.com/lightspeed-core/lightspeed-providers/lightspeed_stack_providers/providers/remote/solr_vector_io/solr_vector_io/README.md
373401

374402

375403
**Chunk volume:**
376404

377-
> [!WARNING]
378-
> **Deprecated in 0.7.0**: The chunk limit constants below are replaced by configurable
379-
> fields in `lightspeed-stack.yaml` (`rag.byok.max_chunks`, `rag.okp.max_chunks`,
380-
> `rag.retrieval.inline.max_chunks`, `rag.retrieval.tool.max_chunks`).
381-
> See the [v0.7.0 Migration Guide](migrations/v0.7.0.md) for details.
382405

383406
OKP and BYOK scores are not directly comparable (different scoring systems), so
384-
`score_multiplier` (a BYOK-only concept) does not apply to OKP results. To control
385-
the number of retrieved chunks, set the constants in `src/constants.py`:
407+
`score_multiplier` (a BYOK-only concept) does not apply to OKP results. However, when
408+
the reranker is enabled, it normalizes scores across sources using a cross-encoder model.
409+
To control the number of retrieved chunks, configure `max_chunks` in `lightspeed-stack.yaml`:
386410

387-
| Constant | Value | Description |
388-
|----------|-------|-------------|
389-
| `INLINE_RAG_MAX_CHUNKS` | 10 | Hard upper bound on the final merged inline RAG chunks (BYOK + OKP) delivered to the LLM |
390-
| `OKP_RAG_MAX_CHUNKS` | 5 | Fetch hint for OKP (Inline RAG); controls how many chunks enter the reranking pool |
391-
| `BYOK_RAG_MAX_CHUNKS` | 10 | Fetch hint for BYOK stores (Inline RAG); controls how many chunks enter the reranking pool |
392-
| `TOOL_RAG_MAX_CHUNKS` | 10 | Max chunks retrieved via Tool RAG (`file_search`); independent from `INLINE_RAG_MAX_CHUNKS` |
411+
| Config path | Default | Description |
412+
|-------------|---------|-------------|
413+
| `rag.retrieval.inline.max_chunks` | 10 | Hard upper bound on the final merged inline RAG chunks (BYOK + OKP) delivered to the LLM |
414+
| `rag.okp.max_chunks` | 5 | Fetch limit for OKP (Inline RAG); controls how many chunks enter the reranking pool |
415+
| `rag.byok.max_chunks` | 10 | Fetch limit for BYOK stores (Inline RAG); controls how many chunks enter the reranking pool |
416+
| `rag.retrieval.tool.max_chunks` | 10 | Max chunks retrieved via Tool RAG (`file_search`); independent from inline max_chunks |
393417

394418
**Limitations:**
395419

@@ -399,9 +423,7 @@ the number of retrieved chunks, set the constants in `src/constants.py`:
399423

400424
# Complete Configuration Reference
401425

402-
To enable RAG functionality, configure the `byok_rag` and `rag` sections in
403-
your `lightspeed-stack.yaml`. Add `vector_store` when you also need
404-
runtime `POST /v1/vector-stores` capacity.
426+
To enable RAG functionality, configure the `rag` section (including `rag.byok.stores` and `rag.retrieval`) in your `lightspeed-stack.yaml`. Add `vector_store` when you also need runtime `POST /v1/vector-stores` capacity.
405427

406428
Below is an example of a working `lightspeed-stack.yaml` configuration with:
407429

@@ -420,14 +442,6 @@ service:
420442
port: 8080
421443
auth_enabled: false
422444

423-
byok_rag:
424-
- rag_id: ocp-docs
425-
rag_type: inline::faiss
426-
embedding_model: sentence-transformers/all-mpnet-base-v2
427-
embedding_dimension: 768
428-
vector_db_id: vs_3a7f9b2e-45dc-4e1a-b8f2-1c9d0e3f5a6b
429-
db_path: /home/USER/lightspeed-stack/vector_dbs/ocp_docs/faiss_store.db
430-
431445
# Optional: capacity for runtime POST /v1/vector-stores (not a static corpus)
432446
vector_store:
433447
default_provider: example
@@ -440,18 +454,24 @@ vector_store:
440454
path: /home/USER/lightspeed-stack/vector_dbs/example/faiss_store.db
441455

442456
rag:
443-
inline:
444-
- ocp-docs
445-
tool:
446-
- ocp-docs
457+
byok:
458+
stores:
459+
- rag_id: ocp-docs
460+
backend: faiss
461+
embedding_model: sentence-transformers/all-mpnet-base-v2
462+
embedding_dimension: 768
463+
vector_db_id: vs_3a7f9b2e-45dc-4e1a-b8f2-1c9d0e3f5a6b
464+
db_path: /home/USER/lightspeed-stack/vector_dbs/ocp_docs/faiss_store.db
465+
retrieval:
466+
inline:
467+
sources:
468+
- ocp-docs
469+
tool:
470+
sources:
471+
- ocp-docs
447472
```
448473
449-
BYOK providers and registered resources are generated at startup from
450-
`byok_rag`. Dynamic providers and create defaults are generated from
451-
`vector_store` during unified synthesis. Embedding models for
452-
those providers are registered automatically when needed. Inference models
453-
and providers must still be configured separately (for example in your
454-
baseline / profile `run.yaml`).
474+
BYOK providers and registered resources are generated at startup from `rag.byok.stores`. Dynamic providers and create defaults are generated from `vector_store` during unified synthesis. Embedding models for those providers are registered automatically when needed. Inference models and providers must still be configured separately (for example in your baseline / profile `run.yaml`).
455475

456476
---
457477

examples/lightspeed-stack-byok-okp-rag.yaml

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,40 +34,45 @@ quota_handlers:
3434
scheduler:
3535
# scheduler ticks in seconds
3636
period: 10
37-
byok_rag:
38-
- rag_id: ocp-docs # referenced in rag.inline / rag.tool
39-
rag_type: inline::faiss
40-
embedding_model: sentence-transformers/all-mpnet-base-v2
41-
embedding_dimension: 768
42-
vector_db_id: vs_123 # Vector store ID (from index generation)
43-
db_path: /tmp/ocp.faiss
44-
score_multiplier: 1.0 # Weight for this vector store's results (Inline RAG only)
45-
- rag_id: knowledge-base # referenced in rag.inline / rag.tool
46-
rag_type: inline::faiss
47-
embedding_model: sentence-transformers/all-mpnet-base-v2
48-
embedding_dimension: 768
49-
vector_db_id: vs_456 # Vector store ID (from index generation)
50-
db_path: /tmp/kb.faiss
51-
score_multiplier: 1.2 # Weight for this vector store's results (Inline RAG only)
52-
5337
# RAG configuration
5438
rag:
55-
# Inline RAG: context injected before the LLM request from the listed sources
56-
# List rag_ids from byok_rag, or 'okp' to include OKP
57-
inline:
58-
- ocp-docs
59-
- knowledge-base
60-
- okp
61-
# Tool RAG: LLM can call file_search on demand to retrieve context
62-
# List rag_ids from byok_rag, or 'okp' to include OKP
63-
# Omit to disable tool RAG
64-
tool:
65-
- ocp-docs
66-
- knowledge-base
39+
byok:
40+
max_chunks: 10 # Max total chunks across all BYOK stores
41+
stores:
42+
- rag_id: ocp-docs # Referenced in retrieval.inline / retrieval.tool
43+
backend: faiss
44+
embedding_dimension: 1024
45+
vector_db_id: vs_123 # Llama-stack vector_store_id
46+
db_path: /tmp/ocp.faiss
47+
score_multiplier: 1.0 # Weight for this vector store's results (Inline RAG only)
48+
- rag_id: knowledge-base # Referenced in retrieval.inline / retrieval.tool
49+
backend: faiss
50+
embedding_dimension: 384
51+
vector_db_id: vs_456 # Llama-stack vector_store_id
52+
db_path: /tmp/kb.faiss
53+
score_multiplier: 1.2 # Weight for this vector store's results (Inline RAG only)
54+
55+
# OKP provider settings (only used when 'okp' is listed in retrieval sources)
56+
okp:
57+
offline: true # true = use parent_id for source URLs, false = use reference_url
58+
max_chunks: 5 # Max chunks fetched from OKP
59+
# Additional Solr filter query applied to every OKP search request.
60+
# Use Solr boolean syntax
61+
# chunk_filter_query: "product:*ansible* AND product:*openshift*"
6762

68-
# OKP provider settings (only used when 'okp' is listed in rag.inline or rag.tool)
69-
okp:
70-
offline: true # true = use parent_id for source URLs, false = use reference_url
71-
# Additional Solr filter query applied to every OKP search request.
72-
# Use Solr boolean syntax
73-
# chunk_filter_query: "product:*ansible* AND product:*openshift*"
63+
retrieval:
64+
# Inline RAG: context injected before the LLM request from the listed sources
65+
# List rag_ids from byok stores, or 'okp' to include OKP
66+
inline:
67+
sources:
68+
- ocp-docs
69+
- knowledge-base
70+
- okp
71+
max_chunks: 10 # Cap on merged inline result
72+
# Tool RAG: LLM can call file_search on demand to retrieve context
73+
# List rag_ids from byok stores, or 'okp' to include OKP
74+
tool:
75+
sources:
76+
- ocp-docs
77+
- knowledge-base
78+
max_chunks: 10 # Tool RAG limit

examples/quota-limiter-configuration-sqlite.yaml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,6 @@ conversation_cache:
3333
ssl_mode: disable
3434
gss_encmode: disable
3535

36-
#byok_rag:
37-
# - rag_id: ocp_docs
38-
# rag_type: inline::faiss
39-
# embedding_dimension: 1024
40-
# vector_db_id: vector_byok_1
41-
# db_path: /tmp/ocp.faiss
42-
# - rag_id: knowledge_base
43-
# rag_type: inline::faiss
44-
# embedding_dimension: 384
45-
# vector_db_id: vector_byok_2
46-
# db_path: /tmp/kb.faiss
47-
4836
quota_handlers:
4937
sqlite:
5038
db_path: quota.sqlite

src/app/endpoints/rags.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
RAGInfoResponse,
2525
RAGListResponse,
2626
)
27-
from models.config import Action, ByokRag
27+
from models.config import Action, RagStore
2828
from utils.endpoints import check_configuration_loaded
2929

3030
logger = get_logger(__name__)
@@ -112,7 +112,7 @@ async def rags_endpoint_handler(
112112
raise HTTPException(**response.model_dump()) from e
113113

114114

115-
def _resolve_rag_id_to_vector_db_id(rag_id: str, byok_rags: list[ByokRag]) -> str:
115+
def _resolve_rag_id_to_vector_db_id(rag_id: str, byok_rags: list[RagStore]) -> str:
116116
"""Resolve a user-facing rag_id to the llama-stack vector_db_id.
117117
118118
Checks if the given ID matches a rag_id in the BYOK config and returns
@@ -178,7 +178,7 @@ async def get_rag_endpoint_handler(
178178

179179
# Resolve user-facing rag_id to llama-stack vector_db_id
180180
vector_db_id = _resolve_rag_id_to_vector_db_id(
181-
rag_id, configuration.configuration.byok_rag
181+
rag_id, configuration.configuration.rag.byok.stores
182182
)
183183

184184
try:

0 commit comments

Comments
 (0)