6897 words
34 minutes
Hr-Helper Agent
NOTE

输入输出、节点流转、按需求拆分任务、多Agent框架、Sub-Agent 职责划分

多 Agent 协作职责划分#

整体协作图#

┌─────────────────┐
│ Orchestrator │
│ (Router) │
│ ───────────── │
│ 意图分类 │
│ 任务分发 │
│ 结果聚合 │
└────────┬────────┘
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ JD Worker │ │ Resume Worker │ │ Match Worker │
│ Pool (1-2) │ │ Pool (5-10) │ │ Pool (3-5) │
└────────┬───────┘ └────────┬───────┘ └────────┬───────┘
│ │ │
▼ ▼ ▼
JDSchema ResumeSchema MatchResult

1. Orchestrator (Router)#

项目内容
类型调度者(不是执行者)
模型Haiku 4.5(简单路由,便宜)
职责意图分类、任务分发、结果聚合

输入
HR: “筛选 5 年以上 Python 工程师,重点看架构能力”

Orchestrator Think

  1. 意图识别:这是一个「筛选请求」
  2. 需要 JD 解析 + 批量简历匹配
  3. 分发 JD Worker → 等待 JDSchema
  4. 分发 Resume Worker → 等待批量 ResumeSchema
  5. 分发 Match Worker → 等待 MatchResults
  6. 聚合结果返回给 HR

输出

{
"intent": "screen_candidates",
"tasks": [
{"task_id": "t1", "agent": "JDWorker", "input": "..."},
{"task_id": "t2", "agent": "ResumeWorker", "input": "resume_batch_001"},
{"task_id": "t3", "agent": "MatchWorker", "input": {"jd: "t1", "resumes": "t2"}}
],
"wait_for": ["t3"]
}

2. JD Worker#

项目内容
类型单任务执行者
模型Sonnet 4.6(深度理解 JD)
副本1-2 个(JD 解析不频繁)

职责:将 JD 文本解析为结构化 JDSchema

输入
“招聘高级 Python 后端开发,要求 5 年以上经验,熟悉 FastAPI、Django,有微服务架构经验优先,具备良好的团队协作能力和沟通能力,本科及以上学历”

处理流程

  1. LLM 提取关键实体(技能、经验、学历)
  2. 构建技能树 + 权重
  3. 区分 required vs optional
  4. 异常检测(技能矛盾、要求不合理)
  5. 输出 JDSchema

输出

{
"job_id": "jd_001",
"job_title": "高级 Python 后端开发",
"硬技能": [
{"skill": "Python", "weight": 0.3, "required": true, "level": "expert"},
{"skill": "FastAPI", "weight": 0.2, "required": true, "level": "advanced"},
{"skill": "Django", "weight": 0.15, "required": true, "level": "advanced"},
{"skill": "微服务架构", "weight": 0.1, "required": false, "level": "intermediate"}
],
"软技能": [
{"skill": "团队协作", "weight": 0.15, "required": true},
{"skill": "沟通能力", "weight": 0.1, "required": true}
],
"经验年限": {"min": 5},
"学历": {"min": "本科"},
"jd_embedding": [0.123, ...]
}

3. Resume Worker#

项目内容
类型单任务执行者
模型Haiku 4.5(高吞吐,便宜)
副本5-10 个(简历量大)
特点无状态,可水平扩展

职责:解析简历为结构化 ResumeSchema

输入
resume_file: PDF/DOCX/IMG
candidate_id: “cand_001”

处理流程

1. 格式检测(PDF/DOCX/HTML/IMG)
2. 文本提取
- PDF: pdf-parse
- DOCX: python-docx
- IMG: Tesseract OCR
3. LLM 结构化提取
- 姓名、联系方式
- 工作经历(公司、职位、时间、描述)
- 教育背景(学历、专业、毕业年份)
- 技能清单(技能名、年限、级别)
4. 向量化(用于向量召回)
5. 输出 ResumeSchema

输出

{
"candidate_id": "cand_001",
"name": "张三",
"工作经历": [
{
"company": "XX科技",
"title": "高级工程师",
"duration": "2020.03 - 至今",
"years": 4,
"description": "负责后端架构设计,使用 FastAPI 重构微服务...",
"skills_extracted": ["Python", "FastAPI", "微服务"]
}
],
"教育背景": {"degree": "本科", "major": "计算机"},
"技能清单": {
"Python": {"level": "expert", "years": 6},
"FastAPI": {"level": "advanced", "years": 3}
},
"总工作经验": 6,
"resume_embedding": [0.456, ...]
}

4. Match Worker#

项目内容
类型单任务执行者
模型Sonnet 4.6(深度匹配+推理)
副本3-5 个
特点核心计算模块,最耗时

职责:计算 JD 与简历的匹配度 + 生成解释

输入

{
"jd": JDSchema,
"candidate": ResumeSchema
}

处理流程

1. 硬技能匹配 (40%)
- 技能级别对比:Python expert ≥ JD 要求 expert ✓
- 技能是否存在:简历有 FastAPI,JD 要求 FastAPI ✓
2. 软技能匹配 (20%)
- 语义相似度计算
- 从工作描述推断软技能
3. 经验年限匹配 (25%)
- 简历 6 年 ≥ JD 要求 5 年 ✓
4. 学历匹配 (15%)
- 简历本科 ≥ JD 要求本科 ✓
5. 优选条件加分 (5%)
- 简历有微服务经验,属于优选条件 +20% 加分
6. 综合得分计算
36.8 + 15.6 + 25.0 + 15.0 + 1.0 = 85.6 分
7. Explanation 生成
- 为什么推荐/不推荐
- 匹配的优势
- 潜在风险
- 面试重点

输出

{
"candidate_id": "cand_001",
"total_score": 85.6,
"recommendation": "强烈推荐",
"breakdown": {
"硬技能": {"score": 92, "weighted": 36.8},
"软技能": {"score": 78, "weighted": 15.6},
"经验": {"score": 100, "weighted": 25.0},
"学历": {"score": 100, "weighted": 15.0},
"优选条件": {"score": 20, "weighted": 1.0}
},
"explanation": {
"summary": "综合得分 85.6,与岗位高度匹配",
"strengths": [
"Python 专家级别(6年),超过岗位要求",
"FastAPI/Django 技能与岗位吻合",
"具备微服务架构经验(优选条件加分)"
],
"concerns": ["软技能建议面试核实"],
"missing": [],
"interview_focus": ["微服务架构设计思路", "团队协作角色"]
},
"confidence": 0.89
}

5. Worker 间协作时序#

HR Request
┌─────────────────────────────────────────────────────────────────┐
│ Orchestrator │
│ 1. 意图分类:「筛选候选人」 │
│ 2. 任务分发 │
└─────────────────────────────────────────────────────────────────┘
├──────────────────────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ JD Worker │ │ Resume Repo │
│ │ │ (批量读取) │
│ 解析 JD │ │ │
└──────┬───────┘ └──────┬───────┘
│ │
│ JDSchema │ ResumeSchema[]
│ │
│ ┌─────────────────┘
│ │
▼ ▼
┌──────────────────────────────────┐
│ Match Worker Pool │
│ ┌────────┐ ┌────────┐ ┌────────┐│
│ │Match #1│ │Match #2│ │Match #N││
│ └────────┘ └────────┘ └────────┘│
│ 并行计算每个候选人的匹配度 │
└──────────────────────────────────┘
│ MatchResults[]
┌──────────────────────────────────┐
│ Orchestrator │
│ 聚合 + 排序 + 分页 │
│ 返回 Top-K 给 HR │
└──────────────────────────────────┘

6. 职责边界清晰化#

问题解答
JD Worker 太多?JD 解析不频繁,1-2 个足够
Resume Worker 太少?简历量大,需要 5-10 个并行
Match Worker 挂了?Orchestrator 检测超时,重新分发
JD 还没解析完就匹配?Orchestrator 等待 t1 完成后再分发 t3
两个 Worker 抢资源?Redis Queue 内部实现,不暴露给 Agent

7. 与传统 Orchestrator-Workers 的区别#

传统模式本设计
Orchestrator 决定「谁来执行」Orchestrator 只决定「做什么」,Queue 决定「谁来做」
Worker 是通用执行者Worker 是专业化 agent(JD专用、Match专用)
结果直接返回统一经过 Orchestrator 聚合

这样设计的好处是:专业化比通用化更精准,JD Worker 专注理解招聘需求,Match Worker 专注匹配逻辑。

简历知识库存储什么?#


1. 数据分层#

┌─────────────────────────────────────────────────────────────────┐
│ 简历知识库四层架构 │
├─────────────────────────────────────────────────────────────────┤
│ L1: 原始文件层 (Raw Files) │
│ - PDF/DOCX/HTML/IMG 原文件 │
│ - 用途: 存档、复核、OCR 重新处理 │
├─────────────────────────────────────────────────────────────────┤
│ L2: 结构化数据层 (Structured Schema) │
│ - ResumeSchema (JSON) │
│ - 用途: 业务查询、筛选、排序 │
├─────────────────────────────────────────────────────────────────┤
│ L3: 语义索引层 (Semantic Index) │
│ - 向量 embedding (技能、工作描述) │
│ - 用途: 语义相似召回 │
├─────────────────────────────────────────────────────────────────┤
│ L4: 知识图谱层 (Knowledge Graph) │
│ - 技能实体关系 │
│ - 候选人-公司-技能-项目的图关系 │
│ - 用途: 跨维度推理、同义词扩展 │
└─────────────────────────────────────────────────────────────────┘

2. 存储选型与数据内容#

┌───────────────┬────────────────────────┬────────────────────────────────────────┐
│ 存储层 │ 技术选型 │ 存储内容 │
├───────────────┼────────────────────────┼────────────────────────────────────────┤
│ L1 原始文件 │ S3 / Blob Storage │ PDF/DOCX/IMG 原始文件 │
├───────────────┼────────────────────────┼────────────────────────────────────────┤
│ L2 结构化数据 │ PostgreSQL │ ResumeSchema JSON + 业务字段 │
├───────────────┼────────────────────────┼────────────────────────────────────────┤
│ L3 向量索引 │ Weaviate / Pinecone │ skill_embedding, description_embedding │
├───────────────┼────────────────────────┼────────────────────────────────────────┤
│ L4 知识图谱 │ Neo4j / Amazon Neptune │ 技能图谱、公司关系、项目关系 │
└───────────────┴────────────────────────┴────────────────────────────────────────┘

3. 读写分离#

┌─────────────────────────────────────────────────────────────────┐
│ 读写分离架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 写操作 (简历上传、JD创建) │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Primary │ (PostgreSQL Primary) │
│ │ Write DB │ │
│ └──────┬──────┘ │
│ │ │
│ │ Streaming Replication │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Replica 1 │ │ Replica 2 │ │
│ │ (读) │ │ (读) │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ 读操作 (筛选、搜索) │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ PgBouncer │ (读写分离路由) │
│ │ (连接池) │ │
│ └──────┬──────┘ │
│ │ │
│ ├─── Read 1 ──▶ Replica 1 │
│ │ │
│ └─── Read 2 ──▶ Replica 2 │
│ │
└─────────────────────────────────────────────────────────────────┘

高可用#

1. 基建#

┌────────────────────┬─────────────────────┬──────────────┐
│ 组件 │ 高可用策略 │ 故障切换时间 │
├────────────────────┼─────────────────────┼──────────────┤
│ 多区域部署 │ 主从 + 异步复制 │ 分钟级 │
├────────────────────┼─────────────────────┼──────────────┤
│ Kubernetes Cluster │ 多 Master 节点 │ 秒级 │
├────────────────────┼─────────────────────┼──────────────┤
│ 负载均衡器 │ 健康检查 + 自动摘除 │ 秒级 │
├────────────────────┼─────────────────────┼──────────────┤
│ DNS │ TTL 多值 + 智能解析 │ 分钟级 │
└────────────────────┴─────────────────────┴──────────────┘

2. 数据库层高可用#

┌─────────────────────────────────────────────────────────────────┐
│ PostgreSQL 高可用架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Client │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ PgBouncer │ (连接池 + 读写分离路由) │
│ └──────┬──────┘ │
│ │ │
│ ├────────────────────┬────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Primary │◀────│ Standby 1 │◀────│ Standby 2 │ │
│ │ (写) │ 同步 │ (热备) │ 同步 │ (热备) │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ │ Streaming Replication │
│ ▼ │
│ ┌─────────────┐ │
│ │ Read │ (读副本,用于报表/离线分析) │
│ │ Replica 3 │ │
│ └─────────────┘ │
│ │
│ 自动故障切换: PgPool-II 或 Patroni + etcd │
└─────────────────────────────────────────────────────────────────┘

3. MQ高可用#

redis cluster 哨兵

4. 知识库高可用#

读写分离

高并发#

4.1 简历处理高并发
┌─────────────────────────────────────────────────────────────────────────────┐
│ 简历处理高并发架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 简历上传 │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ API Gateway │ (限流 + Auth + 路由) │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Upload S3 │ (直接上传到对象存储,避开 API 服务器) │
│ │ Pre-signed URL │ │
│ └──────┬──────┘ │
│ │ │
│ │ Async Event │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Redis Stream (消息队列) │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ resume:uploaded │ resume:uploaded │ resume:uploaded ... │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ ▲ ▲ ▲ │ │
│ │ │ │ │ │ │
│ └─────────┼────────────────────┼────────────────────┼───────────────┘ │
│ │ │ │ │
│ │ │ │ │
│ ┌────────┴───────┐ ┌────────┴───────┐ ┌────────┴───────┐ │
│ │ Worker Group A │ │ Worker Group B │ │ Worker Group N │ │
│ │ (处理分区 0-99) │ │ (处理分区 100-199)│ │ (处理分区 200-299)│ │
│ └────────┬───────┘ └────────┬───────┘ └────────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Consumer Group (消费者组) │ │
│ │ 同一消费者组内的 Worker 竞争消费同一分区 │ │
│ │ 不同消费者组可以独立处理同一消息 │ │
│ │ │ │
│ │ Group A: 解析 ──▶ 写入 PG ──▶ 触发 Vector Agent │ │
│ │ Group B: 解析 ──▶ 触发 Graph Agent ──▶ 更新质量分 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

性能指标#

┌─────────────────┬────────────────┬──────────┬─────────────┐
│ 指标 │ 正常范围 │ 告警阈值 │ 处理策略 │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ API P99 Latency │ < 500ms │ > 1s │ 扩容 + 降级 │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ API Error Rate │ < 0.1% │ > 1% │ 熔断 + 告警 │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ Queue Depth │ < 1000 │ > 5000 │ 扩容 Worker │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ CPU Utilization │ 40-70% │ > 80% │ 扩容 │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ Memory Usage │ 50-70% │ > 85% │ 扩容 │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ DB Connections │ < 80% │ > 90% │ 连接池调优 │
├─────────────────┼────────────────┼──────────┼─────────────┤
│ Vector DB QPS │ < 80% capacity │ > 90% │ 扩容副本 │
└─────────────────┴────────────────┴──────────┴─────────────┘

整体服务架构

┌─────────────────────────────────────────────────────────────────────────────┐
│ 全球多区域部署架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ Region A │ │ Region B │ │ Region C │
│ │ (主: 北京) │◀──────▶│ (备: 上海) │◀──────▶│ (备: 广州) │
│ │ │ 同步 │ │ 异步 │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │ │
└─────────────┼───────────────────────────┼───────────────────────────┼─────────┘
│ │ │
▼ ▼ ▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ Global Load Balancer (GSLB) │
│ (DNS 智能解析 + 健康检查 + 流量调度) │
└─────────────────────────────────┬─────────────────────────────────────────────┘
┌─────────────┴─────────────┐
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ API Gateway │ │ API Gateway │
│ (Kong/AWS API GW) │ │ (Kong/AWS API GW) │
│ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ Rate Limiter │ │ │ │ Rate Limiter │ │
│ │ Auth/JWT │ │ │ │ Auth/JWT │ │
│ │ Router │ │ │ │ Router │ │
│ │熔断器/Circuit │ │ │ │ 熔断器/Circuit │ │
│ └───────────────┘ │ │ └───────────────┘ │
└────────┬───────────┘ └─────────┬─────────┘
│ │
└─────────────┬─────────────────┘
┌────────────────────────────────────────┐
│ Kubernetes Cluster (K8s) │
│ ┌──────────────────────────────────┐ │
│ │ Ingress Controller │ │
│ └──────────────────────────────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ API Pod │ │ API Pod │ │ API Pod │ │
│ │ (3+ replicas) │ │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ HPA (自动扩缩容) │ │
│ │ 基于 CPU / Memory / RPS 指标 │ │
│ └──────────────────────────────────┘ │
│ │
└──────────────────────────────────────────┘
┌──────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Resume Worker │ │ JD Worker │ │ Match Worker │
│ Pool (5-20) │ │ Pool (2-8) │ │ Pool (5-20) │
│ HPA enabled │ │ HPA enabled │ │ HPA enabled │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
└──────────────────────┼──────────────────────┘
┌────────────────────────────────────────┐
│ Redis Cluster (Queue + Cache) │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │Master │ │ Slave1 │ │ Slave2 │ │
│ └────────┘ └────────┘ └────────┘ │
│ Sentinel / Cluster Mode │
└────────────────────────────────────────┘
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ PostgreSQL │ │ Weaviate │ │ Neo4j │
│ (主从+读 replica) │ │ (多副本) │ │ (多副本) │
│ ┌───┐ ┌───┐ │ │ ┌───┐ ┌───┐ │ │ ┌───┐ ┌───┐ │
│ │Primary│ │Read │ │ │Node│ │Node│ │ │ │Primary│ │Read │
│ │ │ │Replica│ │ │ 1 │ │ 2 │ │ │ │ │ │Replica│ │
│ └───┘ └───┘ │ │ └───┘ └───┘ │ │ └───┘ └───┘ │
└───────────────┘ └───────────────┘ └───────────────┘

生产环境架构选型与规划#

1.1 Redis 作为 MQ 的核心问题#

┌─────────────────────────────────────────────────────────────────┐
│ Redis 不适合做主力 MQ 的原因 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 消息持久化问题 │─┐
│ ├── Redis 持久化是"建议性"的,断电可能丢消息 │
│ ├── AOF + fsync every sec 模式下,最坏丢 1 秒数据 │┤
│ └── 生产环境:简历数据丢了 = 灾难 ││
│ │──┤
│ 2. 消息堆积能力 │ │
│ ├── Redis 所有数据在内存,堆积消息 = OOM │┤
│ ├── 简历处理峰值 10万/小时,峰谷比 10:1 │ │
│ └── 专业 MQ 磁盘持久化,堆积百万级消息 │┤
│ │ │
│ 3. 消息顺序保证 │─┘
│ ├── Redis Stream 虽然有 consumer group,但无法保证全局顺序 │
│ ├── 批量筛选需要:JD 解析先于匹配,简历按序处理 │
│ └── Kafka/RocketMQ 靠分区保证顺序 │
│ │
│ 4. 事务与exactly-once │
│ ├── 简历解析完成 → 写入 PG → 写入向量库 → 发送通知 │
│ ├── Redis 无法保证跨系统的分布式事务 │
│ └── RocketMQ 事务消息 = 本地事务 + 消息投递原子性 │
│ │
│ 5. 延迟/定时消息 │
│ ├── 简历重试、HR 通知提醒、定时任务 │
│ ├── Redis 用 Sorted Set 模拟,复杂且不可靠 │
│ └── RocketMQ 延迟消息是原生支持 │
│ │
│ 6. 死信队列 / 消息回溯 │
│ ├── 消费失败 → 死信队列 → 人工处理 │
│ ├── Redis 需要自己实现 │
│ └── Kafka/RocketMQ 原生支持 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌────────────┬──────────────────────────────────┐
1.2 消息队列选型对比 解决方案 │
├────────────┼──────────────────────────────────┤
┌──────────────┬──────────────┬────────────────────┬────────────────┐
│ 特性 │ RocketMQ │ Kafka │ Redis Stream │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 消息持久化 │ 磁盘,TB 级 │ 磁盘,PB 级 │ 内存优先 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 吞吐量 │ 10万/秒 │ 100万/秒 │ 20万/秒 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 消息堆积 │ 强,磁盘无限 │ 极强,保留 7-30 天 │ 弱,受内存限制 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 顺序消息 │ 支持全局顺序 │ 分区内有序 │ 不保证 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 事务消息 │ 原生支持 │ 需自研 │ 不支持 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 延迟消息 │ 原生支持 │ 需插件 │ 模拟实现 │可用。
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 死信队列 │ 原生 │ 原生 │ 需自研 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 消息回溯 │ 支持 │ 支持 │ 不支持 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 运维难度 │ 中 │ 高 │ 低 │
├──────────────┼──────────────┼────────────────────┼────────────────┤
│ 单条消息成本 │ 中 │ 低 │ 低 │
└──────────────┴──────────────┴────────────────────┴────────────────┘

1.3 推荐方案

┌─────────────────────────────────────────────────────────────────┐
│ 生产环境 MQ 选型建议 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ RocketMQ (推荐) ││
│ │ ││
│ │ ✅ 事务消息(简历处理链路的原子性) ││
│ │ ✅ 延迟消息(重试、通知调度) ││
│ │ ✅ 顺序消息(简历按序处理) ││
│ │ ✅ 消息堆积(峰值削峰) ││
│ │ ✅ 死信队列(失败处理) ││
│ │ ✅ Java 生态(团队技能匹配) ││
│ │ ││
│ │ 适用场景: ││
│ │ - 简历处理 Pipeline (解析→标准化→向量化→存储) ││
│ │ - 筛选任务分发 ││
│ │ - HR 通知消息 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Kafka (备选/大数据场景) ││
│ │ ││
│ │ ✅ 极高吞吐量(HR SaaS 多租户日志、审计日志) ││
│ │ ✅ 消息回溯(重新处理历史简历) ││
│ │ ✅ 生态丰富(与 Flink/Spark 集成) ││
│ │ ││
│ │ 适用场景: ││
│ │ - 简历原始文件上传事件 ││
│ │ - 审计日志/操作日志 ││
│ │ - 实时数据分析 (筛选漏斗、HR 行为分析) ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Redis (仅限缓存,不做 MQ) ││
│ │ ││
│ │ ✅ Session 缓存 ││
│ │ ✅ 计算结果缓存 (JD Schema, Match Results) ││
│ │ ✅ 分布式锁 ││
│ │ ✅ HPA 指标存储 (队列深度采集) ││
│ │ ❌ 不做消息队列 ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

二、其他架构改进点

2.1 向量数据库选型问题

┌─────────────────────────────────────────────────────────────────┐
│ Weaviate/Pinecone 生产问题 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 问题 1: Weaviate 是 Java 服务,内存消耗大 │
│ ├── 官方建议 16GB+ 内存 │
│ └── 多副本 = 内存成本乘以副本数 │
│ │
│ 问题 2: 混合搜索的局限 │
│ ├── BM25 + Vector 融合不如专业方案 │
│ └── RRF 融合是自己实现,后期维护成本高 │
│ │
│ 推荐方案: │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Milvus (推荐) │ │
│ │ ├── 专为向量设计,性能优 │ │
│ │ ├── 混合搜索插件丰富 │ │
│ │ ├── GPU 加速支持 │ │
│ │ └── 国产开源,社区活跃 │ │
│ │ │ │
│ │ 或: │ │
│ │ │ │
│ │ PgVector (简单场景) │ │
│ │ ├── PostgreSQL 生态,运维简单 │ │
│ │ ├── <10万向量足够 │ │
│ │ └── 不足: 扩展性一般 │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

2.2 知识图谱必要性评估

┌─────────────────────────────────────────────────────────────────┐
│ 知识图谱真的是必须的吗? │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 当前设计: Neo4j 存储技能图谱 │
│ │
│ 生产问题: │
│ ├── 技能图谱数据从哪来?维护成本极高 │
│ ├── "微服务" 的同义词: [分布式系统, SOA, MSA] 谁来维护? │
│ ├── JD 和简历的技能匹配,用 embedding 语义相似度已经能解决 80% │
│ └── 引入 Neo4j = 多一套存储 + 多一套运维 │
│ │
│ 简化方案: │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 用 Embedding + 同义词表替代知识图谱 │ │
│ │ │ │
│ │ skill_synonyms = { │ │
│ │ "微服务架构": ["分布式系统", "SOA", "MSA", "服务化"], │ │
│ │ "Python": ["Python3"], │ │
│ │ "机器学习": ["ML", "Machine Learning"] │ │
│ │ } │ │
│ │ │ │
│ │ 匹配时: │ │
│ │ 1. 直接匹配 │ │
│ │ 2. 同义词扩展匹配 │ │
│ │ 3. 向量语义相似度兜底 │ │
│ │ │ │
│ │ 收益: -Neo4j 依赖,-运维成本,+系统简单性 │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ 结论: 知识图谱适合前期 POC 验证,业务验证跑通后再考虑引入 │
│ │
└─────────────────────────────────────────────────────────────────┘

2.3 多租户隔离问题

┌─────────────────────────────────────────────────────────────────┐
│ 当前架构多租户隔离不足 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 问题: │
│ ├── 所有租户共用一套 PostgreSQL/Weaviate/Redis │
│ ├── 租户 A 的简历可能通过向量相似度 召回 租户 B 的简历 │
│ ├── 数据泄露风险 │
│ └── 资源竞争: 租户 A 批量导入影响 租户 B 的筛选延迟 │
│ │
│ 改进方案: │
│ │
│ 方案 A: Schema 隔离 (简单场景) │
│ ├── PostgreSQL: schema per tenant │
│ ├── Weaviate: tenant_id 字段隔离 │
│ └── 优点: 简单,缺点: 跨租户查询困难 │
│ │
│ 方案 B: Namespace 隔离 (推荐) │
│ ├── 每个租户独立的 namespace │
│ ├── 消息队列: tenant_id 分区 │
│ ├── 向量库: namespace 隔离 │
│ └── 优点: 隔离性好,缺点: 资源成本 x N │
│ │
│ 方案 C: 资源配额 + 逻辑隔离 (成本敏感场景) │
│ ├── 租户级别资源配额 (QPS limit, storage quota) │
│ ├── 租户 ID 标记所有数据 │
│ ├── 查询时强制加 tenant_id 过滤 │
│ └── 优点: 成本低,缺点: 隔离性弱 │
│ │
│ 推荐: 初期用方案 C,验证业务后升级到方案 B │
│ │
└─────────────────────────────────────────────────────────────────┘

三、生产环境关键改进

3.1 LLM 调用的高可用问题

┌─────────────────────────────────────────────────────────────────┐
│ LLM API 是单点故障 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 当前设计: 直接调用 OpenAI/Anthropic API │
│ │
│ 生产问题: │
│ ├── OpenAI API 故障 = 系统不可用 │
│ ├── API 限流 = 批量处理中断 │
│ ├── Token 成本不可预测 = 预算失控 │
│ └── API 响应时间波动大 = SLA 无法保证 │
│ │
│ 改进方案: │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ LLM Gateway 架构 │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ OpenAI │ │ Anthropic│ │ Azure │ ┌─────────┐ │ │
│ │ │ GPT-4 │ │ Claude │ │ OpenAI │ │ 本地模型 │ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ │ │ │ │ │ │ │
│ │ └──────────────┼──────────────┼──────────────┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ LLM Gateway │ │ │
│ │ │ ┌─────────────────────────┐ │ │ │
│ │ │ │ 多模型路由 (策略模式) │ │ │ │
│ │ │ │ - Primary/Secondary │ │ │ │
│ │ │ │ - 成本优先 │ │ │ │
│ │ │ │ - 延迟优先 │ │ │ │
│ │ │ └─────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────┐ │ │ │
│ │ │ │ 熔断器 (每模型独立) │ │ │ │
│ │ │ │ - 失败率 > 50% → 切换 │ │ │ │
│ │ │ └─────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────┐ │ │ │
│ │ │ │ 限流 + 配额管理 │ │ │ │
│ │ │ │ - per tenant QPS │ │ │ │
│ │ │ │ - per model limit │ │ │ │
│ │ │ └─────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────┐ │ │ │
│ │ │ │ 响应缓存 (semantic cache)│ │ │ │
│ │ │ │ - 相同 JD 解析结果缓存 │ │ │ │
│ │ │ │ - LLM 调用 -50% │ │ │ │
│ │ │ └─────────────────────────┘ │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ 开源方案: │
│ ├── LiteLLM (Python) - 支持 50+ LLM API │
│ ├── PortKey (SaaS) - LLM 网关 + 分析 │
│ └── GPTCache - 本地语义缓存 │
│ │
└─────────────────────────────────────────────────────────────────┘

3.2 简历处理链路的 Exactly-Once 问题

┌─────────────────────────────────────────────────────────────────┐
│ 简历处理 Exactly-Once 问题 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 当前设计的问题: │
│ │
│ 简历上传 → Resume Worker → Ingestion → Vector → Graph → 通知 │
│ │ │ │ │ │ │
│ │ 写入 PG 写入向量 写入图 发邮件 │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ 可能失败点: 任意一步失败,简历状态不一致 │
│ │
│ 问题场景: │
│ 1. Ingestion 成功,但 Vector Agent 失败 → PG 有数据,向量库没有 │
│ 2. 重试后,向量库重复写入 → 数据重复 │
│ 3. Graph Agent 失败 → 技能图谱不完整 │
│ │
│ 改进方案: RocketMQ 事务消息 │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ RocketMQ 事务消息处理: │ │
│ │ │ │
│ │ Producer Broker Consumer │ │
│ │ │ │ │ │ │
│ │ │ 发送 half 消息 │ │ │ │
│ │ │──────────────────────>│ │ │ │
│ │ │ │ │ │ │
│ │ │ 执行本地事务 │ │ │ │
│ │ │ (写入 PG) │ │ │ │
│ │ │ │ │ │ │
│ │ │ commit/rollback │ │ │ │
│ │ │──────────────────────>│ │ │ │
│ │ │ │ │ │ │
│ │ │ │ 投递消息 │ │ │
│ │ │ │───────────────>│ │ │
│ │ │ │ │ │ │
│ │ │ │ 处理向量/图/通知 │ │
│ │ │ │ │ │ │
│ │ │ │ commit │ │ │
│ │ │ │<───────────────│ │ │
│ │ │ │ │ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ 事务状态表设计: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ resume_transaction │ │
│ │ ───────────────── │ │
│ │ transaction_id: UUID │ │
│ │ candidate_id: UUID │ │
│ │ status: PENDING|COMMITTED|ROLLBACK │ │
│ │ steps: { │ │
│ │ ingestion: DONE, │ │
│ │ vector: PENDING, │ │
│ │ graph: PENDING, │ │
│ │ notification: PENDING │ │
│ │ } │ │
│ │ created_at, updated_at │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

四、完整改进后的架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│ 生产级改进架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 接入层 │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Kong API GW │ │ Kong API GW │ │ Kong API GW │ │ │
│ │ │ (区域 A) │ │ (区域 B) │ │ (区域 C) │ │ │
│ │ │ Rate Limit │ │ Rate Limit │ │ Rate Limit │ │ │
│ │ │ Auth │ │ Auth │ │ Auth │ │ │
│ │ │ WAF │ │ WAF │ │ WAF │ │ │
│ │ └───────────────┘ └───────────────┘ └───────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ LLM Gateway (LiteLLM) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────────────┐ │ │
│ │ │ OpenAI │ │Claude │ │ Azure │ │ 语义缓存 (GPTCache) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ RocketMQ (事务消息 + 延迟消息) │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ resume:parse │ │ resume:sync │ │ match:batch │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 延迟重试 │ │ 跨系统同步 │ │ 批量筛选 │ │ │
│ │ │ 死信队列 │ │ 顺序保证 │ │ 结果聚合 │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┼──────────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Resume Worker │ │ Ingestion │ │ Match Worker │ │
│ │ Pool (HPA) │───────▶│ Agent │───────▶│ Pool (HPA) │ │
│ │ │ │ │ │ │ │
│ │ - 格式解析 │ │ - 事务写入 │ │ - 向量召回 │ │
│ │ - LLM 提取 │ │ - 去重检测 │ │ - 深度匹配 │ │
│ │ │ │ - 质量评分 │ │ - 排序 │ │
│ └───────────────┘ └───────┬───────┘ └───────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 存储层 (多租户隔离) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ PostgreSQL │ │ Milvus │ │ Redis │ │ │
│ │ │ (读写分离) │ │ (向量存储) │ │ (缓存) │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ schema per │ │ namespace │ │ - Session │ │ │
│ │ │ tenant │ │ per tenant │ │ - Results │ │ │
│ │ │ │ │ │ │ - Metrics │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 可观测性层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Jaeger │ │ Prometheus │ │ Grafana │ │ │
│ │ │ (Trace) │ │ (Metrics) │ │ (Dashboard)│ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

五、改进清单汇总

┌──────────────┬──────────────┬────────────────────────────────┬────────┐
│ 问题 │ 当前方案 │ 推荐改进 │ 优先级 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ MQ 选型 │ Redis Stream │ RocketMQ (事务消息) │ P0 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ LLM 可用性 │ 直接调用 API │ LLM Gateway (多模型+熔断+缓存) │ P0 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ 向量库选型 │ Weaviate │ Milvus (性能+GPU支持) │ P1 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ Exactly-Once │ 无 │ RocketMQ 事务消息 │ P0 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ 多租户隔离 │ 逻辑隔离 │ Namespace 隔离 + 资源配额 │ P1 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ 知识图谱 │ Neo4j │ 简化为同义词表 + Embedding │ P2 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ 监控告警 │ 简单指标 │ 全链路追踪 + 业务指标 │ P1 │
├──────────────┼──────────────┼────────────────────────────────┼────────┤
│ 成本控制 │ 无 │ LLM Gateway 配额 + 缓存 │ P1 │
└──────────────┴──────────────┴────────────────────────────────┴────────┘

六、总结

┌────────┬──────────────┬───────────────────┐
│ 维度 │ 原设计 │ 改进后 │
├────────┼──────────────┼───────────────────┤
│ MQ │ Redis Stream │ RocketMQ │
├────────┼──────────────┼───────────────────┤
│ 向量库 │ Weaviate │ Milvus │
├────────┼──────────────┼───────────────────┤
│ LLM │ 直连 API │ LLM Gateway │
├────────┼──────────────┼───────────────────┤
│ 多租户 │ 逻辑隔离 │ Namespace + 配额 │
├────────┼──────────────┼───────────────────┤
│ 事务 │ 无 │ RocketMQ 事务消息 │
├────────┼──────────────┼───────────────────┤
│ 图谱 │ Neo4j │ 同义词表 │
├────────┼──────────────┼───────────────────┤
│ 缓存 │ 无 │ GPTCache │
└────────┴──────────────┴───────────────────┘

核心原则:

  1. 生产环境 Redis 不做 MQ - 用 RocketMQ
  2. LLM 调用必须加网关 - 可用性 > 成本
  3. 先简化再迭代 - 知识图谱不是必须项
  4. 多租户隔离要提前考虑 - 后期改造成本高
Hr-Helper Agent
https://sgjki547.top/posts/hrhelper-agent/
Author
SGJki
Published at
2026-04-13
License
CC BY-NC-SA 4.0