瀏覽代碼

增加与ai大模型对话

wwh 3 周之前
父節點
當前提交
6a3559daa7

+ 15 - 29
huimv-employment/fe-api/src/main/java/com/huimv/employment/controller/mcp/McpDraftController.java

@@ -2,6 +2,7 @@ package com.huimv.employment.controller.mcp;
2 2
 
3 3
 import com.huimv.employment.common.web.R;
4 4
 import com.huimv.employment.service.draft.McpDraftService;
5
+import com.huimv.employment.service.draft.dto.McpDraftCalculateRequest;
5 6
 import com.huimv.employment.service.draft.dto.McpDraftCalculateResponse;
6 7
 import com.huimv.employment.service.draft.dto.McpDraftGenerateRequest;
7 8
 import com.huimv.employment.service.draft.dto.McpDraftGenerateResponse;
@@ -19,25 +20,22 @@ import org.springframework.web.bind.annotation.GetMapping;
19 20
 import org.springframework.web.bind.annotation.PostMapping;
20 21
 import org.springframework.web.bind.annotation.PutMapping;
21 22
 import org.springframework.web.bind.annotation.RequestBody;
22
-import org.springframework.web.bind.annotation.RequestHeader;
23 23
 import org.springframework.web.bind.annotation.RequestMapping;
24
+import org.springframework.web.bind.annotation.RequestParam;
24 25
 import org.springframework.web.bind.annotation.RestController;
25 26
 
26 27
 /**
27 28
  * MCP 草稿接口(交互规则 v2 §6.3)。
28 29
  * <p>
29
- * 通过 {@code X-Session-Id} + {@code X-Agent-Id} 自动关联会话与草稿,Agent 无需传递 draft_id。
30
+ * 通过请求体/查询参数 {@code session_id}(= conversation_no)自动关联会话与草稿,Agent 无需传递 draft_id。
30 31
  * 鉴权见 {@code fe.internal.ai-key} 与 {@link com.huimv.employment.security.McpAuthFilter}。
31 32
  * </p>
32 33
  */
33 34
 @RestController
34 35
 @RequestMapping("/api/mcp/draft")
35
-@Tag(name = "MCP-草稿", description = "智能体草稿 generate/update/info,需 X-Fe-Ai-Key + X-Session-Id")
36
+@Tag(name = "MCP-草稿", description = "智能体草稿 generate/update/info,需 X-Fe-Ai-Key + session_id")
36 37
 public class McpDraftController {
37 38
 
38
-    public static final String HEADER_SESSION_ID = "X-Session-Id";
39
-    public static final String HEADER_AGENT_ID = "X-Agent-Id";
40
-
41 39
     private final McpDraftService mcpDraftService;
42 40
 
43 41
     public McpDraftController(McpDraftService mcpDraftService) {
@@ -48,40 +46,32 @@ public class McpDraftController {
48 46
     @Operation(summary = "生成初始草稿结构",
49 47
             description = "后端生成含 Schema、默认值与 missing_fields 的草稿骨架。同会话已有 pending 草稿时幂等返回。",
50 48
             parameters = {
51
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true,
52
-                            description = "会话标识,与 AI chat session_id / conversation_no 一致"),
53
-                    @Parameter(name = HEADER_AGENT_ID, in = ParameterIn.HEADER,
54
-                            description = "智能体标识,默认 default"),
55 49
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER,
56 50
                             description = "内网服务密钥")
57 51
             })
58
-    public R<McpDraftGenerateResponse> generate(
59
-            @RequestHeader(HEADER_SESSION_ID) String sessionId,
60
-            @Validated @RequestBody McpDraftGenerateRequest request) {
61
-        return R.ok(mcpDraftService.generate(sessionId, request));
52
+    public R<McpDraftGenerateResponse> generate(@Validated @RequestBody McpDraftGenerateRequest request) {
53
+        return R.ok(mcpDraftService.generate(request.getSessionId(), request));
62 54
     }
63 55
 
64 56
     @PutMapping("/update")
65 57
     @Operation(summary = "更新草稿数据",
66 58
             description = "根据用户回答或画像预填字段;不可编辑时返回 status=ban。",
67 59
             parameters = {
68
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true),
69 60
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER)
70 61
             })
71
-    public R<McpDraftUpdateResponse> update(
72
-            @RequestHeader(HEADER_SESSION_ID) String sessionId,
73
-            @Validated @RequestBody McpDraftUpdateRequest request) {
74
-        return R.ok(mcpDraftService.update(sessionId, request));
62
+    public R<McpDraftUpdateResponse> update(@Validated @RequestBody McpDraftUpdateRequest request) {
63
+        return R.ok(mcpDraftService.update(request.getSessionId(), request));
75 64
     }
76 65
 
77 66
     @GetMapping("/info")
78 67
     @Operation(summary = "获取草稿详情与状态",
79 68
             description = "返回 status(incomplete/ready/submitted)、data、editable、missing_fields。",
80 69
             parameters = {
81
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true),
70
+                    @Parameter(name = "session_id", in = ParameterIn.QUERY, required = true,
71
+                            description = "会话标识,与 AI chat session_id / conversation_no 一致"),
82 72
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER)
83 73
             })
84
-    public R<McpDraftInfoResponse> info(@RequestHeader(HEADER_SESSION_ID) String sessionId) {
74
+    public R<McpDraftInfoResponse> info(@RequestParam("session_id") String sessionId) {
85 75
         return R.ok(mcpDraftService.getInfo(sessionId));
86 76
     }
87 77
 
@@ -89,23 +79,19 @@ public class McpDraftController {
89 79
     @Operation(summary = "成本测算",
90 80
             description = "草稿 status=ready 后调用,返回 SCHEME_A/SCHEME_B 多套合规方案。",
91 81
             parameters = {
92
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true),
93 82
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER)
94 83
             })
95
-    public R<McpDraftCalculateResponse> calculate(@RequestHeader(HEADER_SESSION_ID) String sessionId) {
96
-        return R.ok(mcpDraftService.calculate(sessionId));
84
+    public R<McpDraftCalculateResponse> calculate(@Validated @RequestBody McpDraftCalculateRequest request) {
85
+        return R.ok(mcpDraftService.calculate(request.getSessionId()));
97 86
     }
98 87
 
99 88
     @PostMapping("/submit")
100 89
     @Operation(summary = "确认并提交草稿",
101 90
             description = "用户选定方案后转化为正式订单,需先调用 calculate。",
102 91
             parameters = {
103
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true),
104 92
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER)
105 93
             })
106
-    public R<McpDraftSubmitResponse> submit(
107
-            @RequestHeader(HEADER_SESSION_ID) String sessionId,
108
-            @Validated @RequestBody McpDraftSubmitRequest request) {
109
-        return R.ok(mcpDraftService.submit(sessionId, request));
94
+    public R<McpDraftSubmitResponse> submit(@Validated @RequestBody McpDraftSubmitRequest request) {
95
+        return R.ok(mcpDraftService.submit(request.getSessionId(), request));
110 96
     }
111 97
 }

+ 6 - 10
huimv-employment/fe-api/src/main/java/com/huimv/employment/controller/mcp/McpEnterpriseProfileController.java

@@ -13,24 +13,22 @@ import org.springframework.validation.annotation.Validated;
13 13
 import org.springframework.web.bind.annotation.GetMapping;
14 14
 import org.springframework.web.bind.annotation.PutMapping;
15 15
 import org.springframework.web.bind.annotation.RequestBody;
16
-import org.springframework.web.bind.annotation.RequestHeader;
17 16
 import org.springframework.web.bind.annotation.RequestMapping;
17
+import org.springframework.web.bind.annotation.RequestParam;
18 18
 import org.springframework.web.bind.annotation.RestController;
19 19
 
20 20
 /**
21 21
  * MCP 企业画像接口(交互规则 v2 §6.2)。
22 22
  * <p>
23
- * 通过 {@code X-Session-Id} 自动关联会话与企业,Agent 无需传递 enterprise_id。
23
+ * 通过请求体/查询参数 {@code session_id} 自动关联会话与企业,Agent 无需传递 enterprise_id。
24 24
  * 鉴权见 {@code fe.internal.ai-key} 与 {@link com.huimv.employment.security.McpAuthFilter}。
25 25
  * </p>
26 26
  */
27 27
 @RestController
28 28
 @RequestMapping("/api/mcp/enterprise")
29
-@Tag(name = "MCP-企业画像", description = "智能体加载/更新企业画像,需 X-Fe-Ai-Key + X-Session-Id")
29
+@Tag(name = "MCP-企业画像", description = "智能体加载/更新企业画像,需 X-Fe-Ai-Key + session_id")
30 30
 public class McpEnterpriseProfileController {
31 31
 
32
-    public static final String HEADER_SESSION_ID = "X-Session-Id";
33
-
34 32
     private final McpEnterpriseProfileService mcpEnterpriseProfileService;
35 33
 
36 34
     public McpEnterpriseProfileController(McpEnterpriseProfileService mcpEnterpriseProfileService) {
@@ -41,12 +39,12 @@ public class McpEnterpriseProfileController {
41 39
     @Operation(summary = "获取企业画像",
42 40
             description = "会话初始化时加载企业基础信息与偏好设置,供 Agent 注入上下文。",
43 41
             parameters = {
44
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true,
42
+                    @Parameter(name = "session_id", in = ParameterIn.QUERY, required = true,
45 43
                             description = "会话标识,与 AI chat session_id / conversation_no 一致"),
46 44
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER,
47 45
                             description = "内网服务密钥")
48 46
             })
49
-    public R<McpEnterpriseProfileResponse> getProfile(@RequestHeader(HEADER_SESSION_ID) String sessionId) {
47
+    public R<McpEnterpriseProfileResponse> getProfile(@RequestParam("session_id") String sessionId) {
50 48
         return R.ok(mcpEnterpriseProfileService.getProfile(sessionId));
51 49
     }
52 50
 
@@ -54,12 +52,10 @@ public class McpEnterpriseProfileController {
54 52
     @Operation(summary = "增量更新企业画像",
55 53
             description = "捕获对话中的新信息(如地址变更、结算偏好),支持 preferences.xxx 点路径。",
56 54
             parameters = {
57
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true),
58 55
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER)
59 56
             })
60 57
     public R<McpEnterpriseProfileUpdateResponse> updateProfile(
61
-            @RequestHeader(HEADER_SESSION_ID) String sessionId,
62 58
             @Validated @RequestBody McpEnterpriseProfileUpdateRequest request) {
63
-        return R.ok(mcpEnterpriseProfileService.updateProfile(sessionId, request));
59
+        return R.ok(mcpEnterpriseProfileService.updateProfile(request.getSessionId(), request));
64 60
     }
65 61
 }

+ 5 - 11
huimv-employment/fe-api/src/main/java/com/huimv/employment/controller/mcp/McpOrderController.java

@@ -13,7 +13,6 @@ import org.springframework.validation.annotation.Validated;
13 13
 import org.springframework.web.bind.annotation.GetMapping;
14 14
 import org.springframework.web.bind.annotation.PostMapping;
15 15
 import org.springframework.web.bind.annotation.RequestBody;
16
-import org.springframework.web.bind.annotation.RequestHeader;
17 16
 import org.springframework.web.bind.annotation.RequestMapping;
18 17
 import org.springframework.web.bind.annotation.RequestParam;
19 18
 import org.springframework.web.bind.annotation.RestController;
@@ -23,11 +22,9 @@ import org.springframework.web.bind.annotation.RestController;
23 22
  */
24 23
 @RestController
25 24
 @RequestMapping("/api/mcp/orders")
26
-@Tag(name = "MCP-订单", description = "订单查询与克隆至草稿,需 X-Fe-Ai-Key + X-Session-Id")
25
+@Tag(name = "MCP-订单", description = "订单查询与克隆至草稿,需 X-Fe-Ai-Key + session_id")
27 26
 public class McpOrderController {
28 27
 
29
-    public static final String HEADER_SESSION_ID = "X-Session-Id";
30
-
31 28
     private final McpOrderService mcpOrderService;
32 29
 
33 30
     public McpOrderController(McpOrderService mcpOrderService) {
@@ -38,7 +35,7 @@ public class McpOrderController {
38 35
     @Operation(summary = "统一订单查询",
39 36
             description = "按企业上下文查询历史/进行中订单,支持 status、limit 筛选,用于再来一单引导。",
40 37
             parameters = {
41
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true,
38
+                    @Parameter(name = "session_id", in = ParameterIn.QUERY, required = true,
42 39
                             description = "会话标识,与 AI chat session_id / conversation_no 一致"),
43 40
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER,
44 41
                             description = "内网服务密钥"),
@@ -48,7 +45,7 @@ public class McpOrderController {
48 45
                             description = "返回条数,默认 10,最大 50")
49 46
             })
50 47
     public R<McpOrderListResponse> listOrders(
51
-            @RequestHeader(HEADER_SESSION_ID) String sessionId,
48
+            @RequestParam("session_id") String sessionId,
52 49
             @RequestParam(required = false) String status,
53 50
             @RequestParam(required = false) Integer limit) {
54 51
         return R.ok(mcpOrderService.listOrders(sessionId, status, limit));
@@ -58,12 +55,9 @@ public class McpOrderController {
58 55
     @Operation(summary = "克隆历史订单至草稿",
59 56
             description = "将历史订单快照转化为新草稿并绑定当前会话,随后可 GET /api/mcp/draft/info 检查待补字段。",
60 57
             parameters = {
61
-                    @Parameter(name = HEADER_SESSION_ID, in = ParameterIn.HEADER, required = true),
62 58
                     @Parameter(name = "X-Fe-Ai-Key", in = ParameterIn.HEADER)
63 59
             })
64
-    public R<McpOrderCloneResponse> cloneToDraft(
65
-            @RequestHeader(HEADER_SESSION_ID) String sessionId,
66
-            @Validated @RequestBody McpOrderCloneRequest request) {
67
-        return R.ok(mcpOrderService.cloneToDraft(sessionId, request));
60
+    public R<McpOrderCloneResponse> cloneToDraft(@Validated @RequestBody McpOrderCloneRequest request) {
61
+        return R.ok(mcpOrderService.cloneToDraft(request.getSessionId(), request));
68 62
     }
69 63
 }

+ 1 - 1
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/conversation/ConversationService.java

@@ -120,7 +120,7 @@ public class ConversationService {
120 120
      */
121 121
     public FeConversation requireBySessionId(String sessionId) {
122 122
         if (!StringUtils.hasText(sessionId)) {
123
-            throw new BizException(ErrorCode.BAD_REQUEST, "X-Session-Id 不能为空");
123
+            throw new BizException(ErrorCode.BAD_REQUEST, "session_id 不能为空");
124 124
         }
125 125
         String conversationNo = normalizeConversationNo(sessionId.trim());
126 126
         FeConversation conversation = feConversationMapper.selectOne(new LambdaQueryWrapper<FeConversation>()

+ 15 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/draft/dto/McpDraftGenerateRequest.java

@@ -1,5 +1,6 @@
1 1
 package com.huimv.employment.service.draft.dto;
2 2
 
3
+import com.fasterxml.jackson.annotation.JsonProperty;
3 4
 import io.swagger.v3.oas.annotations.media.Schema;
4 5
 
5 6
 import javax.validation.constraints.NotBlank;
@@ -7,6 +8,12 @@ import javax.validation.constraints.NotBlank;
7 8
 @Schema(description = "MCP 生成初始草稿请求")
8 9
 public class McpDraftGenerateRequest {
9 10
 
11
+    @NotBlank(message = "session_id 不能为空")
12
+    @JsonProperty("session_id")
13
+    @Schema(description = "会话标识,与 AI chat session_id / conversation_no 一致",
14
+            example = "a1b2c3d4e5f6", requiredMode = Schema.RequiredMode.REQUIRED)
15
+    private String sessionId;
16
+
10 17
     @Schema(description = "来源类型:intent / clone / button", example = "intent", requiredMode = Schema.RequiredMode.REQUIRED)
11 18
     @NotBlank(message = "source_type 不能为空")
12 19
     private String sourceType;
@@ -17,6 +24,14 @@ public class McpDraftGenerateRequest {
17 24
     @Schema(description = "历史订单 ID(source_type=clone 时使用)")
18 25
     private String historyOrderId;
19 26
 
27
+    public String getSessionId() {
28
+        return sessionId;
29
+    }
30
+
31
+    public void setSessionId(String sessionId) {
32
+        this.sessionId = sessionId;
33
+    }
34
+
20 35
     public String getSourceType() {
21 36
         return sourceType;
22 37
     }

+ 14 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/draft/dto/McpDraftSubmitRequest.java

@@ -8,11 +8,25 @@ import javax.validation.constraints.NotBlank;
8 8
 @Schema(description = "MCP 确认提交草稿请求(v2 §6.3.5)")
9 9
 public class McpDraftSubmitRequest {
10 10
 
11
+    @NotBlank(message = "session_id 不能为空")
12
+    @JsonProperty("session_id")
13
+    @Schema(description = "会话标识,与 AI chat session_id / conversation_no 一致",
14
+            example = "a1b2c3d4e5f6", requiredMode = Schema.RequiredMode.REQUIRED)
15
+    private String sessionId;
16
+
11 17
     @NotBlank(message = "selected_scheme_code 不能为空")
12 18
     @JsonProperty("selected_scheme_code")
13 19
     @Schema(description = "用户选定的方案编码", example = "SCHEME_A", requiredMode = Schema.RequiredMode.REQUIRED)
14 20
     private String selectedSchemeCode;
15 21
 
22
+    public String getSessionId() {
23
+        return sessionId;
24
+    }
25
+
26
+    public void setSessionId(String sessionId) {
27
+        this.sessionId = sessionId;
28
+    }
29
+
16 30
     public String getSelectedSchemeCode() {
17 31
         return selectedSchemeCode;
18 32
     }

+ 16 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/draft/dto/McpDraftUpdateRequest.java

@@ -1,18 +1,34 @@
1 1
 package com.huimv.employment.service.draft.dto;
2 2
 
3
+import com.fasterxml.jackson.annotation.JsonProperty;
3 4
 import io.swagger.v3.oas.annotations.media.Schema;
4 5
 
6
+import javax.validation.constraints.NotBlank;
5 7
 import javax.validation.constraints.NotEmpty;
6 8
 import java.util.Map;
7 9
 
8 10
 @Schema(description = "MCP 更新草稿请求")
9 11
 public class McpDraftUpdateRequest {
10 12
 
13
+    @NotBlank(message = "session_id 不能为空")
14
+    @JsonProperty("session_id")
15
+    @Schema(description = "会话标识,与 AI chat session_id / conversation_no 一致",
16
+            example = "a1b2c3d4e5f6", requiredMode = Schema.RequiredMode.REQUIRED)
17
+    private String sessionId;
18
+
11 19
     @Schema(description = "待更新字段(snake_case 键名)", requiredMode = Schema.RequiredMode.REQUIRED,
12 20
             example = "{\"worker_count\": 10, \"total_amount\": 3000}")
13 21
     @NotEmpty(message = "fields 不能为空")
14 22
     private Map<String, Object> fields;
15 23
 
24
+    public String getSessionId() {
25
+        return sessionId;
26
+    }
27
+
28
+    public void setSessionId(String sessionId) {
29
+        this.sessionId = sessionId;
30
+    }
31
+
16 32
     public Map<String, Object> getFields() {
17 33
         return fields;
18 34
     }

+ 16 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/enterprise/dto/McpEnterpriseProfileUpdateRequest.java

@@ -1,18 +1,34 @@
1 1
 package com.huimv.employment.service.enterprise.dto;
2 2
 
3
+import com.fasterxml.jackson.annotation.JsonProperty;
3 4
 import io.swagger.v3.oas.annotations.media.Schema;
4 5
 
6
+import javax.validation.constraints.NotBlank;
5 7
 import javax.validation.constraints.NotEmpty;
6 8
 import java.util.Map;
7 9
 
8 10
 @Schema(description = "MCP 企业画像增量更新请求(v2 §6.2.2)")
9 11
 public class McpEnterpriseProfileUpdateRequest {
10 12
 
13
+    @NotBlank(message = "session_id 不能为空")
14
+    @JsonProperty("session_id")
15
+    @Schema(description = "会话标识,与 AI chat session_id / conversation_no 一致",
16
+            example = "a1b2c3d4e5f6", requiredMode = Schema.RequiredMode.REQUIRED)
17
+    private String sessionId;
18
+
11 19
     @NotEmpty(message = "updates 不能为空")
12 20
     @Schema(description = "增量更新字段,支持点路径如 preferences.settlement_cycle",
13 21
             example = "{\"preferences.settlement_cycle\":\"monthly\",\"company_address\":\"上海市浦东新区...\"}")
14 22
     private Map<String, Object> updates;
15 23
 
24
+    public String getSessionId() {
25
+        return sessionId;
26
+    }
27
+
28
+    public void setSessionId(String sessionId) {
29
+        this.sessionId = sessionId;
30
+    }
31
+
16 32
     public Map<String, Object> getUpdates() {
17 33
         return updates;
18 34
     }

+ 14 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/order/dto/McpOrderCloneRequest.java

@@ -8,11 +8,25 @@ import javax.validation.constraints.NotBlank;
8 8
 @Schema(description = "MCP 克隆订单至草稿请求(v2 §6.3.7)")
9 9
 public class McpOrderCloneRequest {
10 10
 
11
+    @NotBlank(message = "session_id 不能为空")
12
+    @JsonProperty("session_id")
13
+    @Schema(description = "会话标识,与 AI chat session_id / conversation_no 一致",
14
+            example = "a1b2c3d4e5f6", requiredMode = Schema.RequiredMode.REQUIRED)
15
+    private String sessionId;
16
+
11 17
     @NotBlank(message = "order_id 不能为空")
12 18
     @JsonProperty("order_id")
13 19
     @Schema(description = "历史订单编号", example = "ord_111", requiredMode = Schema.RequiredMode.REQUIRED)
14 20
     private String orderId;
15 21
 
22
+    public String getSessionId() {
23
+        return sessionId;
24
+    }
25
+
26
+    public void setSessionId(String sessionId) {
27
+        this.sessionId = sessionId;
28
+    }
29
+
16 30
     public String getOrderId() {
17 31
         return orderId;
18 32
     }