【Spring AI实战】第9章 轻量级AI智能体开发
1. 智能体核心思想:自主规划、工具调用、迭代执行
Spring AI 智能体的核心思想可以概括为:一个能够感知环境、自主规划、调用工具、并通过迭代执行与反思来完成复杂目标的智能系统。 它旨在将大语言模型的推理能力与外部工具的执行能力相结合,超越简单的“一问一答”模式,实现多步骤、动态的交互式任务处理。
下面我们来详细拆解这三个核心思想:
自主规划
这是智能体区别于简单提示的关键。智能体不会直接给出最终答案,而是像人类一样,先“思考”出一个计划。
- 目标分解 :智能体将用户模糊或复杂的高层目标(例如:“帮我策划一个周末旅行”)分解成一系列具体的、可操作的子任务(例如:1. 确定目的地;2. 查询天气;3. 查找景点和餐厅;4. 制定日程表)。
- 策略制定 :它需要决定完成这些子任务的顺序 和方法 。是先查天气再定目的地,还是反过来?用什么工具来查?
- 动态调整 :初始计划不是一成不变的。在执行过程中,如果遇到意外(如工具调用失败、信息不符合预期),智能体能够重新规划或调整后续步骤。
在Spring AI中的体现 :通常通过提示工程,让LLM扮演“规划者”角色,输出结构化的计划(如JSON格式的任务列表),或者通过更复杂的框架(如ReAct模式)进行隐式规划。
工具调用
智能体的“手”和“眼睛”。LLM本身是“大脑”,知识可能滞后且无法操作外部世界。工具赋予了它行动的能力。
- 工具抽象 :将各种能力封装成统一的“工具”接口,例如:
SearchTool(搜索)、CalculatorTool(计算)、DatabaseQueryTool(查数据库)、CodeExecutorTool(执行代码)、APICallTool(调用API)等。 - 按需调用 :智能体根据规划,在需要时自主选择并调用合适的工具。例如,要回答“今天纽约的天气如何?”,它会调用
WeatherAPITool。 - 结果处理 :接收工具的返回结果(可能是结构化数据、文本、错误信息等),并将其作为上下文信息,用于后续的决策和回答生成。
在Spring AI中的体现 :通过 Function Calling 机制实现。开发者将工具(Java方法)注册给AI模型,模型在对话中可以根据需要请求调用这些方法,并将执行结果返回给模型进行后续处理。
迭代执行
智能体的“试错与学习”循环。任务完成很少能一蹴而就,迭代是核心执行模式。
- 观察-思考-行动循环 :
- 观察 :分析当前状态(用户输入、历史对话、工具执行结果)。
- 思考 :评估当前信息,决定下一步是调用工具、重新规划,还是给出最终答案。
- 行动 :执行决定(如调用一个工具,或生成回答)。
- 反思与修正 :在一次或多次行动后,智能体可以评估进展是否朝向目标。如果偏离或遇到障碍,它会“反思”问题所在,并修正后续行动。例如,调用搜索工具后没找到有用信息,它可能会尝试使用不同的关键词重新搜索。
- 持续直至完成 :这个循环会一直进行,直到智能体认为已经收集到足够信息来形成令人满意的最终答案,或者达到迭代次数限制。
在Spring AI中的体现 :通过 Agent 抽象和 ReAct、Chain-of-Thought 等内置实现来封装这个循环。开发者可以配置代理的执行流程、工具集以及决定何时停止迭代的策略。
总结与类比
你可以将Spring AI智能体想象成一个经验丰富的项目助理 :
- 接到任务 (用户请求)后,他不会立刻埋头苦干,而是先制定一个项目计划 (自主规划 )。
- 在计划中,他知道哪些工作自己可以做(LLM内部推理),哪些需要联系其他部门或使用专业软件 (工具调用 ):比如让市场部(搜索工具)提供数据,让财务部(计算工具)核算成本。
- 在执行过程中,他会不断跟进和协调 (迭代执行 ):如果市场部给的数据不对,他会要求澄清或寻找其他来源;如果发现计划有瑕疵,他会及时调整。直到所有环节就绪,他才会向你汇报最终成果。
Spring AI 的支持
Spring AI 通过高层次的抽象,简化了构建此类智能体的过程:
-
Agent 接口 :定义了智能体的核心行为。 -
Tool 接口 :统一了工具调用的方式。 -
PromptTemplate :帮助构建指导智能体进行规划和决策的提示词。 - 多种内置代理实现 :如
ReActAgent、ChainOfThoughtAgent等,提供了开箱即用的经典推理模式。
通过组合这些组件,开发者可以专注于业务逻辑和工具定义,而无需从头实现复杂的推理循环机制,从而高效地构建出能够解决实际复杂问题的AI智能体应用。
2. SpringAI 智能体快速搭建:工具集整合、任务拆解
我来详细介绍如何使用 Spring AI 快速搭建智能体,包括工具集整合和任务拆解。
一、Spring AI 智能体核心概念
智能体架构
// 智能体核心组件
Agent -> Planner -> Tools -> Memory -> OutputParser
二、工具集整合
内置工具使用
@Configuration
public class AgentToolsConfig {
@Bean
public WebSearchTool webSearchTool() {
return new WebSearchTool(webSearchService());
}
@Bean
public CalculatorTool calculatorTool() {
return new CalculatorTool();
}
@Bean
public WeatherTool weatherTool() {
return new WeatherTool(weatherService());
}
@Bean
public DocumentSearchTool documentSearchTool() {
return new DocumentSearchTool(vectorStore());
}
}
自定义工具开发
@Component
public class DatabaseQueryTool implements FunctionTool {
@Tool(name = "queryDatabase", description = "查询数据库获取信息")
public String queryDatabase(
@ToolParam(description = "SQL查询语句") String sql,
@ToolParam(description = "最大返回行数") int limit
) {
// 执行数据库查询
return jdbcTemplate.queryForList(sql, limit).toString();
}
@Override
public FunctionCallback get() {
return FunctionCallbackWrapper.from(this);
}
}
工具注册与管理
@Configuration
public class ToolRegistryConfig {
@Bean
public ToolRegistry toolRegistry(
List<FunctionTool> tools,
WebSearchTool webSearchTool,
CalculatorTool calculatorTool
) {
ToolRegistry registry = new ToolRegistry();
// 注册内置工具
registry.registerTool(webSearchTool);
registry.registerTool(calculatorTool);
// 注册自定义工具
tools.forEach(registry::registerTool);
return registry;
}
}
三、任务拆解与规划
基于 Chain of Thought 的任务拆解
@Component
public class TaskPlanner {
private final ChatClient chatClient;
public List<String> planComplexTask(String userRequest) {
String prompt = """
请将以下复杂任务拆解为可执行的子任务:
原始任务:%s
请按步骤输出,每个步骤一行。
""".formatted(userRequest);
String response = chatClient.prompt(prompt)
.call()
.content();
return Arrays.stream(response.split("\n"))
.filter(line -> !line.trim().isEmpty())
.collect(Collectors.toList());
}
}
ReAct 模式实现
@Component
public class ReactAgent {
private final ChatClient chatClient;
private final ToolRegistry toolRegistry;
public String executeWithReact(String task) {
String thought = "";
String action = "";
String observation = "";
for (int i = 0; i < 10; i++) { // 最大迭代次数
String prompt = buildReActPrompt(thought, action, observation, task);
String response = chatClient.prompt(prompt).call().content();
// 解析 Thought/Action/Observation
Map<String, String> parsed = parseReActResponse(response);
if ("FINISH".equals(parsed.get("action"))) {
return parsed.get("observation");
}
// 执行工具调用
String toolResult = executeTool(parsed.get("action"));
observation = toolResult;
}
return "任务执行超时";
}
private String buildReActPrompt(String thought, String action,
String observation, String task) {
return """
Task: %s
Thought: %s
Action: %s
Observation: %s
请继续思考下一步:
Thought:""".formatted(task, thought, action, observation);
}
}
四、智能体完整实现
智能体配置类
@Configuration
public class AgentConfiguration {
@Bean
public ChatModel chatModel() {
return new OpenAiChatModel(
OpenAiChatOptions.builder()
.model("gpt-4")
.temperature(0.1)
.build()
);
}
@Bean
public Agent agent(ChatModel chatModel, ToolRegistry toolRegistry) {
return Agent.builder()
.chatModel(chatModel)
.tools(toolRegistry.getTools())
.memory(new SimpleChatMemory())
.outputParser(new AgentOutputParser())
.promptTemplate("""
你是一个智能助手,可以调用以下工具:
{tools}
历史对话:
{history}
当前任务:{input}
请根据需要调用工具完成任务。
""")
.build();
}
}
智能体服务层
@Service
public class AgentService {
private final Agent agent;
private final TaskPlanner taskPlanner;
public AgentResponse executeTask(String userRequest) {
// 1. 任务拆解
List<String> subTasks = taskPlanner.planComplexTask(userRequest);
// 2. 顺序执行子任务
List<TaskResult> results = new ArrayList<>();
for (String subTask : subTasks) {
AgentResponse response = agent.call(subTask);
results.add(new TaskResult(subTask, response.content()));
}
// 3. 结果汇总
String summary = summarizeResults(results, userRequest);
return new AgentResponse(summary, results);
}
private String summarizeResults(List<TaskResult> results, String originalTask) {
// 调用 LLM 汇总结果
String prompt = """
请基于以下子任务执行结果,总结完成原始任务的最终答案:
原始任务:%s
子任务结果:
%s
""".formatted(originalTask,
results.stream()
.map(r -> "- " + r.subTask() + ": " + r.result())
.collect(Collectors.joining("\n")));
return agent.call(prompt).content();
}
}
五、高级功能实现
并行任务执行
@Service
public class ParallelAgentExecutor {
private final ExecutorService executor = Executors.newFixedThreadPool(5);
public Map<String, Object> executeParallelTasks(
List<String> tasks,
Agent agent
) {
List<CompletableFuture<AgentResponse>> futures = tasks.stream()
.map(task -> CompletableFuture.supplyAsync(
() -> agent.call(task),
executor
))
.collect(Collectors.toList());
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0])
);
return allFutures.thenApply(v ->
futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toMap(
r -> r.input(),
AgentResponse::content
))
).join();
}
}
工具调用链
@Component
public class ToolChainExecutor {
public String executeToolChain(String initialInput, List<ToolSpec> toolChain) {
String currentResult = initialInput;
for (ToolSpec toolSpec : toolChain) {
FunctionTool tool = getToolByName(toolSpec.toolName());
String toolInput = buildToolInput(currentResult, toolSpec.parameters());
currentResult = tool.execute(toolInput);
// 检查是否需要继续
if (shouldStop(currentResult, toolSpec.stopCondition())) {
break;
}
}
return currentResult;
}
record ToolSpec(String toolName, Map<String, Object> parameters, String stopCondition) {}
}
六、监控与评估
智能体性能监控
@Aspect
@Component
public class AgentMonitoringAspect {
@Around("execution(* com.example.agent..*Agent.*(..))")
public Object monitorAgentExecution(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
String methodName = joinPoint.getSignature().getName();
try {
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - startTime;
// 记录指标
recordMetrics(methodName, duration, true);
return result;
} catch (Exception e) {
recordMetrics(methodName,
System.currentTimeMillis() - startTime, false);
throw e;
}
}
private void recordMetrics(String operation, long duration, boolean success) {
// 发送到监控系统
Metrics.counter("agent.operation.total", "operation", operation).increment();
Metrics.timer("agent.operation.duration", "operation", operation)
.record(duration, TimeUnit.MILLISECONDS);
if (!success) {
Metrics.counter("agent.operation.errors", "operation", operation).increment();
}
}
}
七、最佳实践
配置建议
# application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4
temperature: 0.1
max-tokens: 2000
agent:
max-iterations: 10
timeout-seconds: 30
tools:
enabled:
- web-search
- calculator
- database-query
- weather
memory:
type: redis # 或 simple, jdbc
max-messages: 50
错误处理策略
@Service
public class ResilientAgentService {
public AgentResponse executeWithRetry(String input, int maxRetries) {
for (int i = 0; i < maxRetries; i++) {
try {
return agent.call(input);
} catch (RateLimitException e) {
// 指数退避
long waitTime = (long) (Math.pow(2, i) * 1000);
Thread.sleep(waitTime + random.nextInt(1000));
} catch (ApiException e) {
if (i == maxRetries - 1) throw e;
// 其他API错误,稍后重试
Thread.sleep(2000);
}
}
throw new AgentExecutionException("执行失败,达到最大重试次数");
}
}
八、示例应用:数据分析智能体
@Component
public class DataAnalysisAgent {
@Tool(name = "analyzeData", description = "分析数据集并生成报告")
public String analyzeData(
@ToolParam(description = "数据集ID") String datasetId,
@ToolParam(description = "分析类型") AnalysisType analysisType
) {
// 1. 获取数据
String data = dataService.getDataset(datasetId);
// 2. 调用Python分析服务
String analysisResult = pythonService.analyze(data, analysisType);
// 3. 生成自然语言报告
return chatClient.prompt("""
请将以下数据分析结果转化为自然语言报告:
数据ID:%s
分析类型:%s
分析结果:%s
""".formatted(datasetId, analysisType, analysisResult))
.call()
.content();
}
}
快速开始步骤:
- 添加依赖 :
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
- 配置API密钥
- 定义工具
- 创建智能体
- 实现任务拆解逻辑
- 添加监控和错误处理
这种架构提供了灵活的工具集成、智能的任务拆解能力,并且易于扩展和维护。
3. 多工具联动:知识库检索+业务接口调用组合执行
Spring AI 多工具联动是一种强大的功能,允许你通过单一请求组合多个工具(如知识库检索和业务接口调用)来完成任务。以下是实现这种组合执行的详细方案:
项目结构与依赖
pom.xml 关键依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
核心配置类
@Configuration
public class ToolConfiguration {
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
// 配置向量存储(如PGVector、Redis等)
return new PgVectorStore(...);
}
@Bean
public ChatModel chatModel() {
return new OpenAiChatModel("gpt-4", apiKey);
}
}
知识库检索工具
@Component
public class KnowledgeBaseTool implements FunctionCallback {
private final VectorStore vectorStore;
private final EmbeddingModel embeddingModel;
@Override
public String getName() {
return "knowledgeBaseSearch";
}
@Override
public String getDescription() {
return "从知识库中检索相关信息,输入为查询问题";
}
@Override
public String getInputTypeSchema() {
return """
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "用户查询的问题"
}
},
"required": ["query"]
}
""";
}
@Override
public Object call(Message requestMessage) {
Map<String, Object> arguments = parseArguments(requestMessage);
String query = (String) arguments.get("query");
// 生成查询向量
List<Double> queryEmbedding = embeddingModel.embed(query);
// 相似度搜索
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query(query)
.topK(5)
.build()
);
// 格式化结果
return formatResults(results);
}
private String formatResults(List<Document> documents) {
return documents.stream()
.map(doc -> "来源: " + doc.getMetadata().get("source") +
"\n内容: " + doc.getContent())
.collect(Collectors.joining("\n\n"));
}
}
业务接口调用工具
@Component
public class BusinessApiTool implements FunctionCallback {
@Override
public String getName() {
return "callBusinessApi";
}
@Override
public String getDescription() {
return "调用业务系统API获取实时数据或执行操作";
}
@Override
public String getInputTypeSchema() {
return """
{
"type": "object",
"properties": {
"apiName": {
"type": "string",
"description": "要调用的API名称",
"enum": ["getUserInfo", "createOrder", "checkInventory"]
},
"parameters": {
"type": "object",
"description": "API参数"
}
},
"required": ["apiName"]
}
""";
}
@Override
public Object call(Message requestMessage) {
Map<String, Object> arguments = parseArguments(requestMessage);
String apiName = (String) arguments.get("apiName");
Map<String, Object> params = (Map<String, Object>) arguments.get("parameters");
switch (apiName) {
case "getUserInfo":
return getUserInfo((String) params.get("userId"));
case "createOrder":
return createOrder(params);
case "checkInventory":
return checkInventory((String) params.get("productId"));
default:
throw new IllegalArgumentException("未知的API: " + apiName);
}
}
private String getUserInfo(String userId) {
// 调用用户服务API
return "用户信息: {id: " + userId + ", name: '张三', level: 'VIP'}";
}
private String createOrder(Map<String, Object> params) {
// 调用订单服务API
return "订单创建成功,订单号: ORD20240101001";
}
private String checkInventory(String productId) {
// 调用库存服务API
return "产品库存: {productId: " + productId + ", stock: 100}";
}
}
工具协调与执行器
@Service
public class MultiToolExecutor {
private final ChatModel chatModel;
private final List<FunctionCallback> tools;
private final PromptTemplate toolSelectionPrompt;
public MultiToolExecutor(ChatModel chatModel,
List<FunctionCallback> tools) {
this.chatModel = chatModel;
this.tools = tools;
this.toolSelectionPrompt = new PromptTemplate("""
基于用户查询和当前上下文,决定需要调用哪些工具。
可用工具:
{tools}
历史对话:
{history}
用户查询: {query}
请分析并返回JSON格式的调用计划:
{
"reasoning": "推理过程",
"toolCalls": [
{
"tool": "工具名称",
"input": "工具输入参数",
"purpose": "调用目的"
}
],
"executionOrder": "sequential|parallel"
}
""");
}
public String executeMultiToolQuery(String userQuery,
List<Message> conversationHistory) {
// 1. 工具选择决策
String toolSelection = decideTools(userQuery, conversationHistory);
ToolExecutionPlan plan = parseExecutionPlan(toolSelection);
// 2. 按顺序执行工具
List<ToolResult> results = new ArrayList<>();
for (ToolCall toolCall : plan.getToolCalls()) {
ToolResult result = executeSingleTool(toolCall);
results.add(result);
// 如果需要,基于中间结果调整后续执行
if (shouldAdjustPlan(result, toolCall)) {
plan = adjustExecutionPlan(plan, results);
}
}
// 3. 结果整合与最终响应生成
return synthesizeFinalResponse(userQuery, results, conversationHistory);
}
private String decideTools(String query, List<Message> history) {
String toolsDescription = tools.stream()
.map(tool -> "- " + tool.getName() + ": " + tool.getDescription())
.collect(Collectors.joining("\n"));
Map<String, Object> params = Map.of(
"tools", toolsDescription,
"history", formatHistory(history),
"query", query
);
return chatModel.call(toolSelectionPrompt.create(params));
}
private ToolResult executeSingleTool(ToolCall toolCall) {
FunctionCallback tool = tools.stream()
.filter(t -> t.getName().equals(toolCall.getToolName()))
.findFirst()
.orElseThrow(() -> new RuntimeException("工具未找到: " + toolCall.getToolName()));
try {
Object result = tool.call(createToolMessage(toolCall));
return ToolResult.success(toolCall, result);
} catch (Exception e) {
return ToolResult.failure(toolCall, e.getMessage());
}
}
private String synthesizeFinalResponse(String query,
List<ToolResult> results,
List<Message> history) {
String context = buildContextFromResults(results);
PromptTemplate finalPrompt = new PromptTemplate("""
基于以下信息回答用户问题:
用户问题: {query}
检索到的知识库信息:
{knowledge}
业务API调用结果:
{businessResults}
历史对话:
{history}
请生成完整、准确的回答,必要时引用具体来源。
""");
Map<String, Object> params = Map.of(
"query", query,
"knowledge", extractKnowledgeResults(results),
"businessResults", extractBusinessResults(results),
"history", formatHistory(history)
);
return chatModel.call(finalPrompt.create(params));
}
}
控制器与API端点
@RestController
@RequestMapping("/api/ai")
public class AIController {
private final MultiToolExecutor executor;
@PostMapping("/query")
public ResponseEntity<AiResponse> handleQuery(@RequestBody UserQuery request) {
String response = executor.executeMultiToolQuery(
request.getQuery(),
request.getConversationHistory()
);
return ResponseEntity.ok(new AiResponse(response));
}
@PostMapping("/stream")
public SseEmitter streamQuery(@RequestBody UserQuery request) {
SseEmitter emitter = new SseEmitter();
// 流式处理工具执行和响应生成
executor.executeStreaming(request.getQuery(),
new StreamingResponseHandler() {
@Override
public void onToolStart(String toolName) {
sendEvent(emitter, "tool_start", toolName);
}
@Override
public void onToolResult(String toolName, Object result) {
sendEvent(emitter, "tool_result",
Map.of("tool", toolName, "result", result));
}
@Override
public void onPartialResponse(String chunk) {
sendEvent(emitter, "response_chunk", chunk);
}
});
return emitter;
}
}
复杂场景示例
场景:客户咨询产品库存并下单
// 示例调用
public class ComplexScenarioExample {
public void handleCustomerInquiry() {
String query = "我想购买iPhone 15 Pro,现在有货吗?如果有的话帮我下单,收货地址用我默认的。";
// 工具链自动执行:
// 1. 知识库检索 -> 产品信息、购买政策
// 2. 业务API -> 检查库存
// 3. 业务API -> 获取用户默认地址
// 4. 业务API -> 创建订单
// 5. 生成最终回答
String response = multiToolExecutor.executeMultiToolQuery(query, history);
// 响应示例:
// "根据知识库信息,iPhone 15 Pro 正在促销中...
// 库存检查显示有货(剩余50件)...
// 已使用您的默认地址(北京市海淀区...)
// 订单创建成功,订单号ORD20240101001,预计明天送达"
}
}
高级特性实现
工具执行编排
@Component
public class ToolOrchestrator {
public enum ExecutionStrategy {
SEQUENTIAL, // 顺序执行
PARALLEL, // 并行执行
CONDITIONAL, // 条件执行
RETRY_ON_FAILURE // 失败重试
}
public List<ToolResult> orchestrate(
List<ToolCall> toolCalls,
ExecutionStrategy strategy,
Map<String, Object> context) {
switch (strategy) {
case PARALLEL:
return executeParallel(toolCalls);
case CONDITIONAL:
return executeConditional(toolCalls, context);
default:
return executeSequential(toolCalls);
}
}
private List<ToolResult> executeConditional(
List<ToolCall> toolCalls,
Map<String, Object> context) {
List<ToolResult> results = new ArrayList<>();
for (ToolCall toolCall : toolCalls) {
// 检查执行条件
if (evaluateCondition(toolCall.getCondition(), context)) {
results.add(executeTool(toolCall));
// 更新上下文
context.put("lastResult", results.get(results.size()-1));
}
}
return results;
}
}
工具执行监控
@Aspect
@Component
public class ToolExecutionMonitor {
@Around("@annotation(MonitorToolExecution)")
public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
String toolName = getToolName(joinPoint);
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - startTime;
// 记录指标
recordMetrics(toolName, duration, true);
// 缓存结果(如果适用)
cacheIfNeeded(toolName, joinPoint.getArgs(), result);
return result;
} catch (Exception e) {
recordMetrics(toolName,
System.currentTimeMillis() - startTime, false);
throw e;
}
}
}
配置与优化建议
application.yml 配置
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-4-turbo
temperature: 0.1 # 降低随机性以保证工具调用准确性
vectorstore:
pgvector:
enabled: true
index-type: HNSW
tool:
execution:
timeout: 30000 # 工具执行超时时间
max-retries: 2 # 失败重试次数
cache:
enabled: true
ttl: 300 # 缓存5分钟
性能优化建议
- 并行执行 :不依赖的工具可以并行执行
- 结果缓存 :频繁查询的结果进行缓存
- 增量更新 :知识库向量增量更新
- 连接池 :业务API调用使用连接池
- 流式响应 :长时间操作使用流式响应
总结
Spring AI 多工具联动通过以下关键设计实现:
- 工具抽象 :统一 FunctionCallback 接口
- 智能编排 :LLM 决策工具调用顺序
- 上下文传递 :工具间结果传递和共享
- 错误处理 :优雅降级和重试机制
- 监控观测 :完整的执行链路追踪
这种架构可以灵活扩展新的工具,适应复杂的业务场景,同时保持系统的可维护性和可观测性。
4. 实战:智能办公助手(查资料、查数据、生成文档一体化)
项目架构设计
技术栈
- Spring Boot 3.x
- Spring AI (支持OpenAI/Azure OpenAI/本地模型)
- 向量数据库: Pinecone/Weaviate/Chroma
- 文档处理: Apache Tika, LangChain4j
- 数据源: 数据库 + API接口
- 前端: Vue.js/React + WebSocket实时通信
核心模块设计
// 项目结构
src/main/java/com/office/ai/
├── OfficeAIAssistantApplication.java
├── config/
│ ├── AiConfig.java # AI模型配置
│ ├── VectorStoreConfig.java # 向量存储配置
│ └── WebConfig.java
├── controller/
│ ├── AssistantController.java
│ └── DocumentController.java
├── service/
│ ├── AssistantService.java # 核心助手服务
│ ├── DataQueryService.java # 数据查询服务
│ ├── DocumentService.java # 文档生成服务
│ ├── KnowledgeService.java # 知识库服务
│ └── SearchService.java # 资料搜索服务
├── repository/
│ ├── DocumentRepository.java
│ └── KnowledgeRepository.java
└── model/
├── dto/
└── entity/
核心功能实现
AI配置与初始化
@Configuration
public class AiConfig {
@Value("${spring.ai.openai.api-key}")
private String apiKey;
@Value("${spring.ai.openai.base-url}")
private String baseUrl;
@Bean
public OpenAiChatModel chatModel() {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.baseUrl(baseUrl)
.model("gpt-4")
.temperature(0.7)
.build();
}
@Bean
public EmbeddingModel embeddingModel() {
return new OpenAiEmbeddingModel(apiKey, baseUrl);
}
}
智能资料查询服务
@Service
public class SearchService {
@Autowired
private ChatModel chatModel;
@Autowired
private VectorStore vectorStore;
/**
* 智能资料查询
*/
public SearchResult searchKnowledge(String query, String userId) {
// 1. 向量相似度搜索
List<Document> relevantDocs = vectorStore.similaritySearch(
SearchRequest.query(query)
.topK(5)
.filter("userId", userId)
);
// 2. 构建上下文
String context = buildContext(relevantDocs);
// 3. 使用AI整理答案
String prompt = """
基于以下资料,回答用户问题:
资料:
%s
用户问题:%s
要求:
1. 基于资料准确回答
2. 标注引用来源
3. 如资料不足,明确说明
""".formatted(context, query);
ChatResponse response = chatModel.call(
new UserMessage(prompt)
);
return new SearchResult(
response.getResult().getOutput().getContent(),
relevantDocs
);
}
}
数据查询服务
@Service
public class DataQueryService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private ChatModel chatModel;
/**
* 自然语言转SQL查询
*/
public QueryResult queryData(String naturalQuery) {
// 1. 获取数据库schema
String schema = getDatabaseSchema();
// 2. 使用AI生成SQL
String sqlPrompt = """
基于以下数据库结构,将自然语言转换为SQL:
表结构:
%s
用户查询:"%s"
只返回SQL语句,不要解释。
""".formatted(schema, naturalQuery);
String sql = chatModel.call(sqlPrompt).getContent();
// 3. 执行查询
List<Map<String, Object>> data = jdbcTemplate.queryForList(sql);
// 4. AI分析结果
String analysisPrompt = """
分析以下数据:
%s
原始查询:"%s"
给出关键洞察和建议。
""".formatted(data.toString(), naturalQuery);
String analysis = chatModel.call(analysisPrompt).getContent();
return new QueryResult(data, analysis, sql);
}
}
智能文档生成服务
@Service
public class DocumentService {
@Autowired
private ChatModel chatModel;
/**
* 生成多种类型文档
*/
public GeneratedDocument generateDocument(DocumentRequest request) {
String template = getTemplate(request.getType());
String prompt = """
根据以下信息生成%s:
模板要求:
%s
内容数据:
%s
风格要求:%s
字数要求:%s
请生成完整文档。
""".formatted(
request.getType(),
template,
request.getContent(),
request.getStyle(),
request.getWordCount()
);
ChatResponse response = chatModel.call(
new Prompt(List.of(
new SystemMessage("你是一个专业的文档撰写助手"),
new UserMessage(prompt)
))
);
String content = response.getResult().getOutput().getContent();
// 格式化为指定格式
return formatDocument(content, request.getFormat());
}
private String getTemplate(DocumentType type) {
return switch (type) {
case REPORT -> """
# 报告结构
1. 摘要
2. 背景介绍
3. 数据分析
4. 结论
5. 建议
""";
case EMAIL -> """
# 邮件结构
收件人:{recipient}
主题:{subject}
正文:
尊敬的{recipient},
{content}
此致
{sender}
""";
case PROPOSAL -> """
# 方案结构
1. 项目背景
2. 目标
3. 实施方案
4. 时间计划
5. 预算
6. 预期效果
""";
};
}
}
一体化助手服务
@Service
public class AssistantService {
@Autowired
private SearchService searchService;
@Autowired
private DataQueryService dataQueryService;
@Autowired
private DocumentService documentService;
@Autowired
private ChatModel chatModel;
/**
* 统一处理用户请求
*/
public AssistantResponse handleRequest(UserRequest request) {
// 1. 意图识别
String intent = detectIntent(request.getQuery());
// 2. 路由到对应服务
return switch (intent) {
case "SEARCH_KNOWLEDGE" ->
handleSearch(request);
case "QUERY_DATA" ->
handleDataQuery(request);
case "GENERATE_DOCUMENT" ->
handleDocumentGeneration(request);
case "COMPLEX_TASK" ->
handleComplexTask(request);
default ->
handleGeneralChat(request);
};
}
private String detectIntent(String query) {
String prompt = """
识别用户意图,返回以下之一:
SEARCH_KNOWLEDGE - 查询资料
QUERY_DATA - 查询数据
GENERATE_DOCUMENT - 生成文档
COMPLEX_TASK - 复杂任务
GENERAL_CHAT - 一般聊天
用户输入:%s
""".formatted(query);
return chatModel.call(prompt).getContent();
}
private AssistantResponse handleComplexTask(UserRequest request) {
// 任务分解和执行
String plan = createExecutionPlan(request.getQuery());
// 分步执行
List<TaskResult> results = executePlan(plan);
// 汇总结果
String summary = summarizeResults(results);
return new ComplexTaskResponse(plan, results, summary);
}
}
REST API控制器
@RestController
@RequestMapping("/api/assistant")
public class AssistantController {
@Autowired
private AssistantService assistantService;
@PostMapping("/query")
public ResponseEntity<AssistantResponse> query(
@RequestBody UserRequest request) {
AssistantResponse response = assistantService.handleRequest(request);
return ResponseEntity.ok(response);
}
@PostMapping("/document/generate")
public ResponseEntity<GeneratedDocument> generateDocument(
@RequestBody DocumentRequest request) {
GeneratedDocument document = documentService.generateDocument(request);
return ResponseEntity.ok(document);
}
@GetMapping("/data/query")
public ResponseEntity<QueryResult> queryData(
@RequestParam String query) {
QueryResult result = dataQueryService.queryData(query);
return ResponseEntity.ok(result);
}
}
WebSocket实时通信
@Controller
public class AssistantWebSocketHandler {
@Autowired
private AssistantService assistantService;
@MessageMapping("/assistant/chat")
@SendTo("/topic/assistant/responses")
public StreamingResponse chatStream(
@Payload UserRequest request,
SimpMessageHeaderAccessor headerAccessor) {
return new StreamingResponse() {
@Override
public Flux<String> getContent() {
return Flux.create(sink -> {
// 流式响应
assistantService.streamResponse(
request,
chunk -> sink.next(chunk),
() -> sink.complete()
);
});
}
};
}
}
前端示例(Vue.js)
<template>
<div class="assistant-container">
<!-- 聊天界面 -->
<div class="chat-section">
<div v-for="msg in messages" :key="msg.id">
<div :class="['message', msg.role]">
{{ msg.content }}
</div>
</div>
</div>
<!-- 功能面板 -->
<div class="tool-panel">
<button @click="showSearch">查资料</button>
<button @click="showDataQuery">查数据</button>
<button @click="showDocumentGen">生成文档</button>
</div>
<!-- 文档生成器 -->
<div v-if="showDocumentGenerator" class="document-generator">
<select v-model="docType">
<option value="report">报告</option>
<option value="email">邮件</option>
<option value="proposal">方案</option>
</select>
<textarea v-model="docContent" placeholder="输入内容..."></textarea>
<button @click="generateDocument">生成</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useAssistantStore } from '@/stores/assistant'
const store = useAssistantStore()
const messages = ref([])
const showDocumentGenerator = ref(false)
async function sendMessage(content) {
const response = await store.queryAssistant({
query: content,
userId: 'user123'
})
messages.value.push({
role: 'assistant',
content: response.content
})
}
async function generateDocument() {
const doc = await store.generateDocument({
type: docType.value,
content: docContent.value,
format: 'markdown'
})
// 下载文档
downloadFile(doc.content, `document.${doc.format}`)
}
</script>
部署配置
application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com/v1
chat:
model: gpt-4
temperature: 0.7
embedding:
model: text-embedding-ada-002
datasource:
url: jdbc:mysql://localhost:3306/office_db
username: ${DB_USER}
password: ${DB_PASSWORD}
vectorstore:
pinecone:
api-key: ${PINECONE_API_KEY}
environment: us-west1-gcp
index-name: office-knowledge
高级功能扩展
多模型支持
@Configuration
public class MultiModelConfig {
@Bean
@Primary
@ConditionalOnProperty(name = "ai.model", havingValue = "openai")
public ChatModel openAiChatModel() {
// OpenAI配置
}
@Bean
@ConditionalOnProperty(name = "ai.model", havingValue = "local")
public ChatModel localChatModel() {
// 本地模型配置
}
}
知识库管理
@Service
public class KnowledgeManagementService {
public void addDocument(String filePath) {
// 解析文档
String content = parseDocument(filePath);
// 分块
List<TextSegment> chunks = splitIntoChunks(content);
// 生成向量并存储
List<Embedding> embeddings = embeddingModel.embed(chunks);
vectorStore.add(embeddings, chunks);
}
public void syncDatabaseKnowledge() {
// 同步数据库schema到知识库
String schema = extractDatabaseSchema();
addToKnowledgeBase("数据库结构", schema);
}
}
工作流引擎
@Service
public class WorkflowService {
public WorkflowResult executeWorkflow(String workflowName, Map<String, Object> inputs) {
// 定义工作流
Workflow workflow = workflowRegistry.get(workflowName);
// 执行步骤
return workflow.execute(inputs, context -> {
// 每个步骤可以使用AI
if (context.needsAiAssistance()) {
return callAiForStep(context);
}
return executeStep(context);
});
}
}
监控与优化
@Aspect
@Component
public class PerformanceMonitor {
@Around("@annotation(TrackPerformance)")
public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
// 记录性能指标
metricsService.recordDuration(
joinPoint.getSignature().getName(),
duration
);
return result;
}
}
这个智能办公助手系统具备以下特点:
- 一体化设计 :统一入口处理多种办公需求
- 智能路由 :自动识别用户意图并路由到对应服务
- 上下文感知 :结合知识库和历史对话
- 流式响应 :提供良好的用户体验
- 可扩展性 :易于添加新的功能模块
- 安全性 :用户隔离和权限控制
你可以根据实际需求调整和扩展这个框架,比如添加:
- 文件上传解析
- 多语言支持
- 团队协作功能
- 审批工作流集成
- 与现有OA系统对接
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)