Java 开发者如何理解 AI Agent 架构
从传统服务端分层出发,拆解 Agent Runtime、模型、工具与状态管理的责任边界。
很多后端工程师第一次接触 Agent,会把它理解成“调用一次大模型,再把回答返回”。这能做出原型,却没有解释工具选择、状态管理、失败恢复和权限边界应该放在哪里。本文从熟悉的 Java 服务端视角,建立一张更实用的系统地图。
从请求响应到受控循环
普通 API 通常由代码决定下一步动作;Agent 则把一部分决策交给模型。模型可以提出工具调用,但执行工具、校验权限、记录结果仍应由应用控制。一个最小循环可以表示为:接收任务、构造上下文、请求模型、检查模型输出、执行获准的工具、把结果放回上下文,直到完成或达到预算。
while (!state.isTerminal() && state.steps() < maxSteps) {
AgentDecision decision = model.decide(state.toPrompt());
policy.validate(decision, state.actor());
state = executor.apply(decision, state);
}
这段伪代码刻意把 policy 与 executor 保持为应用侧组件。模型输出是待验证的数据,不是可信的程序指令。
主要模块与边界
| 模块 | 职责 | 需要明确的边界 |
|---|---|---|
| Agent Runtime | 推进任务状态、控制步数和超时 | 不直接持有所有业务权限 |
| Model Gateway | 模型适配、重试与用量记录 | 不把供应商协议泄漏到领域层 |
| Tool Registry | 描述可调用工具及输入输出 | 注册不代表任何用户都可调用 |
| Policy | 身份校验、参数校验、授权与审计 | 默认拒绝未知工具 |
| State Store | 保存运行状态和事件 | 区分敏感数据与可回放数据 |
落到 Spring 应用中,这些边界可以是独立服务或清晰的模块接口。早期不必拆微服务,先通过接口和依赖方向保证运行时不会绕过策略层。
工具调用需要像 API 一样治理
工具描述应包含稳定名称、版本、输入 Schema、执行超时和副作用说明。执行前进行身份与参数校验;执行后记录调用者、工具版本、脱敏后的参数摘要、耗时和结果状态。写入、付款、发送消息等操作还需要幂等键或人工确认步骤。
建议将模型产出的调用转换为内部命令,再交给既有业务服务:
Model ToolCall -> Schema Validation -> Authorization -> Domain Command -> Audit Event
这样 Agent 复用的是业务能力,而不是一套绕开业务规则的后门。
状态和故障处理
一次运行可能经历模型超时、工具限流、重复投递或用户中断。把每一步作为可追踪事件记录,可以恢复运行并解释结果。重试必须区分只读和有副作用的操作:读取通常可以安全重试,写入则需要幂等保护。为每次运行设定最大步数、总耗时和 token 预算,避免循环无限扩张。
实践起步顺序
- 先实现只有一个只读工具的同步流程。
- 为决策、工具请求、工具结果定义显式类型。
- 加入权限校验、超时、预算和审计事件。
- 用固定输入构造回归样例,记录工具选择是否符合预期。
- 再考虑异步任务、人工审批和多 Agent 协作。
这个顺序让系统先具备可控的故障边界,再逐步增加自主性。Agent 的“智能程度”不能替代传统服务的权限、可靠性与可观测性设计。