手记

大型语言模型的函数调用入门:让AI模型动起来,不只是生成文字

AI模型在学习做什么,而不仅仅是说什么

功能调用可以让大型语言模型(LLM)根据用户的输入与外部工具或功能进行交互。大型语言模型(LLM)不仅能生成文本,还能根据用户输入判断需要执行特定操作,并请求外部工具或功能来完成这些操作。

通过函数调用,允许用户使用自然语言与复杂系统交互,而大型语言模型则处理底层执行的函数。因此,大型语言模型可以专注于解决实际问题的同时,而不是仅仅生成文本。

比如,如果用户询问天气,模型可以调用天气API获取实时数据,而不仅仅是生成通用回复。如果可能会下雨,它会提醒你带伞。

函数调用过程详解

让我们来拆解一下函数调用在大型语言模型(LLM)中是如何运作的。

  1. 用户查询: 过程始于用户提出一个问题或请求一个动作(例如,“今天天气怎么样?”或“检查产品X是否有库存”)。
  2. LLM处理: LLM 分析查询,识别出需要外部数据或执行动作来完成请求。例如:
  • 如果用户询问天气,LLM 会识别出需要获取实时天气数据。

  • 如果用户想要库存详情,它会触发数据库查询。
    1. 函数调用决策: LLM 决定执行一个函数调用,可以是:
  • 获取实时天气数据
  • 查询库存详情

  • API 调用:调用外部服务(例如,获取实时天气预报)。
  • 自定义函数:调用内部工具或数据库(例如,检查库存水平)。
    1. 数据检索:函数获取所需的数据(例如,从天气 API 获取温度,获取仓库中产品的可用性)。
  1. 数据整合: 检索到的数据被发送回LLM,LLM处理它并生成符合上下文且准确的回复给用户。
函数调用的用例以及它们如何提高性能

通过调用函数的能力,LLM 不仅限于文本生成。它可以执行诸如获取实时数据流或与其他软件进行互动等操作。这使得模型在实际应用中更加灵活和有用。例如:。

  • 提供最新的信息: 如果模型可以通过函数调用来获取最新的信息,它可以提供更准确的答案。例如,不通过函数调用来回答当前事件的问题可能会导致信息过时,但通过访问新闻API,答案可以保持最新。
  • 可以使用函数调用来自动化重复性任务: 例如,如果用户想要安排会议,LLM可以通过调用日历API来自动添加事件,这可以节省时间并减少手动输入的需求。
  • 与其它服务进行集成: LLM可以成为更大生态系统的一部分,与数据库、CRM或其它企业系统连接。这使得LLM在专业环境中更加灵活。
  • 通过多个函数调用来解决多步骤问题: 例如,规划旅行,通过不同的API来查询航班可用性、预订酒店和租车。
  • 无需重新训练即可更新为使用新功能或API: 当新的函数或API的出现时,可以更新LLM以使用它们,这样只需最小的努力就能保持系统最新。

比如一些调用函数的例子

如果你使用过ChatGPT市场中的任何GPT,你可能已经见过或体验过函数调用。这些GPT可以执行自定义功能,让人们创建专用工具,例如待办事项列表构建器、提示增强器、应用程序连接器和问答机器人。ChatGPT内置的“任务”功能同样使用这种方法——可以通过在特定时间触发这些功能来设定提醒。

Claude的模型上下文协议(MCP)也做了类似的事情。在Sonnet 3.5版本中,Claude可以搜索网络结果(如Brave Search),访问其图形记忆系统,或链接到其他应用。这两个系统都展示了AI现在如何通过这些“功能调用”将其核心智能与现实世界的工具相连接起来。

支持功能调用的AI模型

注意: 有时候人们也把调用函数叫做调用工具。这两种说法意思相同。

支持函数调用的其中一些模型包括有,调用函数。

(Note: Given the need to adhere to standard punctuation and the suggestion to end with a period, the final corrected translation should be: 支持函数调用的其中一些模型包括有,调用函数。 However, due to the limitation of keeping the period at the end and considering the overall sentence structure, the comma before the period is typically omitted in this context, so the final translation could more naturally be presented as: 支持函数调用的其中一些模型包括有。)

  • GPT-4o,
  • Llama 3.2,
  • Google 的 Gemini 2.0 Flash 实验版,
  • Claude,
  • Mistral,
  • Cohere 的 Command R (指令R)

虽然还有许多其他模型,这些模型可以通过API轻松访问,其中一些还是开源的,可以通过Ollama在本地使用。

实战功能调用 — 用Ollama创建一个AI搜索工具 我们来创建

我们正在构建一个搜索工具,在该工具中Llama 3.2充当决策角色——它首先分析查询是否需要实时网络数据。如果是的话,它会自动触发web_search工具。这模仿了Perplexity如何平衡AI推理与实时数据的策略。
我们所需要的有:

  1. Ollama:本地运行 Llama 3.2 模型。
  2. Python 3.11+:用于异步/等待模式,这对性能至关重要。
  3. SearchAPI:免费层级每天支持 100 次请求。 (链接)

我们先定义一下函数:

注:Ollama 称这叫工具调用,这和函数调用是一样的。

这将是我们用的工具,它的参数是根据通过 Google 的 SearchAPI 得到的答案来确定的。

    # 定义我们的网络搜索工具
    search_tool = {
        'type': 'function',
        'function': {
            'name': 'web_search',
            'description': '搜索关于某个主题的最新信息',
            'parameters': {
                'type': 'object',
                'required': ['query'],
                'properties': {
                    'query': {
                        'type': 'string',
                        'description': '搜索查询词'
                    }
                }
            }
        }
    }

切换到全屏模式;退出全屏

这将在我们的main.py文件中使用,我们将在该文件中调用Ollama,然后决定是否再次调用该工具。
我们的项目结构将如下所示:

这是项目文件夹的结构,包含了环境配置文件和两个主要的Python脚本。

    project_folder/
    ├── .env
    ├── search_tool.py
    └── main.py

全屏模式,退出全屏

文件说明如下:

  • .env: 隔离 API 密钥和代码
  • search_tool.py: 分离搜索逻辑以便重用
  • main.py: 专注于编排(模型与工具间的交互)

包可以通过以下方式安装:

    pip install ollama python-dotenv requests  # 在命令行中运行此命令来安装这些Python库

全屏模式,退出全屏

主流程(main.py 文件)

  1. 异步客户端:处理并发工具调用,不阻塞执行
  2. 工具响应的处理:
  • 检查响应中的tool_calls(工具调用)

  • 使用messages数组来保持对话状态
    1. 错误传播:直接将auth或search错误反馈给用户

main.py的代码如下所示:

    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
                        }
                    ]

                    # 获取最终响应,包含搜索结果
                    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())

点击全屏模式;点击退出

现在我们来专注于创建我们的搜索工具程序,这里我们需要保存用于发起API调用并获取结果的函数。代码基于这里提供的架构。

搜索工具的实现:(search_tool.py)

  1. API 错误处理:明确捕捉 401/429 错误
  2. 内容提取:
  • 优先提取 answer_box(精选摘要)

  • 限制结果为最多 4 个,以避免 token 超出限额

search_tool.py的代码如下:

    import os
    import requests
    from typing import Dict, Any
    from dotenv import load_dotenv

    # 使用搜索API搜索网络
    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 密钥 here

SEARCH_API_KEY=ABCD123

切换到全屏 退出全屏

就这样开始吧:

运行 python main.py

全屏模式,退出全屏

然后你可以问任何你想问的问题,Ollama会决定是否使用工具。

您可以在GitHub上找到完整代码[此处]。

最后的总结

函数调用让AI模型不再仅仅局限于对话——现在它们可以触发行动,比如获取实时天气数据或检查库存情况,通过连接到工具和APIs。而不是提供通用答案的方式,它们通过将自然语言与软件及现实世界数据结合来解决实际问题。这将聊天机器人转变为动态助手,能够自动化任务、获取更新并与其他系统互动,重塑了我们日常使用AI的方式。

看看这个 GitHub 仓库:

🌟 GitHub 上的函数调用功能


参考资料和工具:

  1. https://github.com/ollama/ollama-python
  2. https://www.searchapi.io/
  3. https://ollama.com/library/llama3.2
  4. https://www.searchapi.io/docs/google
0人推荐
随时随地看视频
慕课网APP