use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct RAGVectorConfig {
pub enabled: bool,
#[serde(default = "default_embedding_model")]
pub embedding_model: String,
#[serde(default)]
pub sparse_embeddings: bool,
#[serde(default = "default_sparse_model")]
pub sparse_model: String,
#[serde(default = "default_vector_path")]
pub vector_path: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct RagChunkingConfig {
#[serde(default = "default_chunking_strategy")]
pub chunking_strategy: String,
#[serde(default = "default_chunk_size")]
pub chunk_size: usize,
#[serde(default = "default_chunk_overlap")]
pub chunk_overlap: usize,
#[serde(default = "default_min_chunk_size")]
pub min_chunk_size: usize,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct RagSearchConfig {
#[serde(default = "default_search_strategy")]
pub search_strategy: String,
#[serde(default = "default_search_limit")]
pub search_limit: usize,
#[serde(default)]
pub search_threshold: f32,
#[serde(default)]
pub hybrid_weights: Option<HybridWeightsConfig>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct RagRerankingConfig {
#[serde(default)]
pub rerank_enabled: bool,
#[serde(default = "default_reranker_model")]
pub reranker_model: String,
#[serde(default = "default_rerank_weight")]
pub rerank_weight: f32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct RagConfig {
pub vector: RAGVectorConfig,
pub chunking: RagChunkingConfig,
pub search: RagSearchConfig,
pub rerank: RagRerankingConfig,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct HybridWeightsConfig {
#[serde(default = "default_semantic_weight")]
pub semantic: f32,
#[serde(default = "default_bm25_weight")]
pub bm25: f32,
#[serde(default = "default_fuzzy_weight")]
pub fuzzy: f32,
}
impl Default for HybridWeightsConfig {
fn default() -> Self {
Self {
semantic: 0.5,
bm25: 0.3,
fuzzy: 0.2,
}
}
}
impl Default for RAGVectorConfig {
fn default() -> Self {
Self {
enabled: false,
embedding_model: default_embedding_model(),
sparse_embeddings: false,
sparse_model: default_sparse_model(),
vector_path: default_vector_path(),
}
}
}
impl Default for RagChunkingConfig {
fn default() -> Self {
Self {
chunking_strategy: default_chunking_strategy(),
chunk_size: default_chunk_size(),
chunk_overlap: default_chunk_overlap(),
min_chunk_size: default_min_chunk_size(),
}
}
}
impl Default for RagSearchConfig {
fn default() -> Self {
Self {
search_strategy: default_search_strategy(),
search_limit: default_search_limit(),
search_threshold: 0.0,
hybrid_weights: None,
}
}
}
impl Default for RagRerankingConfig {
fn default() -> Self {
Self {
rerank_enabled: false,
reranker_model: default_reranker_model(),
rerank_weight: default_rerank_weight(),
}
}
}
fn default_semantic_weight() -> f32 {
0.5
}
fn default_bm25_weight() -> f32 {
0.3
}
fn default_fuzzy_weight() -> f32 {
0.2
}
fn default_vector_path() -> String {
"./data/vectors".to_string()
}
fn default_embedding_model() -> String {
"bge-small-en-v1.5".to_string()
}
fn default_sparse_model() -> String {
"splade-pp-en-v1".to_string()
}
fn default_chunking_strategy() -> String {
"word".to_string()
}
fn default_chunk_size() -> usize {
200
}
fn default_chunk_overlap() -> usize {
50
}
fn default_min_chunk_size() -> usize {
20
}
fn default_search_strategy() -> String {
"semantic".to_string()
}
fn default_search_limit() -> usize {
10
}
fn default_reranker_model() -> String {
"bge-reranker-base".to_string()
}
fn default_rerank_weight() -> f32 {
0.6
}