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智能体想象成一个经验丰富的项目助理 :

  1. 接到任务 (用户请求)后,他不会立刻埋头苦干,而是先制定一个项目计划 (自主规划 )。
  2. 在计划中,他知道哪些工作自己可以做(LLM内部推理),哪些需要联系其他部门或使用专业软件 (工具调用 ):比如让市场部(搜索工具)提供数据,让财务部(计算工具)核算成本。
  3. 在执行过程中,他会不断跟进和协调 (迭代执行 ):如果市场部给的数据不对,他会要求澄清或寻找其他来源;如果发现计划有瑕疵,他会及时调整。直到所有环节就绪,他才会向你汇报最终成果。
Spring AI 的支持

Spring AI 通过高层次的抽象,简化了构建此类智能体的过程:

  • ​Agent​​ 接口 :定义了智能体的核心行为。
  • ​Tool​​ 接口 :统一了工具调用的方式。
  • ​PromptTemplate​​ :帮助构建指导智能体进行规划和决策的提示词。
  • 多种内置代理实现 :如 ReActAgentChainOfThoughtAgent 等,提供了开箱即用的经典推理模式。

通过组合这些组件,开发者可以专注于业务逻辑和工具定义,而无需从头实现复杂的推理循环机制,从而高效地构建出能够解决实际复杂问题的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();
    }
}

快速开始步骤:

  1. 添加依赖 :
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
  1. 配置API密钥
  2. 定义工具
  3. 创建智能体
  4. 实现任务拆解逻辑
  5. 添加监控和错误处理

这种架构提供了灵活的工具集成、智能的任务拆解能力,并且易于扩展和维护。

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分钟
性能优化建议
  1. 并行执行 :不依赖的工具可以并行执行
  2. 结果缓存 :频繁查询的结果进行缓存
  3. 增量更新 :知识库向量增量更新
  4. 连接池 :业务API调用使用连接池
  5. 流式响应 :长时间操作使用流式响应

总结

Spring AI 多工具联动通过以下关键设计实现:

  1. 工具抽象 :统一 FunctionCallback 接口
  2. 智能编排 :LLM 决策工具调用顺序
  3. 上下文传递 :工具间结果传递和共享
  4. 错误处理 :优雅降级和重试机制
  5. 监控观测 :完整的执行链路追踪

这种架构可以灵活扩展新的工具,适应复杂的业务场景,同时保持系统的可维护性和可观测性。

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;
    }
}

这个智能办公助手系统具备以下特点:

  1. 一体化设计 :统一入口处理多种办公需求
  2. 智能路由 :自动识别用户意图并路由到对应服务
  3. 上下文感知 :结合知识库和历史对话
  4. 流式响应 :提供良好的用户体验
  5. 可扩展性 :易于添加新的功能模块
  6. 安全性 :用户隔离和权限控制

你可以根据实际需求调整和扩展这个框架,比如添加:

  • 文件上传解析
  • 多语言支持
  • 团队协作功能
  • 审批工作流集成
  • 与现有OA系统对接

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐