← blog AI Agent · 2026-04-13

Hr-Helper Agent

帮助hr从海量简历中寻找符合JD的候选人

15 min read

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

多 Agent 协作职责划分

整体协作图

graph TD
    O["Orchestrator (Router)<br/>意图分类 / 任务分发 / 结果聚合"]
    O --> J["JD Worker Pool (1-2)"]
    O --> R["Resume Worker Pool (5-10)"]
    O --> M["Match Worker Pool (3-5)"]
    J --> JS["JDSchema"]
    R --> RS["ResumeSchema"]
    M --> MR["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”

处理流程:

graph TD
    A["1. 格式检测 (PDF/DOCX/HTML/IMG)"]
    B["2. 文本提取<br/>- PDF: pdf-parse<br/>- DOCX: python-docx<br/>- IMG: Tesseract OCR"]
    C["3. LLM 结构化提取<br/>- 姓名、联系方式<br/>- 工作经历<br/>- 教育背景<br/>- 技能清单"]
    D["4. 向量化(用于向量召回)"]
    E["5. 输出 ResumeSchema"]
    A --> B --> C --> D --> E

输出:

{
  "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
}

处理流程:

graph TD
    A["1. 硬技能匹配 (40%)<br/>技能级别对比 / 技能是否存在"]
    B["2. 软技能匹配 (20%)<br/>语义相似度计算 / 从工作描述推断软技能"]
    C["3. 经验年限匹配 (25%)<br/>简历 6 年 ≥ JD 要求 5 年"]
    D["4. 学历匹配 (15%)<br/>简历本科 ≥ JD 要求本科"]
    E["5. 优选条件加分 (5%)<br/>简历有微服务经验 +20% 加分"]
    F["6. 综合得分计算<br/>36.8 + 15.6 + 25.0 + 15.0 + 1.0 = 85.6 分"]
    G["7. Explanation 生成<br/>为什么推荐/不推荐、优势、潜在风险、面试重点"]
    A --> B --> C --> D --> E --> F --> G

输出:

{
  "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 间协作时序

graph TD
    REQ["HR Request"]
    O1["Orchestrator<br/>1. 意图分类:「筛选候选人」<br/>2. 任务分发"]
    JD["JD Worker<br/>解析 JD"]
    RR["Resume Repo (批量读取)"]
    MW["Match Worker Pool<br/>Match #1 / #2 / #N<br/>并行计算每个候选人的匹配度"]
    O2["Orchestrator<br/>聚合 + 排序 + 分页<br/>返回 Top-K 给 HR"]
    REQ --> O1
    O1 --> JD
    O1 --> RR
    JD -- "JDSchema" --> MW
    RR -- "ResumeSchema[]" --> MW
    MW -- "MatchResults[]" --> O2

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. 数据分层

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

2. 存储选型与数据内容

存储层技术选型存储内容
L1 原始文件S3 / Blob StoragePDF/DOCX/IMG 原始文件
L2 结构化数据PostgreSQLResumeSchema JSON + 业务字段
L3 向量索引Weaviate / Pineconeskill_embedding, description_embedding
L4 知识图谱Neo4j / Amazon Neptune技能图谱、公司关系、项目关系

3. 读写分离

graph TD
    W["写操作 (简历上传、JD创建)"]
    P["Primary Write DB (PostgreSQL Primary)"]
    R1["Replica 1 (读)"]
    R2["Replica 2 (读)"]
    RD["读操作 (筛选、搜索)"]
    PB["PgBouncer (连接池, 读写分离路由)"]
    W --> P
    P -- "Streaming Replication" --> R1
    P -- "Streaming Replication" --> R2
    RD --> PB
    PB -- "Read 1" --> R1
    PB -- "Read 2" --> R2

高可用

1. 基建

组件高可用策略故障切换时间
多区域部署主从 + 异步复制分钟级
Kubernetes Cluster多 Master 节点秒级
负载均衡器健康检查 + 自动摘除秒级
DNSTTL 多值 + 智能解析分钟级

2. 数据库层高可用

graph TD
    C["Client"]
    PB["PgBouncer (连接池 + 读写分离路由)"]
    P["Primary (写)"]
    S1["Standby 1 (热备)"]
    S2["Standby 2 (热备)"]
    RR["Read Replica 3 (读副本,用于报表/离线分析)"]
    C --> PB
    PB --> P
    S1 -- "同步" --> P
    S2 -- "同步" --> P
    P -- "Streaming Replication" --> RR
    note["自动故障切换: PgPool-II 或 Patroni + etcd"]

3. MQ高可用

redis cluster 哨兵

4. 知识库高可用

读写分离

高并发

graph TD
    U["简历上传"]
    GW["API Gateway (限流 + Auth + 路由)"]
    S3["Upload S3 (Pre-signed URL, 避开 API 服务器)"]
    RS["Redis Stream (消息队列)<br/>resume:uploaded 消息"]
    subgraph Workers["Worker Groups (按分区并行消费)"]
        GA["Worker Group A (处理分区 0-99)"]
        GB["Worker Group B (处理分区 100-199)"]
        GN["Worker Group N (处理分区 200-299)"]
    end
    subgraph CG["Consumer Group (消费者组)<br/>同一组内竞争消费同一分区,不同组独立处理"]
        CA["Group A: 解析 → 写入 PG → 触发 Vector Agent"]
        CB["Group B: 解析 → 触发 Graph Agent → 更新质量分"]
    end
    U --> GW --> S3 -- "Async Event" --> RS
    RS --> GA
    RS --> GB
    RS --> GN
    GA --> CA
    GB --> CB
    GN --> CA

性能指标

指标正常范围告警阈值处理策略
API P99 Latency< 500ms> 1s扩容 + 降级
API Error Rate< 0.1%> 1%熔断 + 告警
Queue Depth< 1000> 5000扩容 Worker
CPU Utilization40-70%> 80%扩容
Memory Usage50-70%> 85%扩容
DB Connections< 80%> 90%连接池调优
Vector DB QPS< 80% capacity> 90%扩容副本
整体服务架构
graph TD
    subgraph Regions["全球多区域部署架构"]
        RA["Region A (主: 北京)"]
        RB["Region B (备: 上海)"]
        RC["Region C (备: 广州)"]
    end
    RA <-. "同步" .-> RB
    RB <-. "异步" .-> RC
    GSLB["Global Load Balancer (GSLB)<br/>DNS 智能解析 + 健康检查 + 流量调度"]
    subgraph GW["API Gateway (Kong/AWS API GW)"]
        G1["Rate Limiter / Auth+JWT / Router / 熔断器"]
        G2["Rate Limiter / Auth+JWT / Router / 熔断器"]
    end
    K8S["Kubernetes Cluster (K8s)<br/>Ingress Controller + API Pod (3+ replicas)<br/>HPA 自动扩缩容 (CPU/Memory/RPS)"]
    subgraph Workers["Worker Pools"]
        RW["Resume Worker Pool (5-20) HPA"]
        JW["JD Worker Pool (2-8) HPA"]
        MW["Match Worker Pool (5-20) HPA"]
    end
    REDIS["Redis Cluster (Queue + Cache)<br/>Master + Slave1 + Slave2<br/>Sentinel / Cluster Mode"]
    subgraph Storage["存储层"]
        PG["PostgreSQL (主从+读 replica)"]
        WV["Weaviate (多副本)"]
        N4J["Neo4j (多副本)"]
    end
    RA --> GSLB
    RB --> GSLB
    RC --> GSLB
    GSLB --> G1
    GSLB --> G2
    G1 --> K8S
    G2 --> K8S
    K8S --> RW
    K8S --> JW
    K8S --> MW
    RW --> REDIS
    JW --> REDIS
    MW --> REDIS
    REDIS --> PG
    REDIS --> WV
    REDIS --> N4J

生产环境架构选型与规划

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 消息队列选型对比

特性RocketMQKafkaRedis 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 生态,运维简单                              │  │
  │  │  ├── &lt;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 调用的高可用问题

当前设计: 直接调用 OpenAI/Anthropic API

生产问题:

  • OpenAI API 故障 = 系统不可用
  • API 限流 = 批量处理中断
  • Token 成本不可预测 = 预算失控
  • API 响应时间波动大 = SLA 无法保证

改进方案 (LLM Gateway 架构):

graph LR
    subgraph Providers["模型提供方"]
        O["OpenAI GPT-4"]
        A["Anthropic Claude"]
        AZ["Azure OpenAI"]
        L["本地模型"]
    end
    subgraph GW["LLM Gateway"]
        R["多模型路由 (策略模式)<br/>Primary/Secondary / 成本优先 / 延迟优先"]
        CB["熔断器 (每模型独立)<br/>失败率 > 50% → 切换"]
        RL["限流 + 配额管理<br/>per tenant QPS / per model limit"]
        CACHE["响应缓存 (semantic cache)<br/>相同 JD 解析结果缓存, LLM 调用 -50%"]
    end
    O --> R
    A --> R
    AZ --> R
    L --> R

开源方案:

  • LiteLLM (Python) - 支持 50+ LLM API
  • PortKey (SaaS) - LLM 网关 + 分析
  • GPTCache - 本地语义缓存 3.2 简历处理链路的 Exactly-Once 问题

当前设计的问题:

简历上传 → Resume Worker → Ingestion → Vector → Graph → 通知
    │                    │           │         │        │
    │                 写入 PG      写入向量   写入图    发邮件
    │                    │           │         │        │
    ▼                    ▼           ▼         ▼        ▼
  可能失败点: 任意一步失败,简历状态不一致

问题场景:

  1. Ingestion 成功,但 Vector Agent 失败 → PG 有数据,向量库没有
  2. 重试后,向量库重复写入 → 数据重复
  3. Graph Agent 失败 → 技能图谱不完整

改进方案: RocketMQ 事务消息

sequenceDiagram
    participant P as Producer
    participant B as Broker
    participant C as Consumer
    P->>B: 发送 half 消息
    P->>P: 执行本地事务 (写入 PG)
    P->>B: commit/rollback
    B->>C: 投递消息
    C->>C: 处理向量/图/通知
    C-->>B: 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

    四、完整改进后的架构图
graph TD
    subgraph Access["接入层"]
        K1["Kong API GW (区域 A)<br/>Rate Limit / Auth / WAF"]
        K2["Kong API GW (区域 B)<br/>Rate Limit / Auth / WAF"]
        K3["Kong API GW (区域 C)<br/>Rate Limit / Auth / WAF"]
    end
    subgraph LLMGW["LLM Gateway (LiteLLM)"]
        O["OpenAI"]
        C["Claude"]
        AZ["Azure"]
        CACHE["语义缓存 (GPTCache)"]
    end
    subgraph MQ["RocketMQ (事务消息 + 延迟消息)"]
        P["resume:parse<br/>延迟重试 / 死信队列"]
        S["resume:sync<br/>跨系统同步 / 顺序保证"]
        M["match:batch<br/>批量筛选 / 结果聚合"]
    end
    subgraph Workers["处理层"]
        RW["Resume Worker Pool (HPA)<br/>格式解析 / LLM 提取"]
        IA["Ingestion Agent<br/>事务写入 / 去重检测 / 质量评分"]
        MW["Match Worker Pool (HPA)<br/>向量召回 / 深度匹配 / 排序"]
    end
    subgraph Storage["存储层 (多租户隔离)"]
        PG["PostgreSQL (读写分离, schema per tenant)"]
        M["Milvus (向量存储, namespace per tenant)"]
        RD["Redis (缓存: Session/Results/Metrics)"]
    end
    subgraph Obs["可观测性层"]
        J["Jaeger (Trace)"]
        PR["Prometheus (Metrics)"]
        G["Grafana (Dashboard)"]
    end
    K1 --> LLMGW
    K2 --> LLMGW
    K3 --> LLMGW
    LLMGW --> MQ
    MQ --> RW
    MQ --> IA
    MQ --> MW
    RW --> IA
    IA --> MW
    RW --> Storage
    IA --> Storage
    MW --> Storage
    Storage --> Obs

五、改进清单汇总

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

六、总结

维度原设计改进后
MQRedis StreamRocketMQ
向量库WeaviateMilvus
LLM直连 APILLM Gateway
多租户逻辑隔离Namespace + 配额
事务无RocketMQ 事务消息
图谱Neo4j同义词表
缓存无GPTCache
核心原则:
  1. 生产环境 Redis 不做 MQ - 用 RocketMQ
  2. LLM 调用必须加网关 - 可用性 > 成本
  3. 先简化再迭代 - 知识图谱不是必须项
  4. 多租户隔离要提前考虑 - 后期改造成本高

Sources

No external sources for this entry.

Related