Other

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

OpenOutreach 深度解析:把 LinkedIn 获客从“脚本自动化”推进到“AI 决策闭环”

项目背景与痛点

B2B 冷启动的经典路径是 LinkedIn:找到对的人,发一条不像群发的消息,再跟进两三轮,直到成单。问题是这条路几乎不可规模化——手动搜关键词、点开几十个主页判断匹配度、逐条起草开场白,一天下来真正有质量的触达不过二三十人。

市面上的工具(PhantomBuster、Expandi、Waalaxy 之类)大多停留在“规则自动化”:关键词布尔搜索 + 模板消息 + 定时任务。它们解决了“手快”,但没解决“脑子”——谁值得联系、该说什么话,仍然靠人预先写死的规则。结果是触达量上去了,回复率反而被模板稀释。

OpenOutreach 的切入点很明确:你只负责用自然语言描述“我卖什么、卖给谁”,线索发现、资格判断、消息生成、对话推进交给 AI。这是从“自动化动作”到“自动化判断”的跃迁。

核心技术揭秘

从工程形态看,它是一个 Django 单体应用,配 Playwright 做浏览器自动化,LLM 负责语义决策。真正的设计精髓不在技术栈本身,而在把获客流程建模成可持久化的状态机。

它没有用 LinkedIn 官方 API——因为搜索和私信能力基本不对外开放。取而代之的是 Playwright 驱动真实浏览器、复用本地登录态,用接近真人的节奏完成搜索、翻页、点击。这个选择的代价是脆弱性(前端一改版选择器就挂),收益是能力上限高。

数据流大致如下:

graph TD A[产品描述与目标市场] --> B[Campaign 参数配置] B --> C[LinkedIn 搜索与主页采集] C --> D{"LLM 资格评估"} D -->|"高匹配"| E[写入发送队列] D -->|"低匹配"| F[归档放弃] E --> G[Playwright 模拟真人操作] G --> H[发送连接请求] H --> I{"对方是否回应"} I -->|"已连接"| J[LLM 生成跟进消息] I -->|"无回应"| K[限速后重试] J --> L[Deal 状态回写]

值得拆开看的有三点。

其一,状态持久化。 每个 Lead 和 Deal 都是数据库实体,带着明确状态(已评分、待发送、已连接、对话中……)。后台 daemon 进程轮询推进,任何一步失败都可重入。这跟“一跑到底的死循环脚本”是本质区别——你可以在第 200 个线索处停掉服务,明天接着跑,状态不丢。

其二,LLM 承担两个职责。 资格评估是“读主页 → 打匹配分 → 给理由”的结构化判断;消息生成是“结合产品上下文 → 写个性化开场”的生成任务。前者决定漏斗质量,后者决定回复率,两者都靠提示词工程和结构化输出约束。

其三,人工闸门。 在真正发送前保留人工复核的机会,是项目对 AI 幻觉的务实妥协——让模型负责“筛”和“写”,但把“按下发送”的最终权力留给人。

功能亮点与差异

和传统竞品相比,它最明显的差异是以自然语言定义目标市场,而非配一堆搜索布尔表达式。你对 AI 说清楚 ICP(理想客户画像),它自己去理解并扩大或收窄搜索范围。

其次是可观测性:自带定制化的 Django 后台界面,能看到每条线索的评分理由、对话历史、当前状态,而不是黑盒跑完给个 CSV。第三是自托管,数据留在本地,对合规敏感的团队更友好。最后是可中断、可恢复的长期运行形态,适合做持续外联而非一次性爆破。

应用场景与落地建议

它适合早期 SaaS、咨询工作室、独立开发者做冷启动——目标客户集中在 LinkedIn 且单笔客单价较高时收益最大。不适合纯 To C 或客户在垂直行业社群里而非 LinkedIn 的业务。

生产落地要注意几件事:一是风控,LinkedIn 对自动化极不友好,务必用非主力账号试跑,日操作量从保守值起步,逐步校准;二是ToS 风险要有清晰认知,这不是“官方合规工具”;三是 LLM 成本与延迟,评分和生成都是逐条调用,量大时成本可观,建议缓存评估结果;四是消息质量需人工抽检,模型偶尔会写出脱离语境的句子;五是选择器维护,把 Playwright 层做好抽象,便于前端改版时快速修。

综合评价

优点:把 AI 放进获客闭环而非仅仅做内容生成,方向正确;状态机式的持久化设计让长期运行成为可能;开源、自托管、可观测,工程底子在同品类里算扎实;上手门槛比想象中低。

缺点:浏览器自动化天生脆弱,LinkedIn 前端一动就要修;账号封禁风险是悬顶之剑;Django 单机 + 轮询的形态限制了横向扩展;LLM 判断的稳定性依赖提示词迭代,效果需要时间调优。

一句话总结:它不是“更快的群发器”,而是一个把销售判断流程工程化的最小可行样本。想省人力可以看它,想零风险躺赚,别指望任何工具。

关于

GitHub 原始描述(英文)

Linkedin Automation Tool: Describe your product. Define your target market. The AI finds the leads for you.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

语言占比

Dockerfile
Makefile
Python
Shell

README

OpenOutreach Logo

OpenOutreach — open-source AI agent for B2B lead generation

Describe your product. Define your target market. The AI finds the people who fit, tells you why each one does, and emails them.

Self-hosted CLI. One install, one onboarding, one command.

Rather not run it yourself? Get ten leads free at openoutreach.app, each with the reason it fits.

GitHub stars GitHub forks License: GPLv3 Open Issues


Demo

Demo Animation

🚀 What is OpenOutreach?

OpenOutreach is a self-hosted, open-source lead finder that qualifies for you — and then writes the email. You describe your product and your target market; it discovers matching people from a licensed data provider, judges each one against the ICP it learned from your description, hands you the ones that fit with the reason each was chosen written out, and opens the conversation from your own mailbox.

Two things make that different from what you may have used before:

  • Unlike a cold-email sequencer, you don’t bring a list. There is nothing to upload. The input is a sentence about your product.
  • Unlike a lead database, the output is not rows. It is a verdict per person, in plain language you can read and disagree with — and correcting the description is how you correct the verdicts.

It has zero platform-ToS surface: browserless, no social-network account, no scraping. There is no account to get banned, because there is no account.

Rather not run it yourself? I run it for you. Tell me what you sell and who buys it at openoutreach.app and I send back ten LinkedIn profiles that fit, each with the reason written out, free. After that it’s $2 a lead. Nothing to install, no keys, no account.


⚡ Quick Start

uv tool install openoutreach
openoutreach

That is the whole thing. A bare openoutreach onboards you if it has to, finds leads that fit, buys a verified work address for each, and emails them from your mailbox — narrating what it did as it goes. One install, one wizard, one command.

Prefer to say it out loud, or to set the size of the first run?

openoutreach run 5        # find five leads carrying an address, then send — at most 5 credits

The verbs:

openoutreach                  # onboard if needed, then find and send
openoutreach run 5            # ...with an explicit goal
openoutreach init             # onboard only — one flow, every answer, nothing spent
openoutreach init --product-docs product.md --target target.md   # ...the two long fields from files
openoutreach find 10          # ten more qualified leads → CSV on stdout — free, cannot spend
openoutreach find 10 emails   # ...carrying a work email (one credit each)
openoutreach find 0           # no work — print what you already have
openoutreach send             # mail what is already stored
openoutreach send 5           # ...until five conversations are open
openoutreach status           # what is configured, blocked and counted

Everything lives in ~/.openoutreach, so stopping and starting loses nothing: the number you ask for is more than you already have, so running it again continues where it left off. No browser, no daemon manager, no container.


🤖 Use it from Claude Code

This repo ships a Claude Code plugin, so you can pull leads without leaving your agent session:

/plugin marketplace add eracle/OpenOutreach
/plugin install openoutreach@openoutreach

The skill (skills/find-leads/SKILL.md) teaches Claude when to run find, which flags cost credits and which cannot, how to read the CSV on stdout, and what each error: <type> means. It never buys an address you did not ask for, and never sends without being asked. Prefer skills to plugins? Copy skills/find-leads/ into ~/.claude/skills/ instead.

Not on Claude Code? The skill is a markdown file describing the CLI’s own contract — nothing Claude-specific is required to use openoutreach itself. Codex, Cursor, or any other agent can call the same openoutreach find / send / run / status commands directly; point your agent’s instructions file at skills/find-leads/SKILL.md and it reads the same rules.


🧩 Three packages, one product

OpenOutreach is an orchestrator. The finding and the sending are two standalone programs, and this package installs both and hosts them in one process, one database and one onboarding:

Package What it is Standalone
OpenOutFind discovery, qualification, enrichment, the CRM uvx --from openoutfind outfind find 10
OpenOutSend the outreach agent, the mailbox, the send guards uvx --from openoutsend outsend send
OpenOutreach (this) one install, one wizard, one command over both —

The wizard is here because the children do not have one. Both are agent-first: they read their configuration from OPENOUTFIND_* / OUTSEND_* on every run and remember none of it, which is right for a program a script or an agent drives and wrong for a person. So this is where the questions are asked, where the answers are kept, and where they are handed to each child in its own variables.

Neither child is diminished by the bundle. Each keeps its own console script, its own settings module and its own test suite, and the contract between them is a public one:

outfind find 50 --json | outsend      # anybody's producer, anybody's receiver
outsend send                          # a separate invocation, on the mailbox's clock

openoutreach run is that same pipe, in one process — the JSON Lines still cross the boundary, they just cross it in a buffer. There is no privileged in-memory hand-off, because a second, untested path between the same two programs would make the public one a lie.

Which shape is for you: if you are an agent, a script, or a power user with your own sender, take the two CLIs and the pipe. If you want to see whether this works, take the one command.


📤 What You Get Out

The finder’s deliverable is a file, and it is shaped for the tools you already send with:

openoutreach find 10 emails > leads.csv

It runs until it has ten more leads carrying an address, prints every lead you have as CSV, and exits — so the file you just wrote is always the current truth. Exit 0 means it got what you asked for; anything short still prints its rows and says why it stopped.

email, first_name, last_name, company, title, website, linkedin_url, reason, lead_id, qualified_at

Those column names are the importers’, not ours. Instantly and Smartlead both require email/first_name/last_name and recognise company/title/website/linkedin_url as standard fields, so an exported file imports without column mapping. Anything else — including reason — arrives as a custom variable you can merge into a template.

  • reason is the point. Everybody exports rows; almost nobody exports why this lead.
  • There is no score column, on purpose. The model’s confidence is a spend gate for the paid lookup, not a quality signal. The fit verdict is the LLM’s, and it is already in the file as a sentence.
  • A lead with no email still exports. If you have no email-finder credits, you still get the qualified person, their employer and the reason.
  • A rejected lead never exports. Both rejections are excluded, always.

If you send with your own tool: turn on its import dedupe. It is opt-in on Smartlead and undocumented on Instantly, so a lead you export twice can otherwise be contacted twice.


📋 What You Need

# What Example
1 An LLM API key OpenAI, Anthropic, or any OpenAI-compatible endpoint
2 An email-finder API key (BetterContact) Free account: 40 credits, no card. Powers both discovery (Lead Finder, billed nothing) and enrichment (one credit per verified work email)
3 A product description + target market “We sell cloud cost optimization for DevOps teams at mid-market SaaS companies”
4 A mailbox to send from Its address and an app password — not your login password. Google Workspace works out of the box; any other provider names its SMTP/IMAP host and port

No keys yet? Ask for ten leads at openoutreach.app and I’ll find them for you, free.

Onboarding asks for all four in one pass and asks only once — the answers are kept in ~/.openoutreach, and every later run exports them into the variables the children read. A question whose variable is already exported is not asked at all, so an operator or a unit file that sets OPENOUTFIND_* / OUTSEND_* never has to repeat it into a prompt; that is what makes a headless install possible. With no TTY and something still unanswered, setup stops naming the variables that would have answered it rather than blocking on a question nobody is there to hear.

The two long fields are read from files, not flags — a markdown paragraph shell-quoted onto a command line corrupts quietly:

openoutreach init --product-docs product.md --target target.md

The LLM key is verified at the prompt, and the mailbox by a real SMTP login before setup finishes: a wrong key is an answer you can retype, not a traceback halfway through a run.

The BetterContact link above is an affiliate link — signing up through it supports OpenOutreach, at no markup to you.


Why choose OpenOutreach?

  • 🧠 You don’t need a list — describe your product; it finds candidates from licensed data
  • 📝 A stated reason per lead — read exactly why the agent picked someone, and fix the description when it is wrong
  • 🔍 Nothing decides in the dark — the ICP, the verdicts and the whole pipeline are on your machine and open to read
  • 🛡️ Zero platform-ToS surface — browserless, no social-network account, no scraping — nothing to get banned
  • 💸 Pay only for what resolves — searching is free; a paid lookup is rationed and billed on a verified hit
  • 📤 Or export where you already work — CSV in the shape the sequencer importers expect
  • ⚡ One-command setup — uv tool install openoutreach && openoutreach

Every comparable tool that qualifies leads for you is paid SaaS. This one is GPLv3, runs on your machine, and you bring your own provider keys.


💸 How OpenOutreach Stays Free

Affiliate links, and that is now the whole of it. The one paid third-party service the tool relies on — the lead-data provider — is surfaced during onboarding through an affiliate link. Sign up through it and the project may earn a commission, at no markup to you. Sign up any other way if you prefer. See the Legal Notice (§4).


📖 How It Works

Discover → qualify → gate → resolve → write → send.

  1. You provide a product description and a campaign objective
  2. An LLM turns that into opening search keywords and pages matching firmographic profiles from a licensed discovery source (BetterContact Lead Finder) — no emails yet, billed nothing
  3. Discovery walks the keyword index by counting, adding one word at a time and spending its next query where the accepted-lead counts say the best ones came from
  4. An LLM qualifies each candidate against your ICP and writes down why. A Gaussian Process over profile embeddings learns from those verdicts and picks who to qualify next
  5. A confidence gate rations the one paid step — a work address is resolved for the best-fit leads only, one credit per verified hit
  6. The outreach agent writes each opener from the same product description, and the send guards (sending window, daily cap, pacing) decide when it actually leaves your mailbox

Steps 1–5 are OpenOutFind’s and step 6 is OpenOutSend’s; each repo documents its own internals. Searching the licensed source is free, so the system can afford to look at a lot and spend paid lookups only on the best fits. (The learning loop is an active experiment — it is not yet shown to beat picking at random, and no claim is made that it does.)


📂 Project Structure

This repo is the orchestrator and holds no pipeline of its own — that is the point of it:

├── openoutreach/
│   ├── __main__.py     # the `openoutreach` console script: find · send · status · run
│   ├── settings.py     # one Django registry hosting both children's apps, on one database
│   ├── config/         # the one model: the answers you gave, and the variables they export as
│   └── wizard.py       # one onboarding — ask once, keep it, hand it to both children
├── tests/              # the registry, the wizard's row and export, the CLI's own decisions
├── manage.py           # checkout shim over openoutreach/__main__.py
├── pyproject.toml      # package metadata, pinned children, console script
├── local.yml           # Docker Compose — the server deploy only
└── Makefile            # Shortcuts (setup, run, find, test)

⚙️ Local Installation (Development)

git clone https://github.com/eracle/OpenOutreach.git
cd OpenOutreach
make setup              # install -e ".[dev]" + migrate both children's apps
make run                # onboard, find, send
make test

Working on the pipeline itself? It is not here — clone OpenOutFind or OpenOutSend, and point this project at your checkout with uv pip install -e ../OpenOutFind.

Running it on a server instead? A Docker image is published to GitHub Container Registry for exactly that — see the Docker Guide.


💬 Channel

Join for support and discussions: Telegram Channel


🗓️ Book a Free 15-Minute Call

Got a specific use case, feature request, or questions about setup?

Book a free 15-minute call — I’d love to hear your needs and improve the tool based on real feedback.

Book a 15-min call


❤️ Support OpenOutreach

This project is built in spare time to provide powerful, free open-source growth tools. Your sponsorship funds faster updates and keeps it free for everyone.

Sponsor with GitHub


Tier Monthly Benefits
☕ Supporter $5 Huge thanks + name in README supporters list
🚀 Booster $25 All above + priority feature requests + early access to new campaigns
🦸 Hero $100 All above + personal 1-on-1 support + influence roadmap
💎 Legend $500+ All above + custom feature development + shoutout in releases

⚖️ License

GNU GPLv3 — see LICENCE.md


By using this software you accept the Legal Notice. It covers the third-party services you connect (data provider, email-finder), your responsibilities as data controller under data-protection law, your duties as the sender of the mail this tool writes, automatic newsletter subscription for non-opt-in jurisdictions, the central contacts store, and liability disclaimers.

Use at your own risk — no liability assumed.


Star History Chart

Made with ❤️

评论

暂无评论