大模型应用:解锁大模型能力边界:Skill 与 Function Call的底层逻辑与实战应用.117

一、前言

在大模型从对话交互走向实际落地的过程中,Function Call作为连接语言模型与外部能力的关键机制,早已成为行业标配。我们曾深入拆解过它的底层逻辑、执行流程与工程实现,清楚其核心价值在于让大模型输出结构化调用指令,完成计算、查询、接口交互等原本无法可靠完成的任务。但在很长一段时间里,我们广泛讨论 Function Call 时,很少提及Skill,甚至将二者混为一谈。

随着大模型应用复杂度快速提升,单一函数调用已无法满足多场景、多任务、可管理的智能体需求,Skill 这一概念才正式走到台前。相信很多人都会疑惑:同样是扩展大模型能力,Skill 与早已熟悉的 Function Call 究竟是什么关系?二者在定位、设计、使用场景上又存在哪些本质差异?带着这个疑问,我们从核心定义、工程形态、应用演进三个维度,清晰梳理 Skill 与 Function Call 的关联与区别,并解释为何早期只强调 Function Call,而如今必须将二者结合理解,为真正掌握大模型的能力扩展体系打下基础。

Function Calling往期文章参考:

《构建AI智能体:Function Calling - 解锁大语言模型的实际行动力+案例解析;》

二、核心基础

1. 什么是 Skill(技能)

Skill(技能)是为大模型定义的可执行任务模板,是对大模型能力的具象化扩展。我们可以把它理解为给大模型"安装的插件"或"学会的新本领,比如"计算数学题"、"查询天气"、"生成 Excel 报表"、"调用地图 API查路线"等,每个 Skill 对应一类特定任务,包含任务描述、输入参数、执行逻辑、输出格式四个核心要素。

关键特征:

  • 针对性:一个 Skill 只解决一类问题,比如"文本翻译 Skill"仅处理翻译任务,避免功能混杂;
  • 标准化:Skill 需定义清晰的输入输出规范,让大模型能精准理解"该传什么参数"、"能得到什么结果";
  • 可组合性:多个 Skill 可以组合完成复杂任务,如"查天气 Skill"+"生成出行建议 Skill"="智能出行规划";
  • 可复用性:定义好的 Skill 可以在不同场景重复调用,无需重复开发。

举个通俗例子:大模型本身像一个只会聊天的大脑,而 Skill 就是给它配备的工具手册,手册里写清楚"计算器工具怎么用"、"查快递工具怎么用",大脑只需按手册操作就能完成原本不会的任务。

2. 什么是 Function Call(函数调用)

Function Call(函数调用)是大模型执行Skill的桥梁机制,指大模型根据用户指令,识别需要调用的 Skill 对应的函数,按照预设格式生成函数调用指令,交由外部系统执行后,再将结果返回给用户的全过程。

核心区别:

  • Skill 是"能力定义",比如"定义一个计算两数之和的技能";
  • Function Call 是"能力执行",比如"调用这个求和技能,计算 10+20 的结果"。

Function Call 的核心要素:

    1. 函数元数据:函数名称、参数列表(参数名、类型、是否必填)、返回值类型;
    1. 调用触发器:大模型识别用户指令中包含"需要执行具体操作"的意图,比如用户说"帮我算一下 3.14×50 的结果",触发 "计算器函数"调用;
    1. 参数提取:大模型从用户指令中提取函数所需参数,比如从"3.14×50"中提取参数 a=3.14,b=50,操作符 =×;
    1. 执行器:执行函数调用的外部程序,可以是 Python 函数、API 接口、本地脚本等;
    1. 结果解析与返回:将函数执行结果转换为自然语言,返回给用户。

3. Skill 和 Function Call的特点

大模型原生能力存在三大痛点,而 Skill+Function Call 正是解决方案:

    1. 能力边界限制:大模型无法执行实时计算(比如复杂数学公式)、访问实时数据(比如最新股票价格)、操作外部系统(比如调用企业 ERP 接口);
    1. 准确性问题:大模型对数字计算、逻辑推理的准确率远低于程序,比如计算"12345×6789"时容易出错,而调用计算器函数可100%准确;
    1. 安全性与可控性:直接让大模型生成代码执行存在安全风险,而通过标准化 Skill 和 Function Call 可限定调用范围,降低风险。

简单来说:Skill 定义"大模型能做什么",Function Call 实现"大模型怎么做",二者结合让大模型从语言模型升级为智能执行体。

4. Skill与Function Call的深度关系

不知道大家有没有一个疑问,为什么以前讲 Function Call 很少提 Skill?为什么现在又必须绑定 Skill 一起讲?

4.1 早期为什么只讲 Function Call,不提 Skill

早期,2023年初 OpenAI刚推出Function Call,大家的场景都超级简单:

  • 只调用1个函数
  • 函数是 写死的
  • 用途是 计算器、查天气、查时间 这种小工具
  • 没有"技能管理"、"技能选择"、"技能编排"

那时大家关心的只有三件事:

    1. 模型能不能输出结构化JSON
    1. 能不能 正确填参数
    1. 本地能不能 执行函数

所以大家只讲:Prompt → 模型输出函数调用 → 本地执行 → 返回结果

这就是 Function Call,Skill 这个概念根本没必要出现。

4.2 什么时候 Skill 被迫出现了

当应用从调用1个函数变成同时管理10/50/100个函数时,问题炸了:

  • 函数太多,模型不知道该用哪个
  • 函数描述混乱,模型经常乱调用
  • 函数重复、冲突、难维护
  • 不同场景要切换不同能力集
  • 要做 权限控制、版本管理、热更新

这时大家突然发现:单纯的 Function Call 根本撑不起复杂应用。

于是行业统一做了一件事:给"一堆函数 + 描述 + 参数 + 逻辑"起个名字:Skill(技能)

4.3 本质区别

  • Function Call:是调用方式、是协议、是格式、是技术机制,模型如何调用外部能力,包含机制、协议、格式
    • Function Call 是执行层,核心是:模型 → 输出 JSON → 调用外部代码
  • Skill:是被调用的能力单元、是封装好的功能模块、是可管理、可组合、可上架的技能,被模型调用的能力单元,包含功能、封装、业务
    • Skill 是能力层,包含计算器 Skill、天气 Skill、订单查询 Skill、知识库 Skill...

总的来说,Skill 是 Function Call 的内容,Function Call 是 Skill 的入口。

三、原理与流程

1. Skill 的设计原理

一个完整的 Skill 本质是 "结构化的任务描述 + 可执行的逻辑代码",其设计遵循以下核心原理:

1.1 Skill 的结构化定义规范

无论使用哪种大模型平台,Skill 的定义都包含以下标准化结构(以 JSON 格式为例):

javascript 复制代码
{
  "skill_name": "calculator",  // 技能名称(唯一标识)
  "skill_description": "用于执行基本数学运算,支持加减乘除、平方、开方",  // 技能描述(让大模型理解用途)
  "parameters": [  // 参数列表
    {
      "name": "num1",  // 参数名
      "type": "float",  // 参数类型
      "required": true,  // 是否必填
      "description": "第一个运算数"  // 参数描述
    },
    {
      "name": "num2",
      "type": "float",
      "required": false,  // 非必填(比如平方只需要一个数)
      "description": "第二个运算数"
    },
    {
      "name": "operation",
      "type": "string",
      "required": true,
      "description": "运算类型,可选值:add, sub, mul, div, square, sqrt",
      "enum": ["add", "sub", "mul", "div", "square", "sqrt"]  // 枚举值(限定输入范围)
    }
  ],
  "return_value": {  // 返回值定义
    "type": "float",
    "description": "数学运算的结果"
  },
  "error_handling": {  // 异常处理规则
    "div_by_zero": "除数不能为0,返回错误提示",
    "invalid_param": "参数类型错误,返回参数要求说明"
  }
}

这个结构化定义的核心目的是让大模型能精准理解 Skill 的使用规则,比如大模型看到这个定义后,就知道 "calculator" 技能需要哪些参数、参数类型是什么、支持哪些运算,从而在用户提问时准确提取参数并调用。

1.2 Skill 的分类

根据执行方式和应用场景,Skill 可分为三类:

    1. 本地函数型 Skill:对应的执行逻辑是本地 Python/Java 函数,比如本地计算器函数,优点是响应快、无网络依赖;
    1. API 调用型 Skill:对应的执行逻辑是调用外部 API,比如天气 API、地图 API,优点是能获取实时数据、访问远程服务;
    1. 组合型 Skill:由多个基础 Skill 组合而成,比"查天气 Skill"+"查交通 Skill"+"生成建议 Skill"="出行规划 Skill",优点是能解决复杂任务。

2. Function Call执行流程

Function Call 的执行是一个"大模型意图识别→参数提取→函数执行→结果返回" 的闭环流程,我们以"用户让大模型计算 3.14×50 的结果"为例,拆解完整执行流程:

流程说明与技术细节分析:

步骤 1:意图识别

大模型通过"指令理解 + Skill 匹配"判断是否需要调用函数。实现方式有两种:

  • 基于提示词(Prompt)的意图识别:在 Prompt 中明确告诉大模型"当用户的问题涉及数学计算时,调用 calculator 函数";
  • 基于微调的意图识别:对大模型进行微调,让它能更精准识别需要调用函数的场景,更适合专业场景。

**技术细节:**Prompt 设计需包含"Skill 列表 + 调用规则",比如:

你是一个能调用函数的智能助手,可用函数列表:

  1. calculator:用于数学计算,参数包括num1(浮点数)、num2(浮点数,可选)、operation(运算类型:add/sub/mul/div/square/sqrt)

当用户的问题涉及数学计算时,你需要生成JSON格式的函数调用指令,格式如下:

{"function_name": "calculator", "parameters": {"num1": 值, "num2": 值, "operation": 运算类型}}

如果不需要调用函数,直接回复用户即可。

步骤 2:参数提取

大模型从用户指令中提取函数所需参数,核心挑战是"处理非标准化输入",比如用户说"帮我算一下圆周率乘以 50",需要先将"圆周率" 转换为 3.14。

**技术细节:**可通过"实体识别 + 同义词映射 + 默认值填充"提升参数提取准确率:

  • 实体识别:识别指令中的数字、运算类型等关键实体;
  • 同义词映射:将"乘以"映射为"mul","加上"映射为"add";
  • 默认值填充:比如用户只说"计算10的平方",自动填充num2为null,operation为square。

步骤 3:生成函数调用指令

大模型需生成标准化的调用指令,通常为JSON格式,确保外部执行器能解析。比如针对"3.14×50",生成的调用指令为:

javascript 复制代码
{"function_name": "calculator", "parameters": {"num1": 3.14, "num2": 50, "operation": "mul"}}

**技术细节:**为避免大模型生成格式错误的 JSON,可在 Prompt 中加入格式约束,比如"必须严格按照JSON格式生成,不要添加额外文字,确保JSON可被Python的json.loads()解析"。

步骤 4:函数执行

外部执行器接收调用指令,解析参数后执行对应函数。执行器的核心逻辑是"函数注册表 + 参数校验 + 执行":

  • 函数注册表:维护"函数名→函数对象"的映射关系;
  • 参数校验:检查参数类型、必填项是否符合Skill定义;
  • 执行:调用函数并捕获异常,比如除零错误。

步骤 5:结果返回与转换

  • 执行器将函数结果返回给大模型,大模型将机器结果转换为自然语言结果。
  • 比如函数返回157.0,大模型转换为"3.14 乘以 50 的计算结果是 157.0"。

3. Skill 与 Function Call原理总结

  • Skill 的核心原理:标准化定义能力边界,让大模型知道"能调用什么、怎么调用";
  • Function Call 的核心原理:意图驱动的闭环执行,将大模型的语言理解能力与外部程序的执行能 结合;
  • 二者的本质:突破大模型的原生能力边界,实现"语言理解→逻辑执行→结果反馈"的完整智能闭环。

四、应用实践

我们常用的混元大模型(Hunyuan)已经提供了 OpenAI 兼容接口,支持 Function Call(函数调用)功能。特别是 hunyuan-turbo、hunyuan-pro 以及专门的 hunyuan-functioncall 模型都支持此功能。但由于在 OpenAI 兼容接口中,参数名已从旧版的 functions/function_call 更新为更通用的 tools/tool_choice,基于此我们实现一个计算的示例:

python 复制代码
import json
import os
from dotenv import load_dotenv
from openai import OpenAI

# 加载环境变量 (如果需要)
load_dotenv()

# ====================== 配置腾讯混元客户端 ======================
# 注意:请确保您的 API Key 有权限访问混元大模型

client = OpenAI(
    api_key=os.getenv("TENCENT_API_KEY"),
    base_url="https://api.hunyuan.cloud.tencent.com/v1",  # 腾讯混元 OpenAI 兼容接口地址
)

# ====================== 第一步:定义 Tool(计算器技能) ======================
# 混元兼容接口推荐使用 tools 格式 (OpenAI 新版标准)
calculator_tool = {
    "type": "function",
    "function": {
        "name": "calculator",
        "description": "用于执行基本数学运算,支持加减乘除、平方、开方",
        "parameters": {
            "type": "object",
            "properties": {
                "num1": {
                    "type": "number",
                    "description": "第一个运算数"
                },
                "num2": {
                    "type": "number",
                    "description": "第二个运算数(平方、开方时可选)"
                },
                "operation": {
                    "type": "string",
                    "description": "运算类型",
                    "enum": ["add", "sub", "mul", "div", "square", "sqrt"]
                }
            },
            "required": ["num1", "operation"]
        }
    }
}

# ====================== 第二步:Skill 对应的执行函数 ======================
def calculator_function(num1: float, operation: str, num2: float = None) -> float:
    """
    计算器函数,执行基本数学运算
    """
    try:
        if operation == "add":
            return num1 + num2
        elif operation == "sub":
            return num1 - num2
        elif operation == "mul":
            return num1 * num2
        elif operation == "div":
            if num2 == 0:
                raise ValueError("除数不能为0")
            return num1 / num2
        elif operation == "square":
            return num1 ** 2
        elif operation == "sqrt":
            if num1 < 0:
                raise ValueError("负数不能开平方")
            return num1 ** 0.5
        else:
            raise ValueError(f"不支持的运算类型:{operation}")
    except Exception as e:
        raise Exception(f"计算失败:{str(e)}")

# ====================== 第三步:核心逻辑 ======================
def get_completion_with_tools(messages, tools=None, tool_choice="auto"):
    """
    调用腾讯混元 API,处理工具调用逻辑
    使用 tools 参数替代旧的 functions 参数
    """
    try:
        response = client.chat.completions.create(
            model="hunyuan-turbo",  # 推荐使用 turbo 或 functioncall 专用模型,lite 可能不支持
            messages=messages,
            tools=tools,            # 使用 tools 列表
            tool_choice=tool_choice # 自动选择或指定
        )
        return response
    except Exception as e:
        print(f"API 调用错误:{e}")
        raise e

def execute_function_call(function_name, function_args):
    """
    执行函数调用
    """
    function_registry = {
        "calculator": calculator_function
    }
    
    if function_name not in function_registry:
        return f"错误:未找到函数 {function_name}"
    
    try:
        result = function_registry[function_name](**function_args)
        return result
    except Exception as e:
        return f"函数执行失败:{str(e)}"

# ====================== 第四步:完整流程测试 ======================
def main():
    # 1. 用户输入 (包含两个计算请求)
    user_input = "帮我计算一下 3.14 乘以 50 的结果,再算一下 100 的平方根"
    
    # 2. 构造对话消息
    messages = [
        {"role": "system", "content": "你是一个快乐的小助手,擅长使用工具进行精确计算。"},
        {"role": "user", "content": user_input}
    ]
    
    print(f"用户输入:{user_input}\n")
    
    # 3. 第一次调用 API,获取工具调用指令
    # 注意:混元模型可能需要明确的 tool_choice="auto" 来触发
    response = get_completion_with_tools(
        messages=messages,
        tools=[calculator_tool],
        tool_choice="auto"
    )
    
    response_message = response.choices[0].message
    messages.append(response_message)
    
    # 4. 判断是否需要调用工具
    # 新版 API 返回的是 tool_calls 列表,而不是单一的 function_call
    if hasattr(response_message, 'tool_calls') and response_message.tool_calls:
        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.function.arguments)
            
            print(f"模型决定调用函数:{function_name}")
            print(f"函数参数:{function_args}")
            
            # 执行函数
            function_result = execute_function_call(function_name, function_args)
            print(f"函数执行结果:{function_result}")
            
            # 将结果返回给模型
            # 注意:tool_call_id 必须与请求中的 id 一致,以便模型对应
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "name": function_name,
                "content": str(function_result)
            })
        
        # 5. 再次调用 API,让模型根据工具返回结果生成自然语言回复
        # 此时不再需要传递 tools,或者传递但不设置 tool_choice,让模型直接回答
        final_response = get_completion_with_tools(
            messages=messages,
            tools=[calculator_tool], 
            tool_choice="none" # 强制模型不再调用工具,直接生成回复
        )
        
        print("\n===== 最终回复 =====")
        print(final_response.choices[0].message.content)
        
    else:
        # 不需要调用工具,直接输出响应
        print("\n===== 模型直接回复 =====")
        print(response_message.content)

if __name__ == "__main__":
    main()

代码说明:

  • 模型选择:
    • 代码中使用了 hunyuan-turbo。hunyuan-lite 主要是轻量级模型,可能对 Function Call 支持不完善或不支持。如果遇到报错,请尝试切换到 hunyuan-pro 或确认您的账号是否开通了 hunyuan-functioncall 模型的使用权限。
  • 参数名称变化:
    • OpenAI 旧接口/部分兼容functions, function_call, 返回 message.function_call。
    • OpenAI 新接口/混元推荐:tools, tool_choice, 返回 message.tool_calls。
  • Role 的变化:
    • 在返回工具执行结果时,新版规范要求 role 为 "tool" ,而不是 "function",并且必须携带 tool_call_id 字段,该 ID 来自模型第一次请求返回的 tool_call.id。这对于多工具并行调用尤其重要。

输出结果:

用户输入:帮我计算一下 3.14 乘以 50 的结果,再算一下 100 的平方根

模型决定调用函数:calculator

函数参数:{'num1': 3.14, 'num2': 50, 'operation': 'mul'}

函数执行结果:157.0

模型决定调用函数:calculator

函数参数:{'num1': 100, 'operation': 'sqrt'}

函数执行结果:10.0

===== 最终回复 =====

3.14 乘以 50 的结果是 157.0,100 的平方根是 10。

五、对大模型的意义

1. 突破大模型的能力边界

大模型的原生能力受限于训练数据和模型架构:

  • 训练数据是静态的,无法获取实时信息,如最新的股票价格、最新天气;
  • 模型架构是基于语言建模的,不擅长精确计算、逻辑推理、外部系统交互。

Skill+Function Call 让大模型具备了"实时数据访问"、"精确计算"、"外部系统操作"的能力,比如:

  • 调用股票 API 获取实时股价,让大模型能做股票分析;
  • 调用企业 ERP API 查询库存,让大模型能做库存管理建议;
  • 调用代码执行引擎,让大模型能生成并执行代码解决复杂问题。

2. 提升大模型的准确性和可靠性

大模型在处理数字、逻辑、专业数据时容易出现幻觉,生成错误信息,比如:

  • 计算"123456×789012"时,大模型可能生成错误结果;
  • 回答"2024 年杭州GDP"时,可能生成过时或错误的数据。

而通过 Skill+Function Call 调用专业工具:

  • 计算类问题调用计算器函数,准确率 100%;
  • 数据类问题调用权威 API,确保数据实时且准确;
  • 逻辑类问题调用代码执行引擎,确保推理过程正确。

3. 增强大模型的可控性和安全性

直接让大模型生成代码、执行操作存在安全风险,比如生成恶意代码、调用未授权API,而 Skill+Function Call 通过以下方式提升可控性:

  • 白名单机制:只允许调用预定义的 Skill,禁止调用未授权的函数;
  • 参数校验:严格校验函数参数的类型、范围,防止注入攻击;
  • 权限控制:为不同 Skill 分配不同权限,比如普通用户只能调用天气 Skill,管理员才能调用数据库 Skill;
  • 审计日志:记录所有 Function Call 的执行记录,便于追溯和排查问题。

4. 推动大模型从对话工具向智能体进化

智能体(Agent)是具备"感知→决策→执行→反馈"能力的智能系统,而 Skill+Function Call 是大模型成为智能体的核心基础:

  • 感知:通过自然语言理解获取用户需求;
  • 决策:通过意图识别选择需要调用的 Skill;
  • 执行:通过 Function Call 执行具体操作;
  • 反馈:将执行结果转换为自然语言返回给用户。

比如一个"智能出行助手"智能体:

    1. 感知:用户说"明天去上海出差,帮我规划行程";
    1. 决策:需要调用"天气 Skill"(查上海明天天气)、"机票 Skill"(查北京到上海机票)、"酒店 Skill"(查上海酒店)、"路线 Skill"(查机场到酒店路线);
    1. 执行:依次调用上述 Skill,获取各部分数据;
    1. 反馈:整合所有数据,生成完整的出行规划。

六、总结

总的来说,Skill 和 Function Call,一个是能做什么,一个是怎么去做,两者绑定在一起,才能真正让大模型突破自身局限,从只会聊天变成能干活的工具。

Function Call 就是一套调用机制,就是大模型识别到有具体任务(比如算个账、查天气),就按规矩生成指令,让外部程序去执行。而 Skill 呢,就是被调用的那个本事,是咱们提前定义好的、标准化的功能模块,比如计算器 Skill、天气 Skill,里面写清楚了能做啥、要啥参数、怎么返回结果。

以前我们聊 Function Call,很少提 Skill,是那时候场景太简单,就调用一两个函数,直接叫函数、工具就够了。但现在不一样了,大模型要做复杂任务,要管理十几个、几十个功能,还得组合使用,这时候就必须把这些功能标准化、模块化,这就是 Skill 的作用。

简单说,两者结合起来,大模型才能精准干活、高效执行,这也是咱们现在做大模型应用、搞智能体,必须吃透的核心逻辑。

相关推荐
启效云12 小时前
AI赋能制造丨启效云亮相2026工业母机产业链高质量发展大会
大数据·人工智能·制造
TK泰妞12 小时前
如何利用跨境女装提示词库提升销售效率?从商品图片到TikTok内容的完整方法
大数据·人工智能
鲜于言悠90512 小时前
opencode
人工智能
猛犸象限12 小时前
【CJMP Grok Bot实践】用 CJMP 搬游戏时碰到的三个缺口,和我们的绕法
人工智能·grok
用户abcde12 小时前
RAG 检索增强生成
人工智能
文谦南宁AI普工12 小时前
RAG 检索全对,回答全错?用位置扫描 10 分钟定位 Lost in the Middle
人工智能·aigc
alonglong12 小时前
183 行 llmctl:把 4 个启动脚本收成一个 CLI,总控该管什么、不该管什么
人工智能
野生码农AI实战12 小时前
一句追问查出停滞 50 天的口径烂账,我把团队规则的锚换到了数字团队花名册
人工智能
宇擎智脑科技12 小时前
Sirchmunk 深度解析(一):一个无需向量数据库的自进化搜索引擎架构设计
人工智能·rag·sirchmunk
小魚88412 小时前
豆包工作的核心能力有哪些
人工智能