# OpenAI function calling: ให้โมเดลมี tool search_web

> Web search สำหรับ OpenAI function calling: JSON schema ของ search_web, ลูป Responses API ใน Python และ tool เดียวกันใน Agents SDK ไม่ต้อง KYC จ่ายด้วยคริปโต

- URL: https://llmwebsearch.com/th/docs/openai/
- อัปเดตล่าสุด: 2026-10-22
- ผู้เผยแพร่: LLMWebSearch (https://llmwebsearch.com)

อธิบายฟังก์ชัน `search_web` ให้โมเดล รันการเรียกที่มันขอเทียบกับ API ของเรา แล้วส่งแหล่งอ้างอิงกลับไป โมเดลจะตอบพร้อม citation หน้านี้แสดง JSON schema, ลูป Responses API และเวอร์ชัน OpenAI Agents SDK ที่สั้นกว่า

**คำตอบสั้น — ฉันจะเพิ่ม web search ให้โมเดล OpenAI ด้วย function calling ได้อย่างไร?**

ประกาศฟังก์ชัน `search_web` พร้อม JSON schema และเมื่อโมเดลเรียกมัน ให้ POST คำค้นหาไปที่ `https://llmwebsearch.com/api/v1/search` ของ **LLMWebSearch** ส่งคืนแหล่งอ้างอิงที่มีหมายเลข พร้อม 3 หน้าแรกเป็น Markdown ในรูปของ `function_call_output` โมเดลจะตอบและอ้างอิงแหล่งเหล่านั้น การค้นหาหนึ่งครั้งมีค่า 1 เครดิต จาก US$1.20/1K การค้นหา ณ ตุลาคม 2026 ไม่ต้อง KYC จ่ายด้วยคริปโต

## สิ่งที่คุณต้องมี

| คุณลักษณะ | ค่า |
| --- | --- |
| แพ็กเกจ | `openai` และ `requests` (หรือ `openai-agents` สำหรับเวอร์ชัน Agents SDK) |
| Keys | `OPENAI_API_KEY` สำหรับโมเดล `LLMWEBSEARCH_API_KEY` สำหรับการค้นหา |
| Model | โมเดลใดก็ได้ที่รองรับ function calling ตั้งค่าใน `OPENAI_MODEL` |
| API ที่ใช้ | Responses API: `client.responses.create` พร้อม `tools` และ `input` |
| การเรียกเก็บเงินฝั่งเรา | หนึ่งเครดิตจ่ายสำหรับการค้นหาหนึ่งครั้ง: ผลลัพธ์แบบจัดอันดับสูงสุด 20 รายการ โดยอ่านหน้าเว็บของ 3 รายการแรกและส่งกลับเป็น Markdown การอ่าน 4 ถึง 10 หน้าใช้ 2 เครดิต การเรียกที่จบลงด้วยข้อผิดพลาดไม่มีค่าใช้จ่าย |

## schema ของ tool หน้าตาเป็นอย่างไร?

function tool มี `name`, `description` และ JSON Schema `parameters` เขียน description ให้ชัดเจน: tool คืนอะไร และควรอ้างอิงแหล่งด้วยหมายเลข สองพารามิเตอร์ก็เพียงพอสำหรับ agent ส่วนใหญ่: `query` และจำนวนผลลัพธ์อันดับต้นที่ต้องการแบบเต็ม `read`

โมเดลไม่เคยเห็น API key ของคุณ มันเพียงเสนอ arguments โค้ดของคุณเป็นผู้ตัดสินใจว่าจะเรียก API อย่างไรและส่งอะไรกลับไป

## ลูปการเรียกทำงานอย่างไร?

ส่งข้อความของผู้ใช้พร้อม tools ถ้าการตอบกลับมี item ชนิด `function_call` ให้ parse JSON `arguments` ของแต่ละรายการ รันการค้นหา แล้วต่อท้าย `function_call_output` ด้วย `call_id` เดียวกัน จากนั้นเรียกโมเดลอีกครั้งพร้อมรายการ input ที่ยาวขึ้น เมื่อการตอบกลับไม่มี function call ข้อความของมันคือคำตอบ

ลูปด้านล่างหยุดหลังห้ารอบ เป็นการป้องกันโมเดลที่ค้นหาไม่หยุด คู่มือ function-calling ของ OpenAI อธิบาย item `function_call` และ `function_call_output` แบบเดียวกัน อ่านเมื่อ 22 ตุลาคม 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})

```

## มีเวอร์ชันที่สั้นกว่าด้วย Agents SDK ไหม?

มี OpenAI Agents SDK เปลี่ยนฟังก์ชัน Python เป็น tool ด้วย decorator และรันลูปการเรียกให้คุณ เอกสาร tools ของมันที่อ่านเมื่อ 22 ตุลาคม 2026 แสดง decorator `@tool` จาก `agents.decorators` โดย description มาจาก docstring และ description ของแต่ละ argument มาจากส่วน `Args` ของมัน หน้าเดียวกันยังกล่าวถึงรูปแบบ `@function_tool` ด้วย

`Runner.run_sync` รัน agent จนกว่าจะได้คำตอบสุดท้าย เรียก `search_web` บ่อยเท่าที่โมเดลขอ

*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)

```

## ทำไมต้องใช้ API tool แทน web search ที่มีมาในตัวของ OpenAI?

ส่วนใหญ่เพื่อควบคุมว่าอะไรที่ model อ่านและค่าใช้จ่ายเท่าไร tool ของเราส่งแหล่งข้อมูลดิบให้โค้ดของคุณ พร้อม URL และข้อความในหน้าเว็บ คุณจึงตัดสินใจได้ว่าอะไรจะเข้าสู่ context บันทึก log ได้ และจัดเก็บได้ เราไม่ฝึกโมเดลใดๆ ด้วยคำค้นหาของคุณหรือข้อมูลที่ API ส่งกลับ และเราไม่เพิ่มกฎของเราเองต่อต้านการจัดเก็บผลลัพธ์; สิทธิ์ของเว็บไซต์ที่คุณอ่านหน้ายังคงมีผล

ราคายังคงที่ต่อการค้นหาแต่ละครั้ง แทนที่จะขึ้นกับว่า model อ่านเนื้อหาที่ดึงมามากแค่ไหน [การเปรียบเทียบ built-in tools](https://llmwebsearch.com/th/compare/built-in-web-search-tools/) วางราคาต่อครั้งของ OpenAI, Anthropic, Google และอื่นๆ ไว้เคียงกัน พร้อมวันที่

## ทำอย่างไรไม่ให้ model ค้นหามากเกินไป?

บอกใน instructions ว่า: ค้นหาหนึ่งครั้ง อ่านแหล่งข้อมูล แล้วค้นหาอีกครั้งเฉพาะเมื่อแหล่งข้อมูลขัดแย้งกันหรือไม่ตรงประเด็น จำกัดจำนวนรอบใน loop ของคุณเองเหมือนที่ script ข้างต้นทำด้วยค่าห้า

รักษา `max_chars` ให้พอประมาณ สามหน้าละ 5,000 ตัวอักษรคือประมาณ 4,000 tokens ต่อการค้นหาหนึ่งครั้ง และแต่ละรอบจะเพิ่มเข้าไปใน input ของการเรียก model ครั้งถัดไป

## OpenAI function calling: คำถามที่พบบ่อย

### ใช้ได้กับ Chat Completions API ไหม?

ได้ กับรูปแบบ `tools` แบบเก่าของ Chat Completions ซึ่ง function อยู่ใน object `function` และผลลัพธ์ส่งกลับมาเป็นข้อความ `tool` ตัวฟังก์ชันค้นหาเองไม่เปลี่ยน

### model อ่านหน้าที่พบในแหล่งข้อมูลได้ไหม?

เพิ่มฟังก์ชันที่สอง `read_urls` ที่ส่ง URL ไปยัง `https://llmwebsearch.com/api/v1/extract` การอ่านหน้าเว็บที่คุณมี URL อยู่แล้วใช้ 1 เครดิตต่อกลุ่ม 3 หน้าที่เริ่มอ่านและส่งกลับพร้อมเนื้อหา สูงสุด 20 URL ต่อการเรียก; URL ที่ถูกปฏิเสธหรือล้มเหลวไม่ถูกนับ

### ควรใช้ model ไหน?

model ใดก็ได้ที่รองรับ function calling ลองสักสองสามตัวกับคำถามของคุณเอง: คำตอบขึ้นกับแหล่งข้อมูลพอๆ กับตัว model และ model ที่เล็กกว่าก็มีค่าใช้จ่ายต่อรอบน้อยกว่า

## แหล่งที่มา

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

---

LLMWebSearch: LLMWebSearch คือ web search API สำหรับ AI agents ที่คืนผลการค้นหาที่จัดอันดับแล้วพร้อมเนื้อหาของหน้าอันดับต้นๆ ในรูปแบบ Markdown จ่ายด้วยคริปโตโดยไม่ต้องอัปโหลดเอกสารยืนยันตัวตน เครดิตแบบเติมล่วงหน้าตั้งแต่ US$1.20/1K การค้นหา ไม่มีวันหมดอายุ ไม่ต้อง KYC — ไม่ต้องใช้บัตรประชาชน ไม่ต้องเซลฟี่ ไม่ต้องใช้เอกสาร จ่ายด้วยคริปโต
