Преглед изворни кода

新增 规划控制器 用于测试规划过程
修改 创建规划时 JSON 序列化出现问题的bug

alibct пре 2 месеци
родитељ
комит
225b48a2a9

+ 18 - 2
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/core/agent/planner/PlanContext.java

@@ -3,6 +3,9 @@ package com.pavis.admin.aigc.core.agent.planner;
 import com.pavis.admin.aigc.model.resp.AgentPlanResp;
 import lombok.Data;
 
+import java.io.Serial;
+import java.io.Serializable;
+
 /**
  * 规划上下文类
  * 用于在计划的创建、执行和总结过程中传递和维护状态信息
@@ -15,7 +18,20 @@ import lombok.Data;
  * - 控制是否需要生成执行总结
  */
 @Data
-public class PlanContext {
+public class PlanContext implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 会话ID
+     */
+    private Long conversationId;
+
+    /**
+     * 消息ID
+     */
+    private Long messageId;
 
     /**
      * 计划的唯一标识符
@@ -40,7 +56,7 @@ public class PlanContext {
     /**
      * 是否需要为执行结果调用大模型生成摘要,true是调用大模型,false是不调用直接输出结果
      */
-    private boolean needSummary;
+    private boolean needSummary = true;
 
     /**
      * 计划执行是否成功的标志

+ 46 - 16
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/core/agent/tool/PlanningTool.java

@@ -1,13 +1,12 @@
 package com.pavis.admin.aigc.core.agent.tool;
 
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.TypeReference;
 import com.pavis.admin.aigc.model.resp.AgentPlanResp;
 import com.pavis.admin.aigc.model.resp.AgentPlanStepResp;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.ai.openai.api.OpenAiApi.FunctionTool;
 import org.springframework.ai.tool.function.FunctionToolCallback;
 import org.springframework.ai.tool.metadata.ToolMetadata;
+import org.springframework.core.ParameterizedTypeReference;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -18,7 +17,7 @@ import java.util.function.Function;
  * 计划工具类
  */
 @Slf4j
-public class PlanningTool implements Function<String, ToolExecuteResult> {
+public class PlanningTool implements Function<Map<String, Object>, ToolExecuteResult> {
 
     private AgentPlanResp currentPlan;
 
@@ -39,11 +38,11 @@ public class PlanningTool implements Function<String, ToolExecuteResult> {
                         "enum": [
                             "create"
                         ],
-                        "type": "long"
+                        "type": "string"
                     },
                     "plan_id": {
                         "description": "Unique identifier for the plan",
-                        "type": "string"
+                        "type": "integer"
                     },
                     "title": {
                         "description": "Title for the plan",
@@ -83,23 +82,53 @@ public class PlanningTool implements Function<String, ToolExecuteResult> {
     }
 
     public FunctionToolCallback getFunctionToolCallback() {
+        // 创建保留泛型信息的类型引用
+        ParameterizedTypeReference<Map<String, Object>> typeRef =
+                new ParameterizedTypeReference<Map<String, Object>>() {
+                };
+
         return FunctionToolCallback.builder(name, this)
                 .description(description)
                 .inputSchema(PARAMETERS)
-                .inputType(String.class)
+                .inputType(typeRef) // 使用 ParameterizedTypeReference
                 .toolMetadata(ToolMetadata.builder().returnDirect(true).build())
                 .build();
     }
 
-    public ToolExecuteResult run(String toolInput) {
+    public ToolExecuteResult run(Map<String, Object> toolInput) {
         try {
-            Map<String, Object> input = JSON.parseObject(toolInput, new TypeReference<Map<String, Object>>() {
-            });
-            String command = (String) input.get("command");
-            Long planId = (Long) input.get("plan_id");
-            String title = (String) input.get("title");
-            List<String> steps = JSON.parseObject(JSON.toJSONString(input.get("steps")), new TypeReference<>() {
-            });
+            log.info("Planning tool parsed input: {}", toolInput);
+            String command = (String) toolInput.get("command");
+
+            // 安全处理 plan_id
+            Long planId = null;
+            Object planIdObj = toolInput.get("plan_id");
+            if (planIdObj != null) {
+                if (planIdObj instanceof Number) {
+                    planId = ((Number) planIdObj).longValue();
+                } else {
+                    try {
+                        planId = Long.parseLong(planIdObj.toString());
+                    } catch (NumberFormatException e) {
+                        log.warn("Invalid plan_id format: {}", planIdObj);
+                    }
+                }
+            }
+
+            String title = (String) toolInput.get("title");
+
+            // 安全处理 steps
+            List<String> steps = new ArrayList<>();
+            Object stepsObj = toolInput.get("steps");
+            if (stepsObj instanceof List) {
+                for (Object item : (List<?>) stepsObj) {
+                    if (item != null) {
+                        steps.add(item.toString());
+                    }
+                }
+            }
+
+            log.info("Executing command: {}, planId: {}, title: {}, steps: {}", command, planId, title, steps);
             return switch (command) {
                 case "create" -> createPlan(planId, title, steps);
                 // case "update" -> updatePlan(planId, title, steps);
@@ -139,8 +168,9 @@ public class PlanningTool implements Function<String, ToolExecuteResult> {
     }
 
     @Override
-    public ToolExecuteResult apply(String input) {
-        return run(input);
+    public ToolExecuteResult apply(Map<String, Object> toolInput) {
+        log.info("Planning tool raw input: {}", toolInput);
+        return run(toolInput);
     }
 
 }

+ 16 - 17
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/service/impl/AgentPlanServiceImpl.java

@@ -3,26 +3,24 @@ package com.pavis.admin.aigc.service.impl;
 import com.pavis.admin.aigc.core.agent.planner.PlanContext;
 import com.pavis.admin.aigc.core.agent.tool.PlanningTool;
 import com.pavis.admin.aigc.core.llm.LlmService;
+import com.pavis.admin.aigc.mapper.AgentPlanMapper;
+import com.pavis.admin.aigc.model.entity.AgentPlanDO;
+import com.pavis.admin.aigc.model.query.AgentPlanQuery;
 import com.pavis.admin.aigc.model.query.AgentQuery;
+import com.pavis.admin.aigc.model.req.AgentPlanReq;
+import com.pavis.admin.aigc.model.resp.AgentPlanDetailResp;
+import com.pavis.admin.aigc.model.resp.AgentPlanResp;
 import com.pavis.admin.aigc.model.resp.AgentResp;
+import com.pavis.admin.aigc.service.AgentPlanService;
 import com.pavis.admin.aigc.service.AgentService;
 import lombok.RequiredArgsConstructor;
-
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.ai.chat.client.ChatClient;
 import org.springframework.ai.chat.prompt.Prompt;
 import org.springframework.ai.chat.prompt.PromptTemplate;
 import org.springframework.stereotype.Service;
-
 import top.continew.starter.extension.crud.model.query.SortQuery;
 import top.continew.starter.extension.crud.service.BaseServiceImpl;
-import com.pavis.admin.aigc.mapper.AgentPlanMapper;
-import com.pavis.admin.aigc.model.entity.AgentPlanDO;
-import com.pavis.admin.aigc.model.query.AgentPlanQuery;
-import com.pavis.admin.aigc.model.req.AgentPlanReq;
-import com.pavis.admin.aigc.model.resp.AgentPlanDetailResp;
-import com.pavis.admin.aigc.model.resp.AgentPlanResp;
-import com.pavis.admin.aigc.service.AgentPlanService;
 
 import java.util.List;
 
@@ -53,7 +51,6 @@ public class AgentPlanServiceImpl extends BaseServiceImpl<AgentPlanMapper, Agent
             AgentPlanResp currentPlan = null;
             // 生成计划提示
             String planPrompt = generatePlanPrompt(context.getUserMessage(), agentsInfo, planId);
-
             // 使用 LLM 生成计划
             PromptTemplate promptTemplate = new PromptTemplate(planPrompt);
             Prompt prompt = promptTemplate.create();
@@ -64,7 +61,7 @@ public class AgentPlanServiceImpl extends BaseServiceImpl<AgentPlanMapper, Agent
             ChatClient.CallResponseSpec response = llmService.getPlanningChatClient()
                     .prompt(prompt)
                     .toolCallbacks(List.of(planningTool.getFunctionToolCallback()))
-                    .advisors(memoryAdvisor -> memoryAdvisor.param("chat_memory_conversation_id", planId)
+                    .advisors(memoryAdvisor -> memoryAdvisor.param("chat_memory_conversation_id", context.getConversationId())
                             .param("chat_memory_retrieve_size", 100))
                     .call();
             String outputText = response.chatResponse().getResult().getOutput().getText();
@@ -101,12 +98,14 @@ public class AgentPlanServiceImpl extends BaseServiceImpl<AgentPlanMapper, Agent
         SortQuery sortQuery = new SortQuery();
         List<AgentResp> agents = agentService.list(query, sortQuery);
         StringBuilder agentsInfo = new StringBuilder("Available Agents:\n");
-        for (AgentResp agent : agents) {
-            agentsInfo.append("- Agent Name: ")
-                    .append(agent.getName())
-                    .append("\n  Description: ")
-                    .append(agent.getDescription())
-                    .append("\n");
+        if (agents != null && !agents.isEmpty()) {
+            for (AgentResp agent : agents) {
+                agentsInfo.append("- Agent Name: ")
+                        .append(agent.getName())
+                        .append("\n  Description: ")
+                        .append(agent.getDescription())
+                        .append("\n");
+            }
         }
         return agentsInfo.toString();
     }

+ 54 - 0
pavis-webapi/src/main/java/com/pavis/admin/controller/aigc/AgentPlanController.java

@@ -0,0 +1,54 @@
+package com.pavis.admin.controller.aigc;
+
+import com.pavis.admin.aigc.core.agent.planner.PlanContext;
+import com.pavis.admin.aigc.model.query.AgentPlanQuery;
+import com.pavis.admin.aigc.model.req.AgentPlanReq;
+import com.pavis.admin.aigc.model.resp.AgentPlanDetailResp;
+import com.pavis.admin.aigc.model.resp.AgentPlanResp;
+import com.pavis.admin.aigc.service.AgentPlanService;
+import com.pavis.admin.common.controller.BaseController;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
+import top.continew.starter.extension.crud.enums.Api;
+
+import java.util.Map;
+
+/**
+ * 智能体规划记录管理 API
+ *
+ * @author semi
+ * @since 2025/05/28 16:59
+ */
+@Tag(name = "智能体规划记录管理 API")
+@RestController
+@CrudRequestMapping(value = "/aigc/agentPlan", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE, Api.EXPORT})
+public class AgentPlanController extends BaseController<AgentPlanService, AgentPlanResp, AgentPlanDetailResp, AgentPlanQuery, AgentPlanReq> {
+
+    @Autowired
+    private AgentPlanService agentPlanService;
+
+    /**
+     * 生成计划
+     *
+     * @param request 用户请求JSON信息
+     * @return 计划上下文信息
+     */
+    @PostMapping("/generate")
+    public PlanContext generatePlan(@RequestBody Map<String, Object> request) {
+        Long conversationId = (Long) request.get("conversationId");
+        Long messageId = (Long) request.get("messageId");
+        Long planId = (Long) request.get("planId");
+        String userMessage = (String) request.get("userMessage");
+        PlanContext context = new PlanContext();
+        context.setConversationId(conversationId);
+        context.setMessageId(messageId);
+        context.setPlanId(planId);
+        context.setUserMessage(userMessage);
+        return agentPlanService.createPlan(context);
+    }
+
+}

+ 1 - 1
pavis-webapi/src/main/resources/config/application-dev.yml

@@ -13,7 +13,7 @@ spring:
   ai:
     openai:
       base-url: https://dashscope.aliyuncs.com/compatible-mode
-      api-key: ${AI_DASHSCOPE_API_KEY:sk-0030e327c58e4321b5cc51c3bf79ff7c}
+      api-key: ${AI_DASHSCOPE_API_KEY:sk-e9855234f47346049809ce23ed3ebe3f}
       chat:
         options:
           model: qwen-max-latest