Spring AI Alibaba Graph实战:构建HR自动化AI Agent的工程化指南
2026/9/15 16:04:40 网站建设 项目流程

你有没有遇到过这样的场景:一个HR同事,每天要处理几十份简历,筛选、分类、初步沟通、安排面试、跟进反馈……这些重复性工作不仅耗时,还容易因为疲劳而错过优秀人才。或者,你作为一个开发者,看到AI Agent的概念很火,但一上手就发现,从“跑通一个Demo”到“做出一个能在真实业务里稳定工作的智能体”,中间隔着一道巨大的鸿沟。

最近,Spring AI Alibaba Graph 的出现,让很多Java开发者看到了一个机会:用自己熟悉的Spring生态,去搭建一个真正能处理复杂工作流的AI Agent。但问题也随之而来——网上的教程要么停留在“Hello World”级别的API调用,要么直接跳到“企业级架构”这种抽象概念,中间那部分“怎么从玩具变成工具”的实操经验,几乎没人细说。

今天,我们就以“HR自动化AI Agent”这个跨行业通用的实战案例为线索,拆解如何用Spring AI Alibaba Graph搭建一个能理解任务、拆解步骤、调用工具并完成闭环的智能体。这不仅仅是一个技术实现,更是一次关于如何将大模型能力“工程化”的深度探索。你会发现,真正的难点从来不是调用哪个API,而是如何设计一个可靠、可维护、可扩展的智能工作流。

1. 为什么是“HR自动化”?一个理解AI Agent价值的绝佳切口

在开始写代码之前,我们必须先回答一个问题:为什么选择HR场景作为案例?它真的能体现AI Agent的核心价值吗?

我的判断是:HR的日常工作流程,是检验一个AI Agent框架是否具备“业务理解”和“流程编排”能力的试金石。它不像聊天机器人那样简单的一问一答,也不像单次文本生成那样独立。一个HR Agent需要串联起多个环节:

  1. 理解需求:从“帮我找一下Java后端工程师”这样模糊的指令,拆解出具体的技能要求、经验年限、薪资范围。
  2. 执行动作:它可能需要去简历库搜索、去招聘网站爬取(模拟)、给候选人发送初步沟通邮件、甚至预约面试时间。
  3. 决策与判断:根据简历内容进行初步筛选,判断与岗位的匹配度。
  4. 状态管理与回溯:记住已经联系过哪些人、面试进展到哪一步,并在后续对话中能回溯上下文。

这个过程天然就是一个“图”(Graph)。Spring AI Alibaba Graph 中的“Graph”,指的就是这种有向无环的工作流。每个节点代表一个处理单元(可以是LLM调用、工具函数、条件判断),节点之间的边代表执行路径和数据的流动。

所以,搭建HR Agent的过程,本质上是在用代码定义一套“招聘专家”的思维和工作流程。这比单纯演示“请写一首诗”要有价值得多,因为它触及了AI Agent落地的核心:将不确定的自然语言指令,转化为确定性的、可重复执行的业务步骤。

2. 超越“Hello World”:用Spring AI Alibaba Graph构建智能体的核心骨架

很多教程止步于配置一个ChatClient,然后调用chat()方法。这离一个真正的Agent还差得很远。Spring AI Alibaba Graph 提供了一套更高级的抽象,让我们能以“编排工作流”的思维来构建应用。

2.1 环境搭建与依赖:避开第一个坑

首先,确保你的项目是基于Spring Boot 3.x(推荐3.2+)和Java 17+。在pom.xml中,核心依赖不仅仅是spring-ai-alibaba-spring-boot-starter

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-alibaba-spring-boot-starter</artifactId> <version>最新版本</version> <!-- 请替换为官方最新版本 --> </dependency> <!-- 图形化工作流定义通常需要 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-core</artifactId> </dependency> <!-- 如果你需要连接自己的数据源(如简历库),数据库驱动也是必须的 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>

第一个关键点:模型配置。application.yml中,你需要明确指定使用的模型。这里以阿里云灵积平台为例:

spring: ai: alibaba: chat: options: # 模型名称,例如 qwen-max, qwen-plus model: qwen-max # 阿里云API密钥 api-key: ${ALIBABA_API_KEY} # 通常base-url是固定的 base-url: https://dashscope.aliyuncs.com/compatible-mode/v1

注意api-key务必通过环境变量${ALIBABA_API_KEY}注入,不要硬编码在配置文件里。这是安全实践的第一步。

2.2 定义“工具”(Tool):让Agent拥有“手和脚”

Agent的强大之处在于它能调用外部工具。在HR场景中,工具可能就是:

  • ResumeSearchTool: 根据条件从数据库查询简历。
  • EmailSenderTool: 发送面试邀请或感谢信。
  • CalendarCheckTool: 检查面试官的空闲时间。

在Spring AI中,定义一个工具非常简单,就是一个普通的Spring Bean,方法上标注@Tool注解。

import org.springframework.ai.tool.annotation.Tool; import org.springframework.stereotype.Component; @Component public class ResumeSearchTool { @Tool(description = "根据技能关键词、工作年限和地点搜索简历,返回匹配的简历列表。") public List<Resume> searchResumes( @ToolParam(description = "技能关键词,如Java, Spring Cloud") String skills, @ToolParam(description = "最低工作年限") int minYearsOfExperience, @ToolParam(description = "工作地点") String location) { // 这里实现你的数据库查询逻辑 // 示例:return resumeRepository.findBySkillsContainingAndExperienceGreaterThanEqualAndLocation(skills, minYearsOfExperience, location); return new ArrayList<>(); // 返回示例 } }

关键理解@Tool注解和描述(description)至关重要。大模型(LLM)正是根据这些描述来决定在什么情况下调用哪个工具,以及如何传递参数。描述要清晰、准确,就像你在给一个实习生写工作说明书。

2.3 构建工作流(Graph):从线性思维到图状思维

这是最核心的部分。传统的代码是线性的:A -> B -> C。而Graph允许我们定义更复杂的关系:根据A的结果,决定走B分支还是C分支,甚至并行执行D和E。

Spring AI Alibaba Graph 支持通过Java DSL(领域特定语言)或YAML来定义Graph。对于复杂流程,DSL更灵活。

import org.springframework.ai.graph.Graph; import org.springframework.ai.graph.builder.GraphBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class HrAgentGraphConfig { @Bean public Graph hrRecruitmentGraph(GraphBuilder graphBuilder) { return graphBuilder .start("parse_requirement") // 节点1:解析需求 .function("llmFunction") // 使用LLM解析用户输入 .to("decide_action") // 流向决策节点 .node("decide_action") // 节点2:决策下一步行动 .function("llmFunction") // LLM判断该搜索、发邮件还是其他 .to("search_resumes", "send_email", "schedule_interview") // 三个可能的分支 .node("search_resumes") .tool("resumeSearchTool") // 调用我们定义的工具 .to("format_results") .node("format_results") .function("llmFunction") // 将搜索结果格式化为友好回复 .end() // 结束 .node("send_email") .tool("emailSenderTool") .end() .node("schedule_interview") .tool("calendarCheckTool") .to("send_invitation") .node("send_invitation") .tool("emailSenderTool") .end() .build(); } }

这个Graph定义了以下流程:

  1. 开始 -> 解析用户需求(LLM)。
  2. 根据解析结果,决定走哪条分支:搜索简历、发送邮件或安排面试。
  3. 每条分支调用相应的工具执行具体任务。
  4. 任务完成后,可能经过格式化(LLM),最终结束。

为什么这比直接写Service类更好?因为它的声明式可视化。整个工作流的逻辑一目了然,修改执行顺序或增加新节点就像修改流程图一样简单,而不需要深入业务代码逻辑中去寻找调用链。

3. 实战演练:拆解一个完整的“筛选并联系候选人”流程

让我们把上面的骨架填充上血肉,实现一个具体的场景:HR说“帮我找3个在北京有5年以上Java经验的工程师,并发送初步沟通邮件”。

3.1 步骤一:设计提示词(Prompt)—— 告诉LLM如何思考

LLM需要明确的指令。我们将为Graph中的llmFunction节点设计专用的提示词模板。

import org.springframework.ai.prompt.PromptTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class PromptConfig { @Bean(name = "requirementParserPrompt") public PromptTemplate requirementParserPrompt() { return new PromptTemplate(""" 你是一个专业的HR助手。请从用户的以下请求中,精确提取出招聘需求信息。 用户请求:{userInput} 请以JSON格式输出,且只输出JSON,不要有任何其他解释。 JSON结构: { "position": "职位名称", "skills": ["技能1", "技能2", ...], "minExperience": 最低工作年限(数字), "location": "工作地点", "action": "需要执行的主要动作,如:search_resumes, send_email" } """); } @Bean(name = "actionDeciderPrompt") public PromptTemplate actionDeciderPrompt() { return new PromptTemplate(""" 你是一个工作流决策器。根据当前的招聘需求上下文,决定下一步应该做什么。 当前需求:{requirementJson} 历史动作:{history} 请从以下选项中选择一个且仅一个动作: - search_resumes: 如果还需要搜索或筛选简历。 - send_email: 如果已经确定了候选人,需要发送邮件。 - schedule_interview: 如果需要安排面试。 - complete: 如果所有任务已完成。 只输出动作名称,例如:search_resumes """); } }

提示词设计的核心结构化输出和严格约束。通过要求LLM输出特定格式的JSON或限定选项,我们才能在后继的代码中可靠地解析其结果,驱动工作流走向不同的分支。这是Agent稳定性的基石。

3.2 步骤二:实现工具类与数据层

ResumeSearchTool需要真实的查询。这里假设使用Spring Data JPA。

@Component public class ResumeSearchTool { @Autowired private ResumeRepository resumeRepository; @Tool(description = "根据技能、最小工作年限、地点和需要的数量搜索简历,返回匹配的简历列表。") public List<Resume> searchResumes( @ToolParam(description = "技能列表") List<String> skills, @ToolParam(description = "最低工作年限") int minYearsOfExperience, @ToolParam(description = "工作地点") String location, @ToolParam(description = "需要返回的最大简历数量") int limit) { // 一个简单的多技能匹配查询示例(实际可能更复杂) return resumeRepository .findByLocationAndYearsOfExperienceGreaterThanEqual(location, minYearsOfExperience) .stream() .filter(resume -> skills.stream().anyMatch(skill -> resume.getSkills().contains(skill))) .limit(limit) .collect(Collectors.toList()); } }

EmailSenderTool则集成邮件发送服务(如JavaMailSender)。

3.3 步骤三:组装与执行Graph

在Service中,我们注入定义好的Graph并执行它。

@Service public class HrAgentService { @Autowired private Graph hrRecruitmentGraph; @Autowired private GraphExecutor graphExecutor; public String processHrRequest(String userInput) { // 1. 准备初始输入 Map<String, Object> initialInput = new HashMap<>(); initialInput.put("userInput", userInput); initialInput.put("history", "[]"); // 初始无历史 // 2. 执行Graph GraphResponse response = graphExecutor.execute(hrRecruitmentGraph, initialInput); // 3. 从最终节点获取结果 // 假设我们的Graph结束在名为“format_results”或“send_email”的节点 // 需要根据Graph设计来获取具体结果 Map<String, Object> finalOutput = response.getOutput(); return (String) finalOutput.get("finalReply"); // 返回给用户的最终消息 } }

3.4 步骤四:暴露为API

最后,通过一个简单的REST控制器提供服务。

@RestController @RequestMapping("/api/hr-agent") public class HrAgentController { @Autowired private HrAgentService hrAgentService; @PostMapping("/process") public ResponseEntity<AgentResponse> processRequest(@RequestBody UserRequest request) { String reply = hrAgentService.processHrRequest(request.getQuery()); return ResponseEntity.ok(new AgentResponse(reply)); } }

至此,一个具备基本能力的HR自动化Agent后端就搭建完成了。用户通过API发送自然语言请求,后端通过Graph工作流协调LLM和工具,完成从理解到执行的闭环。

4. 从“跑通”到“用好”:20个必须关注的工程化核心点

Demo跑起来只是第一步。要让这个Agent能在实际环境中可靠工作,以下20个核心点是你必须逐一检查和思考的。这不仅是技术点,更是面试中展现你工程深度的关键。

4.1 性能与成本管控

  1. Token消耗统计与优化:Spring AI Alibaba 提供了TokenUsage类来统计每次调用的消耗。在application.yml中开启spring.ai.alibaba.chat.options.log-requests: true也能看到详情。优化策略:在提示词中严格要求输出格式,避免冗余;对长文本简历进行智能摘要后再喂给LLM。
  2. 请求超时与重试:网络和模型服务都不稳定。务必配置合理的超时(spring.ai.alibaba.chat.options.request-timeout)和重试机制(可结合Spring Retry)。
  3. 速率限制(Rate Limiting):模型服务商有QPS限制。在客户端必须实现限流,避免突发流量导致请求失败。
  4. 异步与非阻塞:Graph的执行,特别是涉及多个LLM调用和工具调用时,可能是耗时的。考虑使用@Async或WebFlux进行异步处理,避免阻塞HTTP线程。

4.2 稳定性与可靠性

  1. 工具的健壮性ResumeSearchTool里数据库查询可能慢或失败;EmailSenderTool可能遇到SMTP服务器问题。每个工具都必须有完善的异常处理和日志记录,并考虑设计降级方案(如查询失败时返回缓存结果)。
  2. Graph的状态管理与持久化:复杂的多轮交互Agent,其Graph执行状态可能需要保存到数据库或Redis中,以便中断后恢复。Spring AI Graph 本身支持GraphExecution状态持久化,需要你配置GraphExecutionRepository
  3. LLM输出的不确定性处理:尽管我们要求LLM输出JSON,但它偶尔仍可能“胡说八道”。必须在代码中添加解析校验逻辑,一旦解析失败,触发重试或转入人工处理流程。
  4. 循环与深度控制:Graph要避免设计成无限循环。确保每个执行路径都有明确的终止条件(end()节点)。

4.3 可观测性与调试

  1. 结构化日志:记录每个Graph节点的输入、输出、耗时和Token使用情况。使用MDC(Mapped Diagnostic Context)为每次请求分配唯一ID,方便链路追踪。
  2. Graph可视化:Spring AI 部分版本支持将Graph导出为Mermaid.js或DOT格式的图表。将其集成到管理后台,直观查看工作流和实时执行状态。
  3. 输入输出快照:在开发测试阶段,保存每次重要LLM调用和工具调用的输入输出,便于复现和调试诡异问题。

4.4 架构与扩展性

  1. 工具的动态注册与发现:随着业务增长,工具类会越来越多。可以设计一个工具注册中心,让Graph能动态发现可用的工具,而不是硬编码在配置里。
  2. 多模型路由与降级:不要绑定死一个模型。可以设计一个ModelRouter,根据任务类型(创意性 vs 逻辑性)、成本、当前负载等因素,动态选择不同的模型(如Qwen-Max用于复杂决策,Qwen-Turbo用于简单分类)。并在主模型不可用时,自动切换到备用模型。
  3. 向量数据库集成:对于简历搜索,简单的关键词匹配不够。使用Spring AI的向量存储抽象,将简历技能描述向量化,进行语义搜索,匹配效果更佳。
  4. Agent的“记忆”能力:为Agent添加长期记忆(如使用Redis存储对话历史摘要)和短期记忆(当前会话上下文),使其能在多轮对话中保持一致性。

4.5 安全与合规

  1. 输入输出过滤与审查:对用户输入和LLM输出进行必要的敏感词过滤、防注入攻击检查。特别是涉及发送邮件、访问数据库的工具。
  2. 数据隐私:简历信息是高度敏感的个人数据。确保工具在查询、处理和日志记录时都进行了脱敏。LLM调用是否涉及数据出境需合规评估。
  3. 权限控制:不同的HR用户可能只能操作自己部门的简历或职位。需要在Graph执行入口或具体工具中,注入并校验用户权限上下文。

4.6 开发与部署

  1. 配置外部化:所有模型API Key、端点、超时时间、提示词模板等,必须全部放在配置中心(如Nacos、Apollo)或环境变量中,杜绝硬编码。
  2. 版本管理与回滚:Graph的定义、提示词、工具逻辑都可能频繁迭代。需要像管理代码一样管理它们的版本,并具备快速回滚能力。

5. 面试少走弯路:如何向面试官阐述你的AI Agent项目

如果你在简历中写了这样一个项目,面试官想听的绝不仅仅是“我用Spring AI调了通义千问”。他们想考察的是你面对新技术时的工程化思维解决真实问题的能力。你可以按这个框架来组织你的回答:

“我构建了一个用于HR场景的自动化AI Agent,核心是解决从模糊需求到确定性执行的流程自动化问题。我选用Spring AI Alibaba Graph,是因为它提供了基于工作流编排的声明式编程模型,非常适合处理HR招聘这类多步骤、有分支的任务。”

“在实现上,我重点解决了三个层面的问题:”

  1. 交互层(LLM调用):通过设计结构化的提示词,约束LLM的输出,使其成为可靠的工作流决策节点,而不是黑盒聊天。
  2. 执行层(工具集成):将简历查询、邮件发送等能力封装成@Tool,让Agent具备了操作真实业务系统的“手”。
  3. 流程层(Graph编排):用DSL清晰定义了“解析需求->决策->执行->反馈”的流程,使得业务逻辑可视化、可维护。

“在项目深入阶段,我特别关注了工程化落地:”

  • 性能与成本:通过Token统计和提示词优化控制成本,通过异步化和缓存提升响应速度。
  • 稳定性:为每个工具和LLM调用设置了超时、重试和降级策略。
  • 可观测性:实现了全链路的结构化日志和Graph执行状态追踪,便于调试。
  • 安全:加入了输入校验、数据脱敏和基于角色的权限控制。

“这个项目的价值在于,它不是一个玩具,而是一个展示了如何将大模型能力以可控、可靠、可扩展的方式嵌入到现有Java技术栈和业务系统中的原型。它让我深入思考了AI Native应用开发与传统业务系统开发在架构模式上的异同。”

这样的阐述,表明你不仅会使用框架,更理解其背后的设计理念,并具备了将前沿技术落地到复杂生产环境所需的全面思考。这才是面试官真正想听到的“干货”。

回到开头的问题,用Spring AI Alibaba Graph搭建AI Agent,技术上的入门并不难。真正的挑战和乐趣,在于如何用软件工程的严谨思维,去驾驭大模型的不确定性,设计出既智能又鲁棒的业务流程。HR自动化只是一个起点,这套方法论可以平移到客服、运维、内容审核、智能导购等无数场景。当你开始用“图”的视角去拆解业务,用“工具”的思维去扩展能力,用“工程化”的标准去要求每一个细节时,你就已经走在了AI Agent实战开发的正道上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询