# OpenAI function calling：为你的模型提供 read_url 工具

> 使用 read_url 工具的 OpenAI function calling：JSON schema 和将链接转换为干净 Markdown 供模型使用的 Python 循环。无需 KYC，加密货币支付。

- URL: https://webreaderapi.com/zh/docs/openai/
- 最后更新: 2026-10-22
- 发布者: WebReaderAPI (https://webreaderapi.com)

定义一个函数 `read_url`，并在模型请求时运行它。模型选择读取哪些页面；你的代码调用 API 并返回 Markdown。同一套 schema 也适用于其他支持工具调用的模型。

**快速回答 — 如何让 OpenAI 模型通过函数调用读取网页？**

在 `tools` 列表中声明一个 `read_url` 函数，然后运行一个循环：当模型返回工具调用时，用 URL 调用 **WebReaderAPI** 的 `/read` endpoint，并把 Markdown 作为 `tool` 消息回传。每个页面消耗 1 积分，使用浏览器时消耗 2 积分，价格自 2026 年 10 月起为 US$0.07/千页。无需 KYC；使用加密货币支付。

## read_url schema 是什么样的？

两个参数就够了：要读取的 `url`（必填），以及一个可选的 `max_chars`，让模型可以保持长页面简短。description 是最重要的部分：它告诉模型这个工具返回什么、何时使用。保持事实性并简短。

我们将该工具命名为 `read_url` 而不是 `web_fetch`，以避免与某些 agent 运行时已在该名称下提供的工具发生冲突。

*工具定义*

```json
{
  "type": "function",
  "function": {
    "name": "read_url",
    "description": "Read a public web page and return its main content as Markdown, with its title and source URL. Use it when the user gives a link or when a page must be read to answer.",
    "parameters": {
      "type": "object",
      "properties": {
        "url": { "type": "string", "description": "The http or https address of the page." },
        "max_chars": { "type": "integer", "description": "Most characters to return, 1000 to 500000. Default 20000." }
      },
      "required": ["url"],
      "additionalProperties": false
    }
  }
}
```

## 工具调用循环是如何工作的？

发送带有 `tools` 列表的对话。如果回复包含工具调用，就逐个运行，将结果作为带有 role `tool` 和匹配的 `tool_call_id` 的消息追加，然后再次询问模型。当回复返回时没有工具调用，它就是最终答案。

限制轮数。对于涉及少量页面的问题，三轮或四轮就足够了，而且这个上限可以保护你免受不断要求更多内容的模型影响。

*Python：使用 openai 包的完整循环*

```python
import json
import os

import requests
from openai import OpenAI

READ_URL = {
    "type": "function",
    "function": {
        "name": "read_url",
        "description": "Read a public web page and return its main content as Markdown, with its title and source URL.",
        "parameters": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "The http or https address of the page."},
                "max_chars": {"type": "integer", "description": "Most characters to return. Default 20000."},
            },
            "required": ["url"],
            "additionalProperties": False,
        },
    },
}


def read_url(url, max_chars=20000):
    resp = requests.get(
        "https://webreaderapi.com/api/v1/read",
        headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
        params={"url": url, "max_chars": max_chars},
        timeout=75,
    )
    body = resp.json()
    if resp.status_code != 200:
        return "Could not read the page: " + body["error"]["code"]
    return "# " + (body.get("title") or url) + "\nSource: " + body["final_url"] + "\n\n" + body["markdown"]


client = OpenAI()
model = os.environ.get("OPENAI_MODEL", "gpt-4.1-mini")
messages = [{"role": "user", "content": "What does https://example.com/blog/first-post announce? Answer in two sentences."}]

for _ in range(4):
    reply = client.chat.completions.create(model=model, messages=messages, tools=[READ_URL])
    msg = reply.choices[0].message
    if not msg.tool_calls:
        print(msg.content)
        break
    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": read_url(**args)})

```

## 如何降低 token 使用量和成本？

有三个设置很重要。将 `max_chars` 保持在适度水平，每页约 8,000 到 20,000 个字符，因为你返回的每个字符都会被模型读取。保持默认的 `main_content=true`，这样菜单和页脚永远不会进入上下文。并且如上所述限制循环，这样一个问题无法触发数十次读取。

在我们这边，成本按页计算，而不是按字符计算：1 积分 = 读取 1 个页面且无需浏览器；当页面需要浏览器渲染 JavaScript 时为 2 积分。失败的请求，或被网站 robots.txt 拒绝的请求，不扣费。一个每天读取 300 个页面的支持助手每月大约使用 9,000 积分，在 10,000 个网页（US$3.75）之内。

## 该 schema 能与其他模型一起使用吗？

可以，只需要在 wrapper 中做小的改动。大多数工具调用 API 接受用于参数的 JSON Schema，以及工具的名称和描述，因此 `read_url` 可以原样跨提供商迁移。[MCP 页面](https://webreaderapi.com/zh/docs/mcp/) 为使用 Model Context Protocol 的客户端打包了相同的函数，而 [LangChain 页面](https://webreaderapi.com/zh/docs/langchain/) 为 LangChain 和 LlamaIndex agent 封装了它。

## 页面被拒绝时模型应该看到什么？

一句简短、清晰的句子，就像上面的循环返回的那样："Could not read the page: blocked_by_robots"。模型能很好地处理这种情况，并回退到其他来源或告诉用户。我们遵守 robots.txt：我们的爬虫以 WebReaderAPI 标识自身，遵循专为其或为所有爬虫编写的规则，不读取网站禁止的页面。被拒绝的页面不扣费。如果网站拒绝我们的请求，我们会返回其答复：我们从不破解 CAPTCHA、不登录账户，也不试图绕过封锁或付费墙。这些拒绝都不会消耗积分。

## 函数调用：常见问题

### 这需要 Responses API 还是 Chat Completions？

示例使用带有 `tools` 参数的 Chat Completions。相同的函数定义和相同的 `read_url` 请求体也适用于其他接受函数工具的 OpenAI 接口；只有围绕它们的循环会发生变化。

### 模型能在一轮中读取多个页面吗？

可以。一个回复可以包含多个工具调用；循环会运行每个调用，并在再次询问模型之前返回每个结果。当模型一次读取多个页面时，请将 `max_chars` 设得更低。

### API 密钥会暴露给模型吗？

不会。密钥保留在你代码的环境中。模型只能看到工具的名称、描述以及你的函数返回的文本。

### 被拒绝的页面会花费什么？

什么也不花费。1 积分 = 读取 1 个页面且无需浏览器；当页面需要浏览器渲染 JavaScript 时为 2 积分。失败的请求，或被网站 robots.txt 拒绝的请求，不扣费。

---

WebReaderAPI: WebReaderAPI 是一款面向 AI agents 的网页读取 API，可将任何公开网页转换为干净的 Markdown，用加密货币支付，无需上传身份证件。预付费积分低至 US$0.07/千页，永不过期，且遵守 robots.txt。无需 KYC — 无身份证、无自拍、无证件。加密货币支付。
