跳至主要内容

GPT-4.5 函数调用教程:用 AI 提取股价与新闻

使用 OpenAI 最先进的模型构建一个多函数调用的 AI 系统,用于提取股价与新闻。
· 12分钟 阅读

使用 AI 探索

大型语言模型(LLM)在稳定地产生结构化输出(如 JSON)方面常常表现不佳,即使用了先进的提示工程技巧也不例外。提示工程能提升效果,但并非万无一失——测试过程中仍可能出现错误,导致偶发失败。那么,如何才能每次都确保准确、可靠的结构化输出?

函数调用是指 LLM 生成结构化数据响应(通常为 JSON 对象)的能力。借助该特性,LLM 能够超越纯文本生成,与外部系统、API 和工具进行交互。通过利用函数调用,LLM 可以在保持所需结构与准确性的同时,执行更复杂、依情境而定的任务。

在本教程中,我们将学习如何使用GPT-4.5(当前最准确、最注重事实的模型)来创建一个函数调用脚本。首先,我们将实现一个函数,从互联网上提取股价。随后,我们会再添加一个函数,使 LLM 能在多种工具间进行选择,并根据用户提示挑选最合适的工具。

完成本教程后,您将学会构建一个能够提供任意公司股价并推送新闻源的智能应用。

图片来源:作者

GPT-4.5 的函数调用能力

OpenAI 最新的 GPT-4.5 引入了多项高级功能,其中包括增强的函数调用能力。这些能力旨在提升模型与外部系统的交互能力,并通过基于用户输入调用特定函数来执行复杂任务。

来源:Model - OpenAI API

以下是 GPT-4.5 函数调用的关键特性:

1. 与 API 集成

GPT-4.5 通过 Chat Completions API、Assistants API 和 Batch API 支持函数调用。这使开发者能够将模型无缝集成到其应用中,让其执行数据检索、处理,甚至在软件环境中执行命令等任务。

2. 结构化输出

模型可返回结构化输出(如 JSON),这对需要模型与要求特定数据格式的系统或工具交互的开发者尤为有用。

3. 视觉能力

尽管 GPT-4.5 不支持语音或视频等多模态输出,但它支持通过图像输入的视觉能力。模型能够处理和分析视觉数据,并可与函数调用结合,完成同时涉及文本与图像数据的任务。

4. 高级功能

GPT-4.5 的函数调用功能旨在简化复杂工作流,允许模型建议或调用您代码中编写的函数。这对于自动化重复性任务,或将 AI 驱动的决策融入现有软件系统尤为有用。

想了解该 OpenAI 新模型的全部细节,请阅读博文GPT 4.5:特性、获取方式、与 GPT-4o 的对比等。

GPT-4.5 单函数调用

接下来我们将使用 GPT-4.5 模型与 Yahooquery 库构建一个简单的函数调用系统。Yahooquery 将帮助我们从 Yahoo Finance 提取任意与股票相关的数据。

我们的方案允许用户提出有关股价的问题,进而触发一个特定函数,从互联网上检索该股价并生成回复。就是这么简单。

我们先用 PIP 命令安装 openai 和 yahooquery 库。

!pip install openai yahooquery -q

创建一个股价函数  

创建一个 Python 函数,接收股票代码(如 AAPL),并返回该股票的价格。函数在后端使用 yahooquery 提取相关数据。

from openai import OpenAI
import json
from yahooquery import Ticker

def get_stock_price(ticker):
    try:
        # Create a Ticker object for the provided ticker symbol
        t = Ticker(ticker)
        # Retrieve the price data
        price_data = t.price
        # Check if we received valid data for the ticker
        if ticker in price_data and price_data[ticker].get("regularMarketPrice") is not None:
            price = price_data[ticker]["regularMarketPrice"]
        else:
            return f"Price information for {ticker} is unavailable."
    except Exception as e:
        return f"Failed to retrieve data for {ticker}: {str(e)}"
    
    return f"{ticker} is currently trading at ${price:.2f}"

用函数定义工具

OpenAI 客户端并不理解 Python 函数,因此我们需要用字典列表来创建一个工具。必须提供必要的名称、描述和输出类型。

每当调用此函数时,它会从提示中提取股票代码,并以结构化格式返回。

tools = [{
    "type": "function",
    "function": {
        "name": "get_stock_price",
        "description": "Get current stock price for a provided ticker symbol from Yahoo Finance using the yahooquery Python library.",
        "parameters": {
            "type": "object",
            "properties": {
                "ticker": {"type": "string"}
            },
            "required": ["ticker"],
            "additionalProperties": False
        },
        "strict": True
    }
}]

让模型自行决定是否调用函数

测试我们刚创建的 OpenAI 函数。向聊天补全提供用户消息、模型名称和工具。

client = OpenAI()

messages = [{"role": "user", "content": "What's the current price of Meta stock?"}]

completion = client.chat.completions.create(
    model="gpt-4.5-preview",
    messages=messages,
    tools=tools,
)

print(completion.choices[0].message.tool_calls)

可以看到,GPT-4.5 准确调用了 get_stock_price,并返回了正确的股票代码(META)。

[ChatCompletionMessageToolCall(id='call_uVGbahRiMnn4AkOJYbv8gfIV', function=Function(arguments='{"ticker":"META"}', name='get_stock_price'), type='function')]

用提供的股票代码执行函数

现在我们可以把这个代码传给 Python 函数 get_stock_price。

tool_call = completion.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)

result = get_stock_price(args["ticker"])

print(result)

结果中,您会收到包含股票代码及其对应价格的响应。

META is currently trading at $640.00

您可以到此为止,但若要提供自然语言的完整回答,需要再次将结果传回聊天补全。

追加函数调用与工具结果

我们将把上一轮对话中生成的响应追加进去,并包含带有工具 ID 与工具结果的调用。

messages.append(completion.choices[0].message)  # Model's function call message
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": str(result)
})

将更新后的对话发回给模型

使用包含工具调用内容的消息再次运行聊天补全。

completion_2 = client.chat.completions.create(
    model="gpt-4.5-preview",
    messages=messages,
    tools=tools,
)

# The final model response incorporating the stock price information
print(completion_2.choices[0].message.content)

如您所见,我们得到了正确的结果。

The current price of Meta stock (META) is $640.00.

您可能会觉得这一步没必要,但在输出复杂时,这一步能帮助您用通俗英语理解结果,而非只看到 JSON 格式。

如果您对 OpenAI API 感到困惑并想进一步学习,建议参加OpenAI 基础职业路径课程,学习如何使用 OpenAI API 调用 OpenAI 的 GPT 与 Whisper 模型。

GPT-4.5 多函数调用

现在,我们将为 AI 系统添加另一个函数,使 GPT-4.5 能够根据用户提示自动决定调用哪个函数。我们将添加一个新的资讯订阅函数,返回指定股票代码的前 3 条新闻及其链接。

先使用 pip 命令安装 feedparser 库。我们将用它来提取指定股票代码的头条新闻。

!pip install feedparser -q

定义股票新闻函数

创建 Python 函数 get_stock_news,接收股票代码作为输入,返回前三条新闻标题及其链接。

import feedparser


def get_stock_news(ticker):
    # Construct the RSS feed URL for the given ticker.
    rss_url = f"https://feeds.finance.yahoo.com/rss/2.0/headline?s={ticker}&region=US&lang=en-US"
    try:
        feed = feedparser.parse(rss_url)
        if not feed.entries:
            return f"No news found for {ticker}."
        # Extract the top 3 news items (title and link)
        news_items = []
        for entry in feed.entries[:3]:
            title = entry.get("title", "No Title")
            link = entry.get("link", "No Link")
            news_items.append(f"{title} ({link})")
        news_str = "\n".join(news_items)
    except Exception as e:
        return f"Failed to retrieve news for {ticker}: {str(e)}"
    
    return f"Latest news for {ticker}:\n{news_str}"

get_stock_news("AAPL")

我们收集了关于苹果的前三条头条新闻,并附上了相应链接。

'Latest news for AAPL:\nNvidia AI Server Maker Hon Hai Posts 25% Jump in Two-Month Sales 
(https://finance.yahoo.com/news/nvidia-ai-server-maker-hon-075011863.html?.tsrc=rss)\nFoxconn says February revenue rose 56.43% y/y
(https://finance.yahoo.com/news/foxconn-says-february-revenue-rose-074433615.html?.tsrc=rss)\nApple Inc. (AAPL): Among the Best Stocks To Invest In According to Billionaires 
(https://finance.yahoo.com/news/apple-inc-aapl-among-best-051548210.html?.tsrc=rss)'

为股价与新闻定义多个工具

我们现在需要添加另一个名为 get_stock_news 的 OpenAI 函数,并为其提供恰当的描述和输出。

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "Get current stock price for a provided ticker symbol using yahooquery.",
            "parameters": {
                "type": "object",
                "properties": {
                    "ticker": {"type": "string"}
                },
                "required": ["ticker"],
                "additionalProperties": False
            },
            "strict": True
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_stock_news",
            "description": "Get the latest news for a provided ticker symbol by parsing the Yahoo Finance RSS feed using feedparser.",
            "parameters": {
                "type": "object",
                "properties": {
                    "ticker": {"type": "string"}
                },
                "required": ["ticker"],
                "additionalProperties": False
            },
            "strict": True
        }
    }
]

让模型决定调用一个或两个函数

我们来测试一下,通过向 GPT-4.5 询问谷歌的股价以及最新相关新闻。

messages = [{
    "role": "user",
    "content": "What's the current price of Google stock and can you show me the latest news about it?"
}]


completion = client.chat.completions.create(
    model="gpt-4.5-preview",
    messages=messages,
    tools=tools,
)

completion.choices[0].message.tool_calls

如我们所见,它已调用了用于股价和最新新闻的两个函数。

[ChatCompletionMessageToolCall(id='call_zfcRJ4EcIUUqHCcN8SErjeoi', function=Function(arguments='{"ticker": "GOOGL"}', name='get_stock_price'), type='function'),
 ChatCompletionMessageToolCall(id='call_jBv8TlSPOyFKcRWHwByxLMb4', function=Function(arguments='{"ticker": "GOOGL"}', name='get_stock_news'), type='function')]

保存函数调用结果

问题在于两个函数都返回了股票代码作为结果。我们需要用 if-else 语句判断哪个函数被调用。我们会把函数结果存入字典。

# The model returns function call requests.
tool_calls = completion.choices[0].message.tool_calls

# Execute each function call based on the tool the model requested
tool_results = {}
for tool_call in tool_calls:
    func_name = tool_call.function.name
    args = json.loads(tool_call.function.arguments)
    if func_name == "get_stock_price":
        tool_results["price"] = get_stock_price(args["ticker"])
    elif func_name == "get_stock_news":
        tool_results["news"] = get_stock_news(args["ticker"])

追加函数调用与工具结果

现在我们将追加之前生成的结果,并把带有工具 ID 的函数结果也一并追加。

messages.append(completion.choices[0].message)  # Append the model's function call message

for tool_call in tool_calls:
    func_name = tool_call.function.name
    result_content = tool_results.get("price") if func_name == "get_stock_price" else tool_results.get("news")
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": result_content
    })

将更新后的对话发回给模型

当我们把结果消息传给 GPT-4.5 后,它生成了十分合理、非常出色的结果。

from IPython.display import display, Markdown

completion_2 = client.chat.completions.create(
    model="gpt-4.5-preview",
    messages=messages,
    tools=tools,
)

# The final model response incorporates both stock price and news.
Markdown(completion_2.choices[0].message.content)

我们获得了谷歌股价以及关于谷歌的热门新闻链接。

源代码与输出可在DataLab 工作区中获取。您只需将自己的OpenAI API 密钥添加到环境变量,即可自行运行全部内容。

结语

我们让大型语言模型生成结构化输出,并将其传给 API 或其他 Python 函数来执行特定任务。像 GPT-4.5 这样的先进 AI,能够使用多种服务或 API 生成高度集成的响应。

未来,我们将通过函数调用与智能体来掌控周边的一切;只需向您的 AI 发送语音指令,它就会根据您的指令调用必要的工具,并对系统进行更改。

我们已经拥有 GPT-4.5,但许多 AI 专家正期待更接近通用人工智能(AGI)的 GPT-5。您可以通过阅读博文我们所知的 GPT-5 全部信息来了解这款即将发布的模型。

Abid Ali Awan

作者

Abid Ali Awan

作为一名持证的数据科学家,我热衷于利用前沿技术打造创新的机器学习应用。凭借在语音识别、数据分析与报告、MLOps、对话式人工智能以及自然语言处理方面的扎实背景,我不断打磨构建智能系统的能力,力求带来切实影响。除技术专长外,我也擅长沟通,能够将复杂概念提炼为清晰、简明的表述。因此,我成为数据科学领域备受关注的博主,与不断壮大的数据专业人士社区分享洞见与实践经验。目前,我专注于内容创作与编辑,借助大语言模型打造有力且吸引人的内容,帮助企业与个人更好地发挥数据价值。

主题