ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenHire:用MCP让Claude实时检索机器人公司招聘信息

OpenHire:用MCP让Claude实时检索机器人公司招聘信息 1. 项目起因与整体设计思路1.1 一个有点笨但真有用的想法先说结论OpenHire 是一个把国内机器人公司招聘信息抓下来、整理成结构化数据、再让 Claude 通过工具调用直接检索的开源小项目。v0.2 版本支持宇树、优必选等 11 家公司的职位搜索使用场景就是一句话——你在 Claude 里问杭州有哪些机器人公司正在招 SLAM 算法工程师它不再靠猜而是真的去查一份实时更新的职位库把公司、城市、薪资范围、投递链接给你列出来。我为什么会做这个东西经常看机器人行业机会的朋友应该都有同感这个行业的招聘信息极度分散。宇树、优必选这些头部公司有自己的招聘官网但中小公司更多是把职位挂在 Boss 直聘、猎聘、拉勾上还有一些只在公众号和牛客帖里发。你想系统性地比对一下哪家公司在招啥、给多少钱、在哪个城市基本得自己开十几个网页来回切。通用搜索引擎的召回很差搜宇树 招聘出来的可能是一堆新闻稿而不是职位列表。我当时想干脆自己维护一个职位信息源再把它接进 AI 工具里让检索这件事变成自然语言对话。于是就有了 OpenHire 这个项目。1.2 v0.1 踩过的坑以及 v0.2 为什么换成Claude 直接搜OpenHire 的 v0.1 其实做得很粗糙。当时我把采集到的职位信息全部灌进一个 JSON 文件然后在 prompt 里把这份数据一股脑塞给 Claude靠它的上下文理解去做筛选。听起来挺直接但实际用起来问题很大数据量一上来prompt 里的 token 消耗非常快。11 家公司、每家公司十几个职位光职位描述就几万字一次对话的上下文基本全被占满。Claude 的上下文窗口有限职位一多就记不住经常漏掉后面的公司。数据更新一次就要重新构造 prompt交互体验很差。v0.2 换了个思路不再把数据喂给模型而是让模型自己来查。核心就是把职位库做成一个可检索的外部工具Claude 在需要的时候主动调用工具、传入查询条件、拿到结果再回答。这种按需拉取的方式让 token 消耗降了一个数量级检索也精准得多。这个转变说白了就是从填鸭式喂资料变成给模型一个搜索引擎。Claude 不再需要记住所有职位它只需要知道有这么一个工具需要查职位的时候调用它就对了。1.3 方案选型为什么用 Claude 而不是自建前端可能有人会问你都把数据结构化好了为什么不直接写个网页或小程序大家自己上去查不就完了答案很简单OpenHire 的定位不是 To C 的招聘平台而是AI 工作流的一部分。如果你只是搜一次两次网页确实够用。但如果你像我一样需要频繁地调研行业动态、定期看竞品公司在扩招哪些岗位、帮朋友整理某个方向的职位机会那对话式交互的效率和体验完全不一样。另外Claude Code 本身具备很强的工具调用能力支持 MCPModel Context Protocol标准协议。这意味着 OpenHire 不需要为每个 AI 客户端单独开发适配层只要实现一个标准的 MCP server就能被 Claude 以及其他支持 MCP 的客户端直接使用。选型的时候我对比过几套方案方案交互方式接入成本维护成本扩展性自建 Web 前端手动搜索高高差直接把数据写进 prompt对话低中差受限于上下文自定义 Tool/Function Calling对话中低好MCP Server对话中低最好多家客户端通用最终选了 MCP Server 路线核心原因就是一次实现到处可用。v0.2 里我用的是 Claude Code 做测试客户端但这个 MCP server 本身并不绑定 Claude其他 AI 编程工具或 IDE 插件理论上也能接入。2. 数据层11 家机器人公司职位信息的结构化采集2.1 公司怎么选从我想去哪到行业晴雨表OpenHire 选公司没有追求数量而是有明确的标准。第一优先级是头部热门包括宇树、优必选、智元、云深处、傅利叶、乐聚、星动纪元、银河通用、松灵、逐际动力、加速进化这 11 家。选它们的逻辑有三层产品有辨识度。宇树的人形机器人、四足机器人知名度高优必选的 Walker 系列也是行业标杆这些公司的招聘动向本身就是行业风向标。岗位类型丰富。头部机器人公司通常同时招算法、硬件、软件、产品、销售、供应链等各类岗位样本够多检索才有意义。数据源相对公开。这些公司都有自己的官网招聘页信息结构比较规整采集难度低。这 11 家看起来是拍脑袋选的但背后其实是把行业头部公司 融资活跃公司 招聘需求旺盛的公司三个维度做了交集。2.2 采集策略官方招聘页为主没有一上来就到处爬职位数据是 OpenHire 的地基采集方式我分了三种按优先级排列第一种官方招聘页结构化解析。宇树、优必选这些大厂的招聘页面大多基于统一模板比如用 Moka、北森这类招聘管理系统页面上有固定的 DOM 结构和接口。通过分析接口返回的 JSON能比较干净地拿到职位名称、城市、经验要求、薪资范围、学历要求这些关键信息。这种方式的数据质量最高字段完整而且职位链接直接导向官方投递入口基本不会有假职位。第二种公开招聘平台的搜索接口。对没有官网招聘页的公司退而求其次是去公共招聘平台搜。这里必须强调一点我只采集公开可访问的搜索结果页并且严格遵守网站的 robots 协议和访问频率限制。用 Python 的 requests 加合理延时去请求而不是并发爆破。这也是合规底线——OpenHire 里所有的职位信息都来自公开渠道不碰任何需要登录才能看的内容也不做简历侧的任何事情。第三种人工标注兜底。总有些职位只通过 HR 朋友圈或者行业群传播没有固定的抓取源。这类信息我会手工整理成标准化条目后录入。别觉得手工 low信息聚合类项目人工审核本来就是质量保障的一环。2.3 数据结构设计了哪些字段为什么职位数据的结构从 v0.1 的抓到啥就存啥到 v0.2 收敛成了一个固定 schema。核心字段包括{ id: unitree-20240512-001, company: 宇树, company_alias: [Unitree, 宇树科技], title: SLAM算法工程师, category: 算法, city: 杭州, experience: 3-5年, education: 硕士, salary_min: 30, salary_max: 60, salary_unit: K, publish_date: 2025-05-12, source: official, url: https://www.unitree.com/careers/xxx, description_snippet: 负责机器人SLAM算法..., last_updated: 2025-05-12T10:00:0008:00 }字段设计有几个讲究。company_alias很关键宇树和 Unitree 是同一家公司如果不在别名里做好映射用户问Unitree 在招人吗就搜不到结果。category字段用于粗粒度聚合方便用户按算法硬件产品这类方向筛选。salary_min/max拆成结构化数字是为了让 Claude 能理解30-60K和月薪3万到6万是同一个意思——模型要处理的是自然语言跨度数据结构化程度越高越不容易产生歧义。数据存储用的是 JSON Lines每个职位一行便于增量更新和 Git 版本管理。这个选择没有太高深的理由就是简单可靠出问题容易排查也方便开源社区的人直接 diff。3. 接入层让 Claude 具备搜索职位库的完整实现3.1 核心机制从大模型到会使用工具的大模型先解释一个概念。Claude 本身不懂任何公司现在招不招人它的知识截止日期是固定的也不可能实时访问外部数据。但 Anthropic 给 Claude 提供了 Tool Use 机制让模型在对话过程中能够调用外部函数。打个比方你把一个大厨放在一个陌生的厨房里他菜谱背得再熟也没法做菜因为不知道这个厨房里有哪些食材。Tool Use 就相当于递给大厨一张菜单告诉他你想做什么菜就按菜单去取食材。Claude 在回答你宇树最近在招什么职位之前它会先判断这个问题需要实时数据我应该调用search_jobs这个工具。于是模型发起一次工具调用请求OpenHire 的服务端收到请求、执行查询、返回结构化结果Claude 拿到结果后组织语言回复你。这个过程不是AI 搜索而是AI 决定要不要搜索、怎么搜索。模型自己掌握着工具使用的主动权这就比你在 prompt 里硬塞一份数据高级得多。3.2 用 MCP 封装职位检索能力v0.2 里我选用了 MCP 来封装 OpenHire 的检索能力。MCP 的架构很清晰客户端比如 Claude Code负责和模型交互服务器端负责提供工具两者通过 JSON-RPC 通信。我需要做的事情就是实现一个 MCP server对外暴露一个工具。用 Python 写的话依赖mcpSDK核心代码非常简洁import json from mcp.server import Server from mcp.server.stdio import stdio_server from typing import Any app Server(openhire) # 加载职位数据 with open(data/jobs.jsonl, r, encodingutf-8) as f: jobs [json.loads(line) for line in f] app.list_tools() async def list_tools(): return [ { name: search_jobs, description: 搜索机器人公司职位。支持按公司、城市、职位关键词、学历要求等条件过滤返回匹配的职位列表。, inputSchema: { type: object, properties: { company: { type: string, description: 公司名称或别名如宇树、Unitree、优必选、UBTECH }, city: { type: string, description: 工作城市如杭州、深圳、北京 }, keyword: { type: string, description: 职位关键词如SLAM、强化学习、嵌入式 }, experience: { type: string, description: 经验要求如3-5年 } } } } ] app.call_tool() async def call_tool(name: str, arguments: dict[str, Any]): if name ! search_jobs: return {content: [{type: text, text: f未知工具: {name}}]} results query_jobs(arguments) return { content: [ { type: text, text: json.dumps(results, ensure_asciiFalse, indent2) } ] }query_jobs函数就是普通的 Python 逻辑遍历内存中的职位列表按条件过滤。这里有个细节工具返回的内容类型是text内容是一段经过裁剪的 JSON。为什么要裁剪因为返回给 Claude 的内容本身也占用 token。如果匹配到 30 个职位每个都带完整描述一次工具调用就可能吃掉几千 token。所以query_jobs里做了字段裁剪默认只保留职位名称、公司、城市、薪资范围、URL 这些关键字段description_snippet只保留前 200 字。Claude 觉得某个职位合适用户想了解更多再点链接进去看完整 JD这是合理的分流。3.3 在 Claude Code 中配置 OpenHire MCP Server光有 server 还不行得让 Claude Code 知道去哪里找它。配置 MCP server 通常是在 Claude Code 的配置文件claude_desktop_config.json或settings.json里声明{ mcpServers: { openhire: { command: python, args: [/path/to/openhire/server.py], env: { OPENHIRE_DATA_PATH: /path/to/openhire/data/jobs.jsonl } } } }配置好之后重启 Claude Code输入/mcp查看已连接的 server能看到openhire出现在列表里就说明连接成功。这时候直接问帮我在杭州找找机器人公司的 SLAM 算法岗位要硕士学历、3 年以上经验的。正常来说Claude 会自己决定调用search_jobs然后返回市面上的职位列表并附上原始链接。我实际测试过程中前几次 Claude 确实会主动调用工具但它还是会偶尔自作聪明。比如用户问宇树招嵌入式吗Claude 可能直接调用工具查了一遍然后把结果里没有匹配项的结论说出来这没问题。但有时候它会跳过工具直接基于常识回答宇树作为机器人公司一般会招嵌入式岗位——这种回答虽然不完全是错的但没有时效性也不够具体。解决办法是在工具 description 里写清楚此工具覆盖以下公司宇树、优必选、智元、云深处、傅利叶、乐聚、星动纪元、银河通用、松灵、逐际动力、加速进化并在 system prompt 层面提醒涉及职位招聘信息必须先调用 search_jobs。这个强制先调工具的提示在信息准确性要求高的场景里很值得借鉴。4. 实操过程与常见问题排查实录4.1 完整跑通流程从安装到第一次检索如果你也想在本地把 OpenHire v0.2 跑起来完整的流程可以拆成四步第一步准备环境。需要 Python 3.10 和 Claude Code 客户端。Python 环境用venv隔离避免依赖冲突python3 -m venv .venv source .venv/bin/activate pip install mcp httpx这里提醒一句无论你用什么虚拟环境工具关键在于把 MCP server 的 Python 解释器路径搞对。Claude Code 在启动 server 时用的是配置里command指定的可执行文件如果你直接用python而不是.venv/bin/python很可能出现依赖装了一大堆但 server 启动就报 ModuleNotFoundError 的情况。第二步拉取项目和职位数据。从 GitHub 仓库 clone OpenHire然后运行数据更新脚本git clone https://github.com/yourname/openhire.git cd openhire python scripts/update_data.pyupdate_data.py会访问各家公司的招聘接口增量抓取最新职位并写入data/jobs.jsonl。第一次运行建议加--full参数做全量抓取之后就是增量更新。第三步配置 MCP server。按 3.3 节的方式把mcpServers配置写入 Claude Code 的配置文件。路径搞不清楚的话直接在 Claude Code 里执行/mcp add openhire -- python /path/to/openhire/server.py它会帮你写入配置。第四步验证。在 Claude Code 里输入/mcp确认openhire显示为 connected。然后测试一句优必选最近在招哪些岗位帮我按深圳和算法方向筛一下。如果 Claude 返回了符合预期的职位列表说明整个链路是通的。4.2 职位更新不生效的排查思路我在实际维护过程中遇到最多的问题就是数据明明更新了但 Claude 搜到的还是旧数据。先说原因server.py在启动时会把jobs.jsonl一次性加载进内存。如果你在 server 运行期间重新跑了update_data.py内存里存的是旧数据搜索当然不生效。这不是 bug是设计使然——避免每次查询都去读磁盘性能更好。解决办法有两个一是改完数据后重启 Claude Code让 MCP server 重新加载二是我后来加的方案在search_jobs里加了一个可选的reload参数当检测到数据文件 mtime 有变化时自动重载。说实话对于个人使用场景重启客户端反而是最省事最不容易出错的方式。加了自动重载之后反而出现过数据文件写了一半、JSON 解析失败导致 server 崩溃的情况。这里也引出一个教训如果要做自动重载必须保证数据文件是原子写入的——先写临时文件写入成功后用os.replace替换原文件。4.3 中文搜索的坑别名映射与分词问题中文信息检索天然比英文复杂OpenHire 也踩了几个典型的坑。第一个坑是公司名别名。用户问宇树能查到但问Unitree就查不到。解决方案是建一个别名映射表把公司中文名、英文名、简称都关联到同一个实体上。这个表在 2.3 节的company_alias字段里体现过。别小看这个映射宇树的别名至少包括宇树宇树科技UnitreeUnitree Robotics优必选则有优必选UBTECH优必选科技三种常见叫法。如果用户说的是简称或者英文名映射表不够全召回就会出问题。第二个坑是职位名称的分词。用户搜机器人算法工程师和搜算法工程师是两个需求前者可能希望匹配更精专的岗位后者更宽泛。简单的做法是子串匹配但SLAM 算法工程师这种复合词直接按空格拆开匹配会出问题。我在实现里用了多关键词 AND 匹配逻辑把用户的查询拆成多个词要求所有词都出现在职位标题或公司名里。比如搜杭州 SLAM就要求职位记录里 city 含杭州且 title 含SLAM。这种朴素的方法在几十条数据量的场景下效果很好不够高级但足够实用。第三个坑是城市名。成都和重庆带都字但完全不同北京北京市北京·海淀区也指向同一城市。我在入库前做了城市名归一化统一转成标准的市级名称。4.4 数据采集合规与反爬注意事项前面提到过OpenHire 只采集公开信息。但在实际操作中还是要遵守几个隐性规则否则既会给对方服务器制造压力也可能给自己惹麻烦控制请求频率。爬取招聘页面时至少设置 1-2 秒的间隔加上随机抖动不要并发请求。识别和尊重 robots.txt。有些招聘站点明确禁止抓取这时候就得放弃该数据源改用人工标注或直接引导用户去官网自行搜索。不抓登录后可见的数据。公开页面上没有的职位信息说明人家本来就没打算公开展示强行去抓就过了线。数据展示时保留原始链接。OpenHire 的定位是索引而不是搬运用户在 AI 回答里看到的是职位摘要想要完整 JD 必须点击跳转原始来源。这样既尊重了招聘方的信息版权也能确保用户看到的信息永远是最新的。4.5 常见问题速查表为了方便后来者我把开发调试中遇到的高频问题整理成一个速查表问题现象可能原因排查与解决/mcp显示 openhire disconnectedMCP server 启动失败手动运行python server.py看报错检查 Python 依赖是否装齐Claude 不调用search_jobs直接瞎答工具描述不够明确或客户端缓存了旧配置在工具 description 中明确触发条件重启 Claude Code必要时在 system prompt 里加强制调用说明搜索结果有旧数据server 内存里的数据没刷新重启 Claude Code后端休改数据更新脚本为原子写入中文职位名匹配不到没有做分词或别名映射检查公司别名表尝试用关键词 AND 匹配而不是整句匹配JSON 解析报错数据文件被部分写入改为写临时文件后os.replace原子替换启动时做好异常兜底工具返回内容过长命中职位过多裁剪返回字段限制单次返回条数建议最多 20 条引导用户加筛选条件4.6 使用体验上的一层理性思考OpenHire 本质上是个索引工具它解决的问题是知道哪家公司大概在招什么方向的人但无法保证职位信息的实时性、完整性更无法帮你判断一家公司的真实发展状况。招聘页面上挂着岗位不代表这家公司就一定在大力扩张也可能只是挂着没撤。所以在实际使用中我把 OpenHire 定位为线索发现工具而不是决策依据——AI 告诉你有哪些机会但投不投、去哪家还得靠自己的判断。5. 从 v0.2 往后还能怎么扩展OpenHire v0.2 目前支持 11 家公司已经是让 Claude 直接搜职位的可用状态。但说实话我心里清楚它还处于能用到好用之间的位置。接下来的几个方向按优先级排列一是扩大公司覆盖范围。机器人行业的腰部公司还有很多比如宇树之外的四足机器人厂商、专注灵巧手和传感器的新锐团队、做仓储物流机器人的集成商这些都值得纳入。另外一个思路是开放自定义数据源配置让用户把自己关注的特定公司和招聘页面加进去。二是增加职位趋势分析。现在 Claude 能搜到职位但还不能回答过去三个月宇树新增了多少算法岗或者哪些公司在大量招具身智能相关的人。这些分析逻辑其实不复杂只要在检索层之上加一个聚合统计的接口Claude 就能基于历史数据做趋势判断。这比单纯搜索职位信息更有价值也更贴合用户调研行业的需求。三是兼容更多 AI 客户端。MCP 的好处就是一处实现多处接入。目前实测过 Claude Code后续还可以在 Cursor、VSCode 扩展等支持 MCP 的工具里直接复用同一套 server无需额外开发成本。最后从一个使用者的角度说点真实体会。我花了很长时间搭这个项目但真正让我觉得值了的瞬间不是看到工具被成功调用的日志输出而是某天一个朋友随口问我宇树现在算法岗位卡得严吗我想了想打开终端对 Claude 说帮我查一下宇树最近发的算法岗JD和学历要求几秒钟后得到了一份带着链接的清晰列表。那一刻我突然意识到所谓 AI 改变信息获取方式其实不需要什么惊天动地的应用把一件小事做扎实让人能用自然语言按需检索一个小而精的信息库就已经足够实用了。这也是我坚持把 OpenHire 做成开源项目的原因——如果你也想在自己的机器人行业求职调研里用上它欢迎提 issue 或直接贡献你关注的职位源。
返回列表