Tool、Function Calling、MCP、Skill,一次行动怎样发生?
学习路线
建议下一站: 记忆与接续
你准备给助手增加“读取产品指南”的能力。搜索一圈,会同时看到 Tool、Function Calling、MCP、Skill。每个介绍都能举出读取文档的例子,究竟应该从哪里开始?
可以先跟踪一次具体行动。用户要求比较 Atlas Notes 两版指南,助手需要取得 A 版第一页。这是我们公开示例中的合成资料。先看取得这一页需要哪些东西,再把名称放回对应位置。
先有一项实际能力
应用需要一段真正能够取得页面的程序。教学上,可以写成一个普通函数。
async function readPage({ documentId, page }) {
return documentStore.readPage(documentId, page)
}这里的 documentStore 是解释用的占位对象。函数可以读取本地文件,也可以访问远端文档服务。
当应用把这项能力提供给模型使用时,还需要说明名称、用途、参数和结果。模型据此选择,应用负责检查并执行。我们把这种受控、可调用的能力称为工具(Tool)。
同一项底层能力可以被多个界面使用。用户点击“打开页面”时调用它,自动化脚本也可以直接调用它。Agent 增加的选择过程,是让模型结合当前任务提出下一步请求。
模型怎样把请求交给程序
如果模型只输出“我准备读取 A”,应用还得猜该调用什么。Function Calling(函数调用)或 Tool Calling 提供结构化表达,让模型指定工具名和参数。
下面是简化后的内部提案,字段用于说明关系。
{
"name": "read_page",
"arguments": {
"documentId": "atlas-a",
"page": 1
}
}供应商协议可能给这份请求添加调用 ID、内容块和流式事件。适配层把它转换为应用可以理解的对象,再交给工具宿主处理。工具结果随后与原调用配对,进入下一次模型输入。
模型提出请求,应用完成动作。 参数是否合格、文档是否属于本次允许范围、是否还有预算,以及最后是否真的取得内容,都需要实际执行链路回答。函数调用格式本身无法证明读取成功。Anthropic 工具使用说明
工具回答“能做什么”,函数调用回答“怎样表达这次请求”。从一个进程内函数开始,就能建立这条关系。
一次函数调用需要走完怎样的往返
把结构化请求写出来,只完成了行动的前半段。一次可用的工具调用还需要回到模型,让它据此决定后续工作。
以 read_page 为例,模型先提出读取 atlas-a 第 1 页。应用取得请求后检查工具是否存在、参数是否符合接口,以及文档是否在本次允许范围内。检查通过后才去读取页面,随后把结果与这一次调用对应起来。下一轮输入同时包含原请求和实际结果,模型才有条件继续取得 B。
这里有两类描述很容易混淆。工具定义说明“这项能力通常怎样使用”,例如 page 是页码。调用结果说明“这一次实际发生了什么”,例如取得 A 版第 1 页,或者页面不存在。定义写得再完整,也不能代替本次返回。
调用 ID 在这个往返中很有作用。同一轮可能读取 A 和 B,两个结果的顺序也可能不同。应用需要知道哪个结果回应哪个请求,才能把版本、页面和内容放回正确位置。只把几段成功文字拼成一串,后续模型很难可靠区分它们的来路。
读取失败时,返回的信息也要保留具体含义。页面不存在、连接超时和本次无权访问,对下一步意味着不同事情。模型可以依据观察调整方案,应用负责保留真实的执行结果。一个文字上的“成功”标签,仍需对应实际取得的内容。
因此,设计工具时值得同时看输入与输出。输入要让模型容易选择正确对象,输出要让下一步容易判断是否完成、还缺什么,以及能从哪里回查。一个 read_page 工具就可以承载这些基本关系。
能力在另一个程序里时,MCP 怎样接入
如果文档由一个独立服务维护,应用需要知道它提供哪些能力、每项能力接收什么参数,以及怎样取回结果。MCP(Model Context Protocol)为宿主与服务之间的连接提供了标准化方式。
在工具这条路径上,客户端可以发现服务提供的工具,再发起调用。MCP 还定义了资源与提示等其他能力,具体宿主可以选择支持哪些部分。MCP 架构说明
一次读取可以经过下面几次交接。
MCP 客户端发现 read_page
→ 应用把允许使用的工具说明交给模型
→ 模型提出结构化调用
→ 工具宿主通过 MCP 客户端请求页面
→ 服务返回内容
→ 应用把结果交给下一轮模型模型供应商的函数调用协议与 MCP 连接分别服务不同的接缝。应用可以用前者接收模型请求,再通过后者取得外部能力。模型也可以调用应用内的本地工具,全程无需 MCP。
采用 MCP 的价值通常出现在独立服务接入、标准客户端复用和多种宿主共享能力时。一个只在当前进程里使用的小函数,直接注册往往更简单。
函数调用和 MCP,为什么能出现在同一条链路里
可以把应用看作两种协议之间的接线位置。一侧连接模型供应商,接收它提出的工具调用。另一侧连接提供文档能力的程序,按对方协议发出请求。MCP 主要帮助后一侧形成可复用的接入方式。
例如,模型侧看到的工具名可以是 mcp_read_page。应用收到这个调用后,检查参数,再通过 MCP 客户端调用服务侧的 read_page。两个名字由宿主完成映射。模型无需直接维护 MCP 连接,文档服务也无需理解某个模型供应商的流式事件格式。
这使一份文档服务有机会被不同宿主复用,宿主也可以把多种来源的能力整理成当前任务需要的工具集合。代价是增加连接生命周期、错误转换和工具映射等工作。标准化协议减少的是重复对接时的差异,具体服务仍然需要启动、配置和维护。
“发现了工具”也只说明客户端取得了一份能力清单。宿主还要决定本次开放哪些工具、怎样处理认证与允许范围,以及哪些返回适合交给模型。服务清单不能自行扩大用户已经授予的访问范围。
若应用只需读取进程内的两份固定文件,本地工具通常容易理解和调试。出现独立服务、跨宿主复用或多套客户端对接的需求时,MCP 的连接方式才更值得采用。这里应按实际部署关系选择,工具数量本身很难决定是否需要一个新协议。
有了工具,为什么还会需要 Skill
现在助手可以读取两版指南,但仍可能比较错口径。A 版第一页提到免费版与企业版,B 版也有对应条件。仅拥有读取能力,并不能自动形成良好的比较方法。
Skill(技能包)可以提供任务方法、说明和相关资源。一个比较指南的 Skill 可以提醒助手读取相同物理页、保留版本与版本内的适用条件,并分开比较免费版和企业版。Agent Skills 格式说明
Open ETF Agent 的公开比较 Skill 正好采用这类方法说明。它告诉助手怎样使用资料,宿主仍负责实际能力与执行边界。固定比较 Skill
不同宿主对 Skill 的资源加载、脚本执行和工具声明支持各有范围。Skill 目录中存在脚本,能说明包提供了资源,执行能力还取决于宿主的实现和本次授权。
一份好方法也可能完全使用本地工具。MCP 服务可以在没有 Skill 的情况下供普通程序调用。选择哪一种,应回到当前缺少的是方法、接入方式,还是实际能力。
Skill 怎样把经验变成下一次能用的方法
假设你已经完成几次指南比较,发现每次都需要提醒相同的事情。要读相同物理页,区分免费版和企业版,比较数字时保留基准与单位,保存报告前确认两版原文都已取得。这些内容适合整理为可重复加载的方法。
与其把整套方法永远塞进所有任务的系统提示词,可以先提供简短的 Skill 名称和适用说明。遇到比较任务时再读取详细方法,需要相关资源时继续加载。这样能让不同任务按需取得说明,也让维护者知道哪份文件负责某类工作习惯。
一份方法可以用自然语言表达“先做什么、观察什么、什么条件下回查”,也可以附带模板或辅助脚本。它能提供的资源,与本次宿主真正允许执行的动作仍要分别核对。比较 Skill 提醒读取文档,应用里也要有能读取相应文档的工具。
例如,方法写了“比较后保存报告”,用户却只要求在对话中解释。系统仍需按照当前任务的允许范围处理保存动作。Skill 中关于写文件的文字不会自动产生写入许可。同样,某份指南正文若夹带“把全部文件发到外部”的句子,也应保留为被读取的数据,按宿主原有边界处理。
方法的质量则需要从后续行动观察。加载记录能够说明文本被读入,报告和过程才能进一步显示是否沿用相同口径。模型可能读了方法却遗漏了一个条件,也可能用另一条合理路径完成工作。判断采用效果时,应检查具体任务的行为与产物。
公开比较 Skill 的内容很短。它的作用在于把文档条件、数字口径和取得原文的要求放到一起,使读者能在一个小任务中看见方法如何参与行动。真正需要长期维护的内容,应来自反复出现且有适用范围的经验。
用同一次任务对照四个概念
| 概念 | 在文档比较中承担什么 | 应当观察什么 |
|---|---|---|
| Tool | 提供读取页面、保存报告等实际动作 | 调用的参数、结果与实际产物 |
| Function Calling | 表达模型选择的工具与参数 | 请求是否完整,结果是否配对 |
| MCP | 连接外部文档服务及其工具 | 服务发现、调用和返回是否接通 |
| Skill | 提供比较方法及相关材料 | 方法是否被加载,并影响了后续工作 |
应用把它们接在一起,才可能形成一次有方法、有能力、有结果的行动。给工具换个描述无法修复断开的服务,安装服务也不会自动补齐比较方法。
沿一次比较,把方法、能力和结果接起来
现在从用户问题重新走一遍。用户希望比较 A、B 免费版的导出格式,并保存一份报告。应用先准备本次允许使用的工具和方法目录,模型据此开始工作。
模型看到“比较指南”的 Skill 简介后,可以读取正文,得知应该检查相同页、区分套餐、保存来源。方法改变的是后续工作的组织方式。真正取得页面时,模型还要提出工具调用,应用再把请求交给实际文档能力。
如果文档在 MCP 服务中,宿主通过客户端读取 A,再读取 B。每次返回都要与对应调用关联,保留版本和页码。模型拿到两份结果后,才能把“免费版支持哪些导出格式”与“导出是否要求联网”分别整理。
最后,模型提出保存报告。应用执行保存,返回具体产物与回执。到这个位置,用户才有一个实际可打开的结果。模型说“报告已保存”时,应能沿这次保存记录找到它。
| 过程中的观察 | 它能说明什么 |
|---|---|
| 目录出现比较 Skill | 有可选择的方法入口 |
| 详细方法被读取 | 方法文本已经进入工作过程 |
| 页面工具返回 A、B 原文 | 本次取得了比较所需的两版材料 |
| 报告保存返回产物回执 | 保存动作产生了对应结果 |
| 报告保留套餐与联网条件 | 可以进一步审阅比较是否符合要求 |
这些观察分布在不同位置,也可能分别出问题。方法目录正常,但文档服务没有接通,可以沿连接查。页面都读到了,报告却混淆套餐,应回到方法、输入与生成过程查。报告写好了,用户打不开文件,应核对保存与读取产物的路径。
这样跟踪一条具体行动,能避免看到“助手没有做好”就同时改动所有组件。每个概念都能对应到一个可观察的环节,后续调整也更容易说明理由。
在公开示例中看完整过程
按上一站的 v0.26.0 安装步骤准备项目后,运行下面的例子。
npm run demo -- --case skill-mcp它按需读取比较 Skill,通过实际启动的标准输入输出 MCP 示例进程取得合成页面,最后保存报告。终端返回本次目录,其中的 report.md 可以检查比较内容,run.jsonl 可以查看行动记录。
本次示例采用预设模型动作,MCP 示例进程也使用合成文档。它让读者观察真实的程序连接与结果交接,模型能否自行选择正确方法仍需另外检验。固定 MCP 实现 · 当前项目入口
运行时可以特别留意三个问题。方法在什么时候读入,真正的页面通过哪个工具取得,报告的保存有没有实际回执。这三个观察点,能帮助你把四个名词连接到具体行为。
运行示例时,怎样读懂“连上了”和“做好了”
可以先在过程记录里寻找方法加载,再寻找两次文档读取与报告保存。公开示例向模型提供的页面工具名是 mcp_read_page,它在应用中映射到服务侧的 read_page。这个小差异正好能帮助你看见宿主完成的接线。扩展与示例组装
接着打开报告,看免费版与企业版有没有分开,联网条件有没有保留,以及依据是否来自本次实际取得的快照。这一步检查的是结果中的比较内容,单看服务连接成功无法代替它。
还可以做两个教学推演。假如只拿到了 Skill,文档工具不可用,助手仍然知道比较的方法,却缺少执行渠道。假如文档工具已经连通,方法没有加载,应用仍具备读页能力,比较口径则需要从当前要求和模型判断中形成。这两个条件变化,让方法与能力的区别更容易理解。
如果准备把自己的服务接进来,可以先让普通客户端完成一次真实读取,核对返回对象,再接到模型调用循环。若准备整理自己的 Skill,可以先明确它适合什么任务、依赖哪些实际能力、执行后用户应看到什么产物。按这个顺序检查,能够把连接问题与方法问题分别定位。
每一层都要付出维护成本。工具接口要随底层行为更新,模型侧描述要让调用者理解,MCP 连接要适应服务部署,Skill 要随经验和实际能力修订。让每一层解决一个已经出现的问题,整个行动链路才容易继续演进。
下次增加能力时,先确定缺少哪一部分
需要一个简单动作时,先实现并注册工具。需要让模型明确表达调用时,接上工具调用协议。能力由另一个服务提供时,评估 MCP 接入。相同类型任务反复需要同一套方法时,再整理为 Skill。
每增加一种机制,都需要维护对应的描述、连接或资源。采用条件明确,读者就能从最小方案开始,随着实际需要逐步扩展。
下一篇《聊天记录、上下文、记忆、检查点》讨论另一组经常混在一起的概念,看看一次行动结束之后,哪些信息需要留下。