资讯详情

资讯详情

从 MCP 到 Skill:基于 FileBased Skill 与 Agent Framework 的配置实践与验证

1. 从 MCP 到 FileBased Skill为什么工具接进来了Agent 还是不好用MCP 解决的是连接问题它把本地文件、数据库、搜索引擎、业务 API 这些外部能力用一套标准协议暴露给模型。你可以把它理解成 AI 应用的 USB-C 接口只要对方支持这个协议插上就能用。这一步很关键没有它Agent 只能靠训练时记住的知识空转接不了实时数据也触发不了真实操作。但工具接进来之后新的问题马上出现。工具少的时候模型还能应付一旦工具数量涨到几十个模型面对的不再是能力不足而是信息过载。它要在一堆工具里挑却没有稳定的判断依据选错、用错、顺序搞反都很常见。更麻烦的是MCP 只负责把能力暴露出来不负责告诉模型在一个具体任务里先做什么、再做什么。多步骤任务里模型只能靠当前 prompt 临时推理一套流程这次跑通下次可能就偏了。FileBased Skill 补的正是这一层。它把经验和方法写成文件用目录结构组织起来让 Agent 在需要时按需加载而不是一次性把所有说明塞进上下文。这篇就聚焦 FileBased Skill 在 Agent Framework 里的落地路径从 MCP 出发梳理 Skill 文件化组织的配置骨架、调用链路交付可复制的目录结构、接入配置片段以及从 MCP 迁移过来的验证动作和排查清单目标是在本地跑通一个最小可用示例。2. TaoToken 前置准备把模型调用通道先打通在写 Skill 之前得先有一个能稳定调用的模型通道。Agent Framework 本身不绑定某一家模型服务它通过 OpenAI 兼容接口去请求模型。我这边习惯用 TaoToken 来做这一层原因是它的接口形态和 OpenAI 一致Agent Framework 里换 base_url 和 key 就能接上不用改业务代码。你需要准备两样东西一个 API Key以及确认要用的模型名。Key 在控制台里生成模型名在文档里能查到当前可用的列表。这两样拿到之后后面所有配置都围绕它们展开。注意Key 只放在环境变量或本地配置文件里不要硬编码进源码提交到仓库。我见过太多人把 key 写进 appsettings.json 然后推到公开仓库第二天就被刷爆额度。如果你后面要长期跑编码类 Agent或者做多轮工具调用的场景可以顺带看一下 Coding Plan它针对这类高频调用做了额度上的安排。但最小示例阶段一个普通 Key 就够了。3. FileBased Skill 目录结构与 Agent Framework 接入配置3.1 Skill 目录骨架FileBased Skill 的核心是渐进式披露元数据始终加载指令在触发时加载资源和代码按需加载。落到文件系统上就是一个 Skill 一个目录目录里放 SKILL.md 和可选的 references、scripts。skills/ └── unit-converter/ ├── SKILL.md ├── references/ │ └── conversion-table.md └── scripts/ └── convert.pySKILL.md 的头部是 YAML frontmatter只有 name 和 description 两个字段会被启动时加载每个 Skill 大约 100 tokens。description 写得好不好直接决定模型能不能在正确时机触发这个 Skill。--- name: unit-converter description: 用于执行单位转换通过 value 和 factor 计算结果 --- ## 使用方法 当用户请求单位转换时 1. 首先查看 references/conversion-table.md找到对应的换算系数 2. 运行 scripts/convert.py 脚本并传入参数 --value 数值 --factor 系数 例如--value 26.2 --factor 1.60934 3. 将转换结果清晰地展示出来并同时标明原单位和目标单位references 里放换算表scripts 里放真正干活的 Python 脚本。脚本通过 bash 执行执行过程不消耗上下文只有结果回到模型。这是 FileBased Skill 相比纯 prompt 方案最大的优势确定性操作交给代码模型只负责判断和编排。# scripts/convert.py import argparse parser argparse.ArgumentParser() parser.add_argument(--value, typefloat, requiredTrue) parser.add_argument(--factor, typefloat, requiredTrue) args parser.parse_args() result args.value * args.factor print(f{args.value} * {args.factor} {result:.4f})3.2 Agent Framework 接入片段Agent Framework 里接入 FileBased Skill核心是构造一个 AgentSkillsProvider把它塞进 Agent 的 AIContextProviders。Provider 的第一个参数是 Skill 根目录第二个参数是一个委托用来告诉框架怎么运行 Skill 里的脚本。AgentFileSkillScriptRunner myRunner async (skill, script, args, ct) { var psi new ProcessStartInfo(python) { RedirectStandardOutput true, RedirectStandardError true, UseShellExecute false, }; psi.ArgumentList.Add(Path.Combine(skill.Path, script.FullPath)); if (args ! null) { foreach (var (key, value) in args) { if (value is not null !string.IsNullOrWhiteSpace(value.ToString())) { psi.ArgumentList.Add(key); psi.ArgumentList.Add(value.ToString()!); } } } using var process Process.Start(psi)!; string output await process.StandardOutput.ReadToEndAsync(); await process.WaitForExitAsync(); return output.Trim(); }; var skillsProvider new AgentSkillsProvider( Path.Combine(AppContext.BaseDirectory, skills), myRunner);这个 runner 是整条链路里最灵活的地方。你可以在里面调 Python、调 HTTP API、查数据库甚至直接调你自己的 C# 方法。框架不关心你怎么执行只要求你返回一个字符串结果。这意味着 Skill 的脚本层可以复用你现有的任何工具链。创建 Agent 时把 provider 传进去AIAgent agent new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) .GetResponsesClient() .AsAIAgent(new ChatClientAgentOptions { Name UnitConverterAgent, ChatOptions new() { Instructions 你是一个可以调用工具进行单位转换的助手。, }, AIContextProviders [skillsProvider], }, model: deploymentName);这里的 endpoint 和 deploymentName 换成 TaoToken 的地址和你要用的模型名即可。因为走的是 OpenAI 兼容协议Agent Framework 不需要知道背后是谁在提供服务。4. 验证请求与成功结果跑通最小可用示例配置写完跑一个真实请求来验证整条链路。prompt 里故意放两个不同单位的转换看 Agent 会不会自动触发 unit-converter并按 SKILL.md 的指导去调脚本。Console.WriteLine(正在使用基于文件的技能进行单位转换); Console.WriteLine(new string(-, 60)); var stringBuilder new StringBuilder(); await foreach (var response in agent.RunStreamingAsync( 请严格用脚本计算。马拉松26.2 英里等于多少公里另外75 千克等于多少磅)) { stringBuilder.Append(response.Text); } Console.WriteLine(stringBuilder.ToString());预期行为是这样的Agent 先读 SKILL.md 的 description判断当前请求匹配 unit-converter然后加载 SKILL.md 主体按里面的步骤先去 references 查换算系数再调 convert.py最后把结果整理成自然语言返回。实测下来第一次跑最容易卡在脚本路径上。runner 里用的是Path.Combine(skill.Path, script.FullPath)如果 skill.Path 是相对路径而工作目录又不对Python 就会报找不到文件。建议在 runner 开头把 skill.Path 打印出来确认一下。成功时你会看到类似这样的输出运行脚本: convert.py STDOUT: 26.2 * 1.60934 42.1647 STDOUT: 75.0 * 2.20462 165.3465 马拉松 26.2 英里约等于 42.16 公里75 千克约等于 165.35 磅。注意 STDOUT 那两行是 runner 里打印的最后一行才是模型整理后的回答。这说明脚本确实被执行了而不是模型自己算的。验证 FileBased Skill 有没有真正生效关键就看脚本有没有被调用而不是只看回答对不对。5. 本篇常见错排查清单5.1 Skill 没被触发最常见的原因是 description 写得太泛。比如写成「单位转换工具」模型可能觉得和当前请求匹配度不够。description 要写清楚「什么时候用」而不是「这是什么」。改成「用于执行单位转换通过 value 和 factor 计算结果」之后触发率明显提升。另一个原因是 SKILL.md 的 frontmatter 格式不对。YAML 头部必须以---开头和结尾name 和 description 缺一不可。少一个字段整个 Skill 在启动时就不会被注册。5.2 脚本执行报错先确认 runner 里用的解释器在目标机器上存在。上面用的是python如果你的环境只有python3就得改。其次确认脚本路径拼接正确skill.Path和script.FullPath拼出来要是一个真实存在的文件。如果脚本有参数检查 args 的传递方式。runner 里是把 key 和 value 依次加进 ArgumentList所以脚本里用 argparse 接收时参数名要和 SKILL.md 里写的一致。SKILL.md 写--value脚本里就不能定义成--val。5.3 上下文里看不到 Skill 内容这是正常的。Level 1 的元数据始终加载但 Level 2 的 SKILL.md 主体只有在触发时才进上下文。如果你在调试时想确认 Skill 有没有被加载可以在 runner 里打印 skill.Name或者在 Agent 启动后检查 AIContextProviders 是否包含 skillsProvider。5.4 从 MCP 迁移过来的额外注意点如果你之前用 MCP 接了一堆工具现在想逐步迁到 FileBased Skill不要一次性全迁。先挑一个流程固定、步骤明确的任务做成 Skill跑通之后再迁下一个。MCP 负责连接Skill 负责方法两者可以共存。迁移过程中原来 MCP 暴露的工具可以继续留着Skill 只是在它上面加了一层使用说明。排查时如果发现模型在两个 Skill 之间反复横跳说明 description 的边界没划清。两个 Skill 的适用场景要有明显区分否则模型会在触发阶段就犹豫。6. 接入通道与后续动作整条链路跑通之后你会发现 FileBased Skill 的价值不在于替代 MCP而在于把「怎么用工具」这件事从 prompt 里抽出来变成可版本管理、可复用、可按需加载的文件。Agent Framework 的 AgentSkillsProvider 把加载和执行解耦runner 负责执行SKILL.md 负责指导模型只负责判断。如果你还没拿到可用的 Key先去控制台生成一个然后照着接入文档把 endpoint 和 model 换掉就能把上面的示例跑起来。想先验证模型对 Skill 描述的理解能力可以直接在模型对话里贴一段 SKILL.md 的 description看它能不能正确判断触发时机。长期跑编码类 Agent 的话Coding Plan 在额度上会更合适一些。最后留一个实用技巧SKILL.md 里的步骤编号尽量和脚本参数一一对应模型在加载指令后照着编号走出错概率会低很多。我试过把步骤写成散文式描述模型偶尔会跳步改成编号列表之后就稳定了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →