Appearance
框架选型边界:什么时候用 Spring AI,什么时候上 AgentScope
1. 本节产出
一张清晰的选型边界表:什么场景用 Spring AI 自带的编排就够,什么场景需要 AgentScope 或自研编排;以及一个**「先轻后重」的演进路径**,避免一开始就上重型框架。
2. 前置依赖
- 03-01 ReAct 范式:已手写过 ReAct 循环
3. 为什么选型会出问题
两种典型失败:
失败一:一上来就上重型框架。 团队用 AgentScope 做了一个只需要「查天气 + 查订单」的单 Agent,结果:
- 学习成本:团队两周才搞清楚消息机制;
- 调试困难:出问题时不知道是框架行为还是自己代码;
- 部署复杂:多了一套运行时依赖。
而这两件事用手写循环 60 行就能做完。
失败二:什么都自己写。 另一个团队拒绝任何框架,自己实现了消息总线、状态机、工具注册。半年后发现:
- 代码 8000 行,只有最初写的人能改;
- 缺少的功能(并发、重试、追踪)不断补,越补越乱;
- 换模型厂商要改三处。
判断标准:框架的价值不在「让你能写 Agent」,而在「替你处理你不擅长的基础设施」。
4. 核心原理
4.1 能力对照
| 能力 | Spring AI 2.0 | AgentScope Java | 自研 |
|---|---|---|---|
| 模型调用与多厂商 | ✅ 原生 | ✅ | 自己适配 |
| Tool 注册与调用 | ✅ @Tool | ✅ Toolkit | 自己写 |
| ReAct 单 Agent | ⚠️ 需自己写循环 | ✅ 原生 | 60 行 |
| Advisor / 拦截器链 | ✅ 成熟 | ⚠️ 较弱 | 自己写 |
| 多 Agent 协作(Supervisor/Handoff) | ❌ 无 | ✅ 原生 | 大量工作 |
| 分布式 Agent / 跨进程 | ❌ | ✅ 设计目标 | 不现实 |
| 状态持久化 | ⚠️ 自己做 | ✅ 有抽象 | 自己写 |
| 与 Spring 生态集成 | ✅ 天然 | ⚠️ 需桥接 | — |
| 学习曲线 | 低 | 中高 | — |
| 版本稳定性 | 中(迭代快) | 低(演进中) | — |
4.2 决策规则
需求判断:
Q1:是否需要多个 Agent 协作(分工、辩论、流水线)?
是 → 考虑 AgentScope
否 → 继续
Q2:是否需要 Agent 跨进程 / 分布式运行?
是 → AgentScope
否 → 继续
Q3:是否需要复杂的消息机制(多轮对话、中断恢复、消息持久化)?
是 → 考虑 AgentScope
否 → Spring AI + 自研循环(推荐)默认答案是「Spring AI + 自研循环」。因为:
| 理由 | 说明 |
|---|---|
| 单 Agent 场景占绝大多数 | 企业里 80% 的需求是单 Agent + 几个工具 |
| 可靠性才是难点 | 无论用哪个框架,超时/熔断/审计都要自己写 |
| 与 Spring 生态一致 | 依赖注入、配置、监控、事务全部复用现有能力 |
| 依赖更少 | Spring AI 是 Spring 官方项目,稳定性更有保障 |
4.3 推荐的演进路径
阶段一(0-3 个月):Spring AI + 手写 ReAct 循环
└─ 验证业务价值,跑通 1-2 个场景
阶段二(3-6 个月):抽取自研 Harness
└─ 把超时/熔断/审计/状态沉淀成可复用组件(03B)
阶段三(6 个月+):按需引入 AgentScope
└─ 只在真正需要多 Agent 协作的模块引入,与 Spring AI 共存阶段二的自研 Harness 是本课程的核心交付(03B-13)。它的定位是:框架不管的可靠性,我来管。
4.4 混合架构:两者共存
┌─────────────────────────────────────────┐
│ Web 层 / API 网关(Spring Boot) │
├─────────────────────────────────────────┤
│ 编排层 │
│ ├─ 单 Agent:Spring AI + 自研 Harness │
│ └─ 复杂子图:AgentScope Bridge │
├─────────────────────────────────────────┤
│ 共享基础设施 │
│ 审计 / 配额 / 追踪 / 工具权限(Spring) │
└─────────────────────────────────────────┘关键:无论用哪个引擎,共享同一套基础设施(审计、权限、配额)。这样切换引擎不会丢失治理能力。
5. 代码走查
5.1 统一抽象:让两者可切换
java
// src/main/java/com/example/harness/agent/AgentRunner.java
public interface AgentRunner {
/** 统一的运行入口:输入目标,输出结果与轨迹 */
AgentResult run(AgentRequest request);
}
public record AgentRequest(String runId, String goal, String tenantId,
String userId, List<String> allowedTools,
Duration timeout) {}
public record AgentResult(String answer, List<Step> trace,
int iterations, int totalTokens, Status status) {
public enum Status { DONE, MAX_ITERATIONS, TIMEOUT, NEED_APPROVAL, FAILED }
}定义自己的 AgentRunner 接口是关键一步。这样:
- 初期用一个
SpringAiAgentRunner实现; - 需要时再加一个
AgentScopeRunner; - 上层编排代码完全不动。
5.2 Spring AI 实现
java
// src/main/java/com/example/harness/agent/SpringAiAgentRunner.java
@Component
@ConditionalOnProperty(name = "agent.engine", havingValue = "spring-ai", matchIfMissing = true)
public class SpringAiAgentRunner implements AgentRunner {
private final ReactLoop loop;
private final AuditLogger audit;
@Override
public AgentResult run(AgentRequest req) {
audit.logStart(req);
try {
String answer = loop.run(req.goal(), req.allowedTools());
return AgentResult.done(answer, loop.lastTrace());
} finally {
audit.logEnd(req);
}
}
}5.3 AgentScope 桥接(示意)
java
// src/main/java/com/example/harness/agent/AgentScopeRunner.java
@Component
@ConditionalOnProperty(name = "agent.engine", havingValue = "agentscope")
public class AgentScopeRunner implements AgentRunner {
@Override
public AgentResult run(AgentRequest req) {
// 把 AgentRequest 映射到 AgentScope 的消息与 Agent 配置
// 运行子图,把结果映射回 AgentResult
// 注意:审计/权限仍在 Harness 层,不依赖 AgentScope
...
}
}5.4 通过配置切换
yaml
agent:
engine: spring-ai # 或 agentscope
max-iterations: 10
timeout: 60s6. 跑起来
bash
git checkout ch03-02-framework-choice
mvn -q test -Dtest=AgentRunnerSwitchTestbash
# 1. 用默认引擎跑
curl -X POST http://localhost:8080/api/agent/run \
-d '{"goal":"查一下北京今天天气,适合户外运动吗"}'
# 期望:返回结果 + trace,engine=spring-ai
# 2. 切换引擎(若已配置 AgentScope)
# 改 application.yml: agent.engine=agentscope,重启
# 期望:同样的请求返回同样的结构(trace 格式一致)| 检查项 | 通过标准 |
|---|---|
| 接口统一 | 两个引擎返回同一个 AgentResult 结构 |
| 切换不改业务 | 上层编排代码零改动 |
| 审计不丢 | 切换引擎后审计日志仍然完整 |
| 默认可用 | 不配 AgentScope 时系统正常工作 |
7. 生产避坑
- 不要为了「以后可能需要多 Agent」而提前上重型框架。先用手写循环验证业务价值,等真的需要协作模式时再引入。提前引入的成本是确定的,收益是不确定的。
- 定义自己的
AgentRunner抽象,不要直接在业务代码里用框架类型。这是唯一能让你后期切换引擎而不改业务的做法。成本极低(一个接口),收益很大。 - 无论用哪个引擎,审计与权限必须放在自己的 Harness 层。依赖框架提供的审计能力,意味着换框架时治理能力跟着丢——而治理能力恰恰是你最不能丢的东西。
8. 延伸与锚点
- 思考题:工具越来越多(20+),模型选不准工具了,怎么办?(答案在下一课时:工具设计)
- 代码锚点:
git checkout ch03-02-framework-choice - 下一课时:03-03 工具设计与参数 Schema
- 对应课件:L03-02 框架选型