尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Agent Skills开发实战:从Function Calling到技能化架构的落地指南
“Agent Skills”这个词我最早是在一场内部技术分享会上听来的。当时隔壁团队做的企业知识库助手正处于最痛苦的阶段大模型的对话能力大家都有目共睹但只要涉及到正经业务动作——查数据、填单子、改配置、发通知——整个系统的表现就开始飘今天能用、明天不能换个提问方式结果完全不一样。后来他们把能力体系整体切成了“技能化”架构问题大幅缓解。我在这套思路启发下在模拟项目X里完整落地了一遍形成了一套个人认为可以复用的方法论。这篇文章不打算讲概念PPT直接聊我理解的、做出来的、踩过的Agent Skills体系。这篇文章适合两类人看一类是做AI Agent应用、正在被“模型为什么总是自作主张”折磨的开发者另一类是技术选型阶段需要在“一个大Prompt走天下”和“精细拆分能力单元”之间拿捏的同学。我会尽量把为什么这么设计、代码怎么写、坑在哪里都交代清楚争取你看完就能直接在自己的项目里搭一套最小闭环。1. 先想清楚Agent Skills 到底在解决什么问题1.1 从“聊天”到“办事”的关键转变很多人对Agent的第一印象仍然是“一个更智能的对话框”。用户问一句模型答一句聊天体验做得再好本质上还是在消费模型的文本生成能力。但业务方真正想要的不是聊天而是“让AI帮我把事办完”。这两者之间有一条巨大的鸿沟。一个典型的业务任务是长这样的“把昨天所有销售数据从后台系统导出来去掉重复项按区域汇总生成一份Excel报表再发到对应的工作群。”拆开看这个任务至少需要四步到五步每一步都涉及外部系统交互。如果把这些步骤全部写进System Prompt让模型自己发挥理论上确实存在一次推理就走通的可能但现实往往很骨感上游接口字段变了、某个数据源临时不可用、报表格式要求调整了任何一个环节出问题整条链路就断了。更麻烦的是模型在链路断裂之后往往不知道怎么恢复它会一本正经地告诉你“已完成”实际上什么都没发生。Agent Skills解决的核心问题就是把“完成一个任务”从“依赖模型临场发挥”变成“调用一组有明确输入输出边界的技能”。调度层只负责判断当前该选哪个技能、参数怎么填技能内部负责自己那一段的逻辑正确性和异常兜底。这是典型的分工思维让模型的归模型让工程的归工程。1.2 它和Function Calling、插件体系到底是什么关系说句实话我刚接触Agent Skills时也被术语绕晕过。Function Calling、Tool Use、插件、技能这些概念听起来高度重叠实际定位却各不相同。Function Calling本质上是一种模型侧协议它解决的是“模型如何输出结构化调用指令”的问题。你给模型一批函数定义模型在回答时能输出一个JSON结构包括函数名和参数。这只是一次“对话中的约定”用完就没了。插件Plugin通常是某个平台体系下的能力扩展机制解决的是“应用如何动态接入外部服务”的问题一般由平台定义宿主环境、权限模型和安装方式。Agent Skills是一种工程侧的架构模式重点不在于“模型能否输出一段JSON”而在于“能力如何被定义、注册、发现、执行、评估、沉淀”。一次调用只是一瞬间一个技能却可以跨项目复用跨版本演进。我用一个类比来区分Function Calling好比是你请了一位临时工你跟他说“去把桌子擦了”他说“好我会擦”然后这次合作结束Agent Skills则是你建了一套岗位说明书和SOP每个岗位有明确的职责边界、操作手册、异常处理流程新人来了按手册就能上手。临时工来解决一次性问题很灵活但一个要长期运转的组织必须有岗位体系。这里做一个直接对比表格方便看结论对比维度Function Calling / Tool UseAgent Skills本质模型输出结构化指令的协议能力定义与管理架构生命周期触发路径中的一次环节注册、评估、迭代、废弃的完整链路复用方式每次重新定义或加载注册一次多处调度组合性单次调用相互独立高阶技能可以编排低阶技能失败处理通常交给模型自行判断技能内部固化重试、降级、补偿逻辑可测试性依赖对话场景复现技能可以脱离对话单独做单元测试我的结论是做一个短期Demo直接用Function Calling最省事。但凡是生命周期超过三个月、后续还要接更多业务系统、需要多人协作维护的Agent项目技能化基本上是必经之路。因为技能是可积累资产Prompt里的描述则很难沉淀。2. 技能体系的核心设计定义、注册、执行三个关键层2.1 定义层接口即契约先把边界立住我见过很多技能化尝试翻车原因不在执行力而在定义层偷工减料。技能定义绝不是“起个名字、写两百字描述”就完事。我实际使用的技能定义结构至少包含以下字段name机器可读的唯一标识比如query_project_status全局唯一description面向模型和调度器的语义描述必须写清楚这个技能能做什么、在什么场景用、不能做什么parameters_schema结构化的输入参数Schema逻辑上就是一份JSON Schemahandler真正执行能力的函数或远程服务地址timeout超时时间防止技能把整个链路拖死max_retries最大重试次数required_permissions技能执行所需的最小权限列表。在所有这些字段里我最重视的是parameters_schema。很多同学写技能时把参数定义得很随便让模型自由发挥结果模型把字符串传成数组、把必填字段漏掉、把不存在的选项编出来。在技能入口处做严格校验用代码把错误拦截在业务逻辑之前这是成本最低的容错手段。宁可入口卡得死一点也不要去下游各种兜底。描述文本也值得认真写。我领悟到的原则是描述和参数必须一一对应。描述里提到的每一个可配置项Schema里都必须有字段承接Schema里没有的字段描述里一个字都不要出现。否则模型会非常合理地“幻觉”出一些参数然后被校验拦下来链路自然就断了。2.2 注册与发现层让Agent知道你自己有什么武器有了技能定义下一步是收集起来形成一个注册中心。注册中心的逻辑功能无非就是三个登记技能、按名称查找、按描述生成索引。但它背后有一个重要的产品逻辑技能清单是模型“可感知”的知识来源。模型在调度时怎么选技能不依赖任何高级魔法主要就是靠当前用户问题和技能description之间的语义匹配。描述写得越精确、越贴近实际使用条件模型就越容易选对。描述写得越泛模型就越容易选到相邻领域的技能。这里分享一个我实测有效的细节给每个技能额外配两个“使用样例”作为描述的一部分。比如query_project_status的使用样例可以写成用户问“P001项目最近什么进展”提取project_idP001用户问“帮我看看所有项目的状态”则不应该优先使用本技能因为本技能只支持单项目查询。注册中心里带上这样两条样例句之后模型对技能的命中率提升非常明显。原因是模型的语义匹配需要“锚点”单纯抽象描述对模型来说太飘具体样例可以帮它落到真实的语言模式上。另外注册时一定要做重名校验。多人协作项目里两个人同时往注册中心加技能很容易起重复名字而又因为描述文本不同不会立刻暴露等调度层命中了某个“同名不同义”的技能时排查起来非常痛苦。2.3 执行层校验、重试、降级一个都不能少执行层是技能体系中最容易“纸面完美、运行稀烂”的部分。很多团队把技能定义和注册做得漂漂亮亮结果handler内部没有任何防护第三方服务一抖动整个Agent会话就跟着失败。我的习惯是给每个技能的执行路径配置三层防护校验层入参Schema校验、权限校验。这层在调用入口统一处理逐技能共用重试层针对“只读、幂等”操作自动重试重试间隔做指数退避最大次数由技能定义里的max_retries控制降级层主路径失败后是否有备用数据源、备用算法或简化输出模式。有就启用没有就明确向调度层返回失败原因。把这个逻辑固化成技能基类的一个通用方法之后新增技能时可以少写大量重复代码执行行为的可预期性也会明显提升。我看到太多Agent项目把重试、降级这些逻辑交给模型自行判断这其实是不对的模型每次重新推理都会消耗额外token而且决策结果不可控而把规则固化在工程侧每次执行结果都可重复、可测试。还有一点容易被忽略返回值结构必须统一。我强制约定技能一律返回{result: ..., meta: {...}}这种格式result是给调度层和下一步使用的规范化数据meta记录耗时、来源版本、是否降级等信息。这么做之后调度层的代码量至少减半日志可阅读性也大幅提升。3. 实操演示从零搭一个可使用 Agent Skills 的最小闭环3.1 场景与选型说明我选一个非常简单的场景来做演示目的是把技能体系的骨架讲清楚而不是陷入具体业务复杂度。场景设定为企业内部的一个项目查询助手支持用户用自然语言问“某项目的当前进展”Agent需要先查出项目状态再生成一段中文摘要。整个闭环用到两个技能query_project_status负责查询项目状态只接受项目IDbuild_summary负责把原始状态文本加工成面向用户的摘要。实现语言用Python原因是生态成熟、示例直观。我刻意不绑定任何特定大模型平台调用LLM的部分用伪代码表示你可以根据自己的实际环境替换。3.2 技能基类与参数校验先定义一个技能基类把定义约束和执行通用逻辑放在一起from typing import Any, Callable, Optional from dataclasses import dataclass from jsonschema import validate, ValidationError class SkillInvocationError(Exception): 技能调用异常 dataclass class AgentSkill: name: str description: str parameters_schema: dict handler: Callable[..., Any] timeout: float 10.0 max_retries: int 2 permissions: Optional[list] None def invoke(self, params: dict) - dict: # 第一道防线参数校验 try: validate(instanceparams, schemaself.parameters_schema) except ValidationError as exc: raise SkillInvocationError( f[{self.name}] 参数校验失败: {exc.message} ) from exc # 第二道防线执行带超时控制 try: result self._run_with_timeout(params) except Exception as exc: raise SkillInvocationError( f[{self.name}] 执行失败: {exc} ) from exc return {result: result, meta: {skill: self.name}} def _run_with_timeout(self, params: dict) - Any: # 简化版超时控制实际项目可用 concurrent.futures 或 asyncio.wait_for return self.handler(**params)这段代码虽然短但把“定义”和“执行”的关键约束都立住了入参必须符合Schema否则直接抛异常不进入业务逻辑执行结果统一包一层result/meta结构。后续想要加权限校验、加重试逻辑都往这个类里面填就行。3.3 定义两个具体技能第一个技能是查询项目状态def _fetch_project_status(project_id: str) - str: # 真实项目中这里会调用内部服务这里用模拟数据替代 fake_db { P001: 开发中进度正常, P002: 已延期风险较高, } if project_id not in fake_db: raise ValueError(f未知项目: {project_id}) return fake_db[project_id] query_project_status AgentSkill( namequery_project_status, description( 查询指定项目的当前状态。 当用户询问项目进展、状态、风险时使用。 参数project_id必填仅支持P001和P002两个项目。 示例用户问‘P001最近怎么样’应传{\project_id\: \P001\}。 ), parameters_schema{ type: object, properties: { project_id: { type: string, enum: [P001, P002], } }, required: [project_id], }, handler_fetch_project_status, )第二个技能是生成摘要def _build_project_summary(project_id: str, raw_status: str) - str: return f项目{project_id}的最新状态是{raw_status}。 build_summary AgentSkill( namebuild_summary, description( 把项目原始状态文本生成一段面向用户的中文摘要。 入参必须包含项目ID和原始状态文本。 通常在查询项目状态之后使用。 ), parameters_schema{ type: object, properties: { project_id: {type: string}, raw_status: {type: string}, }, required: [project_id, raw_status], }, handler_build_project_summary, )注意query_project_status的描述里故意加了一个“负例”说明它只支持单项目查询。这样做的好处是当用户问“帮我看看所有项目的状态”时模型不会错误地调用这个技能而是会告诉你当前能力不足或者触发其他逻辑。3.4 注册中心实现注册中心保持极简三个功能够用即可注册、按名查找、生成技能清单文本。class SkillRegistry: def __init__(self): self._skills {} def register(self, skill: AgentSkill) - None: if skill.name in self._skills: raise ValueError(f技能重复注册: {skill.name}) self._skills[skill.name] skill def get(self, name: str) - Optional[AgentSkill]: return self._skills.get(name) def list_descriptions(self) - list[str]: return [ f{skill.name}: {skill.description} for skill in self._skills.values() ] registry SkillRegistry() registry.register(query_project_status) registry.register(build_summary)重复注册检查非常重要。多人协作时同名技能经常是新来的人不知道已经有人注册过覆盖后其他调用方会莫名收到错误结果有了这个校验问题能在启动阶段直接暴露。3.5 模型调度链路的伪代码实现调度层负责把用户问题变成一系列技能调用。我采用的方式是让模型先输出一个JSON数组数组里每个元素是“技能名参数”。然后由代码逐个执行。import json def call_llm(prompt: str) - str: 调用任意大模型平台接口返回文本结果。这里用伪代码表示。 # return chat_completion(prompt) pass def run_agent(user_query: str) - str: skill_menu registry.list_descriptions() prompt f用户需求{user_query} 当前可用的技能如下 {chr(10).join(skill_menu)} 请根据需求输出一段JSON数组每个元素包含 skill 和 params 两个字段。 只允许使用上面列出的技能不要编造不存在的技能名。 raw_output call_llm(prompt) try: actions json.loads(raw_output) except json.JSONDecodeError as exc: return f模型输出不是合法JSON: {exc} context {} for action in actions: skill_name action.get(skill) skill_params action.get(params, {}) skill registry.get(skill_name) if skill is None: return f模型尝试调用未知技能: {skill_name} try: step_result skill.invoke(skill_params) except Exception as exc: return f技能执行失败: {exc} context[skill_name] step_result[result] # 如果前面已经执行过 query_project_status就组装摘要 if query_project_status in context: return build_summary.invoke({ project_id: context[query_project_status][project_id] if project_id in context[query_project_status] else unknown, raw_status: context[query_project_status], })[result] return 完成但没有找到合适的后续动作。这段代码做了一件很重要的事把模型从“执行者”变成“决策者”。模型负责决定调用谁、参数是什么代码负责把决策变成可靠的执行。这样一来若某一步失败我们能准确知道是哪一步、哪个参数、什么异常而不是对着模型日志一头雾水。3.6 跑一个实际例子看效果假设用户输入是“P001项目现在怎么样了帮我总结一下”。整个系统中的日志会呈现类似下面的执行轨迹第一步模型看到技能清单选中query_project_status生成参数{project_id: P001}第二步注册中心查到这个技能执行handler返回开发中进度正常第三步模型继续生成第二个动作build_summary参数包含project_id和raw_status第四步build_summary.invoke返回最终摘要。最终输出项目P001的最新状态是开发中进度正常。看起来平平无奇但这里面的关键不在结果有多惊艳而在于整个执行链路是可追踪、可控、可重试的。如果模型把project_id误写成了p001Schema枚举校验会直接拦截不会拿着错误参数去查数据库也不会产生脏结果。这种“边界下沉到代码”的做法就是技能化比裸Prompt稳得多的本质原因。4. 在实际项目中我踩过的坑与排查技巧4.1 技能描述与参数Schema脱节导致模型幻觉参数这是我认为出现频率最高的问题。早期做技能时我把build_summary的描述写成“该技能可以总结项目状态、生成报告、分析风险、给出优化建议”但实际参数Schema里只有project_id和raw_status两个字段。结果模型看到描述后非常合理地以为可以传入risk_level、report_format这类参数然后理所当然地被参数校验拦截导致流程中断。这个坑的解法就是我在设计篇提到的原则描述与Schema严格一一对应不存在的参数一个词也不要写。宁可描述短一点、保守一点也别让模型产生“泛能力”的误判。4.2 技能返回值结构不统一造成调度混乱有段时间我们的技能有的返回纯文本有的返回嵌套JSON什么都不统一。这让调度层在组装多步任务时非常难受上一步的结果不知道能不能直接作为下一步的入参模型也经常因为历史结果结构不一致而犯错。后来我强制所有技能返回统一结构{result: ..., meta: {...}}。result放规范数据meta放执行元信息。这个改动看起来小实际上把调度层的复杂度和模型的理解成本同时降了下来。4.3 重试逻辑在非幂等操作上引发脏数据某次我们上线了一个会创建工单的技能当时天真地加了自动重试逻辑。结果某天第三方接口响应超时重试机制自动触发第二次调用而第一次请求其实已经在服务端成功了最终下游系统出现了两张一模一样的工单。排查时我们盯着日志看半天只见超时最后去下游对账才发现重复。吃这个教训后我给所有技能增加了一个属性叫idempotent只读操作可以自动重试写操作必须提供幂等键如果没有则直接禁止自动重试改为人工介入。这里的重点是一定要在设计阶段就想清楚操作性质而不是上线后靠事故来提醒。4.4 结构化日志让排查效率翻倍技能化给我带来最大的隐性收益是可观测性。在纯Prompt时代一个请求失败很难定位到底是模型理解错了、Prompt规则冲突了还是外部接口出了问题。技能化之后每步都有明确的入参、出参、耗时和异常排查顺序可以固定为先看校验层是否拦截参数问题再看执行层是否超时外部依赖问题最后看返回结构是否合规契约问题。按这个顺序来大多数问题都能在半小时内定位。我在项目里养成的习惯是给每个技能的执行轨迹输出一条结构化日志包含技能名、输入摘要、校验结果、执行耗时、输出摘要。等到问题出现时按技能名聚合日志快速比对历史成功样本差异点一下就出来了。4.5 一个实用的小技巧为每个技能建立健康度指标这是我后期总结出来的一个额外做法。除了日志我还给每个技能统计了三个指标调用成功率、平均耗时、校验失败率。每周看一次。有意思的是这组指标常常能提前暴露问题比如某个技能的平均耗时从200毫秒突然涨到2秒但成功率还没掉下来这时主动去查下游接口性能往往能赶在用户感知到问题之前做掉优化。技能在这里不仅是一个执行单元也是一个可以独立监控的“业务服务单元”。这种能力是单一Prompt体系很难具备的。5. 最后聊几句个人体会这套技能化体系真正让我信服的地方不是某个技术细节有多精巧而是它把“让模型做事”这件事从临场发挥变成了组织能力。在大模型本身快速迭代的背景下技能化让团队做到了一件事模型换了一个又一个技能资产一直沉淀下来一个人写完的技能另一个人不读完整代码只靠描述和Schema就知道怎么接、怎么改。当然这套体系还远远没到完美的程度。现在让我比较纠结的是“技能如何自动生成”这条新方向未来Agent能不能根据任务描述自动写新技能、自动注册、自动评估目前我还在实验阶段但方向上是认同的——与其在每次对话里把能力重新叙述一遍不如让系统维护一个持续生长的能力清单哪一天这个概念真正成熟Agent工程化又会往前走一大步。如果你在做一个超过两个月寿命周期的Agent项目我的建议很直接尽早引入技能化的思路先不要贪多搭建三五个核心技能把定义、注册、执行、观测这条链路跑通再逐步扩张。踩坑的学费我已经替你交过了按这套思路走至少能避开早期的大部分问题。
RELATED

相关推荐

微电网储能系统Simulink仿真建模与工程实践

微电网储能系统Simulink仿真建模与工程实践

1. 微电网储能系统概述 微电网作为分布式能源系统的重要组成部分,其稳定运行离不开储能单元的协调控制。在实际工程中,储能主控单元需要实时响应电网状态变化,完成功率平衡、电压调节等关键功能。传统手工计算和硬件在环测试成本高、周期长&a…

📅 2026/10/14 9:35:49
构建Agent技能库:从堆提示词到可复用技能清单的实战复盘

构建Agent技能库:从堆提示词到可复用技能清单的实战复盘

做Agent应用做到第三个版本的时候,我彻底想明白了一件事:能不能把Agent做稳,根本不在于你给它写的那段系统提示词有多长,而在于你手里有没有一套可复用、可插拔、可度量的技能清单。 我管这套清单叫agent-skills。它不是什么高大…

📅 2026/10/14 9:35:49
街景OCR实战:检测识别两阶段方案与边缘部署要点

街景OCR实战:检测识别两阶段方案与边缘部署要点

1. 项目概述:这不是一场普通比赛,而是一次街景OCR实战沙盘 “【阿里天池新人赛】之街景字符识别(2)”——光看标题,你可能以为这只是又一个Kaggle式练手题。但实际跑完全部流程后我才意识到,这根本不是在识…

📅 2026/10/14 9:30:47
MORE NEWS

更多资讯

📰

Python自动化Excel数据清洗与汇总实战

1. 项目概述 每次月底盘点水果库存时,你是不是也对着几十张Excel表格发愁?从不同门店收集来的销售数据格式五花八门,手动复制粘贴不仅容易出错,还特别耗时。去年夏天我在连锁水果店做系统升级时就遇到过这个痛点 - 当时财务部的同…

📰

从“干完再发照片“到“每一步都能被确认“:异地交付的三段闭环,附 4 条可复制提示词

异地干活的真正成本:你做了 10 步,对方只看见最后 1 步 异地干活觉得累,第一反应通常是"累在来回跑、累在沟通"。 但真正让一个项目变难的,往往不是距离,是对方看不见你在干什么。 同一件活,你…

📰

罗伊氏粘液乳杆菌:肠道健康的微生物守护者

1. 罗伊氏粘液乳杆菌:从微生物学特性到实际应用罗伊氏粘液乳杆菌(Limosilactobacillus reuteri)这个看起来复杂的名字,其实是我们肠道里的"老朋友"。作为一名长期关注微生态健康的从业者,我见证了这个菌种从…

📰

值班大屏实战指南:轻量级工业可视化系统部署与信创适配

简介:这是一套专为值班监控场景设计的可视化大屏系统,面向运维、IT值守、数据中心及公共安全等需24小时实时信息展示的岗位人员,解决传统值班界面信息杂乱、更新滞后、缺乏设计感等问题。资源包共992个文件,体量9.7MB,…

📰

Web滚动性能优化与渲染管线深度解析

1. 高性能滚动与渲染优化的重要性现代Web应用对流畅滚动的需求越来越高。根据Google的研究,当页面帧率低于60fps时,用户就能明显感知到卡顿。而滚动性能直接影响到核心用户体验指标——首次输入延迟(FID)和累积布局偏移&#xff0…

📰

AB测试分层抽样实战:解决随机分组的样本偏差问题

1. 为什么AB测试不能只靠“随机分组”就万事大吉?我第一次在某电商公司的增长团队接手AB测试项目时,信心满满地写了二十行random.shuffle()np.array_split(),把10万用户按50:50切成了A组和B组,跑完一周数据后兴冲冲去汇报&#xf…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬