AI认知篇3:Function Calling/MCP/Skills 的概念和作用

前言

这是我的agent系列文章的第2篇,该系列分为三部分:

  • AI认知篇:详细讲解相关基础概念
  • AI实践篇:分享诸如skills怎么写、怎么ai coding、怎么写好prompt等的最佳实践
  • AI八股篇:分享我自己整理的应付大模型应用开发岗位必备的八股笔记

如果觉得有帮助,欢迎关注我并期待后续文章!预期是日更哦!当天没更可能是因为太累了,周末会弥补的。

做 AI Agent 开发,总被 Function Calling、MCP、Skills 这三个概念绕晕?其实三者层层递进,MCP 和 Skills 都基于 Function Calling 打造,只是解决的实际问题不同,二者甚至并非互补,而是核心竞争关系。这篇文用通俗的语言讲清三者的本质、差异和适用场景,快速上手不踩坑。

1.先懂底层:AI Agent 工具调用的核心逻辑

不管是哪种技术,AI Agent 调用工具的核心流程都只有 4 步,也是 Function Calling 的设计基础:

一个典型的 AI Agent 工具调用流程是这样的:

1、LLM 接收用户请求和工具描述

  • 用户提出需求(比如 "帮我查一下北京今天的天气")
  • 系统向 LLM 提供可用工具的列表和描述(比如 "天气查询工具:可以查询指定城市的天气信息")

2、LLM 决定是否需要调用工具

  • LLM 根据用户需求和工具描述,判断是否需要调用工具
  • 如果需要,LLM 会生成结构化的工具调用请求

这里的关键是 LLM 返回的是结构化的 JSON 格式,而不是自然语言。比如用户说 "帮我查一下北京今天的天气",LLM 可能会返回:

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\": \"北京\", \"date\": \"today\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ]
}

这种结构化的输出格式,就是 Function Calling 的核心机制。它让系统能够稳定地解析 LLM 的意图,而不需要复杂的文本解析逻辑。注意关键字段:

  • tool_calls:当需要调用工具时,这里包含工具调用的信息;
  • function.name:要调用的工具名称;
  • function.arguments:工具的参数(JSON 字符串格式);

3、系统解析并执行工具调用

  • 系统解析 LLM 生成的工具调用请求;
  • 执行对应的工具函数(比如调用天气 API);
  • 获取工具执行结果

还是以上面的 llm 返回为例,上面的 JSON 格式会被系统解析并转换为真正的函数调用。以 JavaScript 为例:

// 1. 从LLM响应中提取工具调用信息
const toolCall = response.choices[0].message.tool_calls[0];
const functionName = toolCall.function.name;  // "get_weather"
const functionArgs = JSON.parse(toolCall.function.arguments);  // {city: "北京", date: "today"}

// 2. 根据工具名称找到对应的函数
const tools = {
  get_weather: (city, date) => {
    // 执行天气查询逻辑
    return `北京今天天气:25°C,晴天`;
  },
  // ... 其他工具
};

// 3. 执行工具调用
const result = tools[functionName](functionArgs.city, functionArgs.date);
// 实际调用:tools["get_weather"]("北京", "today")

这个过程是自动的:系统根据function.name找到对应的函数,解析function.arguments获取参数,然后执行调用。这就是 Function Calling 让工具调用变得可预测和可靠的核心机制。

4、将结果返回给 LLM

工具执行结果被返回给 LLM;

LLM 根据结果决定下一步行动(继续调用工具,或者生成最终回答)。

小结:function calling工具调用的本质

这个流程的核心在于:LLM 需要把用户的非结构化需求(一段自然语言文本)转换为结构化的函数调用(函数名和参数),然后与其他应用程序交互,再将结构化结果返回给模型,让模型能够基于这些结果进行下一步决策。

问题的本质在于,历史上其他系统(数据库、API、文件系统等)只能处理结构化信息,而 LLM 擅长处理非结构化信息(文本)。因此,LLM 必须想办法在两种信息形式之间架起桥梁:将非结构化的用户需求转换为结构化的函数调用,这样才能与外部系统交互。

这就是 Function Calling 的本质,也是后面 MCP 和 Skills 能够存在的前置条件。

2.既然有了function calling,为什么又会有 MCP 和 Skills 呢?

Function Calling 确实解决了核心问题:让 LLM 能够稳定地输出结构化的工具调用请求,实现了 "非结构化→结构化" 的转换。这是 AI Agent 工具能力的基础。

但在实际应用中,开发者很快发现了一个新的问题:工具集成成本太高

Function calling 会有工具集成成本高的问题

现实世界中,有大量的既有系统和数据:数据库里存储着业务数据,文件系统里有各种文档和代码,GitHub 上有项目仓库和 Issue,dingding 里有团队沟通记录,还有各种 API 服务提供实时数据。这些既有系统里有着丰富的信息,如果能让 LLM 直接使用这些系统和数据,AI Agent 的能力会大大增强。

但问题是:如何让 LLM 能够使用这些既有系统?

在 Function Calling 的框架下,每个既有系统都需要单独集成到应用中。每个组织或公司都有自己的 API、认证方式、数据格式,开发者需要为每个组织或公司编写对应的函数实现。这就是 MCP 产生的原因:提供一个服务,可以让既有系统快速集成到 LLM 中

MCP 的核心其实还是基于 Function Calling 的。它做的事情很简单:把 Function Calling 的调用,在客户端转换成一套 JSON+HTTP 的请求。然后提供一套 Server 来响应这个 JSON+HTTP 请求,这样就能实现各类应用都可以被 LLM 使用的效果。

LLM -> Function Calling -> MCP Client -> JSON+HTTP请求 -> MCP Server -> 既有系统(GitHub/Slack/数据库等)
                                                                          ↓
LLM <- Function Calling结果 <- MCP Client <- JSON响应 <- MCP Server <- 既有系统返回结果

  1. LLM 决策:用户提出需求,LLM 判断需要调用工具,并通过 Function Calling 生成结构化的调用请求(包含工具名和参数)。
  2. 协议转换MCP Client 捕获这个请求,将其转换为标准的 JSON-RPC over HTTP 格式。
  3. 服务端处理MCP Server 收到标准请求,根据预定义的逻辑,去调用具体的既有系统(如执行 SQL 查询、调用 GitHub API、读取本地文件)。
  4. 结果回传:既有系统的执行结果被 MCP Server 封装成标准 JSON 格式,沿原路返回给 LLM。
  5. 最终响应:LLM 结合工具返回的数据,生成自然语言回答给用户。

但 MCP 解决了工具集成的问题后,又出现了另一个问题。

Function Calling 和 MCP 都会有任务流程定义困难的问题

在实际使用中,用户经常需要让 AI Agent 按照特定的方式执行任务。比如,格式化 Excel 表格要按照公司的品牌指南,法律审查要遵循特定的合规性要求,数据分析要按照组织的工作流程。这些任务往往需要复杂的提示词和多个步骤的组合。

但在 Function Calling 和 MCP 的框架下,用户面临一个两难的问题:当前的大模型很难仅仅依托自己的模型能力就做出最优的工具调用步骤。很多任务需要特定的执行顺序、规则和约束,但把这些步骤全部写成代码又不太现实。就像我们在第一篇文章里讲的,模型的核心优势是面对不确定性时可以走一步看一步,动态调整策略。如果全部落成程序,就会丧失模型的核心优势。

举个例子,我们以 Lynxe 实际在跑的一个 new_branch 流程定义为例,我这个流程用文字写到一个 markdown 里面,每次都让模型遵照执行:

1) 确认本地的 VERSION 与 pom.xml 与 本地branch 中的版本一致,不一致的话以pom.xml为准
2) mvn package
3) 进入 ui-vue3 运行pnpm lint
4) 退回项目目录, git merge upstream/main
5) 项目目录,运行 make ui-deploy
6) git 提交 branch到origin
7) git 打包 tag名字与pom的版本号一致,先删除远程tag(如果存在):git push upstream :refs/tags/v{版本号},然后上传tag到 upstream (上传之前请先用git remote 看一下upstream是哪里,确认是spring-ai-alibaba/JManus)

这个流程有 7 个步骤,每个步骤都有特定的顺序、条件和规则。如果完全写成代码,每一步都要处理各种异常情况(比如版本不一致、tag 已存在、upstream 地址不对等),代码会变得非常复杂。但如果只给模型一个简单的提示词 "帮我创建新分支",模型可能无法按照这个精确的流程执行,或者执行顺序不对。 而用文字表达,非常直接简单,而且实际跑的过程中只有很小的概率会出错,非常爽。

而这就是这个问题的本质:如何在尽可能的准确的前提下,能让用户能用文字(而非代码)指导模型按照特定的流程和规则执行任务?

这就是 Skills 产生的原因(其实也是 Lynxe 的 Func-Agent 产生的核心原因):提供一个方式,让用户可以用文字定义指令、脚本和资源,形成可复用的任务流程。

Skills 的核心其实也是基于 Function Calling :通过一个固化的函数和参数,让模型去查找和加载固定的 skills 文档。

这里的关键是,Skills 完全依赖于 Function Calling 这个基础能力。 如果没有 Function Calling,Skills 就无法工作。Skills 只是在 Function Calling 之上的一个巧妙应用:把 "加载文档" 这个操作封装成一个函数,然后让 Claude 在需要时自动调用。

具体工作流程是这样的:

  1. 初始化阶段:用户用文字定义指令、脚本和资源,打包成 Skills(包含 SKILL.md 和可选的脚本、参考资料等)。Claude 在启动时会读取所有 Skills 的元数据(名称和描述),这些元数据被加载到模型的上下文中(每个约 100 token)。
  2. 发现阶段:当用户发起请求时,Claude 会根据请求内容,对比已加载的 Skills 元数据,判断是否需要使用某个 Skill。这个判断过程本质上就是 LLM 根据上下文做决策,跟 Function Calling 中判断是否需要调用工具是一样的。
  3. 加载阶段(Function Calling):如果 Claude 判断需要某个 Skill,它会通过 Function Calling 机制调用一个专门的加载函数(类似load_skill(skill_name)),将对应的 SKILL.md 文档内容读取并加载到当前上下文中。这一步完全依赖 Function Calling 的能力。
  4. 执行阶段(继续使用 Function Calling):SKILL.md 的内容(包含指令、流程、示例等)被加入到上下文后,Claude 按照文档中定义的指令执行任务。如果 SKILL.md 中定义了需要执行脚本(比如 scripts/rotate_pdf.py),Claude 还是会通过 Function Calling 调用执行脚本的函数。如果需要加载参考资料,同样是通过 Function Calling 调用读取文件的函数。

可以看到,整个 Skills 的运行过程,从加载文档、执行脚本到读取资源,每一步都离不开 Function Calling。Skills 并没有创造新的能力,它只是把 Function Calling 这个基础能力组织成了一个更易用的形式:让用户可以用文字定义流程,让 Claude 自动发现和加载相关知识。 从本质来说,它替代的是 mcp 调用的函数里面,过去可能会用代码写的一套串接各种 API 的逻辑流程,用这种方式,可以增强流程的适应性,其实也是呼应了我们第二篇文章的核心观点:Agent 将决策权完全下放给了 Agent 和 Prompt,能够解决原有写程序不能解决的问题 —— 比如处理不确定性、动态调整策略、理解自然语言意图等。

Claude 判断是否需调用某 Skill(基于请求内容匹配已加载的 skill_name 与 description)
↓
若需要,则通过 Function Calling 调用 load_skill(skill_name)
↓
将对应 SKILL.md 的内容注入当前上下文,作为执行指令依据
↓
Claude 依照 SKILL.md 中定义的流程执行任务
↓
在执行过程中,按需通过 Function Calling:
  • 调用 bash 执行附带脚本
  • 调用 read_file 读取所需资源文件
↓
整合执行结果

3.逐个拆解:三个概念的本质与价值

Function Calling:AI Agent 调用工具的「基本功」

核心定位:AI Agent 调用工具的基础能力,是 MCP 和 Skills 存在的前提,无它则后续两者都无法实现。

核心价值:架起「LLM 自然语言」和「外部工具结构化调用」的桥梁,让 LLM 能把用户的自然语言需求,转换成包含函数名、入参的结构化 JSON 格式,系统可直接解析执行,无需复杂的文本处理。

一句话总结:所有 AI Agent 调用外部工具,都离不开 Function Calling 这个底层能力。

MCP(Model Context Protocol):解决工具集成的「标准化方案」

核心定位:由 Anthropic 推动、现已捐赠给 Linux 基金会的开放接驳标准,完全基于 Function Calling 打造。

核心解决问题:Function Calling 集成既有系统(数据库、GitHub、各类 API、钉钉等)时,每个系统都要单独写代码适配,认证方式、数据格式不统一,集成成本极高

核心价值把 Function Calling 的调用请求,标准化转换为 JSON+HTTP 请求,通过 MCP Client/Server 架构,让 LLM 能统一对接各类外部系统,开发者无需为每个系统单独做适配,大幅降低集成成本。

小提醒:MCP 只是「标准化方案」,并非唯一选择,用 curl、bash 等传统方式也能对接系统,实际开发中后者甚至更简单。

Skills(Claude Skills):解决流程定义的「文字化方案」

核心定位:Anthropic Claude 的新尝试,是sub-agent 的包装形式,同样基于 Function Calling 实现。

核心解决问题:Function Calling 和 MCP 都无法简单定义复杂任务流程 —— 写代码实现流程会丧失 LLM 处理不确定性的灵活性,仅靠提示词又会让流程执行混乱、出错率高。

核心价值让用户用纯文字(编写在 SKILL.md 文档中)定义任务的执行流程、规则和资源,Claude 会基于 Function Calling 自动发现、加载并执行这些文字流程,既保留 LLM 动态调整策略的优势,又能让复杂任务按指定规则执行

执行逻辑加载全部 Skills 元数据→匹配用户需求→通过 Function Calling 加载对应 SKILL.md→按文档流程执行→按需调用工具 / 脚本→整合结果。

4.最精简总结

本质定位

AI Agent 工具调用的基础能力

LLM 对接外部系统的标准化接驳协议

用文字定义流程的 sub-agent 包装

核心解决问题

自然语言转结构化工具调用

工具集成成本高、对接标准不统一

复杂任务流程定义难,代码实现丧失灵活性

核心优势

所有工具调用的底层基础,适配性强

统一对接标准,降低多系统集成成本

文字定义流程,保留 LLM 动态调整的优势

适用场景

所有需要 LLM 调用外部工具的场景

需对接数据库、GitHub、各类 API 等多系统的场景

代码审查、部署流程、文档格式化等需固定规则的复杂任务

1. Function (函数调用)

  • 是什么:LLM(大模型)的“”。
  • 作用:让只会说话的大模型能够执行具体操作(如查天气、算数、搜索)。
  • 工作原理 用户提问。大模型发现需要工具,输出一个结构化指令(例如:“调用 get_weather,参数 city=北京”)。外部程序接收指令,执行代码,把结果返回给大模型。大模型结合结果回答用户。
  • 痛点:每接一个新工具,开发者都要写专门的代码来对接,像给每个电器配不同的插头,麻烦且成本高。

2. MCP (Model Context Protocol)

  • 是什么:AI 界的“通用 USB 接口”(标准化协议)。
  • 作用:解决 Function 对接成本高的问题,让各种系统(数据库、文件、GitHub等)能即插即用。
  • 工作原理统一标准:定义了一套标准的通信语言(JSON + HTTP)。中间件模式 MCP Client(客户端):在大模型侧,把模型的指令翻译成标准语言。MCP Server(服务端):在具体系统侧(如你的电脑或数据库),听懂标准语言,去执行实际操作。流程:模型 -> 标准指令 -> MCP Server -> 既有系统 -> 返回结果。
  • 核心价值:开发者只需写一次“适配器”(MCP Server),所有支持 MCP 的 AI 都能直接用它,无需重复造轮子。

3. Skills (技能/流程定义)

  • 是什么:用文字写成的“操作说明书”(基于 Prompt 的动态流程)。
  • 作用:让大模型学会串联多个步骤去完成复杂任务,而无需编写复杂的代码逻辑。
  • 工作原理 用户用一个 Markdown 文件(如 SKILL.md)写下自然语言流程(例如:“第一步查库存,如果少于10,第二步发邮件给经理”)。大模型阅读这份“说明书”,理解逻辑。在执行时,大模型根据当前情况,动态决定下一步该调用哪个 Function 或 MCP 工具。
  • 核心价值用提示词代替代码。适合处理灵活多变、逻辑不确定或需要频繁调整的业务流程。

三者关系总结图

Function

让 AI 能干活

基础能力

MCP

万能插座

让 AI 能低成本连接各种设备

建立在 Function 之上,做标准化

Skills

操作手册

让 AI 能按复杂逻辑自动干活

建立在 Function/MCP 之上,做流程编排

一句话总结Function 是 AI 做事的能力;MCP 是让 AI 更容易连接到各种工具的标准接口Skills 是用文字指令教 AI 如何组合这些工具去完成复杂任务的方法

其他

考研失利想速成冲春招的考研看看我发过的这篇帖子:论考研失利如何冲春招

想要学习Java冲实习或冲春招的,我能助你一臂之力,我之前整理了高质量可速成的魔改外卖项目话术和7000字轮子项目话术,还有超全超精品八股大全专栏怎么写简历,怎么包装实习经历,怎么0基础速成冲春招和实习等等精品帖子,大家可以去看看我的精品文章汇总帖子:往期精品秋招帖子汇总

我的java和大模型应用开发全专栏(20w人学习,超千人订阅,牛客最受欢迎最高质量java八股专栏,内容包含: 1.八股大全:多一句没有少一句不行的最精简八股整理,完全可以应付校招社招的八股拷打! 2.速成项目话术:目前有魔改苍穹外卖项目话术(额外扩展了很多技术亮点),能速成拿去面试,后面会更新魔改黑马点评、商城项目等等热门高质量项目话术 3.智力题超详细题解汇总; 4.面试时非技术问题话术整理,绝对震惊面试官一年; 5.算法lc hot100全题系列题解:绝对通俗易懂;6、场景题汇总快速冲刺秋招专栏

#大模型应用开发##春招##AI应用##java##聊聊我眼中的AI#
全部评论
今日份日更贴来了,我tm猛猛学
1 回复 分享
发布于 昨天 23:22 北京

相关推荐

本人双九(一般的985)现在🐻厂实习字节hr两次电联同一个职位的实习,问我考不考虑,第二次说的很恳切🐻厂给的测开,字节给的后端本人还没确定,秋招走大厂还是走央国企,目前暂时偏向稳定,更倾向于在江浙一带工作犹豫的点:1.目前组内氛围好,mt也好,组长也好2.如果再面试,我需要重跑我的项目,再准备+八股+手撕,会很累3.如果准备不充分,怕脏面评过来人告诉你&nbsp;字节hr&nbsp;就是这德行面试前对每个候选人特别舔&nbsp;面完找他问进度就查无此人了哈哈哈哈哈,这几天在xhs上略有了解海捞吧hhh前期很热情,突然很冷淡😁双九这么不自信的吗?我这个实习的准备时间短,感觉在接其他面试被拷打了,项目和技术栈不熟,就没什么自信稳定也挺好呀在面字节前面几家其它的后端面试会好一些哈哈哈哈我同门面字节,一面二面就没有低于1h的,哈人🐻厂留用率?哥们儿你不知道字节是一线大厂里面发面最多的吗,发面试又不是oc,hr再恳切有作用吗现在知道了哈哈哈为啥要犹豫,字节不还是正常面试吗,又不是已经拿到oc了不想脏面评,不过现在也无所谓了,也不准备去大厂现在这么卷,0实习能进的,都是有真本事的测开转后端也不错吧,不过HR虽然舔,面试要求不会放松的🐻厂留用率?听说转正会比较容易?不是特别了解还以为是到hr面了让你去呢,就约个面试能有多诚恳那就赶紧准备啊,看看别人面经,刷八股啥的暂时没有特别想换的准备,大概率all&nbsp;in央国企了字节hr都很热情吧,最近27届暑期开了,也收到几个电话&nbsp;但是考虑不想脏面评就不面了已经略有了解了,感觉很海捞建议不要脏面评,年后投随便约面666又遇到兄弟了hr是说约年后试一下咯暂时不考虑了hhh双***历都到顶了不是很厉害的9,曾经被嘲过要不等年后吧,不差这一次吧??字节那不是投了就能面吗?一定要面这个岗?打电话也是准备说年后了,年前肯定不行哈哈哈我投的少,我也不知道是不是投了就能面主要怕我面得不好,唉双9干什么测开哈哈哈哈哈,准备实习的时间很短很仓促,收到的后端面试不多,想着先有个实习就走了测开熊是什么厂百度大胆去面吧&nbsp;我就是不自信加上没后端实习&nbsp;秋招大厂只投了测开&nbsp;现在有点后悔,不自信加上项目不熟,我感觉会被拷打所以害怕没事&nbsp;不会损失啥&nbsp;等你真的拿了测开就会像我一样从激动欣喜到焦虑前景还有一个就是怕字节脏面评,所以如果接面试肯定也会努力准备一下的如果秋招不满意的话,还能搏一搏春招吧,我身边就有在春招找到不错的岗位的还有就是,emmmm,周围也有面字节的,普遍表示有难度,我觉得我菜
点赞 评论 收藏
分享
评论
4
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务