AI Agent Skill 高阶使用指南:从入门到精通

作为一名后端 Java 开发,我在探索 AI Agent 开发的过程中,发现 Skill(技能/插件)的合理设计与编排是决定 Agent 智能程度的关键。本文总结了一些高阶使用技巧和值得推荐的 Skill,希望对你有帮助。


一、Skill 的本质:Agent 的"手脚"

很多开发者初接触 AI Agent 时,容易把 Skill 等同于"函数调用"。这个理解不算错,但远远不够。

Skill 的本质是赋予 LLM 与外部世界交互的能力。 没有 Skill 的 LLM 只是一个"大脑"------能思考、能表达,但无法行动。Skill 就是它的手和脚。

从架构上看,一个 Skill 的生命周期是:

text

arduino 复制代码
text
用户意图 → LLM 推理 → Skill 选择 → 参数构造 → 外部调用 → 结果回传 → LLM 总结

对于 Java 后端开发者来说,你可以把 Skill 理解为一个 "由 LLM 动态路由的 RPC 接口" ,只不过路由逻辑不是你写的 if-else,而是模型的语义理解能力。


二、Skill 高阶使用技巧

技巧 1:Skill 的 Description 工程------最容易被忽略的胜负手

大多数开发者写 Skill 时,把精力放在 API 对接和参数定义上,却草草写下 description。这是一个巨大的误区。

LLM 选择哪个 Skill、传什么参数,完全依赖你的 Description 文本。 Description 就是你的 Skill 在 LLM 眼中的"简历"。

反面示例:

yaml

makefile 复制代码
yaml
name: query_order
description: 查询订单

正面示例:

yaml

makefile 复制代码
yaml
name: query_order
description: |
  根据订单号或用户手机号查询订单详情。
  适用场景:
  - 用户提供了订单号(如 ORD20240513xxxx),需要查询该订单的状态、物流、金额等信息
  - 用户提供了手机号,需要查询该手机号下所有近 90 天的订单
  - 用户询问"我的快递到哪了"、"之前买的东西什么状态"等订单相关问题
  不适用场景:
  - 用户要退换货 → 应使用 apply_refund
  - 用户要投诉 → 应使用 create_ticket

关键原则:

  • 写清楚 "什么时候用""什么时候不用"
  • 用自然语言举出用户可能的表达方式(帮助 LLM 做意图匹配)
  • 明确与其他 Skill 的边界,避免 LLM 纠结选择

技巧 2:参数设计的"LLM 友好"原则

后端开发者习惯设计精确、严格的接口参数。但 Skill 的参数是给 LLM 填的,需要换一种思路。

原则一:用 enum 约束 LLM 的输出空间

json

json 复制代码
json
{
  "order_status": {
    "type": "string",
    "enum": ["pending", "paid", "shipped", "delivered", "cancelled"],
    "description": "订单状态。用户说'还没发货'对应 shipped 前的状态,取 pending 或 paid"
  }
}

不要期望 LLM 能猜出你定义的魔法字符串。用 enum + 场景说明,把它的"发挥空间"限制在正确范围内。

原则二:参数名用语义化命名,而非技术缩写

json

json 复制代码
json
// 差:LLM 可能不理解缩写
{ "uid": { "type": "string" } }

// 好:语义清晰
{ "user_id": { "type": "string", "description": "用户ID,通常为纯数字" } }

原则三:提供 default 值和 fallback 策略

json

json 复制代码
json
{
  "page_size": {
    "type": "integer",
    "default": 10,
    "description": "每页返回数量,默认10。用户没有特别要求时使用默认值"
  }
}

这样 LLM 在用户没有明确指定时,不需要"猜",直接用默认值即可,减少无效的追问轮次。


技巧 3:Skill 编排------从单步调用到多步工作流

初级用法是单个 Skill 独立调用。但真实业务场景往往需要多个 Skill 协同。

场景示例:用户说"帮我把上周买的那个蓝牙耳机退了"

Agent 需要完成的链路:

text

scss 复制代码
text
1. query_order(关键词="蓝牙耳机", 时间范围="上周")
   → 返回订单列表

2. LLM 判断:有多个订单,追问用户确认具体是哪一个

3. 用户确认后 → apply_refund(order_id=xxx, reason="七天无理由")
   → 返回退款申请结果

4. notify_user(用户ID=xxx, 内容="退款申请已提交,预计3个工作日到账")

高阶技巧:在 System Prompt 中定义编排策略

markdown

markdown 复制代码
markdown
## 技能编排规则
1. 当用户意图涉及"退款"时,必须先调用 query_order 确认订单,再调用 apply_refund
2. query_order 返回多个结果时,必须列出订单摘要让用户确认,不得自行选择
3. 退款操作完成后,主动调用 notify_user 通知用户
4. 任何涉及金额的操作,必须在执行前向用户二次确认

这相当于你在 System Prompt 中写了一个"业务流程引擎"。LLM 就是流程的执行者。


技巧 4:Skill 内嵌业务校验------不要信任 LLM 的参数

这是一个后端开发者特别容易忽视的点:LLM 传过来的参数不一定靠谱。

你的 Skill 实现层必须做完整的参数校验和业务校验,就像处理任何外部输入一样。

java

java 复制代码
java
@Override
public SkillResult execute(SkillContext context) {
    String orderId = context.getParam("order_id");

    // 1. 参数校验
    if (StringUtils.isBlank(orderId)) {
        return SkillResult.fail("缺少必要参数:order_id");
    }

    // 2. 业务校验
    Order order = orderService.findById(orderId);
    if (order == null) {
        return SkillResult.fail("未找到订单:" + orderId + ",请检查订单号是否正确");
    }

    if (!order.isRefundable()) {
        return SkillResult.fail(
            "该订单不支持退款。原因:" + order.getRefundBlockReason()
        );
    }

    // 3. 执行业务
    RefundResult result = refundService.apply(orderId, reason);
    return SkillResult.success("退款申请已提交,退款单号:" + result.getRefundNo());
}

关键:错误信息要返回给 LLM,而不是抛异常。 因为 LLM 需要理解错误原因,才能给用户一个有意义的回复,或者决定下一步操作(比如换个参数重试)。


技巧 5:Skill 返回值的"LLM 友好"设计

Skill 的返回值不是返回给前端的 JSON,而是返回给 LLM 的"上下文信息"。格式上要兼顾信息密度和可读性。

反面示例:

json

css 复制代码
json
{
  "code": 200,
  "data": {
    "orders": [
      {
        "oid": "ORD20240513001",
        "st": 3,
        "amt": 29900,
        "itm": [
          {"sku": "BT-001", "n": "索尼WH-1000XM5", "q": 1, "p": 29900}
        ],
        "addr": "北京市朝阳区xxx",
        "exp": "SF1234567890"
      }
    ]
  }
}

正面示例:

json

json 复制代码
json
{
  "success": true,
  "summary": "找到1笔订单",
  "orders": [
    {
      "order_id": "ORD20240513001",
      "status": "已发货",
      "status_code": "shipped",
      "total_amount": "299.00元",
      "items": "索尼WH-1000XM5 头戴式降噪耳机 x1",
      "shipping_info": "顺丰快递 SF1234567890,预计明天送达",
      "can_refund": true
    }
  ],
  "hint": "如果用户要退款,可以直接调用 apply_refund,订单号为 ORD20240513001"
}

关键差异:

  • 字段名语义化,LLM 可以直接理解
  • 金额从"分"转为"元",加上单位
  • 状态从枚举值转为自然语言
  • 加了 hint 字段,引导 LLM 下一步操作
  • 加了 summary 字段,方便 LLM 生成总结

技巧 6:利用 Skill 实现"人机协作"模式

有些操作不适合让 LLM 全自动执行(比如大额转账、删除数据)。可以在 Skill 中实现审批流

java

java 复制代码
java
@Override
public SkillResult execute(SkillContext context) {
    BigDecimal amount = context.getParam("amount", BigDecimal.class);

    if (amount.compareTo(new BigDecimal("5000")) > 0) {
        // 大额操作,需要人工审批
        String approvalId = approvalService.createApproval(
            context.getUserId(),
            "transfer",
            context.getParams()
        );

        return SkillResult.needApproval(
            "转账金额超过5000元,已提交人工审批。" +
            "审批单号:" + approvalId + "," +
            "预计1个工作日内完成审批,请耐心等待。"
        );
    }

    // 小额直接执行
    TransferResult result = transferService.execute(context.getParams());
    return SkillResult.success("转账成功,交易流水号:" + result.getTxId());
}

这种设计让 Agent 在自动化和安全性之间找到平衡,也是企业级落地的核心需求。


三、推荐的实用 Skill 及设计思路

以下是一些在实际项目中验证过的高价值 Skill 设计,你可以直接参考或改造:

1. 结构化数据查询 Skill(Text-to-SQL)

适用场景: 用户用自然语言查询业务数据

yaml

vbnet 复制代码
yaml
name: data_query
description: |
  将用户的自然语言问题转化为 SQL 查询,返回业务数据。
  适用场景:用户询问数据统计、报表、趋势分析等问题。
  例如:"最近7天的新增用户数"、"本月销售额最高的Top10商品"
  限制:只支持 SELECT 查询,不支持写操作。

后端实现要点:

  • 只允许 SELECT,禁止 INSERT/UPDATE/DELETE
  • 限制查询的表和字段范围(白名单)
  • 强制加 LIMIT,防止全表扫描
  • 对返回结果做脱敏处理(手机号、身份证等)

java

typescript 复制代码
java
@Component
public class DataQuerySkill implements Skill {

    private static final Set<String> ALLOWED_TABLES = Set.of(
        "t_order", "t_user", "t_product", "t_payment"
    );

    @Override
    public SkillResult execute(SkillContext context) {
        String sql = context.getParam("sql");

        // 安全校验
        SqlValidation validation = sqlValidator.validate(sql, ALLOWED_TABLES);
        if (!validation.isValid()) {
            return SkillResult.fail("SQL校验不通过:" + validation.getReason());
        }

        // 强制加 LIMIT
        sql = sqlLimiter.addLimit(sql, 100);

        // 执行查询
        List<Map<String, Object>> results = jdbcTemplate.queryForList(sql);

        return SkillResult.success(formatResults(results));
    }
}

2. 知识库检索 Skill(RAG)

适用场景: 让 Agent 基于企业内部文档回答问题

yaml

makefile 复制代码
yaml
name: knowledge_search
description: |
  从企业知识库中检索相关信息,用于回答用户关于公司政策、产品文档、
  技术规范、常见问题等方面的问题。
  适用场景:用户询问"xxx功能怎么用"、"公司的报销流程是什么"

高阶技巧:

  • 返回结果附带来源引用,让 LLM 可以标注"根据《xxx文档》..."
  • 返回置信度分数,让 LLM 决定是直接回答还是说"我不确定"
  • 支持多轮追问时的上下文感知------把上一轮的检索结果作为下一轮的参考

3. 多系统联动 Skill(编排型)

适用场景: 一个操作需要跨多个内部系统

yaml

yaml 复制代码
yaml
name: onboard_employee
description: |
  新员工入职一站式处理。自动完成以下操作:
  1. 在 HR 系统中创建员工档案
  2. 在 OA 系统中开通门禁和考勤权限
  3. 在 IT 系统中申请邮箱和 VPN 账号
  4. 在知识库中推送新人入职指南
  需要提供:员工姓名、部门、职位、入职日期

这类 Skill 本质上是一个微服务编排层,非常适合 Java 后端用 Spring 的事务管理或 Saga 模式来实现。


4. 定时任务调度 Skill

适用场景: 用户要求 Agent 在特定时间执行某个操作

yaml

makefile 复制代码
yaml
name: schedule_task
description: |
  创建一个定时任务。用户说"每天早上9点给我发昨日数据报告"、
  "下周三提醒我xxx"时使用此技能。
  支持一次性任务和周期性任务(cron表达式)。

5. 代码执行 Skill(沙箱型)

适用场景: 需要动态计算、数据处理、生成图表

yaml

yaml 复制代码
yaml
name: code_interpreter
description: |
  在安全沙箱中执行 Python 代码,用于:
  - 数学计算和统计分析
  - 数据清洗和转换
  - 生成图表和可视化
  当用户的请求涉及复杂计算或数据分析时使用。

四、避坑指南

坑 1:Skill 数量爆炸

不要给 Agent 配置太多 Skill。LLM 在面对 20+ 个 Skill 时,选择准确率会明显下降。

解决方案: 分层设计

  • 通用层: 基础能力(搜索、计算、时间)
  • 业务层: 按领域分组(订单、用户、商品)
  • 专家层: 特定场景的复合 Skill

在 System Prompt 中用条件触发来控制加载哪些 Skill,而非一次性全部暴露。

坑 2:Skill 之间职责模糊

如果两个 Skill 的 Description 高度重叠,LLM 会随机选择,导致行为不稳定。

解决方案: 定义清晰的边界条件,用"适用/不适用"做区分。

坑 3:忽略超时和重试

LLM 调用 Skill 有超时限制。如果你的 Skill 执行时间过长(比如跑一个复杂查询),可能会超时。

解决方案:

  • 对于耗时操作,Skill 先返回"处理中"状态,异步通知结果
  • 设置合理的超时时间
  • 实现幂等性,支持 LLM 重试调用

坑 4:安全意识不足

Skill 是 LLM 与你的后端系统之间的桥梁。LLM 的参数构造完全基于自然语言理解,存在注入风险。

必须做的安全措施:

  • 所有输入参数做严格校验(类型、长度、格式)
  • SQL/NoSQL 注入防护
  • 权限校验------Skill 的执行权限不应超过调用用户本身的权限
  • 敏感操作加二次确认机制
  • 记录完整的调用日志(入参、出参、耗时),便于审计

五、总结

维度 初级做法 高阶做法
Description 一句话描述 场景 + 正例 + 反例 + 边界
参数设计 照搬 API 文档 enum 约束 + 语义化命名 + 默认值
返回值 原始 JSON 语义化 + summary + hint
错误处理 抛异常 结构化错误信息回传 LLM
安全 信任 LLM 参数 全面校验 + 权限控制 + 审计日志
编排 单 Skill 独立调用 多 Skill 链式编排 + 流程控制

Skill 的设计质量,直接决定了 Agent 的智能上限。 LLM 再强,如果 Skill 设计粗糙,Agent 的表现也会大打折扣。

作为后端开发者,我们天然具备设计高质量 Skill 的优势------接口设计、参数校验、异常处理、安全防护,这些都是我们的日常。把 Skill 当作一个"特殊的微服务接口"来设计,你就已经赢在起跑线上了。


以上是我个人在实践中的总结,如果你有更好的 Skill 设计技巧,欢迎交流讨论。


相关推荐
用户962377954481 小时前
代码审计 | Struts2 —— S2-016 OGNL 注入原理
后端
9号达人1 小时前
为什么你应该在 MQ 里用多个消费者,而不是一个
java·后端·架构
阿星做前端2 小时前
重度 AI 编程用户的一天:我怎么把 Claude Code / Codex 工作流搬进浏览器工作台
前端·javascript·后端
代码羊羊2 小时前
Rust 类型转换全方位通俗易懂指南(as、TryInto、强制转换、Transmute)
后端·rust
jay神2 小时前
基于SpringBoot的宠物生命周期信息管理系统
java·数据库·spring boot·后端·web开发·宠物·管理系统
星栈2 小时前
Rust 全栈一个 main.rs 搞定启动:migration + CQRS + 投影监听,部署只需一个二进制
后端·架构
Penge6662 小时前
一文理清 Mac/Linux 终端配置文件(.bash_profile, .bashrc, .zshrc)
后端
Rust研习社2 小时前
Rust 性能陷阱:那些看起来很优雅但很慢的写法(上)
后端·rust·编程语言
万亿少女的梦1682 小时前
基于SpringBoot的在线考试管理系统设计与实现
java·spring boot·后端