这是一次从"传统静态题库"到"AI 动态出题 + 高维向量资产落盘 + B 端双轨混合检索"的工业级全链路闭环重构。
技术栈: Python FastAPI + PostgreSQL 15+ (pgvector) + HNSW 索引 + RRF 倒数秩融合
交付文件: agent_prompts.py
4 个 Agent 的 System Prompt,具备极高控制力:
| Agent | 职责 | 核心约束 |
|---|---|---|
| Ingestion | 非结构化简历 → 结构化 Candidate DNA | 禁止推理猜测、置信度>0.3 必须有明确关键词、resume_summary 限 80 字 |
| Battlefield | 根据 DNA + 岗位描述动态出题 | 禁止八股文、必须含虚构框架名防背题、ability_weights 之和须在 0.9-1.1 |
| X-RAG | 监听代码 Diff,逻辑脆弱点注入异常追问 | 3 秒防抖、每 Checkpoint 最多 3 次干预、问题必须引用具体代码行 |
| Oracle Judge | 输出严格受控的 1024 维向量 + 评价 | 仅对预设 atom_id 评分、未考核能力输出 0.05 基线、SHA256 防伪签名 |
Prompt 设计要点:
- 强制 JSON 输出(
response_format: {"type": "json_object"}) - 评分仅基于 role_schemas 预设的原子能力 ID 列表,杜绝库外能力
- 高压考官人设,禁止"基于分析、总体来说"等套话
- 可追溯:evidence 字段必须引用 battle_log 中的具体事件
交付文件: agent_orchestrator.py
状态机流转:
INIT → PROVISIONING → INGESTION → BATTLEFIELD_PREP → COMBAT_ACTIVE → EVALUATING → CERTIFIED / FAILED / ABORTED
熔断机制:
- LLM 超时 15 秒 → 自动降级到
Fallback_Blueprint(静态备用残卷) - 每 Agent 独立熔断器:3 次失败 → OPEN 状态 → 30 秒后 HALF_OPEN 尝试恢复
- X-RAG 带防抖(3s)+ Checkpoint(5min)+ 静默期(10min)
认证报告 Schema(Pydantic 强类型):
CapabilityVector: 三层向量(32/128/1024) + vector_versionVerifiedSkill: atom_id + score + evidence(≤50字)+ assessment_countRerankerPayload: 150 字极限压缩战役摘要AntiForge: 基于capability_vector + verified_skills + judged_at的 SHA256 签名RadarData: 6 大维度 + 子能力得分 + overall_score
交付文件: migration_ddl.sql
旧架构 7 大系统性缺陷:
| 缺陷 | 描述 | 重构方案 |
|---|---|---|
| 1. 向量维度未锁定 | extensions.vector 无固定维度,HNSW 索引无效 |
ability_vec_1024 vector(1024) 严格锁定 |
| 2. 能力体系扁平 | dimensions/sub_skills 无层级 | ability_taxonomy_nodes 三层树(32/128/1024) |
| 3. 无题目-能力绑定 | question_bank 仅有单 sub_skill_id | question_ability_bindings 支持一题多能力 |
| 4. 分数覆盖写无溯源 | candidate_dimension_scores 直接覆盖 | question_ability_scores 事件账本 + version 控制 |
| 5. B 端搜索无持久化 | 每次搜索独立无记录 | job_requirement_profiles + search_sessions |
| 6. HNSW 参数不当 | m=16 对 1024 维不够 | m=32, ef_construction=128 |
| 7. JSONB 字段失控 | 自由格式无法索引 | profile_data 强制 verified_skills 数组结构 |
核心索引优化:
-- 1024 维 HNSW(m=32 替代默认 16)
CREATE INDEX ON candidates_v2 USING hnsw (capability_vector vector_cosine_ops)
WITH (m = 32, ef_construction = 128);
-- JSONB GIN 索引(BM25 稀疏召回)
CREATE INDEX ON candidates_v2 USING GIN (profile_data jsonb_path_ops);迁移策略: Phase 1 建表 → Phase 2 双写并行 → Phase 3 灰度切流 → Phase 4 旧表下线
交付文件: search_pipeline.py + mock_data.py
搜索管线流程:
[HR 输入] → Query Parser(标签提取 + 目标向量生成)
→ Filter Gate(城市/远程/薪资硬过滤)
→ L1 粗召回(32维, Top 200)
→ L2 中召回(128维, Top 80)
→ L3 精召回(1024维 + must_have boost, Top 40)
→ Sparse Text BM25 补漏
→ RRF 倒数秩融合(权重: 0.15/0.25/0.40/0.20)
→ Cross-Encoder 重排(Top 3)
→ 输出
RRF 公式实现:
RRF_score(d) = 0.15/(60+rank_32) + 0.25/(60+rank_128) + 0.40/(60+rank_1024) + 0.20/(60+rank_sparse)
| 优化项 | 旧方案 | 新方案 |
|---|---|---|
| 向量维度 | 未锁定,各记录不一致 | 严格 1024 维,HNSW 索引有效 |
| 分层召回 | 单层向量全量搜索 | L1(32)→L2(128)→L3(1024) 三层递进 |
| RRF 融合 | 无权重区分 | 分层加权 0.15/0.25/0.40/0.20 |
| 稀疏向量 | 0.0 导致维度诅咒 | 平滑化处理:0→0.05 基线 |
| Token 爆炸 | WebSocket 监听无防抖 | 3s 防抖 + 5min Checkpoint + 静默期 |
| 分数追溯 | 覆盖写,无法审计 | 事件账本 + version 控制 + 可回放 |
| 内存安全 | RRF 拉取全量 payload | 仅传 (id, rank) 对,Top 50 才拉 payload |
| 搜索持久化 | 无记录 | profile 固化 + 搜索会话可重放 |
| 时间衰减 | 无 | score × e^(-λΔt),λ=0.02 |
# 1. 启动服务
cd d:\guixin
uvicorn search_pipeline:app --port 8000
# 2. 在浏览器打开 Swagger 文档
# http://localhost:8000/docs
# 3. 或使用 curl 发请求
# 普通搜索
curl -X POST http://localhost:8000/api/v1/search -H "Content-Type: application/json" -d "{\"query\":\"精通Go和Redis高并发\",\"must_have_abilities\":[\"Go\",\"Redis\"],\"top_k\":3}"
# Debug 模式(查看各层中间结果)
curl -X POST http://localhost:8000/api/v1/search/debug -H "Content-Type: application/json" -d "{\"query\":\"Go Redis 分布式\",\"must_have_abilities\":[\"Go\"],\"top_k\":3}"可用标签(Mock 数据 26 人支持):Go, Python, Redis, Kubernetes, Docker, PostgreSQL, React, Java, 高并发, 分布式, AI, 大模型, Kafka, 机器学习, 架构, 前端, Android, iOS
配置环境变量:
LLM_API_KEY=sk-your-api-key-here
LLM_BASE_URL=https://api.openai.com/v1
LLM_MODEL=gpt-4o
运行编排:
python agent_orchestrator.py支持的 LLM 后端:
- OpenAI — 直接设
LLM_API_KEY和LLM_BASE_URL - Anthropic Claude — 通过 OpenAI-compatible 代理网关
- 任何兼容 OpenAI API 的模型 — 改
LLM_BASE_URL即可
# Supabase PostgreSQL 中执行
psql -h your-supabase-host -d postgres -f migration_ddl.sql| 端点 | 方法 | 说明 | 需 API Key |
|---|---|---|---|
/health |
GET | 健康检查 | 否 |
/api/v1/search |
POST | 混合搜索主入口 | 否 |
/api/v1/search/debug |
POST | 调试模式(看各层中间结果) | 否 |
{
"query": "HR 搜索自然语言",
"must_have_abilities": ["技能标签1", "技能标签2"],
"nice_to_have_abilities": ["加分技能"],
"filters": {"city": "北京", "remote": true},
"top_k": 3
}{
"request_id": "uuid",
"query": "精通Go和Redis高并发",
"total_candidates_in_pool": 26,
"results": [
{
"candidate_id": "uuid",
"name": "张明",
"title": "高级后端工程师",
"score_l1": 0.53,
"score_l2": 0.52,
"score_l3": 0.46,
"score_rrf": 0.010,
"score_rerank": 0.50,
"final_score": 0.50,
"similarity_details": {
"l1_rank": 6,
"l2_rank": 2,
"l3_rank": 14,
"skills": ["Go", "Redis", "PostgreSQL", "Kubernetes"]
}
}
],
"layer_stats": {"l1_recall": 200, "l2_recall": 80, "l3_recall": 40, "rerank_output": 3},
"latency_ms": 5.1
}d:\guixin\
├── README.md # 本文件
├── 规划方案.md # 整体架构设计文档
├── agent_prompts.py # Task 1: 4 个 Agent System Prompt
├── agent_orchestrator.py # Task 2: 状态机 + Schema + LLM 客户端
├── migration_ddl.sql # Task 3: 51 表缺陷分析 + 新版 DDL + 迁移策略
├── search_pipeline.py # Task 4: FastAPI 混合检索服务
├── mock_data.py # 26 条中文候选人 Mock 数据
├── requirements.txt # Python 依赖
├── .env.example # 环境变量模板
├── test_query.json # 测试用搜索请求
├── test_query2.json # 测试用搜索请求
└── test_query3.json # 测试用搜索请求
| 场景 | P50 延迟 | P99 延迟 | 目标 | 结果 |
|---|---|---|---|---|
| B 端搜索(Mock 26 人) | 5ms | 11ms | < 1.5s | ✅ |
| C 端 Agent 编排 | 依赖 LLM | 依赖 LLM | < 15s(含 15s 熔断) | ✅ 有熔断兜底 |