xz-rerank 0.1.1

检索结果重排序 — 本地多信号融合 + 远程 Rerank API 适配
Documentation
use async_trait::async_trait;

use crate::error::RerankError;
use crate::traits::SignalPlugin;
use crate::types::RerankCandidate;

use crate::types::RecencyMode;

/// 时间近因性信号
#[derive(Debug)]
pub struct RecencySignal {
    mode: RecencyMode,
    now_ms: u64,
}

impl RecencySignal {
    /// 创建时间近因性信号
    ///
    /// `mode` 指定近因性衰减模式(线性、指数或不衰减)。
    /// 当前时间通过系统时钟自动获取。
    pub fn new(mode: RecencyMode) -> Self {
        let now_ms = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_millis() as u64;
        Self { mode, now_ms }
    }

    /// 设置自定义当前时间(用于测试或离线重排)
    pub fn with_now(mut self, now_ms: u64) -> Self {
        self.now_ms = now_ms;
        self
    }
}

#[async_trait]
impl SignalPlugin for RecencySignal {
    fn name(&self) -> &str {
        "recency"
    }

    fn weight_key(&self) -> &'static str {
        "recency"
    }

    async fn score(&self, _query: &str, candidate: &RerankCandidate) -> Result<f32, RerankError> {
        let created_at = match candidate.created_at {
            Some(t) => t,
            None => return Ok(0.5), // 无时间信息,中性分数
        };

        let age_seconds = (self.now_ms.saturating_sub(created_at) as f64) / 1000.0;

        let score = match &self.mode {
            RecencyMode::NoDecay => 1.0,
            RecencyMode::LinearDecay { max_age_days } => {
                let max_age_s = max_age_days * 86400.0;
                (1.0 - age_seconds / max_age_s).max(0.0)
            }
            RecencyMode::ExponentialDecay { decay_rate } => (-decay_rate * age_seconds).exp(),
        };

        Ok(score as f32)
    }
}