Skip to content

工具开发

开发业务工具,让 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);
}

新增工具

  1. 创建 XiuxianXxxTools extends BaseToolSupport
  2. 注入所需业务 Service
  3. 定义 @Tool 方法(注解中填写清晰的 description 供 LLM 理解)
  4. XiuxianAgentService 构造函数中添加参数,并在 .tools() 调用中注册

无需修改任何已有工具代码。

下一步