LLM 中的函数调用和工具是什么?

在学习 LLM 的过程中,你应该经常听到 function call 和 tool。那么 function call 和 tool 是什么?有什么作用呢?本文就来详细给你介绍下。

如何让 AI 模型学会"做"而不仅仅是"说"

函数调用使大型语言模型(LLMs)能够根据用户的输入与外部工具、API 和函数进行交互。LLM 不仅生成文本,还能判断需要采取特定动作,然后请求外部函数执行该动作。

函数调用允许用户使用自然语言与复杂系统进行交互,而 LLM 则处理基本功能的执行。因此,LLM 能够专注于解决实际问题,而不仅仅是生成文本。

例如,如果用户询问天气,模型可以调用天气 API 获取实时数据,而不是仅仅生成一个普通的回答。如果有下雨的可能,它还可以提醒你带上雨伞。

函数调用过程解析

让我们详细分解一下函数调用在 LLM 内部是如何工作的:

  1. 用户查询:该过程开始于用户提问或请求操作(例如,"今天的天气怎么样?"或"检查产品 X 是否有货。");
  2. LLM 处理 :LLM 分析查询,并识别到它需要外部数据或某个操作来满足请求。例如:
    • 如果用户询问天气,LLM 会识别出需要提取实时数据;
    • 如果用户想要库存详情,它会触发数据库查找。
  3. 函数调用决策 :LLM 决定执行函数调用,这可能是:
    • API 调用:连接到外部服务(例如,天气 API 以获取实时天气预报);
    • 自定义函数:访问内部工具或数据库(例如,库存访问以检查库存水平)。
  4. 数据检索:函数获取所需的数据显示(例如,从天气 API 获取温度,从仓库数据库获取产品可用性);
  5. 数据整合:检索到的数据被发送回 LLM,LLM 处理这些数据并为用户生成上下文准确的响应。

函数调用的用例及如何提升性能

通过能够调用函数,LLM 不仅局限于文本生成。它可以执行诸如检索实时数据或与其他软件交互等操作。这使得该模型在实际应用中更具动态性和实用性。例如:

  1. 提供最新信息:如果模型可以通过函数调用获取最新信息,它可以提供更准确的答案。例如,关于当前事件的提问,如果没有函数调用,可能导致信息过时,但通过访问新闻 API,答案可以保持更新;
  2. 自动化重复任务:函数调用可以自动化重复的任务。例如,如果用户想要安排一个会议,LLM 可以调用日历 API 自动添加事件。这节省了时间,并减少了手动输入的需要;
  3. 与其他服务连接:LLMs 可以成为更大生态系统的一部分,与数据库、客户关系管理(CRM)或其他企业系统连接。这使它们在专业环境中更具多功能性;
  4. 处理复杂工作流程:LLM 不仅可以回答单个问题,它可以协调多个函数调用以解决多步骤问题。例如,通过检查航班可用性、预订酒店和租车来计划一次旅行;
  5. 在不重训练的情况下更新信息:随着新功能或 API 的出现,LLM 可以在不重训练整个模型的情况下更新以使用它们。这保持了系统的最新状态,且只需最小的努力。

函数调用示例

如果你使用过 ChatGPT 市场的任何 GPT,你可能已经看到或体验过函数调用。这些 GPT 执行自定义函数,让人们创建像待办事项列表构建器、提示增强器、应用连接器以及问答机器人等特定工具。ChatGPT 内置的"任务"功能也使用了这一点------它可以在特定时间触发函数设置提醒。

Claude 的模型上下文协议(MCP)做了类似的事情。通过 Sonnet 3.5,Claude 可以激活工具,如 Brave Search 以获取网页结果,访问其图记忆系统或链接到其他应用。两个系统展示了AI如何使用这些"函数调用"将其核心智能与现实世界工具连接起来。

支持函数调用的AI模型

注意:有时函数调用也被称为工具调用。这两个术语是相同的。

一些支持函数调用的模型包括:

  • GPT-4o
  • Llama 3.2
  • 谷歌的Gemini 2.0 Flash Experimental
  • Claude
  • Mistral
  • Cohere的Command R

虽然还有更多模型,但这些模型通过 API 很容易访问,还有一些可以通过 Ollama 本地使用并且是开源的。

函数调用实例 --- 创建一个使用 Ollama 的 AI 搜索工具

我们将构建一个搜索工具,Llama 3.2 将充当决策者------它首先分析查询是否需要实时网页数据。如果需要,它会通过 Ollama 的工具调用 API 自动触发 web_search 工具。这模仿了 Perplexity 如何平衡 AI 推理与实时数据。

我们需要的:

  • Ollama:在本地托管 Llama 3.2 模型。
  • Python 3.11+:支持 async/await 模式(对性能至关重要)。
  • SearchAPI:免费层支持每日 100 个请求。(链接)

让我们开始定义该函数

注意:Ollama 将其称为工具调用,这与函数调用是相同的。这将是我们的工具,其参数基于通过 SearchAPI 返回的答案。

python 复制代码
# 定义我们的搜索工具
search_tool = {
    'type': 'function',
    'function': {
        'name': 'web_search',
        'description': '搜索有关主题的当前信息',
        'parameters': {
            'type': 'object',
            'required': ['query'],
            'properties': {
                'query': {
                    'type': 'string',
                    'description': '要查找的搜索查询'
                }
            }
        }
    }
}

此代码将在我们的文件 main.py 中使用,我们将调用 Ollama 并尝试决定是否调用工具。我们的项目结构大致如下:

plain 复制代码
project_folder/
├── .env
├── search_tool.py
└── main.py

文件说明:

  • .env:将 API 密钥与代码隔离。
  • search_tool.py:分离搜索逻辑以实现可重用性。
  • main.py:专注于协调(模型 ↔ 工具交互)。

可以通过以下命令安装相关的包:

bash 复制代码
pip install ollama python-dotenv requests

主要工作流程(main.py

  • AsyncClient:处理并发工具调用而不阻塞。
  • 工具响应处理:检查响应中的 tool_calls。
  • 错误传播:直接将身份验证/搜索错误返回给用户。

main.py 的代码如下

python 复制代码
import asyncio
from ollama import AsyncClient
from search_tool import web_search, extract_content

async def process_query(query: str) -> str:
    client = AsyncClient()

    # 定义我们的搜索工具
    search_tool = {
        'type': 'function',
        'function': {
            'name': 'web_search',
            'description': '搜索有关主题的当前信息',
            'parameters': {
                'type': 'object',
                'required': ['query'],
                'properties': {
                    'query': {
                        'type': 'string',
                        'description': '要查找的搜索查询'
                    }
                }
            }
        }
    }

    # 首先,让Ollama决定是否需要搜索
    response = await client.chat(
        'llama3.2',
        messages=[{
            'role': 'user',
            'content': f'回答这个问题:{query}'
        }],
        tools=[search_tool]
    )

    # 初始化可用功能
    available_functions = {
        'web_search': web_search
    }

    # 检查Ollama是否要使用搜索工具
    if response.message.tool_calls:
        print("正在搜索网络...")

        for tool in response.message.tool_calls:
            if function_to_call := available_functions.get(tool.function.name):
                # 调用搜索函数
                search_results = function_to_call(**tool.function.arguments)

                if "error" in search_results:
                    if search_results["error"] == "authentication_failed":
                        return "身份验证失败。请检查你的API密钥。"
                    return f"搜索错误:{search_results['error']}"

                # 提取相关内容
                content = extract_content(search_results)

                if not content:
                    return "未找到相关信息。"

                # 将搜索结果添加到对话中
                messages = [
                    {'role': 'user', 'content': query},
                    response.message,
                    {
                        'role': 'tool',
                        'name': tool.function.name,
                        'content': content
                    }
                ]

                # 结合搜索结果从Ollama获取最终响应
                final_response = await client.chat(
                    'llama3.2',
                    messages=messages
                )

                return final_response.message.content

    # 如果没有工具调用,直接返回响应
    return response.message.content

async def main():
    question = input("你想知道什么?")
    print("\n正在处理你的问题...")
    answer = await process_query(question)
    print("\n答案:")
    print(answer)

if __name__ == "__main__":
    asyncio.run(main())

现在,让我们专注于创建我们的 search_tool,在这里我们需要保存函数以进行API调用并获取结果。代码基于此处提供的模式。

搜索实现(search_tool.py)

  • API错误处理:显式捕获 401/429。
  • 内容提取
    • 优先考虑 nswer_box(精选摘要)。
    • 限制为 4 个结果以避免令牌溢出。

search_tool.py 的代码如下

python 复制代码
import os
import requests
from typing import Dict, Any
from dotenv import load_dotenv

# 使用SearchAPI搜索网络
def web_search(query: str) -> Dict[Any, Any]:
    load_dotenv()
    api_key = os.getenv('SEARCH_API_KEY')

    if not api_key:
        return {"error": "环境变量中未找到API密钥"}

    url = "https://www.searchapi.io/api/v1/search"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    params = {
        "engine": "google_news",
        "q": query,
        "num": 5
    }

    try:
        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 401:
            return {"error": "无效的API密钥或身份验证失败"}
        elif response.status_code == 429:
            return {"error": "超出速率限制"}

        response.raise_for_status()
        return response.json()

    except requests.exceptions.RequestException as e:
        error_msg = f"获取搜索结果时出错:{e}"
        if hasattr(e, 'response') and e.response:
            try:
                error_details = e.response.json()
                error_msg = f"{error_msg} - {error_details.get('message', '')}"
            except:
                pass
        return {"error": error_msg}

# 从搜索结果中提取相关内容,因为API返回了大量数据
def extract_content(search_results: dict) -> str:
    content = []

    if "organic_results" in search_results:
        for result in search_results["organic_results"][:4]:  # 取前4个结果
            if "snippet" in result:
                content.append(result["snippet"])

    if "answer_box" in search_results and search_results["answer_box"]:
        if "answer" in search_results["answer_box"]:
            content.insert(0, search_results["answer_box"]["answer"])

    return "\n\n".join(content)

创建一个.env文件并在其中存储你的API密钥。获取你的SearchAPI密钥在这里:

plain 复制代码
SEARCH_API_KEY=ABCD123

然后执行以下命令测试整个流程:

bash 复制代码
python main.py

接下来,你可以询问任何问题,Ollama 将决定是否使用工具:

结论

函数调用让 AI 模型不仅仅是对话------它们现在可以触发动作,如拉取实时天气数据或检查库存,通过连接到工具和 API。它们不再提供普通答案,而是通过将自然语言与软件和现实世界数据相结合来解决实际问题。这使得聊天机器人变成动态助手,能够自动化任务、获取更新以及与其他系统交互,重新塑造我们在日常需求中使用AI的方式。

参考文献和工具:

  • 知识星球:云原生AI实战营。10+ 高质量体系课( Go、云原生、AI Infra)、15+ 实战项目,P8 技术专家助你提高技术天花板,冲击百万年薪!
  • 公众号:令飞编程,分享 Go、云原生、AI Infra 相关技术。回复「资料」免费下载 Go、云原生、AI 等学习资料;
  • 哔哩哔哩:令飞编程 ,分享技术、职场、面经等,并有免费直播课「云原生AI高新就业课」,大厂级项目实战到大厂面试通关;
相关推荐
鲜枣课堂7 分钟前
发力“5G-A x AI融智创新”,中国移动推出重要行动计划!打造“杭州Mobile AI第一城”!
人工智能·5g
爱的叹息15 分钟前
AI应用开发平台 和 通用自动化工作流工具 的详细对比,涵盖定义、核心功能、典型工具、适用场景及优缺点分析
运维·人工智能·自动化
Dm_dotnet22 分钟前
使用CAMEL创建第一个Agent Society
人工智能
新智元29 分钟前
MIT 惊人神作:AI 独立提出哈密顿物理!0 先验知识,一天破译人类百年理论
人工智能·openai
闰土_RUNTU37 分钟前
机器学习中的数学(PartⅡ)——线性代数:2.1线性方程组
人工智能·线性代数·机器学习
东锋1.341 分钟前
Spring AI 发布了它的 1.0.0 版本的第七个里程碑(M7)
java·人工智能·spring
邪恶的贝利亚1 小时前
神经网络复习
人工智能·神经网络·机器学习
新智元1 小时前
支付宝被 AI 调用,一句话运营小红书!国内最大 MCP 社区来了,开发者狂欢
人工智能·openai
岁月如歌,青春不败1 小时前
AI智能体开发与大语言模型的本地化部署、优化技术
人工智能·深度学习·机器学习·大语言模型·智能体
杰瑞学AI1 小时前
Devops之GitOps:什么是Gitops,以及它有什么优势
运维·git·云原生·kubernetes·devops·argocd