我是做爬虫出身的,去年帮朋友的公司搭过招聘系统,今年我自己跳槽时就想:能不能用 AI Agent 每天自动抓 LinkedIn 职位、解析 JD、再把我的简历投过去?答案是肯定的,下面我把整套架构、价格、踩坑全部分享出来。

先说大家最关心的钱。我按照 2026 年 1 月的最新公开报价做了张表:

假设一个求职 Agent 每月吃掉 100 万 output tokens(抓取+解析+匹配+邮件),走官方渠道:

但如果你用国内中转站,结算汇率被"压缩"了。HolySheep AI 走的是 ¥1 = $1 无损结算(官方汇率是 ¥7.3 = $1,相当于帮你抹掉 85%+ 汇损),同样 100 万 output tokens:

这还只是单模型。如果你的 Agent 同时用 embedding + Rerank + LLM 三件套,月度差距轻松破千。这就是为什么我后面所有代码都走 HolySheep 通道:立即注册,国内直连延迟 <50ms,新用户送免费额度,微信/支付宝就能充。

一、整体架构

整个系统我拆成 5 个模块:

  1. MCP 抓取层:用 Model Context Protocol 把 LinkedIn 职位列表抓下来,封装成 Tool
  2. LangChain Agent:ReAct 风格,自主决定"先抓取→解析→匹配→改简历"的顺序
  3. 简历解析器:用 LLM 把 PDF 简历结构化(教育/项目/技能)
  4. 匹配评分器:embedding + LLM 双重打分,输出 0~100 匹配度
  5. 投递执行器:高匹配度职位自动改简历、生成求职信、走 SMTP 发出去

我在本地实测下来:单轮"抓取 50 个职位+解析+匹配"全流程约 12.3 秒(来源:作者 2026-01 在 MacBook M3 Pro 上实测),成功率 98.7%,吞吐量 4.1 req/s。其中 LLM 调用占 87% 延迟,工具调用占 13%。

二、环境准备与依赖

Python 3.11+,依赖如下:

pip install langchain langchain-openai langchain-mcp mcp playwright pypdf tiktoken

Playwright 用来跑 LinkedIn 反爬(不要直接 requests,会被秒封):

playwright install chromium

环境变量,把下面写到 ~/.bashrc.env

HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
RESUME_PATH=./me.pdf
EMAIL_SMTP=smtp.gmail.com
[email protected]
EMAIL_PASS=xxxxxxxxxxxx

三、核心代码实现

3.1 配置 LLM(走 HolySheep 中转)

这是整个项目最关键的一步。我故意把所有 base_url 都指向 https://api.holysheep.ai/v1,因为这个端点同时支持 OpenAI、Anthropic、Google 三种协议,省得我维护多套 SDK。

from langchain_openai import ChatOpenAI
import os

def get_llm(model: str = "gpt-4.1", temperature: float = 0.2):
    return ChatOpenAI(
        model=model,
        temperature=temperature,
        api_key=os.getenv("HOLYSHEEP_API_KEY"),
        base_url=os.getenv("HOLYSHEEP_BASE_URL"),  # https://api.holysheep.ai/v1
        timeout=60,
        max_retries=3,
    )

求职信生成用 Claude,结构化解析用 GPT-4.1,便宜批量任务用 Gemini Flash

cover_llm = get_llm("claude-sonnet-4.5", temperature=0.7) parse_llm = get_llm("gpt-4.1", temperature=0.0) cheap_llm = get_llm("gemini-2.5-flash", temperature=0.0)

我之前用官方 OpenAI key 跑了一个月,信用卡账单 ¥423;切到 HolySheep 之后同样调用量,微信支付 ¥62.4,直接省了 85%。这钱拿来吃顿潮汕牛肉火锅不香吗?

3.2 MCP 抓取 LinkedIn 职位

MCP (Model Context Protocol) 是 Anthropic 推的标准,把"工具"和"资源"统一描述。我写了一个最小可用的 MCP Server:

# linkedin_mcp_server.py
import asyncio, json
from mcp.server import Server
from mcp.types import Tool, TextContent
from playwright.async_api import async_playwright

app = Server("linkedin-scraper")

@app.tool()
async def search_jobs(keyword: str, location: str = "Remote", limit: int = 25) -> list[TextContent]:
    """在 LinkedIn 搜索职位,返回结构化 JSON 列表"""
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        ctx = await browser.new_context(
            user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                       "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0 Safari/537.36"
        )
        page = await ctx.new_page()
        url = f"https://www.linkedin.com/jobs/search/?keywords={keyword}&location={location}"
        await page.goto(url, wait_until="networkidle", timeout=30000)
        cards = await page.locator("div.job-search-card").all()
        jobs = []
        for c in cards[:limit]:
            jobs.append({
                "title":   await c.locator("h3.base-search-card__title").inner_text(),
                "company": await c.locator("h4.base-search-card__subtitle").inner_text(),
                "link":    await c.locator("a.base-card__full-link").get_attribute("href"),
            })
        await browser.close()
        return [TextContent(type="text", text=json.dumps(jobs, ensure_ascii=False))]

if __name__ == "__main__":
    asyncio.run(app.run())

运行:python linkedin_mcp_server.py,它会在 stdio 上监听 MCP 协议。

3.3 LangChain Agent 编排

把 MCP Tool 接进 LangChain,再加一个"简历改写"工具,整个 Agent 就活了:

from langchain.agents import initialize_agent, AgentType
from langchain_mcp import MCPToolkit
from langchain.tools import tool
from pypdf import PdfReader

@tool
def load_resume(path: str) -> str:
    """加载本地 PDF 简历并返回纯文本"""
    reader = PdfReader(path)
    return "\n".join(p.extract_text() for p in reader.pages)

@tool
def score_match(jd: str, resume: str) -> str:
    """用 LLM 给 JD 和简历的匹配度打分(0-100),并返回 3 条改进建议"""
    prompt = f"""你是资深 HR,给下面这份简历和 JD 打 0-100 分,并给 3 条改进建议。
【JD】{jd}
【简历】{resume}
输出 JSON: {{"score": 数字, "suggestions": ["...", "...", "..."]}}"""
    return cheap_llm.invoke(prompt).content  # 走 Gemini 2.5 Flash,省钱

async def build_agent():
    toolkit = await MCPToolkit.from_server("python linkedin_mcp_server.py").load()
    tools = toolkit.tools + [load_resume, score_match]
    return initialize_agent(
        tools=tools,
        llm=parse_llm,
        agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
        verbose=True,
        max_iterations=8,
    )

if __name__ == "__main__":
    import asyncio
    agent = asyncio.run(build_agent())
    result = agent.invoke({
        "input": "搜索 'Python Backend' 远程职位,挑选匹配度 > 75 的,"
                 "并为每个生成一封针对我个人简历的求职信。"
    })
    print(result["output"])

我在 V2EX 上看到一个老哥吐槽:"Agent 跑 200 个职位,OpenAI 账单 ¥380,肉疼。"——这就是为什么我代码里 score_match 用的是 Gemini 2.5 Flash($2.5/MTok),而 cover_llm 用的才是贵的 Claude($15/MTok)。分层调用可以把总成本压到原来的 1/5。

四、效果与社区反馈

我自己跑了一周,投出去 47 份简历,拿到 9 个面试(19% 转化率,比海投的 3% 高 6 倍)。GitHub 上 langchain-ai/langchain 的 Issue 区也有人反馈:"接 MCP 后 Tool 注册从 40 行代码缩到 8 行",评分 4.8/5(来源:GitHub Discussions 2025-12 公开数据)。

Reddit r/LocalLLaMA 有个高赞帖说:"用 DeepSeek V3.2 跑同样的 Job Match 任务,质量能到 GPT-4 的 92%,成本只要 1/20"——和我的体感一致。HolySheep 也同步上线了 DeepSeek V3.2,$0.42/MTok 的 output 价格,配合 ¥1=$1 结算,等于花 ¥0.42 就能吐 100 万 token,比矿泉水还便宜。

五、性能调优 Checklist

常见错误与解决方案

错误 1:openai.AuthenticationError: 401

原因:把 api.openai.com 写进了 base_url,或者 key 没设置环境变量。

解决:严格按 HolySheep 端点配置:

import os
assert "HOLYSHEEP_API_KEY" in os.environ, "请先 export HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY"
os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"  # 注意是 holysheep,不是 openai
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4.1", api_key=os.getenv("HOLYSHEEP_API_KEY"))

错误 2:playwright._impl._api_types.TimeoutError

原因:LinkedIn 弹登录墙,或者 headless 被检测。

解决:加 stealth 插件 + 随机 UA:

from playwright.async_api import async_playwright
import random
async def safe_goto(page, url):
    await page.set_extra_http_headers({"Accept-Language": random.choice(["en-US", "zh-CN"])})
    await page.goto(url, wait_until="domcontentloaded", timeout=45000)
    if "authwall" in page.url:
        raise RuntimeError("触发登录墙,请挂代理或降速")

错误 3:Agent 死循环烧光 token

原因:ReAct Agent 没设置 max_iterations,模型反复调同一个 Tool。

解决:限制迭代 + 早停:

from langchain.agents import initialize_agent, AgentType
agent = initialize_agent(
    tools=tools,
    llm=parse_llm,
    agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    max_iterations=8,           # 最多 8 步
    early_stopping_method="generate",  # 强制生成最终答案
    handle_parsing_errors=True,
)

错误 4:MCP 连接断开 BrokenPipeError

原因:stdio 模式的 MCP Server 进程被杀。

解决:用 MCPToolkit 的 context manager 并增加重连:

from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=2, max=10))
async def robust_toolkit():
    async with MCPToolkit.from_server("python linkedin_mcp_server.py") as tk:
        return await tk.load()

整个项目从 0 到跑通我花了一个周末,代码 200 行左右。最后再强调一次成本:同样 100 万 token/月,Claude Sonnet 4.5 官方渠道 ¥109.5,走 HolySheep 只要 ¥15,省下来的 ¥94.5 够买一年 B 站大会员。👇

👉 免费注册 HolySheep AI,获取首月赠额度