简介:文章从代码实现层面拆解 Agent Skills 与 Function Calling 的职责边界、加载机制和协作关系。两者不是替代关系,而是分别解决“调用什么工具、传什么参数”与“什么时候用、按什么步骤做、参考哪些材料”的问题。阅读本文可帮助开发者在设计智能体工具系统时更准确地划分上下文组织、工具注册与流程编排逻辑。
在构建基于大模型的智能体应用时,开发者通常会先实现一个基础的“工具调用循环”:模型接收用户请求,判断是否需要调用某个工具,生成结构化的调用参数,宿主执行对应函数,再把结果返回给模型继续推理。这个过程中最核心的机制通常被称为 Function Calling,它解决的是“模型如何表达一次工具调用”的问题。
但随着任务复杂度上升,单个工具调用往往不够。一个完整的数据质量检查可能涉及读取文件、执行脚本、核对主键、统计缺失值、生成报告等多个步骤。如果每次都要模型从零推导这些步骤,上下文会变得冗长且不稳定。于是出现了一种新的组织方式:把一个任务域相关的操作步骤、规则约束、脚本指引和参考材料打包成一个“技能”,也就是 Agent Skills。
这不是简单的命名替换,也不是某些框架中把普通函数注册成“skill”的旧用法。本文讨论的 Agent Skills 是一种带有元数据文件和说明文档的开放格式。理解它与 Function Calling 的关系,关键在于看清两者在代码层面各自承担什么职责,以及宿主程序如何把它们串起来。
Function Calling 是模型生成结构化调用意图的能力。模型不是直接执行函数,而是输出一个包含函数名和参数的对象,由宿主程序解析后真正执行。这个机制的核心在于:模型知道“有哪些工具可以调用”“每个工具需要什么参数”,并能根据用户输入生成合法的调用请求。
在代码实现上,Function Calling 通常表现为工具 Schema 的定义与注册。宿主把一组函数描述交给模型,模型在推理时从这些候选中选择。调用成功与否、参数是否合法、执行后返回什么内容,都由宿主控制。
Agent Skills 把一个任务域的知识封装为可发现、可按需加载的包。一个技能目录通常包含一份元数据文件和若干可选资源,例如脚本、参考文档、模板等。元数据文件描述技能名称、适用场景和核心规则,正文中给出具体操作步骤、约束条件和资源使用方式。
从代码层面看,一个技能不会自动注册成 Function Calling 列表里的某个新函数。技能目录中的脚本仍然是普通文件,宿主需要自行决定如何暴露给模型使用。Agent Skills 的价值在于改变了上下文的组织方式:模型先知道有哪些技能可用,再按需读取对应技能的详细说明,而不是在一开始就把所有细节塞进系统提示。
Function Calling 和 Agent Skills 都只是描述层或知识层的东西。模型可以“请求”一个函数调用,也可以“决定”读取某份技能说明,但真正的文件读写、进程执行、权限校验都是由宿主完成的。两者都不具备直接操作系统的能力。
Function Calling 通过结构化约束降低模型生成调用参数的随意性,Agent Skills 通过预先组织的操作说明降低模型在多步骤任务中的不确定性。它们最终都指向同一个方向:让智能体从“会聊天”变成“能办事”。
无论是一个函数 Schema 还是一份技能目录摘要,都必须出现在模型的上下文中,模型才能做出后续决策。区别只在于信息量的多少和加载时机,但它们共享同一个前提:模型不能调用它不知道存在的东西。
Function Calling 的信息单元是“单个工具”。每个工具有自己的名称、参数定义和描述。模型在推理时需要逐一匹配用户意图与可用工具。
Agent Skills 的信息单元是“任务域”。一个技能内部可以关联多个工具、多个脚本、多份参考材料,甚至可以指定工具使用的先后顺序。它把分散的工具使用知识提升到了“做事方法”的层面。
用一个 CSV 数据质量检查任务来说明。假设技能目录结构如下:
csv-audit/├── SKILL.md└── scripts/└── audit.py
其中 SKILL.md 的内容大致是:
---name: csv-auditdescription: 检查 CSV 的缺失值和重复键,输出数据质量摘要。---先确认主键列和空值定义,不自行猜测。使用 scripts/audit.py 检查,不修改输入文件。报告行数、缺失值数、重复键数。执行失败时说明原因,不编造统计数字。
这里的 audit.py 承载实际计算逻辑,SKILL.md 承载操作方法和约束。Function Calling 能表达“调用 audit.py 并传某个参数”,但无法自然表达“先确认主键列再执行脚本”“失败时不要编造数字”这类跨步骤规则。Agent Skills 恰恰补上了这一层。
Function Calling 的工具 Schema 通常在会话开始前就全部注册好。模型在整个对话过程中都能看到所有工具的描述。工具数量少时问题不大,但当成百上千个工具存在时,上下文会被大量 Schema 描述占据。
Agent Skills 引入了“发现后按需加载”的机制。宿主在启动时只把技能目录的摘要交给模型,比如技能名称、一句话描述和文件位置。模型判断任务与某个技能相关后,再触发读取对应的 SKILL.md 正文。这种两阶段加载方式显著降低了无关信息对上下文窗口的占用。
Function Calling 的实现重点在工具 Schema 的定义、注册和调用分发。宿主需要维护一个工具注册表,把模型生成的调用请求映射到具体函数,并处理参数校验、异常捕获和结果回传。
Agent Skills 的实现重点在技能发现和内容加载。宿主需要扫描技能根目录,解析每个技能目录中的元数据文件,生成可供模型检索的目录摘要。当模型发出读取请求时,宿主再定位对应文件并返回内容。
下面的伪代码展示了两者如何共存于一个简化的工具调用循环中:
catalog = discover_metadata(config.skill_roots)messages = [system(base_rules + render_catalog(catalog)),user(request),]tools = [READ_FILE_SCHEMA, RUN_PROCESS_SCHEMA]for round in range(MAX_ROUNDS):reply = model(messages, tools=tools)messages.append(reply)if not reply.tool_calls:return reply.textfor call in reply.tool_calls:result = checked_dispatch(call)messages.append(tool_result(call.id, result))raise BudgetExceeded
这段伪代码省略了 API 适配、文件解析和异常处理细节。可以看到,discover_metadata 负责扫描技能目录并生成摘要,render_catalog 把摘要注入系统提示。工具列表中只有 READ_FILE 和 RUN_PROCESS 两个基础工具,并没有为 CSV 审计技能专门注册一个“audit 工具”。模型先通过目录摘要发现技能,再调用 READ_FILE 读取 SKILL.md 获取详细步骤,最后通过 RUN_PROCESS 执行脚本。
checked_dispatch 是宿主必须实现的关键函数。它需要识别已注册的工具、校验参数和路径、执行权限检查,再在受控环境中执行。Agent Skills 本身不替代这套执行机制。
Function Calling 复用的是“单个函数的调用接口”。同一个函数可以在不同场景中被反复调用,但函数本身不携带使用知识。
Agent Skills 复用的是“完成一类任务的整体方法”。技能包中的说明文档、脚本和模板可以整体迁移到另一个宿主环境中使用。一个团队编写的 CSV 审计技能可以被另一个团队直接采用,只要对方实现了基础的读取文件和执行脚本能力。
Function Calling 通过严格的参数 Schema 约束模型的输出格式。模型生成的是结构化数据,宿主可以精确解析。
Agent Skills 通过自然语言说明引导模型的行为方式。模型读取 SKILL.md 后,按照其中的步骤和约束自主规划后续的工具调用序列。这种方式更灵活,但也更依赖模型对自然语言指令的理解能力。
| 对比维度 | Function Calling | Agent Skills |
|---|---|---|
| 核心信息单元 | 单个工具及参数定义 | 任务域的方法包 |
| 主要表达内容 | 调用哪个工具、传什么参数 | 什么时候用、按什么步骤、参考什么材料 |
| 代码实现重点 | Schema 注册与调用分发 | 技能目录发现与内容按需加载 |
| 上下文加载方式 | 会话开始前全量注册 | 目录摘要先行,详细内容按需读取 |
| 可复用粒度 | 函数接口级 | 任务方法级 |
| 对模型的约束方式 | 结构化参数 Schema | 自然语言操作说明 |
| 适用任务复杂度 | 单步、明确的工具调用 | 多步骤、需要领域知识的任务 |
| 扩展方式 | 新增工具 Schema | 新增技能目录 |
当任务可以清晰拆分为独立、明确的工具调用时,Function Calling 是更直接的选择。例如天气查询、翻译、简单的数据库读写、单次 API 请求等。这些场景下,模型只需要知道“有工具可以做这件事”以及“需要什么参数”,不需要额外的步骤说明。
当任务涉及多步骤操作、领域规则、约束条件或需要参考多个脚本和文档时,Agent Skills 的价值会更明显。典型场景包括数据质量审计、代码仓库分析、合规检查、特定格式文件的生成与校验等。这些任务中,“怎么做的知识”和“实际执行的代码”可以分离管理,技能包让两者形成清晰的对应关系。
大多数生产级智能体应用并不是二选一,而是两者配合。宿主提供一组基础工具用于文件和进程操作,Agent Skills 提供任务级的方法说明,模型读取技能后自行决定调用哪些基础工具。这种组合既保持了工具调用的结构化,又解决了复杂任务的知识组织问题。
如果任务是单步的、参数明确的,直接使用 Function Calling 即可,引入技能目录反而会增加不必要的文件扫描和加载逻辑。如果任务需要多轮推理、领域约束和步骤规划,优先考虑用 Agent Skills 组织知识。
当工具数量较多时,全量注册 Function Calling Schema 会占用大量上下文。此时可以采用技能目录摘要的方式,把详细工具说明放到技能文件中按需加载。这需要在宿主中额外实现技能发现和文件读取分发逻辑,开发成本会有所上升。
如果团队中同时存在“写脚本的人”和“写工具 Schema 的人”,Agent Skills 提供了一种自然的分工边界:脚本开发者专注于脚本逻辑,技能编写者专注于操作说明和规则约束。Function Calling 的 Schema 则通常需要开发者与模型工程师共同维护。
Agent Skills 对模型读取和理解自然语言说明的能力有更高要求。如果使用的模型在长文本理解和多步骤规划方面表现不稳定,应适当增加技能说明的结构化程度,例如在元数据中明确列出前置条件和禁止行为,而不是把所有内容写成一段自由文本。
这是最容易产生误解的地方。技能目录中的脚本文件不会因为存在于目录中就被模型直接调用。宿主必须显式实现基础工具,例如读取文件和执行进程,并让模型通过技能说明知道这些基础工具的存在和使用方式。
当模型可以读取技能文件并执行其中引用的脚本时,宿主必须对文件路径和进程执行范围做严格校验。一个恶意的或错误的技能说明可能引导模型读取不应访问的文件,或者执行带有破坏性的命令。checked_dispatch 实现中的权限检查和安全策略不能因为使用了技能目录而放松。
技能目录摘要是模型判断“是否加载某个技能”的依据。如果元数据中的名称和描述过于模糊,模型可能无法在正确时机触发加载。建议在元数据中明确写出适用任务类型、前置条件和输出要求,便于模型在检索时做出准确匹配。
相比单一的 Function Calling,引入技能目录后,模型的行为路径变得更长:先检索技能摘要,再读取技能文件,再执行脚本。排查问题时需要追踪每一步的输入输出。宿主应在日志中记录技能发现结果、文件读取请求、脚本执行命令和返回码,便于后续定位链路中的异常环节。
技能目录中的说明文档和脚本会随业务变化而更新。宿主需要处理技能缓存失效的问题,避免模型读取到过期的说明内容。对于在线更新的技能包,还需要考虑版本号或内容校验机制,确保模型获取的说明与实际可执行的脚本版本一致。
Agent Skills 与 Function Calling 在代码层面解决的是不同层级的问题。Function Calling 提供了一种结构化的工具调用表达方式,让模型能够可靠地生成调用请求;Agent Skills 提供了一种任务知识的组织方式,让模型能够在合适的时机加载合适的操作说明。前者回答“怎么调用”,后者回答“何时调用、按什么步骤调用、需要注意什么”。
在实现上,Function Calling 的重量级工作在于工具 Schema 的管理和调用分发,Agent Skills 的重量级工作在于技能目录的发现、元数据渲染和内容按需加载。两者并不冲突,反而可以在同一个工具调用循环中协同工作。开发者在设计智能体系统时,应根据任务的复杂度、上下文窗口的压力和团队的知识维护成本,决定采用哪种机制作为主要组织方式,以及如何让两者在统一的宿主逻辑中配合运行。