Solon v3.8.3

skills - 应用示例参考

</> markdown
2026年1月22日 下午11:14:59

以下仅作参考

1、ToolGatewaySkill:动态工具网关技能

解决痛点:当插件库中有成百上千个工具时,一次性全部注入会导致上下文(Token)溢出及模型幻觉。通过网关模式,实现工具的“按需发现”与“延迟加载”。

// 即使后台有 1000 个工具,Agent 启动时也只加载 2 个网关工具
ChatModel model = ChatModel.of(config)
    .defaultSkillAdd(new ToolGatewaySkill()) 
    .build();

// 模型会先调用 search_tools 发现具体的“发票开具”工具,再通过 call_tool 执行它
model.prompt("帮我开一张 100 元的餐饮发票").call();

ToolGatewaySkill

/**
 * 动态工具网关技能(隐藏在后台的巨大工具库,不占用初始上下文)
 */
public class ToolGatewaySkill extends AbsSkill {
    private List<FunctionTool> findRelevant(String query, int size){
        //查找相关工具
        return null;
    }

    private FunctionTool loadTool(String name){
        //加载具体工具
        return null;
    }

    @Override
    public String name() {
        return "dynamic_gateway";
    }

    @Override
    public String description() {
        return "动态工具网关";
    }

    @Override
    public String getInstruction(ChatPrompt prompt) {
        return "你是一个具备无限扩展能力的 Agent。\n" +
                "1. 当你发现现有工具无法解决问题时,请先调用 'search_tools' 搜索工具。\n" +
                "2. 搜索结果会返回工具的详细使用说明(Schema)。\n" +
                "3. 请根据返回的 Schema,使用 'call_tool' 发起真正的请求。";
    }

    @ToolMapping(name = "search_tools", description = "从海量库中发现工具。支持语义搜索和功能描述。")
    public String searchTools(@Param("query") String query) {
        // 模拟模糊搜索
        List<FunctionTool> tools = findRelevant(query, 5);

        if (tools.isEmpty()) return "未发现匹配工具,请换个关键词试试(如:财务、报表、推送)。";

        return ONode.serialize(tools.stream().map(t -> {
            Map<String, Object> info = new HashMap<>();
            info.put("tool_name", t.name());
            info.put("description", t.descriptionAndMeta());
            info.put("input_schema", t.inputSchema()); // 让模型直接读 Schema
            return info;
        }).collect(Collectors.toList()));
    }

    @ToolMapping(name = "call_tool", description = "执行已搜到的工具。")
    public Object callTool(@Param("tool_name") String name,
                           @Param("arguments") Map<String, Object> args) throws Throwable {

        // 动态加载工具实例
        FunctionTool tool = loadTool(name);
        if (tool == null) {
            return "Execution failed: Tool [" + name + "] is no longer available.";
        }

        return tool.handle(args);
    }
}

2、OrderIntentSkill:意图感知的订单技能

解决痛点:通过 isSupported 实现“精准空降”。只有在用户聊到订单相关话题时,对应的指令和工具才会进入上下文,极大提高了非相关对话(如闲聊)时的响应速度和准确度。

ChatModel model = ChatModel.of(config)
    .defaultSkillAdd(new OrderIntentSkill())
    .build();

// 场景 A:闲聊。isSupported 返回 false,模型不会看到订单工具,也不会被订单指令干扰。
model.prompt("今天天气不错").call();

// 场景 B:业务。isSupported 返回 true,模型瞬间获得订单处理专家能力。
model.prompt("我昨天的订单到哪了?").call();

OrderIntentSkill

/**
 * 意图感知的订单技能
 */
public class OrderIntentSkill extends AbsSkill {
    // 定义该技能关心的意图关键词
    private static final List<String> INTENT_KEYWORDS = Arrays.asList("订单", "买过", "物流", "发货", "退款");

    @Override
    public String name() {
        return "order_manager";
    }

    @Override
    public String description() {
        return "处理所有与订单、物流相关的业务请求";
    }

    /**
     * 核心:准入检查
     * 只有当用户提问包含相关关键词时,此技能才会被激活
     */
    @Override
    public boolean isSupported(ChatPrompt prompt) {
        String content = prompt.getUserContent();
        if (content == null) return false;

        // 简单的关键词匹配(生产环境可以换成正则或微型分类模型)
        return INTENT_KEYWORDS.stream().anyMatch(content::contains);
    }

    @Override
    public String getInstruction(ChatPrompt prompt) {
        return "1. 查询订单前,请确认用户是否提供了订单号或手机号。\n" +
                "2. 如果物流状态显示为'已签收',主动询问用户对商品的满意度。";
    }

    @ToolMapping(description = "根据订单号查询详细的物流信息")
    public String getOrderLogistics(@Param("orderId") String orderId) {
        return "订单 " + orderId + " 正在上海分拣中心处理中...";
    }
}

3、TechnicalSupportSkill:多级决策与 RAG 结合

解决痛点:展示了复杂的 SOP(标准作业程序) 控制。Skill 可以根据 Prompt 内容动态调整指令优先级,并利用工具元数据(Meta)触发安全确认,实现 RAG(检索增强生成)与人工干预的闭环。

ChatModel model = ChatModel.of(config)
    .defaultSkillAdd(new TechnicalSupportSkill())
    .build();

// 即使知识库没搜到,模型也会根据 SOP 引导,在最终转人工前执行确认逻辑
model.prompt("Solon AI 如何配置拦截器?知识库搜不到。").call();

TechnicalSupportSkill

/**
 * 技术支持技能:展示多级决策与 RAG 结合
 */
public class TechnicalSupportSkill extends AbsSkill implements Skill {
    public TechnicalSupportSkill() {
        super();
        this.metadata().category("support").tags("rag", "helpdesk").sensitive(false);
    }

    @Override
    public String name() {
        return "tech_support";
    }

    @Override
    public String description() {
        return "多级技术支持与知识库检索";
    }

    @Override
    public String getInstruction(ChatPrompt prompt) {
        String userMessage = prompt.getUserContent();

        // 如果用户直接贴了代码或错误栈,调整 SOP 优先级
        if (userMessage.contains("StackOverflow") || userMessage.contains("Exception")) {
            return "检测到具体异常,请跳过基础搜索,优先调用 'search_online_docs' 查找最新补丁。";
        }

        return "处理技术咨询时必须遵循以下 SOP:\n" +
                "1. 优先调用 'search_knowledge_base' 获取标准答案。\n" +
                "2. 如果知识库无法解决或信息过时,调用 'search_online_docs' 获取最新文档。\n" +
                "3. 只有当前两步都无法给出确切方案,且用户问题属于紧急故障时,才允许调用 'create_human_ticket'。";
    }

    @ToolMapping(description = "检索内部私有知识库 (已核实的标准操作手册)")
    public String searchKnowledgeBase(@Param("query") String query) {
        // 模拟 RAG 检索
        if (query.contains("安装")) {
            return "知识库命中:请运行 'npm install solon-ai' 并配置 API Key。";
        }
        return "知识库未命中相关词条。";
    }

    @ToolMapping(description = "检索实时在线开发文档 (最新 API 变更和社区讨论)")
    public String searchOnlineDocs(@Param("url_path") String path) {
        // 模拟爬虫或文档 API
        return "在线文档显示:3.8.4 版本后,Skill 接口新增了 injectInstruction 方法。";
    }

    @ToolMapping(
            description = "创建人工支持工单",
            // 增加确认话术和操作等级
            meta = "{'danger':3, 'confirm_msg':'确定要转接到人工座席吗?可能会产生额外费用。'}"
    )
    public String createHumanTicket(@Param("issue") String issue, @Param("urgency") String urgency) {
        // 标记为敏感/破坏性操作,会触发你在 ReActSystemPrompt 里的安全约束
        return "工单已提交成功,工单号:TICK-" + System.currentTimeMillis();
    }
}