0. 系列闭环(不公开源码也能跟读)
端到端链路:Vue 前端 → api/routes/chat.py → Guide 多轮 SSE → run_analysis_pipeline(解析→分析→匹配→报告)→ tools/pdf_exporter PDF。
本篇:第 3/17 篇 · 分析环 · 霍兰德 RIASEC
| 阶段 | 用户可见 | 代码入口 | 对应篇 |
|---|---|---|---|
| 建会话 | 欢迎语 | POST /api/sessions | 09 |
| 多轮对话 | SSE 流式 | chat/stream → run_guide_single_turn | 06, 14 |
| 信息充分 | 开始分析 | _run_analysis_background | 05, 07 |
| 履历解析 | 进度 30% | run_resume_parser | 12 |
| 画像/RIASEC | 进度 50% | run_profile_analyzer | 03, 13 |
| 职业匹配 | 进度 70% | run_career_matcher | 02 |
| 报告 | 进度 90% | run_reporter | 11 |
| 下载 PDF | 文件 | GET …/report/pdf | 11, 15 |
| 说明 | |
|---|---|
| 读本篇前 | 第 02 篇 profile_analyzer_node |
| 读完本篇 | 读懂 analyze_riasec 如何产出六维分 |
| 下一环 | 第 13 篇:RIASEC 专用 Prompt(第 4 篇) |
全系列闭环索引:SERIES-LOOP.md
一、霍兰德 RIASEC 模型介绍
霍兰德职业兴趣理论(Holland’s Theory of Vocational Personalities)是由美国心理学家约翰·霍兰德在 1959 年提出的。它将人的职业兴趣分为六个维度:
| 维度 | 英文 | 类型 | 典型职业 |
|---|---|---|---|
| R | Realistic | 实用型 | 工程师、技术员、建筑师 |
| I | Investigative | 研究型 | 科学家、数据分析师、医生 |
| A | Artistic | 艺术型 | 设计师、作家、音乐家 |
| S | Social | 社会型 | 教师、咨询师、社工 |
| E | Enterprising | 企业型 | 企业家、销售经理、律师 |
| C | Conventional | 常规型 | 会计、行政、审计 |
霍兰德代码:取评分最高的 2-3 个维度组成代码(如 IAS、RCE),每个代码对应一组匹配的职业。
为什么选这个模型:
- 心理学界公认,有 60+ 年实证研究支持
- O*NET(美国职业信息网)的官方分类基础
- 六维度结构清晰,适合 LLM 量化评估
- 不需要用户做 120 道题,通过对话就能推断
二、LLM 接入:OpenAI 兼容接口(DeepSeek 为常见部署配置)
实现上没有 DeepSeek 专用 SDK。统一通过 langchain_openai.ChatOpenAI(llm/providers.py)接入,用 LLM_BASE_URL + LLM_MODEL_CHAT / LLM_MODEL_LIGHT 切换厂商——DeepSeek、OpenAI 官方、Ollama 本地均走同一套 invoke_llm / invoke_llm_with_json。
与其他部署方案对比
| 方案 | JSON 模式 | 国内访问 | 说明 |
|---|---|---|---|
| DeepSeek API(如 deepseek-v4-flash) | ✅ | ✅ 直连 | 项目 .env 常用配置 |
| GPT-4o 等 OpenAI 官方 | ✅ | 视网络 | config.py 未配 env 时的代码默认值 |
| Ollama + Qwen3 | ✅ | 本地 | Docker 默认可指向 11434,需 /no_think |
.env 示例(部署配置,非框架写死):
1 | |
双模型策略(以当前代码为准)
llm/providers.py 提供 get_chat_model() 与 get_light_model();默认值来自 config.py(未配 env 时为 gpt-4o):
| 调用方 | 当前实现 |
|---|---|
| Guide / ProfileAnalyzer / CareerMatcher | get_chat_model() |
ResumeParser(agents/resume_parser.py) |
get_light_model() |
Reporter(agents/reporter.py) |
get_chat_model()(文档若写 light,以代码为准) |
通过 .env 切换 LLM_MODEL_CHAT / LLM_MODEL_LIGHT,无需改业务代码。.env 里写 deepseek-v4-flash 只是部署示例,不代表代码默认。
三、RIASEC 在 agents/profile_analyzer.py 中的位置
霍兰德打分不是独立服务,而是 ProfileAnalyzer 子图的一个节点。create_profile_analyzer_graph() 定义顺序链:
1 | |
analyze_riasec 从 ProfileAnalysisState.structured_profile 读取上游 agents/resume_parser.py 的结构化画像,截断 JSON 到约 2000 字符后调 LLM:
1 | |
顶层 workflow.py 的 profile_analyzer_node 把 riasec_scores 写入 personal_profile,供 career_matcher_node 与 tools/pdf_exporter.py 制图使用。
四、LLM 如何做量化评估
传统问卷 vs LLM 评估
传统霍兰德测评需要用户回答 120+ 道题,耗时 20-30 分钟。而 LLM 评估的思路是:
- 用户在对话中描述自己的经历、偏好、困惑
- LLM 从这些自然语言中推断六个维度的倾向
- 给出 0-10 分的评分,并说明理由
Prompt 设计
规则集中在 llm/prompts.py 的 PROFILE_ANALYZER_SYSTEM_PROMPT 第六节;analyze_riasec 节点在 user 消息里再约束 JSON 形状:
1 | |
输出格式:
1 | |
评分依据的设计
关键在于 Prompt 中要求 LLM 说明每个评分的理由:
1 | |
这比单纯输出分数更有价值——用户能看到”为什么 I 得了 9 分”。
五、RIASEC 评分与职业匹配的衔接
Holland Code 如何进入 CareerMatcher
项目没有硬编码 HOLLAND_CAREER_MAP 字典。agents/career_matcher.py 的 generate_candidate_paths 把完整 personal_profile(含 riasec_scores)序列化后,连同 llm/prompts.py 的 CAREER_MATCHER_SYSTEM_PROMPT 发给 LLM,由 Prompt 要求结合霍兰德代码解释三级路径:
1 | |
Prompt 中要求 LLM 在推荐文案里引用 holland_code(如 IEA),说明哪些方向与高分维度一致、哪些是 stretch 方向——比维护静态映射表更灵活,但也更依赖 Prompt 约束与 JSON 解析稳定性(见第 12 篇)。
六、可视化:tools/pdf_exporter.py 柱状图
PDF 报告嵌入图表时,从 personal_profile.riasec_scores 读取 R–C 六键;key 必须与 analyze_riasec 输出一致(单字母大写)。
1 | |
中文字体处理
在 Docker 部署中,matplotlib 默认不支持中文。解决方案:
- 安装系统字体包:
apt-get install fonts-noto-cjk - 在代码中指定字体优先级:
1 | |
七、测评效果评估
与传统问卷的对比
| 维度 | 传统问卷 | LLM 评估 |
|---|---|---|
| 用户耗时 | 20-30 分钟 | 5 分钟对话 |
| 题目数量 | 120+ 道 | 自然对话 |
| 评分精度 | 标准化量表 | 基于语义推断 |
| 适应性 | 固定题目 | 动态追问 |
| 用户体验 | 枯燥 | 像和朋友聊天 |
局限性
- 精度依赖输入质量:用户描述越详细,评估越准确
- 无标准化量表:不像 SDS 量表有大量效度验证
- 文化差异:霍兰德模型基于美国职场,中国场景需要调整权重
八、踩坑记录
- 勿把 DeepSeek 写成代码默认:
config.py默认gpt-4o;DeepSeek 是.env里LLM_BASE_URL=https://api.deepseek.com/v1的部署选择。 - **
holland_code未写入riasec_scores**:analyze_riasec只把 R–C 六维 float 写入 state,holland_code在 LLM JSON 里但不持久化到riasec_scores;PDF 若需展示代码要从原始 JSON 或后处理补全。 - JSON 解析失败全零分:
analyze_riasec异常时返回六维 0.0,下游 Matcher 仍会继续——需结合 Guide 对话质量与 Parser 置信度(confidence_scores)判断。 - **Ollama Qwen3 需
/no_think**:llm/providers.py的_inject_no_think在检测到 Ollama + qwen3 时自动注入,否则 RIASEC JSON 可能被 thinking 块污染。
九、小结
用 LLM 实现霍兰德测评的核心思路是:把心理学量表写进 llm/prompts.py,由 agents/profile_analyzer.py 的 analyze_riasec 从结构化画像推断各维度评分。
关键设计:
- OpenAI 兼容接口 + 环境变量切换模型(DeepSeek / GPT / Ollama 均可)
- Prompt 要求评分 + 理由,确保可解释性
tools/pdf_exporter.py的 matplotlib 柱状图嵌入 PDF- Docker 环境安装
fonts-noto-cjk解决中文显示
下一篇:
core/state.py中 TypedDict + Annotated Reducer 的分层用法。