คำตอบสั้น
ทำอย่างไรให้โมเดล OpenAI อ่านหน้าเว็บด้วย function calling?
ประกาศฟังก์ชัน read_url ในลิสต์ tools แล้วรันลูป: เมื่อโมเดลคืน tool call ให้เรียก endpoint /read ของ WebReaderAPI พร้อม URL แล้วส่ง Markdown กลับไปเป็นข้อความ tool แต่ละหน้าใช้ 1 เครดิต หรือ 2 เครดิตถ้าใช้เบราว์เซอร์ เริ่มต้นที่ US$0.07/1K หน้า ณ เดือนตุลาคม 2026 ไม่ต้อง KYC จ่ายด้วยคริปโต
schema ของ read_url หน้าตาเป็นอย่างไร?
สองพารามิเตอร์ก็พอ: url ที่จะอ่าน (required) และ max_chars แบบไม่บังคับที่ให้โมเดลย่อหน้าเว็บยาวๆ ได้ ส่วน description คือส่วนสำคัญที่สุด: บอกโมเดลว่าเครื่องมือนี้คืนอะไรและใช้เมื่อไร เขียนให้ตรงข้อเท็จจริงและสั้น
เราเรียกเครื่องมือนี้ว่า read_url แทน web_fetch เพื่อเลี่ยงการชนกับเครื่องมือที่บาง agent runtime มีอยู่แล้วในชื่อนั้น
{
"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
}
}
}ลูป tool calling ทำงานอย่างไร?
ส่งบทสนทนาพร้อมลิสต์ tools ถ้าคำตอบมี tool call ให้รันแต่ละตัว เพิ่มผลลัพธ์เป็นข้อความที่มี role tool และ tool_call_id ที่ตรงกัน แล้วถามโมเดลอีกครั้ง เมื่อคำตอบกลับมาโดยไม่มี tool call นั่นคือคำตอบสุดท้าย
จำกัดจำนวนรอบไว้ สามหรือสี่รอบก็เพียงพอสำหรับคำถามเกี่ยวกับหน้าเว็บไม่กี่หน้า และเพดานนี้ช่วยปกป้องคุณจากโมเดลที่ขออ่านเพิ่มไม่หยุด
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 แบบค่าเริ่มต้นไว้ เพื่อให้เมนูและส่วนท้ายไม่หลุดเข้า context และจำกัดลูปตามข้างบน เพื่อไม่ให้คำถามเดียวกระตุ้นการอ่านหลายสิบครั้ง
ฝั่งเรา คิดค่าบริการต่อหน้า ไม่ใช่ต่อตัวอักษร: 1 เครดิต = อ่าน 1 หน้าโดยไม่ใช้เบราว์เซอร์; 2 เครดิตเมื่อหน้านั้นต้องใช้เบราว์เซอร์เพื่อเรนเดอร์ JavaScript คำขอที่ล้มเหลว หรือที่ robots.txt ของเว็บไซต์ปฏิเสธ จะไม่ถูกคิดเครดิต ผู้ช่วยฝ่ายซัพพอร์ตที่อ่าน 300 หน้าต่อวันใช้ประมาณ 9,000 เครดิตต่อเดือน อยู่ใน 10,000 หน้า (US$3.75)
schema ใช้ได้กับโมเดลอื่นไหม?
ได้ โดยแก้ wrapper เล็กน้อย API แบบ tool calling ส่วนใหญ่รับ JSON Schema สำหรับพารามิเตอร์ พร้อมชื่อและ description ของเครื่องมือ ดังนั้น read_url ย้ายข้ามผู้ให้บริการได้เลย หน้า MCP แพ็กฟังก์ชันเดียวกันสำหรับไคลเอนต์ที่พูด Model Context Protocol และ หน้า LangChain ห่อให้ใช้กับ agent ของ LangChain และ LlamaIndex
โมเดลควรเห็นอะไรเมื่อหน้าเว็บถูกปฏิเสธ?
ประโยคสั้นๆ ชัดเจน อย่างที่ลูปข้างบนคืนค่า: "Could not read the page: blocked_by_robots" โมเดลรับมือได้ดีและหันไปใช้แหล่งอื่นหรือแจ้งผู้ใช้ เราเคารพ robots.txt: crawler ของเราระบุตัวเองว่า WebReaderAPI ทำตามกฎที่เขียนไว้สำหรับมันหรือสำหรับ robot ทั้งหมด และจะไม่อ่านหน้าที่เว็บไซต์ไม่อนุญาต หน้าที่ถูกปฏิเสธจะไม่ถูกคิดเครดิต หากเว็บไซต์ปฏิเสธคำขอของเรา เราจะส่งคำตอบของเว็บนั้นกลับไป: เราไม่แก้ CAPTCHA ไม่เข้าสู่ระบบบัญชี และไม่พยายามหลบเลี่ยงการบล็อกหรือ paywall การปฏิเสธเหล่านี้ไม่ใช้เครดิตเลย
Function calling: คำถามที่พบบ่อย
ต้องใช้ Responses API หรือ Chat Completions?
ตัวอย่างใช้ Chat Completions พร้อมพารามิเตอร์ tools นิยามฟังก์ชันเดียวกันและ body read_url เดียวกันใช้ได้กับอินเทอร์เฟซ OpenAI อื่นที่รับ function tools มีแค่ลูปรอบๆ ที่เปลี่ยน
โมเดลอ่านหลายหน้าในรอบเดียวได้ไหม?
ได้ คำตอบหนึ่งอาจมี tool call หลายตัว ลูปจะรันแต่ละตัวและคืนผลลัพธ์ทั้งหมดก่อนถามโมเดลอีกครั้ง ตั้ง max_chars ให้ต่ำลงเมื่อโมเดลอ่านหลายหน้าพร้อมกัน
API key ถูกส่งให้โมเดลเห็นไหม?
ไม่ key อยู่ใน environment ของโค้ดคุณ โมเดลเห็นแค่ชื่อเครื่องมือ description และข้อความที่ฟังก์ชันของคุณคืนค่า
หน้าเว็บที่ถูกปฏิเสธคิดค่าใช้จ่ายเท่าไร?
ไม่มีเลย 1 เครดิต = อ่าน 1 หน้าโดยไม่ใช้เบราว์เซอร์; 2 เครดิตเมื่อหน้านั้นต้องใช้เบราว์เซอร์เพื่อเรนเดอร์ JavaScript คำขอที่ล้มเหลว หรือที่ robots.txt ของเว็บไซต์ปฏิเสธ จะไม่ถูกคิดเครดิต