如何开发一个高效的智能体
<h1>1.概述</h1><p>在智能体逐渐成为人工智能应用核心的今天,如何让它“聪明”且“高效”是开发者最关心的问题。本文将带你从设计思路、核心能力到工程实践,全面解析高效智能体的构建方法。无论是任务分解、知识获取,还是与外部工具的协同,都会结合实际案例,帮助你理解如何打造一个真正能落地、能进化的智能体。</p>
<h1>2.内容</h1>
<h2>2.1 什么是智能体</h2>
<p>智能体(Agent)是人工智能领域中的核心概念,可以理解为一种具备 感知、决策和执行能力的自主系统。它能够从环境中获取信息,结合自身的知识或模型进行推理和判断,并通过调用工具或执行操作来完成任务。与传统程序不同,智能体不仅仅是被动执行预设指令,而是具备一定程度的自主性和适应性,能够在复杂、多变的环境中不断优化行为。</p>
<p>在实际应用中,智能体的使用场景非常广泛:</p>
<ul>
<li>对话交互:例如智能客服或AI助手,能够理解用户需求并给出合适的回应;</li>
<li>任务自动化:如自动化办公、数据分析、代码生成,帮助人类提高效率;</li>
<li>智能决策:在金融风控、供应链优化、推荐系统中,智能体可以快速处理复杂数据并做出判断;</li>
<li>虚拟与现实结合:从游戏NPC到智能机器人,智能体能够与真实世界或虚拟环境交互,带来更智能的体验。</li>
</ul>
<p>简而言之,智能体的核心价值在于 替人类完成复杂任务、提升效率和创造力,它正逐渐成为AI应用的关键载体。</p>
<h2>2.2 何时使用智能体以及智能体框架</h2>
<p>并不是所有问题都需要引入智能体,有些场景用普通脚本或固定规则就能解决。但当任务具备 复杂性、动态性和不确定性 时,智能体和智能体框架就展现出独特优势。</p>
<p>适合使用智能体的典型场景:</p>
<p><strong>1. 任务复杂、需要自主规划</strong></p>
<p>例如在 数据分析 中,不仅要获取数据,还要清洗、建模、可视化。传统脚本需要逐步编写流程,而智能体可以根据目标自动分解任务,并灵活调用工具完成每个环节。</p>
<p><strong>2. 环境动态、信息来源多样</strong></p>
<p>在 金融风控 中,数据源包含市场行情、新闻资讯、历史交易记录,信息随时变化。智能体能持续监控并动态调整策略。</p>
<p><strong>3. 需要多轮交互与记忆</strong></p>
<p>在 智能客服 或 教育辅导 场景中,用户问题往往连续且上下文相关,智能体通过框架中的“记忆机制”保持连贯性,而不是每次都从零开始。</p>
<p><strong>4. 需要调用多种外部工具或API</strong></p>
<p>比如在 软件研发 中,智能体能先检索文档,再调用代码生成工具,最后利用测试框架验证结果,形成一个完整闭环。</p>
<p>智能体框架的价值 在于降低开发门槛。它提供了任务调度、插件管理、上下文记忆等通用能力,让开发者可以专注于业务逻辑。例如:</p>
<ul>
<li>LangChain 适合构建多步推理与工具调用场景;</li>
<li>AutoGen 擅长多智能体协作;</li>
<li>LlamaIndex 在知识库问答中表现突出。</li>
</ul>
<p>当你的问题是 一次性、结构化、固定逻辑 → 用传统脚本即可;<br>当你的问题是 多步骤、不确定性强、需要灵活应对 → 就是使用智能体和框架的好时机。</p>
<h1>3.智能体模式</h1>
<h2>3.1 链式工作流智能体</h2>
<p>Prompt Chaining 工作流模式 是在大型语言模型(LLM)应用开发中常见且高效的一种设计思路。其核心理念是:将复杂的任务 分解为一系列有机衔接的步骤,每个步骤由一次 LLM 调用完成,并且后续步骤会基于前一步的输出继续处理。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202508/666745-20250830220305312-613348436.png" alt="image" width="1380" height="290" loading="lazy"></p>
<p>提示链(Prompt Chaining)模式 在以下几类场景中尤为适用:</p>
<ul>
<li>任务复杂度高:当问题难以一次性解决时,可以将其拆解为一系列更简单、可控的步骤;</li>
<li>需要逐步验证:每个中间输出都可能需要检查、修正或转换,确保最终结果的准确性;</li>
<li>保持清晰链路:通过分步骤衔接,能够清楚追踪数据或逻辑的流转过程,避免“黑箱式”结果。</li>
</ul>
<p>例如,下述案例展示了一个针对 文本中数值数据处理 的四步工作流:</p>
<ol>
<li>提取数值和指标 —— 从原始文本中识别出数字及其对应的含义;</li>
<li>标准化格式 —— 将不同表示方式统一为百分比格式,确保结果一致;</li>
<li>排序处理 —— 按照数值大小进行降序排序,便于后续分析;</li>
<li>结果输出 —— 将整理好的数据转换为 Markdown 表格,便于展示与阅读。</li>
</ol>
<p>通过这种链式调用方式,复杂的数据处理过程被拆分为结构清晰、可追踪的步骤,既提升了 准确性和可维护性,又让开发者能够灵活地对每一环节进行优化和扩展。</p>
<p>具体实现代码如下所示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ChainWorkflow {
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* Array of system prompts that define the transformation steps in the chain.
* Each prompt acts as a gate that validates and transforms the output before
* proceeding to the next step.
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String[] DEFAULT_SYSTEM_PROMPTS =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Step 1</span>
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Extract only the numerical values and their associated metrics from the text.
Format each as</span>'value: metric' on a <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> line.
Example format:
</span>92<span style="color: rgba(0, 0, 0, 1)">: customer satisfaction
</span>45%: revenue growth""",
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Step 2</span>
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Convert all numerical values to percentages where possible.
If not a percentage or points, convert to decimal (e.g., </span>92 points -> 92%<span style="color: rgba(0, 0, 0, 1)">).
Keep one number per line.
Example format:
</span>92%<span style="color: rgba(0, 0, 0, 1)">: customer satisfaction
</span>45%: revenue growth""",
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Step 3</span>
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Sort all lines in descending order by numerical value.
Keep the format </span>'value: metric'<span style="color: rgba(0, 0, 0, 1)"> on each line.
Example:
</span>92%<span style="color: rgba(0, 0, 0, 1)">: customer satisfaction
</span>87%: employee satisfaction""",
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Step 4</span>
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Format the sorted data as a markdown table with columns:
</span>| Metric | Value |
|:--|--:|
| Customer Satisfaction | 92% | <span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ChatClient chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> String[] systemPrompts;
</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ChainWorkflow(ChatClient chatClient) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">(chatClient, DEFAULT_SYSTEM_PROMPTS);
}
</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ChainWorkflow(ChatClient chatClient, String[] systemPrompts) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.chatClient =<span style="color: rgba(0, 0, 0, 1)"> chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.systemPrompts =<span style="color: rgba(0, 0, 0, 1)"> systemPrompts;
}
</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String chain(String userInput) {
</span><span style="color: rgba(0, 0, 255, 1)">int</span> step = 0<span style="color: rgba(0, 0, 0, 1)">;
String response </span>=<span style="color: rgba(0, 0, 0, 1)"> userInput;
System.out.println(String.format(</span>"\nSTEP %s:\n %s", step++<span style="color: rgba(0, 0, 0, 1)">, response));
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (String prompt : systemPrompts) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1. Compose the input using the response from the previous step.</span>
String input = String.format("{%s}\n {%s}"<span style="color: rgba(0, 0, 0, 1)">, prompt, response);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 2. Call the chat client with the new input and get the new response.</span>
response =<span style="color: rgba(0, 0, 0, 1)"> chatClient.prompt(input).call().content();
System.out.println(String.format(</span>"\nSTEP %s:\n %s", step++<span style="color: rgba(0, 0, 0, 1)">, response));
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> response;
}
}</span></pre>
</div>
<p>主服务入口代码实现:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.CommandLineRunner;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.SpringApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.autoconfigure.SpringBootApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Bean;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> PROPMT CHAINING WORKFLOW
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------</span>
<span style="color: rgba(0, 0, 0, 1)">
@SpringBootApplication
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Application {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
SpringApplication.run(Application.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}
String report </span>= <span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Q3 Performance Summary:
Our customer satisfaction score rose to </span>92 points <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> quarter.
Revenue grew by </span>45%<span style="color: rgba(0, 0, 0, 1)"> compared to last year.
Market share is now at </span>23%<span style="color: rgba(0, 0, 0, 1)"> in our primary market.
Customer churn decreased to </span>5% from 8%<span style="color: rgba(0, 0, 0, 1)">.
New user acquisition cost is $</span>43<span style="color: rgba(0, 0, 0, 1)"> per user.
Product adoption rate increased to </span>78%<span style="color: rgba(0, 0, 0, 1)">.
Employee satisfaction is at </span>87<span style="color: rgba(0, 0, 0, 1)"> points.
Operating margin improved to </span>34%<span style="color: rgba(0, 0, 0, 1)">.
</span>""";
<span style="color: rgba(0, 0, 0, 1)">
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> args -><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ChainWorkflow(chatClientBuilder.build()).chain(report);
};
}
}</span></pre>
</div>
<p>该示例通过一系列提示来处理第三季度的绩效报告。以下是示例输入:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Q3 Performance Summary:
Our customer satisfaction score rose to </span>92 points <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> quarter.
Revenue grew by </span>45%<span style="color: rgba(0, 0, 0, 1)"> compared to last year.
Market share is now at </span>23%<span style="color: rgba(0, 0, 0, 1)"> in our primary market.
Customer churn decreased to </span>5% from 8%<span style="color: rgba(0, 0, 0, 1)">.
New user acquisition cost is $</span>43<span style="color: rgba(0, 0, 0, 1)"> per user.
Product adoption rate increased to </span>78%<span style="color: rgba(0, 0, 0, 1)">.
Employee satisfaction is at </span>87<span style="color: rgba(0, 0, 0, 1)"> points.
Operating margin improved to </span>34%.</pre>
</div>
<p>工作流程通过四个步骤来处理此问题:</p>
<p><strong>1.提取值</strong>:提取数值及其指标</p>
<div class="cnblogs_code">
<pre>92<span style="color: rgba(0, 0, 0, 1)">: customer satisfaction
</span>45%<span style="color: rgba(0, 0, 0, 1)">: revenue growth
</span>23%<span style="color: rgba(0, 0, 0, 1)">: market share
</span>5%<span style="color: rgba(0, 0, 0, 1)">: customer churn
</span>43<span style="color: rgba(0, 0, 0, 1)">: user acquisition cost
</span>78%<span style="color: rgba(0, 0, 0, 1)">: product adoption
</span>87<span style="color: rgba(0, 0, 0, 1)">: employee satisfaction
</span>34%: operating margin</pre>
</div>
<p><strong>2.标准化格式</strong>:将适用的值转换为百分比</p>
<div class="cnblogs_code">
<pre>92%<span style="color: rgba(0, 0, 0, 1)">: customer satisfaction
</span>45%<span style="color: rgba(0, 0, 0, 1)">: revenue growth
</span>23%<span style="color: rgba(0, 0, 0, 1)">: market share
</span>5%<span style="color: rgba(0, 0, 0, 1)">: customer churn
</span>78%<span style="color: rgba(0, 0, 0, 1)">: product adoption
</span>87%<span style="color: rgba(0, 0, 0, 1)">: employee satisfaction
</span>34%: operating margin</pre>
</div>
<p><strong>3.排序</strong>:按降序排列值</p>
<div class="cnblogs_code">
<pre>92%<span style="color: rgba(0, 0, 0, 1)">: customer satisfaction
</span>87%<span style="color: rgba(0, 0, 0, 1)">: employee satisfaction
</span>78%<span style="color: rgba(0, 0, 0, 1)">: product adoption
</span>45%<span style="color: rgba(0, 0, 0, 1)">: revenue growth
</span>34%<span style="color: rgba(0, 0, 0, 1)">: operating margin
</span>23%<span style="color: rgba(0, 0, 0, 1)">: market share
</span>5%: customer churn</pre>
</div>
<p><strong>4.格式</strong>:创建 markdown 表</p>
<div class="cnblogs_code">
<pre>| Metric | Value |
|:--|--:|
| Customer Satisfaction | 92% |
| Employee Satisfaction | 87% |
| Product Adoption | 78% |
| Revenue Growth | 45% |
| Operating Margin | 34% |
| Market Share | 23% |
| Customer Churn | 5% |</pre>
</div>
<h2>3.2 评估器-优化器智能体</h2>
<p><img src="https://img2024.cnblogs.com/blog/666745/202508/666745-20250830221026760-1846812202.png" alt="image" width="1380" height="380" loading="lazy"></p>
<p>评估器–优化器模式(Evaluator–Optimizer Pattern) 是一种典型的 双 LLM 协作工作流。它模拟了人类作者“写—审—改”的迭代过程:一个模型负责生成候选答案,另一个模型则充当评估员,给出改进建议,二者循环迭代,直到得到令人满意的结果。</p>
<p>该模式包含两个核心组件:</p>
<ul>
<li>生成器 LLM(Optimizer/Generator):负责为任务生成初始响应,并在收到反馈后进行改进;</li>
<li>评估员 LLM(Evaluator):根据预设的质量标准(如准确性、逻辑性、风格或完整性)对响应进行分析,并输出具体的改进意见。</li>
</ul>
<p>工作机制如下:</p>
<ul>
<li>初始生成 —— 生成器 LLM 根据任务需求给出初稿;</li>
<li>质量评估 —— 评估员 LLM 审查初稿,基于评估标准给出反馈;</li>
<li>改进迭代 —— 如果结果不符合要求,生成器根据反馈重新生成内容;</li>
<li>收敛输出 —— 当评估员确认结果达到满意水平时,最终答案被采纳。</li>
</ul>
<p>这种模式的优势在于:</p>
<ul>
<li>提升结果质量:避免“一次性生成”的粗糙输出,通过多轮改进获得更佳结果;</li>
<li>增强鲁棒性:减少模型幻觉或逻辑错误;</li>
<li>灵活性高:评估标准可以根据不同任务(如代码正确性、文本风格、数据完整性)进行定制。</li>
</ul>
<p>应用场景示例:</p>
<ul>
<li>内容创作:生成文章后由评估员检查逻辑流畅性和语言风格,再反复打磨;</li>
<li>代码生成:评估员负责检测语法错误和单元测试结果,生成器根据反馈修复代码;</li>
<li>问答系统:确保答案不仅正确,还要清晰、全面。</li>
</ul>
<p>简而言之,评估器–优化器模式就像“作者与编辑”的协作,前者负责创作,后者负责把关,两者交替工作,最终产出高质量成果。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202508/666745-20250830221232237-841473455.png" alt="image" width="530" height="500" loading="lazy"></p>
<p>评估器–优化器模式 在以下场景中特别适用:</p>
<ul>
<li>有明确的质量标准:当任务结果能够通过清晰的指标(如正确性、逻辑性、风格或一致性)进行评估时;</li>
<li>迭代能带来显著改进:输出质量在多轮反馈中能逐步优化,而不是“一次生成定型”;</li>
<li>任务需要深度审查:复杂问题往往需要多轮批评与修正,才能得到高质量的结果。</li>
</ul>
<p>示例应用</p>
<ul>
<li>文学翻译:在直译之外捕捉语境和风格的细微差别,通过多轮优化更贴近原文意境;</li>
<li>复杂搜索与分析:如学术研究或市场调研,需要多次筛选、比对和总结;</li>
<li>代码生成与调试:初始生成后经过系统性审查,逐步修复语法错误、逻辑漏洞或性能问题;</li>
<li>内容创作:写作往往需要多次草稿与润色,模型在迭代过程中可不断提升逻辑连贯性和表达质量。</li>
</ul>
<p>简而言之,当任务 可以被客观评估 且 质量提升依赖迭代打磨 时,这种模式能显著提高最终成果的可靠性与可用性。</p>
<p>具体实现代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.ArrayList;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.List;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.StringJoiner;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.util.Assert;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.slf4j.Logger;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.slf4j.LoggerFactory;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> EvaluatorOptimizer {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Logger logger = LoggerFactory.getLogger(EvaluatorOptimizer.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String DEFAULT_GENERATOR_PROMPT = <span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Your goal is to complete the task based on the input. If there are feedback
from your previous generations, you should reflect on them to improve your solution.
CRITICAL: Your response must be a SINGLE LINE of valid JSON with NO LINE BREAKS except those explicitly escaped with \\n.
Here is the exact format to follow, including all quotes and braces:
{</span>"thoughts":"Brief description here","response":"public class Example {\\n // Code here\\n}"<span style="color: rgba(0, 0, 0, 1)">}
Rules </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> the response field:
</span>1<span style="color: rgba(0, 0, 0, 1)">. ALL line breaks must use \\n
</span>2. ALL quotes must use \\<span style="color: rgba(0, 0, 0, 1)">"
</span> 3<span style="color: rgba(0, 0, 0, 1)">. ALL backslashes must be doubled: \\
</span>4. NO actual line breaks or formatting -<span style="color: rgba(0, 0, 0, 1)"> everything on one line
</span>5<span style="color: rgba(0, 0, 0, 1)">. NO tabs or special characters
</span>6<span style="color: rgba(0, 0, 0, 1)">. Java code must be complete and properly escaped
Example of properly formatted response:
{</span>"thoughts":"Implementing counter","response":"public class Counter {\\n private int count;\\n public Counter() {\\n count = 0;\\n }\\n public void increment() {\\n count++;\\n }\\n}"<span style="color: rgba(0, 0, 0, 1)">}
Follow </span><span style="color: rgba(0, 0, 255, 1)">this</span> format EXACTLY -<span style="color: rgba(0, 0, 0, 1)"> your response must be valid JSON on a single line.
</span>""";
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String DEFAULT_EVALUATOR_PROMPT = <span style="color: rgba(0, 0, 0, 1)">"""
</span> Evaluate <span style="color: rgba(0, 0, 255, 1)">this</span> code implementation <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> correctness, time complexity, and best practices.
Ensure the code have proper javadoc documentation.
Respond with EXACTLY </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> JSON format on a single line:
{</span>"evaluation":"PASS, NEEDS_IMPROVEMENT, or FAIL", "feedback":"Your feedback here"<span style="color: rgba(0, 0, 0, 1)">}
The evaluation field must be one of: </span>"PASS", "NEEDS_IMPROVEMENT", "FAIL"<span style="color: rgba(0, 0, 0, 1)">
Use </span>"PASS" only <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> all criteria are met with no improvements needed.
</span>""";
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">int</span> MAX_ITERATIONS = 10<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">enum</span><span style="color: rgba(0, 0, 0, 1)"> Evaluation {
PASS, NEEDS_IMPROVEMENT, FAIL
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record EvaluationResponse(Evaluation evaluation, String feedback) {}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> record RefinedResponse(String solution, List<Generation><span style="color: rgba(0, 0, 0, 1)"> chainOfThought) {}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record Generation(String thoughts, String response) {}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ChatClient chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> String generatorPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> String evaluatorPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> maxIterations;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> EvaluatorOptimizer(ChatClient chatClient) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">(chatClient, DEFAULT_GENERATOR_PROMPT, DEFAULT_EVALUATOR_PROMPT, MAX_ITERATIONS);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt, String evaluatorPrompt) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">(chatClient, generatorPrompt, evaluatorPrompt, MAX_ITERATIONS);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt,
String evaluatorPrompt, </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> maxIterations) {
Assert.notNull(chatClient, </span>"ChatClient must not be null"<span style="color: rgba(0, 0, 0, 1)">);
Assert.hasText(generatorPrompt, </span>"Generator prompt must not be empty"<span style="color: rgba(0, 0, 0, 1)">);
Assert.hasText(evaluatorPrompt, </span>"Evaluator prompt must not be empty"<span style="color: rgba(0, 0, 0, 1)">);
Assert.isTrue(maxIterations </span>> 0, "Max iterations must be positive"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.chatClient =<span style="color: rgba(0, 0, 0, 1)"> chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.generatorPrompt =<span style="color: rgba(0, 0, 0, 1)"> generatorPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.evaluatorPrompt =<span style="color: rgba(0, 0, 0, 1)"> evaluatorPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.maxIterations =<span style="color: rgba(0, 0, 0, 1)"> maxIterations;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RefinedResponse loop(String task) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> loop(task, <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<>(), <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<>(), 0<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> RefinedResponse loop(String task, List<String><span style="color: rgba(0, 0, 0, 1)"> memory,
List</span><Generation> chainOfThought, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> iteration) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (iteration >=<span style="color: rgba(0, 0, 0, 1)"> maxIterations) {
logger.warn(</span>"Max iterations ({}) reached without finding a PASS solution"<span style="color: rgba(0, 0, 0, 1)">, maxIterations);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RefinedResponse(getBestSolution(memory), chainOfThought);
}
String context </span>=<span style="color: rgba(0, 0, 0, 1)"> buildContext(memory, chainOfThought);
Generation generation </span>=<span style="color: rgba(0, 0, 0, 1)"> generate(task, context);
memory.add(generation.response());
chainOfThought.add(generation);
EvaluationResponse evaluation </span>=<span style="color: rgba(0, 0, 0, 1)"> evaluate(generation.response(), task);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (evaluation.evaluation() ==<span style="color: rgba(0, 0, 0, 1)"> Evaluation.PASS) {
logger.info(</span>"Solution accepted after {} iterations", iteration + 1<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RefinedResponse(generation.response(), chainOfThought);
}
logger.debug(</span>"Iteration {}: Evaluation {}", iteration + 1<span style="color: rgba(0, 0, 0, 1)">, evaluation.evaluation());
</span><span style="color: rgba(0, 0, 255, 1)">return</span> loop(task, memory, chainOfThought, iteration + 1<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> String buildContext(List<String> memory, List<Generation><span style="color: rgba(0, 0, 0, 1)"> chainOfThought) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (memory.isEmpty()) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> ""<span style="color: rgba(0, 0, 0, 1)">;
}
StringJoiner context </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> StringJoiner("\n"<span style="color: rgba(0, 0, 0, 1)">);
context.add(</span>"Previous attempts and feedback:"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < memory.size(); i++<span style="color: rgba(0, 0, 0, 1)">) {
context.add(String.format(</span>"Attempt %d:", i + 1<span style="color: rgba(0, 0, 0, 1)">));
context.add(</span>"Code: " +<span style="color: rgba(0, 0, 0, 1)"> memory.get(i));
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i <<span style="color: rgba(0, 0, 0, 1)"> chainOfThought.size()) {
context.add(</span>"Thoughts: " +<span style="color: rgba(0, 0, 0, 1)"> chainOfThought.get(i).thoughts());
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> context.toString();
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Generation generate(String task, String context) {
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
Generation generation </span>=<span style="color: rgba(0, 0, 0, 1)"> chatClient.prompt()
.user(u </span>-> u.text("{prompt}\n{context}\nTask: {task}"<span style="color: rgba(0, 0, 0, 1)">)
.param(</span>"prompt"<span style="color: rgba(0, 0, 0, 1)">, generatorPrompt)
.param(</span>"context"<span style="color: rgba(0, 0, 0, 1)">, context)
.param(</span>"task"<span style="color: rgba(0, 0, 0, 1)">, task))
.call()
.entity(Generation.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
logGeneration(generation);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> generation;
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
logger.error(</span>"Generation failed for task: {}"<span style="color: rgba(0, 0, 0, 1)">, task, e);
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Failed to generate solution"<span style="color: rgba(0, 0, 0, 1)">, e);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> EvaluationResponse evaluate(String content, String task) {
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
EvaluationResponse evaluation </span>=<span style="color: rgba(0, 0, 0, 1)"> chatClient.prompt()
.user(u </span>-> u.text("{prompt}\nOriginal task: {task}\nContent to evaluate: {content}"<span style="color: rgba(0, 0, 0, 1)">)
.param(</span>"prompt"<span style="color: rgba(0, 0, 0, 1)">, evaluatorPrompt)
.param(</span>"task"<span style="color: rgba(0, 0, 0, 1)">, task)
.param(</span>"content"<span style="color: rgba(0, 0, 0, 1)">, content))
.call()
.entity(EvaluationResponse.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
logEvaluation(evaluation);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> evaluation;
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
logger.error(</span>"Evaluation failed for content: {}"<span style="color: rgba(0, 0, 0, 1)">, content, e);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> EvaluationResponse(Evaluation.NEEDS_IMPROVEMENT,
</span>"Evaluation service unavailable. Please review the code manually."<span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> logGeneration(Generation generation) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (logger.isDebugEnabled()) {
logger.debug(</span>"\n=== GENERATOR OUTPUT ===\nTHOUGHTS: {}\n\nRESPONSE:\n{}\n"<span style="color: rgba(0, 0, 0, 1)">,
generation.thoughts(), generation.response());
}
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> logEvaluation(EvaluationResponse evaluation) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (logger.isDebugEnabled()) {
logger.debug(</span>"\n=== EVALUATOR OUTPUT ===\nEVALUATION: {}\n\nFEEDBACK: {}\n"<span style="color: rgba(0, 0, 0, 1)">,
evaluation.evaluation(), evaluation.feedback());
}
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> String getBestSolution(List<String><span style="color: rgba(0, 0, 0, 1)"> solutions) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> solutions.isEmpty() ? "" : solutions.get(solutions.size() - 1<span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<p>主服务入口代码实现:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.example.agentic.EvaluatorOptimizer.RefinedResponse;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.CommandLineRunner;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.SpringApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.autoconfigure.SpringBootApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Bean;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> EVALUATOR-OPTIMIZER
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------</span>
<span style="color: rgba(0, 0, 0, 1)">
@SpringBootApplication
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Application {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
SpringApplication.run(Application.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
var chatClient </span>=<span style="color: rgba(0, 0, 0, 1)"> chatClientBuilder.build();
</span><span style="color: rgba(0, 0, 255, 1)">return</span> args -><span style="color: rgba(0, 0, 0, 1)"> {
RefinedResponse refinedResponse </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> EvaluatorOptimizer(chatClient).loop(<span style="color: rgba(0, 0, 0, 1)">"""
</span> <user input><span style="color: rgba(0, 0, 0, 1)">
Implement a Stack in Java with:
</span>1<span style="color: rgba(0, 0, 0, 1)">. push(x)
</span>2<span style="color: rgba(0, 0, 0, 1)">. pop()
</span>3<span style="color: rgba(0, 0, 0, 1)">. getMin()
All operations should be O(</span>1<span style="color: rgba(0, 0, 0, 1)">).
All inner fields should be </span><span style="color: rgba(0, 0, 255, 1)">private</span> and when used should be prefixed with 'this.'<span style="color: rgba(0, 0, 0, 1)">.
</span></user input>
""");
<span style="color: rgba(0, 0, 0, 1)">
System.out.println(</span>"FINAL OUTPUT:\n : " +<span style="color: rgba(0, 0, 0, 1)"> refinedResponse);
};
}
}</span></pre>
</div>
<h2>3.3 协调器-工作者智能体</h2>
<p><img src="https://img2024.cnblogs.com/blog/666745/202508/666745-20250830221947730-1748704086.png" alt="image" width="1321" height="330" loading="lazy"></p>
<p> </p>
<p>Orchestrator–Workers 模式 是一种灵活且强大的工作流结构,专为 需要动态任务分解和专门处理的复杂任务 而设计。它借鉴了现实世界中的“项目经理 + 专业团队”协作模式,将任务拆解、分配和合并,最终形成高质量的解决方案。</p>
<p>该模式通常包含三个核心组件:</p>
<ul>
<li>协调器(Orchestrator):作为中央 LLM,负责理解整体任务,识别所需的子任务,并将它们分配给合适的 Worker;</li>
<li>工作者(Workers):一组专门化的 LLM,每个 Worker 负责解决特定子任务(如数据分析、写作、代码生成等);</li>
<li>合成器(Synthesizer):整合所有 Worker 的输出,对结果进行统一、归纳和优化,形成最终答案。</li>
</ul>
<p>该模式在以下场景中尤其有效:</p>
<ul>
<li>任务难以预先规划:当子任务结构不确定、需要运行中动态拆解时;</li>
<li>需要多种方法或视角:例如既要逻辑推理,又要创造性写作;</li>
<li>强调适应性的问题:面对信息不完整或需求变化的任务,能够灵活调整策略;</li>
<li>专业化处理能提升结果质量:如不同 Worker 分别处理数据检索、知识推理和结果润色。</li>
</ul>
<p>应用示例</p>
<ul>
<li>多学科研究:协调器将问题拆解为文献检索、数据分析和总结,交由不同 Worker 执行;</li>
<li>内容生成:如撰写长文,协调器负责分解大纲,Worker 生成各章节,合成器最终汇总润色;</li>
<li>软件开发:协调器拆分需求,Worker 负责代码编写、单元测试与文档撰写,合成器整合成完整项目。</li>
</ul>
<p>简而言之,Orchestrator–Workers 模式就像一个“AI 项目团队”:协调器是项目经理,Workers 是领域专家,合成器则是总编辑,三者协作确保任务既能 分工明确 又能 产出高效。</p>
<p>具体实现代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.List;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.util.Assert;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> OrchestratorWorkers {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ChatClient chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> String orchestratorPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> String workerPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String DEFAULT_ORCHESTRATOR_PROMPT = <span style="color: rgba(0, 0, 0, 1)">"""
</span> Analyze <span style="color: rgba(0, 0, 255, 1)">this</span> task and <span style="color: rgba(0, 0, 255, 1)">break</span> it down into 2-3<span style="color: rgba(0, 0, 0, 1)"> distinct approaches:
Task: {task}
Return your response in </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> JSON format:
\\{
</span>"analysis": "Explain your understanding of the task and which variations would be valuable.
Focus on how each approach serves different aspects of the task.",
"tasks"<span style="color: rgba(0, 0, 0, 1)">: [
\\{
</span>"type": "formal"<span style="color: rgba(0, 0, 0, 1)">,
</span>"description": "Write a precise, technical version that emphasizes specifications"<span style="color: rgba(0, 0, 0, 1)">
\\},
\\{
</span>"type": "conversational"<span style="color: rgba(0, 0, 0, 1)">,
</span>"description": "Write an engaging, friendly version that connects with readers"<span style="color: rgba(0, 0, 0, 1)">
\\}
]
\\}
</span>""";
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String DEFAULT_WORKER_PROMPT = <span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Generate content based on:
Task: {original_task}
Style: {task_type}
Guidelines: {task_description}
</span>""";
<span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* Represents a subtask identified by the orchestrator that needs to be executed
* by a worker.
*
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> type The type or category of the task (e.g., "formal",
* "conversational")
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> description Detailed description of what the worker should accomplish
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> record Task(String type, String description) {
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* Response from the orchestrator containing task analysis and breakdown into
* subtasks.
*
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> analysis Detailed explanation of the task and how different approaches
* serve its aspects
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> tasks List of subtasks identified by the orchestrator to be
* executed by workers
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> record OrchestratorResponse(String analysis, List<Task><span style="color: rgba(0, 0, 0, 1)"> tasks) {
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> record FinalResponse(String analysis, List<String><span style="color: rgba(0, 0, 0, 1)"> workerResponses) {
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> OrchestratorWorkers(ChatClient chatClient) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">(chatClient, DEFAULT_ORCHESTRATOR_PROMPT, DEFAULT_WORKER_PROMPT);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> OrchestratorWorkers(ChatClient chatClient, String orchestratorPrompt, String workerPrompt) {
Assert.notNull(chatClient, </span>"ChatClient must not be null"<span style="color: rgba(0, 0, 0, 1)">);
Assert.hasText(orchestratorPrompt, </span>"Orchestrator prompt must not be empty"<span style="color: rgba(0, 0, 0, 1)">);
Assert.hasText(workerPrompt, </span>"Worker prompt must not be empty"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.chatClient =<span style="color: rgba(0, 0, 0, 1)"> chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.orchestratorPrompt =<span style="color: rgba(0, 0, 0, 1)"> orchestratorPrompt;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.workerPrompt =<span style="color: rgba(0, 0, 0, 1)"> workerPrompt;
}
@SuppressWarnings(</span>"null"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> FinalResponse process(String taskDescription) {
Assert.hasText(taskDescription, </span>"Task description must not be empty"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Step 1: Get orchestrator response</span>
OrchestratorResponse orchestratorResponse = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.chatClient.prompt()
.user(u </span>-> u.text(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.orchestratorPrompt)
.param(</span>"task"<span style="color: rgba(0, 0, 0, 1)">, taskDescription))
.call()
.entity(OrchestratorResponse.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
System.out.println(String.format(</span>"\n=== ORCHESTRATOR OUTPUT ===\nANALYSIS: %s\n\nTASKS: %s\n"<span style="color: rgba(0, 0, 0, 1)">,
orchestratorResponse.analysis(), orchestratorResponse.tasks()));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Step 2: Process each task</span>
List<String> workerResponses = orchestratorResponse.tasks().stream().map(task -> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.chatClient.prompt()
.user(u </span>-> u.text(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.workerPrompt)
.param(</span>"original_task"<span style="color: rgba(0, 0, 0, 1)">, taskDescription)
.param(</span>"task_type"<span style="color: rgba(0, 0, 0, 1)">, task.type())
.param(</span>"task_description"<span style="color: rgba(0, 0, 0, 1)">, task.description()))
.call()
.content()).toList();
System.out.println(</span>"\n=== WORKER OUTPUT ===\n" +<span style="color: rgba(0, 0, 0, 1)"> workerResponses);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FinalResponse(orchestratorResponse.analysis(), workerResponses);
}
}</span></pre>
</div>
<p>主服务入口代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.CommandLineRunner;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.SpringApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.autoconfigure.SpringBootApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Bean;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ORCHESTRATOR WORKERS
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------</span>
<span style="color: rgba(0, 0, 0, 1)">
@SpringBootApplication
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Application {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
SpringApplication.run(Application.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
var chatClient </span>=<span style="color: rgba(0, 0, 0, 1)"> chatClientBuilder.build();
</span><span style="color: rgba(0, 0, 255, 1)">return</span> args -><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OrchestratorWorkers(chatClient)
.process(</span>"Write a product description for a new eco-friendly water bottle"<span style="color: rgba(0, 0, 0, 1)">);
};
}
}</span></pre>
</div>
<h2>3.4 并行化智能体</h2>
<p><img src="https://img2024.cnblogs.com/blog/666745/202508/666745-20250830222334894-1352837330.png" alt="image" width="1321" height="330" loading="lazy"></p>
<p>并行化工作流模式是一种提高大型语言模型(LLM)处理效率与结果质量的策略,其核心思想是 同时执行多个任务或多次调用,以加快处理速度并获取更多视角。该模式主要体现在两个方面:</p>
<ul>
<li>分段(Segmentation)
<ul>
<li>将复杂任务拆分为相互独立的子任务,使其能够并行处理,减少单个任务的执行瓶颈。</li>
</ul>
</li>
<li>投票(Voting / Ensemble)
<ul>
<li>对同一任务进行多次并行调用,以生成不同版本的响应,然后通过多数决、加权或其他策略选出最优结果,从而获得更可靠和多样化的答案。</li>
</ul>
</li>
</ul>
<p>主要优点</p>
<ul>
<li>提升吞吐量:并行处理多个子任务或调用,提高整体任务处理速度;</li>
<li>优化资源利用:充分利用 LLM API 或计算资源,避免单线程浪费;</li>
<li>缩短批量任务时间:相比串行处理,大幅降低整体执行时长;</li>
<li>提高结果质量:通过多视角、多样化输出,结合投票机制,可显著改善准确性和稳健性。</li>
</ul>
<p>应用示例</p>
<ul>
<li>文本分析:将长文拆分为段落并行分析,最后汇总结果;</li>
<li>内容生成:对同一写作任务多次生成不同版本,通过投票选择最优稿件;</li>
<li>问答系统:对复杂问题进行多次推理,整合答案以减少偏差;</li>
<li>数据标注:多个模型或提示并行执行标注任务,再通过多数投票提高标注一致性。</li>
</ul>
<p>并行化模式就像团队协作中的分工+讨论机制:既能让每个成员(LLM调用)专注完成独立任务,又能通过多方意见汇总,获得更全面、更可靠的最终成果。</p>
<p>具体实现代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.List;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.CompletableFuture;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.ExecutorService;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.Executors;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.stream.Collectors;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.util.Assert;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ParallelizationlWorkflow {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ChatClient chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ParallelizationlWorkflow(ChatClient chatClient) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.chatClient =<span style="color: rgba(0, 0, 0, 1)"> chatClient;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<String> parallel(String prompt, List<String> inputs, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> nWorkers) {
Assert.notNull(prompt, </span>"Prompt cannot be null"<span style="color: rgba(0, 0, 0, 1)">);
Assert.notEmpty(inputs, </span>"Inputs list cannot be empty"<span style="color: rgba(0, 0, 0, 1)">);
Assert.isTrue(nWorkers </span>> 0, "Number of workers must be greater than 0"<span style="color: rgba(0, 0, 0, 1)">);
ExecutorService executor </span>=<span style="color: rgba(0, 0, 0, 1)"> Executors.newFixedThreadPool(nWorkers);
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
List</span><CompletableFuture<String>> futures =<span style="color: rgba(0, 0, 0, 1)"> inputs.stream()
.map(input </span>-> CompletableFuture.supplyAsync(() -><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> chatClient.prompt(prompt + "\nInput: " +<span style="color: rgba(0, 0, 0, 1)"> input).call().content();
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Failed to process input: " +<span style="color: rgba(0, 0, 0, 1)"> input, e);
}
}, executor))
.collect(Collectors.toList());
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Wait for all tasks to complete</span>
CompletableFuture<Void> allFutures =<span style="color: rgba(0, 0, 0, 1)"> CompletableFuture.allOf(
futures.toArray(CompletableFuture[]::</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">));
allFutures.join();
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
} </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
executor.shutdown();
}
}
}</span></pre>
</div>
<p>主服务入口代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.List;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.CommandLineRunner;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.SpringApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.autoconfigure.SpringBootApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Bean;
@SpringBootApplication
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Application {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
SpringApplication.run(Application.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> args -><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> PARALLEL WORKFLOW
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------</span>
<span style="color: rgba(0, 0, 0, 1)">
List</span><String> parallelResponse = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ParallelizationlWorkflow(chatClientBuilder.build())
.parallel(</span><span style="color: rgba(0, 0, 0, 1)">"""
</span> Analyze how market changes will impact <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> stakeholder group.
Provide specific impacts and recommended actions.
Format with clear sections and priorities.
</span>""",
<span style="color: rgba(0, 0, 0, 1)"> List.of(
</span><span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Customers:
</span>-<span style="color: rgba(0, 0, 0, 1)"> Price sensitive
</span>-<span style="color: rgba(0, 0, 0, 1)"> Want better tech
</span>-<span style="color: rgba(0, 0, 0, 1)"> Environmental concerns
</span>""",
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Employees:
</span>-<span style="color: rgba(0, 0, 0, 1)"> Job security worries
</span>- Need <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> skills
</span>-<span style="color: rgba(0, 0, 0, 1)"> Want clear direction
</span>""",
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Investors:
</span>-<span style="color: rgba(0, 0, 0, 1)"> Expect growth
</span>-<span style="color: rgba(0, 0, 0, 1)"> Want cost control
</span>-<span style="color: rgba(0, 0, 0, 1)"> Risk concerns
</span>""",
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Suppliers:
</span>-<span style="color: rgba(0, 0, 0, 1)"> Capacity constraints
</span>-<span style="color: rgba(0, 0, 0, 1)"> Price pressures
</span>-<span style="color: rgba(0, 0, 0, 1)"> Tech transitions
</span>"""),
4<span style="color: rgba(0, 0, 0, 1)">);
System.out.println(parallelResponse);
};
}
}</span></pre>
</div>
<h2>3.5 路由智能体</h2>
<p><img src="https://img2024.cnblogs.com/blog/666745/202508/666745-20250830222651265-2100318312.png" alt="image" width="1321" height="330" loading="lazy"></p>
<p> </p>
<p>路由工作流模式(Routing Workflow Pattern) 专为处理复杂任务而设计,尤其适用于 输入类型多样且需要不同处理策略的场景。其核心理念是:利用 LLM 对输入进行分析和分类,然后将其分发到最合适的专用提示符或处理程序,以获得更高效和准确的结果。</p>
<p>主要优点</p>
<ul>
<li>关注点分离:每条路线可以针对特定类型的输入进行优化,避免单一流程处理所有任务导致效率低下;</li>
<li>提高准确性:专门的提示或处理程序能够更好地发挥其优势,提升结果质量;</li>
<li>可扩展架构:轻松新增路线和专门处理模块,系统能够随需求变化灵活扩展;</li>
<li>资源优化:更简单的任务可分配给轻量模型,复杂任务由高性能模型处理,实现计算资源的合理利用。</li>
</ul>
<p>该模式在以下场景尤其有效:</p>
<ul>
<li>输入类型多样:任务涉及不同格式、主题或结构的数据,需要采用不同处理策略;</li>
<li>可分类任务:LLM 能够准确识别输入类型,从而决定路由路径;</li>
<li>专业化需求:不同类型的输入需要不同领域的知识或处理方法,例如技术文档 vs. 创意写作、财务数据 vs. 市场分析。</li>
</ul>
<p>应用示例</p>
<ul>
<li>客户服务:根据问题类型(退货、账单、技术支持)路由到不同的自动回复或处理模块;</li>
<li>内容生成:针对不同主题或风格,路由到特定提示符生成高质量文本;</li>
<li>数据处理:将结构化数据、非结构化文本或图像输入路由到不同的分析模型;</li>
<li>多模态应用:结合文本、音频或图像输入,分别调用最适合的模型进行处理。</li>
</ul>
<p>路由工作流模式就像 智能分拣系统:先判断“物品类型”,再送到最适合的处理通道,从而提高效率、保证质量,并且易于扩展。</p>
<p>具体实现代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record RoutingResponse(
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* The reasoning behind the route selection, explaining why this particular
* route was chosen based on the input analysis.
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
String reasoning,
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* The selected route name that will handle the input based on the
* classification analysis.
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
String selection) {
}</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Map;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.util.Assert;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> RoutingWorkflow {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ChatClient chatClient;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RoutingWorkflow(ChatClient chatClient) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.chatClient =<span style="color: rgba(0, 0, 0, 1)"> chatClient;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> String route(String input, Map<String, String><span style="color: rgba(0, 0, 0, 1)"> routes) {
Assert.notNull(input, </span>"Input text cannot be null"<span style="color: rgba(0, 0, 0, 1)">);
Assert.notEmpty(routes, </span>"Routes map cannot be null or empty"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Determine the appropriate route for the input</span>
String routeKey =<span style="color: rgba(0, 0, 0, 1)"> determineRoute(input, routes.keySet());
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Get the selected prompt from the routes map</span>
String selectedPrompt =<span style="color: rgba(0, 0, 0, 1)"> routes.get(routeKey);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (selectedPrompt == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> IllegalArgumentException("Selected route '" + routeKey + "' not found in routes map"<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Process the input with the selected prompt</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> chatClient.prompt(selectedPrompt + "\nInput: " +<span style="color: rgba(0, 0, 0, 1)"> input).call().content();
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> String determineRoute(String input, Iterable<String><span style="color: rgba(0, 0, 0, 1)"> availableRoutes) {
System.out.println(</span>"\nAvailable routes: " +<span style="color: rgba(0, 0, 0, 1)"> availableRoutes);
String selectorPrompt </span>= String.format(<span style="color: rgba(0, 0, 0, 1)">"""
</span> Analyze the input and select the most appropriate support team from these options: %<span style="color: rgba(0, 0, 0, 1)">s
First explain your reasoning, then provide your selection in </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> JSON format:
\\{
</span>"reasoning": "Brief explanation of why this ticket should be routed to a specific team.
Consider key terms, user intent, and urgency level.",
"selection": "The chosen team name"<span style="color: rgba(0, 0, 0, 1)">
\\}
Input: </span>%s""", availableRoutes, input);
<span style="color: rgba(0, 0, 0, 1)">
RoutingResponse routingResponse </span>= chatClient.prompt(selectorPrompt).call().entity(RoutingResponse.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
System.out.println(String.format(</span>"Routing Analysis:%s\nSelected route: %s"<span style="color: rgba(0, 0, 0, 1)">,
routingResponse.reasoning(), routingResponse.selection()));
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> routingResponse.selection();
}
}</span></pre>
</div>
<p>主服务入口代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.List;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Map;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.ai.chat.client.ChatClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.CommandLineRunner;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.SpringApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.autoconfigure.SpringBootApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Bean;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ROUTER WORKFLOW
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ------------------------------------------------------------</span>
<span style="color: rgba(0, 0, 0, 1)">@SpringBootApplication
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Application {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
SpringApplication.run(Application.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> args -><span style="color: rgba(0, 0, 0, 1)"> {
Map</span><String, String> supportRoutes = Map.of("billing"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> You are a billing support specialist. Follow these guidelines:
</span>1. Always start with "Billing Support Response:"
2<span style="color: rgba(0, 0, 0, 1)">. First acknowledge the specific billing issue
</span>3<span style="color: rgba(0, 0, 0, 1)">. Explain any charges or discrepancies clearly
</span>4<span style="color: rgba(0, 0, 0, 1)">. List concrete next steps with timeline
</span>5. End with payment options <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> relevant
Keep responses professional but friendly.
Input: </span>""",
"technical"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> You are a technical support engineer. Follow these guidelines:
</span>1. Always start with "Technical Support Response:"
2<span style="color: rgba(0, 0, 0, 1)">. List exact steps to resolve the issue
</span>3. Include system requirements <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> relevant
</span>4. Provide workarounds <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> common problems
</span>5. End with escalation path <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> needed
Use clear, numbered steps and technical details.
Input: </span>""",
"account"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> You are an account security specialist. Follow these guidelines:
</span>1. Always start with "Account Support Response:"
2<span style="color: rgba(0, 0, 0, 1)">. Prioritize account security and verification
</span>3. Provide clear steps <span style="color: rgba(0, 0, 255, 1)">for</span> account recovery/<span style="color: rgba(0, 0, 0, 1)">changes
</span>4<span style="color: rgba(0, 0, 0, 1)">. Include security tips and warnings
</span>5. Set clear expectations <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> resolution time
Maintain a serious, security</span>-<span style="color: rgba(0, 0, 0, 1)">focused tone.
Input: </span>""",
"product"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> You are a product specialist. Follow these guidelines:
</span>1. Always start with "Product Support Response:"
2<span style="color: rgba(0, 0, 0, 1)">. Focus on feature education and best practices
</span>3<span style="color: rgba(0, 0, 0, 1)">. Include specific examples of usage
</span>4<span style="color: rgba(0, 0, 0, 1)">. Link to relevant documentation sections
</span>5<span style="color: rgba(0, 0, 0, 1)">. Suggest related features that might help
Be educational and encouraging in tone.
Input: </span>""");
<span style="color: rgba(0, 0, 0, 1)">
List</span><String> tickets =<span style="color: rgba(0, 0, 0, 1)"> List.of(
</span><span style="color: rgba(0, 0, 0, 1)">"""
</span> Subject: Can't access my account
Message: Hi, I've been trying to log in for the past hour but keep getting an 'invalid password' error.
I'm sure I'm using the right password. Can you help me regain access?<span style="color: rgba(0, 0, 0, 1)"> This is urgent as I need to
submit a report by end of day.
</span>- John""",
<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> Subject: Unexpected charge on my card
Message: Hello, I just noticed a charge of .</span>99<span style="color: rgba(0, 0, 0, 1)"> on my credit card from your company, but I thought
I was on the .</span>99 plan. Can you explain <span style="color: rgba(0, 0, 255, 1)">this</span> charge and adjust it <span style="color: rgba(0, 0, 255, 1)">if</span> it's a mistake?
<span style="color: rgba(0, 0, 0, 1)"> Thanks,
Sarah</span>""",
<span style="color: rgba(0, 0, 0, 1)">"""
</span> Subject: How to export data?<span style="color: rgba(0, 0, 0, 1)">
Message: I need to export all my project data to Excel. I</span>'ve looked through the docs but can'<span style="color: rgba(0, 0, 0, 1)">t
figure out how to </span><span style="color: rgba(0, 0, 255, 1)">do</span> a bulk export. Is <span style="color: rgba(0, 0, 255, 1)">this</span> possible? If so, could you walk me through the steps?<span style="color: rgba(0, 0, 0, 1)">
Best regards,
Mike</span>""");
<span style="color: rgba(0, 0, 0, 1)">
var routerWorkflow </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RoutingWorkflow(chatClientBuilder.build());
</span><span style="color: rgba(0, 0, 255, 1)">int</span> i = 1<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (String ticket : tickets) {
System.out.println(</span>"\nTicket " + i++<span style="color: rgba(0, 0, 0, 1)">);
System.out.println(</span>"------------------------------------------------------------"<span style="color: rgba(0, 0, 0, 1)">);
System.out.println(ticket);
System.out.println(</span>"------------------------------------------------------------"<span style="color: rgba(0, 0, 0, 1)">);
System.out.println(routerWorkflow.route(ticket, supportRoutes));
}
};
}
}</span></pre>
</div>
<h1>4.总结</h1>
<p>开发一个高效的智能体,不仅仅是调用大型语言模型,更在于 合理设计工作流、优化任务处理和迭代改进。本文介绍了多种关键模式——从 提示链(Prompt Chaining)、评估器–优化器(Evaluator–Optimizer)、Orchestrator–Workers、并行化 到 路由工作流——每一种方法都有其独特价值,针对不同任务场景提供最佳实践。</p>
<p>通过这些模式的灵活组合,智能体能够实现 复杂任务分解、专业化处理、多轮改进和高效输出,同时提升准确性、可扩展性和资源利用效率。最终,高效智能体的目标是让模型不仅能“完成任务”,还能 以可控、可靠且高质量的方式应对多样化问题。</p>
<h1>5.结束语</h1>
<p>这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!</p>
<p>另外,博主出新书了《<span style="color: rgba(255, 0, 0, 1)"><strong><span style="color: rgba(255, 0, 0, 1)">Hadoop与Spark大数据全景解析</span></strong></span>》、同时已出版的《<span style="color: rgba(0, 0, 255, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">深入理解Hive</span></strong></span>》、《<span style="color: rgba(0, 0, 255, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">Kafka并不难学</span></strong></span>》和《<span style="color: rgba(0, 0, 255, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">Hadoop大数据挖掘从入门到进阶实战</span></strong></span>》也可以和新书配套使用,喜欢的朋友或同学, 可以<span style="color: rgba(255, 0, 0, 1)"><strong>在公告栏那里点击购买链接购买博主的书</strong></span>进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。</p>
</div>
<div id="MySignature" role="contentinfo">
<div>
<b class="b1"></b><b class="b2 d1"></b><b class="b3 d1"></b><b class="b4 d1"></b>
<div class="b d1 k">
联系方式:
<br/>
邮箱:smartloli.org@gmail.com
<br/>
<strong style="color: green">QQ群(Hive与AI实战【新群】):935396818</strong>
<br/>
QQ群(Hadoop - 交流社区1):424769183
<br/>
QQ群(Kafka并不难学):825943084
<br/>
温馨提示:请大家加群的时候写上加群理由(姓名+公司/学校),方便管理员审核,谢谢!
<br/>
<h3>热爱生活,享受编程,与君共勉!</h3>
</div>
<b class="b4b d1"></b><b class="b3b d1"></b><b class="b2b d1"></b><b class="b1b"></b>
</div>
<br>
<div>
<b class="b1"></b><b class="b2 d1"></b><b class="b3 d1"></b><b class="b4 d1"></b>
<div class="b d1 k">
<h3>公众号:</h3>
<h3><img style="width: 8%; margin-left: 10px" src="https://www.cnblogs.com/images/cnblogs_com/smartloli/1324636/t_qr.png"></h3>
</div>
<b class="b4b d1"></b><b class="b3b d1"></b><b class="b2b d1"></b><b class="b1b"></b>
</div>
<br>
<div>
<b class="b1"></b><b class="b2 d1"></b><b class="b3 d1"></b><b class="b4 d1"></b>
<div class="b d1 k">
<h3>作者:哥不是小萝莉 [关于我][犒赏]</h3>
<h3>出处:http://www.cnblogs.com/smartloli/</h3>
<h3>转载请注明出处,谢谢合作!</h3>
</div>
<b class="b4b d1"></b><b class="b3b d1"></b><b class="b2b d1"></b><b class="b1b"></b>
</div><br><br>
来源:https://www.cnblogs.com/smartloli/p/19066323
頁:
[1]