Function Call 函数调用高阶方法:从零开始,深入理解 AI 函数调用的核心原理与实战技巧

Function Call 函数调用高阶方法


为什么需要"进阶"技巧?

基础的 Function Call 很简单,但在实际应用中会遇到很多挑战:

  • 意图识别难:如何让 AI 准确选择正确的函数?
  • 函数太多:当有 100+ 个函数时,如何管理?
  • 性能问题:如何提高响应速度?
  • 并发处理:如何同时处理多个任务?
c 复制代码
挑战1 - 意图识别问题
    ├─ 问题分析
    ├─ 优化 JSON Schema 的 4 大技巧
    └─ 干预模型选择的方法
    ↓
挑战2 - 海量函数调用
    ├─ 函数分层策略
    ├─ 粗略对齐 + 精准对齐
    └─ 向量数据库 + RAG 方案
    ↓
挑战3 - 函数并发调用
    ├─ 串行调用实战
    └─ 并行调用实战(3种方法)
    ↓
挑战4 - 响应优化
    ├─ 缓存方案
    └─ 流式响应
    ↓
综合实战与最佳实践
    ├─ 完整项目:智能数学计算器
    ├─ 最佳实践总结
    └─ 常见陷阱与调试技巧

✅ 理解 Function Call 的完整工作原理

✅ 编写高质量的函数描述(JSON Schema)

✅ 解决 AI 函数选择错误的问题

✅ 管理 50+ 甚至 100+ 个函数

✅ 实现高性能的并发调用

✅ 独立开发完整的 Function Call 应用

JSON Schema - 函数的"说明书"

JSON Schema 是一种标准格式,用于描述函数的功能和参数。

类比一下:

  • Python 函数:AI 看不懂
  • JSON Schema:用 AI 能理解的语言描述函数

为什么需要?

AI 模型无法直接读取和理解 Python 代码。我们需要用一种"AI 友好"的格式告诉它:

  • 这个函数叫什么名字?
  • 这个函数是做什么的?
  • 这个函数需要什么参数?
  • 哪些参数是必需的?

如何编写?

标准的 JSON Schema 格式:

json 复制代码
{
  "type": "function",              # 固定写法:表示这是一个函数
  "function": {
    "name": "函数名",               # 函数的名称
    "description": "函数功能描述",   # 详细描述函数的作用
    "parameters": {
      "type": "object",            # 固定写法:参数是一个对象
      "properties": {              # 参数的具体定义
        "参数1": {
          "type": "string",        # 参数类型(string/number/boolean等)
          "description": "参数1的说明"
        },
        "参数2": {
          "type": "number",
          "description": "参数2的说明"
        }
      },
      "required": ["参数1"]        # 必需参数列表
    }
  }
}
实战示例 1:简单的加法函数

Python 函数:

python 复制代码
def add(a, b):
    """计算两个数的和"""
    return a + b

对应的 JSON Schema:

json 复制代码
{
  "type": "function",
  "function": {
    "name": "add",
    "description": "计算两个数的和",
    "parameters": {
      "type": "object",
      "properties": {
        "a": {
          "type": "number",
          "description": "第一个加数"
        },
        "b": {
          "type": "number",
          "description": "第二个加数"
        }
      },
      "required": ["a", "b"]
    }
  }
}

💡 重点总结

  • JSON Schema 是 AI 理解函数的"翻译器"
  • description 字段非常重要,要写清楚!
  • required 数组指定哪些参数是必需的
Tools - AI 的"技能库"

Tools 是一个包含所有可调用函数描述的列表(数组)

简单理解:

  • 单个 JSON Schema = 一个工具的说明书
  • Tools = 整个工具箱(包含多个工具的说明书)

告诉 AI:"你有哪些工具可以用"。

假设我们有两个函数:add(加法)和 multiply(乘法)

python 复制代码
# 这是一个 Tools 列表,包含两个函数的描述
tools = [
    {
        # 第一个工具:加法函数
        "type": "function",
        "function": {
            "name": "add",
            "description": "计算两个数的和",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {"type": "number", "description": "第一个加数"},
                    "b": {"type": "number", "description": "第二个加数"}
                },
                "required": ["a", "b"]
            }
        }
    },
    {
        # 第二个工具:乘法函数
        "type": "function",
        "function": {
            "name": "multiply",
            "description": "计算两个数的乘积",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {"type": "number", "description": "第一个乘数"},
                    "b": {"type": "number", "description": "第二个乘数"}
                },
                "required": ["a", "b"]
            }
        }
    }
]

当我们调用 AI 时,需要把这个 tools 列表传递给它:

python 复制代码
response = client.chat.completions.create(
    model="glm-4",
    messages=messages,
    tools=tools,        # ← 在这里传递工具列表
    tool_choice="auto"
)

AI 会根据用户的问题,从 tools 列表中选择合适的函数。


Tool Choice - "使用工具的策略"

Tool Choice 参数用于控制 AI 如何选择和使用工具。

四种模式
模式 含义 使用场景
"auto" AI 自动判断是否需要调用函数 最常用,让 AI 自主决定
"required" 强制 AI 必须调用某个函数 确定需要执行函数时
"none" 禁止 AI 调用任何函数 只想要对话,不想执行操作
"function_name" 指定调用某个特定函数 明确知道要用哪个函数
示例对比

示例 1:auto 模式

python 复制代码
response = client.chat.completions.create(
    model="glm-4",
    messages=[{"role": "user", "content": "1 + 1 等于几?"}],
    tools=tools,
    tool_choice="auto"  # AI 自动判断是否需要调用函数
)
# AI 可能会调用 add(1, 1),也可能直接回答 "2"

示例 2:required 模式

python 复制代码
response = client.chat.completions.create(
    model="glm-4",
    messages=[{"role": "user", "content": "1 + 1 等于几?"}],
    tools=tools,
    tool_choice="required"  # 强制 AI 必须调用函数
)
# AI 一定会调用 add(1, 1),不会直接回答

示例 3:指定函数名

python 复制代码
response = client.chat.completions.create(
    model="glm-4",
    messages=[{"role": "user", "content": "计算一下"}],
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "add"}}
)
# 强制 AI 调用 add 函数(即使用户问题不明确)

💡 推荐做法

  • 大多数情况下使用 "auto",让 AI 智能选择
  • 只在非常明确的场景下使用 "required" 或指定函数名

一、意图识别:当你有多个相似的函数时,AI 如何准确选择?

c 复制代码
解决方案
├── 1. 优化 JSON Schema(治本)
│   ├── 技巧1:使用关键词(最重要)
│   ├── 技巧2:使用分类标记
│   ├── 技巧3:增加权重提示
│   └── 技巧4:使用否定句
└── 2. 干预模型选择(治标)
    ├── 方法1:自查 Prompts
    └── 方法2:关键词匹配(最可靠)
  1. 设计函数时

    • 使用清晰、独特的函数名
    • 添加分类前缀(如 user_, admin_
    • 写详细的文档字符串
  2. 编写 JSON Schema 时

    • 包含丰富的使用场景说明
    • 明确排除场景(告诉 AI 何时不用)
    • 添加权重提示词
  3. 核心业务功能

    • 使用关键词匹配确保准确性
    • 不要完全依赖 AI 的判断
    • 代码控制 > AI 理解

工具函数

  • auto_functions:自动生成 JSON Schema
  • 基于 inspect 模块实现
  • 适合简单场景,复杂需求需手动调整
首先,我们需要一个自动生成 JSON Schema 的工具函数

在实际开发中,手写 JSON Schema 太麻烦了。我们可以使用一个工具函数自动生成:

python 复制代码
import inspect  # Python 内置库,用于检查活动对象(函数、类等)
import json
from typing import List, Callable

def auto_functions(func_list: List[Callable]) -> List[dict]:
    """
    自动生成函数的 JSON Schema 描述

    参数:
        func_list: Python 函数列表

    返回:
        JSON Schema 格式的工具描述列表
    """
    # 步骤1:创建空列表,用于存储所有函数的描述
    tools_description = []

    # 步骤2:遍历每个函数
    for func in func_list:
        # ===== 步骤2.1:获取函数的签名信息 =====
        # inspect.signature() 可以获取函数的详细信息
        # 包括:参数名、参数类型、默认值等
        sig = inspect.signature(func)
        func_params = sig.parameters  # 获取所有参数

        # ===== 步骤2.2:初始化参数描述结构 =====
        parameters = {
            'type': 'object',     # JSON Schema 固定格式
            'properties': {},     # 存储每个参数的详细信息
            'required': []        # 存储必需参数的名称
        }

        # ===== 步骤2.3:遍历函数的每个参数 =====
        for param_name, param in func_params.items():
            # 添加参数描述
            parameters['properties'][param_name] = {
                # 参数的说明文字
                # 如果参数有类型注解且注解有文档,使用文档;否则为空
                'description': (
                    param.annotation.__doc__
                    if param.annotation is not inspect._empty
                    else ""
                ),
                # 参数的类型
                # 如果有类型注解,转换为字符串;否则标记为 'Any'
                'type': (
                    str(param.annotation)
                    if param.annotation != param.empty
                    else 'Any'
                )
            }

            # 判断参数是否必需
            # 如果参数没有默认值,说明它是必需的
            if param.default == param.empty:
                parameters['required'].append(param_name)

        # ===== 步骤2.4:构建单个函数的完整描述 =====
        func_dict = {
            "type": "function",  # 固定值:表示这是一个函数
            "function": {
                "name": func.__name__,                 # 函数名
                "description": func.__doc__.strip(),   # 函数的文档字符串
                "parameters": parameters               # 参数描述
            }
        }

        # 步骤3:添加到结果列表
        tools_description.append(func_dict)

    # 步骤4:返回所有函数的描述
    return tools_description

为什么需要这个函数?

  • 自动化:避免手动编写重复的 JSON Schema
  • 减少错误:自动提取函数信息,避免手写错误
  • 易于维护:修改 Python 函数后,自动更新 Schema
auto_functions 的局限性

局限1:依赖文档字符串

  • 如果函数没有写文档字符串,description 会是空的
  • 解决方案:养成写文档字符串的习惯

局限2:类型注解的处理

  • 复杂类型(如 List[str])会被转成字符串形式
  • 可能不符合 JSON Schema 的标准
  • 解决方案:为复杂类型手动编写 Schema

局限3:无法处理特殊需求

  • 例如:参数之间的依赖关系、条件约束等
  • 解决方案:在生成后手动修改 Schema

问题本质

AI 进行函数选择时,主要依据:

  1. 函数名的相似度machine_learning_1machine_learning_2 非常相似
  2. 描述的语义相似度:"机器学习"和"深度学习"在语义上高度相关
  3. 关键词匹配:用户问题中的关键词与函数描述的匹配程度

当两个函数的名称和描述都很相似时,AI 很容易"选错"。

现实场景中的影响

在实际应用中,这种错误可能导致:

  • 银行系统:用户要"开信用卡",AI 却调用了"开储蓄卡"函数
  • 客服系统:用户要"退款",AI 却调用了"退货"函数
  • 订单系统:用户要"取消订单",AI 却调用了"修改订单"函数

后果可能很严重!

技巧一:优化 JSON Schema

第一种解决方案是:提升 JSON Schema 的质量,让 AI 更容易区分不同的函数。

记住这个核心原则:高质量的 JSON Schema = 清晰的函数命名 + 详细的描述 + 独特的标识

让每个函数名包含独特的、不易混淆的关键词

技巧1:使用关键词(最重要!)

💡 最佳实践

  • 为重要业务功能设计独特的触发词
  • 在函数名和描述中都包含这些触发词
  • 让触发词简短、易记、不易混淆

不好的命名

python 复制代码
def machine_learning_1():
    """解释机器学习是什么"""
    pass

def machine_learning_2():
    """描述机器学习和深度学习的区别"""
    pass

问题:

  • 函数名几乎一样,只有数字不同
  • AI 无法从函数名判断功能差异

好的命名

python 复制代码
def explain_machine_learning():
    """解释机器学习是什么"""
    pass

def compare_ml_and_dl():
    """对比机器学习和深度学习的区别"""
    pass

优势:

  • 函数名直接表达功能:explain(解释)vs compare(对比)
  • 包含核心关键词:machine_learning vs ml_and_dl
  • 一眼就能看出区别

技巧2:使用分类标记

使用前缀或后缀对函数进行分类,让 AI 一眼就能看出函数所属的类别。

分类方式

  • 用户功能:user_xxx
  • 管理员功能:admin_xxx
  • 数据功能:data_xxx

效果

  • 当用户说"我要注册"时,AI 会优先考虑 user_ 开头的函数
  • 当管理员说"查看日志"时,AI 会优先考虑 admin_ 开头的函数
  • 分类清晰,减少混淆

技巧3:增加权重提示

在函数描述中添加重要性标记,帮助 AI 判断优先级。

示例
python 复制代码
def create_order():
    """
    【核心功能】【经常使用】【优先考虑】
    创建新订单

    这是系统最常用的功能之一,用户下单时必须使用。
    请在用户提到"购买"、"下单"、"买东西"等关键词时调用此函数。
    """
    pass

def cancel_order():
    """
    【次要功能】
    取消已创建的订单

    用于用户主动取消订单的场景。
    只有当用户明确提到"取消订单"时才调用。
    """
    pass

权重提示词

  • 【核心功能】:最重要的功能
  • 【经常使用】:使用频率高
  • 【优先考虑】:有歧义时优先选择
  • 【次要功能】:不常用的功能

效果

  • AI 会更倾向于选择标记为"核心"、"优先"的函数
  • 减少误选不常用功能的概率

技巧4:使用否定句

明确告诉 AI 什么时候不该用这个函数

示例
python 复制代码
def explain_machine_learning():
    """
    解释机器学习的基本概念

    用途:当用户询问"什么是机器学习"、"机器学习的定义"时使用

    ⚠️ 注意:当用户询问深度学习时,请勿使用此函数!
    深度学习相关问题请使用 compare_ml_and_dl 函数。
    """
    pass

def compare_ml_and_dl():
    """
    对比机器学习和深度学习的区别

    用途:当用户询问"深度学习是什么"、"机器学习和深度学习的区别"时使用

    ⚠️ 注意:仅当问题涉及"深度学习"时使用此函数!
    """
    pass

关键点

  • 明确排除场景:告诉 AI 哪些情况不要用
  • 提供替代建议:告诉 AI 应该用哪个函数

技巧 5:组合

让我们把所有技巧结合起来,重新设计之前的两个函数:

python 复制代码
def ML_Basic_Explain():
    """
    【机器学习-基础概念】解释机器学习是什么

    功能:介绍机器学习的基本定义和核心原理

    使用场景:
    - 用户询问"什么是机器学习"
    - 用户询问"机器学习的定义"
    - 用户询问"ML是什么"(ML是机器学习的缩写)

    ⚠️ 重要提示:
    - 不要在涉及深度学习的问题中使用此函数
    - 深度学习相关问题请使用 DL_Compare_With_ML 函数
    """
    answer = """机器学习是人工智能的一个分支,研究计算机如何自动从数据中学习,
    提升性能并做出预测。它通过算法让计算机提炼知识,优化任务执行,而无需明确编程。"""
    return answer

def DL_Compare_With_ML():
    """
    【深度学习-对比分析】对比机器学习和深度学习

    功能:详细说明深度学习的特点,以及它与机器学习的区别

    使用场景:
    - 用户询问"什么是深度学习"
    - 用户询问"深度学习和机器学习的区别"
    - 用户询问"DL是什么"(DL是深度学习的缩写)

    ⚠️ 重要提示:
    - 只要问题涉及深度学习(Deep Learning),就使用此函数
    - 即使只问"深度学习是什么",也应该用这个函数
    """
    answer = """机器学习涉及算法从数据中学习模式以做出预测或决策。
    深度学习是机器学习的一个子集,专注于使用深层神经网络,
    来处理复杂的数据结构,实现高级功能如图像识别和自然语言理解。"""
    return answer

改进总结

  1. ✅ 使用分类前缀:ML_ vs DL_
  2. ✅ 函数名清晰:Explain vs Compare
  3. ✅ 详细的使用场景说明
  4. ✅ 明确的排除提示

解决方案2:干预模型选择

有时候,即使优化了 JSON Schema,AI 仍然可能选错。这时我们需要在代码层面干预 AI 的选择过程。

方法1:自查 Prompts

原理

在真正调用函数之前,先问 AI 一个问题:"这个问题你能不能回答?"

  • 如果 AI 说"能",就直接让它回答,不调用函数
  • 如果 AI 说"不能",再调用函数

这样可以避免 AI 错误地调用函数。

python 复制代码
def function_call_with_check(prompt, tools):
    """
    在调用函数前,先让 AI 自查是否需要外部工具

    参数:
        prompt: 用户问题
        tools: 可用的工具列表
    """
    # 第一步:询问 AI 是否能从知识库回答
    judge_prompt = prompt + "\n\n这个问题的答案是否在你的语料库里?\
        请回答'这个问题答案在我的语料库里'或者'这个问题的答案不在我的语料库里',\
        不要回答其他额外的文字"

    # 构建消息
    message = [
        {"role": "user", "content": judge_prompt}
    ]

    # 调用 AI 进行自查
    response_check = client.chat.completions.create(
        model="glm-4",
        messages=message
    )

    # 获取 AI 的回答
    check_result = response_check.choices[0].message.content

    # 第二步:根据自查结果决定是否调用函数
    if "这个问题答案在我的语料库里" in check_result:
        # AI 认为可以直接回答,不调用函数
        message = [{"role": "user", "content": prompt}]
        response = client.chat.completions.create(
            model="glm-4",
            messages=message
        )
        print(response.choices[0].message.content)
    else:
        # AI 认为需要外部工具,调用函数
        message = [{"role": "user", "content": prompt}]
        response = client.chat.completions.create(
            model="glm-4",
            messages=message,
            tools=tools,
            tool_choice="auto"
        )
        print(response.choices[0].message.tool_calls[0].function.name)

优势

  • 减少不必要的函数调用
  • 避免 AI 在可以直接回答时仍然调用函数
  • 提高响应速度(直接回答比调用函数快)

注意事项

⚠️ AI 可能会"说谎"!有时候 AI 会认为自己知道答案,但实际上答案是错的。所以这个方法要谨慎使用。

方法2:关键词匹配(最可靠!)

依赖编程逻辑,而不是依赖 AI 的理解。

在用户提问时,先用代码进行关键词匹配,直接指定调用哪个函数,而不让 AI 选择。

实现代码
python 复制代码
def function_call_with_keywords(prompt, tools, keyword_mapping):
    """
    使用关键词匹配来选择函数

    参数:
        prompt: 用户问题
        tools: 可用的工具列表
        keyword_mapping: 关键词到函数名的映射
    """
    # 遍历关键词映射
    selected_function = None
    for keywords, function_name in keyword_mapping.items():
        # 检查用户问题中是否包含关键词
        if any(keyword in prompt for keyword in keywords):
            selected_function = function_name
            break

    # 构建消息
    message = [{"role": "user", "content": prompt}]

    if selected_function:
        # 找到匹配的函数,强制调用
        response = client.chat.completions.create(
            model="glm-4",
            messages=message,
            tools=tools,
            tool_choice={"type": "function", "function": {"name": selected_function}}
        )
    else:
        # 没有匹配的函数,让 AI 自动选择
        response = client.chat.completions.create(
            model="glm-4",
            messages=message,
            tools=tools,
            tool_choice="auto"
        )

    return response
使用示例:餐厅点餐系统
python 复制代码
# 定义关键词映射
keyword_mapping = {
    ("点餐", "下单", "要吃", "我要"): "create_order",
    ("取消", "不要了", "退单"): "cancel_order",
    ("查询", "看看", "订单状态"): "query_order",
}

# 测试
prompt1 = "我要点餐"
response1 = function_call_with_keywords(prompt1, tools, keyword_mapping)
# 直接调用 create_order 函数

prompt2 = "帮我取消订单"
response2 = function_call_with_keywords(prompt2, tools, keyword_mapping)
# 直接调用 cancel_order 函数

优势

  • ✅ 最可靠:100% 准确,不依赖 AI 的理解
  • ✅ 可控性强:完全由代码控制
  • ✅ 响应快:不需要 AI 思考选择

劣势

  • ❌ 需要维护关键词库
  • ❌ 无法处理复杂的自然语言
  • ❌ 关键词可能冲突

💡 最佳实践

  • 核心业务功能设置关键词匹配
  • 容易混淆的功能设置关键词匹配
  • 将关键词匹配作为第一道防线 ,让 AI 选择作为兜底方案

二、海量函数调用

我们解决了意图识别的问题。但那只是在函数数量较少(2-10个)的情况下。

当你的应用规模扩大,函数数量达到 50+、100+ 甚至更多时,新的问题就出现了。

函数数量 AI 选择准确率 平均响应时间
5个以内 ~95% 1-2秒
10-20个 ~85% 2-3秒
30-50个 ~70% 3-5秒
50-100个 ~50% 5-8秒
100个以上 ~30% 8秒以上

问题分析

  1. Token 限制

    • AI 一次能处理的文本量有限
    • 100个函数的 JSON Schema 可能超过 token 上限
    • 即使没超过,也会占用大量 token,影响性能
  2. 语义相似度混淆

    • 函数越多,相似的函数越多
    • AI 更容易混淆
    • 例如:query_user_by_id vs query_user_by_name vs query_user_by_email
  3. 计算性能下降

    • AI 需要在海量函数中进行语义匹配
    • 计算复杂度呈指数级增长
    • 响应速度明显变慢
c 复制代码
解决方案
├── 函数数量 < 50
│   └── 直接使用 Function Call(第1章方法)
├── 函数数量 50-200
│   └── 分层对齐策略
│       ├── 按业务模块分组
│       ├── 按关键词分组
│       └── 粗略对齐 + 精准对齐
└── 函数数量 > 200
    └── RAG + 向量数据库
        ├── 离线:函数描述向量化
        ├── 在线:检索相关函数
        └── 小范围内精准匹配

核心技巧

  1. 分而治之:把大问题分解成小问题
  2. 两步对齐:先确定类别,再精准选择
  3. 关键词优先:能用关键词就不用 AI
  4. 优雅降级:无法处理时给出合理回复

案例1:电商平台

c 复制代码
用户模块:注册、登录、修改资料、找回密码... (10+ 个函数)
商品模块:搜索、详情、评价、收藏... (15+ 个函数)
订单模块:创建、支付、取消、退款、查询... (20+ 个函数)
购物车模块:添加、删除、修改数量... (10+ 个函数)
物流模块:查询物流、地址管理... (10+ 个函数)
客服模块:提交工单、查看回复... (10+ 个函数)
数据分析:销售报表、用户行为分析... (15+ 个函数)
--------------------------------
总计:90+ 个函数

当函数数量超过一定规模时:

  • ❌ 不能把所有函数一股脑塞给 AI
  • ❌ 不能期望 AI 在海量函数中准确选择
  • ✅ 必须主动管理和组织这些函数
  • ✅ 必须分步骤、分层次让 AI 选择

核心思想:化整为零,分而治之

就像图书馆用分类系统管理图书一样:

c 复制代码
图书馆
├── 文学区
│   ├── 中国文学
│   ├── 外国文学
│   └── 诗歌散文
├── 科技区
│   ├── 计算机
│   ├── 物理
│   └── 生物
└── 历史区
    ├── 中国历史
    └── 世界历史

我们也要把函数进行分层管理

c 复制代码
用户提问
    ↓
第一步:粗略对齐(确定大类)
    ↓
选择一个小的函数组(10-20个)
    ↓
第二步:精准对齐(在小范围内选择)
    ↓
执行函数
    ↓
返回结果

第一步:分类(按业务模块分层)

按业务模块分层

按业务模块分层,55个函数 → 分成4组,每组10-15个

python 复制代码
# ========== 基础数学运算 ==========
def Basic_add(a, b):
    """【基础数学】计算两个数的和"""
    return a + b

def Basic_subtract(a, b):
    """【基础数学】计算两个数的差"""
    return a - b

def Basic_multiply(a, b):
    """【基础数学】计算两个数的积"""
    return a * b

def Basic_divide(a, b):
    """【基础数学】计算两个数的商"""
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b

def Basic_power(a, b):
    """【基础数学】计算 a 的 b 次方"""
    return a ** b

# ... 更多基础数学函数(共约15个)

# ========== 三角函数运算 ==========
def Tri_func_sin(a):
    """【三角函数】计算正弦值"""
    import math
    return math.sin(a)

def Tri_func_cos(a):
    """【三角函数】计算余弦值"""
    import math
    return math.cos(a)

def Tri_func_tan(a):
    """【三角函数】计算正切值"""
    import math
    return math.tan(a)

# ... 更多三角函数(共约10个)

# ========== 概率统计 ==========
def Prob_comb(n, k):
    """【概率论】计算组合数 C(n, k)"""
    import math
    return math.comb(n, k)

def Prob_perm(n, k):
    """【概率论】计算排列数 P(n, k)"""
    import math
    return math.perm(n, k)

# ... 更多概率统计函数(共约15个)

# ========== 高等数学 ==========
def Advanced_Math_derivative(func, a, h=1e-5):
    """【高等数学】计算函数在某点的导数"""
    return (func(a + h) - func(a - h)) / (2 * h)

def Advanced_Math_integral(func, a, b, n=1000):
    """【高等数学】计算定积分"""
    width = (b - a) / n
    total = 0.5 * (func(a) + func(b))
    for i in range(1, n):
        total += func(a + i * width)
    return total * width

# ... 更多高等数学函数(共约15个)

分组结果

  • 基础数学:15个函数
  • 三角函数:10个函数
  • 概率统计:15个函数
  • 高等数学:15个函数
python 复制代码
# 第一步:按模块分组函数
# 这里我们使用原教程中的数学函数作为示例

# 基础数学函数列表(索引0-16,每个名字都是有一个数学函数的实现)
basic_math_functions = [
    Basic_add, Basic_subtract, Basic_divide, Basic_multiply,
    Basic_power, Basic_sqrt, Basic_mod, Basic_abs_val,
    Basic_factorial, Basic_gcd, Basic_lcm, Basic_exp,
    Basic_log, Basic_log10, Basic_round_val,
    Basic_level_ceil, Basic_level_floor
]

# 三角函数列表(索引17-27)
trig_functions = [
    Tri_func_sin_val, Tri_func_cos_val, Tri_func_tan_val,
    Tri_func_asin_val, Tri_func_acos_val, Tri_func_atan_val,
    Tri_func_sinh_val, Tri_func_cosh_val, Tri_func_tanh_val,
    Tri_func_degrees, Tri_func_radians
]

# 概率统计函数列表(索引28-44)
prob_functions = [
    Prob_comb, Prob_perm, Prob_factorial_prob,
    Prob_binom_pmf, Prob_binom_cdf,
    Prob_poisson_pmf, Prob_poisson_cdf,
    Prob_uniform_pdf, Prob_uniform_cdf,
    Prob_normal_pdf, Prob_normal_cdf,
    Prob_expon_pdf, Prob_expon_cdf,
    Prob_geom_pmf, Prob_geom_cdf,
    Prob_beta_pdf, Prob_beta_cdf
]

# 高等数学函数列表(索引45+)
advanced_math_functions = [
    Advanced_Math_Derivative, Advanced_Math_integral,
    Advanced_Math_double_integral, Advanced_Math_partial_derivative,
    Advanced_Math_gradient, Advanced_Math_laplacian,
    Advanced_Math_divergence, Advanced_Math_curl,
    Advanced_Math_jacobian, Advanced_Math_hessian,
    Advanced_Math_taylor_series, Advanced_Math_fourier_series,
    Advanced_Math_laplace_transform, Advanced_Math_fourier_transform
]

# 第二步:为每个分组生成 JSON Schema
# 使用我们之前的 auto_functions 工具函数

# 生成各组的 tools
basic_math_tools = auto_functions(basic_math_functions)       # 基础数学工具
trig_tools = auto_functions(trig_functions)                   # 三角函数工具
prob_tools = auto_functions(prob_functions)                   # 概率统计工具
advanced_math_tools = auto_functions(advanced_math_functions) # 高等数学工具

# 第三步:创建函数类型映射字典
# 这个字典用于快速获取对应类型的工具列表
function_type_mapping = {
    "基础数学": basic_math_tools,
    "三角函数": trig_tools,
    "概率论": prob_tools,
    "高等数学": advanced_math_tools,
    "其他": auto_functions(basic_math_functions + trig_functions +
                          prob_functions + advanced_math_functions)  # 兜底方案
}

# 第四步:创建函数名到函数体的映射
# 将所有函数合并到一个字典中,方便执行
all_functions = (basic_math_functions + trig_functions +
                 prob_functions + advanced_math_functions)
available_math_functions = {func.__name__: func for func in all_functions}

为什么这么设计?

  • 分组清晰:每个分组有明确的功能边界
  • 易于扩展:添加新函数只需加入对应分组
  • 性能优化:每次只给 AI 10-15个函数,而不是55个

第二步:粗略对齐 + 精准对齐

现在我们有了分组,接下来实现两步对齐策略。

c 复制代码
用户问题:"计算 1314520 除以 520 等于几?"
    ↓
粗略对齐:判断问题属于哪个类别
    → AI 分析:"这是基础的除法运算"
    → 选择:基础数学工具组(15个函数)
    ↓
精准对齐:在小范围内选择具体函数
    → AI 从15个基础数学函数中选择
    → 选中:Basic_divide 函数
    ↓
执行函数并返回结果
python 复制代码
def math_calculate(prompt, function_type_mapping, available_functions):
    """
    智能数学计算函数:使用分层对齐策略

    参数:
        prompt: 用户的问题
        function_type_mapping: 函数类型到工具列表的映射
        available_functions: 函数名到函数体的映射

    返回:
        计算结果
    """

    # ===== 第一步:粗略对齐(确定函数类别) =====

    # 构建判断问题类别的提示词
    judge_prompt = prompt + "\n\n请问上述问题最接近哪一类数学问题?\
    请回应:基础数学、或三角函数、或概率论、或高等数学、或其他。\
    不要回应别的任何文字。"

    # 构建消息
    message = [
        {"role": "user", "content": judge_prompt}
    ]

    # 调用 AI 进行意图识别(粗略对齐)
    response_first_align = client.chat.completions.create(
        model="glm-4",       # 使用的模型
        messages=message     # 传入消息
    )

    # 获取 AI 的判断结果
    func_type = response_first_align.choices[0].message.content

    print(f"初步意图识别结果: {func_type}\n")

    # ===== 第二步:根据类别选择对应的函数组 =====

    # 默认值:如果无法识别,使用"其他"(包含所有函数)
    current_function_tools = None

    # 使用关键词匹配确定使用哪个函数组
    if "基础数学" in func_type:
        current_function_tools = function_type_mapping["基础数学"]
    elif "三角函数" in func_type:
        current_function_tools = function_type_mapping["三角函数"]
    elif "概率论" in func_type:
        current_function_tools = function_type_mapping["概率论"]
    elif "高等数学" in func_type:
        current_function_tools = function_type_mapping["高等数学"]
    else:
        # 无法识别类别,使用所有函数(兜底)
        current_function_tools = function_type_mapping["其他"]

    # ===== 第三步:精准对齐(在小范围内选择具体函数) =====

    # 重新构建消息(带有提示信息)
    message = [
        {
            "role": "assistant",
            "content": "当你被问到数学问题时,尝试调用 Tools 来解决问题。"
        }
    ]
    message.append({"role": "user", "content": prompt})

    # 在选定的函数组中进行精准匹配
    response_second_align = client.chat.completions.create(
        model="glm-4",                       # 使用的模型
        messages=message,                    # 传入消息
        tools=current_function_tools,        # 传入筛选后的工具列表(关键!)
        tool_choice="auto"                   # 让 AI 自动选择
    )

    # ===== 第四步:执行函数 =====

    try:
        # 获取函数调用信息
        function_calls = response_second_align.choices[0].message.tool_calls[0]

        print(f"被调用的函数是: {function_calls.function.name}\n")

        # 根据函数名获取函数体
        function_to_call = available_functions[function_calls.function.name]

        # 解析函数参数(从 JSON 字符串转为字典)
        function_args = json.loads(function_calls.function.arguments)

        # 执行函数
        function_response = function_to_call(**function_args)

        # ===== 第五步:格式化返回结果 =====

        # 重新构建消息,包含函数执行结果
        message = []
        message.append({
            "role": "assistant",
            "content": f"你使用了 tools 工具,最终获得的答案是 {function_response}"
        })
        message.append({
            "role": "user",
            "content": prompt + " 请仅仅回答题目的答案(如果是数字,则只显示数字),不要包括其他描述"
        })

        # 第三次调用 AI,生成友好的回复
        response_final = client.chat.completions.create(
            model="glm-4",
            messages=message
        )

        # 返回最终结果
        print(response_final.choices[0].message.content)
        return response_final.choices[0].message.content

    except Exception as e:
        # 如果函数调用失败
        print(f"\n函数调用失败!错误信息: {str(e)}")
        print("请检查函数定义或重新设计解决方案")
        return None

代码详解要点

  1. 第一步:粗略对齐

    • 用 prompt 让 AI 判断问题类别
    • 关键:不提供 tools,只让 AI 做分类
    • 结果:得到 "基础数学"、"三角函数" 等类别
  2. 第二步:选择函数组

    • 根据类别从 function_type_mapping 获取对应工具组
    • 关键:缩小范围,从 55个函数 → 10-15个函数
  3. 第三步:精准对齐

    • 在小范围内让 AI 选择具体函数
    • 关键:只传入筛选后的 tools,不是全部
    • 准确率大幅提升!
  4. 异常处理

    • 使用 try-except 捕获错误
    • 给出明确的错误提示

分类方法2:按关键词分类

除了按业务模块分组,还可以使用关键词分组

关键词匹配逻辑

python 复制代码
def select_function_group_by_keyword(prompt):
    """
    根据关键词选择函数组

    参数:
        prompt: 用户问题

    返回:
        对应的函数组
    """
    # 定义关键词到函数组的映射
    keyword_to_group = {
        ("注册", "登录", "账户", "密码"): user_functions,
        ("订单", "下单", "支付", "退款"): order_functions,
        ("商品", "搜索", "购买", "评价"): product_functions,
        ("购物车", "加入", "清空"): cart_functions
    }

    # 遍历关键词映射
    for keywords, function_group in keyword_to_group.items():
        # 检查提示词中是否包含任何关键词
        if any(keyword in prompt for keyword in keywords):
            return function_group

    # 如果没有匹配,返回所有函数
    return user_functions + order_functions + product_functions + cart_functions

优势

  • 直接、快速
  • 不依赖 AI 判断
  • 适合关键词明确的业务场景

劣势

  • 需要维护关键词库
  • 无法处理复杂的自然语言
方法3 高级方案:向量数据库 + RAG

当函数数量超过 1000+ 时,即使分层对齐也可能力不从心。这时需要更高级的方案。

RAG(Retrieval-Augmented Generation) = 检索增强生成

通俗理解:

  1. 检索(Retrieval):先在数据库中搜索相关信息
  2. 增强(Augmented):用搜索到的信息增强输入
  3. 生成(Generation):AI 基于增强后的输入生成回复

向量数据库:存储文本的数字化表示(向量)的数据库。

想象你要整理一堆照片:

  • 传统方法:按日期、地点分类(手动标签)
  • 向量方法:计算机"看懂"照片内容,自动找相似的

文本也一样

  • 每段文本可以转换成一组数字(向量)
  • 意思相近的文本,向量也相近
  • 通过计算向量距离,找到最相关的内容
示例
c 复制代码
文本1:"我想买一台手机" → 向量:[0.2, 0.8, 0.3, ...]
文本2:"购买智能手机" → 向量:[0.25, 0.75, 0.35, ...]
文本3:"今天天气真好" → 向量:[-0.5, 0.1, 0.9, ...]

计算相似度:

  • 文本1 和 文本2:相似度很高(都在说买手机)
  • 文本1 和 文本3:相似度很低(话题不同)

RAG + 向量数据库的工作流程

c 复制代码
准备阶段(离线):
1. 把所有函数的描述转换成向量
2. 存储到向量数据库中

运行阶段(在线):
1. 用户提问:"我要计算导数"
2. 把问题也转换成向量
3. 在向量数据库中搜索最相似的函数描述
4. 返回 Top-K 个最相关的函数(例如 K=5)
5. 只把这 K 个函数给 AI 选择
6. AI 在小范围内准确选择

RAG 方案的优势

  1. 可扩展性强

    • 支持 10000+ 函数
    • 性能不会随函数数量显著下降
  2. 准确率高

    • 基于语义相似度匹配
    • 比关键词匹配更智能
  3. 自动化

    • 不需要手动分类
    • 添加新函数自动适配### 特殊问题处理

问题1:当没有合适的函数时

有时候,用户的问题可能超出了我们提供的函数范围。

python 复制代码
prompt = "请帮我写一首诗"
math_calculate(prompt, function_type_mapping, available_math_functions)

# 可能会出现:
# - AI 随意选择一个函数(错误)
# - 程序报错(不友好)
解决方案:增加"无法处理"选项
python 复制代码
def math_calculate_with_fallback(prompt, function_type_mapping, available_functions):
    """
    带降级处理的数学计算函数
    """
    # 第一步:先判断是否是数学问题
    check_prompt = prompt + "\n\n这是一个数学计算问题吗?请回答'是'或'否',不要回答其他内容。"

    message = [{"role": "user", "content": check_prompt}]

    response_check = client.chat.completions.create(
        model="glm-4",
        messages=message
    )

    # 如果不是数学问题,直接让 AI 回答,不调用函数
    if "否" in response_check.choices[0].message.content:
        print("检测到这不是数学问题,将直接回答:\n")

        message = [{"role": "user", "content": prompt}]
        response = client.chat.completions.create(
            model="glm-4",
            messages=message
        )

        print(response.choices[0].message.content)
        return response.choices[0].message.content

    # 如果是数学问题,继续正常的 Function Call 流程
    else:
        return math_calculate(prompt, function_type_mapping, available_functions)

优势

  • 优雅降级:无法处理时给出合理回复
  • 避免错误:不会强行调用不相关的函数
  • 用户体验好:无论什么问题都能得到回应

二、函数并发调用

当需要同时执行多个任务时,如何提高效率?串行 vs 并行的选择和实现!

注意事项

⚠️ 并发数不是越多越好!

  • 太多并发可能导致 API 限流
  • 建议控制在 5-10 个并发
  • 可以使用 asyncio.Semaphore 限制并发数

常见陷阱

  1. 过度并发:导致 API 限流

    • 解决:使用 asyncio.Semaphore 限制并发数
  2. 忽略错误:一个任务失败导致整体失败

    • 解决:用 try-except 包裹每个任务
  3. 混淆场景:有依赖的任务强行并行

    • 解决:先分析依赖关系,再决定并行策略

四、响应速度优化:缓存、流式输出

优化方法 适用场景 提升幅度
缓存 高频重复 100-3000x
流式 长文本 体验提升5x
JSONL代替JSON 所有场景 60%
分层对齐 50+函数 70%
并发调用 多任务 4-10x

想象你在餐厅点餐后等待上菜:

场景1:漫长的等待(响应慢)

c 复制代码
你点完餐 → 等待30分钟 → 终于上菜
期间:
- 不知道厨房在做什么
- 不知道还要等多久
- 焦虑、不耐烦
- 可能会投诉或离开

场景2:优化的体验(响应快)

c 复制代码
你点完餐 → 5分钟后上菜
或者:
你点完餐 → 服务员告诉你"大约需要15分钟"
        → 10分钟后服务员说"菜马上好"
        → 15分钟后上菜
期间:
- 知道进度
- 心里有数
- 体验良好

AI 应用中的类似问题

  • 用户提问后,等待20秒才看到回复 → 用户可能关闭页面
  • 复杂的 Function Call 需要多次 AI 调用 → 累积延迟很长
  • 相同的问题重复问,每次都要重新计算 → 浪费资源

总结

c 复制代码
Function Call 技能树
│
├── 基础技能 ⭐⭐⭐
│   ├── 编写 JSON Schema
│   ├── 理解调用流程
│   └── 执行函数并返回结果
│
├── 进阶技能 ⭐⭐⭐⭐
│   ├── 优化函数命名和描述
│   ├── 处理意图识别问题
│   └── 实现分层对齐机制
│
├── 高级技能 ⭐⭐⭐⭐⭐
│   ├── 管理 100+ 函数
│   ├── 实现并发调用
│   ├── 综合性能优化
│   └── 设计完整应用架构
│
└── 专家技能 ⭐⭐⭐⭐⭐⭐
    ├── RAG + 向量数据库
    ├── 自定义评估体系
    └── 企业级系统设计
相关推荐
超龄超能程序猿36 分钟前
提升文本转SQL(Text-to-SQL)精准度的实践指南
数据库·人工智能·sql
柒柒钏1 小时前
PyTorch学习总结(一)
人工智能·pytorch·学习
金融小师妹1 小时前
基于NLP政策信号解析的联邦基金利率预测:美银动态调整12月降息概率至88%,2026年双降路径的强化学习模拟
大数据·人工智能·深度学习·1024程序员节
_山止川行1 小时前
生活
人工智能
是Dream呀1 小时前
昇腾实战 | 昇腾 NPU 异构编程与 GEMM 调优核心方法
人工智能·华为·cann
JobDocLS1 小时前
深度学习软件安装
人工智能·深度学习
新智元1 小时前
2027 年,人类最后一次抉择
人工智能·openai
新智元1 小时前
DeepSeek V3.2 爆火,Agentic 性能暴涨 40% 解密
人工智能·aigc
多云的夏天2 小时前
AI-工具使用总结-2025-12
人工智能