无需 KYC — 无需 ID、无需自拍、无需文件。使用加密货币支付:BTC, USDT, USDC, ETH, SOL, LTC
语言: 简体中文
获取 API 密钥

文档 · Function calling · Tool use · Python

OpenAI function calling:60 行 Python 实现一个 Google 搜索工具

向模型描述一个 google_search 函数,运行它请求的查询,再把结果发回。该 schema 是纯 JSON Schema,因此可以直接用于 Claude 和其他支持工具调用的模型。

最后更新:

快速回答

如何给 OpenAI 模型一个网页搜索工具?

在 tools 中用 JSON Schema 声明一个 google_search 函数,然后循环:当模型返回 tool_calls 时,在 https://serpcrypto.com/api/v1/search 上运行每次查询,并把结果作为 tool 消息追加,直到它给出答案。SerpCrypto 每次成功查询收取 1 个积分,起价为 US$0.30/千次搜索,用加密货币支付,无需 KYC。

工具 schema 是什么样的?

一个 function 工具包含名称、描述和 JSON Schema 格式的参数。模型只能看到这三样东西,因此描述必须说明该工具返回什么以及何时使用它。只有 query 是必填的;country 和 language 是可选的,在代码中默认为 US English。

工具定义(Chat Completions 格式)
{
  "type": "function",
  "function": {
    "name": "google_search",
    "description": "Search Google for current information. Returns the top results with title, link and snippet. Use it for facts newer than your training data.",
    "parameters": {
      "type": "object",
      "properties": {
        "query": { "type": "string", "description": "The search query, as a person would type it." },
        "gl": { "type": "string", "description": "Two-letter country code of the results, e.g. us, gb, de." },
        "hl": { "type": "string", "description": "Language code, e.g. en, de, pt-BR." }
      },
      "required": ["query"]
    }
  }
}

工具调用循环是怎么运作的?

用 tools 发送问题。如果回复中包含 tool_calls,就逐个执行,追加 assistant 消息,并为每次调用追加一条带有对应 tool_call_id 的 tool 消息,然后再次调用模型。当某条回复没有任何工具调用时,它就是最终答案。

下面的循环在三次查询后停止。如果模型不断查询,上限可以保护你的积分,而三次查询就能回答大多数事实性问题。

search_agent.py
"""Tool-calling loop: the model asks for searches, this code runs them on SerpCrypto."""
import json
import os

import requests
from openai import OpenAI

client = OpenAI()  # reads OPENAI_API_KEY
MODEL = os.environ["OPENAI_MODEL"]  # any OpenAI chat model with tool calling
API_URL = "https://serpcrypto.com/api/v1/search"

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "google_search",
            "description": "Search Google for current information. Returns the top results with title, link and snippet.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "The search query."},
                    "gl": {"type": "string", "description": "Two-letter country code, e.g. us."},
                    "hl": {"type": "string", "description": "Language code, e.g. en."},
                },
                "required": ["query"],
            },
        },
    }
]


def google_search(query, gl="us", hl="en"):
    r = requests.get(
        API_URL,
        params={"q": query, "gl": gl, "hl": hl},
        headers={"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]},
        timeout=90,
    )
    if r.status_code != 200:
        return f"Search failed with HTTP {r.status_code}."
    items = r.json().get("organic_results", [])[:5]
    return "\n\n".join(f"{x['title']}\n{x['link']}\n{x.get('snippet', '')}" for x in items) or "No results."


def ask(question, max_searches=3):
    messages = [{"role": "user", "content": question}]
    for _ in range(max_searches + 1):
        reply = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
        msg = reply.choices[0].message
        if not msg.tool_calls:
            return msg.content
        messages.append(msg)
        for call in msg.tool_calls:
            args = json.loads(call.function.arguments)
            messages.append({"role": "tool", "tool_call_id": call.id, "content": google_search(**args)})
    return "Stopped: search limit reached."


print(ask("Which countries changed their data protection laws in 2026? Cite sources."))

同一份 schema 也适用于 Claude 和其他模型吗?

适用,只是封装不同。Claude 的 tool use 在 input_schema 下接受相同的 JSON Schema,与 name 和 description 并列。大多数其他支持工具调用的 API 在参数上也接受 JSON Schema,只是外层字段名不同。搜索函数本身保持不变,因为它只调用 SerpCrypto endpoint。

同一个工具用于 Claude(Messages API)
{
  "name": "google_search",
  "description": "Search Google for current information. Returns the top results with title, link and snippet.",
  "input_schema": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "The search query." },
      "gl": { "type": "string", "description": "Two-letter country code, e.g. us." },
      "hl": { "type": "string", "description": "Language code, e.g. en." }
    },
    "required": ["query"]
  }
}

工具应该向模型返回什么?

带链接的简短文本。五条包含标题、链接和摘要的结果通常就足够模型回答和引用。返回完整 JSON 也行,但会消耗更多 token,并给模型更多噪声去读。

如果存在 AI Overview 文本,可以加上,让模型看到 Google 自己的摘要,并保留来源链接,这样答案可以引用页面而不是概述。

如何让搜索成本可预测?

统计工具调用:每次成功调用计 1 积分。像循环那样为每个问题限制查询次数,并用查询词记录每次调用,这样你能看到模型在问什么。在 100,000 次搜索 套餐上费率为 US$0.56/千次搜索,并且 预付的搜索积分永不过期:未使用的查询会一直留在你的账户中,直到你使用它们。

出错不扣费:1 积分 = 1 次成功的查询请求,可在任意支持的引擎上返回一页结果。失败的请求不计费。

Function calling 常见问题

可以用 Responses API 代替 Chat Completions 吗?

可以。Responses API 接受带有相同 JSON Schema 的 function 工具,其中 name、description 和 parameters 位于每个工具的顶层。搜索函数和循环的思路都不变。

为什么不使用模型提供商内置的网页搜索?

内置搜索工具会自行选择来源和设置。在 SerpCrypto 上使用 function,可以按你选择的国家和语言获取 Google 搜索结果,以可记录的 JSON 返回,每次查询价格已知。

模型能选择国家吗?

能。gl 是工具的一个 parameter,所以模型可以根据问题来设置它,例如针对关于英国的问题设为 gb。对于没有提到国家的问题,在代码中保留默认值。

获取搜索 API 密钥需要信用卡吗?

不需要。SerpCrypto 积分用 BTC, USDT, USDC, ETH, SOL, LTC 支付,无需身份证、无需自拍、无需证件。使用账号登录;邮箱为选填。

起价 US$0.30/千次搜索 · 无需 KYC

获取 API 密钥