工具开发
开发业务工具,让 LLM 调用后端业务能力。每个工具是一个 @Tool 方法,继承 BaseToolSupport。
基本结构
java
@Slf4j
@Component
@RequiredArgsConstructor
public class XiuxianUserTools extends BaseToolSupport {
private static final String USER_INFO = """
**【${name}】${infoTitle}**
| 属性 | 值 |
|------|------|
| 境界 | ${realm} |
| 灵根类型 | ${spiritRootType} |
| 状态 | ${statusName} |
""";
private final XiuxianUserService userService;
@Tool(description = "查询修士基本信息")
public String queryUserBasic(
@ToolParam(description = "修士的道号或姓名") String userName,
ToolContext toolContext) {
// ...
}
}BaseToolSupport 工具方法
| 方法 | 说明 |
|---|---|
render(template, params) | Velocity 模板渲染 |
notifyProgress(message, ctx) | 发送 PROGRESS 进度通知 |
error(message) | ❌ ${message} |
success(message) | ✅ ${message} |
warning(message) | ⚠️ ${message} |
updateField(setter, value, allowClear) | 统一字段更新(控制是否允许清空) |
updateIfPresent(setter, value) | null / 空字符串跳过 |
updateOrClear(setter, value) | 允许清空 |
checkPeakPermission(user, action, ctx) | 峰主数据权限检查 |
executePageQuery(service, wrapper, pn, ps, mapper) | 分页查询模板 |
renderPageResult(result, template) | 渲染分页结果 |
formatGradeLevel(grade, level) | 格式化品阶(如"天·上品") |
formatRealm(realm, level) | 格式化境界(如"筑基初期") |
bold(text) | 加粗文本 |
nv(value) | 空值转 "-" |
获取上下文
每个 @Tool 方法需接收 ToolContext 参数,从中获取 XiuxianAgentContext:
java
@Tool(description = "查询修士基本信息")
public String queryUserBasic(
@ToolParam(description = "修士的道号或姓名") String userName,
ToolContext toolContext) {
XiuxianAgentContext ctx = XiuxianAgentContext.fromToolContext(toolContext);
// 使用 ctx 获取当前用户身份、发送进度通知等
}模板渲染 — 用加粗代替标题
java
// ✅ 推荐:使用 **加粗** 代替 ### 标题
private static final String USER_INFO = """
**【${name}】修士信息**
| 属性 | 值 |
|------|------|
| 境界 | ${realm} |
""";
// ❌ 不要用 ### 标题,会和 Velocity 的 #if/#foreach 冲突
private static final String USER_INFO = """
### 【${name}】修士信息 // 会出错!
""";字段更新
BaseToolSupport 提供三种更新策略:
java
// 不允许清空:空字符串跳过(如修改名称不可为空)
updateField(user::setName, dto.getName(), false);
// null 和空字符串都跳过
updateIfPresent(user::setName, dto.getName());
// 允许清空:null/空字符串设为空(如清空描述)
updateOrClear(manual::setDescription, dto.getDescription());权限检查
java
@Tool(description = "调整修士灵石")
public String adjustAssets(..., ToolContext toolContext) {
XiuxianAgentContext ctx = XiuxianAgentContext.fromToolContext(toolContext);
// 角色权限检查
if (ctx != null && !ctx.hasPermission(XiuxianRole.PEAK_MASTER)) {
return error("权限不足:调整资产需要峰主及以上权限");
}
// 数据权限检查(峰主只能操作本峰)
String err = checkPeakPermission(user, "调整资产", ctx);
if (err != null) return error(err);
// 执行业务...
}进度通知
java
XiuxianAgentContext ctx = XiuxianAgentContext.fromToolContext(toolContext);
notifyProgress("正在查询修士信息...", ctx);
// 查询完成
notifyProgress("查询完成", ctx);调用 notifyProgress() 实际通过 ctx.notify() 发送 PROGRESS 事件,前端实时展示。
分页查询
java
PageResult<Map<String, Object>> result = executePageQuery(
userService, wrapper, pageNum, pageSize, this::buildUserRowParams);
return renderPageResult(result, USER_LIST);消歧确认
模糊匹配到多个结果时,构建 CONFIRMATION 响应:
java
if (candidates.size() > 1) {
List<Candidate> cards = candidates.stream()
.map(c -> new Candidate(c.getId(), c.getLabel()))
.toList();
return AgentResponse.needConfirm("找到多位同名修士,请选择:", cards);
}新增工具
- 创建
XiuxianXxxTools extends BaseToolSupport - 注入所需业务 Service
- 定义
@Tool方法(注解中填写清晰的description供 LLM 理解) - 在
XiuxianAgentService构造函数中添加参数,并在.tools()调用中注册
无需修改任何已有工具代码。