liveBook · Manning

Semantic matching

As explained in Financial AI in Practice

Semantic matching is a retrieval technique that compares representations of content according to meaning rather than exact wording.

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

How Financial AI in Practice covers it

How deep it goes
Explains shared-space geometric matching and cosine scoring, while separating user-only signals from content comparison.
Examples
Contrasts speculative content for a risk-taking user with educational and macro-oriented content for a saver.
What it assumes
Requires user and content vectors in the same embedding space and separates user-only signals from content matching.
What you can do after
Apply cosine similarity to match precomputed user vectors with financial content, while allowing policy rules to override unsuitable recommendations.
How it connects
Connects embeddings, cosine similarity, personalization, cold-start recommendations, and suitability guardrails.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Financial AI in Practice. The section links point to the parts of the book it draws on.