本地LLM驱动的职位筛选利器:JobRadar实用指南

📅 2026/8/26 13:47:53
本地LLM驱动的职位筛选利器:JobRadar实用指南
求职这件事大部分人的效率瓶颈其实不在“投简历”这一步而在“筛选职位”这一步。每天打开招聘平台搜索一个关键词返回几百条结果。你逐条点开看 JD、看薪资范围、看公司规模、看技术栈是否匹配然后默默关掉一半。真正花在“判断一个职位值不值得申请”上的时间远远超过“提交一份简历”的时间。JobRadar 这类开源项目切入的正是这个痛点它把“筛选职位”这个重复性判断工作交给了一个跑在本地的大模型来完成。本地模型读取职位描述按照你自己的偏好标准打分、排序最后只把高分的职位推给你。关键点在于这个过程中你的求职偏好、公司搜索记录、JD 文本都没有离开你的电脑。这篇文章不打算只介绍“它是什么”而是从实际使用角度拆解几件事JobRadar 这类 job search agent 的核心工作流是什么本地 LLM 在其中的角色为什么不可替代部署一个最小可用的环境需要准备什么以及真正落地时会在哪些环节踩坑。如果你想搭一个“私人职位雷达”这套思路可以直接复用到自己的项目里。1. 这篇文章真正要解决的问题先给出一个明确判断JobRadar 解决的不是“找不到工作”的问题而是“筛选职位投入产出比太低”的问题。传统求职流程中“筛选”这个动作完全依赖人工判断。你得打开多个平台切换关键词逐条阅读 JD然后在脑子里完成一系列判断薪资是否匹配、技术栈是否对口、远程还是坐班、公司规模是否合适、JD 里有没有隐藏的加班信号。这些判断本身不复杂但重复执行几百次之后人的注意力会急剧下降漏掉好职位、误判差职位的概率会明显上升。JobRadar 做的事情是用一个本地大模型来代替你完成“初筛”。它把职位描述输入给模型模型根据你预设的评分标准给每个职位打出 0 到 100 的分数然后按分数排序。你会拿到一张经过预排序的职位清单只需要从 Top 20 甚至 Top 10 开始看就行了。这里有一个容易误解的地方JobRadar 不是“自动投简历”工具。它不做自动网申也不替你写求职信。它的定位是“雷达”——负责发现和筛选目标最终是否接近目标、怎么接近仍然由你决定。这种定位的好处是风险可控不会因为自动化程度过高而造成误投、重复投递等尴尬问题。那么“本地 LLM”在这里的意义是什么三个字隐私、成本、可控。职位搜索天然包含大量个人偏好信息比如当前薪资、期望薪资、所在城市、关注的公司列表。这些数据如果交给云端 AI 处理会在外部服务器上留下痕迹。本地 LLM 不产生按 token 计费的 API 费用。高频抓取和评分背景下成本优势非常明显。你可以自由切换模型、调整 prompt、修改评分维度不受第三方服务条款限制。什么样的读者最适合读这篇文章第一类是正在求职、每天被海量 JD 轰炸的开发者第二类是研究 Agent 工作流、想看看“LLM 爬虫 结构化输出”如何组合成实用工具的技术爱好者第三类是打算把本地模型接入具体业务场景、但目前还停留在“调 API 聊天”阶段的工程师。2. 核心概念job search agent 与本地 LLM2.1 什么是 job search agent“Agent”这个词在 AI 领域被讨论很多但放到 JobRadar 这个场景里它的含义其实非常具体一个能自主执行多步骤任务的程序。一个完整的 job search agent 至少包含四个模块信息获取模块从招聘网站、RSS 源、公司招聘页面抓取职位列表。解析清洗模块把 HTML、JSON、RSS 等不同格式的数据转换成统一的职位结构提取标题、公司、地点、薪资、JD 全文等字段。评估决策模块调用 LLM根据预设标准对每个职位打分。输出通知模块把评分结果按阈值过滤生成报告或发送通知。传统爬虫只能做到前两步抓数据、存数据。真正的“智能”发生在第三步——评估决策。这也是引入 LLM 的核心价值。2.2 本地 LLM 在评分环节的角色在 JobRadar 的工作流里LLM 扮演的不是“聊天助手”而是一个结构化文本评估器。你需要把职位描述和评分标准一起拼进 prompt让模型输出一个分数和理由。例如你是一名资深的招聘顾问。请根据以下标准为这个职位打分0-100 1. 技术栈匹配度权重 40% 2. 薪资范围是否符合期望权重 30% 3. 远程办公友好度权重 20% 4. 公司规模与行业匹配度权重 10% 职位信息 {job_description} 请严格输出 JSON 格式{score: 0-100, reason: 简要理由}模型会返回一个结构化结果程序解析后存入数据库。你看到的最终排名实际上是几十次甚至几百次独立模型判断的汇总结果。2.3 为什么“本地”很关键很多人觉得本地模型效果不如云端大模型这个判断在复杂对话场景下可能成立但在“职位打分”这类任务上本地模型的优势反而更明显。职位打分的特点是输入文本长度有限输出格式固定判断标准可以提前写死。这种任务不依赖模型的“知识广度”而依赖“指令遵循能力”。现在的开源模型在指令遵循方面已经做得相当成熟打分这种简单任务完全能够胜任。本地部署还带来一个额外好处完全离线可用。没有网络波动没有 API 限流没有内容审核拦截。你在本地可以任意调整 prompt不断迭代评分标准不会产生任何增量成本。2.4 与传统关键词过滤的本质差异可能你会问这种打分逻辑用规则引擎不也能实现吗比如“包含 Python 加 10 分包含 Java 加 5 分薪资范围匹配加 20 分”。这样做确实可以但存在两个致命问题无法理解语义。一条 JD 写“熟悉 Python 或 Go”规则引擎不知道这是“任一即可”会机械地同时加两个分。无法识别隐含信号。比如 JD 里写“能够在快节奏环境中工作”规则引擎完全看不懂这可能是“加班强度大”的委婉表达。而 LLM 能理解这类潜台词并把“快节奏”“结果导向”“抗压能力强”等表达识别为潜在风险信号。所以用 LLM 做评分不是“锦上添花”而是把筛选质量提升到了一个新的层级。说得更直白一点规则引擎只能做“硬过滤”LLM 能做“软评估”。3. JobRadar 这类工具适合谁不适合谁在动手部署之前先想清楚一个问题这个工具真的适合你的使用场景吗场景是否适合原因大量职位需要初筛每天超过 50 条非常适合人工筛选成本高机器预排序收益明显职位量少每周只有几条不建议配置和调试成本高于收益需要严格的隐私保护非常适合数据不出本地需要自动投递简历不适合JobRadar 定位是筛选不是投递对 LLM 输出要求极高准确率需要谨慎评分有概率性不保证 100% 符合预期对技术栈完全陌生不想碰代码不建议部署和调试需要一定命令行基础从技术角度看这个工具更适合有两类背景的人正在求职的开发者。你本身就懂技术知道怎么跑 Python 脚本怎么配置环境变量。JobRadar 可以帮你把每天刷职位的时间从两个小时压缩到二十分钟。研究 Agent 落地的工程师。JobRadar 是一个极好的“LLM Agent”教学案例数据获取、结构化解析、模型调用、输出反馈整个链路完整且易于拆解。你不需要造一个复杂的大项目就能看到 Agent 的完整工作方式。反过来如果你期望的是“打开网页点一下按钮AI 自动帮你把所有事情办完”那当前阶段的开源项目大概率不能满足你。这类工具仍然需要一定的配置和调试成本它的价值是“每天帮你省一小时”而不是“帮你完全替代求职过程”。4. 环境准备与前置条件这一部分我们进入实操。需要说明的是由于开源项目版本迭代较快具体版本号以你实际拉取到的项目 README 为准下面的内容聚焦的是通用的环境准备思路。4.1 硬件与操作系统本地 LLM 的部署对硬件有一定要求。如果你只跑 7B 参数级别的量化模型macOS 16GB 内存或 Windows/Linux 16GB 内存即可流畅运行如果模型跑到 13B 以上建议 32GB 内存起步。操作系统方面macOS 和 Linux 是最省心的选择。Windows 也能跑但可能需要额外配置 WSL2 或 Docker 环境。4.2 安装本地 LLM 运行时目前最主流的本地模型运行工具是 Ollama。它提供了简洁的命令行接口和 HTTP API非常适合与 Python 脚本集成。# macOS 或 Linux 安装脚本 curl -fsSL https://ollama.com/install.sh | sh # Windows 用户请前往官网下载安装包安装完成后启动并拉取一个适合评分的模型# 启动 Ollama 服务 ollama serve # 拉取一个通用的开源模型 ollama pull qwen2.5:7b拉取完成后可以验证本地模型是否可用ollama run qwen2.5:7b 用一句话介绍你自己如果模型能正常回复说明本地 LLM 环境已经就绪。Ollama 默认在11434端口提供 HTTP API后续的 Python 代码会调用这个接口。4.3 获取 JobRadar 项目git clone JobRadar 项目仓库地址 cd jobradar具体仓库地址请以项目官方文档为准。克隆完成后查看项目结构ls -la cat README.md务必先阅读 README了解项目的依赖要求和配置方式。不同类型项目的配置方式差异很大有的是纯 Python 脚本有的提供 Web UI有的需要 Docker 部署不要假设所有项目都是同一种模式。4.4 创建 Python 虚拟环境与安装依赖大多数 Python 项目都会提供requirements.txt或pyproject.toml。建议先创建虚拟环境python3 -m venv .venv source .venv/bin/activate # Windows 使用 .venv\Scripts\activate pip install -r requirements.txt如果项目使用 Poetry 或 uv 管理依赖就按项目文档执行相应命令。4.5 准备配置文件多数 job search agent 项目会有一个配置文件用于声明模型名称、评分维度、数据源、通知方式等。典型的配置项可能包括# config.yaml 示例具体字段以项目实际为准 llm: provider: ollama model: qwen2.5:7b base_url: http://localhost:11434 temperature: 0.2 # 评分任务建议用较低温度 search: keywords: - python developer - backend engineer locations: - remote scoring: weights: tech_stack_match: 40 salary_match: 30 remote_friendly: 20 company_fit: 10 min_score: 70 # 低于 70 分的职位不进入推荐列表这里特别强调temperature: 0.2这个配置。评分任务与聊天任务不同需要的是稳定可复现的输出而不是创造性发散。温度越高模型输出的随机性越大同一个 JD 可能一会儿打 80 分一会儿打 60 分。降低温度能显著提高评分稳定性。5. 核心工作流拆解JobRadar 的完整工作流可以拆成五步。每一步都有独立职责也都有各自的坑。5.1 职位数据获取第一步是获取原始职位数据。常见的来源包括招聘平台的 RSS 订阅源。这是最稳定的来源结构化程度高抓取成本低。招聘平台的公开页面。结构复杂且需要处理反爬机制。公司官方招聘页面。数量少但精准适合定向监控目标公司。从实践角度看RSS 源是最友好的数据来源。它本质上是 XML 格式的职位列表不需要处理复杂的 JavaScript 渲染页面也不会频繁触发反爬策略。5.2 数据解析与清洗拿到原始数据后要统一成结构化格式。无论是 HTML、JSON 还是 XML最终都要转换成类似下面的结构dataclass class JobPosting: title: str company: str location: str salary_range: str | None description: str url: str published_at: str这一步的坑在于不同数据源的字段命名和格式差异极大。有些源把薪资写在标题里有些写在描述里有些完全不提供。清洗逻辑需要足够鲁棒不能因为某个字段缺失就中断整个流程。5.3 LLM 评分评分是 JobRadar 的核心环节。程序把职位描述和评分标准构造成 prompt发送给本地模型然后解析返回的 JSON。评分环节的稳定性直接决定整个工具的价值。如果模型输出格式不稳定后续的解析和排序都会出问题。建议在 prompt 中明确指出“只输出 JSON不要包含任何额外说明”并在代码中加入容错重试机制。5.4 结果存储与排序每一条职位评分结果都应该持久化存储便于后续查看历史记录和趋势。SQLite 是这类项目最常用的选择零配置、单文件、足够应付个人使用场景。存储后按分数降序排列再按min_score阈值过滤。最终生成的推荐列表就是你在邮件或终端里看到的结果。5.5 通知推送最后一步是把推荐列表推送给用户。最简单的形式是终端直接打印进阶一点可以写成 HTML 邮件更复杂的可以接入钉钉、企业微信或 Telegram Bot。从材料看JobRadar 这类项目通常会选择一种或多种通知方式。实际使用中建议先选择最简单的方式跑通流程再逐步增加通知渠道。6. 完整示例代码实现下面提供一个最小可运行的“本地 LLM 职位评分”示例。这个示例不依赖 JobRadar 项目的具体内部实现而是演示通用的实现思路你可以把它理解为 JobRadar 评分模块的最小原型。6.1 示例一构造职位评分 Prompt# 文件路径scoring_prompt.py def build_scoring_prompt(job_description: str, criteria: dict) - str: 构造职位评分 prompt。 :param job_description: 职位描述原文 :param criteria: 评分标准包含权重和说明 :return: 完整的 prompt 字符串 criteria_lines [] for key, value in criteria.items(): weight value.get(weight, 0) description value.get(description, ) criteria_lines.append(f{key}权重 {weight}%{description}) criteria_text \n.join(criteria_lines) prompt f 你是一名资深的招聘顾问请根据以下评分标准为给定的职位描述打分0-100 分。 评分标准 {criteria_text} 职位描述 {job_description} 请严格输出如下 JSON 格式不要包含其他任何内容 {{score: 0-100, reason: 打分理由不超过 100 字}} return prompt这段代码的关键在于把评分标准动态拼装进 prompt。不同用户的偏好不同有的人看重远程有的人看重技术栈匹配度有的人只看薪资范围。评分标准如果写死在代码里每次调整都要改代码、重启服务非常低效。通过字典参数动态生成 prompt后续只需要改配置文件即可调整评分维度。6.2 示例二调用 Ollama 本地模型评分# 文件路径llm_scorer.py import json import requests from scoring_prompt import build_scoring_prompt def score_job_with_ollama( job_description: str, criteria: dict, base_url: str http://localhost:11434, model: str qwen2.5:7b, temperature: float 0.2, ) - dict: 调用 Ollama 本地模型为职位打分。 :return: 包含 score 和 reason 的字典 prompt build_scoring_prompt(job_description, criteria) payload { model: model, prompt: prompt, stream: False, format: json, options: { temperature: temperature, }, } resp requests.post( f{base_url}/api/generate, jsonpayload, timeout120, ) resp.raise_for_status() result resp.json() text result.get(response, ) try: parsed json.loads(text) return { score: int(parsed[score]), reason: parsed.get(reason, ), } except (json.JSONDecodeError, KeyError, ValueError) as e: # 输出不符合预期时返回一个低分并标记异常 return { score: 0, reason: f模型输出解析失败: {e} | 原始输出: {text[:200]}, }这段代码有几个细节值得注意。第一format: json参数。Ollama 从较新版本开始支持结构化输出指定后模型会更倾向于输出合法 JSON。如果你的 Ollama 版本不支持这个参数忽略它也不会报错只是解析容错率会降低。第二stream: false。评分任务不需要流式输出一次性返回结果即可这样代码逻辑更简单。第三异常处理。模型输出偶尔会夹杂非 JSON 内容比如换行符、解释性文字。这种情况下直接抛异常会导致整个评分流程中断。更稳妥的做法是捕获异常并返回一个低分标记由下游逻辑决定是重试还是忽略。6.3 示例三批量评分并输出推荐清单# 文件路径main.py import json import time from llm_scorer import score_job_with_ollama # 模拟从数据源获取的职位列表 # 实际项目中这里的数据来自 RSS 源或爬虫解析结果 jobs [ { id: 1, title: Python Backend Engineer, company: Example Tech, location: Remote, description: We are looking for a Python backend engineer with experience in FastAPI, PostgreSQL, and Docker. Fully remote position., }, { id: 2, title: Full Stack Developer, company: Startup X, location: Berlin, description: Join our team! Work on React, Node.js, and MongoDB. Fast-paced environment, results-oriented culture., }, { id: 3, title: Data Scientist, company: Big Corp, location: New York, description: Build machine learning models with PyTorch and Spark. Requires 5 years experience. Hybrid work model., }, ] criteria { 技术栈匹配: { weight: 40, description: 技术栈与 Python、FastAPI、PostgreSQL、机器学习相关程度越高越好 }, 远程友好: { weight: 30, description: 支持远程办公的职位得分更高 }, 经验要求匹配: { weight: 20, description: 工作经验要求与 3-5 年匹配度 }, 明确性: { weight: 10, description: JD 描述是否清晰职责和待遇越明确得分越高 }, } MIN_SCORE 70 def main(): results [] for job in jobs: # 构造评分文本把标题和描述都喂给模型 text f{job[title]}\n{job[description]} print(f正在评分为: {job[title]} ...) result score_job_with_ollama(text, criteria) results.append({ id: job[id], title: job[title], company: job[company], location: job[location], score: result[score], reason: result[reason], }) # 给模型留一点处理间隔避免连续请求过于频繁 time.sleep(1) # 按分数降序排列 results.sort(keylambda x: x[score], reverseTrue) print(\n 职位推荐清单 ) for item in results: if item[score] MIN_SCORE: print( f[{item[score]}] {item[title]} {item[company]} ({item[location]}) ) print(f 理由: {item[reason]}) # 输出完整结果到 JSON 文件便于后续分析 with open(scoring_result.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) if __name__ __main__: main()运行方式python main.py预期输出类似正在评分为: Python Backend Engineer ... 正在评分为: Full Stack Developer ... 正在评分为: Data Scientist ... 职位推荐清单 [90] Python Backend Engineer Example Tech (Remote) 理由: 技术栈完全匹配支持远程JD 描述清晰 [72] Data Scientist Big Corp (New York) 理由: 机器学习方向匹配但远程支持程度有限同时当前目录下会生成scoring_result.json包含全部职位的评分明细。6.4 判断运行是否成功运行成功有两个标准程序没有抛出异常完整跑完所有职位评分。scoring_result.json正常生成每个职位都有分数和理由。如果所有职位分数都是 0且理由字段是“模型输出解析失败”说明模型输出格式与预期不符优先检查 Ollama 服务和 prompt 结构。7. 运行结果与效果验证方式7.1 验证模型输出稳定性第一次跑通后不要急着接入真实数据源。先用 5 到 10 条职位数据反复测试观察同一个职位多次评分的分数波动情况。# 对同一条职位描述连续评分五次 for i in {1..5}; do python main.py; done理想情况下同一职位在不同轮次中的分数差应该在 5 分以内。如果波动过大说明 temperature 设置偏高或者 prompt 表述模糊。7.2 验证评分逻辑合理性检查模型给出的“理由”是否与评分标准一致。比如一条“技术栈完全匹配 支持远程”的职位分数应该明显高于“技术栈不匹配 强制坐班”的职位。如果出现明显与常识相悖的结果不要急着怪模型先检查评分标准和权重分配是否合理。7.3 验证阈值过滤与排序把MIN_SCORE调整几次观察推荐清单的变化。阈值设得太低推荐清单里会混入大量低质量职位阈值设得太高可能一个职位都推不出来。合理做法是先设一个较低阈值跑几天观察实际数据分布后再逐步调优。7.4 失败时的排查顺序如果运行失败按以下顺序排查Ollama 服务是否在运行curl http://localhost:11434/api/tags能看到模型列表说明服务正常。模型是否已拉取ollama list确认模型名与配置一致。Python 依赖是否完整检查requests库是否安装。端口是否被占用Ollama 默认 11434 端口如果被其他程序占用需要调整配置。8. 常见问题与排查思路问题现象可能原因排查方式解决方案请求 Ollama 超时模型未加载完成或硬件性能不足查看 Ollama 日志观察 CPU/内存占用首次请求会触发模型加载等待 10-30 秒调小模型或增加内存所有职位分数都是 0模型输出不是合法 JSON打印原始响应文本在 prompt 中强调“只输出 JSON”使用format: json增加重试机制分数波动大temperature 设置过高多次评分对比结果将 temperature 调整到 0.2 以下评分结果与预期明显不符评分标准描述不够具体查看模型给出的 reason细化每条评分标准的描述增加正反例中文输出乱码终端编码问题检查终端编码设置设置PYTHONIOENCODINGutf-8抓取职位数量为 0数据源格式变化或 RSS 链接失效手动访问数据源 URL更新数据源增加数据源数量内存占用过高模型参数规模太大查看内存监控换用更低参数量的量化模型关于“评分结果与预期明显不符”这一点值得多说两句。很多第一次使用 LLM 打分的开发者会有一个错觉模型打分应该是“客观”的。实际上LLM 的评分结果高度依赖 prompt 中评分标准的描述方式。举个例子如果你写“技术栈匹配度高得分高”模型会按自己的理解判断“什么是匹配度高”。但如果写“技术栈要求包含 Python、FastAPI、PostgreSQL职位描述中出现这些技术越集中得分越高”模型的判断就精准得多。评分标准本质上是一段解释性文本写得多细模型就执行得多准。9. 最佳实践与工程建议9.1 把评分标准当成产品来迭代JobRadar 的核心价值不是“抓职位”而是“按你的标准筛选职位”。这个结论听起来简单但很多人会在项目跑通后忘记持续打磨评分标准。建议把评分标准拆成独立配置文件而不是硬编码在代码里。每次使用后把模型评分与自己的实际判断做对照发现偏差就调整评分标准的描述。这本质上是在迭代一个“私人职位评估模型”。用一两周时间打磨评分准确率会有明显提升。9.2 控制 LLM 的随机性评分任务追求稳定不追求创造性。在调用本地模型时务必把 temperature 调低。不同的模型运行框架对 temperature 的默认值不同Ollama 的默认值可能偏高建议显式指定。另外在 prompt 中强调“请根据评分标准客观打分不要受职位描述中的营销语言影响”。这样可以减少模型被“业界领先”“高速成长”“挑战性工作”这类模糊表述干扰的概率。9.3 避免生成真实职位数据与隐私合规风险本地部署的最大优势是隐私保护但数据获取环节仍然要遵守合法合规原则。使用公开 RSS 源是较稳妥的方式如果需要抓取网页应遵守目标网站的 robots.txt 和访问频率限制不要对目标站点造成压力。不要把你自己的简历内容、薪资期望等敏感信息硬编码在公开仓库中使用。配置文件加入.gitignore避免提交时泄露。9.4 增加异常容忍与手动复核机制LLM 的输出天然带有不确定性偶尔出现离谱评分是正常现象。建议在管道中加入两层保护格式层保护解析失败时自动重试一次连续失败则跳过该职位不要让单条异常中断整个流程。人工复核层保护分数超过 90 分的职位值得人工看一遍 JD确认模型没有漏掉关键负面信息。对一部分超高分职位保留“人工确认”这一步是避免被模型误导的稳健做法。9.5 日志记录与效果回溯每次评分结果都落库或写日志记录职位、分数、理由、模型版本、评分标准版本。这看起来是额外工作但当你需要分析“为什么最近推荐质量下降了”时这些历史记录是唯一突破口。常见的原因包括数据源质量下降、评分标准调整后权重失衡、模型版本更新导致行为变化。没有日志这些问题几乎无法定位。10. 总结与后续学习方向写到这里回到开头那个判断JobRadar 真正改变的不是“找工作”这件事本身而是“筛选职位”这个环节的效率模型。它把机器擅长的高速处理与 LLM 擅长的语义理解结合到一起让求职者把有限精力集中在真正值得申请的职位上。如果你的目标是把 JobRadar 这类工具真正用起来建议从最小闭环开始先跑通本地 LLM 调用再手动维护一个十几条职位的测试列表验证评分逻辑符合预期最后才接入真实数据源。不要一开始就追求全自动先用半自动方式积累对工具输出质量的信任感再逐步增加自动化程度。如果你对 Agent 工程本身更感兴趣这个项目能带给你的启发是Agent 的真正难点不在模型能力而在工程稳定性和交互设计——如何处理模型输出的不确定性如何设计可迭代的 prompt 体系如何让用户在自动化与可控性之间找到平衡。这些经验可以迁移到很多场景不只是职位搜索。下一步值得深入的方向包括接入更多数据源并对不同数据源做归一化、为同一个职位设计多轮评分并取平均值、把评分结果可视化展示、加入历史趋势分析。无论往哪个方向扩展核心思路都不变用本地 LLM 把重复的判断工作自动化但始终保留人的最终决策权。