Java实现智能体应用 之 工具的使用 原理与实现
Spring AI Alibaba是Spring AI的一个实现,专注于接入阿里云的通义大模型服务。它支持对话、文生图、文生语音等功能,并提供了如OutputParser和Prompt Template等实用工具。Spring AI Alibaba的核心优势在于通过统一接口简化了不同AI提供者的集成过程,让开发者能够轻松切换不同的AI服务,极大减少了程序编写与迁移的工作量。同时,它也支持本地部署和
智能体是什么?
智能体是指 以大语言模型(LLM)作为大脑的 “一整套系统”:该系统能够执行观察、思考、行动和记忆等功能。这样的智能体可以理解为一种高级的应用或服务,它不仅能够处理复杂的业务逻辑,还能够通过学习和适应环境变化来优化自身的性能。
例如,在微服务架构中,智能体可以通过分析服务间的交互模式自动调整负载均衡策略,或者基于过往的数据预测故障并提前采取措施,从而提高整个系统的稳定性和效率。
智能体的关键组成流程与工具
智能体的关键流程包括:
信息输入观察、思考与计划、使用工具执行行动以及长短期外部记忆。
首先,通过传感器或数据接口获取环境信息,形成对当前状态的理解。
接着,基于收集到的信息进行分析处理,制定出达成目标的具体步骤。
然后,利用各种软件工具或物理设备按照计划采取行动。
最后,将有价值的经验和数据存储于长短期记忆系统中,以便未来参考学习,持续优化决策过程。
这一系列环节相互配合,共同支持着智能体高效完成任务。
工具(function call)在里面起到什么作用?
在智能体应用中,工具function call就像是为大模型配备了一套可以扩展其“感知”与“行动”能力的装备。正如人可以通过望远镜观察到更远处的事物、通过汽车快速到达目的地一样,在这个比喻里,应用提供的功能调用机制允许大型语言模型(LLM)借助特定工具或函数完成原本难以直接达成的任务。
例如,当一个基于spring ai alibaba的应用程序面对需要查询消息状态的问题时,它不会直接尝试解析该请求,而是识别出应该使用先前定义好的messageStatusFunction来处理这个问题。
这相当于人类意识到自己需要使用特定工具——比如打开手电筒照明黑暗角落——才能更好地解决问题。
通过这种方式,不仅加强了应用程序处理复杂任务的能力,也使得像搜索信息或控制物理设备(如开关灯)这样的具体操作变得更加直观和高效。
这样一来,大模型不再局限于自身的知识库内,而是能够有效地利用外部资源进行学习和执行任务,极大地拓展了它的应用范围。
函数function call是怎么运作的?
在Spring AI中,函数调用(Function Calling)机制允许大型语言模型(LLM)与外部定义的Java函数进行交互。用户首先实现一个Java接口,并通过注解详细描述该函数的输入参数、输出结果以及其具体功能。@JsonProperty 和 JsonPropertyDescription 注解在这里起关键作用,它们提供了关于函数所需参数和预期输出的信息,这些信息对于让大模型理解如何使用这个函数至关重要。
当用户将这样的函数注册到Spring AI框架内时,框架会自动解析这些注解信息,并将其转换成易于大模型理解的文字描述。此描述作为上下文的一部分被传递给大模型。一旦大模型分析出为了完成特定任务需要调用某个已注册的函数,它会向Spring AI发出请求,指明要调用的具体函数及相应参数。Spring AI接收到这个指令后,在本地执行指定函数并获取执行结果。最后,这个结果连同原有的对话历史一起再次发送给大模型,从而形成了一个完整的闭环互动过程。这种方式使得大模型能够利用预定义的功能扩展其能力范围,同时保持了对实际业务逻辑的高度控制性和灵活性。
Spring AI Alibaba 简单介绍
Spring AI Alibaba是Spring AI的一个实现,专注于接入阿里云的通义大模型服务。它支持对话、文生图、文生语音等功能,并提供了如OutputParser和Prompt Template等实用工具。Spring AI Alibaba的核心优势在于通过统一接口简化了不同AI提供者的集成过程,让开发者能够轻松切换不同的AI服务,极大减少了程序编写与迁移的工作量。同时,它也支持本地部署和其他主流AI框架如OpenAI的集成,进一步提升了开发灵活性。
Spring AI Alibaba 实现 第三方函数调用
具体步骤
1. 环境准备
- 确保JDK版本为17及以上。
- Spring Boot版本3.3.x或更高。
- 在阿里云上申请通义千问的API Key
- 将Spring AI Alibaba及所需依赖添加到项目中。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M2</version>
</dependency>
<!-- Add other necessary dependencies here -->
</dependencies>
2. 定义函数实现
首先定义一个服务类,该类实现了Function接口,接受一个包含股票代码的对象作为输入,返回从雪球API获取并解析后的利润率信息。
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
public class StockProfitService implements Function<StockProfitRequest, String> {
@Override
public String apply(StockProfitRequest request) {
// Implement the logic to call XueQiu API and parse the response
return "解析后的利润率为:...";
}
public static class StockProfitRequest {
@JsonProperty(required = true, value = "股票代码")
@JsonPropertyDescription("例如: SH600900")
private String symbol;
public StockProfitRequest() {}
public StockProfitRequest(String symbol) { this.symbol = symbol; }
public String getSymbol() { return symbol; }
public void setSymbol(String symbol) { this.symbol = symbol; }
}
}
3. 注册函数
在配置类中注册上述定义的函数,以便稍后可以在聊天请求中使用它。
@Configuration
public class AppConfig {
@Bean
@Description("查询指定股票的利润表并分析利润率")
public Function<StockProfitService.StockProfitRequest, String> stockProfitFunction() {
return new StockProfitService();
}
}
4. 创建控制器处理聊天请求
创建一个REST Controller来处理来自前端的GET请求,同时支持CORS跨域资源共享。使用Prompt Template和ChatClient结合之前注册的功能函数来完成整个流程。
@RestController
@RequestMapping("/ai")
@CrossOrigin(origins = "*")
public class ChatController {
private final ChatClient chatClient;
@Value("classpath:/prompts/stock-analysis-prompt.st")
Resource promptResource;
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/chatSteam")
public Flux<String> chatSteam(@RequestParam String input) {
PromptTemplate promptTemplate = new PromptTemplate(promptResource);
Map<String, Object> map = Map.of("input", input);
DashscopeChatOptionsBuilder optionsBuilder = DashScopeChatOptions.builder()
.withFunction("stockProfitFunction");
DashscopeChatOptions options = optionsBuilder.build();
Prompt prompt = promptTemplate.create(map, options);
return chatClient.prompt(prompt).stream().content();
}
}
5. 编写提示词模板
最后,不要忘记编写对应的提示词模板文件stock-analysis-prompt.st,放置于资源目录下:
请根据以下信息,对{input}这只股票最近的利润率情况进行简单分析。
解释
上述步骤展示了如何整合Spring AI Alibaba、Prompt模板以及Function Calling能力来构建一个可以调用外部API并对结果进行分析的应用。首先定义了负责与第三方API交互的服务类,并将其注册为Spring Bean,然后在控制器中组合使用Prompt和ChatClient发起对话请求。当用户提出关于某只股票的查询时,系统会自动触发对外部API的调用来获取最新财务数据,并最终通过大语言模型给出相应的分析结论。
构建前端
构建前端
为了构建一个基于React的简单前端项目,该项目能够处理来自后端的流式数据(flux),我们将按照以下步骤进行:
1. 创建新的React应用
首先,需要在本地环境中创建一个新的React应用。这一步骤通过create-react-app工具来完成,并确保安装了所有必要的依赖。
npx create-react-app frontend
cd frontend
npm install
2. 设置基础HTML文件
接下来,我们保持默认生成的public/index.html不变,因为它已经满足基本需求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chat App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
3. 配置入口JS文件
对于src/index.js,同样维持其原始结构,它将作为应用程序的入口点。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
4. 定义主组件
src/App.js中定义了一个简单的功能,即渲染聊天组件。
import React from 'react';
import ChatComponent from './components/ChatComponent';
function App() {
return (
<div className="App">
<ChatComponent />
</div>
);
}
export default App;
5. 实现聊天组件
核心部分在于src/components/ChatComponent.js,这里实现了用户输入消息、发送给服务器并接收响应的功能。特别注意的是,这里使用了Fetch API与WebSocket模拟的GET请求相结合的方法来读取流式响应。
import React, { useState } from 'react';
function ChatComponent() {
const [input, setInput] = useState('');
const [messages, setMessages] = useState('');
const handleInputChange = (event) => {
setInput(event.target.value);
};
const handleSendMessage = async () => {
try {
// 注意URL需替换为实际的服务地址
const response = await fetch(`http://your-backend-url/ai/chatStream?input=${input}`);
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let done = false;
while (!done) {
const { value, done: readerDone } = await reader.read();
done = readerDone;
const chunk = decoder.decode(value, { stream: true });
setMessages((prevMessages) => prevMessages + chunk);
}
// 请求结束时添加分隔符
setMessages((prevMessages) => prevMessages + '\n\n=============================\n\n');
} catch (error) {
console.error('Failed to fetch', error);
}
};
const handleClearMessages = () => {
setMessages('');
};
return (
<div>
<input
type="text"
value={input}
onChange={handleInputChange}
placeholder="Enter your message"
/>
<button onClick={handleSendMessage}>Send</button>
<button onClick={handleClearMessages}>Clear</button>
<div>
<h3>Messages:</h3>
<pre>{messages}</pre>
</div>
</div>
);
}
export default ChatComponent;
6. 启动前端服务
最后,通过运行如下命令启动你的React应用:
cd frontend
npm start
这样就完成了整个前端应用的搭建过程,现在你应该能够通过访问http://localhost:3000看到页面,并且可以通过填写表单向指定的后端API发送请求,展示返回的流式数据了。
说明:
上述步骤提供了一个基本框架,用于构建可以与支持流式输出(如Flux)的后端交互的前端React应用。其中关键在于如何处理来自后端的连续数据块,并正确地将其显示给用户。通过利用JavaScript的异步特性以及Fetch API的能力,我们可以有效地实现这一目标。
更多推荐


所有评论(0)