魏惠芳 發表於 2025-11-8 21:15:00

耄大厨——AI厨师智能体(3-程序调用)

<style>pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; line-height: 1.6 !important; padding: 16px !important; margin: 16px 0 !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; tab-size: 4 !important; -moz-tab-size: 4 !important; max-width: 100% !important; box-sizing: border-box !important }
code { font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow-wrap: normal !important; display: inline !important; background: rgba(0, 0, 0, 0) !important; border: none !important; padding: 0 !important; margin: 0 !important; line-height: inherit !important }
pre code { background: rgba(0, 0, 0, 0) !important; border: 0 !important; border-radius: 0 !important; display: block !important; line-height: 1.6 !important; margin: 0 !important; max-width: none !important; overflow: visible !important; padding: 0 !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; color: inherit !important }
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: rgba(112, 128, 144, 1) !important; font-style: italic !important }
.token.punctuation { color: rgba(153, 153, 153, 1) !important }
.token.atrule, .token.attr-value, .token.keyword { color: rgba(0, 119, 170, 1) !important; font-weight: bold !important }
.token.function, .token.class-name { color: rgba(221, 74, 104, 1) !important; font-weight: bold !important }
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: rgba(102, 153, 0, 1) !important }
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: rgba(153, 0, 85, 1) !important }
.cnblogs-markdown pre, .cnblogs-post-body pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; padding: 16px !important; margin: 16px 0 !important }
pre, pre, pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important }</style>
      <div class="markdown_views prism-atom-one-dark" id="content_views"><svg style="display: none" xmlns="http://www.w3.org/2000/svg"><path d="M5,0 0,2.5 5,5z" id="raphael-marker-block" stroke-linecap="round" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0)"></path></svg><p></p><div class="toc"><h4>文章目录</h4><ul><li>工具调用</li><li><ul><li>需求分析</li><li>工具调用介绍</li><li><ul><li>什么是工具调用?</li><li>工具调用的原理</li></ul></li><li>SpringAI工具开发</li><li><ul><li>定义工具</li><li>使用工具</li><li>工具开发</li><li><ul><li>文件操作</li><li>联网搜索</li><li>网页抓取</li><li>终端操作</li><li>资源下载</li><li>PDF生成</li></ul></li><li>集中注册工具</li><li>使用工具</li></ul></li></ul></li></ul></div><p></p><h2>工具调用</h2><p>以Spring Al框架为例,学习AI应用开发的核心特性一工具调用,大幅增强AI的能力,并实战主流工具的开<br> 发,熟悉工具的原理和高级特性。</p><h3>需求分析</h3><p>之前我们的耄大厨项目已经实现了AI对话功能、自定义Advisor、RAG、向量存储,今天我们继续开发一个AI智能体的一个重要功能——<strong>工具调用</strong></p><p>主要开发以下几个工具(你也可以自行进行扩展):</p><ul><li>联网搜索</li><li>网页抓取</li><li>资源下载</li><li>终端操作</li><li>文件操作</li><li>PDF生成</li></ul><p>如果A!能够完成上述需求,就不再只是一个有知识的"大脑”,而是有手有脚,会利用工具完成任务的“智能体”<br> 了。</p><h3>工具调用介绍</h3><h4>什么是工具调用?</h4><p><code>工具调用(Tool Calling)</code>可以理解为让Al大模型<strong>借用外部工具</strong>来完成它自己做不到的事情。</p><p>跟人类一样,如果只凭手脚完成不了工作,那么就可以利用工具箱来完成。</p><p>工具可以是任何东西,比如网页搜索、对外部AP的调用、访问外部数据、或执行特定的代码等。</p><p>目前工具调用技术发展的已经比较成熟了,几乎所有主流的、新出的AI大模型和AI应用开发平台都支持工具调<br> 用。</p><h4>工具调用的原理</h4><p>其实,工具调用的工作原理非常简单,<strong>并不是AI服务器自己调用这些工具、也不是把工具的代码发送给AI服务</strong><br><strong>器让它执行</strong>,它只能提出要求,表示“我需要执行XX工具完成任务”。而真正执行工具的是我们自己的应用程<br> 序,执行后再把结果告诉AI,让它继续工作。</p><p>这里我用SpringAI框架的工具调用来解释:</p><p><img alt="image-20251012133101442" src="https://i-blog.csdnimg.cn/img_convert/9d7fa608ae6958512fbcaedffe7feb34.webp?x-oss-process=image/format,png"></p><ol><li>工具定义与注册:Spring Al可以通过简洁的注解自动生成工具定义和SON Schema,让Java方法轻松转变<br> 为AI可调用的工具。</li><li>工具调用请求:Spring Al自动处理与Al模型的通信并解析工具调用请求,并且支持多个工具链式调用。</li><li>工具执行:Spring Al提供统一的工具管理接口,自动根据Al返回的工具调用请求找到对应的工具并解析参<br> 数进行调用,让开发者专注于业务逻辑实现。</li><li>处理工具结果:Spring Al内置结果转换和异常处理机制,支持各种复杂Java对象作为返回值并优雅处理错误<br> 情况。</li><li>返回结果给模型:Spring Al封装响应结果并管理上下文,确保工具执行结果正确传递给模型或直接返回给用<br> 户。</li><li>生成最终响应:Spring Al自动整合工具调用结果到对话上下文,支持多轮复杂交互,确保Al回复的连贯性<br> 和准确性。</li></ol><h3>SpringAI工具开发</h3><h4>定义工具</h4><p>在Spring AI中,定义工具主要有两种模式:基于Methods方法或者Functions函数式编程。</p><p>记结论就行了,我们只用学习基于<code>Methods</code>方法来定义工具,另外一种了解即可。原因是Methods方式更容易<br> 编写、更容易理解、支持的参数和返回类型更多。</p><table><thead><tr><th>特性</th><th>Methods 方式</th><th>Functions 方式</th></tr></thead><tbody><tr><td>定义方式</td><td>使用 @Tool和 @ToolParam注解标记类方法</td><td>使用函数式接口并通过 Spring Bean 定义</td></tr><tr><td>语法复杂度</td><td>简单,直观</td><td>较复杂,需要定义请求/响应对象</td></tr><tr><td>支持的参数类型</td><td>大多数 Java 类型,包括基本类型、POJO、集合等</td><td>不支持基本类型、Optional、集合类型</td></tr><tr><td>支持的返回类型</td><td>几乎所有可序列化类型,包括 void</td><td>不支持基本类型、Optional、集合类型等</td></tr><tr><td>使用场景</td><td>适合大多数新项目开发</td><td>适合与现有函数式API集成</td></tr><tr><td>注册方式</td><td>支持按需注册和全局注册</td><td>通常在配置类中预先定义</td></tr><tr><td>类型转换</td><td>自动处理</td><td>需要更多手动配置</td></tr><tr><td>文档支持</td><td>通过注解提供描述</td><td>通过Bean描述和JSON属性注解</td></tr></tbody></table><p>举个例子:</p><p>1)Methods模式:通过<code>@Tool</code>注解定义工具,通过<code>tools</code>方法绑定工具</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">class</span> <span class="token class-name">WeatherTools</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Get current weather for a location"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getWeather</span><span class="token punctuation">(</span><span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"The city name"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> city<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">"Current weather in "</span> <span class="token operator">+</span> city <span class="token operator">+</span> <span class="token string">": Sunny, 25°C"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 使用方式</span>
<span class="token class-name">ChatClient</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>chatModel<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">"What's the weather in Beijing?"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">tools</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WeatherTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>2)Functions模式:通过<code>@Bean</code>注解定义工具,通过<code>functions</code>方法绑定工具</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ToolConfig</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Bean</span>
<span class="token annotation punctuation">@Description</span><span class="token punctuation">(</span><span class="token string">"Get current weather for a location"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Function</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">WeatherRequest</span><span class="token punctuation">,</span> <span class="token class-name">WeatherResponse</span><span class="token punctuation">&gt;</span></span> <span class="token function">weatherFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> request <span class="token operator">-&gt;</span> <span class="token keyword">new</span> <span class="token class-name">WeatherResponse</span><span class="token punctuation">(</span><span class="token string">"Weather in "</span> <span class="token operator">+</span> request<span class="token punctuation">.</span><span class="token function">getCity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">": Sunny, 25°C"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 使用方式</span>
<span class="token class-name">ChatClient</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>chatModel<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">"What's the weather in Beijing?"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">functions</span><span class="token punctuation">(</span><span class="token string">"weatherFunction"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>显然Methods模式的开发量更少。</p><h4>使用工具</h4><p>定义好工具后,Spring Al提供了多种灵活的方式将工具提供给ChatClient,让Al能够在需要时调用这些工具。</p><p>1)按需使用:这是最简单的方式,直接在构建ChatClient请求时通过tools()方法附加工具。这种方式适合只<br> 在特定对话中使用某些工具的场景。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token class-name">String</span> response <span class="token operator">=</span> <span class="token class-name">ChatClient</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>chatModel<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">"北京今天天气怎么样?"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">tools</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WeatherTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 在这次对话中提供天气工具</span>
<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">content</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>2)全局使用:如果某些工具需要在所有对话中都可用,可以在构建ChatClient时注册默认工具。这样,这些工具<br> 将对从同一个ChatClient发起的所有对话可用。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token class-name">ChatClient</span> chatClient <span class="token operator">=</span> <span class="token class-name">ChatClient</span><span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span>chatModel<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">defaultTools</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WeatherTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">TimeTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 注册默认工具</span>
<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>3)更底层的使用方式:除了给ChatClient绑定工具外,也可以给更底层的ChatModel绑定工具(毕竟工具调用<br> 是A!大模型支持的能力),适合需要更精细控制的场景。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token comment">// 先得到工具对象</span>
<span class="token class-name">ToolCallback</span><span class="token punctuation">[</span><span class="token punctuation">]</span> weatherTools <span class="token operator">=</span> <span class="token class-name">ToolCallbacks</span><span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WeatherTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 绑定工具到对话</span>
<span class="token class-name">ChatOptions</span> chatOptions <span class="token operator">=</span> <span class="token class-name">ToolCallingChatOptions</span><span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">toolCallbacks</span><span class="token punctuation">(</span>weatherTools<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 构造 Prompt 时指定对话选项</span>
<span class="token class-name">Prompt</span> prompt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Prompt</span><span class="token punctuation">(</span><span class="token string">"北京今天天气怎么样?"</span><span class="token punctuation">,</span> chatOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
chatModel<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>prompt<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h4>工具开发</h4><p>在项目目录下新建<code>tools</code>目录,用于存放我们开发的工具。</p><h5>文件操作</h5><p>文件操作工具主要提供2大功能:保存文件、读取文件。</p><p>由于会影响系统资源,所以我们需要将文件统一存放到一个隔离的目录进行存储,在<code>constant</code>包下新建文件常<br> 量类,约定文件保存目录为项目根目录下的<code>/tmp</code>目录中。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">FileConstant</span> <span class="token punctuation">{</span>
<span class="token comment">//文件保存目录</span>
<span class="token class-name">String</span> FILE_SAVE_DIR <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">getProperty</span><span class="token punctuation">(</span><span class="token string">"user.dir()"</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/tmp"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>编写文件操作工具类,通过注解式定义工具,代码如下:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FileOperationTool</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">String</span> FILE_DIR <span class="token operator">=</span> <span class="token class-name">FileConstant</span><span class="token punctuation">.</span>FILE_SAVE_DIR <span class="token operator">+</span> <span class="token string">"/file"</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Read content from a file"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">readFile</span><span class="token punctuation">(</span><span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Name of the file to read"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> fileName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> filePath <span class="token operator">=</span> FILE_DIR <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> fileName<span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">FileUtil</span><span class="token punctuation">.</span><span class="token function">readUtf8String</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">"Error reading file: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Write content to a file"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">writeFile</span><span class="token punctuation">(</span>
<span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Name of the file to write"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> fileName<span class="token punctuation">,</span>
<span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Content to write to the file"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> filePath <span class="token operator">=</span> FILE_DIR <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> fileName<span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// 创建目录</span>
<span class="token class-name">FileUtil</span><span class="token punctuation">.</span><span class="token function">mkdir</span><span class="token punctuation">(</span>FILE_DIR<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">FileUtil</span><span class="token punctuation">.</span><span class="token function">writeUtf8String</span><span class="token punctuation">(</span>content<span class="token punctuation">,</span> filePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token string">"File written successfully to: "</span> <span class="token operator">+</span> filePath<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">"Error writing to file: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>编写测试类:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FileOperationToolTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testReadFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">FileOperationTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileOperationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> fileName <span class="token operator">=</span> <span class="token string">"耄耄爱哈气"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testWriteFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">FileOperationTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileOperationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> fileName <span class="token operator">=</span> <span class="token string">"耄耄爱哈气.txt"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"https://chengfushi.blog.csdn.net/"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">writeFile</span><span class="token punctuation">(</span>fileName<span class="token punctuation">,</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="image-20251012140446295" src="https://i-blog.csdnimg.cn/img_convert/0ea92b7221577582470765027fdea542.webp?x-oss-process=image/format,png"></p><h5>联网搜索</h5><p>联网搜索工具的作用是根据关键词搜索网页列表。</p><p>我们可以使用专业的网页搜索APIl,如Search API来实现从多个网站搜索内容,这类服务通常按量计费。当然<br> 可以直接使用Google或Big的搜索APl(甚至是通过爬虫和网页解析从某个搜索引擎获取内容)。</p><p>1)阅读Search API的官方文档,重点关注API的请求参数和返回结果。从API返回的结果中,我们只需要提取<br> 关键部分:</p><p><img alt="image-20251012140851441" src="https://i-blog.csdnimg.cn/img_convert/839b177238d7e42edaab1df6f27c8051.webp?x-oss-process=image/format,png"></p><p>2)可以把接口文档喂给AI,让它帮我们生成工具代码,网页搜索工具代码如下:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebSearchTool</span> <span class="token punctuation">{</span>
<span class="token comment">// SearchAPI 的搜索接口地址</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> SEARCH_API_URL <span class="token operator">=</span> <span class="token string">"https://www.searchapi.io/api/v1/search"</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">String</span> apiKey<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">WebSearchTool</span><span class="token punctuation">(</span><span class="token class-name">String</span> apiKey<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>apiKey <span class="token operator">=</span> apiKey<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Search for information from Baidu Search Engine"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">searchWeb</span><span class="token punctuation">(</span>
<span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Search query keyword"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> query<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> paramMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
paramMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"q"</span><span class="token punctuation">,</span> query<span class="token punctuation">)</span><span class="token punctuation">;</span>
paramMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"api_key"</span><span class="token punctuation">,</span> apiKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
paramMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"engine"</span><span class="token punctuation">,</span> <span class="token string">"baidu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> response <span class="token operator">=</span> <span class="token class-name">HttpUtil</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>SEARCH_API_URL<span class="token punctuation">,</span> paramMap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 取出返回结果的前 5 条</span>
<span class="token class-name">JSONObject</span> jsonObject <span class="token operator">=</span> <span class="token class-name">JSONUtil</span><span class="token punctuation">.</span><span class="token function">parseObj</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 提取 organic_results 部分</span>
<span class="token class-name">JSONArray</span> organicResults <span class="token operator">=</span> jsonObject<span class="token punctuation">.</span><span class="token function">getJSONArray</span><span class="token punctuation">(</span><span class="token string">"organic_results"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> objects <span class="token operator">=</span> organicResults<span class="token punctuation">.</span><span class="token function">subList</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 拼接搜索结果为字符串</span>
    <span class="token class-name">String</span> result <span class="token operator">=</span> objects<span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>obj <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>
    <span class="token class-name">JSONObject</span> tmpJSONObject <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">JSONObject</span><span class="token punctuation">)</span> obj<span class="token punctuation">;</span>
    <span class="token keyword">return</span> tmpJSONObject<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token class-name">Collectors</span><span class="token punctuation">.</span><span class="token function">joining</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">"Error searching Baidu: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token punctuation">}</span></code></pre>
<p>3)获取网页搜索API</p><p><img alt="image-20251012141541376" src="https://i-blog.csdnimg.cn/img_convert/621a14cb338d8095c489af39639ad62c.webp?x-oss-process=image/format,png"></p><p>4)在配置文件中添加API Key:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-yml"><span class="token comment"># searchApi</span>
<span class="token key atrule">search-api</span><span class="token punctuation">:</span>
<span class="token key atrule">api-key</span><span class="token punctuation">:</span> 你的 API Key</code></pre>
<p>5)编写测试代码</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebSearchToolTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${search-api.api-key}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> searchApiKey<span class="token punctuation">;</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testSearchWeb</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">WebSearchTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebSearchTool</span><span class="token punctuation">(</span>searchApiKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> query <span class="token operator">=</span> <span class="token string">"程序员鱼皮编程导航 codefather.cn"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">searchWeb</span><span class="token punctuation">(</span>query<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="image-20251012141940621" src="https://i-blog.csdnimg.cn/img_convert/0bed480b8a1f3462667bfb38b4b9f3ac.webp?x-oss-process=image/format,png"></p><p>能进行网络搜索</p><h5>网页抓取</h5><p>网页抓取工具的作用是根据网址解析到网页的内容。</p><p>1)可以使用jsoup库实现网页内容抓取和解析,首先给项目添加依赖:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.jsoup<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>jsoup<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>1.19.1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span></code></pre>
<p>2)编写网络抓取类</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebScrapingTool</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Scrape the content of a web page"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">scrapeWebPage</span><span class="token punctuation">(</span><span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"URL of the web page to scrape"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">Document</span> doc <span class="token operator">=</span> <span class="token class-name">Jsoup</span><span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> doc<span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">"Error scraping web page: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>3)编写测试类</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebScrapingToolTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testScrapeWebPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">WebScrapingTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebScrapingTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> url <span class="token operator">=</span> <span class="token string">"https://chengfushi.blog.csdn.net/"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">scrapeWebPage</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="image-20251012142514610" src="https://i-blog.csdnimg.cn/img_convert/944e432265799abb4ac0d6659f311565.webp?x-oss-process=image/format,png"></p><h5>终端操作</h5><p>终端操作工具的作用是在终端执行命令,比如执行python命令来运行脚本。</p><p>1)可以通过Java的Process API实现终端命令执行,注意Windows和其他操作系统下的实现略有区别)。工具类<br> 代码如下:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TerminalOperationTool</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Execute a command in the terminal"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">executeTerminalCommand</span><span class="token punctuation">(</span><span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Command to execute in the terminal"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">StringBuilder</span> output <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">ProcessBuilder</span> builder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProcessBuilder</span><span class="token punctuation">(</span><span class="token string">"cmd.exe"</span><span class="token punctuation">,</span> <span class="token string">"/c"</span><span class="token punctuation">,</span> command<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//            Process process = Runtime.getRuntime().exec(command);</span>
<span class="token class-name">Process</span> process <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">BufferedReader</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> line<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>line <span class="token operator">=</span> reader<span class="token punctuation">.</span><span class="token function">readLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
output<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>line<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> exitCode <span class="token operator">=</span> process<span class="token punctuation">.</span><span class="token function">waitFor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>exitCode <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
output<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"Command execution failed with exit code: "</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>exitCode<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> <span class="token operator">|</span> <span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
output<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"Error executing command: "</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> output<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>2)编写单元测试代码:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TerminalOperationToolTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testExecuteTerminalCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">TerminalOperationTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TerminalOperationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> command <span class="token operator">=</span> <span class="token string">"dir"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">executeTerminalCommand</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="image-20251012143007635" src="https://i-blog.csdnimg.cn/img_convert/febf13e8d90f1e28810ff3a36c049413.webp?x-oss-process=image/format,png"></p><h5>资源下载</h5><p>资源下载工具的作用是通过链接下载文件到本地。</p><p>1)使用Hutool的<code>HttpUtil.downloadFile</code>方法实现资源下载。资源下载工具类的代码如下:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ResourceDownloadTool</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Download a resource from a given URL"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">downloadResource</span><span class="token punctuation">(</span><span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"URL of the resource to download"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> url<span class="token punctuation">,</span> <span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Name of the file to save the downloaded resource"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> fileName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> fileDir <span class="token operator">=</span> <span class="token class-name">FileConstant</span><span class="token punctuation">.</span>FILE_SAVE_DIR <span class="token operator">+</span> <span class="token string">"/download"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> filePath <span class="token operator">=</span> fileDir <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> fileName<span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// 创建目录</span>
<span class="token class-name">FileUtil</span><span class="token punctuation">.</span><span class="token function">mkdir</span><span class="token punctuation">(</span>fileDir<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 使用 Hutool 的 downloadFile 方法下载资源</span>
<span class="token class-name">HttpUtil</span><span class="token punctuation">.</span><span class="token function">downloadFile</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">File</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token string">"Resource downloaded successfully to: "</span> <span class="token operator">+</span> filePath<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">"Error downloading resource: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>2)编写单元测试类</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ResourceDownloadToolTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testDownloadResource</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">ResourceDownloadTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ResourceDownloadTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> url <span class="token operator">=</span> <span class="token string">"https://i-avatar.csdnimg.cn/99cfb2a8a4b04a708780939ef43086d6_2303_82176667.jpg!1"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> fileName <span class="token operator">=</span> <span class="token string">"logo.png"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">downloadResource</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> fileName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="image-20251012143350706" src="https://i-blog.csdnimg.cn/img_convert/ef752498fb1c8d6076abd37d7c242ea7.webp?x-oss-process=image/format,png"></p><h5>PDF生成</h5><p>PDF生成工具的作用是根据文件名和内容生成PDF文档并保存。</p><p>可以使用itext库实现PDF生成。需要注意的是,itext对中文字体的支持需要额外配置,不同操作系统提供的字<br> 体也不同,如果真要做生产级应用,建议自行下载所需字体。</p><p>不过对于学习来说,不建议在这里浪费太多时间,可以使用内置中文字体(不引入font-asian字体依赖也可以使<br> 用):</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token comment">// 使用内置中文字体</span>
<span class="token class-name">PdfFont</span> font <span class="token operator">=</span> <span class="token class-name">PdfFontFactory</span><span class="token punctuation">.</span><span class="token function">createFont</span><span class="token punctuation">(</span><span class="token string">"STSongStd-Light"</span><span class="token punctuation">,</span> <span class="token string">"UniGB-UCS2-H"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">setFont</span><span class="token punctuation">(</span>font<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>1)给项目添加依赖:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-xml"><span class="token comment">&lt;!-- https://mvnrepository.com/artifact/com.itextpdf/itext-core --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.itextpdf<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>itext-core<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>9.1.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>type</span><span class="token punctuation">&gt;</span></span>pom<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>type</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- https://mvnrepository.com/artifact/com.itextpdf/font-asian --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.itextpdf<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>font-asian<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>9.1.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span></code></pre>
<p>2)编写工具类实现代码:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PDFGenerationTool</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Tool</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Generate a PDF file with given content"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">generatePDF</span><span class="token punctuation">(</span>
<span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Name of the file to save the generated PDF"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> fileName<span class="token punctuation">,</span>
<span class="token annotation punctuation">@ToolParam</span><span class="token punctuation">(</span>description <span class="token operator">=</span> <span class="token string">"Content to be included in the PDF"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> fileDir <span class="token operator">=</span> <span class="token class-name">FileConstant</span><span class="token punctuation">.</span>FILE_SAVE_DIR <span class="token operator">+</span> <span class="token string">"/pdf"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> filePath <span class="token operator">=</span> fileDir <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> fileName<span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// 创建目录</span>
<span class="token class-name">FileUtil</span><span class="token punctuation">.</span><span class="token function">mkdir</span><span class="token punctuation">(</span>fileDir<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 创建 PdfWriter 和 PdfDocument 对象</span>
<span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">PdfWriter</span> writer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PdfWriter</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">PdfDocument</span> pdf <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PdfDocument</span><span class="token punctuation">(</span>writer<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Document</span> document <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Document</span><span class="token punctuation">(</span>pdf<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 自定义字体(需要人工下载字体文件到特定目录)</span>
<span class="token comment">//                String fontPath = Paths.get("src/main/resources/static/fonts/simsun.ttf")</span>
<span class="token comment">//                        .toAbsolutePath().toString();</span>
<span class="token comment">//                PdfFont font = PdfFontFactory.createFont(fontPath,</span>
<span class="token comment">//                        PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);</span>
<span class="token comment">// 使用内置中文字体</span>
<span class="token class-name">PdfFont</span> font <span class="token operator">=</span> <span class="token class-name">PdfFontFactory</span><span class="token punctuation">.</span><span class="token function">createFont</span><span class="token punctuation">(</span><span class="token string">"STSongStd-Light"</span><span class="token punctuation">,</span> <span class="token string">"UniGB-UCS2-H"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">setFont</span><span class="token punctuation">(</span>font<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 创建段落</span>
<span class="token class-name">Paragraph</span> paragraph <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Paragraph</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 添加段落并关闭文档</span>
document<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>paragraph<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token string">"PDF generated successfully to: "</span> <span class="token operator">+</span> filePath<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">"Error generating PDF: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>3)编写单元测试代码</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PDFGenerationToolTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testGeneratePDF</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">PDFGenerationTool</span> tool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PDFGenerationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> fileName <span class="token operator">=</span> <span class="token string">"耄耄爱哈气.pdf"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"耄耄爱哈气 https://chengfushi.blog.csdn.net/"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> tool<span class="token punctuation">.</span><span class="token function">generatePDF</span><span class="token punctuation">(</span>fileName<span class="token punctuation">,</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">assertNotNull</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>成功生成PDF</p><p><img alt="image-20251012144109679" src="https://i-blog.csdnimg.cn/img_convert/43f67f829417c2f1abef56573553d932.webp?x-oss-process=image/format,png"></p><p><img alt="image-20251012144035882" src="https://i-blog.csdnimg.cn/img_convert/9b330605072a24701aae815a397ae893.webp?x-oss-process=image/format,png"></p><h4>集中注册工具</h4><p>开发好了这么多工具类后,结合我们自己的需求,可以给A!一次性提供所有工具,让它自己决定何时调用。所<br> 我们可以创建<strong>工具注册</strong>类,方便统一管理和绑定所有工具。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ToolRegistration</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${search-api.api-key}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> searchApiKey<span class="token punctuation">;</span>
<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> <span class="token class-name">ToolCallback</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">allTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">FileOperationTool</span> fileOperationTool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileOperationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">WebSearchTool</span> webSearchTool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebSearchTool</span><span class="token punctuation">(</span>searchApiKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">WebScrapingTool</span> webScrapingTool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebScrapingTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">ResourceDownloadTool</span> resourceDownloadTool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ResourceDownloadTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">TerminalOperationTool</span> terminalOperationTool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TerminalOperationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">PDFGenerationTool</span> pdfGenerationTool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PDFGenerationTool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token class-name">ToolCallbacks</span><span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>
fileOperationTool<span class="token punctuation">,</span>
webSearchTool<span class="token punctuation">,</span>
webScrapingTool<span class="token punctuation">,</span>
resourceDownloadTool<span class="token punctuation">,</span>
terminalOperationTool<span class="token punctuation">,</span>
pdfGenerationTool
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>这段代码暗含了好几种设计模式:</p><ol><li>工厂模式:Tools0方法作为一个工厂方法,负责创建和配置多个工具实例,然后将它们包装成统一的数组<br> 返回。这符合工厂模式的核心思想-集中创建对象并隐藏创建细节。</li><li>依赖注入模式:通过@Value注解注入配置值,以及将创建好的工具通过Spring容器注入到需要它们的组件<br> 中。</li><li>注册模式:该类作为一个中央注册点,集中管理和注册所有可用的工具,使它们能够被系统其他部分统一访<br> 问。</li><li>适配器模式的应用:ToolCallbacks.from方法可以看作是一种适配器,它将各种不同的工具类转换为统一的T<br> oolCallback数组,使系统能够以一致的方式处理它们。</li></ol><p>有了这个注册类,如果需要添加或移除工具,只需修改这一个类即可,更利于维护。</p><h4>使用工具</h4>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@Resource</span>
<span class="token keyword">private</span> <span class="token class-name">ToolCallback</span><span class="token punctuation">[</span><span class="token punctuation">]</span> allTools<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">doChatWithTools</span><span class="token punctuation">(</span><span class="token class-name">String</span> message<span class="token punctuation">,</span><span class="token class-name">String</span> chatId<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token class-name">ChatResponse</span> chatResponse <span class="token operator">=</span> chatClient
<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">user</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">advisors</span><span class="token punctuation">(</span>advisorSpec <span class="token operator">-&gt;</span> advisorSpec<span class="token punctuation">.</span><span class="token function">param</span><span class="token punctuation">(</span><span class="token class-name">ChatMemory</span><span class="token punctuation">.</span>CONVERSATION_ID<span class="token punctuation">,</span>chatId<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">toolCallbacks</span><span class="token punctuation">(</span>allTools<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">chatResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> content <span class="token operator">=</span> chatResponse<span class="token punctuation">.</span><span class="token function">getResult</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getOutput</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getText</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"content: {}"</span><span class="token punctuation">,</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> content<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>测试类:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-java"><span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">class</span> <span class="token class-name">CookerAppTest</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Resource</span>
<span class="token keyword">private</span> <span class="token class-name">CookerApp</span> cookerApp<span class="token punctuation">;</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">void</span> <span class="token function">doChatWithTools</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 测试食材推荐</span>
<span class="token function">testMessage</span><span class="token punctuation">(</span><span class="token string">"周末想给家人做一顿特别的晚餐,推荐几种适合家庭聚餐的创意食材搭配?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// // 测试食谱获取</span>
<span class="token comment">// testMessage("想做一道正宗的意大利面,看看美食导航网站(foodnavigator.com)上最受欢迎的做法是什么?");</span>
<span class="token comment">//</span>
<span class="token comment">// // 测试食材图片下载</span>
<span class="token comment">// testMessage("直接下载一张展示法式牛排完美摆盘的图片为文件");</span>
<span class="token comment">//</span>
<span class="token comment">// // 测试营养分析代码执行</span>
<span class="token comment">// testMessage("执行Python3脚本来分析这道菜的营养成分和热量");</span>
<span class="token comment">//</span>
<span class="token comment">// // 测试菜单保存</span>
<span class="token comment">// testMessage("保存我设计的本周家庭菜单为文件");</span>
<span class="token comment">//</span>
<span class="token comment">// // 测试烹饪步骤PDF生成</span>
<span class="token comment">// testMessage("生成一份‘中秋家宴烹饪指南’PDF,包含食材采购清单、分步烹饪教程和摆盘技巧");</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">testMessage</span><span class="token punctuation">(</span><span class="token class-name">String</span> message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> chatId <span class="token operator">=</span> UUID<span class="token punctuation">.</span><span class="token function">randomUUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> answer <span class="token operator">=</span> cookerApp<span class="token punctuation">.</span><span class="token function">doChatWithTools</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> chatId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assertions</span><span class="token punctuation">.</span><span class="token function">assertNotNull</span><span class="token punctuation">(</span>answer<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>1)普通问答:</p><p><img alt="image-20251012150040375" src="https://i-blog.csdnimg.cn/img_convert/1c6d229518c8973cc3196d847ec40f45.webp?x-oss-process=image/format,png"></p><p>2)联网搜索</p><p><img alt="image-20251012150353837" src="https://i-blog.csdnimg.cn/img_convert/5dd47fec31fc5ac34dfb520768a16bb8.webp?x-oss-process=image/format,png"></p><p>3)PDF生成</p><p><img alt="image-20251012151348869" src="https://i-blog.csdnimg.cn/img_convert/963331cb1af81b0c173c521f55c00a79.webp?x-oss-process=image/format,png"></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code>    //
    // // 测试营养分析代码执行
    // testMessage("执行Python3脚本来分析这道菜的营养成分和热量");
    //
    // // 测试菜单保存
    // testMessage("保存我设计的本周家庭菜单为文件");
    //
    // // 测试烹饪步骤PDF生成
    // testMessage("生成一份‘中秋家宴烹饪指南’PDF,包含食材采购清单、分步烹饪教程和摆盘技巧");
}
private void testMessage(String message) {
    String chatId = UUID.randomUUID().toString();
    String answer = cookerApp.doChatWithTools(message, chatId);
    Assertions.assertNotNull(answer);
}</code></pre>
<p>}</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code>1)普通问答:
[外链图片转存中...(img-d1BzBR5m-1760253300884)]
2)联网搜索
[外链图片转存中...(img-QKuIsQwJ-1760253300884)]
3)PDF生成
[外链图片转存中...(img-poaCw4oL-1760253300884)]
!(https://i-blog.csdnimg.cn/img_convert/b679f3b9782017a3813c31a83468d50f.webp?x-oss-process=image/format,png)</code></pre>
</div><br><br>
来源:https://www.cnblogs.com/gccbuaa/p/19203084
頁: [1]
查看完整版本: 耄大厨——AI厨师智能体(3-程序调用)