InteractionTool.java
2.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.xly.tool;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* AskUser 工具(架构 §5 #4)——消歧 / 澄清用的小问题:一句问题 + 若干可点选项(也允许自由输入)。
*
* <p>工具返回结构化 JSON;{@code AgentChatController} 侦测到 {@code type=question} 后推一条 SSE
* {@code question} 事件,前端渲染可点选项片。用户点选/输入的答复作为下一条消息进入对话,凭 ChatMemory
* 自然接续(无需额外的 pending 状态机即可完成一轮澄清)。工具无状态、单例。
*/
@Component
public class InteractionTool {
private final ObjectMapper mapper;
public InteractionTool(ObjectMapper mapper) {
this.mapper = mapper;
}
@Tool("向用户提出一个澄清/消歧的小问题并给出可选项。当用户意图不明确、或需要在几个候选中二选一时使用;"
+ "问完即结束本轮、等待用户回答。options 用中文顿号或逗号分隔(如「本月、上月、本季度」),可留空表示自由回答。")
public String askUser(
@P("要问用户的问题") String question,
@P(value = "候选选项,用、或,分隔;没有明确候选时留空", required = false) String options) {
List<String> opts = new ArrayList<>();
if (options != null && !options.isBlank()) {
for (String o : options.split("[、,,]")) {
String t = o.trim();
if (!t.isEmpty()) {
opts.add(t);
}
}
}
Map<String, Object> out = new LinkedHashMap<>();
out.put("type", "question");
out.put("question", question == null ? "" : question.trim());
out.put("options", opts);
// Claude Code 风格:给了选项也永远保留「自由输入」作为最后一个选项
out.put("allowFree", true);
try {
return mapper.writeValueAsString(out);
} catch (Exception e) {
return "{\"type\":\"question\",\"question\":\"" + (question == null ? "" : question) + "\",\"options\":[],\"allowFree\":true}";
}
}
}