AI Learning System
Relevant source files
The following files were used as context for generating this wiki page:
The AI Learning System is a per-workspace preference engine that adjusts the ranking of social opportunities based on user feedback. It extracts signals from collected documents and user interactions to create a localized preference model. This model nudges the deterministic baseline scores of opportunities to better align with specific workspace interests without storing private raw content.
Sources: lib/learning/signals.ts, test/learning-preference.test.ts:80-85, lib/db/schema.ts:316-320
Architecture Overview
The system operates by capturing user outcome events, deriving preference signals from those events, and applying calculated weights during the ranking phase.
The diagram shows the flow from user feedback to model generation, and how that model influences the scoring of new opportunities.
Sources: lib/learning/signals.ts:167-175, lib/learning/rank.ts, test/learning-preference.test.ts:327-335
Signal Extraction
Signals are derived from three primary dimensions: topics, sources, and intents. The system sanitizes these signals into short, bounded tokens to prevent raw content leakage.
Learning Dimensions
| Dimension | Description | Extraction Logic |
|---|---|---|
| Topic | Keywords from document text. | Tokenizes title and body, removes stop words, and picks top terms. |
| Source | The origin of the post. | Maps document IDs to specific source IDs (e.g., a specific Subreddit or GH Repo). |
| Intent | User buying/pain intent. | Derived from the "intent rung" (0-4) calculated by the pipeline. |
Sources: lib/learning/signals.ts:108-142, lib/learning/types.ts
Signal Constraints
- Key Pattern: Every key follows the format
<dimension>:<term>. Sources: lib/learning/signals.ts:91-93 - Term Bounding: Terms are limited to 40 characters. Sources: lib/learning/signals.ts:86
- Privacy Guard: The system rejects any weight payload carrying raw fields like
contentMd,url, orauthor. Sources: lib/learning/signals.ts:228-245
Preference Modeling
The buildPreferenceModel function aggregates workspace decisions into a versioned model. A model remains inert until it clears specific evidence thresholds.
Evidence Thresholds
| Config Key | Default Value | Purpose |
|---|---|---|
minWorkspaceEvidence | Varies | Minimum total decisions required to activate the model for a workspace. |
minKeyEvidence | Varies | Minimum decisions per signal key before the key can influence ranking. |
maxTotalDelta | 0.15 (typical) | Maximum adjustment allowed to the baseline score. |
Sources: lib/learning/config.ts, test/learning-preference.test.ts:90-110
Weight Calculation
The system uses a shrinkage approach for signalWeight. A key requires repeated agreement (positives vs. negatives) before it can move scores.
export function signalWeight(positives: number, negatives: number, config: LearningConfig): number {
const evidence = positives + negatives;
if (evidence <= 0 || evidence < config.minKeyEvidence) return 0;
const net = (positives - negatives) / evidence;
const shrunk = net * (evidence / (evidence + config.priorStrength));
return round6(clamp(shrunk, -config.maxAbsWeight, config.maxAbsWeight));
}
Sources: lib/learning/signals.ts:153-160
Ranking and Adjustment
The rankWithPreferences function applies the model to an opportunity's baseline features.
Ranking Logic
- Baseline Scoring: Computes the initial score using
BASELINE_FEATURE_WEIGHTS(Fit, Intent, Evidence, Momentum, Timing). Sources: lib/opportunities/features.ts:98-105 - Model Lookup: Matches the opportunity's topics, source, and intent against the preference model's weights.
- Delta Application: Sums the weights of matching signals, multipling by
DIMENSION_FACTORS. Sources: lib/learning/signals.ts:163-165 - Clamping: Clamps the total adjustment to the
maxTotalDeltadefined in configuration. Sources: test/learning-preference.test.ts:223-230
Ranking Sequence
The sequence illustrates how the Rank Engine interacts with the Preference Model to refine an opportunity's score.
Sources: lib/learning/rank.ts, test/learning-preference.test.ts:205-215
Data Model
The workspacePreferenceModel table stores the versioned weights for each workspace.
| Field | Type | Description |
|---|---|---|
workspaceId | uuid | The target workspace. |
version | integer | Incremental version of the preference model. |
weights | jsonb | Array of PreferenceWeightRow objects (key, weight, evidence). |
active | boolean | Whether the model has cleared the evidence threshold. |
enabled | boolean | Operator switch to enable/disable learning for the workspace. |
Sources: lib/db/schema.ts:316-350
Outcome Feedback Mapping
User interactions are mapped to learning decisions to feed the model.
- Positive Decisions:
useful,acted_on. - Negative Decisions:
rejected,not_useful. - Ignored Events:
draft_edit,utm_click(do not influence learning).
Sources: test/learning-preference.test.ts:303-310, lib/db/schema.ts:291-300