Skip to main content
Retriever fusion weights automatically adapt based on how each user interacts with search results. Instead of manually tuning text: 0.7, image: 0.3, the system learns from clicks, purchases, and feedback to discover the optimal blend for every user — using Thompson Sampling (a multi-armed bandit algorithm) with hierarchical fallback from personal to demographic to global priors. Auto-Tune closes the gap between “search works” and “search works for this user” without building a separate recommendation system.

How It Works

1

User searches

A query arrives with a user_id. The system looks up that user’s learned fusion weights — or falls back to segment-level or global weights if the user is new.
2

Results ranked by fusion weights

The feature search stage runs each embedding search and fuses results using the personalized weights. Early on, weights are exploratory (high variance). As data accumulates, they stabilize around what works for this user.
3

User interacts

The user clicks, purchases, skips, or provides feedback. Each interaction is recorded with the document ID, position, and the feature URI that produced the match.
4

Weights updated

Positive interactions (clicks, purchases) increase the weight of the feature that surfaced the result. Negative signals (skips, negative feedback) decrease it. Different interaction types carry different reward magnitudes — a purchase is a stronger signal than a click.
5

Next search reflects preferences

The next query from this user samples from the updated weight distributions. After dozens of interactions, the system converges on near-optimal weights while still occasionally exploring alternatives.
Thompson Sampling: Beta distributions evolve from uniform to peaked as interactions accumulate

Quick Start

1. Create a retriever with learned fusion

curl -X POST "https://api.mixpeek.com/v1/retrievers" \
  -H "Authorization: Bearer $MP_API_KEY" \
  -H "X-Namespace: $MP_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{
    "retriever_name": "product-search-personalized",
    "collection_identifiers": ["col_products"],
    "input_schema": {
      "query": { "type": "text", "description": "Search query", "required": true },
      "user_id": { "type": "text", "description": "User identifier", "required": true }
    },
    "stages": [
      {
        "stage_name": "Personalized Search",
        "stage_type": "filter",
        "config": {
          "stage_id": "feature_search",
          "parameters": {
            "searches": [
              {
                "feature_uri": "mixpeek://text_extractor@v1/multilingual_e5_large_instruct_v1",
                "query": { "input_mode": "text", "value": "{{INPUT.query}}" },
                "top_k": 100
              },
              {
                "feature_uri": "mixpeek://multimodal_extractor@v1/vertex_multimodal_embedding",
                "query": { "input_mode": "text", "value": "{{INPUT.query}}" },
                "top_k": 100
              }
            ],
            "fusion": "learned",
            "learning_config": {
              "context_features": ["INPUT.user_id"],
              "reward_map": {
                "click": 1.0,
                "purchase": 3.0,
                "add_to_cart": 2.0,
                "negative_feedback": -2.0
              },
              "min_interactions": 5,
              "exploration_bonus": 1.0,
              "decay_factor": 0.995
            },
            "final_top_k": 25
          }
        }
      }
    ]
  }'

2. Execute with a user ID

curl -X POST "https://api.mixpeek.com/v1/retrievers/$RETRIEVER_ID/execute" \
  -H "Authorization: Bearer $MP_API_KEY" \
  -H "X-Namespace: $MP_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {
      "query": "wireless earbuds noise canceling",
      "user_id": "user_456"
    }
  }'
With zero interactions, this behaves like RRF (uniform weights). The response includes an execution_id and learned_fusion_context metadata for interaction tracking.

3. Post interactions — results automatically improve

curl -X POST "https://api.mixpeek.com/v1/retrievers/interactions" \
  -H "Authorization: Bearer $MP_API_KEY" \
  -H "X-Namespace: $MP_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{
    "retriever_id": "'$RETRIEVER_ID'",
    "feature_id": "doc_product_789",
    "interaction_type": ["click", "purchase"],
    "position": 2,
    "user_id": "user_456",
    "session_id": "sess_abc",
    "execution_id": "exec_from_step_2",
    "feature_uri": "mixpeek://text_extractor@v1/multilingual_e5_large_instruct_v1"
  }'
After enough interactions, the same search for user_456 returns results personalized to their feature preferences. If this user consistently engages with text-matched results over image-matched ones, the text feature weight increases for their queries.

Key Concepts

Reward Signals

Configure how different interaction types (clicks, purchases, feedback) influence learned fusion weights. Customize the reward map, handle negative signals, and tune temporal decay.

Rollout & Safety

Safely deploy learned fusion with traffic splitting, shadow mode, kill switches, per-user opt-out, and weight bounds. Includes a recommended rollout plan.

Learned Fusion Deep Dive

How Thompson Sampling works under the hood — Beta distributions, exploration vs. exploitation, and the math behind weight convergence.

Evaluations

Measure whether learned fusion actually improves retrieval quality. Compare NDCG, precision, and recall against static fusion baselines.

Configuration Reference

The learning_config object is set inside the feature search stage parameters alongside fusion: "learned":
FieldTypeDefaultDescription
context_featuresstring[]["INPUT.user_id"]Input fields used for personal-level weight learning. Each value references an INPUT.* field from the retriever’s input_schema.
demographic_featuresstring[][]Input fields for segment-level fallback (e.g., "INPUT.user_segment"). Used when a user has insufficient personal history.
reward_signalstring"click"Deprecated. Single interaction type used as the learning signal. Use reward_map instead.
reward_mapobjectSee Reward SignalsMaps interaction types to reward magnitudes. Positive values reinforce; negative values penalize.
min_interactionsinteger5Minimum interactions before using personal-level weights. Below this threshold, the system falls back to demographic or global weights.
exploration_bonusfloat1.0Initial multiplier for distribution variance. Higher values increase exploration (more weight variability).
exploration_decayfloat0.99Per-interaction decay applied to the exploration bonus. Gradually shifts from exploration to exploitation.
exploration_floorfloat0.1Minimum exploration bonus. Prevents the system from fully exploiting — there is always some chance of trying alternative weights.
decay_factorfloat0.995Per-day exponential decay applied to older interactions. 1.0 disables decay (interactions never fade).
decay_window_daysinteger365Interactions older than this are ignored entirely.
min_weightfloat0.05Minimum weight any feature can receive after sampling. Prevents a feature from being silenced.
max_weightfloat0.95Maximum weight any feature can receive after sampling. Prevents one feature from completely dominating.
rollout_pctfloat100.0Percentage of requests (0-100) that use learned weights. The rest use static fusion. Uses deterministic bucketing so a user does not flip-flop between treatments.
shadow_modebooleanfalseWhen true, learned weights are computed and logged but static fusion results are served. Use this to evaluate learned fusion before going live.

Hierarchical Fallback

Not every user has enough interaction history for personalized weights. The system uses a four-level fallback:
LevelContextMin InteractionsWhen Used
PersonalIndividual userConfigurable (default 5)User has enough interactions for reliable personal weights
DemographicUser segment1User is new, but their segment (e.g., “enterprise”, “consumer”) has data
GlobalAll users1No segment data available; uses aggregate behavior across all users
PriorUniform0No interactions at all; falls back to equal weights (equivalent to RRF)
The context_features field controls personal-level resolution (typically ["INPUT.user_id"]). The demographic_features field enables segment-level fallback (e.g., ["INPUT.plan_tier"]).
A new user starts at the Global or Prior level and automatically graduates to Personal as they interact with results — no configuration changes needed. The transition happens transparently at query time.