# OpenAI function calling: cấp cho model một công cụ search_web

> Tìm kiếm web cho OpenAI function calling với JSON schema search_web, vòng lặp Responses API bằng Python và công cụ đó trong Agents SDK. Trả bằng crypto.

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

Mô tả một hàm `search_web` cho model, chạy lời gọi mà nó yêu cầu tới API của chúng tôi, và gửi các nguồn trả lại. Sau đó model trả lời kèm trích dẫn. Trang này trình bày JSON schema, vòng lặp Responses API và phiên bản ngắn hơn với OpenAI Agents SDK.

**Trả lời nhanh — Làm cách nào để thêm tìm kiếm web vào một model OpenAI với function calling?**

Khai báo một hàm `search_web` với JSON schema, và khi model gọi nó, hãy POST truy vấn tới `https://llmwebsearch.com/api/v1/search` của **LLMWebSearch**. Trả lại các nguồn đã đánh số, với 3 trang hàng đầu dưới dạng Markdown, dưới dạng `function_call_output`; model trả lời và trích dẫn chúng. Mỗi lần tìm kiếm tốn 1 credit, từ 1,20 US$/1K lượt tìm kiếm tính đến tháng 10 năm 2026. Không cần KYC; thanh toán bằng crypto.

## Những gì bạn cần

| Thuộc tính | Giá trị |
| --- | --- |
| Package | `openai` và `requests` (hoặc `openai-agents` cho phiên bản Agents SDK) |
| Khóa | `OPENAI_API_KEY` cho model, `LLMWEBSEARCH_API_KEY` cho tìm kiếm |
| Model | Bất kỳ model nào hỗ trợ function calling, được đặt trong `OPENAI_MODEL` |
| API được dùng | Responses API: `client.responses.create` với `tools` và `input` |
| Tính phí phía chúng tôi | Một credit trả cho một lượt tìm kiếm: tối đa 20 kết quả được xếp hạng, với nội dung của 3 trang đầu được đọc và trả về dưới dạng Markdown. Đọc từ 4 đến 10 trang thì tính 2 credit. Lượt gọi kết thúc bằng lỗi không tốn gì |

## Tool schema trông như thế nào?

Một function tool có một `name`, một `description` và JSON Schema `parameters`. Hãy giữ phần mô tả cụ thể: công cụ trả về cái gì, và rằng các nguồn nên được trích dẫn theo số. Hai parameter là đủ cho hầu hết các agent: `query`, và bao nhiêu kết quả hàng đầu cần `read` đầy đủ.

Model không bao giờ thấy khóa API của bạn. Nó chỉ đề xuất các đối số; mã của bạn quyết định cách gọi API và cách gửi trả lại.

## Vòng lặp gọi hoạt động thế nào?

Gửi tin nhắn của người dùng kèm theo các tool. Nếu phản hồi chứa các item kiểu `function_call`, hãy phân tích JSON `arguments` của từng item, chạy tìm kiếm, và thêm vào một `function_call_output` với cùng `call_id`. Sau đó gọi model lần nữa với danh sách đầu vào dài hơn. Khi một phản hồi không chứa lời gọi hàm nào, văn bản của nó chính là câu trả lời.

Vòng lặp bên dưới dừng sau năm vòng, một chốt chặn với model cứ tiếp tục tìm kiếm. Hướng dẫn function calling của OpenAI mô tả cùng các item `function_call` và `function_call_output`, đọc ngày 22 tháng 10 năm 2026.

*search_tool_loop.py (Responses API)*

```python
import json
import os

import requests
from openai import OpenAI

client = OpenAI()
MODEL = os.environ["OPENAI_MODEL"]  # any model that supports function calling
SEARCH = "https://llmwebsearch.com/api/v1/search"

tools = [
    {
        "type": "function",
        "name": "search_web",
        "description": "Search the live web. Returns numbered sources with URLs; the first `read` include page text. Cite sources as [1], [2].",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "What to search for, as a person would type it."},
                "read": {"type": "integer", "minimum": 0, "maximum": 10, "description": "How many top results to read in full."},
            },
            "required": ["query"],
            "additionalProperties": False,
        },
    }
]


def search_web(query, read=3):
    resp = requests.post(
        SEARCH,
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": read, "max_chars": 5000},
        timeout=60,
    )
    if resp.status_code != 200:
        return "Search failed: " + resp.json().get("error", {}).get("code", str(resp.status_code))
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


input_list = [{"role": "user", "content": "How should I size a Postgres connection pool?"}]
for _ in range(5):
    response = client.responses.create(model=MODEL, tools=tools, input=input_list)
    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        print(response.output_text)
        break
    input_list += response.output
    for item in calls:
        args = json.loads(item.arguments)
        output = search_web(args["query"], int(args.get("read", 3)))
        input_list.append({"type": "function_call_output", "call_id": item.call_id, "output": output})

```

## Có phiên bản ngắn hơn với Agents SDK không?

Có. OpenAI Agents SDK biến một hàm Python thành tool bằng một decorator và tự chạy vòng lặp gọi cho bạn. Tài liệu tools của nó, đọc ngày 22 tháng 10 năm 2026, trình bày decorator `@tool` từ `agents.decorators`, với phần mô tả lấy từ docstring và phần mô tả của từng đối số lấy từ mục `Args` của nó. Cùng trang đó cũng đề cập đến dạng `@function_tool`.

`Runner.run_sync` chạy agent cho đến khi nó tạo ra câu trả lời cuối cùng, gọi `search_web` bao nhiêu lần tùy theo model yêu cầu.

*search_agent.py (OpenAI Agents SDK)*

```python
import os

import requests
from agents import Agent, Runner
from agents.decorators import tool


@tool
def search_web(query: str, read: int = 3) -> str:
    """Search the live web and return numbered sources with their URLs.

    Args:
        query: What to search for, as a person would type it.
        read: How many top results to read in full, from 0 to 10.
    """
    resp = requests.post(
        "https://llmwebsearch.com/api/v1/search",
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": max(0, min(read, 10)), "max_chars": 5000},
        timeout=60,
    )
    resp.raise_for_status()
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


agent = Agent(
    name="Researcher",
    instructions="Answer from search_web results only and cite them as [1], [2].",
    tools=[search_web],
)
result = Runner.run_sync(agent, "How should I size a Postgres connection pool?")
print(result.final_output)

```

## Tại sao nên dùng công cụ API thay vì tìm kiếm web tích hợp của OpenAI?

Chủ yếu để kiểm soát những gì mô hình đọc và chi phí ra sao. Công cụ của chúng tôi đưa cho code của bạn các nguồn thô, kèm URL và văn bản trang, để bạn quyết định nội dung nào vào ngữ cảnh, có thể ghi log và lưu trữ. Chúng tôi không huấn luyện bất kỳ model nào trên truy vấn của bạn hay trên những gì API trả về, và chúng tôi không thêm quy tắc riêng nào chống lại việc lưu trữ kết quả; quyền của các trang có nội dung bạn đọc vẫn áp dụng.

Giá cũng được cố định theo mỗi lần tìm kiếm thay vì phụ thuộc vào lượng nội dung mô hình đọc được truy xuất. [Bảng so sánh công cụ tích hợp](https://llmwebsearch.com/vi/compare/built-in-web-search-tools/) đặt giá mỗi lần gọi của OpenAI, Anthropic, Google và các bên khác cạnh nhau, kèm ngày kiểm tra.

## Làm sao để mô hình không tìm kiếm quá nhiều?

Hãy nói rõ trong hướng dẫn: tìm một lần, đọc các nguồn, chỉ tìm lại nếu chúng mâu thuẫn hoặc lạc đề. Giới hạn số vòng lặp trong vòng lặp của chính bạn, như đoạn script ở trên với con số năm.

Giữ `max_chars` ở mức vừa phải. Ba trang 5.000 ký tự tương đương khoảng 4.000 token mỗi lần tìm kiếm, và mỗi vòng lại cộng chúng vào đầu vào của lần gọi mô hình tiếp theo.

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

### Cái này có hoạt động với Chat Completions API không?

Có, với định dạng `tools` cũ hơn của Chat Completions, trong đó function nằm trong một đối tượng `function` và kết quả trả về dưới dạng các message `tool`. Bản thân function tìm kiếm không thay đổi.

### Mô hình có thể đọc một trang mà nó tìm thấy trong một nguồn không?

Thêm một function thứ hai, `read_urls`, gửi URL tới `https://llmwebsearch.com/api/v1/extract`. Đọc các trang mà bạn đã có URL tốn 1 credit cho mỗi nhóm 3 trang bắt đầu được trả về kèm nội dung, tối đa 20 URL mỗi lượt gọi; các URL bị từ chối hoặc thất bại không được tính.

### Nên dùng mô hình nào?

Bất kỳ mô hình nào hỗ trợ function calling. Hãy thử hai hoặc ba mô hình với câu hỏi của chính bạn: câu trả lời phụ thuộc vào các nguồn cũng như vào mô hình, và một mô hình nhỏ hơn tốn ít chi phí hơn mỗi vòng.

## Nguồn

1. [Function calling](https://developers.openai.com/api/docs/guides/function-calling) — OpenAI API docs (read 2026-10-22)
2. [Công cụ (OpenAI Agents SDK)](https://openai.github.io/openai-agents-python/tools/) — OpenAI Agents SDK docs (read 2026-10-22)

---

LLMWebSearch: LLMWebSearch là một web search API cho AI agent, trả về kết quả đã xếp hạng kèm nội dung của các trang hàng đầu ở định dạng Markdown, thanh toán bằng crypto mà không cần tải lên giấy tờ tùy thân. Credit trả trước từ 1,20 US$/1K lượt tìm kiếm không bao giờ hết hạn. Không cần KYC — không ID, không selfie, không giấy tờ. Thanh toán bằng crypto.
