关于 vc-finder
vc-finder 是一项面向创业者的研究技能:根据产品信息寻找可比融资公司,并整理有来源的投资人名单与联系切入点。它要求每项事实都能追溯到 Tavily 搜索结果或产品页面。
主要功能
- 01识别行业、阶段与目标客户
- 02搜索并筛选 5 家可比公司
- 03研究可比公司的投资方
- 04查找发布相关投资论点的 VC
- 05提供来源、排名与联系切入点
- 06限制输出为可核实信息
适用场景
- 01为创业项目寻找潜在投资人
- 02基于相似已融资公司追踪基金
- 03按投资论点筛选 VC
- 04为投资人外联准备个性化切入点
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ varnan-tech/ opendirectory --skill vc-finder安装后在 Claude Code 中输入/vc-finder确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.env.exampleREADME.mddata/vc_funds.jsonevals/evals.jsonreferences/stage-signals.mdvc-outreach-guide.mdscripts/match_funds.py详细介绍
VC Finder
输入产品 URL 或描述。识别行业和阶段。查找 5 家获得融资的可比公司。开展两条研究线:谁投资了这些可比公司(Track A),以及哪些 VC 发布了关于这一领域的投资论点(Track B)。返回一份有来源、经过排序的投资者名单,并附上联系切入点。
零幻觉政策: 输出中的每条事实都必须能追溯到具体的 Tavily 搜索结果或抓取的产品页面。适用于:
- 可比公司名称:必须出现在 Tavily 搜索结果中,而非来自 AI 训练知识
- VC 基金名称:必须原样出现在 Tavily 搜索结果中
- 投资金额、阶段偏好、投资组合公司:必须来自搜索摘要,而非 AI 知识
- 基金概览和投资论点摘要:只能从搜索摘要中提取。如果搜索数据中没有某项细节,请写“搜索数据中未找到”,不要用训练知识补充。
常见错误
| Agent 会想要…… | 为什么这是错的 |
|---|---|
| 因为 a16z 或 Sequoia 很有名就把它们加进去 | 没有证据的知名 VC 只会带来噪音。只纳入针对这一特定产品的 Tavily 搜索结果中出现的 VC。随意提及名号只会浪费创始人的时间。 |
| 根据训练知识生成可比公司 | 可比公司必须来自 Tavily 搜索结果(步骤 6)。AI 对公司的了解并非证据——凭记忆推荐的公司可能融资状态有误,或根本不是真正的可比公司。 |
| 当 Track A 的 5 次搜索全部返回 0 条结果时继续 | Track A 结果为零,意味着可比公司选错了或过于冷门。请停止,使用更宽泛的搜索查询重新执行步骤 6,然后重试。 |
| 在未引用文章或帖子的情况下加入 Track B 的 VC | 没有来源的投资论点与幻觉无法区分。创始人无法核实,名单也会失去全部可信度。 |
| 根据训练知识补充基金概览 | 基金概览必须仅来自 Tavily 摘要文本。如果摘要没有描述该基金,请写“搜索数据中未找到”。 |
| 根据网站的视觉风格判断阶段 | 阶段必须根据步骤 4 中识别出的具体 CTA 信号来判断。 |
| 编写泛泛的联系切入点 | 每个联系切入点都必须提及该产品的具体差异化优势,以及搜索数据中的具体 VC 投资组合信号或投资论点引述。 |
| 用户同时提供描述时跳过 URL 抓取 | 始终抓取 URL。实时页面通常会揭示用户描述中遗漏的阶段信号。 |
步骤 1:设置检查
echo "TAVILY_API_KEY: ${TAVILY_API_KEY:+set}"
echo "FIRECRAWL_API_KEY: ${FIRECRAWL_API_KEY:-not set, Tavily extract will be used as fallback}"
如果缺少 TAVILY_API_KEY: 停止。告知用户:“研究 VC 投资和投资论点需要 TAVILY_API_KEY。没有备用方案。请在 app.tavily.com 获取——免费层级:每月 1000 个额度(约可完整运行 125 次)。将其添加到你的 .env 文件中。”
如果仅缺少 FIRECRAWL_API_KEY: 静默继续。URL 抓取将使用 Tavily extract。
步骤 2:收集输入
你需要:
- 产品 URL(必需,除非用户直接粘贴产品描述)
- 可选:目标阶段提示(pre-seed、seed、series-a、series-b)——如果提供,则使用该阶段并跳过阶段检测
- 可选:地域偏好(US、Europe、global)——未指定时默认为 US
如果用户只提供粘贴的描述(没有 URL): 跳过步骤 3-4。直接进入步骤 5,将粘贴的文本作为 product_content。将 stage_source 设为 user_description。
如果既未提供 URL,也未提供描述: 询问:“你的产品或初创公司的 URL 是什么?或者粘贴一段简短描述:它的功能、面向的用户,以及你所处的阶段(pre-seed、seed、Series A)。”
从 URL 中提取产品 slug,用作输出文件名:
PRODUCT_SLUG=$(python3 -c "
from urllib.parse import urlparse
url = 'URL_HERE'
host = urlparse(url).netloc.replace('www.', '')
print(host.split('.')[0])
")
步骤 3:获取产品页面
首选:Firecrawl(如果已设置 FIRECRAWL_API_KEY)
curl -s -X POST https://api.firecrawl.dev/v1/scrape \
-H "Authorization: Bearer $FIRECRAWL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "URL_HERE", "formats": ["markdown"], "onlyMainContent": true}' \
| python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('data', {}).get('markdown', '') or d.get('markdown', '')
print(f'Fetched: {len(content)} characters')
open('/tmp/vc-product-raw.md', 'w').write(content)
"
备用:Tavily extract(如果未设置 FIRECRAWL_API_KEY)
curl -s -X POST https://api.tavily.com/extract \
-H "Content-Type: application/json" \
-d "{\"api_key\": \"$TAVILY_API_KEY\", \"urls\": [\"URL_HERE\"]}" \
| python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('results', [{}])[0].get('raw_content', '')
print(f'Fetched via Tavily extract: {len(content)} characters')
open('/tmp/vc-product-raw.md', 'w').write(content)
"
步骤级检查点:
python3 -c "
content = open('/tmp/vc-product-raw.md').read()
if len(content) < 200:
print('ERROR: Page returned fewer than 200 characters.')
else:
print(f'Content OK: {len(content)} characters')
"
**如果内容少于 200 个字符:**停止获取。告知用户:“产品页面未返回可读内容。这通常意味着网站由 JavaScript 渲染,需要使用浏览器。请直接粘贴产品描述:它的功能、目标用户,以及你目前所处的阶段。”
使用粘贴的描述作为 product_content,继续执行步骤 5。
步骤 4:在本地检测阶段信号(无需 API)
在分析步骤之前,使用正则表达式解析获取到的 Markdown。
python3 << 'PYEOF'
import re, json
content = open('/tmp/vc-product-raw.md').read().lower()
stage_signals = []
if re.search(r'join\s+(the\s+)?waitlist|sign\s+up\s+for\s+beta|early\s+access|request\s+(an?\s+)?invite|get\s+notified', content):
stage_signals.append({'signal': 'waitlist or beta CTA', 'stage_hint': 'pre-seed'})
if re.search(r'start\s+(your\s+)?free\s+trial|try\s+(it\s+)?for\s+free|request\s+a?\s+demo|book\s+a?\s+demo|schedule\s+a?\s+demo', content):
stage_signals.append({'signal': 'free trial or demo CTA', 'stage_hint': 'seed'})
if re.search(r'contact\s+sales|talk\s+to\s+(our\s+)?sales|see\s+pricing|view\s+pricing|plans\s+and\s+pricing', content):
stage_signals.append({'signal': 'pricing or sales CTA', 'stage_hint': 'series-a'})
if re.search(r'case\s+stud(y|ies)|customer\s+stor(y|ies)|trusted\s+by\s+[\d,]+|used\s+by\s+[\d,]+', content):
stage_signals.append({'signal': 'case studies or customer count', 'stage_hint': 'series-a'})
if re.search(r'enterprise\s+(plan|pricing|tier)|we.?re\s+hiring|join\s+our\s+team|open\s+positions', content):
stage_signals.append({'signal': 'enterprise tier or job openings', 'stage_hint': 'series-a-or-b'})
funding_match = re.search(
r'raised\s+\$[\d,.]+\s*[mk]?|series\s+[abc]\s+round|seed\s+round|(\$[\d,.]+\s*[mk]?\s+(?:seed|series\s+[abc]))',
content
)
if funding_match:
stage_signals.append({'signal': f'funding text: {funding_match.group(0).strip()}', 'stage_hint': 'announced'})
if not stage_signals:
dominant = 'unknown'
elif any(s['stage_hint'] == 'announced' for s in stage_signals):
dominant = 'announced'
elif any(s['stage_hint'] == 'series-a-or-b' for s in stage_signals):
dominant = 'series-a'
elif any(s['stage_hint'] == 'series-a' for s in stage_signals):
dominant = 'series-a'
elif any(s['stage_hint'] == 'seed' for s in stage_signals):
dominant = 'seed'
else:
dominant = 'pre-seed'
confidence = 'high' if len(stage_signals) >= 2 else ('medium' if len(stage_signals) == 1 else 'low')
result = {'signals': stage_signals, 'dominant_stage': dominant, 'confidence': confidence}
json.dump(result, open('/tmp/vc-stage-signals.json', 'w'), indent=2)
print(f'Stage: {dominant} ({confidence} confidence) from {len(stage_signals)} signal(s)')
for s in stage_signals:
print(f' - {s["signal"]} -> {s["stage_hint"]}')
PYEOF
步骤 5:产品分析(分类体系、阶段、ICP)
输出产品内容和阶段信号:
python3 -c "
import json
content = open('/tmp/vc-product-raw.md').read()[:6000]
signals = json.load(open('/tmp/vc-stage-signals.json'))
print('=== PRODUCT PAGE (first 6000 chars) ===')
print(content)
print()
print('=== DETECTED STAGE SIGNALS ===')
print(json.dumps(signals, indent=2))
"
**AI 指令:**分析上方的产品页面内容。仅生成分类体系、ICP 和阶段分类——暂不生成可比公司(将在步骤 6 中通过实时搜索完成)。
写入 /tmp/vc-product-analysis.json:
product_name:来自页面one_line_description:说明产品的功能、目标用户和核心价值主张。少于 20 个词。不要使用营销话术。industry_taxonomy:l1(顶级类别:金融科技 / 医疗科技 / 开发者工具 / 消费者等)、l2(行业类别:销售技术 / 物流软件等)、l3(具体细分领域:主动拓客 / 最后一公里路线规划等)。仅使用“技术”或“软件”等模糊标签不可接受。icp:buyer_persona(职位)、company_type、company_sizedetected_stage:pre-seed / seed / series-a / series-b / unknownstage_confidence:high / medium / lowstage_evidence:用一句话准确指出页面上促成此判断的 CTA 或文本。如果未知,请填写“no clear signals found”。geography_bias:US / Europe / global / unclearcomparable_companies:留空数组[]——将在步骤 6 中填入
python3 << 'PYEOF'
import json
analysis = {
# FILL from your analysis above
"comparable_companies": []
}
json.dump(analysis, open('/tmp/vc-product-analysis.json', 'w'), indent=2)
print('Product analysis written.')
PYEOF
验证:
python3 -c "
import json
a = json.load(open('/tmp/vc-product-analysis.json'))
print('Product:', a['product_name'])
print('Industry:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('Stage:', a['detected_stage'], '(' + a['stage_confidence'] + ' confidence)')
"
步骤 5b:与经过验证的基金数据集进行精选预匹配
将产品分类体系与包含 25 家经过验证的 VC 基金(来源于基金网站)的精选数据集进行比对。为 Track A 生成零幻觉的基金匹配和种子轮可比公司——不消耗 Tavily 点数。
输出产品分析结果以映射标签:
python3 -c "
import json
a = json.load(open('/tmp/vc-product-analysis.json'))
print('Taxonomy:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('Stage:', a['detected_stage'])
print('Geography:', a['geography_bias'])
"
**AI 指令:**将产品分类体系映射到基金数据集使用的标准标签。可用标签:
DevTools、Infrastructure、Open Source、B2B SaaS、AI、Data、FinTech、HealthTech、Enterprise、Consumer、Marketplaces、E-commerce、Crypto、DeepTech、Cybersecurity、Generalist
选择 2-4 个能够描述该产品的标签。将 detected_stage 映射为:Pre-seed、Seed、Series A 或 Growth。将 geography_bias 映射为:US、Europe、India 或 Global。
写入产品上下文:
python3 << 'PYEOF'
import json
# FILL based on taxonomy analysis above
context = {
"extracted_tags": ["TagA", "TagB"], # 2-4 tags from the list above
"stage_hint": "Seed", # Pre-seed / Seed / Series A / Growth
"geography_hint": "US" # US / Europe / India / Global
}
json.dump(context, open('/tmp/vc-product-context.json', 'w'), indent=2)
print('Product context:', context)
PYEOF
使用嵌入的精选数据集进行评分:
python3 << 'PYEOF'
import json
context = json.load(open('/tmp/vc-product-context.json'))
VC_FUNDS = [
{"fund_name":"Y Combinator","thesis":"We provide seed funding for startups. We invest in deeply technical teams building massive companies across all domains.","check_size":"$500k","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","B2B SaaS","DevTools","AI"],"geography_focus":["Global"],"notable_portfolio":["Stripe","Airbnb","GitLab"],"website":"https://www.ycombinator.com"},
{"fund_name":"boldstart ventures","thesis":"Day one partner for developer first, crypto, and SaaS founders. We love deeply technical founders solving hard infrastructure problems.","check_size":"$1M - $3M","stage_focus":["Pre-seed","Seed"],"industry_tags":["DevTools","Infrastructure","Crypto"],"geography_focus":["Global","US"],"notable_portfolio":["Snyk","Blockdaemon","Superhuman"],"website":"https://boldstart.vc"},
{"fund_name":"Heavybit","thesis":"The leading investor in developer-first startups. We help technical founders launch, gain traction, and build enterprise-ready companies.","check_size":"$1M - $5M","stage_focus":["Seed","Series A"],"industry_tags":["DevTools","Infrastructure","Open Source"],"geography_focus":["Global","US"],"notable_portfolio":["PagerDuty","Sanity","Netlify"],"website":"https://www.heavybit.com"},
{"fund_name":"Amplify Partners","thesis":"We invest in technical founders building the next generation of IT infrastructure, developer tools, and data platforms.","check_size":"$2M - $8M","stage_focus":["Seed","Series A"],"industry_tags":["DevTools","Infrastructure","AI","Data"],"geography_focus":["US"],"notable_portfolio":["Datadog","OCTO","dbt Labs"],"website":"https://www.amplifypartners.com"},
{"fund_name":"OSS Capital","thesis":"We exclusively back early-stage founders building Commercial Open Source Software (COSS) companies.","check_size":"$500k - $2M","stage_focus":["Pre-seed","Seed","Series A"],"industry_tags":["Open Source","DevTools"],"geography_focus":["Global"],"notable_portfolio":["Cal.com","Appsmith","Hoppscotch"],"website":"https://oss.capital"},
{"fund_name":"Sequoia Capital","thesis":"We help the daring build legendary companies, from idea to IPO and beyond. Sequoia is an early-stage and growth-stage investor.","check_size":"$1M - $10M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Enterprise","Consumer","AI"],"geography_focus":["Global"],"notable_portfolio":["Apple","Google","WhatsApp"],"website":"https://www.sequoiacap.com"},
{"fund_name":"Andreessen Horowitz (a16z)","thesis":"We invest in software eating the world. We back bold entrepreneurs building the future through technology.","check_size":"$1M - $50M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Crypto","Enterprise","Consumer","AI"],"geography_focus":["Global","US"],"notable_portfolio":["Facebook","Coinbase","Figma"],"website":"https://a16z.com"},
{"fund_name":"Point Nine Capital","thesis":"We are a seed-stage venture capital firm focused on B2B SaaS and B2B marketplaces globally.","check_size":"$1M - $3M","stage_focus":["Seed"],"industry_tags":["B2B SaaS","Marketplaces"],"geography_focus":["Europe","Global"],"notable_portfolio":["Zendesk","Typeform","Docplanner"],"website":"https://www.pointnine.com"},
{"fund_name":"Cherry Ventures","thesis":"We champion founders in Europe from their earliest days. We are generalist seed investors.","check_size":"$1M - $4M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","Consumer","B2B SaaS"],"geography_focus":["Europe"],"notable_portfolio":["FlixBus","Auto1 Group","Forto"],"website":"https://www.cherry.vc"},
{"fund_name":"First Round Capital","thesis":"We are the seed-stage firm that builds the most supportive community for founders.","check_size":"$1M - $4M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","B2B SaaS","Consumer"],"geography_focus":["US"],"notable_portfolio":["Uber","Notion","Roblox"],"website":"https://firstround.com"},
{"fund_name":"Bessemer Venture Partners","thesis":"BVP helps entrepreneurs lay strong foundations to build and forge long-standing companies.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Enterprise","Consumer","FinTech"],"geography_focus":["Global"],"notable_portfolio":["LinkedIn","Twilio","Shopify"],"website":"https://www.bvp.com"},
{"fund_name":"Index Ventures","thesis":"We back the best and most ambitious entrepreneurs across all stages to build category-defining businesses.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","FinTech","Consumer","B2B SaaS"],"geography_focus":["Europe","US","Global"],"notable_portfolio":["Dropbox","Slack","Figma"],"website":"https://www.indexventures.com"},
{"fund_name":"Lightspeed Venture Partners","thesis":"We invest globally in enterprise, consumer, and health founders who are shaping the future.","check_size":"$1M - $25M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Enterprise","Consumer","FinTech"],"geography_focus":["Global"],"notable_portfolio":["Snap","Rippling","MuleSoft"],"website":"https://lsvp.com"},
{"fund_name":"Accel","thesis":"We partner with exceptional founders from inception through all phases of private company growth.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","B2B SaaS","Consumer","DevTools"],"geography_focus":["Global"],"notable_portfolio":["Facebook","Atlassian","Spotify"],"website":"https://www.accel.com"},
{"fund_name":"Bain Capital Ventures","thesis":"From seed to growth, we back founders building legendary infrastructure, fintech, application, and commerce companies.","check_size":"$1M - $50M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Infrastructure","FinTech","B2B SaaS"],"geography_focus":["US","Global"],"notable_portfolio":["DocuSign","SendGrid","Redis"],"website":"https://www.baincapitalventures.com"},
{"fund_name":"Greylock Partners","thesis":"We partner with early-stage founders to build enterprise and consumer software companies that define new categories.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["Enterprise","Consumer","Cybersecurity","AI"],"geography_focus":["US"],"notable_portfolio":["Workday","Palo Alto Networks","LinkedIn"],"website":"https://greylock.com"},
{"fund_name":"Unusual Ventures","thesis":"We provide a breakthrough level of support for early-stage founders building enterprise tech.","check_size":"$1M - $5M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Enterprise","DevTools","B2B SaaS"],"geography_focus":["US"],"notable_portfolio":["Arctic Wolf","Harness","Vivun"],"website":"https://www.unusual.vc"},
{"fund_name":"Crane Venture Partners","thesis":"We back deep tech and enterprise founders in Europe solving hard problems with data and code.","check_size":"$1M - $4M","stage_focus":["Seed"],"industry_tags":["Enterprise","DeepTech","Data","AI"],"geography_focus":["Europe"],"notable_portfolio":["Onfido","Tessian","Forto"],"website":"https://crane.vc"},
{"fund_name":"Founder Collective","thesis":"We are a seed-stage venture capital fund, built by founders, for founders. We back weird, wonderful, and wild startups.","check_size":"$500k - $2M","stage_focus":["Seed"],"industry_tags":["Generalist","Consumer","B2B SaaS"],"geography_focus":["US","Global"],"notable_portfolio":["Uber","Airtable","BuzzFeed"],"website":"https://www.foundercollective.com"},
{"fund_name":"Benchmark","thesis":"We are a partnership of equal partners. We back mission-driven founders at the earliest stages and walk beside them for the long haul.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["Generalist","Marketplaces","Enterprise","Consumer"],"geography_focus":["US","Global"],"notable_portfolio":["Uber","Twitter","eBay","Snapchat"],"website":"https://www.benchmark.com"},
{"fund_name":"Accel India","thesis":"We partner with exceptional founders from inception through all phases of private company growth in the Indian ecosystem.","check_size":"$1M - $15M","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","B2B SaaS","Consumer","FinTech","E-commerce"],"geography_focus":["India"],"notable_portfolio":["Flipkart","Swiggy","Freshworks"],"website":"https://www.accel.com/india"},
{"fund_name":"Blume Ventures","thesis":"We are a seed and pre-seed venture fund that backs startups with both funding and active mentoring.","check_size":"$500k - $3M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","B2B SaaS","Consumer","DeepTech","HealthTech"],"geography_focus":["India"],"notable_portfolio":["Unacademy","Purplle","GreyOrange"],"website":"https://blume.vc"},
{"fund_name":"Elevation Capital","thesis":"We partner with visionary founders in India across early stages to help them build category-defining businesses.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["Generalist","Consumer","FinTech","B2B SaaS","HealthTech"],"geography_focus":["India"],"notable_portfolio":["Paytm","Swiggy","Meesho"],"website":"https://elevationcapital.com"},
{"fund_name":"Peak XV Partners","thesis":"Formerly Sequoia India & SEA, we partner with founders across early, growth, and public stages to build enduring companies.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Consumer","FinTech","B2B SaaS","DevTools","AI"],"geography_focus":["India","South Asia"],"notable_portfolio":["Zomato","Pine Labs","Cred"],"website":"https://www.peakxv.com"},
{"fund_name":"Nexus Venture Partners","thesis":"We are a US-India venture capital firm backing extraordinary founders building product-first companies.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["B2B SaaS","Enterprise","DevTools","Consumer"],"geography_focus":["India","US"],"notable_portfolio":["Postman","Hasura","Zepto"],"website":"https://nexusvp.com"}
]
STAGE_ORDER = {"Pre-seed": 0, "Seed": 1, "Series A": 2, "Growth": 3}
def score_fund(fund, ctx):
score = 0
fund_tags = fund.get("industry_tags", [])
extracted_tags = ctx.get("extracted_tags", ["Generalist"])
tag_points = 0
matched_tags = []
for tag in extracted_tags:
if tag in fund_tags:
tag_points += 5 if tag == "Generalist" else 20
matched_tags.append(tag)
tag_points = min(tag_points, 60)
score += tag_points
stage_hint = ctx.get("stage_hint")
fund_stages = fund.get("stage_focus", [])
if not stage_hint:
score += 10
elif fund_stages:
if stage_hint in fund_stages:
score += 20
elif stage_hint in STAGE_ORDER:
hint_idx = STAGE_ORDER[stage_hint]
if any(f in STAGE_ORDER and abs(STAGE_ORDER[f] - hint_idx) == 1 for f in fund_stages):
score += 10
geo_hint = ctx.get("geography_hint")
fund_geo = fund.get("geography_focus", ["Global"])
if not geo_hint or geo_hint == "Global":
score += 10
elif fund_geo == ["India"] and geo_hint == "US":
pass
elif geo_hint in fund_geo:
score += 20
elif "Global" in fund_geo:
score += 15
if geo_hint == "US" and "India" in fund_geo and "US" not in fund_geo and "Global" not in fund_geo:
score = max(0, score - 30)
if fund_tags and extracted_tags and fund_tags[0] not in extracted_tags and tag_points <= 20:
score = max(0, score - 15)
return score, matched_tags
scored = []
for fund in VC_FUNDS:
score, matched_tags = score_fund(fund, context)
tier = "High" if score >= 70 else ("Medium" if score >= 40 else "Low")
scored.append({
"fund_name": fund["fund_name"],
"thesis": fund["thesis"],
"check_size": fund["check_size"],
"stage_focus": fund["stage_focus"],
"industry_tags": fund["industry_tags"],
"geography_focus": fund["geography_focus"],
"notable_portfolio": fund["notable_portfolio"],
"website": fund["website"],
"source": "verified (fund website)",
"score": score,
"confidence": tier,
"matched_tags": matched_tags
})
scored.sort(key=lambda x: (-x["score"], x["fund_name"]))
relevant = [m for m in scored if m["confidence"] in ("High", "Medium")]
curated_comparables = []
for m in relevant:
for company in m.get("notable_portfolio", []):
if company not in curated_comparables:
curated_comparables.append(company)
output = {
"high_medium_matches": relevant,
"curated_comparables": curated_comparables[:6]
}
json.dump(output, open('/tmp/vc-curated-matches.json', 'w'), indent=2)
print(f'Curated matches: {len(relevant)} High/Medium confidence funds')
for m in relevant[:8]:
print(f' {m["confidence"]:6} ({m["score"]:3}) {m["fund_name"]}')
print(f'Seed comparables from portfolio: {curated_comparables[:6]}')
PYEOF
步骤 6:通过 Tavily 发现可比公司
将步骤 5b 中整理的投资组合公司作为种子可比公司载入:
python3 -c "
import json
matches = json.load(open('/tmp/vc-curated-matches.json'))
curated = matches.get('curated_comparables', [])
print(f'Curated portfolio comparables ({len(curated)}): {curated}')
need = max(0, 5 - len(curated))
print(f'Tavily will supplement with up to {need} more')
"
不要使用 AI 的训练知识来生成可比公司。 上述整理的投资组合公司已根据经过验证的基金数据筛选,属于零幻觉可比公司。Tavily 会补充特定于 L3 细分领域的公司。
python3 << 'PYEOF'
import json, os, urllib.request
analysis = json.load(open('/tmp/vc-product-analysis.json'))
l2 = analysis['industry_taxonomy']['l2']
l3 = analysis['industry_taxonomy']['l3']
tavily_key = os.environ.get('TAVILY_API_KEY', '')
queries = [
f'"{l3}" startup raised funding venture capital seed series',
f'"{l2}" companies venture backed funded startup'
]
all_results = []
for query in queries:
payload = json.dumps({
"api_key": tavily_key,
"query": query,
"search_depth": "advanced",
"max_results": 8,
"include_answer": True
}).encode()
req = urllib.request.Request(
'https://api.tavily.com/search',
data=payload,
headers={'Content-Type': 'application/json'},
method='POST'
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read())
all_results.append({
'query': query,
'answer': result.get('answer', ''),
'results': [
{'title': r.get('title',''), 'url': r.get('url',''), 'content': r.get('content','')[:500]}
for r in result.get('results', [])
]
})
print(f'Comparable search: {len(result.get("results", []))} results for "{query[:60]}"')
except Exception as e:
print(f'Comparable search FAILED: {e}')
all_results.append({'query': query, 'answer': '', 'results': [], 'error': str(e)})
json.dump(all_results, open('/tmp/vc-comparable-search.json', 'w'), indent=2)
PYEOF
打印结果以供 AI 选择:
python3 -c "
import json
results = json.load(open('/tmp/vc-comparable-search.json'))
for r in results:
print(f'Query: {r[\"query\"]}')
print(f'Answer: {r.get(\"answer\",\"\")[:400]}')
for item in r.get('results', []):
print(f' - {item[\"title\"]} | {item[\"url\"]}')
print(f' {item[\"content\"][:200]}')
print()
"
AI 指令: 将 /tmp/vc-curated-matches.json 中整理的投资组合公司与上述 Tavily 搜索结果合并。恰好选出 5 家可比公司。优先选择整理的投资组合公司(这些公司已验证,确实是匹配 VC 基金的投资组合公司)。如有需要,再补充 Tavily 发现的公司,凑足 5 家。
为每家可比公司填写:
name:公司名称similarity_reason:用一句话解释其匹配原因(整理的公司:注明投资该公司的基金;Tavily 发现的公司:引用搜索摘要)source_url:整理的公司填写基金投资组合网站,发现的公司填写 Tavily 结果 URLestimated_stage:根据整理的数据或搜索摘要填写;如果未知,则填写 "not in search data"source_type:"curated_portfolio"或"tavily_discovered"
使用 comparable_companies 数组更新 /tmp/vc-product-analysis.json:
python3 << 'PYEOF'
import json
analysis = json.load(open('/tmp/vc-product-analysis.json'))
analysis['comparable_companies'] = [
# FILL 5 companies -- curated_portfolio first, then tavily_discovered
# Each: {"name": str, "similarity_reason": str, "source_url": str, "estimated_stage": str, "source_type": str}
]
json.dump(analysis, open('/tmp/vc-product-analysis.json', 'w'), indent=2)
print('Comparables written:', ', '.join(c['name'] for c in analysis['comparable_companies']))
PYEOF
如果搜索结果中出现的可比公司少于 3 家: 扩大查询范围。运行第三次搜索:"[l1] startup" funding round venture capital。如果结果仍然有限,则使用现有结果继续,并在 data_quality_flags 中标记。
步骤 7:轨道 A——谁投资了可比公司
针对每家可比公司运行一次 Tavily 搜索,共运行 5 次。
python3 << 'PYEOF'
import json, os, urllib.request
analysis = json.load(open('/tmp/vc-product-analysis.json'))
comparables = analysis['comparable_companies']
tavily_key = os.environ.get('TAVILY_API_KEY', '')
all_track_a = []
for comp in comparables:
company = comp['name']
query = f'"{company}" investors funding venture capital backed seed series'
payload = json.dumps({
"api_key": tavily_key,
"query": query,
"search_depth": "advanced",
"max_results": 5,
"include_answer": True
}).encode()
req = urllib.request.Request(
'https://api.tavily.com/search',
data=payload,
headers={'Content-Type': 'application/json'},
method='POST'
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read())
all_track_a.append({
'comparable_company': company,
'similarity_reason': comp['similarity_reason'],
'query': query,
'answer': result.get('answer', ''),
'results': result.get('results', [])
})
print(f'Track A - {company}: {len(result.get("results", []))} results')
except Exception as e:
print(f'Track A - {company}: FAILED ({e})')
all_track_a.append({
'comparable_company': company,
'similarity_reason': comp['similarity_reason'],
'query': query,
'answer': '',
'results': [],
'error': str(e)
})
json.dump(all_track_a, open('/tmp/vc-tracka-results.json', 'w'), indent=2)
print(f'Track A complete. Comparables with results: {sum(1 for r in all_track_a if r.get("results"))}')
PYEOF
如果所有 5 次轨道 A 搜索都没有返回结果: 使用范围更广的查询重新运行步骤 6。重试时选择媒体报道较多的知名公司。如果仍然没有结果:仅继续使用轨道 B,并在 data_quality_flags 中标记。
步骤 8:轨道 B——对该领域有投资论点的 VC
使用步骤 5 中的 L2 和 L3 分类运行 3 次 Tavily 搜索。
python3 << 'PYEOF'
import json, os, urllib.request
analysis = json.load(open('/tmp/vc-product-analysis.json'))
l2 = analysis['industry_taxonomy']['l2']
l3 = analysis['industry_taxonomy']['l3']
stage = analysis['detected_stage']
tavily_key = os.environ.get('TAVILY_API_KEY', '')
queries = [
{'name': 'thesis_l3', 'query': f'venture capital investment thesis "{l3}" investing 2023 OR 2024 OR 2025'},
{'name': 'thesis_l2', 'query': f'VC fund "{l2}" investment thesis portfolio companies'},
{'name': 'stage_space', 'query': f'{stage} investors "{l3}" startup venture capital fund'}
]
all_track_b = []
for q in queries:
payload = json.dumps({
"api_key": tavily_key,
"query": q['query'],
"search_depth": "advanced",
"max_results": 7,
"include_answer": True
}).encode()
req = urllib.request.Request(
'https://api.tavily.com/search',
data=payload,
headers={'Content-Type': 'application/json'},
method='POST'
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read())
all_track_b.append({
'query_name': q['name'],
'query': q['query'],
'answer': result.get('answer', ''),
'results': result.get('results', [])
})
print(f"Track B - {q['name']}: {len(result.get('results', []))} results")
except Exception as e:
print(f"Track B - {q['name']}: FAILED ({e})")
all_track_b.append({'query_name': q['name'], 'query': q['query'], 'answer': '', 'results': [], 'error': str(e)})
json.dump(all_track_b, open('/tmp/vc-trackb-results.json', 'w'), indent=2)
PYEOF
如果所有 3 次轨道 B 搜索都没有返回结果: 仅使用轨道 A 的结果继续。在 data_quality_flags 中注明:"No thesis-led investors found via public search."
第 9 步:综合——对所有 VC 排名并评分
打印研究数据:
python3 -c "
import json
analysis = json.load(open('/tmp/vc-product-analysis.json'))
track_a = json.load(open('/tmp/vc-tracka-results.json'))
track_b = json.load(open('/tmp/vc-trackb-results.json'))
curated = json.load(open('/tmp/vc-curated-matches.json'))
track_a_summary = []
for item in track_a:
snippets = [{'title': r.get('title',''), 'url': r.get('url',''), 'content': r.get('content','')[:400]}
for r in item.get('results', [])[:3]]
track_a_summary.append({
'comparable_company': item['comparable_company'],
'similarity_reason': item['similarity_reason'],
'answer': item.get('answer', '')[:500],
'top_results': snippets
})
track_b_summary = []
for item in track_b:
snippets = [{'title': r.get('title',''), 'url': r.get('url',''), 'content': r.get('content','')[:400]}
for r in item.get('results', [])[:4]]
track_b_summary.append({
'query_name': item['query_name'],
'answer': item.get('answer', '')[:500],
'top_results': snippets
})
curated_summary = []
for m in curated.get('high_medium_matches', []):
curated_summary.append({
'fund_name': m['fund_name'],
'confidence': m['confidence'],
'score': m['score'],
'matched_tags': m['matched_tags'],
'thesis': m['thesis'],
'check_size': m['check_size'],
'stage_focus': m['stage_focus'],
'notable_portfolio': m['notable_portfolio'],
'website': m['website'],
'source': 'verified (fund website)'
})
print(json.dumps({
'product': {
'name': analysis['product_name'],
'description': analysis['one_line_description'],
'industry': analysis['industry_taxonomy'],
'icp': analysis['icp'],
'stage': analysis['detected_stage'],
'stage_confidence': analysis['stage_confidence'],
'geography': analysis['geography_bias']
},
'curated_matches': curated_summary,
'track_a_research': track_a_summary,
'track_b_research': track_b_summary
}, indent=2))
"
AI 指令——零幻觉规则:
输出中的每个字段都必须能追溯到上方打印的数据。规则:
- curated_vcs: 直接使用
curated_matches数据。这些数据已经过预先验证,无需 Tavily 证据。fund_overview来自精选数据中的thesis字段。check_size和stage_focus来自精选数据中的相应字段。即使是这些基金,也不得根据训练知识填充信息。 - VC 名称(Track A / B): 仅在名称逐字出现在摘要文本或标题中时才纳入基金。无一例外。
- evidence_company(Track A): 该基金投资过的可比公司,必须在摘要文本中明确提及,不得推断。
- thesis_source_title(Track B): 搜索结果中显示的文章或帖子的准确标题。
- fund_overview(Track A / B): 仅从摘要文本中提取,最多 2 句话。如果摘要未介绍该基金,填写“搜索数据中未找到”。
- thesis_summary: 紧贴摘要文本改写,不得添加训练知识中的背景信息。
- check_size(Track A / B): 仅依据摘要数据。如果未提及,填写“搜索数据中未提及”。
- portfolio_in_space: 仅列出搜索摘要中出现的公司。如果没有,填写“搜索数据中未找到”。
- stage_fit_score 1-10: 如果 VC 声明的阶段与检测到的产品阶段不匹配,扣 3 分。
- space_fit_score 1-10: 仅当摘要或精选数据表明 VC 投资过 L3 细分领域的 2 家或以上公司时,才可给 9-10 分。
- approach_method: 选用以下一种——cold email / warm intro required / AngelList / application form / Twitter/X DM。根据摘要或基金网站推断。
- outreach_hook: 必须提及具体的投资组合信号或投资论点引述。诸如“突出你的增长表现”之类的通用切入点不可接受。
- 不得使用 em dash。不得使用营销语言。
写入 /tmp/vc-final-list.json:
product_summary:name、one_line_description、industry_l1、industry_l2、industry_l3、detected_stage、comparable_companies_used(仅名称)curated_vcs:fund_name、confidence("High"/"Medium")、matched_tags、fund_overview(来自 thesis 字段)、check_size、stage_focus、website、source("verified (fund website)")、stage_fit_score、space_fit_scoretrack_a_vcs:fund_name、evidence_company(必填)、evidence_source_url、stage_focus、check_size、fund_overview、thesis_summary、stage_fit_score、space_fit_score、approach_methodtrack_b_vcs:fund_name、thesis_source_title(必填)、thesis_source_url、stage_focus、check_size、fund_overview、thesis_summary、stage_fit_score、space_fit_score、approach_methodtop_5_deep_dives:fund_name、track("Curated"/"A"/"B")、fund_overview、why_fit、portfolio_in_space、how_to_approach(至少 30 个字符)、outreach_hookoutreach_hooks:3 个对象,包含 hook_type、hook_text(2-3 句话)、best_fordata_quality_flags:gaps、missing fields、low-confidence areas
python3 << 'PYEOF'
import json
result = {
# FILL from synthesis above
# Must include: product_summary, curated_vcs, track_a_vcs, track_b_vcs, top_5_deep_dives, outreach_hooks, data_quality_flags
}
json.dump(result, open('/tmp/vc-final-list.json', 'w'), indent=2)
print(f'Synthesis written. Curated: {len(result.get("curated_vcs", []))} VCs. Track A: {len(result.get("track_a_vcs", []))} VCs. Track B: {len(result.get("track_b_vcs", []))} VCs.')
PYEOF
第 10 步:自检
python3 << 'PYEOF'
import json
result = json.load(open('/tmp/vc-final-list.json'))
failures = []
# Remove Track A VCs missing evidence_company
original_a = len(result.get('track_a_vcs', []))
result['track_a_vcs'] = [v for v in result.get('track_a_vcs', []) if v.get('evidence_company')]
removed_a = original_a - len(result['track_a_vcs'])
if removed_a > 0:
failures.append(f'Removed {removed_a} Track A VC(s) missing evidence_company')
# Remove Track B VCs missing thesis_source_title
original_b = len(result.get('track_b_vcs', []))
result['track_b_vcs'] = [v for v in result.get('track_b_vcs', []) if v.get('thesis_source_title')]
removed_b = original_b - len(result['track_b_vcs'])
if removed_b > 0:
failures.append(f'Removed {removed_b} Track B VC(s) missing thesis_source_title')
# Remove deep dives for VCs that were stripped from all tracks
valid_funds = (
{v['fund_name'] for v in result.get('curated_vcs', [])} |
{v['fund_name'] for v in result.get('track_a_vcs', [])} |
{v['fund_name'] for v in result.get('track_b_vcs', [])}
)
original_dives = len(result.get('top_5_deep_dives', []))
result['top_5_deep_dives'] = [d for d in result.get('top_5_deep_dives', []) if d.get('fund_name') in valid_funds]
removed_dives = original_dives - len(result['top_5_deep_dives'])
if removed_dives > 0:
failures.append(f'Removed {removed_dives} deep dive(s) for funds stripped during QA')
# Check top 5 deep dives
dives = result.get('top_5_deep_dives', [])
if len(dives) < 5:
failures.append(f'Only {len(dives)} deep dives (expected 5) -- insufficient search data')
for dd in dives:
if not dd.get('how_to_approach') or len(dd.get('how_to_approach', '')) < 30:
dd['how_to_approach'] = 'Approach method not determinable from search data. Check the fund website directly for application instructions.'
failures.append(f"Fixed: '{dd.get('fund_name')}' had missing how_to_approach")
if not dd.get('fund_overview') or dd.get('fund_overview') == '':
dd['fund_overview'] = 'not found in search data'
# Check outreach hooks count
if len(result.get('outreach_hooks', [])) != 3:
failures.append(f"Expected 3 outreach hooks, got {len(result.get('outreach_hooks', []))}")
# Check for em dashes
full_text = json.dumps(result)
if '—' in full_text:
result = json.loads(full_text.replace('—', '-'))
failures.append('Fixed: em dash characters replaced with hyphens')
# Check for forbidden words
forbidden = ['powerful', 'robust', 'seamless', 'innovative', 'game-changing', 'streamline', 'leverage', 'transform']
full_text_lower = json.dumps(result).lower()
for word in forbidden:
if word in full_text_lower:
failures.append(f"Warning: forbidden word '{word}' found in output -- review before presenting")
# Flag any "not found in search data" entries so user knows coverage is incomplete
not_found_count = json.dumps(result).count('not found in search data')
if not_found_count > 0:
failures.append(f'INFO: {not_found_count} field(s) marked "not found in search data" -- verify directly before outreach')
if 'data_quality_flags' not in result:
result['data_quality_flags'] = []
result['data_quality_flags'].extend(failures)
json.dump(result, open('/tmp/vc-final-list.json', 'w'), indent=2)
print(f'QA complete. Issues addressed: {len(failures)}')
for f in failures:
print(f' - {f}')
if not failures:
print('All QA checks passed.')
PYEOF
第 11 步:保存并呈现输出
DATE=$(date +%Y-%m-%d)
OUTPUT_FILE="docs/vc-intel/${PRODUCT_SLUG}-${DATE}.md"
mkdir -p docs/vc-intel
呈现最终输出:
## VC Finder: [product_name]
Date: [today] | Stage: [detected_stage] ([stage_confidence] confidence) | Geography: [geography_bias]
---
### Product Analysis
What it does: [one_line_description]
Industry: [l1] > [l2] > [l3]
Buyer: [buyer_persona] at [company_type], [company_size]
Comparable companies used: [comma-separated list, noting source_type for each]
---
### Curated Matches (Verified)
*Funds matched from a verified dataset of 25 VC funds sourced from fund websites. Zero hallucination -- details come directly from the dataset.*
| Fund | Confidence | Stage Focus | Check Size | Matched Tags |
|---|---|---|---|---|
[one row per curated VC, sorted by confidence then score]
---
### Track A: VCs Who Backed Similar Companies
*These investors have already written a check in this space. Evidence from live Tavily search.*
| Fund | Backed Comparable | Stage Focus | Check Size | Fit Score | Approach |
|---|---|---|---|---|---|
[one row per Track A VC, sorted by space_fit_score descending]
---
### Track B: Thesis-Led Investors
*These investors are actively publishing about this space.*
| Fund | Thesis Source | Stage Focus | Check Size | Fit Score | Approach |
|---|---|---|---|---|---|
[one row per Track B VC, sorted by space_fit_score descending]
---
### Top 5 Deep Dives
#### [N]. [Fund Name] (Track [Curated/A/B])
Overview: [fund_overview -- from dataset or search data only]
Why it fits: [why_fit]
Portfolio in this space: [from dataset or search data, or "not found in search data"]
How to approach: [how_to_approach]
Outreach hook: "[outreach_hook]"
[repeat for all available deep dives]
---
### 3 Outreach Hooks for This Product Type
**1. [hook_type]**
[hook_text]
Best for: [best_for]
[repeat for all 3]
---
Data quality notes: [data_quality_flags, or "None"]
Saved to: docs/vc-intel/[PRODUCT_SLUG]-[DATE].md
清理临时文件:
rm -f /tmp/vc-product-raw.md /tmp/vc-stage-signals.json /tmp/vc-product-analysis.json \
/tmp/vc-product-context.json /tmp/vc-curated-matches.json /tmp/vc-comparable-search.json \
/tmp/vc-tracka-results.json /tmp/vc-trackb-results.json /tmp/vc-final-list.json