# OpenAI function calling: một tool read_url cho model của bạn

> OpenAI function calling với một tool read_url: JSON schema và vòng lặp Python biến link thành Markdown sạch cho model. Không cần KYC, thanh toán bằng crypto.

- URL: https://webreaderapi.com/vi/docs/openai/
- Cập nhật lần cuối: 2026-10-22
- Đơn vị phát hành: WebReaderAPI (https://webreaderapi.com)

Mô tả một hàm, `read_url`, và chạy nó khi model yêu cầu. Model chọn những trang nào để đọc; code của bạn gọi API và trả lại Markdown. Cùng schema đó hoạt động với các model khác hỗ trợ function calling.

**Câu trả lời nhanh — Làm thế nào để cho một model OpenAI đọc trang web bằng function calling?**

Khai báo một hàm `read_url` trong danh sách `tools`, rồi chạy một vòng lặp: khi model trả về một tool call, gọi endpoint `/read` của **WebReaderAPI** với URL và gửi Markdown trả về dưới dạng message `tool`. Mỗi trang tốn 1 credit, 2 credit nếu dùng trình duyệt, tính từ 0,07 US$/1K trang kể từ tháng 10 năm 2026. Không cần KYC; thanh toán bằng crypto.

## Schema read_url trông như thế nào?

Hai tham số là đủ: `url` cần đọc, bắt buộc, và một `max_chars` tùy chọn cho phép model giữ trang dài ngắn gọn. Phần description là quan trọng nhất: nó cho model biết tool trả về gì và khi nào nên dùng. Hãy giữ nó thực tế và ngắn gọn.

Chúng tôi đặt tên tool là `read_url` thay vì `web_fetch` để tránh trùng với các tool mà một số agent runtime đã cung cấp sẵn dưới tên đó.

*Định nghĩa tool*

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

## Vòng lặp tool calling hoạt động như thế nào?

Gửi cuộc hội thoại kèm danh sách `tools`. Nếu phản hồi chứa tool call, chạy từng cái, thêm kết quả dưới dạng message với role `tool` và `tool_call_id` tương ứng, rồi hỏi model lần nữa. Khi phản hồi trả về mà không có tool call, đó là câu trả lời cuối cùng.

Giới hạn số vòng lặp. Ba hoặc bốn vòng là đủ cho một câu hỏi về vài trang, và giới hạn này bảo vệ bạn khỏi một model liên tục đòi thêm.

*Python: vòng lặp đầy đủ với package 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)})

```

## Làm thế nào để giảm lượng token dùng và chi phí?

Ba cài đặt quan trọng. Giữ `max_chars` vừa phải, khoảng 8.000 đến 20.000 ký tự mỗi trang, vì mọi ký tự bạn trả về đều được model đọc. Giữ `main_content=true` mặc định, để menu và footer không bao giờ lọt vào context. Và giới hạn vòng lặp, như trên, để một câu hỏi không thể kích hoạt hàng chục lần đọc.

Về phía chúng tôi, chi phí tính theo trang, không theo ký tự: 1 credit = đọc 1 trang không cần trình duyệt; 2 credit khi trang cần trình duyệt để render JavaScript. Yêu cầu thất bại, hoặc bị robots.txt của trang web từ chối, không bị tính phí. Một trợ lý hỗ trợ đọc 300 trang mỗi ngày dùng khoảng 9.000 credit mỗi tháng, nằm trong 10.000 trang (3,75 US$).

## Schema có hoạt động với các model khác không?

Có, với thay đổi nhỏ ở phần wrapper. Hầu hết API tool calling đều nhận JSON Schema cho tham số và tên cùng description cho tool, nên `read_url` chuyển được giữa các provider nguyên vẹn. [Trang MCP](https://webreaderapi.com/vi/docs/mcp/) đóng gói cùng hàm đó cho các client nói Model Context Protocol, và [trang LangChain](https://webreaderapi.com/vi/docs/langchain/) bọc nó cho các agent LangChain và LlamaIndex.

## Model nên thấy gì khi một trang bị từ chối?

Một câu ngắn gọn, rõ ràng, như vòng lặp trên trả về: "Could not read the page: blocked_by_robots". Model xử lý tốt điều đó và chuyển sang nguồn khác hoặc báo cho người dùng. Chúng tôi tôn trọng robots.txt: crawler của chúng tôi tự nhận là WebReaderAPI, tuân theo các quy tắc dành cho nó hoặc cho tất cả robot, và không đọc trang mà website không cho phép. Trang bị từ chối không bị tính phí. Nếu một website từ chối yêu cầu của chúng tôi, chúng tôi trả lại câu trả lời của trang đó: chúng tôi không bao giờ giải CAPTCHA, đăng nhập vào tài khoản, hay tìm cách vượt qua chặn hoặc paywall. Không có phản hồi từ chối nào trong số này dùng credit.

## Function calling: các câu hỏi thường gặp

### Việc này cần Responses API hay Chat Completions?

Ví dụ dùng Chat Completions với tham số `tools`. Cùng định nghĩa hàm và cùng body `read_url` hoạt động với các interface OpenAI khác chấp nhận function tools; chỉ có vòng lặp xung quanh chúng thay đổi.

### Model có thể đọc nhiều trang trong một lượt không?

Có. Một phản hồi có thể chứa nhiều tool call; vòng lặp chạy từng cái và trả về mọi kết quả trước khi hỏi lại model. Giữ `max_chars` thấp hơn khi model đọc nhiều trang cùng lúc.

### Khóa API có bị lộ cho model không?

Không. Khóa vẫn nằm trong môi trường của code bạn. Model chỉ thấy tên tool, description của nó và văn bản mà hàm của bạn trả về.

### Một trang bị từ chối tốn bao nhiêu?

Không tốn gì. 1 credit = đọc 1 trang không cần trình duyệt; 2 credit khi trang cần trình duyệt để render JavaScript. Yêu cầu thất bại, hoặc bị robots.txt của trang web từ chối, không bị tính phí.

---

WebReaderAPI: WebReaderAPI là web reader API cho AI agent, chuyển mọi trang web công khai thành Markdown sạch, thanh toán bằng crypto không cần tải lên giấy tờ. Credit trả trước từ 0,07 US$/1K trang không bao giờ hết hạn, và robots.txt được tôn trọng. Không cần KYC — không ID, không selfie, không giấy tờ. Thanh toán bằng crypto.
