Agent 如何触发 Skill?Skill 和 Tool 的区别详解

📅 2026/8/9 1:54:52
Agent 如何触发 Skill?Skill 和 Tool 的区别详解
Agent 如何触发 SkillSkill 和 Tool 的区别先说个让人困惑的问题刚接触 Agent 开发的时候我经常被两个概念搞混Tool 和 Skill。文档里写的是Agent 可以调用 Tool但实际开发时又会看到Skill 编排、“Skill 触发”。这俩到底啥关系是同一个东西换了个名字还是真的有层级差异后来在 NVC 项目里踩了不少坑才算真正搞明白。今天把这块梳理清楚顺便聊聊 Agent 触发 Skill 的几种模式。Tool最小执行单元Tool 是 Agent 与外部世界交互的最小单元。说白了它就是一个可以被调用的函数。# 一个典型的 Tool 定义defsearch_database(query:str,limit:int10)-list[dict]:搜索数据库中的记录 Args: query: 搜索关键词 limit: 返回结果数量限制 Returns: 匹配的记录列表 resultsdb.search(query,limitlimit)returnresultsTool 有几个关键特征特征说明原子性只做一件事不会拆成更小的步骤声明式描述必须有清晰的函数签名和 docstring被动调用自己不会主动执行等别人来调无状态调用之间不保留状态理想情况下LLM 能用 Tool靠的是 Function Calling 机制。LLM 看到 Tool 的描述理解参数含义然后决定要不要调、怎么传参。用户: 帮我查一下最近的订单 ↓ LLM: 看到有 search_orders Tool参数是 user_id 和 date_range ↓ LLM: 生成 function call: search_orders(user_idxxx, date_rangelast_7_days) ↓ 系统: 执行函数返回结果 ↓ LLM: 把结果组织成自然语言回复用户这个过程很直白但有个问题如果完成一个任务需要多步操作呢比如帮我订一张明天去上海的机票拆解下来可能是查询航班信息筛选合适的航班检查座位 availability创建订单处理支付每一步都是一个 Tool 调用但它们之间有先后依赖还有条件分支没座位怎么办支付失败怎么办。这时候就需要更高层的抽象了。Skill编排好的执行流程Skill 是一组编排好的多步骤执行流程。如果说 Tool 是单个乐器那 Skill 就是一段乐谱。# 一个 Skill 的伪代码示例defbook_flight_skill(user_request:str)-BookingResult:订机票的完整流程# Step 1: 解析意图intentparse_travel_intent(user_request)# Step 2: 查询航班flightssearch_flights(originintent.origin,destinationintent.destination,dateintent.date)# Step 3: 筛选推荐recommendedfilter_and_rank(flights,user.preferences)# Step 4: 确认选择可能需要用户交互selectedconfirm_selection(recommended)# Step 5: 创建订单ordercreate_order(selected,user.payment_info)# Step 6: 返回结果returnBookingResult(orderorder,confirmationorder.confirmation_code)Skill 的特征和 Tool 形成对比维度ToolSkill粒度原子操作复合流程是否有状态无状态可以维护上下文调用方式直接函数调用流程编排是否可组合是被 Skill 组合是可以包含其他 Skill错误处理单步异常流程级容错和重试一个 Skill 内部可能调用多个 Tool也可能调用其他 Skill。这种嵌套组合的能力让 Agent 的行为变得灵活而强大。Agent 触发 Skill 的三种模式理解了 Tool 和 Skill 的区别接下来看 Agent 是怎么触发 Skill 的。这里有三种典型模式模式一LLM 直接触发 ToolFunction Calling最简单的情况LLM 直接决定调用哪个 ToolToolLLMUserToolLLMUser今天天气怎么样分析意图决定调用天气 Toolget_weather(city北京){temp: 28, condition: 晴}北京今天 28 度晴天这种模式适合单步任务简单直接。但问题是LLM 本身不执行复杂流程它只负责点菜不负责做菜。模式二编排层触发 SkillOrchestrator 调度当任务复杂度上来后需要一个编排层来管理流程订机票查订单退款用户请求Orchestrator意图识别book_flight Skillquery_order Skillrefund Skillsearch_flights Toolcreate_order Toolprocess_payment Toolquery_database Toolvalidate_refund Toolinitiate_refund ToolOrchestrator 是一个独立的调度层它接收用户请求识别意图决定调用哪个 Skill把 Skill 的执行结果返回给用户这种模式下LLM 可以完全不参与 Skill 的触发过程。Orchestrator 用规则引擎或简单模型就能搞定意图识别速度快、成本低。模式三LLM 触发 Tool 组合多轮 Agent Loop这是最灵活的模式LLM 在一个循环中逐步调用 Tool自己决定下一步做什么defagent_loop(user_request:str,max_iterations:int10):Agent 执行循环messages[{role:user,content:user_request}]toolsget_available_tools()foriinrange(max_iterations):# LLM 决定下一步responsellm.chat(messages,toolstools)# 如果 LLM 决定结束ifresponse.finish_reasonstop:returnresponse.content# 如果 LLM 要调用 Toolifresponse.tool_calls:fortool_callinresponse.tool_calls:resultexecute_tool(tool_call)messages.append({role:tool,content:result,tool_call_id:tool_call.id})# 继续循环让 LLM 看到 Tool 结果后决定下一步return达到最大迭代次数这种模式下LLM 既是决策者又是执行者。它根据每一步的结果动态决定下一步做什么。灵活性最高但也最不可控——LLM 可能陷入循环或者调用了不该调用的 Tool。NVC 项目实战模式路由与工具映射在实际项目中我踩过一个坑让 LLM 自己选 Tool准确率只有 70% 左右。用户说我想练习观察LLM 有时候会调成rag_search而不是practice_start。后来我们设计了一套模式路由 意图预路由机制把 Skill 的触发从LLM 自己选变成了系统根据场景分配。NVC 的 10 个 ToolNVC 项目定义了 10 个 Tool每个都是一个独立的 Spring BeanTool 名称职责RagSearchToolRAG 知识检索从 pgvector 向量库中搜索 NVC 相关知识WikiSearchToolWiki 搜索查找用户生成的 NVC 实践笔记WikiWriteToolWiki 写入异步生成 NVC 实践 WikiProfileQueryTool用户档案查询获取用户能力画像ProfileUpdateTool用户档案更新记录职业、偏好等信息DashboardQueryTool练习数据查询统计练习次数、得分等EvaluateNvcToolNVC 表达评估判断是否符合四步法PracticeStartTool开始练习初始化练习会话ScenarioGenerateTool场景生成AI 生成冲突场景ScenarioSearchTool场景搜索从场景库中检索ModeRouter三种模式路由NVC 支持三种对话模式每种模式下 Agent 可用的 Tool 集合和行为策略不同// 三种模式路由器FreeDialogRouter// 自由对话模式默认 DIALOGUE_GUIDE每 5 轮触发评估ScenarioRouter// 场景驱动模式CREATED 阶段生成场景每 5 轮检查低分触发评估StructuredRouter// 结构化四步模式观察→感受→需求→请求这样做的好处是LLM 看到的 Tool 列表是精简的、模式相关的。在结构化练习模式下LLM 根本看不到dashboard_query这个 Tool自然就不会调错。IntentRouter绕过 LLM 的意图预路由更进一步对于一些明确的意图我们甚至不让 LLM 参与决策// IntentRouter.java - 在 LLM 调用前通过正则匹配快速识别高置信度意图publicAgentResultexecute(PracticeContextcontext){IntentMatchmatchintentRouter.match(context.getUserMessage());if(match!nullmatch.getConfidence()0.8){returntoolExecutor.executeDirectly(match.getToolName(),match.getArgs());}returnreactLoop(context);}IntentRouter 的匹配规则意图匹配模式对应 Toolprofile_update“我是/我的职业是/帮我记录到档案”ProfileUpdateToolprofile_query“看看档案/查看档案”ProfileQueryTooldashboard_query“练习数据/练习统计”DashboardQueryTool这个设计的考量是高频的档案和数据查询可以用正则快速匹配省掉 LLM 推理的 2-3 秒延迟。匹配不上再走 ReAct 循环。完整流程把上面的组件串起来命中且置信度0.8未命中用户消息IntentRouter正则匹配?直接执行 ToolModeRouter选择对话模式AgentLoop 模式 Tool 集LLM 推理执行 Tool返回结果这套架构在 NVC 项目里跑了大半年意图识别准确率从 70% 提升到了 95% 以上。几个容易踩的坑坑一Tool 描述写得太抽象# 反例LLM 看不懂defprocess_data(data,config):处理数据pass# 正例描述具体deffilter_orders(orders:list,status:str,date_range:str)-list:根据状态和日期范围筛选订单 Args: orders: 订单列表 status: 订单状态可选值: pending, paid, shipped, completed, cancelled date_range: 日期范围格式: 2024-01-01~2024-01-31 Returns: 符合条件的订单列表 passTool 的描述是 LLM 理解它的唯一依据。写得越具体LLM 调用得越准。坑二Skill 没有错误处理# 反例Skill 里没有容错defbook_flight_skill(request):flightssearch_flights(request.origin,request.destination)selectedflights[0]# 直接取第一个万一没有航班呢create_order(selected)# 正例每一步都有错误处理defbook_flight_skill(request):flightssearch_flights(request.origin,request.destination)ifnotflights:returnResult.error(没有找到符合条件的航班)selectedflights[0]order_resultcreate_order(selected)iforder_result.is_error():returnResult.error(f下单失败:{order_result.error_message})returnResult.success(order_result.data)Skill 是流程级的抽象必须考虑各种异常情况。Tool 可以抛异常让上层处理但 Skill 必须自己兜底。坑三Agent Loop 没有退出条件# 反例可能无限循环whileTrue:responsellm.chat(messages,toolstools)ifresponse.tool_calls:execute_tools(response.tool_calls)# 正例设置最大迭代次数foriinrange(MAX_ITERATIONS):responsellm.chat(messages,toolstools)ifresponse.finish_reasonstop:returnresponse.contentifresponse.tool_calls:execute_tools(response.tool_calls)return抱歉处理过程中遇到问题请稍后重试LLM 有时候会陷入循环反复调用同一个 Tool。没有退出条件Agent 就会一直跑下去。总结Tool 和 Skill 的区别本质上是粒度的区别Tool 是原子操作一个 Tool 只做一件事Skill 是复合流程一个 Skill 协调多个 Tool 完成一个任务Agent 触发 Skill 的三种模式各有适用场景LLM 直接触发 Tool适合简单任务一个 Tool 就能搞定编排层触发 Skill适合流程固定、对可靠性要求高的场景LLM 触发 Tool 组合适合复杂、需要动态决策的场景NVC 项目的实践表明不是所有场景都需要 LLM 来决策。用 ModeRouter 限制 LLM 的选择范围用 IntentRouter 处理明确意图反而能获得更好的效果。Agent 的核心不是让 LLM 做所有事而是在合适的地方用合适的机制。LLM 擅长理解和生成但不擅长精确执行。把 LLM 放在它擅长的位置其他事情交给确定性的代码这才是好架构。