<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AI Agent on 吾爱主机</title><link>https://blog.waihost.com/tags/ai-agent/</link><description>Recent content in AI Agent on 吾爱主机</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Thu, 23 Jul 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://blog.waihost.com/tags/ai-agent/index.xml" rel="self" type="application/rss+xml"/><item><title>AgentScope Java 2.0 实战：构建带权限审批与可恢复执行的生产级 Agent</title><link>https://blog.waihost.com/posts/agentscope-java-production-agent/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0800</pubDate><guid>https://blog.waihost.com/posts/agentscope-java-production-agent/</guid><description>&lt;img src="https://blog.waihost.com/images/covers/agentscope-java-production-agent.svg" alt="Featured image of post AgentScope Java 2.0 实战：构建带权限审批与可恢复执行的生产级 Agent" /&gt;&lt;p&gt;能调用 Shell、修改文件和派发子任务的 Agent，比普通聊天机器人更有价值，也更危险。Prompt 中一句“执行危险操作前请确认”不是安全边界：模型可能误判上下文、被工具输出诱导，或者在重试中重复执行副作用。&lt;/p&gt;
&lt;p&gt;AgentScope Java 2.0 把这类生产问题放进框架核心：每次工具调用都经过权限系统，结果是 &lt;code&gt;ALLOW&lt;/code&gt;、&lt;code&gt;DENY&lt;/code&gt; 或 &lt;code&gt;ASK&lt;/code&gt;；&lt;code&gt;ASK&lt;/code&gt; 会暂停 Agent，等待用户确认后再恢复。同时，Harness、Workspace、Sandbox 和分布式状态后端用来承载长时间任务。&lt;/p&gt;
&lt;p&gt;本文基于 AgentScope Java &lt;code&gt;2.0.0 GA&lt;/code&gt; 和 JDK 17，先搭建一个 HarnessAgent，再实现“读操作自动放行、写操作必须审批、生产资源不可绕过”的权限策略，最后说明 session 恢复与沙箱的边界。&lt;/p&gt;
&lt;h2 id="一reactagent-与-harnessagent-的分工"&gt;&lt;a href="#%e4%b8%80reactagent-%e4%b8%8e-harnessagent-%e7%9a%84%e5%88%86%e5%b7%a5" class="header-anchor"&gt;&lt;/a&gt;一、ReActAgent 与 HarnessAgent 的分工
&lt;/h2&gt;&lt;p&gt;AgentScope Java 2.0 提供两层抽象：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;抽象&lt;/th&gt;
					&lt;th&gt;适合场景&lt;/th&gt;
					&lt;th&gt;核心关注点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReActAgent&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;轻量聊天、受限 Tool Calling&lt;/td&gt;
					&lt;td&gt;推理—行动循环、模型、工具&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HarnessAgent&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;长任务、文件/代码 Agent、企业部署&lt;/td&gt;
					&lt;td&gt;Workspace、Memory、Skills、Subagent、Sandbox、恢复&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果只需调用一个天气 API，&lt;code&gt;ReActAgent&lt;/code&gt; 已经足够。若 Agent 要在目录里读写文件、执行命令、跨会话继续任务，应该从 Harness 开始，因为这些能力需要共享一致的运行上下文。&lt;/p&gt;
&lt;p&gt;官方 2.0 的设计还强调 Agent 本身无状态：运行状态通过 &lt;code&gt;(userId, sessionId)&lt;/code&gt; 和后端管理。这比把可变消息列表放进单例 Agent 更适合多实例部署。&lt;/p&gt;
&lt;h2 id="二依赖和模型配置"&gt;&lt;a href="#%e4%ba%8c%e4%be%9d%e8%b5%96%e5%92%8c%e6%a8%a1%e5%9e%8b%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;二、依赖和模型配置
&lt;/h2&gt;&lt;p&gt;AgentScope Java 2.0 要求 JDK 17+。Harness 与模型提供商从 2.0 起拆分为独立模块：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;maven.compiler.release&amp;gt;&lt;/span&gt;17&lt;span class="nt"&gt;&amp;lt;/maven.compiler.release&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;agentscope.version&amp;gt;&lt;/span&gt;2.0.0&lt;span class="nt"&gt;&amp;lt;/agentscope.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.agentscope&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;agentscope-harness&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${agentscope.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.agentscope&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;agentscope-extensions-model-dashscope&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${agentscope.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其他官方可选模型模块包括 OpenAI、Anthropic、Gemini 和 Ollama。使用 DashScope 时，把密钥放进环境变量而不是源码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;DASHSCOPE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;你的密钥&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后创建最小 HarnessAgent：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.agent.RuntimeContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.message.UserMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.harness.agent.HarnessAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.nio.file.Paths&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpsAgentApp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HarnessAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HarnessAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ops_assistant&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sysPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 你是运维分析助手。先读后写，输出每一步依据；
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 未获得权限系统批准时，不得声称已经修改任何资源。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;dashscope:qwen-plus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;.agentscope/workspace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RuntimeContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RuntimeContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;incident-20260724-001&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;检查工作区里的故障日志并给出处理建议&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTextContent&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;模型字符串由 ModelRegistry 解析。&lt;code&gt;workspace&lt;/code&gt; 不是随便给 Agent 一个宿主机根目录，而应该是专门分配、权限收敛的工作目录。&lt;/p&gt;
&lt;h2 id="三权限系统如何做决策"&gt;&lt;a href="#%e4%b8%89%e6%9d%83%e9%99%90%e7%b3%bb%e7%bb%9f%e5%a6%82%e4%bd%95%e5%81%9a%e5%86%b3%e7%ad%96" class="header-anchor"&gt;&lt;/a&gt;三、权限系统如何做决策
&lt;/h2&gt;&lt;p&gt;权限系统位于 &lt;code&gt;io.agentscope.core.permission&lt;/code&gt;，拦截每次工具调用。它综合三类信息：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Rules&lt;/strong&gt;：针对工具和调用模式的显式 ALLOW、ASK、DENY；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode&lt;/strong&gt;：未命中规则时的默认策略；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in Checks&lt;/strong&gt;：工具根据真实入参执行的不可绕过检查。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;决策顺序中，DENY 规则和危险路径检查优先。即使启用 &lt;code&gt;BYPASS&lt;/code&gt;，这类保护仍然生效。&lt;/p&gt;
&lt;p&gt;官方提供五种常用模式：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模式&lt;/th&gt;
					&lt;th&gt;未命中规则时的行为&lt;/th&gt;
					&lt;th&gt;适用情况&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DEFAULT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;要求显式规则或用户确认&lt;/td&gt;
					&lt;td&gt;推荐默认值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ACCEPT_EDITS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;放行工作目录内安全文件操作&lt;/td&gt;
					&lt;td&gt;用户在场的开发任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;EXPLORE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;只读，拒绝写与命令&lt;/td&gt;
					&lt;td&gt;代码探索、规划&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;BYPASS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;通常放行，但不可绕过的检查仍有效&lt;/td&gt;
					&lt;td&gt;完全可信且隔离的 Sandbox&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DONT_ASK&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;将 ASK 变为 DENY&lt;/td&gt;
					&lt;td&gt;无人值守任务&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;DONT_ASK&lt;/code&gt; 尤其重要：定时任务没有用户在线，不能让 Agent 永久等待审批，也不应默认放行。&lt;/p&gt;
&lt;h2 id="四配置-allowask-与-deny-规则"&gt;&lt;a href="#%e5%9b%9b%e9%85%8d%e7%bd%ae-allowask-%e4%b8%8e-deny-%e8%a7%84%e5%88%99" class="header-anchor"&gt;&lt;/a&gt;四、配置 ALLOW、ASK 与 DENY 规则
&lt;/h2&gt;&lt;p&gt;下面的策略允许安全读取，删除操作必须询问，删表始终拒绝：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.permission.PermissionBehavior&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.permission.PermissionContextState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.permission.PermissionMode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.permission.PermissionRule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PermissionContextState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionContextState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PermissionMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAllowRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;safe_read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;safe_read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;projectSettings&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAskRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;dangerous_delete&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;dangerous_delete&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ASK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;projectSettings&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addDenyRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;drop_table&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;drop_table&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PermissionBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DENY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;projectSettings&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以把权限上下文交给底层 &lt;code&gt;ReActAgent&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ReActAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReActAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;controlled_agent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sysPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;先检查，再操作&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;permissionContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;若使用 Harness，应在构建 Harness 的 delegate/permission 配置位置应用同一上下文；具体 Builder 入口以 2.0.0 文档和当前模块为准，不要从 RC 版博客复制包名。&lt;/p&gt;
&lt;p&gt;规则来源 &lt;code&gt;projectSettings&lt;/code&gt;、&lt;code&gt;userSettings&lt;/code&gt;、&lt;code&gt;session&lt;/code&gt; 或 &lt;code&gt;suggested&lt;/code&gt; 应进入审计日志。由用户在一次 ASK 中接受的 suggested rule，可能影响后续相同调用，UI 必须明确告诉用户这是“一次允许”还是“以后允许”。&lt;/p&gt;
&lt;h2 id="五自定义不可绕过的工具检查"&gt;&lt;a href="#%e4%ba%94%e8%87%aa%e5%ae%9a%e4%b9%89%e4%b8%8d%e5%8f%af%e7%bb%95%e8%bf%87%e7%9a%84%e5%b7%a5%e5%85%b7%e6%a3%80%e6%9f%a5" class="header-anchor"&gt;&lt;/a&gt;五、自定义不可绕过的工具检查
&lt;/h2&gt;&lt;p&gt;静态规则不一定能识别业务语义。比如同一个 &lt;code&gt;restart_service&lt;/code&gt; 工具，测试环境可以自动执行，生产环境必须审批。自定义 Tool 可覆盖 &lt;code&gt;checkPermissions&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.permission.PermissionDecision&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.tool.ToolBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;io.agentscope.core.tool.ToolExecutionContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;reactor.core.publisher.Mono&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestartServiceTool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ToolBase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;RestartServiceTool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ToolBase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;restart_service&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;重启指定环境中的服务&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PermissionDecision&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;checkPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ToolExecutionContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;environment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;prod&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mono&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PermissionDecision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;目标是生产环境，需要人工批准：&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mono&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PermissionDecision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;passthrough&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;非生产环境，继续按 rules/mode 判断&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;PASSTHROUGH&lt;/code&gt; 不是 ALLOW，它表示把决定权交回规则和模式。对明确禁止的目标可直接返回 &lt;code&gt;deny(...)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;框架还内置危险路径保护，例如 &lt;code&gt;.ssh/&lt;/code&gt;、&lt;code&gt;.git/&lt;/code&gt;、&lt;code&gt;.aws/&lt;/code&gt;、&lt;code&gt;.kube/&lt;/code&gt;、&lt;code&gt;.env&lt;/code&gt; 和凭据文件。命中危险路径时会强制 ASK；自定义 Tool 也可以增加危险文件和目录。&lt;/p&gt;
&lt;h2 id="六ask-后怎样暂停与恢复"&gt;&lt;a href="#%e5%85%adask-%e5%90%8e%e6%80%8e%e6%a0%b7%e6%9a%82%e5%81%9c%e4%b8%8e%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;六、ASK 后怎样暂停与恢复
&lt;/h2&gt;&lt;p&gt;权限结果为 ASK 时，Agent 不执行工具，而是以 &lt;code&gt;GenerateReason.PERMISSION_ASKING&lt;/code&gt; 暂停。返回消息中包含状态为 &lt;code&gt;ASKING&lt;/code&gt; 的 &lt;code&gt;ToolUseBlock&lt;/code&gt;，调用方应：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把工具名和脱敏后的参数展示给用户；&lt;/li&gt;
&lt;li&gt;让用户选择拒绝、仅本次允许或接受建议规则；&lt;/li&gt;
&lt;li&gt;构造 &lt;code&gt;ConfirmResult&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;使用相同 &lt;code&gt;(userId, sessionId)&lt;/code&gt; 恢复 Agent。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;核心确认对象如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ConfirmResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ConfirmResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// confirmed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 本次待确认调用&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSuggestedRules&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 仅在用户明确接受时传入&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生产 UI 不应只放一个模糊的“确认”按钮。至少显示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工具名称与风险级别；&lt;/li&gt;
&lt;li&gt;目标环境、资源 ID、路径；&lt;/li&gt;
&lt;li&gt;是否产生副作用；&lt;/li&gt;
&lt;li&gt;建议规则会影响一次还是后续调用；&lt;/li&gt;
&lt;li&gt;session、用户和过期时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;确认结果必须由服务端绑定当前用户和待审批记录，不能接受客户端随意提交另一个 &lt;code&gt;toolCall&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="七流式事件让执行过程可观察"&gt;&lt;a href="#%e4%b8%83%e6%b5%81%e5%bc%8f%e4%ba%8b%e4%bb%b6%e8%ae%a9%e6%89%a7%e8%a1%8c%e8%bf%87%e7%a8%8b%e5%8f%af%e8%a7%82%e5%af%9f" class="header-anchor"&gt;&lt;/a&gt;七、流式事件让执行过程可观察
&lt;/h2&gt;&lt;p&gt;Harness 可以输出统一事件流：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;streamEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;分析日志；如果需要修改配置先请求批准&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doOnNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getType&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TEXT_BLOCK_DELTA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;TextBlockDeltaEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getDelta&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOOL_CALL_START&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;[tool] &amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ToolCallStartEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getToolCallName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blockLast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;事件流可驱动 Web UI、飞书/钉钉 Channel 或审计平台。注意不要把所有原始参数直接写日志；命令、Prompt 和工具结果可能包含 Token、路径或客户数据。&lt;/p&gt;
&lt;h2 id="八workspacesandbox-和权限各管一层"&gt;&lt;a href="#%e5%85%abworkspacesandbox-%e5%92%8c%e6%9d%83%e9%99%90%e5%90%84%e7%ae%a1%e4%b8%80%e5%b1%82" class="header-anchor"&gt;&lt;/a&gt;八、Workspace、Sandbox 和权限各管一层
&lt;/h2&gt;&lt;p&gt;三者不能互相替代：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workspace&lt;/strong&gt; 组织文件、Memory、Skills 和子 Agent 工作上下文；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permission&lt;/strong&gt; 决定某次工具调用是否允许、拒绝或询问；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sandbox&lt;/strong&gt; 限制已经获准的代码实际能访问哪些系统资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即使权限系统批准 &lt;code&gt;rm temp.txt&lt;/code&gt;，Sandbox 仍应阻止进程读取宿主机 SSH 密钥。反过来，Docker 隔离也不能代替业务审批：容器里的工具可能仍持有生产 API 凭据。&lt;/p&gt;
&lt;p&gt;可按风险逐级部署：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;开发：专用本地目录 + DEFAULT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;测试：Docker Sandbox + ACCEPT_EDITS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;生产交互：Kubernetes Sandbox + DEFAULT + HITL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;生产无人值守：最小工具集 + DONT_ASK + 服务端白名单
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个 Sandbox 还应配置 CPU、内存、进程数、超时、只读根文件系统和网络出口策略。&lt;/p&gt;
&lt;h2 id="九可恢复执行的正确边界"&gt;&lt;a href="#%e4%b9%9d%e5%8f%af%e6%81%a2%e5%a4%8d%e6%89%a7%e8%a1%8c%e7%9a%84%e6%ad%a3%e7%a1%ae%e8%be%b9%e7%95%8c" class="header-anchor"&gt;&lt;/a&gt;九、可恢复执行的正确边界
&lt;/h2&gt;&lt;p&gt;AgentScope Java 2.0 支持 Redis、MySQL、PostgreSQL、OSS/COS 等分布式 session 和 memory 后端，并面向跨副本 session 恢复。但“恢复 Agent 状态”仍不等于“业务操作恰好一次”。&lt;/p&gt;
&lt;p&gt;经典故障窗口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;工具成功重启服务
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 进程在保存工具结果前崩溃
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 恢复后模型再次请求重启
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解决方案在工具层：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;OperationRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;operationId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;operationId&lt;/code&gt; 由可信服务端生成；&lt;/li&gt;
&lt;li&gt;业务库对它建立唯一约束；&lt;/li&gt;
&lt;li&gt;重复请求返回第一次结果，而不是再次执行；&lt;/li&gt;
&lt;li&gt;checkpoint 记录 operationId 与状态；&lt;/li&gt;
&lt;li&gt;外部系统也尽可能使用幂等键。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;userId + sessionId&lt;/code&gt; 用于隔离会话，&lt;code&gt;operationId&lt;/code&gt; 用于隔离副作用，二者不要混为一谈。&lt;/p&gt;
&lt;h2 id="十生产部署清单"&gt;&lt;a href="#%e5%8d%81%e7%94%9f%e4%ba%a7%e9%83%a8%e7%bd%b2%e6%b8%85%e5%8d%95" class="header-anchor"&gt;&lt;/a&gt;十、生产部署清单
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 默认使用 &lt;code&gt;DEFAULT&lt;/code&gt; 或 &lt;code&gt;EXPLORE&lt;/code&gt;，不把 &lt;code&gt;BYPASS&lt;/code&gt; 当省事开关；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 无人值守任务使用 &lt;code&gt;DONT_ASK&lt;/code&gt;，未明确允许的调用直接拒绝；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 生产、凭据和危险路径在 Tool 内做不可绕过检查；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; ASK 绑定用户、session、调用参数摘要和过期时间；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Suggested Rule 的持久化范围对用户透明；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Sandbox 有资源限制、网络出口策略和短期凭据；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 所有写工具都有幂等键与审计记录；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 使用共享状态后端，并测试滚动发布和跨副本恢复；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 对每种工具做 ALLOW、ASK、DENY 和恢复故障测试；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 日志和事件流经过脱敏。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="十一常见问题"&gt;&lt;a href="#%e5%8d%81%e4%b8%80%e5%b8%b8%e8%a7%81%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;十一、常见问题
&lt;/h2&gt;&lt;h3 id="agent-一直要求确认"&gt;&lt;a href="#agent-%e4%b8%80%e7%9b%b4%e8%a6%81%e6%b1%82%e7%a1%ae%e8%ae%a4" class="header-anchor"&gt;&lt;/a&gt;Agent 一直要求确认
&lt;/h3&gt;&lt;p&gt;检查规则的 &lt;code&gt;toolName&lt;/code&gt; 和 &lt;code&gt;ruleContent&lt;/code&gt; 是否真的匹配调用；若默认 &lt;code&gt;DEFAULT&lt;/code&gt; 且没有 ALLOW 规则，询问是预期行为。不要直接切到 &lt;code&gt;BYPASS&lt;/code&gt;，先补齐最小权限规则。&lt;/p&gt;
&lt;h3 id="定时任务卡在-ask"&gt;&lt;a href="#%e5%ae%9a%e6%97%b6%e4%bb%bb%e5%8a%a1%e5%8d%a1%e5%9c%a8-ask" class="header-anchor"&gt;&lt;/a&gt;定时任务卡在 ASK
&lt;/h3&gt;&lt;p&gt;无人值守场景改用 &lt;code&gt;DONT_ASK&lt;/code&gt;，并显式允许安全工具。ASK 会转成 DENY，从而让任务失败得可观察，而不是永久等待不存在的用户。&lt;/p&gt;
&lt;h3 id="工作区恢复后找不到文件"&gt;&lt;a href="#%e5%b7%a5%e4%bd%9c%e5%8c%ba%e6%81%a2%e5%a4%8d%e5%90%8e%e6%89%be%e4%b8%8d%e5%88%b0%e6%96%87%e4%bb%b6" class="header-anchor"&gt;&lt;/a&gt;工作区恢复后找不到文件
&lt;/h3&gt;&lt;p&gt;本地 Workspace 不适合多副本。使用共享存储或远程文件系统，并保证所有副本使用一致的路径映射、租户隔离和版本策略。&lt;/p&gt;
&lt;h3 id="已有-sandbox为什么还要权限系统"&gt;&lt;a href="#%e5%b7%b2%e6%9c%89-sandbox%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%98%e8%a6%81%e6%9d%83%e9%99%90%e7%b3%bb%e7%bb%9f" class="header-anchor"&gt;&lt;/a&gt;已有 Sandbox，为什么还要权限系统
&lt;/h3&gt;&lt;p&gt;Sandbox 限制“能破坏多大范围”，权限系统限制“此刻是否应该执行”。前者是隔离，后者是意图授权，必须叠加。&lt;/p&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;AgentScope Java 2.0 的核心价值不是又实现了一次 ReAct，而是把 Agent 当成一个需要治理的长期运行系统：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;权限系统在每次工具调用前作出 ALLOW、ASK 或 DENY；&lt;/li&gt;
&lt;li&gt;Tool 的 Built-in Check 能根据真实参数建立不可绕过的业务安全线；&lt;/li&gt;
&lt;li&gt;HITL 用同一 session 暂停和恢复，而不是只在 Prompt 里“请求确认”；&lt;/li&gt;
&lt;li&gt;Workspace 管上下文，Sandbox 管隔离，分布式后端管恢复；&lt;/li&gt;
&lt;li&gt;幂等和业务事实仍由工具与数据库负责。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你的 Agent 会改文件、执行命令或触碰生产资源，先设计权限、审批、隔离和恢复，再讨论模型是否更聪明。生产 Agent 最重要的能力，不是永远做对，而是做错时被阻止、失败后可恢复、重试时不重复造成损失。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;&lt;a href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" class="header-anchor"&gt;&lt;/a&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/agentscope-ai/agentscope-java" target="_blank" rel="noopener"
 &gt;AgentScope Java GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java.agentscope.io/v2/zh/intro.html" target="_blank" rel="noopener"
 &gt;AgentScope Java 2.0 中文文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java.agentscope.io/v2/zh/docs/building-blocks/permission-system.html" target="_blank" rel="noopener"
 &gt;Permission System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java.agentscope.io/v2/zh/docs/harness/workspace.html" target="_blank" rel="noopener"
 &gt;Workspace 与 Sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java.agentscope.io/v2/zh/docs/others/going-to-production.html" target="_blank" rel="noopener"
 &gt;生产部署&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/agentscope-ai/agentscope-java/releases/tag/v2.0.0" target="_blank" rel="noopener"
 &gt;AgentScope Java 2.0.0 Release&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Google ADK Java 实战：用 Code-first 方式编排多 Agent 工作流</title><link>https://blog.waihost.com/posts/google-adk-java-multi-agent/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0800</pubDate><guid>https://blog.waihost.com/posts/google-adk-java-multi-agent/</guid><description>&lt;img src="https://blog.waihost.com/images/covers/google-adk-java-multi-agent.svg" alt="Featured image of post Google ADK Java 实战：用 Code-first 方式编排多 Agent 工作流" /&gt;&lt;p&gt;Google Agent Development Kit（ADK）Java 是一个代码优先的 Agent 工具包：Agent 的角色、工具和编排直接写在 Java 中，可以进入版本控制、单元测试和部署流程。它不是只能调用 Gemini 的聊天 SDK，而是提供 &lt;code&gt;LlmAgent&lt;/code&gt;、Sequential/Parallel/Loop Agent、Session/State、Dev UI 和 A2A 集成。&lt;/p&gt;
&lt;p&gt;本文基于 Google ADK Java &lt;code&gt;1.7.0&lt;/code&gt;，实现一个“研究—审查—成稿”的顺序多 Agent 工作流，并说明工具、Session State、Dev UI 以及 A2A 与 MCP 的分工。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;截至 2026-07-23，官方 README 仍将 ADK Java 标记为 &lt;strong&gt;Preview / Pre-GA&lt;/strong&gt;，并说明相关能力按 “as is” 提供、支持可能有限。它适合学习、PoC 和可控试点；关键生产系统上线前必须锁版本、做回归测试并准备替代路径。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一adk-的-code-first-是什么"&gt;&lt;a href="#%e4%b8%80adk-%e7%9a%84-code-first-%e6%98%af%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;一、ADK 的 Code-first 是什么
&lt;/h2&gt;&lt;p&gt;代码优先不只是“不写 YAML”，而是把 Agent 系统的重要结构放进类型化代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BaseAgent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── LlmAgent 模型驱动，能调用工具或委派
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── SequentialAgent 按顺序执行子 Agent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── ParallelAgent 并行执行独立子 Agent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── LoopAgent 在条件下重复执行
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;LLM 适合处理语义判断和非结构化内容；Sequential/Parallel/Loop 则提供确定性控制。一个可靠系统往往混用二者，而不是让一个大模型临场规划全部步骤。&lt;/p&gt;
&lt;p&gt;本文流程是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户主题
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; researcher：形成事实清单，写入 research_notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; reviewer：检查证据与风险，写入 review_notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; writer：读取前两步结果，形成文章提纲
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;三个专业 Agent 可以使用不同 Prompt，输出通过 Session State 传递。&lt;/p&gt;
&lt;h2 id="二依赖凭据与版本状态"&gt;&lt;a href="#%e4%ba%8c%e4%be%9d%e8%b5%96%e5%87%ad%e6%8d%ae%e4%b8%8e%e7%89%88%e6%9c%ac%e7%8a%b6%e6%80%81" class="header-anchor"&gt;&lt;/a&gt;二、依赖、凭据与版本状态
&lt;/h2&gt;&lt;p&gt;Maven 依赖：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;maven.compiler.release&amp;gt;&lt;/span&gt;17&lt;span class="nt"&gt;&amp;lt;/maven.compiler.release&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;adk.version&amp;gt;&lt;/span&gt;1.7.0&lt;span class="nt"&gt;&amp;lt;/adk.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.google.adk&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;google-adk&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${adk.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.google.adk&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;google-adk-dev&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${adk.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;google-adk-dev&lt;/code&gt; 用于本地开发 UI，不建议不加区分地打进生产镜像。&lt;/p&gt;
&lt;p&gt;使用 Google AI Studio / Gemini API 时，凭据名称和认证方式应以当前 ADK 官方文档为准，常见本地配置是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;你的密钥&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果使用 Vertex AI，还需要 Google Cloud Project、区域和 ADC 等配置。不要把服务账号 JSON 放进源码或容器镜像。&lt;/p&gt;
&lt;h2 id="三先实现一个可验证的-functiontool"&gt;&lt;a href="#%e4%b8%89%e5%85%88%e5%ae%9e%e7%8e%b0%e4%b8%80%e4%b8%aa%e5%8f%af%e9%aa%8c%e8%af%81%e7%9a%84-functiontool" class="header-anchor"&gt;&lt;/a&gt;三、先实现一个可验证的 FunctionTool
&lt;/h2&gt;&lt;p&gt;ADK 可以把静态 Java 方法包装成工具。下面的工具只返回受控的本地资料，便于无外部搜索依赖地验证调用链：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.google.adk.tools.Annotations.Schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResearchTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;lookupFrameworkFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;framework&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;框架名称，例如 Spring AI Alibaba 或 AgentScope Java&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;spring ai alibaba&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fact&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;面向 Java 的 Agent、Workflow 与 Multi-Agent 框架&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;agentscope java&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fact&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;面向分布式、生产级、长时间运行 Agent 的 Java 框架&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;not_found&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fact&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;本地资料中没有该框架&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;包装为 &lt;code&gt;FunctionTool&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.google.adk.tools.FunctionTool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;factTool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResearchTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;lookupFrameworkFact&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;工具参数用 &lt;code&gt;@Schema&lt;/code&gt; 写清名称和描述，返回值使用结构化 &lt;code&gt;Map&lt;/code&gt; 或 POJO。模型可以决定是否调用，但 Java 方法必须独立完成参数校验、鉴权、超时和幂等。&lt;/p&gt;
&lt;h2 id="四定义三个专业-llmagent"&gt;&lt;a href="#%e5%9b%9b%e5%ae%9a%e4%b9%89%e4%b8%89%e4%b8%aa%e4%b8%93%e4%b8%9a-llmagent" class="header-anchor"&gt;&lt;/a&gt;四、定义三个专业 LlmAgent
&lt;/h2&gt;&lt;h3 id="1-researcher"&gt;&lt;a href="#1-researcher" class="header-anchor"&gt;&lt;/a&gt;1. Researcher
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.google.adk.agents.LlmAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;researcher&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;查找并整理主题相关事实&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gemini-2.0-flash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 根据用户主题整理事实清单。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 可调用 lookupFrameworkFact；找不到的内容明确标为待核验，禁止编造。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 输出简洁 Markdown 要点。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factTool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outputKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;research_notes&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;outputKey&lt;/code&gt; 会把 Agent 最终输出写入 Session State，供后续 Agent 使用。&lt;/p&gt;
&lt;h3 id="2-reviewer"&gt;&lt;a href="#2-reviewer" class="header-anchor"&gt;&lt;/a&gt;2. Reviewer
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reviewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;reviewer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;审查研究事实、缺口与风险&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gemini-2.0-flash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 阅读 session state 中的 research_notes。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 分成：已确认、证据不足、可能过时三类；
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 不得把推测升级成事实，给出下一步核验建议。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outputKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;review_notes&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-writer"&gt;&lt;a href="#3-writer" class="header-anchor"&gt;&lt;/a&gt;3. Writer
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;writer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;把研究和审查结果组织成文章提纲&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gemini-2.0-flash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 使用 research_notes 和 review_notes 生成中文技术文章提纲。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 对证据不足的结论保留警示；不输出版本发布稿，强调可复用原理与实践。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outputKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;article_outline&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Prompt 应告诉 Agent 从 State 读取哪些键、输出写到哪里。否则三个 Agent 虽然按顺序运行，却不一定有效协作。&lt;/p&gt;
&lt;h2 id="五用-sequentialagent-显式编排"&gt;&lt;a href="#%e4%ba%94%e7%94%a8-sequentialagent-%e6%98%be%e5%bc%8f%e7%bc%96%e6%8e%92" class="header-anchor"&gt;&lt;/a&gt;五、用 SequentialAgent 显式编排
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.google.adk.agents.BaseAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.google.adk.agents.SequentialAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArticleWorkflow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROOT_AGENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SequentialAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;article_workflow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;研究、审查并生成文章提纲&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subAgents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;顺序编排的价值是依赖关系明确：Reviewer 不会在 Researcher 之前运行，Writer 也不会绕过审查。它比让一个“主管 Agent”自行决定顺序更容易测试。&lt;/p&gt;
&lt;p&gt;何时用其他类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ParallelAgent&lt;/code&gt;：两个子任务互不依赖，例如同时查官方文档和运行基准；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LoopAgent&lt;/code&gt;：审查不通过就重写，但必须设置退出条件和最大轮数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LlmAgent + subAgents&lt;/code&gt;：让模型按语义把任务委派给专业 Agent。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要把有先后依赖的任务硬塞进 Parallel，也不要创建没有最大次数的 Loop。&lt;/p&gt;
&lt;h2 id="六启动-dev-ui"&gt;&lt;a href="#%e5%85%ad%e5%90%af%e5%8a%a8-dev-ui" class="header-anchor"&gt;&lt;/a&gt;六、启动 Dev UI
&lt;/h2&gt;&lt;p&gt;ADK Java 自带开发 UI，可用于交互、查看事件和调试 Agent。最简单入口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.google.adk.web.AdkWebServer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AdkWebServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ArticleWorkflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ROOT_AGENT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动后在本地页面输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;比较 Java Agent 框架在工具权限和恢复方面的差异
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开发 UI 适合：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;看模型是否调用了工具；&lt;/li&gt;
&lt;li&gt;检查专业 Agent 的执行顺序；&lt;/li&gt;
&lt;li&gt;观察 State 中输出键；&lt;/li&gt;
&lt;li&gt;保存用于演示和人工回归的会话。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它不是生产认证网关。上线时仍需自己的 API 层、身份系统、限流、审计和 Secret 管理。&lt;/p&gt;
&lt;h2 id="七sessionstate-与-artifact"&gt;&lt;a href="#%e4%b8%83sessionstate-%e4%b8%8e-artifact" class="header-anchor"&gt;&lt;/a&gt;七、Session、State 与 Artifact
&lt;/h2&gt;&lt;p&gt;ADK 中要区分：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;概念&lt;/th&gt;
					&lt;th&gt;用途&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Session&lt;/td&gt;
					&lt;td&gt;某用户/某次连续交互的容器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;State&lt;/td&gt;
					&lt;td&gt;小型结构化状态，如研究摘要、审核结论&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Event&lt;/td&gt;
					&lt;td&gt;用户、模型、工具与 Agent 运行过程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Artifact&lt;/td&gt;
					&lt;td&gt;文件、报告、图片等较大对象&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;outputKey&lt;/code&gt; 写入的是 State，不应把大文件或整份日志塞进去。大对象应使用 Artifact 服务，并在 State 中只保存引用和摘要。&lt;/p&gt;
&lt;p&gt;生产环境还要决定 Session Service 的持久化实现。进程内 Session 适合 Demo；多实例部署需要共享后端，并测试并发更新、过期、迁移和恢复。&lt;/p&gt;
&lt;p&gt;即使 Session 能恢复，工具副作用仍要幂等。流程崩溃可能发生在外部 API 已成功、结果尚未写回 Event/State 的窗口。&lt;/p&gt;
&lt;h2 id="八确定性-workflow-与-llm-路由怎样选择"&gt;&lt;a href="#%e5%85%ab%e7%a1%ae%e5%ae%9a%e6%80%a7-workflow-%e4%b8%8e-llm-%e8%b7%af%e7%94%b1%e6%80%8e%e6%a0%b7%e9%80%89%e6%8b%a9" class="header-anchor"&gt;&lt;/a&gt;八、确定性 Workflow 与 LLM 路由怎样选择
&lt;/h2&gt;&lt;p&gt;优先确定性编排的情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;合规审批顺序固定；&lt;/li&gt;
&lt;li&gt;后一步依赖前一步产物；&lt;/li&gt;
&lt;li&gt;需要精确控制成本和最大循环；&lt;/li&gt;
&lt;li&gt;每个阶段都要测试和审计。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适合 LLM 路由的情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户意图类别多，规则难以穷举；&lt;/li&gt;
&lt;li&gt;多个专业 Agent 能力边界清楚；&lt;/li&gt;
&lt;li&gt;选错路由的损失低，且可以回退；&lt;/li&gt;
&lt;li&gt;工具和 Agent 都没有越权能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常用组合是：顶层确定性 Workflow 控制阶段，某个阶段内部用 LlmAgent 选择工具或子 Agent。&lt;/p&gt;
&lt;h2 id="九a2a-与-mcp-的分工"&gt;&lt;a href="#%e4%b9%9da2a-%e4%b8%8e-mcp-%e7%9a%84%e5%88%86%e5%b7%a5" class="header-anchor"&gt;&lt;/a&gt;九、A2A 与 MCP 的分工
&lt;/h2&gt;&lt;p&gt;ADK 官方重点支持 A2A，用于远程 Agent 之间的能力发现和通信。MCP 则主要面向工具、资源和 Prompt 的互操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;文章 Agent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --A2A--&amp;gt; 独立部署的法务审查 Agent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --MCP--&amp;gt; 搜索、数据库、文件等工具服务器
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;二者不是替代关系：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;协议&lt;/th&gt;
					&lt;th&gt;对端&lt;/th&gt;
					&lt;th&gt;典型能力&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;A2A&lt;/td&gt;
					&lt;td&gt;另一个自治 Agent&lt;/td&gt;
					&lt;td&gt;委派任务、跟踪远程任务、交换结果&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MCP&lt;/td&gt;
					&lt;td&gt;工具/资源服务器&lt;/td&gt;
					&lt;td&gt;调函数、读资源、获取 Prompt&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;跨进程后要验证认证、超时、取消、流式、重试和版本协商。协议兼容不代表安全策略自动兼容。&lt;/p&gt;
&lt;h2 id="十preview-阶段怎样控制风险"&gt;&lt;a href="#%e5%8d%81preview-%e9%98%b6%e6%ae%b5%e6%80%8e%e6%a0%b7%e6%8e%a7%e5%88%b6%e9%a3%8e%e9%99%a9" class="header-anchor"&gt;&lt;/a&gt;十、Preview 阶段怎样控制风险
&lt;/h2&gt;&lt;p&gt;官方 1.7.0 已发布到 Maven Central，但 README 仍标记 Preview / Pre-GA，且部分评测能力仍在演进。工程上应：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;锁定 &lt;code&gt;1.7.0&lt;/code&gt;，不使用动态版本；&lt;/li&gt;
&lt;li&gt;用自己的 &lt;code&gt;AgentWorkflow&lt;/code&gt; 接口包住 ADK 类型；&lt;/li&gt;
&lt;li&gt;保存固定输入、工具调用和状态输出作为回归集；&lt;/li&gt;
&lt;li&gt;将模型与工具封装在可替换适配层；&lt;/li&gt;
&lt;li&gt;不把 Dev UI 暴露到公网生产环境；&lt;/li&gt;
&lt;li&gt;对每次升级验证 Session schema、事件格式和工具调用；&lt;/li&gt;
&lt;li&gt;为迁移到其他工作流引擎保留业务层边界。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“1.x”不自动等于 GA，官方发布阶段声明比版本号更重要。&lt;/p&gt;
&lt;h2 id="十一常见问题"&gt;&lt;a href="#%e5%8d%81%e4%b8%80%e5%b8%b8%e8%a7%81%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;十一、常见问题
&lt;/h2&gt;&lt;h3 id="后续-agent-读不到前一步输出"&gt;&lt;a href="#%e5%90%8e%e7%bb%ad-agent-%e8%af%bb%e4%b8%8d%e5%88%b0%e5%89%8d%e4%b8%80%e6%ad%a5%e8%be%93%e5%87%ba" class="header-anchor"&gt;&lt;/a&gt;后续 Agent 读不到前一步输出
&lt;/h3&gt;&lt;p&gt;确认前一步设置 &lt;code&gt;outputKey&lt;/code&gt;，后续 Prompt 使用同一个 State 键；还要确认 Workflow 使用同一 Session，而不是为每步创建新会话。&lt;/p&gt;
&lt;h3 id="模型不调用-functiontool"&gt;&lt;a href="#%e6%a8%a1%e5%9e%8b%e4%b8%8d%e8%b0%83%e7%94%a8-functiontool" class="header-anchor"&gt;&lt;/a&gt;模型不调用 FunctionTool
&lt;/h3&gt;&lt;p&gt;检查方法是否为可反射调用的静态方法、名称是否传给 &lt;code&gt;FunctionTool.create&lt;/code&gt;、参数 Schema 是否明确，以及具体模型是否支持工具调用。&lt;/p&gt;
&lt;h3 id="parallelagent-结果互相覆盖"&gt;&lt;a href="#parallelagent-%e7%bb%93%e6%9e%9c%e4%ba%92%e7%9b%b8%e8%a6%86%e7%9b%96" class="header-anchor"&gt;&lt;/a&gt;ParallelAgent 结果互相覆盖
&lt;/h3&gt;&lt;p&gt;每个并行 Agent 使用唯一 &lt;code&gt;outputKey&lt;/code&gt;，汇总 Agent 再读取多个键。不要让并行分支写同一个 State 字段。&lt;/p&gt;
&lt;h3 id="loopagent-不停运行"&gt;&lt;a href="#loopagent-%e4%b8%8d%e5%81%9c%e8%bf%90%e8%a1%8c" class="header-anchor"&gt;&lt;/a&gt;LoopAgent 不停运行
&lt;/h3&gt;&lt;p&gt;增加确定性退出条件和最大迭代数，同时记录每轮结果。不要只靠 Prompt 中“完成后停止”。&lt;/p&gt;
&lt;h3 id="本地成功上云后丢-session"&gt;&lt;a href="#%e6%9c%ac%e5%9c%b0%e6%88%90%e5%8a%9f%e4%b8%8a%e4%ba%91%e5%90%8e%e4%b8%a2-session" class="header-anchor"&gt;&lt;/a&gt;本地成功，上云后丢 Session
&lt;/h3&gt;&lt;p&gt;本地 Dev UI 常使用进程内服务。生产要配置共享 Session/Artifact 后端，并验证多副本路由、过期和并发更新。&lt;/p&gt;
&lt;h2 id="十二生产清单"&gt;&lt;a href="#%e5%8d%81%e4%ba%8c%e7%94%9f%e4%ba%a7%e6%b8%85%e5%8d%95" class="header-anchor"&gt;&lt;/a&gt;十二、生产清单
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 明确标记 ADK Java 为 Preview / Pre-GA，并锁定精确版本；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 工作流顺序由代码控制，LLM 只处理需要语义判断的节点；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 每个 State Key 有唯一写入者或明确合并规则；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Artifact 与 State 分开保存；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 工具有鉴权、幂等、超时和结构化错误；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Loop 有最大次数，Parallel 分支避免写冲突；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Dev UI 只用于受控开发环境；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; A2A 和 MCP 分别设计认证与审计；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 升级前运行固定 Agent/Tool/State 回归集；&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 多实例环境使用共享 Session 服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;Google ADK Java 最有价值的地方，是让 Java 开发者在同一套代码中组合两类控制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LlmAgent&lt;/code&gt; 处理语义、工具选择和非结构化内容；&lt;/li&gt;
&lt;li&gt;Sequential、Parallel、Loop 等 Workflow Agent 提供确定性控制；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;outputKey&lt;/code&gt;、Session State 和 Artifact 负责阶段间传递；&lt;/li&gt;
&lt;li&gt;Dev UI 降低本地调试成本；&lt;/li&gt;
&lt;li&gt;A2A 连接独立 Agent，MCP 连接工具和资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Preview 阶段，建议从边界明确的内部工作流开始，而不是立刻替换关键核心系统。Code-first 的真正收益不只是代码看起来清晰，而是工作流能进入代码审查、测试、版本管理和故障演练。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;&lt;a href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" class="header-anchor"&gt;&lt;/a&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/google/adk-java" target="_blank" rel="noopener"
 &gt;Google ADK Java GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://google.github.io/adk-docs/" target="_blank" rel="noopener"
 &gt;Google ADK 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/google/adk-samples" target="_blank" rel="noopener"
 &gt;Google ADK Samples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://central.sonatype.com/artifact/com.google.adk/google-adk/1.7.0" target="_blank" rel="noopener"
 &gt;ADK Java 1.7.0 Maven Central&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/a2aproject/A2A" target="_blank" rel="noopener"
 &gt;A2A Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/google/adk-java/tree/main/a2a" target="_blank" rel="noopener"
 &gt;ADK Java A2A 集成说明&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Java AI Agent 四框架对比：Spring AI Alibaba、AgentScope Java、LangChain4j 与 Google ADK Java</title><link>https://blog.waihost.com/posts/java-agent-framework-comparison/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0800</pubDate><guid>https://blog.waihost.com/posts/java-agent-framework-comparison/</guid><description>&lt;img src="https://blog.waihost.com/images/covers/java-agent-framework-comparison.svg" alt="Featured image of post Java AI Agent 四框架对比：Spring AI Alibaba、AgentScope Java、LangChain4j 与 Google ADK Java" /&gt;&lt;p&gt;Java AI Agent 生态已经不再只有“给大模型套一个 HTTP 客户端”。Spring AI Alibaba、AgentScope Java、LangChain4j、Google ADK Java 都能连接模型和工具，但它们解决的问题并不相同：有的强调 Spring 工作流，有的把权限、沙箱和分布式恢复放在核心位置，有的是通用 JVM AI 工具箱，有的则围绕代码优先的多 Agent 编排设计。&lt;/p&gt;
&lt;p&gt;本文不按 GitHub Star 简单排名，而是从 &lt;strong&gt;编程模型、执行控制、状态恢复、安全、协议、可观测性和生态锁定&lt;/strong&gt; 等方面比较四个框架，并给出面向真实项目的选型路径。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;版本快照：Spring AI Alibaba 稳定线 &lt;code&gt;1.1.2.2&lt;/code&gt;，AgentScope Java &lt;code&gt;2.0.0 GA&lt;/code&gt;，LangChain4j &lt;code&gt;1.18.0&lt;/code&gt;，Google ADK Java &lt;code&gt;1.7.0&lt;/code&gt;。版本状态截至 2026-07-23。Google ADK Java 官方仍标记 Preview / Pre-GA；LangChain4j 核心库与其高层 Agentic 模块的成熟度也不能混为一谈。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一先给结论"&gt;&lt;a href="#%e4%b8%80%e5%85%88%e7%bb%99%e7%bb%93%e8%ae%ba" class="header-anchor"&gt;&lt;/a&gt;一、先给结论
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;如果你的核心问题是&lt;/th&gt;
					&lt;th&gt;优先考虑&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Spring Boot 项目要做 Graph、Supervisor、国内模型和多 Agent&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Spring AI Alibaba&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent 要安全执行 Shell/文件工具，并支持审批、沙箱和跨实例恢复&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;AgentScope Java&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;先统一模型、RAG、Tool Calling、MCP，再逐步加入 Agent&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;LangChain4j&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;需要代码优先的 Sequential/Parallel/Loop 多 Agent，并深度使用 Gemini/Google Cloud&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Google ADK Java&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;只是一个模型调用 2～3 个只读工具&lt;/td&gt;
					&lt;td&gt;先用 &lt;strong&gt;LangChain4j AI Services&lt;/strong&gt; 或 Spring AI，未必需要多 Agent&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;没有“全维度最强”的框架。正确问题不是“哪个框架功能最多”，而是：&lt;strong&gt;你的不确定性主要来自模型决策、工作流状态、工具副作用，还是部署运行时？&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="二四种不同的设计中心"&gt;&lt;a href="#%e4%ba%8c%e5%9b%9b%e7%a7%8d%e4%b8%8d%e5%90%8c%e7%9a%84%e8%ae%be%e8%ae%a1%e4%b8%ad%e5%bf%83" class="header-anchor"&gt;&lt;/a&gt;二、四种不同的设计中心
&lt;/h2&gt;&lt;h3 id="1-spring-ai-alibabaspring--agent-workflow"&gt;&lt;a href="#1-spring-ai-alibabaspring--agent-workflow" class="header-anchor"&gt;&lt;/a&gt;1. Spring AI Alibaba：Spring + Agent Workflow
&lt;/h3&gt;&lt;p&gt;Spring AI Alibaba 在 Spring AI 的模型、工具、消息等抽象上，增加 &lt;code&gt;ReactAgent&lt;/code&gt;、Graph Runtime、&lt;code&gt;SequentialAgent&lt;/code&gt;、&lt;code&gt;ParallelAgent&lt;/code&gt;、&lt;code&gt;RoutingAgent&lt;/code&gt;、Supervisor 等高层能力。&lt;/p&gt;
&lt;p&gt;它的设计中心是 &lt;strong&gt;用 Java 和 Spring 管理可组合的 Agent 工作流&lt;/strong&gt;。适合将 Agent 作为现有 Spring 企业应用的一部分，而不是另起一套运行平台。&lt;/p&gt;
&lt;p&gt;典型结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Spring Boot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Supervisor / Routing / Graph
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; ReactAgent A -&amp;gt; Spring Bean Tools
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; ReactAgent B -&amp;gt; MCP / Service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Saver / Observability / Nacos
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-agentscope-java生产运行时与-harness"&gt;&lt;a href="#2-agentscope-java%e7%94%9f%e4%ba%a7%e8%bf%90%e8%a1%8c%e6%97%b6%e4%b8%8e-harness" class="header-anchor"&gt;&lt;/a&gt;2. AgentScope Java：生产运行时与 Harness
&lt;/h3&gt;&lt;p&gt;AgentScope Java 2.0 不只关心模型如何选择工具，还把生产运行问题提升为一等能力：强类型事件、工具权限、人工审批、Workspace、Sandbox、Middleware、分布式 session 和 memory、跨副本恢复。&lt;/p&gt;
&lt;p&gt;它的设计中心是 &lt;strong&gt;让长时间运行、会执行真实操作的 Agent 安全稳定地活下去&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HarnessAgent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Workspace / Skills / Memory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Permission Decision
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Local / Docker / Kubernetes Sandbox
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Distributed Backend + Session Recovery
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-langchain4jjava-原生-ai-应用工具箱"&gt;&lt;a href="#3-langchain4jjava-%e5%8e%9f%e7%94%9f-ai-%e5%ba%94%e7%94%a8%e5%b7%a5%e5%85%b7%e7%ae%b1" class="header-anchor"&gt;&lt;/a&gt;3. LangChain4j：Java 原生 AI 应用工具箱
&lt;/h3&gt;&lt;p&gt;LangChain4j 首先是通用 Java LLM 应用库。AI Services 允许开发者用 Java 接口定义模型服务，周围组合 Memory、RAG、&lt;code&gt;@Tool&lt;/code&gt; 和 MCP；它同时兼容 Spring Boot、Quarkus、Helidon、Micronaut。&lt;/p&gt;
&lt;p&gt;它的设计中心是 &lt;strong&gt;用符合 Java 习惯的接口、POJO 和注解连接不同模型与 AI 能力&lt;/strong&gt;。这使它适合作为长期底座，但不要因为核心库成熟，就默认高层 &lt;code&gt;langchain4j-agentic&lt;/code&gt; 模块也达到相同稳定程度；官方仍将该模块标为实验性能力。&lt;/p&gt;
&lt;h3 id="4-google-adk-javacode-first-agent-development-kit"&gt;&lt;a href="#4-google-adk-javacode-first-agent-development-kit" class="header-anchor"&gt;&lt;/a&gt;4. Google ADK Java：Code-first Agent Development Kit
&lt;/h3&gt;&lt;p&gt;Google ADK Java 从一开始就围绕 Agent 构建，提供 &lt;code&gt;LlmAgent&lt;/code&gt;、Sequential/Parallel/Loop 工作流、Session/State、工具和开发 UI，并支持 A2A。&lt;/p&gt;
&lt;p&gt;它的设计中心是 &lt;strong&gt;用代码显式定义 Agent、工具和编排，并贯通开发、调试与 Google Cloud 部署&lt;/strong&gt;。优势是 Agent-first 和 Google 生态，代价是项目仍处于 Preview / Pre-GA 阶段。&lt;/p&gt;
&lt;h2 id="三核心能力横向比较"&gt;&lt;a href="#%e4%b8%89%e6%a0%b8%e5%bf%83%e8%83%bd%e5%8a%9b%e6%a8%aa%e5%90%91%e6%af%94%e8%be%83" class="header-anchor"&gt;&lt;/a&gt;三、核心能力横向比较
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;Spring AI Alibaba&lt;/th&gt;
					&lt;th&gt;AgentScope Java 2.0&lt;/th&gt;
					&lt;th&gt;LangChain4j&lt;/th&gt;
					&lt;th&gt;Google ADK Java&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;主要定位&lt;/td&gt;
					&lt;td&gt;Agent 工作流与多智能体&lt;/td&gt;
					&lt;td&gt;生产级 Agent Harness&lt;/td&gt;
					&lt;td&gt;JVM AI 应用工具箱&lt;/td&gt;
					&lt;td&gt;Code-first Agent SDK&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;主要语言&lt;/td&gt;
					&lt;td&gt;Java&lt;/td&gt;
					&lt;td&gt;Java&lt;/td&gt;
					&lt;td&gt;Java&lt;/td&gt;
					&lt;td&gt;Java&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;基础要求&lt;/td&gt;
					&lt;td&gt;JDK 17、Spring Boot&lt;/td&gt;
					&lt;td&gt;JDK 17+&lt;/td&gt;
					&lt;td&gt;依模块而定&lt;/td&gt;
					&lt;td&gt;Java + Maven/Gradle&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;单 Agent&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ReactAgent&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ReActAgent&lt;/code&gt; / &lt;code&gt;HarnessAgent&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;AI Services + Tools；Agentic 模块&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;LlmAgent&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;工作流&lt;/td&gt;
					&lt;td&gt;Graph、顺序、并行、路由、循环&lt;/td&gt;
					&lt;td&gt;Harness、Subagent、事件驱动&lt;/td&gt;
					&lt;td&gt;高层 Agentic 模块仍需谨慎&lt;/td&gt;
					&lt;td&gt;Sequential、Parallel、Loop&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;状态恢复&lt;/td&gt;
					&lt;td&gt;Saver / Graph checkpoint&lt;/td&gt;
					&lt;td&gt;分布式 session、memory、跨副本恢复&lt;/td&gt;
					&lt;td&gt;Chat Memory 为主，复杂恢复自行设计&lt;/td&gt;
					&lt;td&gt;Session / State / Artifact&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;HITL&lt;/td&gt;
					&lt;td&gt;Graph 中断等方式组织&lt;/td&gt;
					&lt;td&gt;原生权限：允许/审批/拒绝&lt;/td&gt;
					&lt;td&gt;通常由应用层实现&lt;/td&gt;
					&lt;td&gt;可通过流程/工具层实现&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Sandbox&lt;/td&gt;
					&lt;td&gt;有独立 Sandbox 生态&lt;/td&gt;
					&lt;td&gt;本地、Docker、K8s、云 Sandbox&lt;/td&gt;
					&lt;td&gt;非核心能力&lt;/td&gt;
					&lt;td&gt;非核心能力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MCP&lt;/td&gt;
					&lt;td&gt;支持&lt;/td&gt;
					&lt;td&gt;支持&lt;/td&gt;
					&lt;td&gt;支持&lt;/td&gt;
					&lt;td&gt;工具生态可扩展，MCP 与 A2A 应分工看待&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;A2A&lt;/td&gt;
					&lt;td&gt;支持，并可结合 Nacos&lt;/td&gt;
					&lt;td&gt;支持&lt;/td&gt;
					&lt;td&gt;需看具体集成&lt;/td&gt;
					&lt;td&gt;官方重点能力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;国内模型&lt;/td&gt;
					&lt;td&gt;很强&lt;/td&gt;
					&lt;td&gt;DashScope、DeepSeek 等扩展&lt;/td&gt;
					&lt;td&gt;提供多厂商集成&lt;/td&gt;
					&lt;td&gt;Gemini 最自然，其他模型需验证&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Spring 集成&lt;/td&gt;
					&lt;td&gt;原生核心&lt;/td&gt;
					&lt;td&gt;可集成，但不是唯一运行方式&lt;/td&gt;
					&lt;td&gt;成熟&lt;/td&gt;
					&lt;td&gt;不是核心设计中心&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;当前主要风险&lt;/td&gt;
					&lt;td&gt;版本线迭代快&lt;/td&gt;
					&lt;td&gt;2.0 GA 较新，工程复杂度高&lt;/td&gt;
					&lt;td&gt;Agentic 高层 API 实验性&lt;/td&gt;
					&lt;td&gt;Preview / Pre-GA、平台偏向&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这张表不能代替 PoC。尤其是“支持”两个字，可能只代表存在适配器，并不代表拥有相同的错误语义、流式事件、结构化输出和生产经验。&lt;/p&gt;
&lt;h2 id="四编程模型接口图harness-与-agent-树"&gt;&lt;a href="#%e5%9b%9b%e7%bc%96%e7%a8%8b%e6%a8%a1%e5%9e%8b%e6%8e%a5%e5%8f%a3%e5%9b%beharness-%e4%b8%8e-agent-%e6%a0%91" class="header-anchor"&gt;&lt;/a&gt;四、编程模型：接口、图、Harness 与 Agent 树
&lt;/h2&gt;&lt;h3 id="spring-ai-alibaba把-agent-当成图中的节点"&gt;&lt;a href="#spring-ai-alibaba%e6%8a%8a-agent-%e5%bd%93%e6%88%90%e5%9b%be%e4%b8%ad%e7%9a%84%e8%8a%82%e7%82%b9" class="header-anchor"&gt;&lt;/a&gt;Spring AI Alibaba：把 Agent 当成图中的节点
&lt;/h3&gt;&lt;p&gt;开发者可以先构建专业 &lt;code&gt;ReactAgent&lt;/code&gt;，再将它们包装成 Supervisor 的工具，或放进 Graph 里增加条件边、重试和 checkpoint。它适合“业务流程大体确定，但部分节点需要 LLM 决策”的系统。&lt;/p&gt;
&lt;p&gt;优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确定性工作流与 Agent 节点可以混合；&lt;/li&gt;
&lt;li&gt;Spring Bean、配置、监控和业务服务复用自然；&lt;/li&gt;
&lt;li&gt;对复杂流程的控制力强于单纯 ReAct 循环。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代价：Graph、Agent Framework、Spring AI 与 Alibaba 版本线需要一起管理，升级时应做依赖树和回归测试。&lt;/p&gt;
&lt;h3 id="agentscope-java把-agent-当成长期运行的受控进程"&gt;&lt;a href="#agentscope-java%e6%8a%8a-agent-%e5%bd%93%e6%88%90%e9%95%bf%e6%9c%9f%e8%bf%90%e8%a1%8c%e7%9a%84%e5%8f%97%e6%8e%a7%e8%bf%9b%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;AgentScope Java：把 Agent 当成长期运行的受控进程
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;HarnessAgent&lt;/code&gt; 组合 Workspace、Memory、Skills、Subagent、权限和沙箱。这里的关键不只是“下一步调哪个函数”，还包括：调用是否需要用户批准、工具在哪个隔离环境运行、崩溃后从哪里恢复、事件如何实时推给前端。&lt;/p&gt;
&lt;p&gt;优势：生产问题覆盖最完整。&lt;/p&gt;
&lt;p&gt;代价：如果业务只需简单问答和只读工具，Harness 的概念和部署组件可能过重。&lt;/p&gt;
&lt;h3 id="langchain4j把-ai-能力当成-java-service"&gt;&lt;a href="#langchain4j%e6%8a%8a-ai-%e8%83%bd%e5%8a%9b%e5%bd%93%e6%88%90-java-service" class="header-anchor"&gt;&lt;/a&gt;LangChain4j：把 AI 能力当成 Java Service
&lt;/h3&gt;&lt;p&gt;典型写法是定义接口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Assistant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@MemoryId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@UserMessage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再通过 &lt;code&gt;AiServices.builder(...)&lt;/code&gt; 绑定模型、Memory Provider 和工具对象。这种方式对传统 Java 团队非常自然，单元测试和依赖注入也容易组织。&lt;/p&gt;
&lt;p&gt;优势：模型、RAG、工具与框架集成广，渐进式采用成本低。&lt;/p&gt;
&lt;p&gt;代价：复杂多 Agent 的暂停、恢复、HITL 和图执行不应仅靠 Chat Memory 拼装；高层 Agentic 模块仍需要固定版本和充分验证。&lt;/p&gt;
&lt;h3 id="google-adk-java把-agent-组合成代码结构"&gt;&lt;a href="#google-adk-java%e6%8a%8a-agent-%e7%bb%84%e5%90%88%e6%88%90%e4%bb%a3%e7%a0%81%e7%bb%93%e6%9e%84" class="header-anchor"&gt;&lt;/a&gt;Google ADK Java：把 Agent 组合成代码结构
&lt;/h3&gt;&lt;p&gt;开发者定义多个 &lt;code&gt;LlmAgent&lt;/code&gt;，再通过 Sequential、Parallel 或 Loop Agent 显式组合。Session 保存对话和状态，Dev UI 用于本地调试。&lt;/p&gt;
&lt;p&gt;优势：多 Agent 编排概念清晰，A2A 与 Google Cloud 路线完整。&lt;/p&gt;
&lt;p&gt;代价：官方 README 仍声明 Preview / Pre-GA，且部分评测能力仍在演进。关键生产系统应先做版本冻结、回归集和退出预案。&lt;/p&gt;
&lt;h2 id="五状态与恢复最容易比较错的维度"&gt;&lt;a href="#%e4%ba%94%e7%8a%b6%e6%80%81%e4%b8%8e%e6%81%a2%e5%a4%8d%e6%9c%80%e5%ae%b9%e6%98%93%e6%af%94%e8%be%83%e9%94%99%e7%9a%84%e7%bb%b4%e5%ba%a6" class="header-anchor"&gt;&lt;/a&gt;五、状态与恢复：最容易比较错的维度
&lt;/h2&gt;&lt;p&gt;“支持 Memory”不等于“支持崩溃恢复”。至少要区分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;对话记忆&lt;/strong&gt;：模型下一轮能看到什么；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工作流 checkpoint&lt;/strong&gt;：程序执行到哪个节点；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;业务事实&lt;/strong&gt;：邮件是否真的发送、订单是否真的创建；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Artifact&lt;/strong&gt;：文件、报告、图片等大对象；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分布式路由状态&lt;/strong&gt;：哪个副本继续哪个 session。&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;需求&lt;/th&gt;
					&lt;th&gt;更适合的起点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;多轮问答记住用户上下文&lt;/td&gt;
					&lt;td&gt;LangChain4j Chat Memory&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Graph 节点暂停后继续&lt;/td&gt;
					&lt;td&gt;Spring AI Alibaba Saver / checkpoint&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;跨副本恢复长任务和子 Agent&lt;/td&gt;
					&lt;td&gt;AgentScope Java Distributed Backend&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent Session、State 与 Artifact 一体组织&lt;/td&gt;
					&lt;td&gt;Google ADK Java&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;无论框架多强，都不能替业务工具完成 exactly-once。崩溃可能发生在“下游已经写成功，但 Agent 还没保存结果”的窗口。邮件、支付、工单等工具必须使用幂等键和唯一约束。&lt;/p&gt;
&lt;h2 id="六安全不要把-prompt-当权限系统"&gt;&lt;a href="#%e5%85%ad%e5%ae%89%e5%85%a8%e4%b8%8d%e8%a6%81%e6%8a%8a-prompt-%e5%bd%93%e6%9d%83%e9%99%90%e7%b3%bb%e7%bb%9f" class="header-anchor"&gt;&lt;/a&gt;六、安全：不要把 Prompt 当权限系统
&lt;/h2&gt;&lt;p&gt;四个框架都可以在 Prompt 中写“删除前请确认”，但这不是安全边界。&lt;/p&gt;
&lt;p&gt;AgentScope Java 的差异最明显：权限系统原生表达 &lt;strong&gt;允许、要求用户审批、拒绝&lt;/strong&gt;，并能把工具放入沙箱。若业务是运维、代码执行或文件操作，它通常更贴近需求。&lt;/p&gt;
&lt;p&gt;其他框架也能实现安全控制，但需要在应用层构建：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Agent 只能调用 prepare_operation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 服务端创建 WAITING_APPROVAL 记录
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 人类在可信 UI 审批
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 后端用 approvalId 执行
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 工具返回真实 operationId
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;所有框架都应遵守：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;身份和租户信息来自服务端上下文，不让模型填写；&lt;/li&gt;
&lt;li&gt;写工具与读工具分离；&lt;/li&gt;
&lt;li&gt;工具参数使用结构化类型和白名单；&lt;/li&gt;
&lt;li&gt;高风险工具默认拒绝或必须审批；&lt;/li&gt;
&lt;li&gt;沙箱之外还要有操作系统、网络和云 IAM 限制；&lt;/li&gt;
&lt;li&gt;日志脱敏，Prompt 与工具结果不能泄露凭据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="七mcp-与-a2a-不是竞争关系"&gt;&lt;a href="#%e4%b8%83mcp-%e4%b8%8e-a2a-%e4%b8%8d%e6%98%af%e7%ab%9e%e4%ba%89%e5%85%b3%e7%b3%bb" class="header-anchor"&gt;&lt;/a&gt;七、MCP 与 A2A 不是竞争关系
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP&lt;/strong&gt; 主要解决 Agent/模型如何发现并调用工具、资源和提示模板；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A2A&lt;/strong&gt; 主要解决相互独立的 Agent 如何描述能力、通信和协作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如，采购 Agent 可以通过 MCP 调 ERP 查询工具，同时通过 A2A 把合同审查任务交给远程法务 Agent。不要因为框架同时写着 MCP 和 A2A，就把二者当成同一层协议。&lt;/p&gt;
&lt;p&gt;选型时应验证的不只是协议名称，还包括：认证、超时、流式、取消、错误码、版本协商、审计和跨租户隔离。&lt;/p&gt;
&lt;h2 id="八用同一个-poc-做公平测试"&gt;&lt;a href="#%e5%85%ab%e7%94%a8%e5%90%8c%e4%b8%80%e4%b8%aa-poc-%e5%81%9a%e5%85%ac%e5%b9%b3%e6%b5%8b%e8%af%95" class="header-anchor"&gt;&lt;/a&gt;八、用同一个 PoC 做公平测试
&lt;/h2&gt;&lt;p&gt;建议不要分别跑四个官方 Hello World，而是实现同一个“采购审批 Agent”：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;读取采购申请
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 并行查询预算与供应商风险
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 生成建议
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 金额超过阈值则等待人工批准
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 创建订单
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 模拟进程崩溃并恢复
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;统一测量：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;指标&lt;/th&gt;
					&lt;th&gt;观察方法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;实现复杂度&lt;/td&gt;
					&lt;td&gt;业务代码量、配置量、概念数量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;工具正确率&lt;/td&gt;
					&lt;td&gt;固定 100 条用例，统计选错/漏调/参数错&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;副作用安全&lt;/td&gt;
					&lt;td&gt;重试和恢复后是否重复创建订单&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;恢复能力&lt;/td&gt;
					&lt;td&gt;在每个节点前后故障注入&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;可观测性&lt;/td&gt;
					&lt;td&gt;能否关联模型、工具、session、审批和错误&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;成本&lt;/td&gt;
					&lt;td&gt;模型调用次数、token、延迟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;可测试性&lt;/td&gt;
					&lt;td&gt;不调用真实模型时能否测试控制流&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;生态约束&lt;/td&gt;
					&lt;td&gt;替换模型、存储、云环境的改动范围&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;真正的选型结论通常不是“框架 A 功能比 B 多”，而是“框架 A 让我们的关键失败模式更容易被测试和控制”。&lt;/p&gt;
&lt;h2 id="九按团队和场景选型"&gt;&lt;a href="#%e4%b9%9d%e6%8c%89%e5%9b%a2%e9%98%9f%e5%92%8c%e5%9c%ba%e6%99%af%e9%80%89%e5%9e%8b" class="header-anchor"&gt;&lt;/a&gt;九、按团队和场景选型
&lt;/h2&gt;&lt;h3 id="场景-1现有-spring-boot-企业系统"&gt;&lt;a href="#%e5%9c%ba%e6%99%af-1%e7%8e%b0%e6%9c%89-spring-boot-%e4%bc%81%e4%b8%9a%e7%b3%bb%e7%bb%9f" class="header-anchor"&gt;&lt;/a&gt;场景 1：现有 Spring Boot 企业系统
&lt;/h3&gt;&lt;p&gt;优先评估 &lt;strong&gt;Spring AI Alibaba&lt;/strong&gt;。它能直接复用 Spring Service、配置、Actuator 和依赖注入，也更容易把确定性 Graph 与 Agent 节点结合。&lt;/p&gt;
&lt;p&gt;若当前阶段只做模型、RAG 和少量工具，也可以从 LangChain4j 或 Spring AI 底层能力开始，不必一开始引入多 Agent。&lt;/p&gt;
&lt;h3 id="场景-2运维-agent代码-agent长任务-agent"&gt;&lt;a href="#%e5%9c%ba%e6%99%af-2%e8%bf%90%e7%bb%b4-agent%e4%bb%a3%e7%a0%81-agent%e9%95%bf%e4%bb%bb%e5%8a%a1-agent" class="header-anchor"&gt;&lt;/a&gt;场景 2：运维 Agent、代码 Agent、长任务 Agent
&lt;/h3&gt;&lt;p&gt;优先评估 &lt;strong&gt;AgentScope Java&lt;/strong&gt;。权限决策、Workspace、Sandbox、事件系统和跨副本恢复与该类风险高度匹配。&lt;/p&gt;
&lt;p&gt;不过，选它不等于自动安全：Docker/Kubernetes 隔离、网络出口、凭据代理、资源配额和人工审批后端仍需自行配置。&lt;/p&gt;
&lt;h3 id="场景-3希望模型和应用框架保持中立"&gt;&lt;a href="#%e5%9c%ba%e6%99%af-3%e5%b8%8c%e6%9c%9b%e6%a8%a1%e5%9e%8b%e5%92%8c%e5%ba%94%e7%94%a8%e6%a1%86%e6%9e%b6%e4%bf%9d%e6%8c%81%e4%b8%ad%e7%ab%8b" class="header-anchor"&gt;&lt;/a&gt;场景 3：希望模型和应用框架保持中立
&lt;/h3&gt;&lt;p&gt;优先评估 &lt;strong&gt;LangChain4j&lt;/strong&gt;。它的提供商和向量库集成广，也能运行在 Spring Boot、Quarkus、Micronaut 等环境中。&lt;/p&gt;
&lt;p&gt;复杂 Agentic 编排要单独做成熟度评估；必要时可把 LangChain4j 作为模型/工具层，配合其他工作流引擎。&lt;/p&gt;
&lt;h3 id="场景-4geminigoogle-searchvertex-ai-和-a2a"&gt;&lt;a href="#%e5%9c%ba%e6%99%af-4geminigoogle-searchvertex-ai-%e5%92%8c-a2a" class="header-anchor"&gt;&lt;/a&gt;场景 4：Gemini、Google Search、Vertex AI 和 A2A
&lt;/h3&gt;&lt;p&gt;优先评估 &lt;strong&gt;Google ADK Java&lt;/strong&gt;。其代码优先的 Agent 树、Dev UI 和 Google 生态协同清晰。&lt;/p&gt;
&lt;p&gt;但 Preview / Pre-GA 是实际风险，不应藏在脚注里。上线前要锁版本、保留回滚路径，并验证非 Google 模型或未来迁移的成本。&lt;/p&gt;
&lt;h3 id="场景-5框架混用"&gt;&lt;a href="#%e5%9c%ba%e6%99%af-5%e6%a1%86%e6%9e%b6%e6%b7%b7%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;场景 5：框架混用
&lt;/h3&gt;&lt;p&gt;混用可以成立，但只在边界明确时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring AI Alibaba Graph 负责确定性业务流程；&lt;/li&gt;
&lt;li&gt;AgentScope Harness 负责需要沙箱的远程专业 Agent；&lt;/li&gt;
&lt;li&gt;LangChain4j 提供某些模型或 RAG 能力；&lt;/li&gt;
&lt;li&gt;A2A 连接独立 Agent 服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要在同一进程同时引入四套消息、Memory、Tool 和 tracing 抽象。每多一层适配，都要明确谁负责重试、取消、状态和错误翻译。&lt;/p&gt;
&lt;h2 id="十决策清单"&gt;&lt;a href="#%e5%8d%81%e5%86%b3%e7%ad%96%e6%b8%85%e5%8d%95" class="header-anchor"&gt;&lt;/a&gt;十、决策清单
&lt;/h2&gt;&lt;p&gt;在确定框架前，逐项回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 我们需要的是聊天记忆，还是工作流崩溃恢复？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 工具是否有副作用，是否必须人工审批？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 是否会执行 Shell、代码或文件操作，需要哪一级沙箱？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 工作流是确定性图，还是高度自治的 ReAct？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 是否需要多实例、跨副本恢复和后台长任务？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; MCP、A2A 分别解决哪个边界？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 是否必须使用 Spring、Google Cloud 或国内模型生态？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 当前所用模块是 GA、稳定版、experimental，还是 Pre-GA？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 能否在不调用真实模型的情况下测试控制流？&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 工具是否具备幂等、鉴权、审计和超时？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;四个项目代表四条不同路线：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Spring AI Alibaba&lt;/strong&gt;：用 Spring 和 Graph 构建可控的 Agent 工作流；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AgentScope Java&lt;/strong&gt;：为安全、长任务和分布式恢复提供生产 Harness；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangChain4j&lt;/strong&gt;：用 Java 原生接口组织模型、RAG、工具与 MCP；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google ADK Java&lt;/strong&gt;：用代码优先方式组合多 Agent，并连接 Google/A2A 生态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于多数团队，最稳妥的方法是先选一个有真实副作用、需要审批和恢复的业务任务，用同一组测试用例做 PoC。Agent 框架的价值，不在于让 Demo 调用更多工具，而在于当模型选错、工具超时、进程崩溃或用户拒绝审批时，系统仍然可解释、可恢复、不会重复造成损失。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;&lt;a href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" class="header-anchor"&gt;&lt;/a&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/alibaba/spring-ai-alibaba" target="_blank" rel="noopener"
 &gt;Spring AI Alibaba GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java2ai.com/docs/overview" target="_blank" rel="noopener"
 &gt;Spring AI Alibaba 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/agentscope-ai/agentscope-java" target="_blank" rel="noopener"
 &gt;AgentScope Java GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java.agentscope.io/v2/zh/intro.html" target="_blank" rel="noopener"
 &gt;AgentScope Java 2.0 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/langchain4j/langchain4j" target="_blank" rel="noopener"
 &gt;LangChain4j GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.langchain4j.dev/" target="_blank" rel="noopener"
 &gt;LangChain4j 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/google/adk-java" target="_blank" rel="noopener"
 &gt;Google ADK Java GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://google.github.io/adk-docs/" target="_blank" rel="noopener"
 &gt;Google ADK 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/a2aproject/A2A" target="_blank" rel="noopener"
 &gt;A2A Protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Spring AI Alibaba 实战：用 Supervisor 构建可持久化的 Java 多智能体助手</title><link>https://blog.waihost.com/posts/spring-ai-alibaba-multi-agent-supervisor/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0800</pubDate><guid>https://blog.waihost.com/posts/spring-ai-alibaba-multi-agent-supervisor/</guid><description>&lt;img src="https://blog.waihost.com/images/covers/spring-ai-alibaba-multi-agent-supervisor.svg" alt="Featured image of post Spring AI Alibaba 实战：用 Supervisor 构建可持久化的 Java 多智能体助手" /&gt;&lt;p&gt;很多 Java Agent 示例只演示“模型调用一个工具”，但真实业务通常横跨多个边界：日历 Agent 理解时间并检查冲突，邮件 Agent 负责收件人和正文，协调者还要决定调用顺序、传递结果，并在失败后恢复。&lt;/p&gt;
&lt;p&gt;本文基于 Spring AI Alibaba 官方稳定依赖线 &lt;code&gt;1.1.2.2&lt;/code&gt;，实现一个 &lt;strong&gt;Supervisor + 专业子 Agent&lt;/strong&gt; 的个人助理。重点不是某个模型的聊天接口，而是四个可复用的工程问题：如何划分 Agent 边界、怎样把子 Agent 暴露成工具、如何保存执行状态，以及如何控制有副作用的操作。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;本文代码结构依据官方 &lt;code&gt;examples/multiagent-patterns/supervisor&lt;/code&gt; 示例整理。Spring AI Alibaba 同时存在面向 Spring AI 2.0 / Spring Boot 4 的 &lt;code&gt;2.0.0-M1.1&lt;/code&gt; 里程碑版本；生产项目不要把 milestone 与本文稳定线混用。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一为什么需要-supervisor"&gt;&lt;a href="#%e4%b8%80%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81-supervisor" class="header-anchor"&gt;&lt;/a&gt;一、为什么需要 Supervisor
&lt;/h2&gt;&lt;p&gt;多 Agent 并不等于“把四个聊天机器人放进一个群”。一个可控系统至少要区分三层：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层次&lt;/th&gt;
					&lt;th&gt;职责&lt;/th&gt;
					&lt;th&gt;本文对应实现&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;决策层&lt;/td&gt;
					&lt;td&gt;拆解请求、选择能力、安排调用顺序&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;personal_assistant&lt;/code&gt; Supervisor&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;专业层&lt;/td&gt;
					&lt;td&gt;在受限领域内推理和调用工具&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;schedule_event&lt;/code&gt;、&lt;code&gt;manage_email&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;执行层&lt;/td&gt;
					&lt;td&gt;访问日历、邮件、数据库等真实系统&lt;/td&gt;
					&lt;td&gt;Java &lt;code&gt;@Tool&lt;/code&gt; 方法&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;用户说“下周二开评审会，并给设计组发提醒”时，Supervisor 先调用日历 Agent；拿到时间和创建结果后，再把必要信息交给邮件 Agent。专业 Agent 看不到无关工具，工具层也不承担自然语言规划。&lt;/p&gt;
&lt;p&gt;这种设计的价值是 &lt;strong&gt;缩小每次模型决策的工具集合&lt;/strong&gt;。如果把查日历、建会议、发邮件、查工单、改数据库等几十个工具全部交给一个 Agent，模型更容易选错工具，权限也难以分层。&lt;/p&gt;
&lt;h2 id="二环境与依赖"&gt;&lt;a href="#%e4%ba%8c%e7%8e%af%e5%a2%83%e4%b8%8e%e4%be%9d%e8%b5%96" class="header-anchor"&gt;&lt;/a&gt;二、环境与依赖
&lt;/h2&gt;&lt;p&gt;官方稳定示例使用 JDK 17、Spring Boot 3.5.7、Spring AI 1.1.2 和 Spring AI Alibaba 1.1.2.2：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.5.7&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;java.version&amp;gt;&lt;/span&gt;17&lt;span class="nt"&gt;&amp;lt;/java.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;spring-ai.version&amp;gt;&lt;/span&gt;1.1.2&lt;span class="nt"&gt;&amp;lt;/spring-ai.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;spring-ai-alibaba.version&amp;gt;&lt;/span&gt;1.1.2.2&lt;span class="nt"&gt;&amp;lt;/spring-ai-alibaba.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${spring-ai.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-alibaba-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${spring-ai-alibaba.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-alibaba-starter-dashscope&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-alibaba-agent-framework&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置密钥时不要写进仓库：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spring&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dashscope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;api-key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${AI_DASHSCOPE_API_KEY}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行前设置环境变量：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AI_DASHSCOPE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;你的密钥&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果换成其他 Spring AI &lt;code&gt;ChatModel&lt;/code&gt;，Agent 编排代码本身可以保持不变，但工具调用、结构化输出和并行调用能力仍取决于具体模型。&lt;/p&gt;
&lt;h2 id="三先写最窄的业务工具"&gt;&lt;a href="#%e4%b8%89%e5%85%88%e5%86%99%e6%9c%80%e7%aa%84%e7%9a%84%e4%b8%9a%e5%8a%a1%e5%b7%a5%e5%85%b7" class="header-anchor"&gt;&lt;/a&gt;三、先写最窄的业务工具
&lt;/h2&gt;&lt;p&gt;工具的参数和描述会进入模型上下文。名称模糊、参数万能化，会直接降低调用准确率。下面用内存实现代替真实日历系统：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalendarTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;检查指定 ISO-8601 起止时间内是否有空闲时段&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getAvailableTimeSlots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;开始时间，例如 2026-07-28T14:00:00+08:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;结束时间，例如 2026-07-28T15:00:00+08:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;AVAILABLE: &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34; ~ &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;创建日历事件；调用前必须已经确认时间可用&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;createCalendarEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;事件标题&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ISO-8601 开始时间&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ISO-8601 结束时间&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;CREATED eventId=&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;, title=&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;邮件工具同样保持窄接口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;发送邮件。仅接受已经确认的收件人、主题和正文&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;SENT to=&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;, subject=&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;演示可以直接返回字符串，生产环境必须补上：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;幂等键&lt;/strong&gt;：重试不能创建两场相同会议或发送两封邮件；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;身份鉴权&lt;/strong&gt;：工具从服务端上下文读取租户和用户，不能信任模型传入身份；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数校验&lt;/strong&gt;：邮箱白名单、时间范围、正文长度均由 Java 代码强制检查；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;审计日志&lt;/strong&gt;：记录调用者、工具名、参数摘要、结果和 trace ID；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;超时与熔断&lt;/strong&gt;：模型重试不应无限放大下游故障。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="四构建两个专业-reactagent"&gt;&lt;a href="#%e5%9b%9b%e6%9e%84%e5%bb%ba%e4%b8%a4%e4%b8%aa%e4%b8%93%e4%b8%9a-reactagent" class="header-anchor"&gt;&lt;/a&gt;四、构建两个专业 ReactAgent
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ReactAgent&lt;/code&gt; 负责“思考—选择工具—观察结果—继续”的循环。每个专业 Agent 只注册本领域工具：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentConfiguration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MemorySaver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;memorySaver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MemorySaver&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;calendarAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChatModel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CalendarTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;schedule_event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;检查空闲时间并创建日历事件，输入为自然语言日程请求&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 你是日历助理。先把时间转换为带时区的 ISO-8601 格式，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 再检查空闲时段；只有可用时才创建事件。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 最终回答必须包含事件 ID 和确认后的起止时间。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodTools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inputType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;emailAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChatModel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EmailTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;manage_email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;根据明确的收件人和上下文撰写并发送邮件&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 你是邮件助理。不得猜测收件地址；缺少地址就要求补充。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 发送前检查主题、正文和会议时间是否一致。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 最终回答给出发送状态，不输出敏感凭据。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodTools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inputType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的 &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;description&lt;/code&gt; 不是装饰字段。Supervisor 会根据它们决定是否调用子 Agent，因此描述要写清楚 &lt;strong&gt;何时调用、输入是什么、能产生什么结果&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="五把子-agent-变成-supervisor-的工具"&gt;&lt;a href="#%e4%ba%94%e6%8a%8a%e5%ad%90-agent-%e5%8f%98%e6%88%90-supervisor-%e7%9a%84%e5%b7%a5%e5%85%b7" class="header-anchor"&gt;&lt;/a&gt;五、把子 Agent 变成 Supervisor 的工具
&lt;/h2&gt;&lt;p&gt;Spring AI Alibaba 提供 &lt;code&gt;AgentTool.getFunctionToolCallback(...)&lt;/code&gt;，可以把整个专业 Agent 包装成上层 Agent 可调用的工具：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;supervisorAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ChatModel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calendarAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;emailAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MemorySaver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memorySaver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;personal_assistant&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 你是任务协调者，可以安排日历和发送邮件。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 先拆解请求，再按依赖顺序调用专业工具。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 邮件依赖会议结果时，必须先完成日历操作。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 不要声称执行了未返回成功结果的操作。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memorySaver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AgentTool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFunctionToolCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calendarAgent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AgentTool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFunctionToolCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emailAgent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用入口非常直接：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoRunner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ApplicationRunner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisorAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;DemoRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReactAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisorAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supervisorAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisorAgent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationArguments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;下周二 14:00 安排一小时设计评审，&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;然后给 design@example.com 发一封提醒邮件&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AssistantMessage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisorAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一次典型执行链是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;User
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; Supervisor
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; schedule_event
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; get_available_time_slots
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; create_calendar_event
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; manage_email
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; send_email
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 汇总最终结果
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;子 Agent 是工具，但它内部仍然可以执行多轮 ReAct。这样既保留自治能力，又把自治限制在专业边界内。&lt;/p&gt;
&lt;h2 id="六状态持久化不等于聊天记忆"&gt;&lt;a href="#%e5%85%ad%e7%8a%b6%e6%80%81%e6%8c%81%e4%b9%85%e5%8c%96%e4%b8%8d%e7%ad%89%e4%ba%8e%e8%81%8a%e5%a4%a9%e8%ae%b0%e5%bf%86" class="header-anchor"&gt;&lt;/a&gt;六、状态持久化不等于聊天记忆
&lt;/h2&gt;&lt;p&gt;示例中的 &lt;code&gt;MemorySaver&lt;/code&gt; 适合本地开发和单进程验证。它保存的是图执行所需的 checkpoint，使 Agent 能围绕同一线程继续运行；它不是生产级共享数据库，也不能替代业务幂等。&lt;/p&gt;
&lt;p&gt;工程上要区分三类状态：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;状态&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
					&lt;th&gt;推荐存储&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;会话上下文&lt;/td&gt;
					&lt;td&gt;用户偏好、已确认的时间&lt;/td&gt;
					&lt;td&gt;Chat Memory / 会话库&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent checkpoint&lt;/td&gt;
					&lt;td&gt;当前节点、工具结果、待恢复位置&lt;/td&gt;
					&lt;td&gt;持久化 Saver&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;业务事实&lt;/td&gt;
					&lt;td&gt;已创建会议、邮件发送记录&lt;/td&gt;
					&lt;td&gt;业务数据库，带唯一约束&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;即便 checkpoint 恢复成功，若工具在崩溃前已经写入业务系统、但结果还没写回 checkpoint，恢复后仍可能重复调用。因此可靠流程要让工具接受 &lt;code&gt;operationId&lt;/code&gt;，并在业务库建立唯一约束。&lt;/p&gt;
&lt;h2 id="七给副作用加一道人工确认"&gt;&lt;a href="#%e4%b8%83%e7%bb%99%e5%89%af%e4%bd%9c%e7%94%a8%e5%8a%a0%e4%b8%80%e9%81%93%e4%ba%ba%e5%b7%a5%e7%a1%ae%e8%ae%a4" class="header-anchor"&gt;&lt;/a&gt;七、给副作用加一道人工确认
&lt;/h2&gt;&lt;p&gt;会议和邮件都属于有副作用操作。最稳妥的方式不是只在 Prompt 中写“请先确认”，而是在工具层建立状态机：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DRAFT -&amp;gt; WAITING_APPROVAL -&amp;gt; EXECUTING -&amp;gt; SUCCEEDED / FAILED
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Agent 第一次调用只生成草稿并返回 &lt;code&gt;approvalId&lt;/code&gt;；API 层收到用户确认后，才调用真正的发送方法。这样即使模型忽略提示，也没有直接执行权限。&lt;/p&gt;
&lt;p&gt;还可以进一步拆成两个工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prepare_email(...)&lt;/code&gt;：任何 Agent 都能调用，只生成草稿；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;send_approved_email(approvalId)&lt;/code&gt;：不接受正文，只执行服务端已经批准且未过期的草稿。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这比让模型把 &lt;code&gt;approved=true&lt;/code&gt; 当参数传进来安全得多。&lt;/p&gt;
&lt;h2 id="八常见问题与排查"&gt;&lt;a href="#%e5%85%ab%e5%b8%b8%e8%a7%81%e9%97%ae%e9%a2%98%e4%b8%8e%e6%8e%92%e6%9f%a5" class="header-anchor"&gt;&lt;/a&gt;八、常见问题与排查
&lt;/h2&gt;&lt;h3 id="1-子-agent-从不被调用"&gt;&lt;a href="#1-%e5%ad%90-agent-%e4%bb%8e%e4%b8%8d%e8%a2%ab%e8%b0%83%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;1. 子 Agent 从不被调用
&lt;/h3&gt;&lt;p&gt;检查 &lt;code&gt;name&lt;/code&gt;、&lt;code&gt;description&lt;/code&gt; 是否明确，并确认模型支持 Tool Calling。描述不要只写“邮件助手”，而要说明输入和使用时机。&lt;/p&gt;
&lt;h3 id="2-依赖冲突或类找不到"&gt;&lt;a href="#2-%e4%be%9d%e8%b5%96%e5%86%b2%e7%aa%81%e6%88%96%e7%b1%bb%e6%89%be%e4%b8%8d%e5%88%b0" class="header-anchor"&gt;&lt;/a&gt;2. 依赖冲突或类找不到
&lt;/h3&gt;&lt;p&gt;不要混用 Spring AI 1.1.x、Spring AI Alibaba 1.1.x 与 2.0 milestone。使用 BOM 统一版本，并执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mvn dependency:tree
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重点检查 &lt;code&gt;spring-ai-*&lt;/code&gt; 是否出现多条不兼容版本线。&lt;/p&gt;
&lt;h3 id="3-时间被理解错"&gt;&lt;a href="#3-%e6%97%b6%e9%97%b4%e8%a2%ab%e7%90%86%e8%a7%a3%e9%94%99" class="header-anchor"&gt;&lt;/a&gt;3. 时间被理解错
&lt;/h3&gt;&lt;p&gt;“明天下午”必须结合用户时区和当前日期解析。生产系统应把当前时间、时区作为可信上下文注入，并在工具层拒绝无时区或已经过期的时间。&lt;/p&gt;
&lt;h3 id="4-重启后任务消失"&gt;&lt;a href="#4-%e9%87%8d%e5%90%af%e5%90%8e%e4%bb%bb%e5%8a%a1%e6%b6%88%e5%a4%b1" class="header-anchor"&gt;&lt;/a&gt;4. 重启后任务消失
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;MemorySaver&lt;/code&gt; 只在进程内。多实例部署需要共享持久化 Saver，同时工具仍要做幂等；二者缺一不可。&lt;/p&gt;
&lt;h3 id="5-最终回答说成功业务却没有记录"&gt;&lt;a href="#5-%e6%9c%80%e7%bb%88%e5%9b%9e%e7%ad%94%e8%af%b4%e6%88%90%e5%8a%9f%e4%b8%9a%e5%8a%a1%e5%8d%b4%e6%b2%a1%e6%9c%89%e8%ae%b0%e5%bd%95" class="header-anchor"&gt;&lt;/a&gt;5. 最终回答说成功，业务却没有记录
&lt;/h3&gt;&lt;p&gt;只信工具返回的结构化结果，不信模型自行生成的成功话术。建议工具返回包含 &lt;code&gt;status&lt;/code&gt;、&lt;code&gt;operationId&lt;/code&gt;、&lt;code&gt;errorCode&lt;/code&gt; 的对象，并在最终输出前增加确定性校验节点。&lt;/p&gt;
&lt;h2 id="九什么时候不用多-agent"&gt;&lt;a href="#%e4%b9%9d%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e4%b8%8d%e7%94%a8%e5%a4%9a-agent" class="header-anchor"&gt;&lt;/a&gt;九、什么时候不用多 Agent
&lt;/h2&gt;&lt;p&gt;如果任务只有一个模型、三个简单只读工具和一次调用，单个 &lt;code&gt;ReactAgent&lt;/code&gt; 往往更便宜、更快，也更容易测试。只有出现以下情况，多 Agent 才真正有价值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同领域需要不同 Prompt、工具权限或模型；&lt;/li&gt;
&lt;li&gt;任务能拆成可独立测试的专业能力；&lt;/li&gt;
&lt;li&gt;子任务需要并行、路由或多阶段交接；&lt;/li&gt;
&lt;li&gt;某些 Agent 必须运行在隔离环境或独立服务中；&lt;/li&gt;
&lt;li&gt;团队希望分别维护日历、邮件、工单等能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要用 Agent 替代确定性代码。固定审批顺序、金额阈值和权限检查应该写进 Java 与工作流，而不是交给 LLM 临场决定。&lt;/p&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;Spring AI Alibaba 的 Supervisor 模式可以概括为：&lt;strong&gt;上层 Agent 负责选择和协调，下层 Agent 负责专业推理，Java 工具负责可信执行，Saver 负责恢复上下文&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;真正决定系统能否进入生产的并不是 Agent 数量，而是边界是否清楚：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每个专业 Agent 只看到必要工具；&lt;/li&gt;
&lt;li&gt;有副作用操作经过服务端审批和幂等保护；&lt;/li&gt;
&lt;li&gt;checkpoint、会话记忆与业务事实分开保存；&lt;/li&gt;
&lt;li&gt;版本通过 BOM 锁定，不混用稳定线和 milestone；&lt;/li&gt;
&lt;li&gt;最终成功状态由真实工具结果而不是模型话术决定。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这个基础上，再引入 &lt;code&gt;ParallelAgent&lt;/code&gt;、&lt;code&gt;RoutingAgent&lt;/code&gt;、Graph 条件边、A2A 或 Nacos，复杂度才是可控增长，而不是把一个不可预测的大 Agent 拆成一群不可预测的小 Agent。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;&lt;a href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" class="header-anchor"&gt;&lt;/a&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/alibaba/spring-ai-alibaba" target="_blank" rel="noopener"
 &gt;Spring AI Alibaba GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java2ai.com/docs/overview" target="_blank" rel="noopener"
 &gt;Spring AI Alibaba 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/alibaba/spring-ai-alibaba/tree/main/examples/multiagent-patterns/supervisor" target="_blank" rel="noopener"
 &gt;官方 Supervisor 示例&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://java2ai.com/docs/frameworks/agent-framework/tutorials/agents" target="_blank" rel="noopener"
 &gt;Agent Framework 教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.spring.io/spring-ai/reference/api/tools.html" target="_blank" rel="noopener"
 &gt;Spring AI Tool Calling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>