- Introduction
- Core Functionality: The Matchmaking Engine
- AI/LLM Integration: The Intelligence Layer
- Founder's Perspective: Taking this to Production
- Technical Details & Setup
- Challenges Faced & Solutions
- Evaluation Criteria Alignment
- License
- Contact
At BreadButter, connecting creative talent with specific client needs is at our core. Clients often provide briefs in natural language ("I need a travel photographer in Goa..."), while our talent database comprises 10,000+ creators with diverse skills, styles, and budgets. This project aims to build the "intelligence layer" to efficiently bridge this gap.
Goal: To design and implement a backend system that takes a creative brief as input and returns a ranked list of recommended talents with clear scores and rationale, significantly optimizing the matchmaking process for BreadButter.
The matchmaking engine is built around a metrics-driven, weighted scoring model. It operates by comparing a structured client brief against a database of structured talent profiles. Each point of alignment (e.g., matching category, location, skills, budget fit) contributes a specific score, while mismatches incur penalties. The total aggregated score determines the talent's rank for a given brief.
The system is prototyped using Python with the Pandas library, allowing for efficient data manipulation and clear algorithmic implementation within a Jupyter Notebook environment.
To enable programmatic matching, both client briefs and talent profiles are represented in structured JSON formats.
-
StructuredBrief.json: Defines the schema for standardized client brief inputs. (View Schema) -
TalentProfile.json: Defines the schema for comprehensive creative talent profiles. (View Schema)
These schemas are populated by:
structured_briefs.json: A dataset of 25 diverse, pre-structured client briefs.talent_profiles.json: A dataset of 20 diverse, dummy creative talent profiles.
The calculate_match_score function is the heart of the engine. It takes one structured brief and one talent profile as input and computes a total_score along with a rationale (a list of reasons for the score).
Key Matching Criteria & Weights (WEIGHTS dictionary):
| Criteria | Weight (Points) | Logic / Rationale |
|---|---|---|
category_match |
+20 |
Perfect match on the core creative category (e.g., "Photography" brief to "Photography" talent). This is fundamental. |
location_perfect_onsite |
+15 |
Talent's base_city exactly matches the brief's On-site city. |
location_onsite_travel |
+10 |
Talent is travel_willingness for On-site brief, but not local. |
location_remote_match |
+8 |
Talent is remote_willingness for Remote brief. |
skill_match_perfect |
+15 |
100% overlap between brief.required_skills_tools and talent.skills/talent.tools_proficient_in. Graded scores for partial matches. |
specialization_match_partial |
+5 (per match) |
Overlap between brief's needs (from required_skills_tools, style_keywords) and talent's specializations. Uses fuzzy matching for flexibility. |
portfolio_keyword_match |
+5 (per match) |
Overlap between brief.style_keywords and talent.portfolio_keywords (e.g., "minimalist", "vibrant"). |
budget_perfect_fit |
+18 |
Talent's budget range is fully within the brief's budget range. Graded scores for partial overlaps or negotiable budgets. |
experience_perfect |
+10 |
Talent has >= 5 years of experience (considered senior). +5 for 3-4 years. |
reviews_high |
+8 |
High client review scores (4.5-5.0). Graded scores for lower ratings. |
availability_available |
+5 |
Talent is currently marked as "Available". |
penalty_category_mismatch |
-50 |
Base penalty for core category mismatch. |
penalty_disqualify_category |
-500 |
Heavy penalty added to penalty_category_mismatch to effectively disqualify talents outside the primary category. This ensures only relevant professional types are ranked. |
penalty_location_mismatch |
-40 |
Adjusted penalty for significant location mismatch (e.g., on-site brief, talent not local and not willing to travel). This was initially -100 but reduced to allow category-matching talents to still achieve positive, albeit lower, scores. |
penalty_missing_required_skill |
-15 |
Penalty if brief.required_skills_tools explicitly states a skill/tool not found in the talent's profile. |
penalty_unavailability |
-10 |
Talent is marked "Busy" or "On Holiday". |
penalty_budget_too_low |
-20 |
Client's maximum budget is below the talent's minimum expectation. |
The entire matchmaking process, from data loading to ranked recommendations, is demonstrated within the BreadButter_Matchmaking_Engine.ipynb Jupyter Notebook. The output includes:
- Sample raw data.
- The aggregated
matches_dfshowing all brief-talent scores. - Detailed Top 3 Matches for Each Brief, complete with their
Total Scoreand aRationaleexplaining each contributing factor (both positive and negative).
AI and LLMs play a transformative role in automating data ingestion and enriching profiles, reducing friction for creators and enabling smarter matchmaking at scale.
- Objective: Automate the conversion of unstructured, natural-language client briefs into the precise
StructuredBrief.jsonformat required by the matchmaking engine. - Implementation: The
convert_human_brief_to_structured_llmfunction leverages the Google Gemini API (gemini-1.5-pro-latestmodel).- It takes a raw text brief and a comprehensive JSON schema as input.
- It uses Gemini's advanced instruction-following capabilities and
response_mime_type="application/json"to ensure the output is always valid and structured JSON. - Technical Detail: Since Gemini's
generate_contentmethod does not directly support thesystemrole in theprompt_partslist, thesysteminstructions are cleverly embedded as the initial part of theuserrole's content, ensuring the model understands its task without API errors.
- Benefit to BreadButter:
- Significant Automation: Eliminates manual data entry for incoming briefs.
- Enhanced Scalability: Processes a high volume of briefs quickly and consistently.
- Data Consistency: Ensures all briefs conform to the same structure, improving matching reliability.
While not live in this specific notebook's code, the TalentProfile.json data is designed with AI enrichment in mind, reflecting a holistic "Smart Talent Profile Builder" (Project 02) approach.
- Image/Video Tagging: AI Vision models (e.g., OpenAI Vision, Replicate models) could analyze talent portfolio media to automatically extract relevant keywords (
portfolio_keywords), describing style, themes, and content (e.g., "minimalist," "candid," "product photography"). This populates crucial matching criteria automatically. - AI-Generated Bios & Summaries: LLMs (e.g., GPT) could synthesize concise and compelling professional bios or project summaries from unstructured inputs (resumes, LinkedIn profiles, personal websites), reducing manual onboarding effort for talent.
- Auto-detection of Skill Sets & Categories: LLMs can analyze work experience and project descriptions to automatically identify specific
skillsandspecializations, enriching profiles for more precise matching.
- Semantic Matching with Embeddings: For true high-dimensional matching, convert entire briefs and talent profiles (including detailed text from bios, project descriptions, skills) into numerical vectors (embeddings) using models like OpenAI Embeddings or Cohere Embeddings. This allows matching based on semantic meaning rather than just keyword overlap. Vector databases (e.g.,
pgvectorfor PostgreSQL, or specialized solutions like Pinecone/Weaviate) enable efficient nearest-neighbor search across thousands of profiles. - Dynamic Weight Adjustment: Utilize machine learning or reinforcement learning to dynamically adjust the weights within the matchmaking algorithm based on the success rate of past recommendations (e.g., client satisfaction with matches).
As a founder building BreadButter, my approach to taking this intelligence layer to production would focus on reliability, scalability, continuous improvement, and user value:
- Data Volume: For 10,000+ profiles and growing, the current brute-force matching (each brief vs. all talents) becomes inefficient.
- Solution 1: Pre-filtering/Indexing: Implement basic filters (e.g., category, location, budget range) to narrow down the talent pool before applying the full scoring algorithm.
- Solution 2: Vector Search Integration: As mentioned above, integrate a vector database. This would allow for lightning-fast semantic similarity searches across millions of profiles, returning a highly relevant subset for detailed scoring.
- Solution 3: Talent Clustering: Group similar talents together. Match briefs to clusters first, then to talents within promising clusters.
- Brief Ingestion: The AI brief structuring would run as an asynchronous process (e.g., via a message queue like RabbitMQ or Kafka) to avoid blocking the client-facing application if LLM calls are slow or rate-limited.
- Infrastructure: Deploy the matching engine as a dedicated microservice, allowing it to scale independently based on demand.
- Error Handling & Retries: Implement robust error handling for external API calls (Gemini, potential future embedding APIs) with exponential backoff and retry mechanisms.
- Monitoring & Alerting: Set up monitoring for API call success rates, response times, and algorithm performance. Alerting for significant drops in matching accuracy or prolonged API outages.
- Caching: Cache frequently requested talent profiles and recently processed briefs to speed up lookups.
- Match Feedback UI: Design a simple UI for clients to provide explicit feedback on the quality of recommended talents ("Good Match," "Bad Match," "Reason?").
- Implicit Feedback: Track engagement metrics (e.g., profile views, messages sent, gigs initiated) from recommendations to infer match quality.
- Continuous Improvement: Use this feedback data (both explicit and implicit) to constantly refine the matchmaking algorithm's weights or train more sophisticated machine learning models, creating a self-improving system.
- Time-based Matching: Incorporate talent availability calendar and project deadlines more granularly.
- Behavioral Data: Integrate data on past successful matches, preferred partners, and declining rates for clients/talents.
- Two-Sided Matching: Allow talents to set preferences for briefs/clients, creating a mutual matching score.
- A/B Testing: Continuously A/B test different scoring weights or algorithm versions to empirically determine which provides the best outcomes.
- Language: Python 3.x
- Core Libraries:
pandas: For data manipulation and analysis.numpy: Numerical operations.json: JSON data handling.fuzzywuzzy&python-Levenshtein: For flexible string matching (skills, specializations).google-generativeai: For integrating Google Gemini API.
- Environment: Jupyter Notebook (for interactive development and demonstration).
breadbutter_intelligence/ ├── BreadButter_Matchmaking_Engine.ipynb # Main Jupyter Notebook with all code & analysis ├── structured_briefs.json # Sample structured client briefs data ├── talent_profiles.json # Sample structured creative talent profiles data ├── StructuredBrief.json # JSON Schema definition for briefs ├── TalentProfile.json # JSON Schema definition for talent profiles ├── README.md # This file └── requirements.txt # Python dependencies
- Clone the Repository:
git clone [https://github.com/](https://github.com/)[Your_GitHub_Handle]/breadbutter_intelligence.git cd breadbutter_intelligence - Create and Activate a Virtual Environment:
python -m venv venv # On Windows: .\venv\Scripts\activate # On macOS/Linux: source venv/bin/activate
- Install Dependencies:
pip install -r requirements.txt
- Set Google Gemini API Key (Crucial for AI Bonus):
- Get your API Key from Google AI Studio.
- Set it as an environment variable in your terminal before launching Jupyter:
# On Windows (Command Prompt): set GOOGLE_API_KEY="YOUR_GEMINI_API_KEY" # On Windows (PowerShell): $env:GOOGLE_API_KEY="YOUR_GEMINI_API_KEY" # On macOS/Linux: export GOOGLE_API_KEY="YOUR_GEMINI_API_KEY"
- From the
breadbutter_intelligencedirectory (with virtual environment active):jupyter notebook
- Your browser will open. Click on
BreadButter_Matchmaking_Engine.ipynb. - Go to
Kernel->Restart & Run Allto execute the entire notebook and see the results.
Building this intelligence layer involved several interesting challenges and required iterative refinement:
- Initial Negative Scores: The first iteration of the matchmaking algorithm consistently produced negative scores, even for seemingly good matches.
- Solution: Discovered that the
category_mismatchpenalty was too high and was incorrectly applied due to subtle string differences. This led to the next solution.
- Solution: Discovered that the
- Inconsistent Category Naming: "Video Editing" in briefs versus "Video Editor" in talent profiles led to false negative category matches.
- Solution: Standardized all category names across both
structured_briefs.jsonandtalent_profiles.jsonto ensure exact matches.
- Solution: Standardized all category names across both
- Overly Aggressive Disqualification for Mismatches: Even after fixing naming, a simple category mismatch would entirely drown out any other positive match points.
- Solution: Introduced a two-tiered penalty system for categories: a base
penalty_category_mismatch(-50) and a strongpenalty_disqualify_category(-500). This ensures irrelevant talents (different core category) are truly disqualified from ranking highly, while preventing non-disqualifying mismatches from ruining a score entirely.
- Solution: Introduced a two-tiered penalty system for categories: a base
- Negative Scores due to Location Penalty: Even after category fix, many category-matching talents still had negative scores because of a very high
penalty_location_mismatch(-100).- Solution: Adjusted the
penalty_location_mismatchto a more balanced value (-40). This still penalizes non-local talents but allows them to retain a positive score if other matching criteria are strong, leading to a more nuanced ranking.
- Solution: Adjusted the
- Python
NameError: name 'json' is not defined': A common error when Jupyter kernel restarts or imports are not executed.- Solution: Emphasized
Kernel -> Restart & Run Alland confirmedimport jsonin the first code cell to ensure all modules are loaded.
- Solution: Emphasized
- Google Gemini API Errors (
insufficient_quota,Content with system role is not supported): Initial attempts to use the Gemini API encountered specific API errors related to billing and prompt formatting.- Solution: First, ensured
GOOGLE_API_KEYwas correctly set as an environment variable. Then, identified and implemented the specific Gemini API prompt structure fix: embedding thesysteminstructions directly into theuserrole's content, as thesystemrole is not supported in the directgenerate_contentmethod for the chosen model. This demonstrated robust API integration and debugging.
- Solution: First, ensured
This project demonstrates:
- Thoughtfulness of Approach & Architecture: Clear weighted scoring, structured data, and iterative refinement.
- Ownership Mindset: End-to-end implementation from problem definition to AI integration and production considerations.
- AI/LLM Awareness: Practical application of LLMs for data structuring and strategic vision for advanced AI use.
- Code Readability & Structure: Clear functions, comments, and Jupyter Notebook organization.
- Creativity and Real-world Applicability: Addresses a direct business problem for a talent marketplace.
- Balance of Product Thinking & Technical Depth: Integrates user needs (reduced friction, better matches) with technical solutions (algorithms, AI, scalability).
This project is open-sourced under the MIT License.
For any questions or further discussion, feel free to reach out:
- Name: Sanjay Kirti
- Email: Lukebrushwood@gmail.com