Semantic matching personalizes financial content by comparing user and content vectors in a shared vector space. Cosine similarity scores how closely a user's Financial DNA aligns with an article's meaning, so recommendations can work even without interaction history. section 13.3.2 section 13.5
For a reliable content match:
- Compare vectors produced in the same embedding space; vectors from different embedding models are not valid matches. section 13.3.2
- Exclude user-only signals from content comparison, and use them separately for ranking and guardrails. section 13.3.2
- Let suitability and jurisdiction rules override candidate recommendations when needed. section 13.5
Matching financial content
A risk-taking user is matched with volatile, speculative content, while a saver receives educational and macro-oriented material. The alignment comes from vector similarity rather than a hand-written rule for each user. section 13.3.2
Listing 13.8 The semantic matching engine [2]
import numpy as np
import pickle
from sklearn.metrics.pairwise import cosine_similarity
# 1. Setup: Load the "Mock Vector DB"
# (In a real app, this would be a connection to Pinecone/Milvus)
# We assume 'content_store.pkl' contains the list of vectorized articles generated in the pipeline.
with open("content_store.pkl", "rb") as f:
content_store = pickle.load(f)
def get_recommendations(user_id, content_list, top_k=2):
# 2. Fetch the User Vector (Pre-computed Financial DNA)
user_row = users.loc[users['user_id'] == user_id]
if user_row.empty:
return []
# Reshape for scikit-learn (1 sample, 1536 features)
user_vec = np.array(user_row.iloc[0]['financial_dna']).reshape(1, -1)
# 3. Score Content Alignment
results = []
for item in content_list:
content_vec = np.array(item['vector']).reshape(1, -1)
# Cosine Similarity: 1.0 = Perfect Match, 0.0 = No Relation
score = cosine_similarity(user_vec, content_vec)[0][0]
results.append((item['title'], item['type'], score))
# 4. Rank by Relevance
return sorted(results, key=lambda x: x[2], reverse=True)[:top_k]
# --- Test Scenario: Comparing Tribes ---
# We select representative users from our clusters to validate the logic.
degen_user = users.loc[users['cluster_id'] == 0, 'user_id'].iloc[0] # Cluster 0: Degen
saver_user = users.loc[users['cluster_id'] == 3, 'user_id'].iloc[0] # Cluster 3: Saver
print(f"--- Recommendations for Degen User ({degen_user}) ---")
for title, ctype, score in get_recommendations(degen_user, content_store):
print(f"[{ctype}] {title} (Score: {score:.3f})")
print(f"\n--- Recommendations for Saver User ({saver_user}) ---")
for title, ctype, score in get_recommendations(saver_user, content_store):
print(f"[{ctype}] {title} (Score: {score:.3f})")
Inspect the recommendation-engine listing for an implementation using user and content vectors with cosine similarity. section 13.3.2
