Discovery Agent
The Discovery Agent finds exceptional wedding vendors on Instagram before they're popular. It leverages multiple curator accounts and Instagram's own recommendation algorithm to surface quality content.
Overview
Mission: Find exceptional vendors before they're popular
Strategy: Instagram-native discovery via curator accounts + AI quality filtering
Phase: Introduced in Phase 2 (Weeks 5-8)
Instagram Curator Strategy
Curator Accounts
We operate multiple Instagram accounts focused on specific regions and styles:
const CURATOR_ACCOUNTS = [
{
username: '@vows_au_modern',
region: 'Australia',
style: 'modern_minimalist',
followers: 'quality_vendors'
},
{
username: '@vows_au_boho',
region: 'Australia',
style: 'bohemian_rustic',
followers: 'quality_vendors'
},
{
username: '@vows_mel_luxury',
region: 'Melbourne',
style: 'luxury_elegant',
followers: 'quality_vendors'
},
{
username: '@vows_syd_garden',
region: 'Sydney',
style: 'garden_outdoor',
followers: 'quality_vendors'
}
];
Discovery Process
class DiscoveryAgent {
async discoverVendors(
region: string,
style: string,
limit: number = 50
): Promise<Vendor[]> {
// 1. Select appropriate curator account
const curator = this.selectCurator(region, style);
// 2. Leverage Instagram's algorithm
const suggestions = await this.getInstagramSuggestions(curator);
// 3. Quality filter with AI
const qualityScores = await this.evaluateQuality(suggestions);
// 4. Return high-quality vendors
return suggestions
.filter((v, i) => qualityScores[i] > 0.75)
.slice(0, limit);
}
private selectCurator(region: string, style: string): CuratorAccount {
// Find best matching curator
return CURATOR_ACCOUNTS.find(
c => c.region === region && c.style === style
) || CURATOR_ACCOUNTS[0]; // Fallback to default
}
}
Instagram Integration
Getting Suggestions
async getInstagramSuggestions(curator: CuratorAccount): Promise<Vendor[]> {
const suggestions = [];
// Method 1: Explore page suggestions
const explorePage = await this.getExplorePage(curator);
suggestions.push(...explorePage.accounts);
// Method 2: "Suggested for you" on posts
const suggestedAccounts = await this.getSuggestedAccounts(curator);
suggestions.push(...suggestedAccounts);
// Method 3: Hashtag exploration
const hashtagVendors = await this.exploreHashtags(
curator,
['#melbournewedding', '#weddingphotographer', '#weddingvenue']
);
suggestions.push(...hashtagVendors);
// Deduplicate
return this.deduplicate(suggestions);
}
Curator Account Management
class CuratorAccountManager {
async engageWithContent(curator: CuratorAccount) {
// Like high-quality posts (signal to Instagram algorithm)
const posts = await this.getRecentPosts(curator.following);
for (const post of posts.slice(0, 20)) {
if (await this.isHighQuality(post)) {
await this.like(curator, post);
// Save exceptional content
if (post.qualityScore > 0.9) {
await this.save(curator, post);
}
}
// Rate limiting
await this.delay(30000); // 30 seconds between actions
}
}
async followQualityVendors(curator: CuratorAccount) {
// Follow new quality vendors in target niche
const candidates = await this.findVendorCandidates(curator);
for (const vendor of candidates) {
const quality = await this.evaluateVendor(vendor);
if (quality > 0.8) {
await this.follow(curator, vendor);
await this.delay(60000); // 1 minute between follows
}
}
}
}
Quality Evaluation
Multi-Modal AI Filtering
async evaluateQuality(vendors: Vendor[]): Promise<number[]> {
// Batch evaluation for efficiency
const batches = this.chunk(vendors, 10);
const scores = [];
for (const batch of batches) {
// Use Gemini for fast, cheap evaluation
const batchScores = await this.batchEvaluate(batch);
scores.push(...batchScores);
}
return scores;
}
async batchEvaluate(vendors: Vendor[]): Promise<number[]> {
const prompt = `
Evaluate these wedding vendors on Instagram for quality and professionalism.
Score each from 0.0 to 1.0.
Criteria:
- Visual quality (professional photography)
- Portfolio consistency
- Genuine wedding work (not just styled shoots)
- Professionalism in captions and engagement
Vendors:
${vendors.map((v, i) => `${i + 1}. @${v.username} - ${v.bio}`).join('\n')}
Return JSON array of scores: [0.8, 0.6, 0.9, ...]
`;
const response = await this.callGemini(prompt);
return JSON.parse(response);
}
Emerging Vendor Detection
async detectEmergingVendors(region: string): Promise<Vendor[]> {
// Find vendors with:
// - High quality content
// - Growing follower count
// - Low current follower count (<5K)
// - High engagement rate
const candidates = await this.getRecentVendors(region);
const emerging = candidates.filter(v => {
const quality = v.qualityScore > 0.8;
const growing = v.followerGrowthRate > 0.1; // 10% monthly
const small = v.followerCount < 5000;
const engaged = v.engagementRate > 0.05; // 5%
return quality && growing && small && engaged;
});
return emerging;
}
Semantic Search
Vendor Search by Description
async searchVendors(
query: string,
region: string,
limit: number = 20
): Promise<Vendor[]> {
// Embed search query
const queryEmbedding = await this.embedQuery(query);
// Vector search in Qdrant
const results = await this.qdrant.search({
collection: 'vendors',
vector: queryEmbedding,
filter: {
must: [
{ key: 'region', match: { value: region } },
{ key: 'qualityScore', range: { gte: 0.7 } }
]
},
limit
});
return results.map(r => r.payload);
}
Content-Based Vendor Discovery
async findSimilarVendors(
vendorId: string,
limit: number = 10
): Promise<Vendor[]> {
// Get vendor's content embeddings
const vendor = await this.getVendor(vendorId);
const vendorEmbedding = await this.computeVendorEmbedding(vendor);
// Find similar vendors in embedding space
const similar = await this.qdrant.search({
collection: 'vendors',
vector: vendorEmbedding,
filter: {
must_not: [
{ key: 'id', match: { value: vendorId } } // Exclude self
]
},
limit
});
return similar.map(r => r.payload);
}
Relationship Graph Analysis
Vendor Network Discovery
async discoverViaNetwork(seedVendor: Vendor): Promise<Vendor[]> {
const network = new Set<Vendor>();
// Level 1: Who seed vendor follows
const following = await this.getFollowing(seedVendor);
network.add(...following);
// Level 2: Who those vendors follow (filtered)
for (const vendor of following) {
if (vendor.qualityScore > 0.8) {
const secondLevel = await this.getFollowing(vendor);
network.add(...secondLevel.slice(0, 10)); // Limit spread
}
}
// Filter by quality
return Array.from(network).filter(v => v.qualityScore > 0.75);
}
Collaborative Filtering
async findCollaborativeVendors(userId: string): Promise<Vendor[]> {
// Find users with similar taste
const similarUsers = await this.findSimilarUsers(userId);
// Get vendors they love but our user hasn't seen
const candidateVendors = new Set<Vendor>();
for (const user of similarUsers) {
const theirVendors = await this.getUserVendors(user.id);
for (const vendor of theirVendors) {
if (!await this.hasSeenVendor(userId, vendor.id)) {
candidateVendors.add(vendor);
}
}
}
return Array.from(candidateVendors)
.sort((a, b) => b.qualityScore - a.qualityScore)
.slice(0, 20);
}
API Endpoints
Discover Vendors
Endpoint: POST /api/discovery/vendors
Request:
Response:
{
"vendors": [
{
"id": "vendor-123",
"username": "modernweddingsmelb",
"displayName": "Modern Weddings Melbourne",
"category": "photographer",
"qualityScore": 0.92,
"followerCount": 3500,
"engagementRate": 0.08,
"isEmerging": true,
"portfolioUrl": "https://instagram.com/modernweddingsmelb"
}
],
"metadata": {
"curatorAccount": "@vows_mel_modern",
"discoveryMethod": "instagram_suggestions",
"totalCandidates": 120,
"filtered": 50
}
}
Search Vendors
Endpoint: GET /api/discovery/search
Request:
Response:
Performance & Costs
Targets
| Metric | Target | Notes |
|---|---|---|
| Discovery rate | 50+ vendors/week | Per region |
| Quality precision | 80%+ | % high quality |
| API cost | < $0.01/vendor | Gemini batch eval |
| Instagram rate limits | 0 violations | Stay within ToS |
Cost Optimization
// Tiered evaluation
async evaluateVendor(vendor: Vendor): Promise<number> {
// Tier 1: Cheap heuristics (free)
const heuristic = this.heuristicScore(vendor);
if (heuristic < 0.5) return heuristic; // Skip bad ones
// Tier 2: Gemini (cheap)
const gemini = await this.geminiScore(vendor);
if (gemini < 0.7) return gemini;
// Tier 3: GPT-4V (expensive, only for edge cases)
return await this.gpt4vScore(vendor);
}
Monitoring
Key Metrics
// Track discovery performance
metrics.increment('vendors_discovered', { region, style });
metrics.histogram('vendor_quality_score', qualityScore);
metrics.gauge('emerging_vendors_found', emergingCount);
// Track API usage
metrics.increment('instagram_api_calls', { curator });
metrics.increment('quality_evaluations', { model: 'gemini' });
// Track costs
metrics.increment('discovery_cost_usd', cost);
Related Components
- Quality Guardian - Validates discovered vendors
- Orchestrator - Uses discoveries in feed ranking
- Foundation Model - Provides embeddings for search