Jakarta Agentic AI 1.0.0-M1 实战:注解驱动 Agent 生命周期与 LLM Facade 生产落地

发布时间:2026/11/3 10:38:45
Jakarta Agentic AI 1.0.0-M1 实战:注解驱动 Agent 生命周期与 LLM Facade 生产落地 一、为什么 Java 团队该关注这个新标准过去两年Java 团队做 AI Agent 基本处于裸奔状态要么直接调 OpenAI/Anthropic 的 SDK要么用 Spring AI、LangChain4j 这类框架把 Agent 逻辑写成一大段过程式的编排代码。这带来两个真实痛点痛点一LLM API 高速漂移Agent 代码被锁定。OpenAI、Anthropic、Google 的 API 半年一个大版本把厂商私有端点硬编码进企业核心系统等于埋了一颗技术债定时炸弹。换一次模型供应商往往意味着一场持续数月的重构。痛点二Agent 代码写的人能看懂接手的人看不懂。脚本式的 Agent 编排while 循环 工具调用 手写状态管理在复杂业务场景下迅速腐化缺乏可预测的结构。2026 年 7 月 30 日Eclipse 基金会发布了Jakarta Agentic AI 1.0.0-M1Maven Central 坐标jakarta.agentic-ai:jakarta.agentic-ai-api:1.0.0-M1这是 Java 生态第一个厂商中立的 Agent 编程模型标准。官方的定位非常清晰做给 Agent 一份Jakarta Servlet 式的规范——就像 Jakarta Servlet 定义了 HTTP 处理、Jakarta Batch 定义了批处理一样它定义 Agent 的生命周期、编程模型和可插拔的 LLM 接入层。需要特别澄清一个常见误解它不是 Spring AI 或 LangChain4j 的竞品而是坐在它们上面的那一层。它不标准化 LLM API 本身那是快速变化的地带而是标准化Agent 的结构。底层的 LLM 调用依然可以由 Spring AI 或 LangChain4j 驱动规范通过一个极简的LargeLanguageModelFacade 把两者解耦。对大企业来说这意味着换模型供应商从多月重构变成配置更新。本文将从规范细节、源码级机制、完整项目实战到生产踩坑把这个 M1 版本讲透。先说清楚一个前提M1 是草案状态Draft参考实现RI和 TCK 还在路上所以本文的实战部分是面向规范编程 自建桥接实现的姿势——这也是未来 RI 落地后可以直接平移的写法。二、核心编程模型注解驱动的 Agent 生命周期2.1 六个注解构成的状态机规范定义的 Agent 就是一个 CDI Bean其工作流由注解标记的方法构成。每个注解有严格的基数Cardinality约束注解阶段基数职责Agent类级声明必须恰好 1 个类上声明 Agent 类默认作用域WorkflowScopedTrigger入口当前必须恰好 1 个由 CDI 事件触发启动工作流Decision决策零或多个决定工作流是否继续/如何分支Action执行零或多个执行业务步骤可自由与 Decision 交错Outcome终点零或一个收尾与副作用必须返回 voidHandleException异常零或多个工作流内的错误恢复规范里有一条容易忽视的硬规则一个方法不得同时声明两个及以上生命周期注解否则是部署错误deployment error——不是运行时才发现是应用起不来。2.2 参数解析五级解析顺序这是整个规范最有框架味的设计。所有生命周期方法的参数都不是手动传入的而是运行时按以下顺序基于类型自动解析触发事件参数类型与 CDI 事件 payload 匹配前一阶段结果参数类型匹配工作流中先前某步骤的返回值多个步骤返回同一类型时取最近一次的LargeLanguageModel参数类型是 LLM Facade 本身异常仅对HandleException抛出的异常或其父类型是必需的第一个参数CDI 注入其余参数当作 CDI Bean 解析。这意味着你在方法签名上就能看出这个阶段吃什么、依赖什么——这就是规范官网说的Structure instead of spaghetti。2.3 Decision 的三种返回模式与 Result 记录Decision支持三种返回类型语义各不相同public record Result(boolean success, Object details) {}返回类型true/非 nullfalse/nullBoolean工作流继续工作流终止Resultsuccesstrue继续details进入工作流状态successfalse终止领域对象非 null对象进入工作流状态继续null终止工作流Result.details是个精妙的设计它按运行时类型注册进工作流状态后续Action方法只要声明匹配的参数类型就能拿到——相当于决策阶段顺手给执行阶段捎话而不需要引入共享可变状态。2.4 WorkflowScoped为 Agent 而生的 CDI 作用域Agent 只能用两种作用域WorkflowScoped默认或ApplicationScoped。规范级的关键语义WorkflowScoped是一个NormalScope每个工作流执行创建一个新实例从 trigger 开始、工作流完成或失败后销毁。并发工作流各自持有独立实例运行时保证不会并发调用同一个实例——你写有状态的 Agent 逻辑也不用加锁。ApplicationScoped单例复用同一实例可能被多个工作流并发调用必须自己保证线程安全无状态或自行并发控制。2.5 线程与执行顺序单个工作流上下文内所有生命周期方法严格顺序执行trigger → decision → action → ... → outcome。WorkflowScopedAgent 的工作流通常跑在单线程上。LargeLanguageModel的会话状态绑定工作流上下文同一工作流内多次query()会基于先前交换构建上下文且实现必须保证按工作流隔离——即使 Agent 是ApplicationScoped的会话状态也绝不能跨并发工作流泄漏。这一条直接决定了后面踩坑清单里的第 3 条。2.6 工作流终止的四种方式与错误处理语义工作流终止条件正常完成outcome 完成、决策返回否定、未处理异常、异常处理器自身抛出异常。HandleException的语义要背下来按 Java 异常层次匹配最具体的处理器处理器正常返回 → 工作流继续下一步处理器重抛/抛新异常 → 工作流停止异常传播到容器处理器自身抛出的异常不会再递归分派给其他HandleException。注意正常返回 → 继续下一步这条它意味着如果你的Action执行了一半失败处理器只记了日志就 return后面的 Action 还会继续跑——这在有副作用的流程里可能是灾难后面踩坑清单细说。三、LargeLanguageModel Facade规范里唯一动 LLM 的地方3.1 接口设计全限定名jakarta.ai.agent.LargeLanguageModel是一个 CDI Bean两个query重载加一个unwrappublic interface LargeLanguageModel { // 原始字符串响应{} 占位符替换或单参数作为结构化上下文 String query(String prompt, Object... parameters); // 类型化响应JSON-B 反序列化为调用者指定类型 T T query(String prompt, ClassT type, Object... parameters); // 厂商特性逃生舱仿 EntityManager.unwrap() 模式 T T unwrap(ClassT type) throws IllegalArgumentException; }3.2 Prompt 构造规则5.4.1两条硬规则违反直接抛IllegalArgumentException必须用精确 token{}做位置替换不是{name}命名占位符prompt 含 N 个{}时位置参数必须恰好 N 个prompt 不含{}时至多 1 个参数作为结构化上下文经 JSON-B 序列化附加给 LLM。类型化响应的错误处理走LLMExceptionLLM 服务错误、或响应无法转换为请求类型时抛出。注意规范自己给的防御性写法——对枚举类字段模型返回的内容解析失败时要给出兜底值如Priority.MEDIUM而不是让异常裸奔。3.3 unwrap()拒绝最低公分母陷阱规范明确说为了避免把所有人锁死在最低公分母上Facade 提供unwrap()逃生舱。你可以先用 Facade 拿到基础结果再尝试 unwrap 到厂商 API 走高级特性unwrap 失败IllegalArgumentException就降级回基础路径——这是 Jakarta Persistence 十几年验证过的模式。四、代码实战RefundGuard 退款风控 Agent规范示例给的是欺诈检测我们做一个更贴近电商业务的退款风控审批 Agent订单退款请求进来 → LLM 风险评估 → 分级处置自动通过 / 人工审核 / 拒绝→ 审计落库。技术栈Jakarta EE 11 运行时 jakarta.agentic-ai-api:1.0.0-M1 LangChain4j桥接LargeLanguageModel。4.1 桥接实现让规范 API 跑在 LangChain4j 上M1 阶段还没有官方 RI生产姿势是自己写一个 Facade 实现未来 RI 出来后整体替换ApplicationScoped public class LangChain4jLlmBridge implements LargeLanguageModel { private final ChatModel delegate; // LangChain4j ChatModel private final ObjectMapper jsonb; // Jakarta JSON-B Inject public LangChain4jLlmBridge(LlmQualifier ChatModel delegate, Jsonb jsonb) { this.delegate delegate; this.jsonb jsonb; } Override public String query(String prompt, Object... parameters) { String filled PromptFiller.fill(prompt, parameters); // 严格 {} 占位符校验 try { return delegate.chat(filled).aiMessage().text(); } catch (RuntimeException e) { throw new LLMException(LLM service error, e); } } Override SuppressWarnings(unchecked) public T T query(String prompt, ClassT type, Object... parameters) { String filled PromptFiller.fill(prompt, parameters); String raw delegate.chat(filled).aiMessage().text(); try { return jsonb.fromJson(stripCodeFence(raw), type); } catch (Exception e) { // 响应无法转换为目标类型按规范抛 LLMException throw new LLMException(Response cannot be converted to type.getName(), e); } } Override public T T unwrap(ClassT type) { if (type.isInstance(delegate)) { return type.cast(delegate); } throw new IllegalArgumentException( Cannot unwrap to type.getName()); } }PromptFiller.fill的关键是严格实现规范的占位符契约统计{}出现次数与参数个数逐一比对不匹配就抛IllegalArgumentException——不要吞掉这个错误它是你 prompt 模板漂移的最早报警。4.2 Agent 主体Agent(description 电商退款风控审批 Agent) WorkflowScoped public class RefundGuardAgent { private static final Logger log Logger.getLogger(RefundGuardAgent.class.getName()); Inject private LargeLanguageModel llm; Inject private RefundOrderRepository refundRepo; // Jakarta Data Inject private AuditService auditService; Inject private EventRiskEscalated escalationEvent; // 升级人工审核的 CDI 事件 // 阶段 1入口参数校验前置 Trigger public void onRefundRequest(Valid NotNull RefundRequest request) { log.info(() - 收到退款申请: request.orderId()); } // 阶段 2LLM 风险评估Result 携带处置细节 Decision public Result assessRisk(RefundRequest request) { RiskAssessment assessment; try { assessment llm.query( 你是电商退款风控分析师。分析以下退款申请 订单金额: {} 元 用户注册天数: {} 该用户 30 天内退款次数: {} 商品类目: {} 按 JSON 返回: {riskLevel: LOW|MEDIUM|HIGH, confidence: 0.0-1.0, reason: ..., autoApprovable: true/false} , RiskAssessment.class, request.amount(), request.registeredDays(), request.refundCount30d(), request.category()); } catch (LLMException e) { // 模型不可用fail-safe 转人工而不是放行 log.warning(风控模型不可用转人工: request.orderId()); return new Result(true, Disposition.MANUAL_REVIEW); } return switch (assessment.riskLevel()) { case LOW when assessment.confidence() 0.8 assessment.autoApprovable() - new Result(true, Disposition.AUTO_APPROVE); case HIGH - new Result(true, Disposition.REJECT); default - new Result(true, Disposition.MANUAL_REVIEW); }; } // 阶段 3按处置类型分发类型化的参数解析自动路由 // 细节类型不同 → 参数解析只命中匹配的方法这是类型即路由 Action public void autoApprove(RefundRequest request, Disposition d) { // 仅当工作流状态中的 Disposition 为 AUTO_APPROVE 时本方法可见该分支... } Action public void rejectRefund(RefundRequest request) { /* ... */ } Action public void escalateToHuman(RefundRequest request) { /* ... */ } // 阶段 4审计收尾 Outcome Transactional public void finalize(RefundRequest request, Disposition disposition) { refundRepo.updateStatus(request.orderId(), disposition.toStatus()); auditService.record(refund-gaurd, request.orderId(), disposition.name()); } // 异常恢复数据库故障时转人工工作流继续 HandleException Transactional public void handlePersistenceFailure(PersistenceException e, RefundRequest request) { log.severe(退款状态更新失败转人工兜底: request.orderId()); escalationEvent.fire(new RiskEscalated(request.orderId(), e.getMessage())); } }4.3 生产级补强重试与幂等LLM 调用必须重试。规范没有内建重试语义靠 CDI 拦截器解决——这也是标准的价值所在Agent 逻辑保持干净横切能力交给 Jakarta EE 原生机制Interceptor LlmRetry(maxAttempts 3, backoffMs 500) public class LlmRetryInterceptor { AroundInvoke public Object retry(InvocationContext ctx) throws Exception { RuntimeException last null; for (int i 0; i 3; i) { try { return ctx.proceed(); } catch (LLMException e) { last e; Thread.sleep(500L * (i 1)); // 线性退避生产可换指数退避 } } throw last; } }配合虚拟线程JDK 25承载 CDI 事件通知线程LLM 的秒级延迟不再阻塞业务线程池——规范说工作流顺序执行但顺序执行不等于必须阻塞宝贵的平台线程。五、生产踩坑清单M1 阶段专属 规范语义陷阱{}占位符与参数个数不匹配 IllegalArgumentException。最常见的翻车点模板改了、调用点没改。把占位符校验放在桥接层并打清晰错误日志包含 prompt 模板哈希否则上线后只会看到一堆参数异常。领域对象返回 null 工作流静默终止。Decision返回领域对象时null的语义是终止不是NPE。写null return表达跳过时要清楚后面的Action一个都不会跑。需要跳过但继续的场景用Result(true, details)或布尔短路表达。ApplicationScopedAgent 的会话状态泄漏。规范要求实现保证 LLM 会话状态按工作流隔离但在 RI 缺位的今天你自己写的桥接层必须保证这一点会话状态绝不能放在单例字段里必须绑定工作流上下文可用 CDIAlterableContext扩展或 ThreadLocal 上下文清理。否则多租户场景下就是上下文串话事故。生命周期方法顺序执行LLM 长调用阻塞事件线程。Trigger由 CDI 事件触发事件在通知线程同步执行。LLM 调动辄数秒若在容器公共线程池上跑会拖垮整个应用的事件吞吐。方案触发侧fireAsync或按第 4.3 节把工作流调度到虚拟线程执行器上。WorkflowScopedAgent 里写通用Observes观察者方法不生效。规范明确WorkflowScopedAgent只能通过Trigger方法观察 CDI 事件通用观察者方法是ApplicationScoped的特权。写了不报错但静默无效——事件飞了Agent 没醒。一方法双注解 部署错误。Action Decision挂同一个方法应用直接起不来。重构时从老代码顺手把两个方法合并成一个方法时最容易踩。覆盖父类方法会静默丢失阶段注解。阶段注解不会隐式携带到未标注的覆盖方法上。子类 override 了父类的Action方法但忘了重新标注该阶段直接从工作流里消失——没有编译错误只有线上少执行一步。团队规范Agent 类原则上不继承组合优先。HandleException正常返回后工作流继续。持久化失败被处理器温和地吞掉后后续Action还会执行。有副作用的流程里处理器必须显式判断要么补偿到位后 return要么抛WorkflowFailureException让工作流停止。记个日志就 return在资金类流程里等于裸奔。校验失败发生在方法调用之前。ConstraintViolationException在参数注入之前抛出trigger 里的业务代码根本没机会执行。别在Trigger方法体内写参数合法性检查用 Jakarta Validation 注解声明用HandleException(ConstraintViolationException)统一兜底。M1 是草案API 可能变。1.0.0-M1 未经发布评审Observes显式声明、基数放宽、Outcome返回值等都在演进中。生产建议把规范 API 的 import 收敛到桥接层业务代码只依赖自建接口RI 出来后一次替换。六、总结标准化的本质是把选择权还给架构师回看 Jakarta Agentic AI 的设计你会发现它没有做任何炫技的事不碰模型 API、不定义工具协议、不做向量检索。它只做了一件事——给 Agent 一个可预测的结构并把模型层声明为可替换的 commodity。这正是 Java 工程师最熟悉的路数从 Servlet 到 CDI 到 BatchJava 生态二十年沉淀的核心方法论就是用稳定的规范抽象波动剧烈的实现。今天 LLM API 的漂移速度比当年 ORM 大战时期有过之而无不及而企业系统最需要的恰恰是把用哪个模型从架构决策降级为配置项。对 Java 程序员来说这再次验证了那句话做 AI 不需要转 Python你的工程化能力——接口抽象、依赖注入、事务边界、错误恢复、可观测性——才是 Agent 真正进入生产系统的护城河。M1 时代就开始按规范写 Agent等 RI 和 TCK 落地你就是第一批无缝切换的人。参考资料Jakarta Agentic AI Specification v1.0 Draftjakarta.ee/specifications/agentic-ai/1.0、Eclipse 基金会项目页jakartaee.github.io/agentic-ai、Foojay.io / InfoQ 相关报道2026-07~08。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询