ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring AI Alibaba Graph实战:HR招聘全流程Agent编排

Spring AI Alibaba Graph实战:HR招聘全流程Agent编排 这次我们来看一个 Spring AI Alibaba Graph 方向的完整实战项目HR 招聘全流程 Agent。这个项目不是单纯调大模型接口而是把简历解析、JD 理解、候选人匹配、面试题生成、评估报告串联成一个有状态、可路由、可复用的工作流。核心价值在于它不绑定某个行业术语招聘场景只是载体里面的 Graph 编排方式、Agent 工具调用、结构化输出和批量任务设计放到客服、研发、运营等场景可以原样复用。文章会先讲 Spring AI Alibaba Graph 适合谁、不适合谁再拆 25 个核心技术点最后给出从环境准备到接口联调、批量任务和问题排查的完整落地路径。如果你是 Java 后端新人建议先跑通第 5 章的骨架如果你已经在用 Spring AI可以直接跳到第 6 章做效果验证。技术门槛并不高需要 JDK 17 以上、Spring Boot 3.x、一个可以调用大模型的 API Key本地实验也可以切换 Ollama 跑开源模型。不需要自己训练模型也不需要 GPUGraph 编排和模型调用都在 JVM 进程里完成。HR 招聘场景天然适合做演示因为链路足够长既能体现 Graph 的多步编排能力也能验证 Function Calling、结构化输出、上下文记忆这些 Agent 关键能力是不是真的可用。1. Spring AI Alibaba Graph 核心能力速览先给一张速览表方便你快速判断这个项目值不值得跟。能力项说明项目类型Spring AI Alibaba Spring AI Graph 的 Agent 实战项目核心框架Spring Boot 3.x、Spring AI Alibaba、Spring AI Graph模型接入云端大模型 API 为主可切换本地 Ollama 等 OpenAI 兼容协议典型链路简历解析 - JD 理解 - 匹配打分 - 面试题生成 - 评估报告Graph 能力有状态多步编排、节点拆分、条件路由、并行处理、循环控制运行模式JVM Web 服务常规 Java 进程不依赖特殊 GPU 服务器API 能力通过 REST 接口暴露 Agent 调用Graph 执行器支持程序化调用批量任务支持多份简历顺序/并行处理需要自行设计任务队列与重试合规要求简历属于个人信息必须脱敏、授权、限制访问范围适合读者熟悉 Java 但没有完整 Agent 落地经验的开发者从这张表可以看到这个项目的重点不是模型本身而是如何把“招聘流程”拆成 Graph 节点再让大模型在每个节点上做专业任务。这种方式比“丢一大段 Prompt 让模型自由发挥”更可控也更容易在真实业务里替换规则、增加人工审核。2. 适用场景与使用边界先说适合谁。如果你在做 Java 后端想从“调 API 返回一段文本”升级到“用编排能力完成一条完整业务流”这个项目非常合适。HR 招聘 Agent 只是示例实际能够复用的是四件事节点拆分方式、状态传递方式、工具调用方式、结果落库方式。把这四件事吃透换到订单客服、IT 工单、内容审核、销售线索筛选都是一样的架构。这个项目不适合什么场景第一不适合做纯聊天机器人。它的优势在多步任务编排而不是开放闲聊。第二不适合对实时性要求极度苛刻的场景。Graph 执行过程中会有多次模型调用单次可能 2 到 5 秒如果要求 200 毫秒返回需要额外做缓存和异步流式设计。第三不适合完全没有人工兜底的场景。AI 评估候选人、自动生成面试题只能作为辅助最终录用决策必须由 HR 人工确认。这里必须强调安全与合规边界。简历信息属于个人敏感数据包含姓名、联系方式、教育经历、工作经历。项目演示时一定要使用脱敏数据或对构造的假简历进行测试。真正上线时需要候选人明确授权“简历用于 AI 辅助筛选”还要限制系统访问范围不能把简历内容随意传给外部模型做训练。如果模型服务在境外还要额外评估数据跨境合规问题。合法授权、最小化收集、人工复核这三条底线不能破。3. 25 个核心技术点一次拆透标题里说“25 个核心技术点”这里做一个系统化拆解。我按层次分成 5 个部分每部分 5 个点总共 25 个和你实际编码顺序一致先搭框架再接入模型再做 Agent 能力再上 Graph 编排最后做工程化与合规。3.1 基础设施层Spring Boot 3.x 项目搭建。注意 Spring AI 对 Spring Boot 版本有要求通常需要 3.2 及以上建议直接用最新稳定版。Starter 依赖管理。Spring AI Alibaba 提供了 Spring Boot 风格的 Starter引入后自动配置模型客户端。配置文件外部化。API Key、模型名、超时时间放在环境变量或 application.yml 中不写死在代码里。日志链路。每一轮 Agent 调用要有 traceId方便后面排查问题。环境隔离。开发、测试、生产使用不同的 API Key 和模型配置。3.2 模型接入层ChatClient 统一调用入口。Spring AI 的 ChatClient 屏蔽了不同模型的差异业务代码不需要关心底层是 qwen-plus 还是 qwen-max。PromptTemplate 模板管理。把 HR 角色的系统提示词、JD 分析模板、简历提取模板做成可复用模板。结构化输出。让模型返回 JSON 而不是自由文本用于简历字段提取、评分表生成。模型参数控制。temperature、maxTokens、topP 这些参数要按节点设置比如简历解析用低 temperature面试题生成可以略高。流式输出。对于报告生成这类长文本任务可以使用流式接口提升体验后面会演示普通同步调用和流式调用两种方式。3.3 Agent 能力层Function Calling 工具调用。让模型调用 Java 方法完成计算类任务比如计算匹配分数、查询 JD 库。多轮上下文记忆。候选人追问后Agent 要记住前面评估的结果不能每次重新解释。工具结果校验。模型调用 Java 方法后返回值要先校验再进入下一步节点。错误指令拦截。当模型做出超出招聘范围的操作时拒绝执行并给出明确提示。人机协同节点。关键决策点插入“人工审核”状态Graph 停在待审核节点等 HR 确认后再继续执行。3.4 Graph 编排层StateGraph 状态图核心。把招聘流程建模成节点、边、状态的图结构。节点拆分原则。每个节点只做一件事简历解析节点不写面试题生成逻辑。条件边路由。匹配分数低于阈值时直接走到“不通过”节点而不是继续生成面试题。并行节点。JD 分析、薪资区间分析、简历提取可以并行减少总耗时。循环与终止条件。面试题追问最多 N 轮达到次数后强制进入报告节点防止死循环。3.5 工程化与合规层Actuator 监控。通过 /actuator/health 和自定义 Metrics 观察接口健康状态和调用次数。接口幂等性。同一个候选人重复提交应该复用已有结果而不是重复消耗 Token。批量任务队列。多份简历批量处理时要限制并发避免打爆 API 配额。数据脱敏与日志清理。日志中不打印完整手机号和邮箱演示数据使用假信息。效果评估集。准备 10 份典型简历做回归测试每次修改 Prompt 后跑一遍确认输出质量没有回退。这 25 个点并不是全部要在第一个版本里实现但它们是完整 Agent 项目必须具备的能力。下面的实战部分会按这个顺序逐步落地核心模块。4. 环境准备与前置条件在开始写代码之前先把环境对齐。下面是一个通用检查清单。JDK17 或 21建议 21。Spring AI 对 JDK 版本要求不高但 17 是底线。构建工具Maven 3.9 或 Gradle 8.x本文以 Maven 为例。框架版本Spring Boot 3.x建议从 Spring Initializr 生成基础工程后再添加 AI 依赖。IDEIntelliJ IDEA 社区版即可不需要付费版。模型服务准备一个可用的大模型 API Key。Spring AI Alibaba 默认对接阿里云百炼平台也可以配置为 OpenAI 兼容协议或用 Ollama 跑本地模型。可选工具Postman 或 curl 用于接口测试Redis 可选用于多轮会话状态缓存。先创建一个空的 Spring Boot 项目然后添加依赖。下面是一个依赖参考片段。!-- 以下坐标为参考具体版本请以 Spring Initializr 生成结果为准 -- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId version${spring-ai-alibaba.version}/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-graph/artifactId version${spring-ai.version}/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency依赖版本不要手写死优先用 Spring Initializr 帮你关联的版本。Spring AI 的版本更新比较快不同版本的配置项存在差异直接套旧版本写法经常会遇到“属性找不到”或“类不存在”的问题。接着配置 application.yml。这里以调用云端模型为例 API Key 从环境变量读取。spring: application: name: hr-agent ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen-plus temperature: 0.3 server: port: 8080 management: endpoints: web: exposure: include: health,metrics注意Spring AI Alibaba 的配置路径在不同版本中可能有调整比如有的版本用spring.ai.dashscope.api-key有的用spring.ai.alibaba.dashscope.api-key。以当前版本官方文档为准。如果启动后日志出现“api-key 未配置”优先检查这一段。如果你没有云端 API Key也可以用 Ollama 跑本地模型。先启动 Ollama 并拉取模型然后在配置中切换为本地地址。这种方式适合离线学习但输出质量和速度都不如云端大模型。5. 从零搭建 HR 招聘全流程 Agent 骨架这里先把最核心的 Spring AI Graph 执行逻辑跑起来。Graph 的本质是一个有状态的工作流定义一个状态对象把流程拆成多个节点节点之间用边连接最后通过执行器跑通整条链路。先定义状态对象。招聘流程状态至少包含简历路径、JD 信息、解析后的候选人画像、匹配分数、面试题列表、最终报告。public class RecruitmentState { private String resumePath; private String jdContent; private String candidateProfile; private Double matchScore; private ListString interviewQuestions; private String report; // 构造函数、getter、setter 省略实际项目使用 record 或 POJO }再定义节点。每个节点实现统一接口从状态对象中读取输入处理后再写回状态对象。这里给一个简历解析节点的示意代码。Component public class ResumeParserNode implements NodeRecruitmentState { private final ChatClient chatClient; public ResumeParserNode(ChatClient chatClient) { this.chatClient chatClient; } Override public RecruitmentState apply(RecruitmentState state) { String prompt 你是一名资深 HR 助理。请从下面的简历文本中提取结构化的候选人信息并以 JSON 返回。 输出字段name, yearsOfExperience, skills, education, lastCompany, highlights。 简历内容 %s .formatted(state.getResumePath()); String result chatClient.call(prompt); state.setCandidateProfile(result); return state; } }上面这份代码的职责很明确输入简历输出结构化候选人画像。实际项目中简历解析不能只传个路径应该由工具节点读取 PDF 转成文本后再交给模型这部分可以用 Spring AI 的 Tool 机制实现。接着配置 Graph。把所有节点按招聘流程串起来。Configuration public class RecruitmentGraphConfig { Bean public GraphRecruitmentState recruitmentGraph( ResumeParserNode resumeParserNode, JdMatcherNode jdMatcherNode, InterviewQuestionNode interviewQuestionNode, ReportNode reportNode) { StateGraphRecruitmentState graph new StateGraph(RecruitmentState.class) .addNode(resumeParser, resumeParserNode) .addNode(jdMatcher, jdMatcherNode) .addNode(interviewQuestion, interviewQuestionNode) .addNode(report, reportNode) .addEdge(START, resumeParser) .addEdge(resumeParser, jdMatcher) .addEdge(jdMatcher, interviewQuestion) .addEdge(interviewQuestion, report) .addEdge(report, END); return graph.compile(); } }这段代码是教学示意不同版本的 Spring AI Graph API 命名可能不同比如StateGraph的构造方式、addEdge的写法、compile()的返回值都需要按当前版本调整。思路是一致的图由节点和边组成执行器给你一个有状态的工作流容器。最后把 Graph 包成一个 Service方便 Controller 调用。Service public class RecruitmentAgentService { private final GraphRecruitmentState graph; public RecruitmentAgentService(GraphRecruitmentState graph) { this.graph graph; } public RecruitmentState run(RecruitmentState initialState) { return graph.execute(initialState); } }到这里一个最小可运行的 Spring AI Alibaba Graph 骨架就完成了。你可以先用一个最简单的测试调用它观察状态对象从“简历路径”到“评估报告”的完整流转。这一步跑通后再逐步加入条件路由和并行节点。6. 功能测试与效果验证工程跑通之后不要急着写复杂业务逻辑先分功能做验证。这里给出 5 个测试维度每个维度都写明测试目标、操作步骤、预期结果和排查方向。6.1 简历解析测试测试目标是确认 ResumeParser 节点能否从简历文本中提取结构化字段。准备一份脱敏的假简历例如“张三5 年 Java 后端经验熟练使用 Spring Boot、MySQL、Redis”。调用后预期输出包含 name、yearsOfExperience、skills 等字段的 JSON。判断成功的标准是字段完整、格式正确、能被 Jackson 正常反序列化。如果模型返回了多余字段或者 JSON 解析失败优先检查 Prompt 模板是否明确指定了“只返回 JSON”以及 temperature 是否偏高。6.2 JD 理解测试把一份真实 JD 文本传入 JdMatcher 节点要求输出职位名称、技能要求、经验要求、软素质要求四个结构化字段。测试时要换 2 到 3 份不同行业的 JD确认模板不是只适配某一个岗位。如果发现 JD 中的“3 年经验”被模型理解成“9 年经验”说明 Prompt 缺少“严格按原文提取数字”的约束。这类问题建议在 Prompt 模板中补充“不要推断原文不存在的门槛”。6.3 匹配打分测试匹配打分建议不要直接让模型输出一个数字而是先让模型列出匹配项和不匹配项再由 Java 方法计算最终分数。这样可以避免模型随意写出一个超出范围的分数。测试场景一个 3 年经验的候选人投递“5 年经验”岗位。预期的输出应当是匹配度偏低并且不匹配项里明确写着“经验不足”。如果模型给出的分数和理由互相矛盾说明功能调用链路没有生效需要检查模型是否真的调用了打分方法。6.4 面试题生成测试面试题生成节点要同时考虑 JD 和候选人画像生成技术题、项目题、行为题三类问题。行为题可以要求模型按 STAR 法则设计追问点。测试时传入一个技能为 Spring Boot 但没有微服务经验的候选人预期技术题中包含微服务相关的基础问题而不是直接问“你做过几个微服务项目”。如果生成结果和候选人画像无关大概率是 Prompt 中没有引用 state 中的 candidateProfile 字段。6.5 端到端 Graph 执行测试这是最关键的验证。完整执行一次 Graph传入简历和 JD观察整个流程是否按“简历解析 - 匹配 - 面试题 - 报告”顺序执行并且最后报告内容包含前面节点的结果。判断成功标准是报告中的候选人画像、匹配分数、面试题相互一致没有张冠李戴。失败时重点排查两个地方边是否连接错误以及某个节点是否因为状态字段为空而提前失败。这里建议在每个节点执行前后打日志输出状态对象快照。7. Agent 接口暴露与批量任务编排Graph 内部跑通后下一步要对外提供接口。最直接的做法是写一个 REST Controller接收候选人信息调用 Graph 执行器返回结果。RestController RequestMapping(/api/hr-agent) public class RecruitmentAgentController { private final RecruitmentAgentService recruitmentAgentService; public RecruitmentAgentController(RecruitmentAgentService recruitmentAgentService) { this.recruitmentAgentService recruitmentAgentService; } PostMapping(/run) public RecruitmentState run(RequestBody RecruitmentState request) { return recruitmentAgentService.run(request); } }用 curl 测试接口curl -X POST http://127.0.0.1:8080/api/hr-agent/run \ -H Content-Type: application/json \ -d { resumePath: ./data/resume_zhangsan.txt, jdContent: 招聘 Java 后端工程师5 年经验熟悉 Spring Boot、MySQL、Redis }这里返回的是完整状态对象包含候选人画像、匹配分数、面试题列表、报告内容。注意接口路径和字段名只是教学示例实际项目要按照自己的业务结构调整。批量任务才是真实业务的主角。一个 HR 系统经常要一次处理几十份简历简单方式是逐个调用接口但更好的设计是任务队列。核心思路如下任务入队把每份简历的路径和对应 JD ID 封装成任务对象。并发控制用线程池限制并发数比如 max(2, CPU 核数)避免同时发出太多请求。状态持久化任务执行进度、中间结果写入数据库失败任务可以重试。幂等设计同一个 resumePath 重复提交时直接返回已有结果。Service public class BatchRecruitmentService { private final RecruitmentAgentService agentService; private final ExecutorService executor Executors.newFixedThreadPool(4); public CompletableFutureRecruitmentState submit(String resumePath, String jdContent) { return CompletableFuture.supplyAsync(() - { RecruitmentState state new RecruitmentState(); state.setResumePath(resumePath); state.setJdContent(jdContent); return agentService.run(state); }, executor); } }批量任务的关键不是并发越高越好而是要让每一步都可追踪、可重试、可审计。真实业务中几十份简历分批处理更合适每批 5 到 10 份跑完一批再进下一批避免单次任务量过大导致 API 超时或 Token 配额耗尽。8. 资源占用与性能观察这个项目跑在 JVM 上本身不涉及显存计算。资源消耗主要看模型服务部署在哪里以及你如何控制调用频率。如果你使用云端大模型 API本机资源占用很低一个 2 核 4G 的服务器就能稳定运行。此时性能瓶颈在三个地方网络延迟、模型响应时间、API 并发配额。建议通过 Actuator 暴露自定义指标统计 Graph 平均执行时间、各节点耗时、Token 消耗量。比如在节点执行前后记录 System.currentTimeMillis()就能快速找出哪个节点最慢。如果你切换到本地 Ollama 或其他开源模型就要考虑显卡资源了。常见 8B 级别量化模型在 6G 到 8G 显存可以运行Embedding 模型更小但这是通用经验值不同的量化方式、上下文长度、并发数都会影响实际占用。更稳妥的判断是先用云端 API 跑通全部功能确认架构没有任何问题后再评估是否值得换成本地模型节省调用费用。还有一个容易被忽略的性能问题Graph 中如果存在大量串行模型调用端到端延迟会非常可观。比如简历解析 2 秒、JD 匹配 3 秒、面试题生成 4 秒、报告生成 5 秒串行加起来 14 秒。优化方式有两种。第一把互不依赖的节点改为并行比如 JD 分析和简历解析同时进行。第二里程碑报告直接流式输出用户先看到前部分内容不用等完整报告生成。9. 常见问题与排查方法实际开发中Spring AI Alibaba Graph 的报错主要集中在依赖版本、配置项、模型返回异常三个方面。下面这张排查表可以帮你快速定位。问题现象可能原因排查方式解决方案启动报 api-key 未配置配置项路径不对或环境变量未设置检查日志中的配置加载信息按当前版本文档修正配置路径调用模型返回 401API Key 无效或已过期用官方控制台验证 Key 是否可用重新生成 API Key改用环境变量注入模型返回内容 JSON 解析失败模型没有严格按 Prompt 返回 JSON打印模型原始输出在 Prompt 中强调“只返回 JSON”降低 temperatureStateGraph 节点循环执行不结束缺少循环终止条件查看执行日志判断哪个节点被反复调用在节点中增加轮次计数达到上限强制终止多个并发任务结果互相污染使用了共享的可变状态对象检查状态对象是否被多个线程复用每次请求创建独立状态实例批量任务中个别简历失败文件解析失败或模型超时查看任务日志中的异常栈增加失败重试按 batch 拆小批量依赖版本冲突Spring Boot 与 Spring AI 版本不匹配执行 mvn dependency:tree 查看依赖树通过 Spring Initializr 重新生成项目统一版本Actuator 没有暴露自定义指标未引入 micrometer 注册代码检查依赖和配置手动注册 Gauge 或 Counter这里要特别提醒一个 Graph 特有的坑循环节点。如果面试追问节点设计成可以反复执行一定记得在状态对象里维护一个questionRound计数字段每轮加一超过上限就走条件边到报告节点。否则一个小数点错误或 Prompt 歧义都可能让 Graph 进入死循环白白消耗 Token。10. 最佳实践与下一步最后给几条工程化建议都是这个项目中已经验证过有价值的做法。第一先小步验证再做大流程。第一次跑 Graph 时只保留“简历解析 - 报告”两个节点确认基础链路稳定后再逐步加入匹配、面试题、条件路由。这样出问题时定位范围非常小。第二Prompt 模板要单独管理。不要把所有提示词都散落在代码里建议放到 resources 目录下的模板文件中或统一封装成 PromptTemplate。每次修改后记录版本号方便对比输出质量变化。第三设置一个人工复核节点。HR 招聘 Agent 的最终报告只能作为参考材料自动化生成的评估结果必须有人工确认环节。在 Graph 中预留一个“PENDING_REVIEW”状态报告生成后停在人工审核审核通过再进入下一流程。这不仅解决业务合规问题也会让你的 Agent 架构更贴近真实生产环境。第四准备一个最小回归测试集。用 10 份不同类型的假简历和 3 份 JD每星期跑一遍端到端测试确认修改 Prompt 或代码后简历解析、匹配分数、面试题质量没有明显退步。这是 Agent 项目最难的部分也是最值得投入的部分。这个项目的核心收获不是“我会写一个招聘 Agent”这么简单而是掌握了一套 Java 生态里的 Agent 编排范式状态定义、节点拆分、条件路由、工具调用、人工审核、批量任务。这套结构不绑死任何行业业务。你现在理解了 HR 招聘流程的 Graph 怎么画下一次面对“工单自动分派”“合同智能审阅”“客服话术推荐”这些需求时只是换一套节点和 Prompt 的问题。建议先把简历解析和 JD 匹配这条最长的链路跑通再把面试题生成和报告节点接上。Graph 的价值要在链路完整之后才真正体现出来。收藏这篇文章按第 4 章到第 6 章的顺序动手跑一遍25 个核心技术点不用一次全懂先把主链路跑起来再逐个点亮其他能力点。
返回列表