尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AgentScope Java Harness:8. Skill技能让 Agent 从“会说话“进化为“会做事“

AgentScope Java Harness:8. Skill技能让 Agent 从“会说话“进化为“会做事“ 工具Tool是 Agent 的双手而技能Skill是 Agent 的操作手册。没有技能的 Agent 拿着锤子不知道该怎么敲有了技能的 Agent才能把工具组合成可复用的工作流。一、引言Tool ≠ Skill这是两个层次的能力在 Agent 开发中一个常见的误区是把注册了工具等同于具备了能力。// 注册了三个工具agent.registerTool(newSearchFlightsTool());agent.registerTool(newBookHotelTool());agent.registerTool(newGetWeatherTool());Agent 现在有手了但它知道什么时候用哪个工具、按什么顺序、传什么参数、如何处理异常吗维度Tool工具Skill技能本质原子操作工作流编排知识粒度单次函数调用多步骤流程 决策逻辑载体Java/Python 代码Markdown 文档谁编写开发者开发者 / 领域专家 / Agent 自己可复用性代码级复用知识级复用跨 Agent 共享运行时开销函数调用Prompt 注入零执行开销AgentScope Harness 的技能系统正是为了填补这个鸿沟用 Markdown 文件定义可复用的工作流知识让 Agent 不仅有手还知道怎么用。二、核心设计文件即技能2.1 技能的物理形态每个技能是一个独立的 Markdown 文件存放在工作区的 skills/ 目录下workspace/ └── skills/ ├── flight-booking.md ← 机票预订技能 ├── hotel-recommendation.md ← 酒店推荐技能 ├── expense-report.md ← 报销单生成技能 └──>2.2 技能文件结构每个 .md 文件遵循Front Matter Body的标准格式--- name: flight-booking description: 根据用户需求搜索、比较并预订航班支持多条件筛选和价格优化 tags: [travel, booking, flight] tools: - search_flights - get_flight_details - book_flight - get_airport_info version: 1.2 author: travel-team --- # Flight Booking Skill ## Trigger 当用户表达以下意图时激活本技能 - 查询/搜索航班 - 比较机票价格 - 预订机票 - 询问航线信息 ## Workflow ### Step 1: 需求澄清 确认以下必要信息缺失则主动询问 - 出发城市、到达城市 - 出发日期返程日期如适用 - 乘客人数和舱位偏好 - 预算范围可选 ### Step 2: 搜索与筛选 1. 调用 search_flights 获取候选航班列表 2. 如果用户指定了机场偏好调用 get_airport_info 验证机场代码 3. 按用户优先级排序价格 / 时间 / 直飞优先 ### Step 3: 结果呈现 以表格形式展示 Top 3 选项 | 航班号 | 起飞-到达 | 时长 | 价格 | 备注 | 每个选项附带简短推荐理由。 ### Step 4: 确认与预订 1. 用户选择后调用 get_flight_details 获取详细信息 2. 向用户确认关键信息日期、乘客、价格 3. 调用 book_flight 完成预订 4. 返回预订确认号和行程摘要 ## Error Handling - search_flights 无结果建议调整日期或邻近机场 - book_flight 失败保留候选列表提示用户重新选择 - 超时告知用户稍后重试不自动重复预订 ## Constraints - 绝不未经用户确认就执行 book_flight - 价格信息必须来自工具返回值禁止估算 - 儿童/婴儿票价需特别标注2.3 Front Matter 字段详解字段必填类型说明name✅String技能唯一标识description✅String能力描述用于匹配和展示tags❌List标签支持分类检索tools❌List技能依赖的工具白名单version❌String版本号支持演进管理author❌String作者/团队enabled❌Boolean是否启用默认 true三、技能装配机制从文件到 Prompt3.1 构建期扫描HarnessAgentagentHarnessAgent.builder().name(travel-assistant).model(model).workspace(Path.of(./workspace))// 框架自动扫描 workspace/skills/*.md// 无需手动注册任何技能.build();扫描流程HarnessAgent.build() │ ▼ WorkspaceContextHook │ ├── listDir(skills/) │ → [flight-booking.md, hotel-recommendation.md, ...] │ ├── 逐个解析 Front Matter │ → SkillSpec(name, description, tools, ...) │ ├── 过滤 enabledtrue 的技能 │ └── 注入主 Agent system prompt → 技能摘要列表name description3.2 两阶段注入策略技能内容不会全部塞进 system prompt那会撑爆上下文。框架采用两阶段注入┌─────────────────────────────────────────────────────────────┐ │ Stage 1: System Prompt每轮都有 │ │ │ │ ## Available Skills │ │ - flight-booking: 根据用户需求搜索、比较并预订航班... │ │ - hotel-recommendation: 基于偏好推荐酒店... │ │ - expense-report: 自动生成差旅报销单... │ │ │ │ Use load_skill tool to load full skill instructions. │ └─────────────────────────────────────────────────────────────┘ ↓ Agent 判断需要某个技能时 ┌─────────────────────────────────────────────────────────────┐ │ Stage 2: load_skill 工具调用按需加载 │ │ │ │ Agent 调用: load_skill(nameflight-booking) │ │ 框架返回: flight-booking.md 的完整 Body 内容 │ │ Agent 将完整工作流纳入当前推理上下文 │ └─────────────────────────────────────────────────────────────┘3.3 为什么是两阶段方案Token 消耗信息完整性适用场景全量注入所有技能 爆炸✅ 完整技能极少3个仅注入摘要 按需加载✅ 可控✅ 完整技能较多推荐完全不注入✅ 零❌ Agent 不知道有哪些技能不可用两阶段注入在 token 效率和信息完整性之间取得了最佳平衡摘要列表让 Agent “知道自己会什么”load_skill 让 Agent “在需要时学会怎么做”。四、技能 vs 工具 vs 子 Agent三者定位辨析这是 Harness 中最容易混淆的三个概念。它们不是替代关系而是互补的不同抽象层┌─────────────────────────────────────────────────────────────┐ │ 能力分层模型 │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Skill技能 工作流知识 │ │ │ │ 如何组合工具完成一个业务目标 │ │ │ │ 载体Markdown · 注入方式Prompt · 执行者当前 Agent │ │ │ └──────────────────────┬──────────────────────────────┘ │ │ │ 使用 │ │ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Tool工具 原子操作 │ │ │ │ 执行一个具体的函数调用 │ │ │ │ 载体代码 · 注入方式Function Schema · 执行者运行时 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Sub-Agent子 Agent 独立能力单元 │ │ │ │ 委派一个完整任务给另一个 Agent │ │ │ │ 载体Markdown · 注入方式委派工具 · 执行者独立实例 │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘4.1 决策指南你的需求选择理由封装一个 API 调用Tool原子操作不需要流程知识定义如何用多个工具完成一个业务目标Skill工作流知识当前 Agent 自己执行需要一个完全独立的能力单元Sub-Agent独立上下文、独立工具集、独立推理让非技术人员定义业务流程SkillMarkdown 编辑无需写代码需要跨 Agent 复用工作流Skill复制 .md 文件即可需要并行执行多个独立任务Sub-Agent子 Agent 可并行委派4.2 协作示例用户帮我订明天去上海的出差行程 主 Agent 推理 → 加载 skill: travel-planning工作流知识 → 按技能定义的 Workflow 执行 Step 1: 调用 search_flightsTool Step 2: 调用 search_hotelsTool Step 3: delegate_to_expense_calculatorSub-Agent Step 4: 整合结果生成行程单技能定义了做什么、怎么做工具提供了做的能力子 Agent 承担了独立子任务。五、技能的运行时生命周期5.1 完整执行流程用户发送消息 │ ▼ WorkspaceContextHook │ 扫描 skills/ → 注入摘要列表到 system prompt │ ▼ ReAct 推理循环 │ ├── Agent 判断需要某个技能 │ │ │ ▼ 调用 load_skill(nameflight-booking) │ │ │ ▼ 框架读取 skills/flight-booking.md │ 返回完整 Body 内容 │ │ │ ▼ Agent 将工作流纳入推理上下文 │ 按 Workflow 步骤依次执行 │ │ │ ├── 调用 search_flightsTool │ ├── 调用 get_flight_detailsTool │ └── 调用 book_flightTool │ ▼ 返回结果给用户5.2 技能内容的缓存load_skill 的结果在当前会话内缓存避免重复读取文件第 1 轮: load_skill(flight-booking) → 读文件 → 缓存 第 2 轮: load_skill(flight-booking) → 命中缓存 → 零 IO 第 3 轮: 新会话 → 缓存失效 → 重新读文件5.3 热更新由于技能是从文件实时读取的修改 .md 文件后下一次 load_skill 立即获取最新内容# 更新技能vimworkspace/skills/flight-booking.md# 无需重启服务# 下一次 call() 中 Agent 调用 load_skill 时自动获取新版本六、高级特性6.1 技能依赖声明技能可以在 Front Matter 中声明对其他技能的依赖---name:travel-planningdescription:端到端差旅规划包含机票、酒店、报销depends_on:-flight-booking-hotel-recommendation-expense-report---当 Agent 加载 travel-planning 时框架可以自动预加载依赖技能的摘要在技能 Body 中引用依赖技能的名称校验依赖技能是否存在6.2 技能模板变量技能 Body 支持运行时变量替换## 约束 - 当前用户{{user.name}} - 报销标准{{policy.max_flight_price}} 元/程 - 当前日期{{current_date}}变量来源RuntimeContext 中的用户信息工作区中的配置文件框架内置变量如 current_date6.3 技能版本管理---name:flight-bookingversion:1.2---结合 Git 版本控制技能的演进历史完全可追溯gitlog--onelineworkspace/skills/flight-booking.md# a3f2c1d v1.2: 增加儿童票价标注# b8e4a2f v1.1: 增加邻近机场建议# c9d5b3e v1.0: 初始版本6.4 技能禁用与灰度---name:experimental-bookingenabled:false# 暂时禁用---或通过标签实现灰度---name:flight-booking-v2tags:[travel,booking,beta]enabled:true---框架可以根据配置决定是否加载带特定标签的技能。七、与其他子系统的协作┌─────────────────────────────────────────────────────────────┐ │ 技能系统生态 │ │ │ │ ┌──────────────┐ │ │ │ skills/*.md │ ← 技能文件人类/Agent 编辑 │ │ └──────┬───────┘ │ │ │ 构建期扫描 │ │ ▼ │ │ ┌──────────────┐ Stage 1: 摘要注入 │ │ │ System Prompt│ ◀── name description │ │ └──────┬───────┘ │ │ │ Agent 判断需要 │ │ ▼ │ │ ┌──────────────┐ Stage 2: load_skill │ │ │ 完整技能内容 │ ──▶ Agent 推理上下文 │ │ └──────┬───────┘ │ │ │ 按 Workflow 执行 │ │ ▼ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 执行面 │ │ │ │ ┌──────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ │ │Tools │ │Sub-Agents│ │ Memory/Knowledge │ │ │ │ │ │原子 │ │委派 │ │ 查阅/写入 │ │ │ │ │ │操作 │ │独立任务 │ │ │ │ │ │ │ └──────┘ └──────────┘ └──────────────────┘ │ │ │ └──────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘子系统与技能的关系Workspace技能文件存储在工作区天然 Git 友好工具技能声明依赖的工具白名单框架可校验子 Agent技能 Workflow 中可以包含委派步骤记忆技能执行过程中可读写 MEMORY.md知识技能 Body 可引用 knowledge/ 中的领域知识沙箱技能中涉及的命令执行在沙箱内隔离运行压缩技能内容作为工具结果参与压缩策略八、实战从零构建一个技能8.1 场景报销单生成Step 1: 创建技能文件touchworkspace/skills/expense-report.mdStep 2: 编写规格--- name: expense-report description: 根据差旅行程自动生成符合公司政策的报销单 tags: [finance, travel, reimbursement] tools: - calculate_expense - validate_policy - generate_pdf version: 1.0 --- # Expense Report Generation ## Trigger 当用户要求生成报销单、提交差旅费用时激活。 ## Workflow ### Step 1: 收集行程信息 从对话上下文中提取或主动询问 - 出差日期范围 - 交通费用明细航班/火车/打车 - 住宿费用明细 - 餐饮补贴天数 ### Step 2: 政策校验 调用 validate_policy 检查 - 机票是否超出经济舱标准 - 酒店单价是否在限额内 - 餐饮补贴天数是否合理 如有违规项列出并请求用户确认或调整。 ### Step 3: 费用计算 调用 calculate_expense 汇总 - 交通费小计 - 住宿费小计 - 餐饮补贴小计 - 总计 ### Step 4: 生成报销单 调用 generate_pdf 生成 PDF 文件。 返回文件路径和费用摘要。 ## Output Format 差旅报销单━━━━━━━━━━━━━━━出差人{{user.name}}日期{{trip.start_date}} ~ {{trip.end_date}}交通费¥{{transport_total}}住宿费¥{{hotel_total}}餐饮补贴¥{{meal_total}}━━━━━━━━━━━━━━━合计¥{{grand_total}} 报销单 PDF{{pdf_path}}## Constraints - 所有金额必须来自工具计算结果禁止手动加总 - 政策校验未通过时不得生成报销单 - PDF 文件名格式报销单_姓名_YYYYMMDD.pdfStep 3: 验证生效// 无需改代码下一轮 call() 自动发现新技能agent.call(List.of(newUserMessage(帮我生成这次出差的报销单)));// Agent 会自动 load_skill(expense-report) 并按 Workflow 执行九、最佳实践9.1 技能编写指南原则说明Trigger 要明确清晰定义激活条件避免误触发Workflow 要分步每步有明确的输入、动作、输出Error Handling 要覆盖每个工具调用都要考虑失败场景Constraints 要具体“不要编造不如价格必须来自工具返回值”Output Format 要标准化便于下游消费和用户阅读description 要精确这是 Agent 决定是否加载技能的唯一依据9.2 技能组织策略策略适用场景一个业务目标一个技能大多数场景大技能拆分为小技能 组合技能复杂流程通用技能放公共目录专用技能放 Agent 专属目录多 Agent 共享技能命名使用 - 格式提高可读性和检索效率9.3 常见反模式# ❌ description 太模糊 description: 处理各种事务 # ❌ Workflow 没有分步 ## Workflow 调用所有相关工具然后生成结果。 # Agent 不知道顺序和逻辑 # ❌ 缺少 Error Handling # 工具失败了怎么办Agent 只能猜 # ❌ Constraints 太笼统 ## Constraints - 要准确 # 什么叫准确 - 要安全 # 什么叫安全 # ❌ 技能体过大2000 tokens # 考虑拆分为多个小技能 组合技能十、设计哲学总结1. 知识外置能力内化技能将怎么做的知识从代码和模型权重中外置为 Markdown 文件。这使得知识可以被人类审查、编辑、版本管理也使得同一个模型可以通过加载不同技能获得不同能力。2. 按需加载Token 友好两阶段注入确保了只有真正需要的技能才会占用上下文窗口。摘要列表是目录完整内容是正文——你不会把整本书塞进脑子里只在需要时翻开对应章节。3. 文件即接口人机共编技能文件是人类和 Agent 的共同接口。开发者写初始版本领域专家补充业务细节Agent 自己在实践中提出改进建议。这种人机共编模式让技能持续进化。4. 组合优于继承技能之间是组合关系不是继承关系。一个大技能可以引用多个小技能一个小技能可以被多个大技能复用。这种扁平的组合模型比深层继承更容易理解和维护。5. 技能是可治理的能力单元每个技能有名称、版本、作者、标签、启用状态。这不是随意的 prompt 片段而是可治理、可审计、可演进的能力资产。十一、结语AgentScope Harness 的技能系统回答了一个关键问题如何让 Agent 从拥有工具进化为掌握工作流答案是把工作流知识从代码和模型中解放出来变成人类可读、机器可解析、Agent 可按需加载的文件。当你把技能看作操作手册而非prompt 模板时很多设计决策就变得自然而然了操作手册可以独立于执行者存在 → 跨 Agent 复用操作手册可以分章节按需查阅 → 两阶段注入操作手册可以由专家编写 → 领域知识沉淀操作手册可以有版本号 → 能力演进可追溯操作手册可以包含错误处理 → 鲁棒性工作流如果你正在构建需要复杂工作流的 Agent 系统这套文件即技能的设计思路值得深入研究和借鉴。它让 Agent 的能力建设从写代码变成了写文档——这不仅是技术范式的转变更是让AI 能力回归人类可理解、可参与、可治理的工程哲学。
返回列表