
1. 一个被混淆的核心概念Skill与Function Call最近在折腾大模型应用开发尤其是想搞点能自动处理复杂任务的Agent时发现社区里有个概念被讨论得有点“浆糊”了。很多人包括一些技术文档都把大模型的“Skill”技能和“Function Call”函数调用混为一谈或者认为后者是前者的高级形态。这导致在架构设计时经常出现定位不清、方案选型错误的问题。比如有人费老大劲用LangChain的工具调用Tool Calling封装了一堆复杂逻辑却发现响应慢、控制不灵活另一边有人试图用OpenAI的Function Calling来实现一个需要长期记忆和状态管理的“技能”结果代码写得又臭又长还容易出错。我自己在构建一个智能工作流助手时就踩过这个坑。当时我需要让模型能根据用户描述的模糊需求比如“帮我整理上周的项目会议纪要并提取待办事项发给相关同事”自动串联起“读取日历”、“检索会议文档”、“总结内容”、“识别责任人”、“生成邮件草稿”这一系列动作。一开始我试图把所有动作都定义成一个个独立的Function Call让模型去调用。结果发现模型经常在“理解用户意图”和“规划调用序列”这两个环节卡壳要么调用顺序错乱要么陷入循环。后来才意识到我需要的不是一个单纯的“函数调用”能力而是一个封装了特定领域工作流和决策逻辑的“Skill”。简单来说你可以这样理解Function Call 是模型完成一个具体、原子性动作的“手”和“脚”而 Skill 是模型指挥手脚去完成一个复杂任务的“大脑”和“经验”。两者协同工作但定位和价值截然不同。混淆它们就像让一个只会拧螺丝的工人Function Call去规划整个生产线Skill或者让一个总工程师Skill亲自去拧每一颗螺丝Function Call效率都会大打折扣。2. 拆解Function Call大模型的“标准化操作接口”我们先来把Function Call函数调用这件事掰扯清楚。自从OpenAI在GPT-3.5/4的API中正式推出这个特性后它几乎成了大模型与外部世界交互的“标准答案”。2.1 Function Call的本质结构化指令的输入与输出Function Call的核心是让大模型能够以结构化的方式“请求”执行一个外部函数。这个过程不涉及模型“真的”去执行代码它只做两件事理解与规划根据你的提示词Prompt和对话历史判断当前是否需要调用一个外部函数来获取信息或执行操作。生成调用指令如果需要它会生成一个符合你预先定义的函数参数格式JSON Schema的调用请求。举个例子你问模型“北京今天天气怎么样” 如果你在后台定义了一个get_weather(location: string)的函数模型可能会输出{ name: get_weather, arguments: {\location\: \北京\} }这个JSON对象就是Function Call的“执行结果”——更准确地说是“调用指令”。你的应用程序收到这个指令后才真正去执行get_weather(北京)这个函数获取到温度、湿度等数据然后再把这些数据作为上下文送回给大模型让它生成最终的回答“北京今天晴气温15-25摄氏度。”这里有一个关键细节也是很多新手容易忽略的Function Call的“执行结果”必须立即放回对话的短期上下文即同一轮对话的后续消息中否则对话逻辑会断裂。如果模型发出了调用指令但它在生成下一轮回复时没有“看到”函数执行后的真实结果它就会基于自己“猜测”的结果来回答往往会导致“幻觉”或错误。这就是为什么在热词里会看到“function call的‘执行结果’必须放进短期上下文否则本轮对话会当场死机”的说法。这并非真的死机而是模型失去了连贯推理的依据。2.2 Function Call的价值与边界精准、可控、但“没脑子”Function Call的价值非常明确突破知识时效与幻觉限制让模型能获取实时、准确的外部数据天气、股价、数据库查询结果。执行具体操作让模型能触发现实世界的动作发送邮件、控制智能设备、创建日历事件。输出结构化强制模型以预定格式输出便于后端程序解析处理比如自动生成数据录入的JSON。但是它的边界同样清晰原子性一个Function Call通常只完成一件非常具体的事。它不负责“为什么要做这件事”、“做完这件事下一步该做什么”。无状态每次调用都是独立的函数本身不记忆之前的调用结果或维护任务状态状态管理需要由你的应用程序来负责。无规划能力模型只会根据当前对话上下文决定“现在”是否需要调用某一个函数。它不会自动规划“为了回答用户问题我需要先调A函数拿到结果后再调B函数最后综合起来回答”。所以Function Call是一个极其强大但“被动”的工具。它完美解决了“让模型使用工具”的问题但没有解决“让模型智能地组合使用工具来完成复杂目标”的问题。3. 探寻Skill的真相大模型的“领域专家模块”那Skill技能又是什么这个词在AI领域尤其是在一些具体的应用或框架如早期的Codex Skill、某些智能体平台中经常出现但它缺乏像Function Call那样统一的官方定义。结合实践和社区讨论我们可以这样概括Skill是一个封装了特定领域知识、推理逻辑和操作序列的高阶能力单元。它不仅仅是一个函数更可能是一个包含多个步骤、条件判断、甚至内部状态的工作流。3.1 Skill的典型构成不止于API调用一个完整的Skill通常包含以下几个层面意图识别Understanding能理解用户输入的、与该技能相关的模糊或复杂意图。例如用户说“我嗓子疼有点发烧”医疗健康类的Skill需要能将其解析为可能的“感冒症状咨询”意图。信息补全与澄清Clarification当输入信息不足时能主动发起询问。例如上述场景中Skill可能会反问“发烧多少度有没有咳嗽、流鼻涕”规划与推理Planning Reasoning根据识别出的意图和已有的信息规划出一系列需要执行的动作Action。这些动作可能包括调用多个Function Call、进行内部计算或逻辑判断。动作执行与协调Execution按照规划有序地执行各个动作并处理动作之间的数据传递和依赖关系。结果整合与表达Synthesis将所有动作的执行结果整合起来形成最终对用户友好、完整的回应。可以看到一个Skill内部可能会多次调用不同的Function。Skill是“导演”Function Call是“演员”。导演Skill理解剧本用户需求安排拍摄顺序规划指导每个演员Function Call完成自己的戏份最后把片段剪辑成一部电影最终回答。3.2 从热词看Skill的实践形态浏览提供的热词我们能发现Skill的一些具体实践线索倪海厦skill、skill经方中医ai这很可能是一个封装了中医特别是经方诊断知识库、问诊逻辑和推荐方案的专用Skill。用户描述症状Skill通过多轮问答收集“四诊”信息然后调用内部的知识推理函数给出方剂建议。这远非一个简单的“查询药方”Function Call能实现。workbuddy skill、agent skill这类Skill通常内置于办公或智能体Agent平台用于处理“安排会议”、“总结邮件”、“生成报告”等复合任务。它需要访问日历、邮箱、文档等多个系统并理解公司内部的协作规范。skill开发、如何编写skill这说明Skill是需要被“开发”的它比定义一个Function Schema要复杂涉及更多的业务逻辑和流程控制代码。codex skill、claude code skill这可能指的是针对代码生成、解释、调试等任务的专用优化模块。它内部可能集成了代码语法知识、常见模式库、调试逻辑等对外提供一个统一的“代码助手”接口。Skill的价值在于它将解决一个复杂领域问题所需的专业知识、操作流程和决策逻辑进行了封装对外提供一个更智能、更贴近人类解决问题方式的接口。用户无需知道背后调用了哪些API、判断逻辑是什么只需要提出目标Skill会自主驱动完成。4. 定位差异对比何时用Skill何时用Function Call为了更直观地理解两者的区别我们可以从多个维度进行对比维度Function Call (函数调用)Skill (技能)核心定位工具使用接口。让模型能“操作”一个外部工具。问题解决模块。让模型能“像专家一样”解决一个领域问题。抽象层级低层级、原子性。关注单个、具体的操作。高层级、复合性。关注包含多步骤的完整任务。内部状态无状态。每次调用独立不记忆历史。通常有状态。可能在多轮对话中维护任务上下文如问诊进度。规划能力无。由模型或应用逻辑决定何时调用。有。技能内部包含达成目标所需的步骤规划。知识封装不封装领域知识。只定义操作接口。封装领域知识。包含解决特定问题所需的专业知识库和推理规则。开发复杂度低。主要是定义JSON Schema和实现后端函数。高。需要设计意图识别、对话管理、工作流引擎等。与模型的关系模型直接调用它。模型是调用者。模型具备或使用它。技能可以是模型能力的一部分也可以是模型调用的一个高级“工具”。类比螺丝刀、扳手。组装一台电脑的完整说明书和操作指南。4.1 实战选型指南根据上表的对比在实际项目中如何选择就清晰了你应该使用Function Call当你需要模型获取实时、准确的外部数据查天气、股价、数据库。你需要模型触发一个单一的、确定性的外部动作发邮件、存文件、调用一个API。你需要模型输出严格的结构化数据以便程序处理。你的任务逻辑非常简单一步就能完成。你应该考虑设计或使用Skill当用户的需求是模糊的、高层次的需要拆解和澄清如“帮我优化系统性能”。完成任务需要多个步骤并且步骤之间有依赖关系或条件分支。该任务涉及特定的领域知识需要一套专业的问答或推理逻辑。你希望为用户提供一个开箱即用、体验连贯的智能服务而不是让用户自己组合多个工具调用。很多时候两者是结合使用的。一个复杂的Skill内部会通过多次、有逻辑地调用不同的Function Call来完成其子任务。5. 主流框架下的实现与混同以LangChain为例现在很多开发者在用LangChain这类框架来构建大模型应用。有趣的是在LangChain的语境下Skill和Function Call的界限被模糊了这可能是造成概念混淆的一个原因。在LangChain中核心概念是Tool。一个Tool本质上就是一个可被模型调用的功能单元它背后通常关联着一个函数。当你用tool装饰器定义一个工具或者用StructuredTool.from_function创建工具时你就是在创建一个LangChain版本的“Function Call”能力。那么Skill在哪里呢在LangChain中更复杂的、多步骤的、有状态的“技能”通常是通过以下方式实现的AgentToolkit 一个Agent代理可以被看作是一个拥有决策能力的实体。你为它配备一套相关的Tools工具包Toolkit并赋予它一个系统提示词System Prompt这个提示词里描述了它的角色、能力和目标。这个Agent加上其专用的Toolkit和Prompt整体上就构成了一个Skill。例如一个“数据分析Agent”拥有查询数据库、绘制图表、进行统计计算等多个Tools并能根据用户问题决定使用哪个或哪几个工具这就是一个数据分析Skill。Chain 对于流程固定、顺序执行的任务你可以用LLMChain、SequentialChain等将多个LLM调用和Tool调用串联起来。这个固定的工作流链Chain也可以被视为一个简单的Skill。所以在LangChain的体系里Tool≈Function Call 原子操作。AgentToolkitPrompt≈Skill 具备领域知识和规划能力的复合模块。Chain≈ 简易版/流水线版Skill 固定流程的复合操作。当你问“langchain 工具调用 和llm function call 有什么区别”时在功能层面上它们非常相似都是让LLM使用外部功能。但LangChain的Tool抽象提供了更统一的接口和更丰富的生态集成。而“langchain 工具调用的速度是受什么影响”这个问题其答案就涉及框架开销、网络延迟如果Tool是远程API、工具本身的执行效率等多个因素这和在裸API层面使用Function Call考虑的性能问题是相通的。6. 架构设计启示构建高效能AI应用的关键厘清Skill和Function Call的差异对于设计一个稳健、高效的大模型应用架构至关重要。以下是一些基于个人实践的设计启示6.1 分层设计清晰的责任边界不要试图用一个“巨无霸”Function或者一个“无所不包”的Skill来解决所有问题。建议采用分层架构基础工具层Function Layer 这一层由大量原子性的、功能单一的Function Call组成。每个函数做好一件事并做好错误处理和日志记录。例如search_database(query),send_email(to, subject, body),call_calendar_api(event_details)。技能服务层Skill Layer 在这一层根据业务领域构建多个独立的Skill。每个Skill内部封装该领域的业务逻辑和工作流。它通过调用基础工具层的多个Function来完成任务。例如MeetingSchedulerSkill会内部调用query_free_slots()、create_calendar_event()、send_invitation_email()等基础函数。智能路由层Orchestration Layer 这是最上层通常由一个更通用的“主Agent”或“路由模型”担任。它负责理解用户的初始意图并决定将任务分发给哪个具体的Skill去处理。如果任务很简单它也可能直接调用某个基础工具。这样的分层使得系统易于维护、扩展和测试。基础工具可以复用技能可以独立开发和迭代。6.2 状态管理Skill的核心挑战Function Call是无状态的但Skill往往需要状态。例如一个订餐Skill需要记住用户已经选择了 pizza正在选择口味。这个状态管理不能依赖大模型有限的上下文窗口。实操方案外部状态存储为每个对话会话Session或每个用户任务Task在数据库或缓存中创建一个状态对象。Skill的执行引擎在每一步操作前后读写这个状态对象。技能专用上下文在调用Skill时将当前的任务状态作为系统提示词的一部分或者作为专用参数传递给Skill的执行逻辑。确保Skill的每一步都能“看到”全局进展。使用支持长上下文的模型或技术虽然不能完全依赖但像GPT-4 Turbo的128K上下文或使用airllm、llamafactory等工具进行长上下文优化、微调可以为简单的状态跟踪提供一定帮助但对于复杂、长期的状态外部存储仍是必须的。6.3 性能优化避免“对话死机”与提升响应速度热词中提到的“死机”问题以及LangChain工具调用的速度问题根源往往在于设计。确保执行结果回传这是铁律。无论是自己实现的循环还是使用LangChain等框架必须确保Function Call的执行结果被添加到大模型下一轮推理的上下文中。在LangChain的Agent执行器中这一步是自动完成的但如果你自己写调用逻辑务必检查。精简Skill的上下文Skill在调用时可能会携带大量领域知识如产品目录、诊断规则作为提示词。要精心设计提示词使用摘要、嵌入检索如通过harness框架进行知识抽取等方式只注入最相关的信息避免不必要的令牌Token消耗和速度下降。并行与异步如果一个Skill内部需要调用多个彼此独立的Function例如同时查询天气和交通状况应尽可能采用异步并行调用而不是同步顺序调用这能显著减少总体响应时间。本地化部署考量如果你使用ollama部署本地大模型或者使用英伟达免费大模型api需要考虑网络延迟和本地算力。对于复杂的、需要多次LLM推理和函数调用的Skill响应时间可能成为瓶颈。此时可能需要简化Skill逻辑或将部分确定性逻辑移到Skill的函数代码中减少对LLM的依赖。7. 从概念到代码一个简易Skill的构建思路最后我们抛开复杂框架用一个高度简化的伪代码示例来看看一个Skill内部是如何协调多个Function Call工作的。假设我们要构建一个“智能会议纪要生成Skill”。# 1. 定义基础工具函数 (Function Call Layer) def search_calendar_events(date_range, keywords): 查询日历事件 # 调用日历API return events def read_document(file_id): 读取云文档 # 调用云存储API return content def summarize_text(text): 总结文本内容这里可以调用LLM prompt f请总结以下会议记录的核心内容和待办事项{text} # 调用LLM API (Function Call) return summary def extract_actions(text): 提取待办事项这里可以调用LLM prompt f从以下文本中提取所有待办事项以JSON格式输出责任人、任务、截止时间{text} # 调用LLM API (Function Call) return actions_json # 2. 定义Skill逻辑 (Skill Layer) class MeetingMinutesSkill: def execute(self, user_request: str): 用户请求示例“生成我上周所有技术评审会的纪要并列出待办。” # 步骤1: 意图解析与信息提取 (可能调用一次LLM) parsed_intent self._parse_intent(user_request) # 输出: {“action”: “generate_minutes”, “time_range”: “last_week”, “meeting_type”: “技术评审”} # 步骤2: 调用工具获取原始数据 calendar_events search_calendar_events( parsed_intent[time_range], parsed_intent[meeting_type] ) all_minutes [] all_actions [] # 步骤3: 对每个会议执行子流程 for event in calendar_events: # 子步骤3.1: 获取会议文档 doc_content read_document(event.linked_doc_id) # 子步骤3.2: 生成摘要 summary summarize_text(doc_content) all_minutes.append({meeting_title: event.title, summary: summary}) # 子步骤3.3: 提取待办 actions extract_actions(doc_content) all_actions.extend(actions) # 步骤4: 结果整合与格式化 final_output self._format_output(all_minutes, all_actions) return final_output def _parse_intent(self, request): # 这里可以是一个简单的规则引擎也可以调用一次LLM进行理解 # 例如使用一个专门的、轻量的LLM Function Call pass def _format_output(self, minutes, actions): # 将中间结果格式化为对用户友好的最终输出 pass # 3. 在主流程中使用Skill (Orchestration Layer) def main_agent(user_input): # 简单的意图路由 if 会议纪要 in user_input or 待办 in user_input: skill MeetingMinutesSkill() result skill.execute(user_input) return result else: # 其他逻辑... pass在这个例子中MeetingMinutesSkill封装了从理解用户需求到生成最终结果的完整工作流。它内部协调了多次日历查询、文档读取、文本总结和事项提取的Function Call。用户只需要说一句模糊的话Skill就能交付一个复杂的结果。这就是Skill的价值——它将复杂性隐藏在了内部提供了更高级别的智能服务。所以下次当你设计AI应用时先问自己我需要的是让模型“学会使用一个工具”Function Call还是让模型“具备解决一类问题的能力”Skill想清楚这一点你的技术选型和架构设计就会清晰很多。