ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

开源AI代理自动挖掘B2B潜客:从环境配置到落地实践

2026/8/27 1:45:52 拓冰建站 浏览量
开源AI代理自动挖掘B2B潜客:从环境配置到落地实践 做B2B销售和客户开发时最花费时间的环节往往不是打电话或写邮件而是“找谁聊”。传统做法是购买现成名单、从展会名册整理、或者让销售每天手工搜索网页这些方式要么成本高要么数据容易过期。现在开源社区出现了一批AI代理项目试图把“找B2B潜客”这件事自动化你不需要自备客户列表AI代理会按照设定好的条件在公开信息中自动寻找、识别、补充和验证潜在客户。本文以GitHub快报第350期提到的开源AI代理方向为起点梳理这类项目从环境准备、代码实现到验证落地的完整思路并重点说明真正跑起来会遇到的问题。这里先明确一个概念文章中的“AI代理”指的是基于大语言模型、能自主调用工具并完成多步任务的智能体不是网络代理。它通过“分析目标 - 调用搜索或网页读取工具 - 提取信息 - 判断是否符合条件 - 输出结果”这样的循环完成工作而不是简单抓取一个网页。1. 先理解“无需自备列表”背后的技术思路1.1 传统B2B线索获取的问题在哪里B2B企业做销售开发通常有一个固定的“找线索”流程确定目标客户画像比如行业、规模、地区、技术栈。从行业报告、展会名册、企业数据库或第三方工具里导出公司列表。销售逐个打开官网找关键人和联系方式。人工验证信息的有效性剔除已离职、同行、无效电话等信息。最后把结果导入CRM或Excel开始外呼或邮件触达。这个流程有三个明显问题列表来源需要额外购买或维护成本不低。列表中的联系人变更很快今天整理的名单可能两个月后已经失效。销售真正有价值的时间被大量消耗在“查资料、补信息”上而不是花在沟通和转化上。所以“无需自备列表”出现时对B2B销售团队和独立开发者都有吸引力。它意味着把“找线索、查官网、补联系人”这类偏重复的信息收集工作交给AI代理人只负责设定规则和复核结果。1.2 AI代理在潜客挖掘中做了什么一个典型的开源AI代理完成B2B潜客挖掘时工作过程类似一个初级销售助理接收目标描述比如“帮我找杭州做跨境电商ERP的软件公司规模50到200人”。将目标拆解为搜索计划先找行业关键词再搜索企业目录再进入官网确认产品和服务。调用工具获取信息工具可以是搜索引擎API、网页抓取函数、企业信息查询接口也可以是RSS解析。从页面中抽取结构化字段公司名称、官网、所在地、员工规模、业务简介、联系人等。对候选公司打分或过滤判断是否属于目标画像。汇总输出名单去重后生成CSV、JSON或表格。这里的关键是“代理”而不是“爬虫”。普通爬虫只能按预设模板抓取字段规则一旦变化就失效AI代理可以通过大模型的语义理解能力从非结构化文本中判断一家公司是否匹配目标画像并在信息不足时主动决定再搜一次。1.3 为什么使用开源项目而不是自研有团队会觉得自己写一个爬虫加规则引擎也能实现类似效果但实际维护成本很高。开源AI代理项目能省掉以下工作已经封装好大模型调用和工具调用循环。已经处理常见输出格式问题比如JSON解析失败、字段缺失。提供任务配置、日志和人工确认入口便于调试。社区会迭代新模型和新工具的适配。当然开源项目也不是拿来就能用。你需要准备大模型API或本地模型定义潜客规则接好数据源并处理误判和重复数据。下面按这个顺序展开。2. 环境准备跑通一个开源AI代理项目需要什么2.1 推荐运行环境与版本在开始写代码之前先确认系统环境。下面是常见项目的推荐配置实际项目可能有差异落地前建议先看对应仓库的README。依赖推荐配置说明操作系统macOS、Linux、Windows WSLLinux服务器最适合长期运行Python版本3.10 或 3.11当前多数AI代理项目基于Python开发包管理工具uv 或 pip建议优先使用虚拟环境大模型APIOpenAI兼容接口或本地Ollama、vLLM直接决定代理的分析能力数据源搜索引擎API、网站可公开访问的页面或RSS不需要自备客户列表但需要指定“去哪里找”需要注意Python版本不要过旧。部分异步HTTP库、Pydantic模型在Python 3.9以下会有兼容性问题。如果原始项目没有给出明确版本要求建议先创建3.11的虚拟环境试跑。2.2 获取项目并安装依赖获取开源AI代理项目通常使用Git拉取代码git clone 项目仓库地址 cd 项目目录 python -m venv .venv source .venv/bin/activate pip install -r requirements.txt如果项目使用uv管理依赖uv sync这一步常见的坑是依赖版本互相冲突尤其是pydantic、openai、langchain-core这类库。遇到安装失败时不要盲目升级所有包先看项目是否锁定了版本范围。很多AI代理项目会在仓库中提供lock文件或requirements按文件安装即可。2.3 配置大模型API或本地模型代理的“大脑”是大模型。你可以选择三种方式使用云厂商提供的OpenAI兼容API。使用本地模型如通过Ollama启动。使用开源模型部署服务如vLLM。以环境变量方式配置云API示例export OPENAI_API_KEYsk-xxx export OPENAI_BASE_URLhttps://api.openai.com/v1 export AGENT_MODELgpt-4o-mini如果你使用本地Ollamaollama pull qwen2.5:14b ollama serve然后在项目配置中把模型名改成qwen2.5:14b并把接口地址指向http://localhost:11434/v1。学习环境下选一个小模型跑通流程即可但要注意模型太小会导致提取结果不稳定。B2B潜客判断需要模型理解公司业务描述、行业关键词和业务关系太小的模型会出现“看起来完成了实际结果杂乱”的情况。注意不管是云API还是本地模型都要在项目配置里区分环境。不要把API密钥直接写进代码仓库建议使用.env文件或环境变量。2.4 创建最小配置文件大部分开源AI代理项目会把任务参数放在一个YAML或JSON配置文件中。下面是一个示意结构task: target_description: 杭州跨境电商ERP软件公司 region: include: - 浙江 - 杭州 employee_scope: min: 50 max: 500 keywords: - 跨境电商 - ERP - SaaS output: format: csv path: output/leads.csv agent: model: gpt-4o-mini max_steps: 12 temperature: 0 tool_timeout_seconds: 30 source: search_api: serpapi allowed_domains: - example.com - itjuzi.com这个配置文件的核心作用是把“销售的目标”翻译成“代理可以执行的指令”。后面解析数据时代理就是依据这份配置判断哪家公司值得进入最终名单。3. 最小可运行案例从“搜索线索”到“输出名单”3.1 项目目录结构设计参考一个常见的AI代理项目结构目录可以设计成下面的样子b2b_lead_agent/ ├── .env ├── config/ │ └── task.yaml ├── src/ │ ├── agent.py │ ├── tools/ │ │ ├── __init__.py │ │ ├── search.py │ │ ├── web_fetch.py │ │ └── extract_contact.py │ ├── memory.py │ └── utils.py ├── output/ ├── logs/ └── main.py这个结构的可维护性在于工具函数和代理主循环分离。后续增加新的数据源时只需要在tools目录里新增一个模块并注册给代理不需要改主循环。3.2 定义潜客筛选规则筛选规则是整个系统里最重要的一环它决定了代理的“判断力”。如果规则写得模糊比如“找一些软件公司”代理会输出大量无关结果如果写得明确比如“杭州市、跨境电商ERP、员工规模50到500人、官网提供产品演示或定价页”代理能把范围收敛很多。推荐的规则定义方式是先写自然语言描述再配结构化字段。task: description: | 寻找杭州地区做跨境电商ERP软件的SaaS公司。 满足条件的公司需要 1. 官网出现“跨境电商ERP”或“跨境ERP”或“跨境电商管理”等关键词。 2. 业务模式是SaaS订阅制不是纯外包项目。 3. 公司所在城市为杭州或官网展示的办公地址在浙江。 4. 员工规模大约在50到500人之间。 fields: company_name: str website: str city: str employee_count: int business_summary: str reason_for_match: str为什么需要reason_for_match这个字段因为代理输出候选名单后人必须能快速判断这条线索为什么被选中。有了这个字段你可以识别模型的判断依据并在误判时调整提示词。3.3 用工具调用让代理获取信息代理本身不直接联网它通过工具函数访问外部信息。这里演示两个最小工具函数搜索和网页读取。# src/tools/search.py import requests def search_web(query: str, api_key: str, engine: str google) - list: 调用搜索引擎接口返回前N条结果。 params { engine: engine, q: query, api_key: api_key, } response requests.post(https://api.example.com/search, jsonparams, timeout15) response.raise_for_status() results response.json().get(results, []) return [ { title: item.get(title), url: item.get(url), snippet: item.get(snippet), } for item in results[:10] ]# src/tools/web_fetch.py import re import httpx from bs4 import BeautifulSoup def fetch_website_text(url: str) - str: 抓取网页正文保留关键文本去除脚本和样式。 headers { User-Agent: Mozilla/5.0 (compatible; B2BLeadAgent/1.0) } response httpx.get(url, headersheaders, timeout20, follow_redirectsTrue) soup BeautifulSoup(response.text, html.parser) for tag in soup([script, style, noscript]): tag.decompose() text soup.get_text(separator\n, stripTrue) return text[:5000]在真实项目里搜索接口提供商可能不同但工具函数的设计思路一致代理发出一个“动作请求”工具返回文本或结构化的“观察结果”。代理根据观察结果再决定下一步动作。这里容易出现两个问题搜索结果里出现垃圾站点导致代理被无关内容带偏。抓取网页时被对方网站拦截返回403或需要校验。处理方式是在代理循环里加入“来源校验”比如只保留公司官网域名或可信目录域名并对抓取失败的结果标记为“未验证”。3.4 代理主循环与人工确认点下面是一个简化版的代理主循环。它用while循环不断执行“模型决定调用哪个工具”的步骤直到模型认为已经收集了足够信息# src/agent.py from typing import List import json class Agent: def __init__(self, model_client, tools): self.model_client model_client self.tools {tool.name: tool for tool in tools} self.messages [] self.steps_taken 0 self.max_steps 12 def run(self, task_prompt: str) - dict: self.messages.append({role: system, content: 你是B2B潜客挖掘助手。}) self.messages.append({role: user, content: task_prompt}) while self.steps_taken self.max_steps: response self.model_client.chat( messagesself.messages, toolslist(self.tools.values()), ) assistant_message response[message] if assistant_message.get(tool_calls): self.messages.append(assistant_message) for tool_call in assistant_message[tool_calls]: tool_result self.execute_tool(tool_call) self.messages.append( { role: tool, tool_call_id: tool_call[id], content: tool_result, } ) self.steps_taken 1 continue final_text assistant_message.get(content, ) return self.parse_final_result(final_text) raise RuntimeError(代理在最大步数内未完成分析请调整规则或增加步数) def execute_tool(self, tool_call) - str: tool_name tool_call[function][name] arguments json.loads(tool_call[function][arguments]) tool self.tools[tool_name] return tool.run(**arguments)这里的关键点是max_steps。实际运行时代理可能为了验证一条线索反复搜索多次导致步骤很快用完。学习环境可以设成20生产环境建议结合成本做上限控制。人工确认点可以放在两个位置每次抓取官网后代理先输出一段“候选摘要”确认后再决定是否进入画像补充。最终输出名单前把候选结果写入一个待审核目录由销售批量复核。不要把人工确认点做得太频繁否则会消耗人工也不要不设置否则误判线索会直接进入销售流程浪费外呼时间。4. 核心流程拆解线索发现、画像补充、资格验证、结果输出4.1 线索发现公开网页、RSS、行业目录“无需自备列表”不代表没有数据来源而是数据来源来自公开、可访问的信息。常用的线索发现渠道包括渠道说明优点需要注意搜索引擎通过关键词搜索公司官网、新闻、测评覆盖面广结果噪声大需要过滤行业目录各类企业黄页、SaaS点评站、协会会员列表结构相对清晰信息更新可能不及时RSS订阅行业新闻站、招聘站、政策公告实时性高内容非结构化需要解析公开API企业信息平台开放接口结构化数据完整通常有配额限制招聘网站公司发布岗位时透露技术栈和规模能反推业务方向抓取合规需评估在代理框架里这些渠道都被封装成工具。代理根据目标描述决定先用哪个渠道。比如目标明确要找“杭州跨境电商ERP公司”代理会先搜索行业关键词再看结果里的域名而不是上来就抓招聘信息。4.2 画像补充公司信息、联系人、业务标签找到候选网站后代理要提取“画像”。一个完整的B2B潜客画像包括公司名称和官网。总部所在地或办公地址。员工数或招聘趋势。主营产品和服务。技术栈、行业、客户类型。可能的决策部门和联系方式。对于联系人信息不建议一开始就做全量联系人抓取因为很多站点的个人信息受隐私保护约束。更稳妥的做法是先把“公司画像”建好等到人工确认后再针对优质线索做下一轮定向信息补充。{ company_name: 杭州某某科技有限公司, website: https://example.com, city: 杭州, employee_count: 120, business_summary: 提供跨境电商ERP和WMS解决方案支持多平台订单管理。, is_saas: true, reason_for_match: 官网首页出现‘跨境电商ERP’关键词产品为SaaS订阅模式地址位于杭州。, contact: { public_email: salesexample.com, public_phone: null } }这个JSON的关键点是字段语义要稳定。稳定才能排重才能让后续人工审核可依赖。4.3 资格验证用规则判断是否值得跟进资格验证不是靠模型凭感觉打分而是把模型判断和规则判断结合。规则判断适合处理硬性条件模型判断适合处理语义条件。判断类型示例实现方式硬性条件城市是否杭州公司域名是否存在代码判断语义条件是否做跨境电商ERP是否SaaS模式模型判断阈值条件员工规模是否在50到500之间从文本估算后代码校验排除条件是否外包公司、招聘中介、广告服务商关键词排除生产系统里建议把最终结论做得保守一些只有当“硬性条件全部通过、语义条件模型判定为匹配”时才进入候选名单。如果语义匹配但硬性条件拿不准可以标记为“待人工确认”而不是直接丢弃。4.4 结果输出排重、字段标准化、人工审核最终输出不能是零散JSON。要做三件事按公司域名或官网去重。统一字段格式比如电话、邮箱、城市名。输出一份带状态字段的CSV方便销售按状态处理。示例CSV输出结构company_name,website,city,employee_count,business_summary,lead_status,reason 杭州某某科技有限公司,https://example.com,杭州,120,跨境电商ERP与WMS,待审核,符合画像 深圳某某网络有限公司,https://example.net,深圳,80,跨境电商ERP,待人工确认,城市不在目标范围把lead_status单独拆出来是为了避免“符合/不符合”这种二分类带来的信息丢失。二分类会让很多边缘线索直接被丢弃改成“待审核”“待人工确认”“排除”三分类后销售可以通过人工判断挽回一部分优质线索。5. 运行验证与结果分析5.1 启动命令与日志观察运行入口可以设计成下面的样子python main.py --config config/task.yaml运行过程中日志至少要输出以下信息当前执行到第几步。调用了哪个工具、输入是什么。工具返回的结果摘要。当前候选公司名称和判断状态。日志示例2025-01-10 10:02:11 [INFO] 步骤 1: 搜索关键词 杭州 跨境电商ERP 公司 2025-01-10 10:02:13 [INFO] 搜索结果: 返回 10 条结果过滤后保留 4 条 2025-01-10 10:02:15 [INFO] 候选公司: 杭州某某科技有限公司 2025-01-10 10:02:16 [INFO] 抓取官网首页成功长度 4320 字符 2025-01-10 10:02:18 [INFO] 模型判断: 匹配理由官网出现“跨境电商ERP”且业务为SaaS 2025-01-10 10:02:19 [INFO] 写入候选名单: output/leads.csv这里要特别注意不能只验证“程序能启动”还要验证“每一步的结果是否符合预期”。很多代理项目表面跑通了但输出全是空值或重复数据问题就出在日志记录不够细。5.2 预期输出样例一个配置正确的最小案例跑完后输出文件应包含以下特征的记录公司名称非空。官网域名可访问。城市字段属于配置的包含范围。reason_for_match不是空话。同一家公司没有重复出现。如果发现输出结果集中在同一家公司大概率是搜索工具返回的结果过于单一或者排重逻辑没有生效。如果输出结果都是“排除”大概率是筛选规则过严或者代理没有理解规则。5.3 结果质量校验方法结果质量可以用三个指标度量准确率候选名单中真正符合画像的公司占比。召回率目标画像公司中被找到的占比。去重率同一公司重复出现的比例。学习环境里可以先准备一份50条的人工标注样本把代理输出和人工判断对比记录准确率和召回率。这一步不能省因为它决定了你要不要继续调规则和提示词。指标计算方式常见问题准确率匹配公司数 / 输出候选总数规则太宽或模型误判召回率命中公司数 / 人工样本目标公司数搜索关键词不全或数据源覆盖不足去重率1 - (重复记录数 / 总记录数)没有按域名做规范去重6. 常见问题排查从现象倒推原因6.1 代理一直在循环但不出结果现象日志显示代理反复调用搜索或抓取工具但迟迟不输出最终名单。可能原因max_steps设置过小代理还没完成就中断。工具返回内容太短模型判断信息不足反复尝试。提示词没有要求模型“在信息不足时先给结论”导致它追求完美。排查方式grep 步骤 logs/app.log | tail -50如果日志显示代理每次都搜索相同关键词说明模型没有从工具结果中提炼关键信息可能是模型能力不足或工具返回结果不可用。解决方式可以是明确告诉模型“当搜索结果中没有足够证据时直接标记为未匹配不要反复搜索。”6.2 调用的数据源返回异常现象日志出现HTTP 403、timeout或解析为空。可能原因网站有反爬限制。请求头不完整。页面是动态渲染直接抓HTML没有内容。检查方式curl -I https://example.com用同一User-Agent测试看能否正常访问。如果原始HTML中确实没有正文说明页面是JavaScript渲染需要调用无头浏览器或改用数据源API。6.3 模型输出格式不稳定现象代理最终返回的不是合法JSON甚至夹杂解释性文字。可能原因输出解析逻辑只处理了一种格式。模型温度设为非0。没有使用结构化输出约束。解决方式把模型temperature设为0。使用带JSON Schema约束的接口。解析失败时增加一次重试提示模型“只输出JSON”。def parse_final_result(text: str) - dict: try: return json.loads(text) except json.JSONDecodeError: start text.find({) end text.rfind(}) 1 if start 0 and end start: return json.loads(text[start:end]) raise ValueError(模型输出内容不包含合法JSON)6.4 API限流与成本失控现象任务跑到一半报rate limit或者账单金额超出预期。可能原因没有对每次工具调用做缓存。同一个公司页面被重复抓取。模型在循环里反复请求步数过多。解决方式增加URL级缓存模块。限制同一域名抓取次数。设置每日费用上限。使用便宜的模型做初筛强模型做最终判断。不要在高频循环里反复调用大模型生成同样的文本。能复用的结果比如公司简介、业务标签第一次得到后就写入缓存。7. 生产环境最佳实践与扩展方向7.1 人工审核环节不能去掉即使是效果很好的AI代理也不建议把线索结果直接导入自动外呼系统。B2B线索误判的代价比信息采集本身更大外呼客户会反感品牌形象会受损。生产环境应该把代理输出定义为“候选名单”而不是“已确认客户”。推荐流程是代理生成候选名单并附带判断理由。运营或销售批量审核把“待确认”改成“通过”或“排除”。审核通过后的线索再进入CRM或外呼系统。人工审核的占比初期可以是100%后续随着规则成熟可以抽样审核。7.2 合规与数据边界公开信息抓取需要特别注意隐私和数据来源合法性问题。不同国家和地区对公开商业信息的抓取和使用要求不同落地前要评估数据源的服务条款。公司基本信息可以处理但个人姓名、电话、邮箱这类个人信息必须确认来源合法且使用范围符合规定。生产环境建议只保存与业务判断相关的必要字段对不必要的信息不要长期存储定期清理过期数据。整篇文章不鼓励任何绕过访问限制或批量抓取非公开数据的行为。7.3 调度、缓存与监控如果任务是每周自动跑一次可以考虑加入以下机制定时调度比如用cron或GitHub Actions。结果缓存避免重复爬取同一公司站点。异常告警当任务失败、输出为空或费用超阈值时通知负责人。数据备份每次运行前保留上次输出方便对比变化。调度示例0 9 * * 1 cd /opt/b2b_lead_agent .venv/bin/python main.py --config config/task.yaml logs/weekly.log 217.4 扩展方向行业站、招聘站、CRM打通跑通最小案例后可以从三个方向扩展增加特定行业数据源。比如只抓SaaS点评站、协会会员名录比搜索全网的准确率更高。接入招聘数据。公司放出的岗位数量和岗位描述能更准确地反推业务方向。与CRM对接。审核通过的线索自动同步到CRM形成“AI找线索 - 人工确认 - CRM跟进”的闭环。扩展时的核心原则是每增加一个数据源都要重新评估准确率和召回率。不是数据源越多越好而是数据源之间的互补性越强越好。对刚开始尝试“开源AI代理自动找B2B潜客”的团队最务实的起点是选一个行业、一个数据源、一份50条的人工验证样本先把规则和输出质量跑出来。不要一开始就追求全量覆盖。把自动收集与人工复核结合起来这套流程才能真正在B2B销售场景里持续发挥作用。