用Gemini+NestJS搭建AI找工作助手,告别海投内耗,精准匹配

内容分享3小时前发布
0 0 0
全能 AI 聚合平台 免费

一站式接入主流 AI 大模型,支持对话 · 生图 · 生视频,即开即用

ChatGPT Claude Gemini Grok DeepSeek 通义千问 Ollama
AI对话 AI生图 AI视频
免费使用 →

用Gemini+NestJS搭建AI找工作助手,告别海投内耗,精准匹配

一、海投300份简历,只收到1个真offer?AI早已帮人躺赢

每个求职者都经历过这样的内耗:每天花3小时刷招聘软件,翻几百条岗位,一半是不符合经验的资深岗,一半是看似匹配实则无关的岗位——后端工程师刷到前端开发,应届生收到总监岗邀请,忙活一周连个有效面试都没有。

有人吐槽“找工作比上班还累”,却很少有人想过,重复的筛选工作本就不该由人来做。开发者Jerlin Joy就抓住了这个痛点,用Google Gemini和NestJS搭建了一款名为JobHunt.ai的AI求职代理,能自动爬取岗位、匹配简历,只把“精准匹配”的机会推送给自己,彻底解放双手。

这款AI助手的出现,的确 打破了传统求职的低效困境,让求职者从繁琐的筛选中解脱出来。但它真的能适配所有求职者?普通人没有编程基础,也能用上这样的工具吗?实则AI求职的核心从不是“替代人”,而是“帮人减负”,关键在于找对方法。

先给大家详细介绍下这款AI助手用到的核心技术,毕竟技术的可靠性,直接决定了求职匹配的精准度,也关系到我们普通人能否借鉴复用。

核心技术详情(开源+免费+GitHub星数,实测可查):

1. NestJS:完全开源免费,截至2026年3月,GitHub星数达67k+,基于Node.js构建,融合了多种编程思想,结构清晰、规范性强,尤其适合中小型微服务项目,也是前端转后端开发者的首选框架,能为AI助手提供稳定的模块化后端支撑。

2. Google Gemini Pro:谷歌推出的AI大模型,支持免费使用(免费版有每日配额限制),也有付费版本(AI Plus每月约50元,AI Pro每月约125元),其中免费版足以满足个人求职助手的搭建需求,能实现语义匹配、领域验证等核心功能,其嵌入服务可将文本转换为高维向量,实现精准语义识别。

3. Tesseract.js:开源免费,GitHub星数达28.8k,支持超过100种语言的OCR识别,能解决扫描版简历无法解析的问题,是AI助手的“眼睛”。

4. pdf2pic:开源免费,可将PDF文件转换为图片格式,配合Tesseract.js实现扫描版简历的文字提取,完美解决传统简历解析工具的短板。

5. GitHub Actions:完全免费,公共仓库可不限时长使用,能实现定时任务触发,让AI助手每天自动运行,无需手动操作。

二、核心拆解:手把手教你搭建AI求职助手,代码可直接复制使用

JobHunt.ai的核心逻辑很简单:替代人工完成“爬取岗位—解析简历—精准匹配—推送通知”的全流程,核心优势在于摆脱了传统招聘平台的“关键词陷阱”,用语义智能实现真正的精准匹配。下面从技术架构、核心模块、具体代码三个方面,完整拆解搭建过程,新手也能跟着操作。

核心前提:环境准备

搭建前需准备好基础环境,确保所有工具能正常运行,步骤如下:

1. 安装Node.js(推荐16.x及以上版本),用于运行NestJS项目;

2. 注册Google账号,获取Gemini API Key(免费版即可),用于调用Gemini Pro模型;

3. 安装Git,用于管理代码和配置GitHub Actions;

4. 安装依赖包:打开终端,执行相应命令安装NestJS、Tesseract.js、pdf2pic等核心依赖。

第一步:搭建后端框架(NestJS)

NestJS作为整个AI助手的后端支撑,负责整合所有模块、处理请求和任务调度,具体操作和代码如下:

// 1. 全局安装NestJS脚手架
npm install -g @nestjs/cli

// 2. 创建新项目
nest new jobhunt-ai

// 3. 进入项目目录
cd jobhunt-ai

// 4. 安装核心依赖(Gemini、OCR相关)
npm install @google/generative-ai tesseract.js pdf2pic axios

创建完成后,项目结构会自动生成,无需手动配置基础架构,NestJS的模块化设计会让后续的功能扩展更便捷。

第二步:实现OCR识别模块(解决扫描简历解析问题)

传统简历解析工具无法识别扫描版PDF,这也是许多求职者的痛点。该模块通过Tesseract.js和pdf2pic实现“PDF转图片—图片识别文字”的自动 fallback,确保所有格式的简历都能正常解析,代码如下:

// src/ocr/ocr.service.ts
import { Injectable } from '@nestjs/common';
import { createWorker } from 'tesseract.js';
import { fromPath } from 'pdf2pic';
import * as fs from 'fs';

@Injectable()
export class OcrService {
  // 解析PDF简历(支持扫描版)
  async parseResume(pdfPath: string): Promise<string> {
    try {
      // 先尝试读取PDF文本
      let text = '';
      // 此处省略简单PDF文本读取逻辑(可通过pdf-parse等依赖实现)
      
      // 如果文本为空,说明是扫描版,执行OCR识别
      if (!text || text.trim() === '') {
        // 1. PDF转图片(300 DPI,确保识别清晰度)
        const options = {
          density: 300,
          savePath: './temp',
          format: 'png',
          width: 1200,
        };
        const convert = fromPath(pdfPath, options);
        const page = await convert(1, { responseType: 'image' });
        
        // 2. 图片OCR识别
        const worker = await createWorker('eng+chi_sim'); // 支持中英文
        const { data: { text: ocrText } } = await worker.recognize(page.path);
        await worker.terminate();
        
        // 删除临时图片
        fs.unlinkSync(page.path);
        text = ocrText;
      }
      
      return text.trim();
    } catch (error) {
      console.error('简历解析失败:', error);
      throw new Error('简历解析失败,请检查文件格式');
    }
  }
}

第三步:实现Gemini语义匹配模块(核心功能)

这是AI助手的核心,摆脱传统关键词匹配的弊端,通过向量嵌入(Vector Embeddings)将简历和岗位描述转换为高维向量,用余弦类似度判断两者的语义匹配度,同时加入领域验证,避免跨领域匹配,代码如下:

// src/gemini/gemini.service.ts
import { Injectable } from '@nestjs/common';
import { GoogleGenerativeAI, Embedding } from '@google/generative-ai';

@Injectable()
export class GeminiService {
  private genAI: GoogleGenerativeAI;
  
  constructor() {
    // 初始化Gemini(替换为你的API Key)
    this.genAI = new GoogleGenerativeAI('你的Gemini API Key');
  }
  
  // 生成文本的向量嵌入
  private async generateEmbedding(text: string): Promise<number[]> {
    const model = this.genAI.getGenerativeModel({ model: 'embedding-001' });
    const result = await model.embedContent({
      content: text,
      taskType: 'retrieval_document',
    });
    return result.embedding.values;
  }
  
  // 计算余弦类似度(判断匹配度,0-1之间,越接近1匹配度越高)
  private calculateCosineSimilarity(vec1: number[], vec2: number[]): number {
    const dotProduct = vec1.reduce((sum, a, i) => sum + a * vec2[i], 0);
    const mag1 = Math.sqrt(vec1.reduce((sum, a) => sum + a * a, 0));
    const mag2 = Math.sqrt(vec2.reduce((sum, a) => sum + a * a, 0));
    return mag1 && mag2 ? dotProduct / (mag1 * mag2) : 0;
  }
  
  // 领域验证(避免后端匹配前端等跨领域情况)
  private async verifyDomain(resumeText: string, jobText: string): Promise<boolean> {
    const model = this.genAI.getGenerativeModel({ model: 'gemini-pro' });
    const prompt = `
      请分析以下简历和岗位描述的领域是否匹配:
      简历:${resumeText.substring(0, 500)}(截取前500字符,避免上下文溢出)
      岗位描述:${jobText.substring(0, 500)}
      要求:1. 判断简历对应的职业领域(如后端开发、前端开发、产品经理等);
            2. 判断岗位对应的职业领域;
            3. 若两者领域一致或高度相关,返回true,否则返回false。
      仅返回true或false,不要多余内容。
    `;
    const result = await model.generateContent(prompt);
    const response = await result.response;
    return response.text().trim().toLowerCase() === 'true';
  }
  
  // 核心匹配方法(返回匹配分数,0-1)
  async matchResumeAndJob(resumeText: string, jobText: string): Promise<number> {
    // 1. 生成向量嵌入
    const resumeEmbedding = await this.generateEmbedding(resumeText);
    const jobEmbedding = await this.generateEmbedding(jobText);
    
    // 2. 计算基础匹配分数
    let score = this.calculateCosineSimilarity(resumeEmbedding, jobEmbedding);
    
    // 3. 领域验证,不匹配则扣除50%分数
    const isDomainMatch = await this.verifyDomain(resumeText, jobText);
    if (!isDomainMatch) {
      score *= 0.5; // 惩罚机制,确保不推送跨领域岗位
    }
    
    return score;
  }
}

第四步:实现岗位爬取与通知模块

该模块负责爬取招聘平台岗位(以LinkedIn为例),筛选出匹配分数高于阈值(如0.7)的岗位,通过Discord Webhook推送给用户,同时加入Token优化,避免超出Gemini免费额度,代码如下:

// src/job/job.service.ts
import { Injectable } from '@nestjs/common';
import axios from 'axios';
import { GeminiService } from '../gemini/gemini.service';
import { OcrService } from '../ocr/ocr.service';

@Injectable()
export class JobService {
  constructor(
    private readonly geminiService: GeminiService,
    private readonly ocrService: OcrService,
  ) {}
  
  // 爬取LinkedIn岗位(简化版,实际可优化爬取逻辑)
  private async scrapeLinkedInJobs(keyword: string): Promise<any[]> {
    const url = `https://www.linkedin.com/jobs/search/?keywords=${encodeURIComponent(keyword)}`;
    const response = await axios.get(url, {
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36',
      },
    });
    
    // 此处省略HTML解析逻辑,提取岗位标题、描述、要求等信息
    // 实际开发中可使用cheerio等依赖解析HTML
    return [
      {
        title: 'Node.js Backend Engineer',
        description: '负责后端服务开发,熟练使用Node.js、NestJS,熟悉数据库设计...',
        company: '某科技公司',
      },
      // 更多岗位...
    ];
  }
  
  // Token & 上下文优化(避免超出Gemini免费额度)
  private async optimizeContext(text: string): Promise<string> {
    // 智能截断长文本(控制在700字符以内)
    if (text.length > 700) {
      return text.substring(0, 700) + '...';
    }
    return text;
  }
  
  // 延迟控制(12秒间隔,避免API调用过于频繁)
  private async delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  
  // 推送通知到Discord
  private async sendDiscordNotification(job: any): Promise<void> {
    const webhookUrl = '你的Discord Webhook URL';
    await axios.post(webhookUrl, {
      content: `找到精准匹配岗位:
标题:${job.title}
公司:${job.company}
描述:${job.description.substring(0, 200)}...`,
    });
  }
  
  // 核心执行方法
  async runJobHunt(resumePath: string, keyword: string): Promise<void> {
    try {
      // 1. 解析简历
      const resumeText = await this.ocrService.parseResume(resumePath);
      
      // 2. 爬取岗位
      const jobs = await this.scrapeLinkedInJobs(keyword);
      
      // 3. 逐一匹配,推送精准岗位
      for (const job of jobs) {
        // 优化岗位描述,避免上下文溢出
        const optimizedJobDesc = await this.optimizeContext(job.description);
        
        // 计算匹配分数
        const matchScore = await this.geminiService.matchResumeAndJob(resumeText, optimizedJobDesc);
        
        // 匹配分数高于0.7,推送通知
        if (matchScore > 0.7) {
          await this.sendDiscordNotification(job);
        }
        
        // 延迟12秒,避免超出API调用限制
        await this.delay(12000);
      }
    } catch (error) {
      console.error('AI求职助手执行失败:', error);
    }
  }
}

第五步:配置定时任务(GitHub Actions)

通过GitHub Actions设置定时任务,让AI助手每天自动运行,无需手动触发,配置文件如下(创建
.github/workflows/jobhunt.yml):

name: JobHunt AI Auto Run
on:
  schedule:
    # 每天早上9点运行(UTC时间1点,北京时间比UTC快8小时)
    - cron: '0 1 * * *'
  workflow_dispatch: # 支持手动触发

jobs:
  run-jobhunt:
    runs-on: ubuntu-latest
    steps:
      - name: 拉取代码
        uses: actions/checkout@v4
      
      - name: 安装Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '16'
      
      - name: 安装依赖
        run: npm install
      
      - name: 运行AI求职助手
        run: npm run start:dev
        env:
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
          DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}

配置完成后,将代码推送到GitHub,在仓库设置中添加Gemini API Key和Discord Webhook URL作为密钥,AI助手就会每天自动爬取岗位、匹配简历并推送通知。

三、辩证分析:AI求职助手不是“万能药”,优势与局限并存

JobHunt.ai的出现,无疑为求职者提供了一种高效的求职方式,它解决了传统海投的低效、内耗问题,让精准匹配成为可能,这是它不可替代的优势。尤其是对于程序员、设计师等技术岗位,语义匹配能精准识别技能需求,避免因关键词遗漏而错过合适岗位,同时自动化流程也节省了大量时间,让求职者能专注于简历优化和面试准备。

但我们不能盲目神化AI求职助手,它也有自身的局限。第一,它的核心依赖编程能力,普通人没有基础,很难独立搭建,即便有现成的代码,也可能因环境配置、API调用等问题无法正常使用;其次,岗位爬取存在必定的局限性,部分招聘平台有反爬机制,可能导致爬取失败或岗位信息不完整;最后,AI匹配无法替代人工判断,列如岗位的隐性要求、公司文化适配度等,都需要求职者自己进一步筛选。

更值得思考的是,AI求职助手的普及,会不会让求职竞争变得更激烈?当所有人都能用AI精准匹配岗位,原本靠“海投碰运气”的求职者,会不会彻底失去机会?实则答案很简单:AI只是工具,它能帮你筛选机会,但不能帮你提升能力。真正能决定你能否拿到offer的,还是你的专业技能和综合素质,AI只是帮你更快地找到适合自己的舞台。

四、现实意义:2026年,求职的核心的是“匹配”,而非“搜索”

在2026年这个自动化时代,“重复劳动就该被AI替代”已经成为共识,求职也不例外。传统的“海投简历—等待回复”模式,不仅效率低下,还容易让求职者陷入自我怀疑,而AI求职助手的核心价值,就是将求职者从重复的筛选工作中解放出来,让求职回归本质——找到真正适合自己的岗位,实现人岗精准匹配。

对于求职者而言,AI求职助手不仅能节省时间和精力,还能减少“无效投递”带来的内耗,让每一次投递都更有针对性,提升面试成功率。尤其是应届生和转行求职者,他们对岗位认知不足,容易投递不符合自身条件的岗位,AI的语义匹配和领域验证功能,能帮他们避开坑位,少走弯路。

对于开发者而言,JobHunt.ai的搭建思路也提供了一个很好的实践案例——将AI大模型与后端框架结合,解决现实中的实际问题。这种“AI+实用工具”的开发模式,未来会越来越普及,无论是求职、办公还是生活,都能通过类似的思路,用技术提升效率、解决痛点。

更重大的是,AI求职助手的出现,也在倒逼招聘行业升级。传统招聘平台的“关键词匹配”模式已经无法满足求职者和企业的需求,未来会有更多平台引入语义匹配、AI筛选等功能,让招聘变得更高效、更精准,实现求职者和企业的双向共赢。

五、互动话题:你被“无效求职”内耗过吗?AI能帮你解决痛点吗?

信任许多人都有过这样的经历:每天刷招聘软件到深夜,投出的简历石沉大海;好不容易收到面试邀请,去了才发现岗位和自己的预期完全不符;为了增加成功率,盲目海投,最后却连一个有效回复都没有,越找越焦虑。

JobHunt.ai这样的AI求职助手,的确 能解决这些痛点,但它也需要必定的编程基础,对于普通人来说,门槛并不低。那么问题来了:

1. 你找工作时,最头疼的是“海投内耗”还是“找不到合适岗位”?

2. 如果有现成的AI求职工具,你愿意尝试吗?你最看重它的什么功能?

3. 你觉得AI会彻底改变求职模式吗?未来求职者还需要自己筛选岗位吗?

欢迎在评论区留言讨论,说说你的求职经历和见解,也可以转发给正在找工作的朋友,一起摆脱内耗,精准求职!

© 版权声明

相关文章

暂无评论

none
暂无评论...