File size: 4,541 Bytes
2e818da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""Registered RAG retrieval pipeline versions.

Task 7 froze ``rag-naive-v1`` as the observed baseline and, from genuine
SigNoz-backed diagnosis (see ``docs/observability/diagnostic-workflow.md``),
picked deduplication of near-duplicate candidates -- over-fetch a larger raw
pool, remove near-duplicates, then truncate back to the caller's requested
count -- as the one architectural variable for ``rag-dedup-v2``.

This module is the single source of truth for what a "pipeline version"
means behaviourally. It does not itself touch Chroma, embeddings, or
telemetry -- ``ChromaDBClient.query_observed`` (``app/rag/chromadb_client.py``)
reads a :class:`PipelineVersion` from here and gates its over-fetch/dedup
logic on ``dedup_enabled``/``overfetch_factor``.

Design contract (do not weaken without updating Task 8's report):

- ``rag-naive-v1`` is immutable: ``dedup_enabled=False``, ``overfetch_factor=1``,
  forever. A test in ``tests/rag/test_pipeline_version.py`` pins this exact
  tuple so an accidental edit here fails loudly.
- The *default* (no pipeline version requested -- ``None``) must always
  resolve to exactly ``rag-naive-v1``'s behavior. Ordinary product traffic
  (Chat, LEARN_NODE, flashcards, quiz, StudyBuddy) never passes an explicit
  pipeline version, so it is always on this default path and is therefore
  provably unaffected by anything registered here.
- An explicitly requested but unregistered version string is a hard error
  (``UnknownPipelineVersionError``), per the brief's "reject evaluation
  startup when the requested version is unknown" -- silently falling back to
  v1 behavior for a typo'd version name would make a v1/v2 comparison
  silently meaningless.
"""

from __future__ import annotations

from dataclasses import dataclass

# Over-fetch factor for rag-dedup-v2: request `requested_top_k * factor` raw
# candidates from Chroma before dedup+truncate, so removing near-duplicates
# can still backfill up to the caller's original requested count instead of
# only ever shrinking the naive top-5 in place (the exact trap the plan
# preamble's acceptance gate calls out: "the improvement is not caused solely
# by returning fewer required candidates"). 3x is a deliberately modest
# choice -- big enough that Task 7's finding of low document_diversity
# (1.58/5 average) has real room to be corrected by pulling in alternate
# documents' chunks, small enough that it doesn't turn `chroma.vector_search`
# into a new dominant cost on top of the already-dominant `embedding.query`
# stage (a 3x-larger candidate pool over a ~10k-chunk shared collection is
# still a small single Chroma call, not a new order of magnitude).
DEDUP_V2_OVERFETCH_FACTOR = 3

DEFAULT_PIPELINE_VERSION = "rag-naive-v1"
CURRENT_PRODUCT_PIPELINE_VERSION = "rag-structured-hybrid-v3"


@dataclass(frozen=True)
class PipelineVersion:
    """One registered, behaviorally-complete retrieval pipeline configuration."""

    name: str
    dedup_enabled: bool
    overfetch_factor: int


class UnknownPipelineVersionError(ValueError):
    """Raised when an explicitly requested pipeline version is not registered."""


_REGISTRY: dict[str, PipelineVersion] = {
    "rag-naive-v1": PipelineVersion(
        name="rag-naive-v1", dedup_enabled=False, overfetch_factor=1
    ),
    "rag-dedup-v2": PipelineVersion(
        name="rag-dedup-v2",
        dedup_enabled=True,
        overfetch_factor=DEDUP_V2_OVERFETCH_FACTOR,
    ),
}


def registered_versions() -> tuple[str, ...]:
    """All registered pipeline version names, for error messages and tests."""
    return tuple(sorted(_REGISTRY))


def get_pipeline_version(name: str | None) -> PipelineVersion:
    """Resolve a pipeline version name to its behavior.

    ``name=None`` (the default for every ordinary product call site) always
    resolves to ``rag-naive-v1`` -- unspecified pipeline version is never
    ambiguous and never requires the caller to know version names exist.

    Raises :class:`UnknownPipelineVersionError` for any non-``None`` name that
    isn't registered, rather than silently falling back to v1 -- an
    evaluation run that mistypes a version string must fail loudly, not
    quietly measure the wrong pipeline.
    """
    if name is None:
        return _REGISTRY[DEFAULT_PIPELINE_VERSION]
    try:
        return _REGISTRY[name]
    except KeyError as exc:
        raise UnknownPipelineVersionError(
            f"Unknown pipeline version {name!r}. Registered versions: "
            f"{', '.join(registered_versions())}"
        ) from exc