Spring AI 2.0 进阶入门:Workflow、Routing、Task State 与可控 Agent

前面的学习已经完成了 Memory → RAG → Tool → MCP → Structured Output。这些组件解决了 Agent 能知道什么、能够调用什么以及怎样把结果交给 Java 的问题。

当 Tool 数量越来越多、任务越来越长时,下一个问题会变成:谁来决定程序下一步执行什么?

有些业务流程可以由 Java 提前确定,有些任务需要 LLM 根据实际情况动态选择。Spring AI 的 Agent Workflow正是在处理这一层问题。

一、先理解 Agent 中的两种控制方式

传统 Java 程序具有非常明确的控制路径:

复制代码
if 条件成立
   ↓
调用 Service A
   ↓
调用 Service B
   ↓
返回结果

相同输入和状态通常会进入相同的代码路径。

LLM 的输出具有概率性。模型面对同一个问题时,受到 Prompt、上下文、模型版本和采样参数影响,可能产生不同判断。

因此,一个实际 Agent 通常同时存在两种控制力量

复制代码
Java / Workflow
→ 决定必须遵守的业务流程

LLM
→ 处理语义理解和无法提前写死的决策

例如退款流程可以固定为:

复制代码
识别退款意图
   ↓
查询订单
   ↓
检查退款资格
   ↓
满足条件后申请退款

其中"用户到底想退款、咨询退款规则还是查询退款进度"很适合交给 LLM 判断。

而:

复制代码
if (refundAmount > 5000) {
    requireManualApproval();
}

这种业务规则更适合继续由 Java 控制。

Spring AI 官方将这两类 Agentic System 分别称为 Workflow 和 AgentWorkflow 使用预定义代码路径组织模型与工具**【Workflow静态】,Agent 允许模型动态决定自己的执行过程【Agent动态,都类似于工作的模式,或者说智能系统Agentic System】**。

对于规则明确的企业任务,Workflow 往往具有更稳定的可预测性。

二、Workflow:把 LLM 放进确定的业务步骤

最简单的是 Chain Workflow,即多个步骤顺序执行。

例如:

复制代码
用户输入
   ↓
提取需求
   ↓
生成方案
   ↓
检查方案
   ↓
生成最终结果

代码本质仍然是普通 Java:

复制代码
String requirement = chatClient.prompt()
        .user("提取需求:" + input)
        .call()
        .content();

String plan = chatClient.prompt()
        .user("根据需求生成方案:" + requirement)
        .call()
        .content();

String result = chatClient.prompt()
        .user("检查并完善方案:" + plan)
        .call()
        .content();

LLM 负责每一步内部的智能处理,Java 负责规定步骤顺序。

Spring AI 官方的 Chain Workflow 示例采用同样的结构:前一步输出作为后一步输入,非常适合具有明确顺序的复杂任务。

三、Routing:先判断意图,再进入不同流程

很多 Agent 的第一步其实是 Routing,也就是意图路由。

例如客服系统收到:

复制代码
"为什么昨天扣了我两次钱?"

模型可以先输出:

复制代码
billing

然后 Java 将它路由到对应业务:

复制代码
用户请求
   ↓
LLM 意图识别
   ↓
billing / technical / general
   ↓
不同 Workflow

实际开发时,最好让模型返回结构化结果:

复制代码
public record RouteDecision(
        String route,
        String reason
) {}

然后:

复制代码
RouteDecision decision = chatClient
        .prompt()
        .user("""
              判断下面问题属于 billing、technical 或 general:
              """ + message)
        .call()
        .entity(RouteDecision.class);

Java 再根据结果执行:

复制代码
return switch (decision.route()) {
    case "billing" -> billingService.handle(message);
    case "technical" -> technicalService.handle(message);
    default -> generalService.handle(message);
};

这里体现了 Structured Output 的一个重要价值:自然语言决策可以转换成 Java 能够稳定读取的控制信号。

Routing 也是 Spring AI 官方列出的基础 Agent Workflow 模式

四、长任务还需要 Task State

学习过 ChatMemory 后,很容易把所有"记忆"都放到 Memory 中。实际 Agent 还需要区分 Conversation Memory 和 Task State。【对于长任务,需要补充State】

ChatMemory 主要保存:

复制代码
用户之前说过什么
模型之前回答过什么
当前对话需要哪些上下文

Task State 保存的是任务执行状态,例如:

复制代码
任务目标:完成退款

当前步骤:检查退款资格

orderId:A1024

订单状态:PAID

资格检查:PASSED

下一步:申请退款

它可以直接使用普通 Java 对象:

复制代码
public record RefundState(
        String orderId,
        String currentStep,
        boolean eligible,
        String status
) {}

复杂 Agent 的运行过程因此更适合理解成:

复制代码
ChatMemory
→ 对话上下文

Task State
→ 当前任务执行到了哪里

Database / Tool
→ 外部业务世界现在是什么状态

Task State 可以存入 Redis、数据库或者工作流引擎。它属于普通软件系统状态管理,并不要求全部塞进 Prompt。

五、任务复杂以后:Planning 与 Orchestrator-Workers

有些任务无法提前知道具体步骤。

例如:

复制代码
"分析这个项目代码并给出性能优化方案。"

系统可能需要:

复制代码
读取项目结构
分析数据库代码
分析缓存
分析接口
运行性能测试
汇总问题

不同项目产生的子任务还可能完全不同。

这时可以让 LLM 承担 Orchestrator:

复制代码
复杂目标
   ↓
LLM 分解任务
   ↓
Task A   Task B   Task C
   ↓       ↓       ↓
Worker  Worker  Worker
   └───────┬───────┘
           ↓
       汇总结果

Spring AI 将这种模式称为 Orchestrator-WorkersOrchestrator 动态产生子任务,Worker 分别执行,再汇总结果官方建议将它用于无法提前预测子任务的复杂任务**【比较简单、模糊的复杂任务口令】**。

如果多个任务彼此独立,还可以并行执行:

复制代码
任务
 ↓
 ├── 分析代码质量
 ├── 分析性能
 └── 分析安全风险
        ↓
      汇总

这对应Parallelization Workflow ,可以降低多个独立 LLM 任务串行执行带来的延迟。【Workflow有点像是代码预定义的一种工作模式,chain/分布式拆解/并行执行等】

六、Evaluator-Optimizer:让一次任务内部自我修正

还有一类模式非常重要:

复制代码
生成结果
   ↓
Evaluator
   ↓
达到标准?
 ↓否
给出修改意见
   ↓
再次生成
   ↓
重新评价

例如生成 Java 代码后,可以让另一个步骤检查:

复制代码
是否线程安全?
是否满足接口要求?
是否遗漏异常处理?

没有达到要求就重新生成。

Spring AI 官方称其为**Evaluator-Optimizer Workflow**,适合具有明确评价标准,并且多轮修改能够稳定提高结果质量的任务

Spring AI 2.0 中已经存在类似思想。例如:

复制代码
.entity(
    Result.class,
    spec -> spec.validateSchema()
)

如果模型输出不符合 JSON Schema,StructuredOutputValidationAdvisor 会获得具体验证错误,再请求模型修正,默认最多执行多次尝试。

Tool Calling 本身也是一种递归循环:

复制代码
LLM
 ↓
Tool
 ↓
Tool Result
 ↓
LLM
 ↓
继续判断

Spring AI 2.0 的 ToolCallingAdvisor 正是一个 Recursive Advisor。

七、运行时 Evaluator-Optimizer 与 Eval 需要区分

这里需要区分两个很容易混淆的概念:Evaluator-Optimizer 是 Agent 的运行时优化模式,Eval 是评价 AI 输出质量的方法和工程过程。

Evaluator-Optimizer 工作在当前任务内部:

复制代码
生成
 ↓
评价
 ↓
发现问题
 ↓
提供反馈
 ↓
重新生成
 ↓
再次评价

它的目标是利用评价结果继续修改当前输出。例如模型生成代码以后,Evaluator 检查是否满足接口要求;如果缺少异常处理,就把问题反馈给模型,让模型继续修改。

而 Eval 的核心目标是衡量结果好不好。它既可以评价一个案例,也可以批量运行整个测试集。

例如单个案例:

复制代码
用户问题
+
RAG Context
+
模型回答
        ↓
RelevancyEvaluator
        ↓
Pass / Fail

如果进一步准备 100 个测试案例:

复制代码
100个 Eval Case
        ↓
分别执行 Evaluator
        ↓
聚合评价结果
        ↓
得到当前版本质量指标

于是可以比较:

复制代码
v1 Prompt:87 / 100
v2 Prompt:93 / 100

因此更准确的关系是:

复制代码
Evaluator-Optimizer
→ 评价之后继续修改当前任务结果
→ 属于运行时 Agent Workflow

Eval
→ 评价结果质量
→ 可以作用于单个 Case、整个 Dataset、
  RAG、Tool Calling 或完整 Agent

Regression Test
→ 把一批固定 Eval Case
  在系统修改以后重新运行
→ 比较不同版本有没有提升或退化

还有一个很重要的细节:两者可以使用相似的评价技术。

例如都可以使用 LLM-as-a-Judge:

复制代码
Evaluator-Optimizer:

回答
 ↓
Judge LLM
 ↓
"不完整,需要补充来源"
 ↓
重新生成

而离线 Eval 中:

复制代码
回答
 ↓
Judge LLM
 ↓
得分:3 / 4
 ↓
记录到测试结果

Spring AI 官方现在甚至已经给出了基于 Recursive Advisor 构建 LLM-as-a-Judge 自我修正循环的示例,这说明"评价"本身既可以用于测试,也可以进入运行时优化循环。区别主要在评价结果是否继续驱动当前任务重新生成。

因此以后最好统一记成一句:

Evaluator 是"怎么评价";Eval 是"建立评价过程";Evaluator-Optimizer 是"评价以后根据反馈继续优化当前结果";回归测试是"把一组 Eval Case 在新版本上重新跑一遍"。

八、Agent 出错时,先判断错误发生在哪一层

到这里,一个 Agent 已经包含很多组件:

复制代码
用户
 ↓
Routing
 ↓
Memory / Context
 ↓
RAG
 ↓
LLM
 ↓
Workflow / Planning
 ↓
Tool
 ↓
外部系统
 ↓
Structured Output

因此用户最终看到一句错误回答时,原因可能完全不同。

例如:

复制代码
知识库根本没有退款规则
→ Knowledge 问题

知识库有规则,但 RAG 找错文档
→ Retrieval 问题

正确文档已经进入 Prompt,模型理解错误
→ Prompt / Model 问题

模型判断正确,但调用错 Tool
→ Tool Calling 问题

Tool 正确,但数据库数据错误
→ Business Data 问题

答案正确,但 JSON 格式错误
→ Output 问题

这就是后续模型效果优化最重要的前置认识:

大模型应用的最终效果来自多个组件共同作用,所以优化工作首先需要定位错误发生在哪个环节。

Spring AI 的 Observability 也围绕这种思想设计。当前框架能够记录 ChatClient、Advisor、ChatModel、Tool Calling、EmbeddingModel 和 VectorStore 等组件的 metrics(性能指标) 与 traces,为后续问题定位提供基础。

九、当前阶段的完整心智模型

现在可以把 Spring AI Agent 理解成三个层次:

复制代码
第一层:信息

Memory
RAG
Context
Business Data

        ↓

第二层:决策与编排

LLM
Routing
Planning
Workflow
Evaluator

        ↓

第三层:执行

Tool
MCP
Java Service
Database / API

外围还有一层工程保障:

复制代码
Structured Output
Validation
Observability
Eval
Error Handling

因此,成熟的 Agent 开发已经越来越接近普通软件工程:模型只是其中一个概率性组件Java 继续负责状态、权限、事务、流程和可靠执行,LLM 负责语言理解以及适合动态处理的决策

下一篇就可以正式回答一个更加实际的问题:

当大模型应用效果不好时,到底应该改 RAG、Prompt、Tool、Workflow,建立 Eval,还是进一步进行 SFT、LoRA、量化和蒸馏?

届时可以按照"知识缺失 → 检索错误 → 上下文利用错误 → 工具执行问题 → 偶发 Badcase → 稳定能力缺陷 → 成本与延迟"的顺序建立一套完整的模型效果优化判断路径。

相关推荐
YangYang9YangYan1 小时前
2026 校招市场数据分析 JD 拆解,SQL 要求、工具与面试考点
数据库·人工智能·数据分析
重生之小比特1 小时前
【Java SE】抽象类和接口
java·开发语言
传奇开心果编程1 小时前
【Rust入门知识点学与练】第33课:异步编程入门(async/await)强化
开发语言·学习·rust
myaifas1 小时前
智能体可视化设计用哪家好
人工智能·ai·ai编程
AI 编程助手GPT1 小时前
Python 备份 SQLite:为什么复制了 .db,恢复后还是少数据?
人工智能·python·ai·chatgpt
AiNightVision1 小时前
AI-ISP微光全彩夜视技术深度解析:如何在0.001Lux下实现全彩成像
人工智能·计算机视觉·车载系统·自动驾驶·无人机·智能家居·智能硬件
AI程序员1 小时前
多开几个 Agent,为什么反而更难把活干好?---- 从 Claude Code、Codex 到 DeepSeek Harness,拆解多 Agent 的收益、成本与运行机制。
人工智能
沐言人生1 小时前
1.3k星!开源「AI健康数据引擎」,把体检报告、智能穿戴设备和基因数据翻译成同一种语言
人工智能
明志数科1 小时前
机器人商业化验证中 真工业场景数据与训练场数据的差异分析
人工智能·机器学习