# LangChain และ LlamaIndex: web page loader และ tool read_url

> LangChain และ LlamaIndex web page loader: tool read_url, document loader และ RAG index ขนาดเล็กที่สร้างจากการ crawl ทั้งหมดใน Python ไม่ต้อง KYC จ่ายด้วยคริปโต

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

สองวิธีในการใช้ API ใน Python AI stack: โหลดหน้าเป็นเอกสารสำหรับ retrieval หรือให้เอเจนต์มี tool `read_url` โค้ดเชื่อมต่อ 20 บรรทัดเดียวกันใช้ได้กับทั้ง LangChain และ LlamaIndex

**คำตอบสั้น — ฉันจะโหลดหน้าเว็บเข้า LangChain หรือ LlamaIndex เป็น Markdown ที่สะอาดได้อย่างไร?**

เรียก endpoint `/read` ของ **WebReaderAPI** แล้วห่อแต่ละคำตอบใน `Document`: Markdown เป็น content, `final_url` และ title เป็น metadata สำหรับเอเจนต์ ให้เปิดเผยการเรียกเดียวกันเป็น tool `read_url` หน้าเว็บละ 1 เครดิต, 2 เครดิตเมื่อใช้เบราว์เซอร์ เริ่มต้นที่ US$0.07/1K หน้า ณ ตุลาคม 2026 ไม่ต้องใช้แพ็กเกจใด ๆ ของเรา ไม่ต้อง KYC จ่ายด้วยคริปโต

## ทำไมใช้เอกสาร Markdown แทน HTML ดิบ?

เพราะ retrieval ทำงานบนข้อความ และ Markdown เก็บโครงสร้างที่สำคัญไว้ขณะที่ตัดส่วนที่เหลือทิ้ง หัวข้อยังอยู่ ดังนั้น splitter สามารถตัดตามการเปลี่ยนหัวข้อได้ ลิสต์และตารางยังอยู่ ดังนั้นขั้นตอนและสเปกจึงอยู่ด้วยกัน ส่วนนำทาง แบนเนอร์คุกกี้ และโฆษณาหายไป จึงไม่ปนเปื้อน embeddings ของคุณหรือเปลือง token

metadata มาจากการเรียกเดียวกัน: `final_url` เป็นแหล่งที่มาสำหรับอ้างอิง, `title`, `published_at` และ `language` สำหรับการกรอง

*reader.py: helper ที่ใช้ร่วมกัน (บันทึกไว้ข้างโค้ดของคุณ)*

```python
import os

import requests

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}


class PageError(Exception):
    pass


def read_page(url, **options):
    resp = requests.get(API, headers=HEADERS, params={"url": url, **options}, timeout=75)
    body = resp.json()
    if resp.status_code != 200:
        raise PageError(body["error"]["code"])
    return body

```

## ฉันจะสร้าง LangChain document loader ได้อย่างไร?

แปลงแต่ละหน้าเป็น `langchain_core.documents.Document` แล้วแบ่งตามหัวข้อด้วย `MarkdownHeaderTextSplitter` จากแพ็กเกจ `langchain-text-splitters` แต่ละ chunk เก็บเส้นทางหัวข้อไว้ใน metadata และคุณเพิ่ม URL ต้นทางเพื่อให้ทุกคำตอบชี้กลับไปยังหน้าได้

หน้าที่ถูกข้าม เช่น หน้าที่ถูก robots.txt ปฏิเสธ จะ raise `PageError` พร้อมรหัส ให้ log ไว้แล้วทำงานต่อไป

*LangChain: โหลดและแบ่งหน้า*

```python
from langchain_core.documents import Document
from langchain_text_splitters import MarkdownHeaderTextSplitter

from reader import PageError, read_page

splitter = MarkdownHeaderTextSplitter(headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")])


def load_pages(urls):
    chunks = []
    for url in urls:
        try:
            page = read_page(url)
        except PageError as exc:
            print("skipped", url, exc)
            continue
        for part in splitter.split_text(page["markdown"]):
            part.metadata.update({"source": page["final_url"], "title": page.get("title", "")})
            chunks.append(part)
    return chunks


docs = load_pages(["https://example.com/docs/install", "https://example.com/docs/configure"])
print(len(docs), "chunks", isinstance(docs[0], Document) if docs else "")

```

## ฉันจะให้เอเจนต์ LangChain มี tool read_url ได้อย่างไร?

ตกแต่งฟังก์ชันด้วย `@tool` จาก `langchain_core.tools` docstring จะกลายเป็นคำอธิบาย tool ที่โมเดลอ่าน ดังนั้นระบุว่า tool คืนอะไรและใช้เมื่อใด คืนข้อความล้วน: บรรทัดชื่อเรื่อง แหล่งที่มา และ Markdown ตัดด้วย `max_chars` ให้เหมาะกับโมเดลของคุณ

bind tool เข้ากับ chat model ใดก็ได้ที่รองรับ tool calling หรือส่งให้ agent constructor ของคุณ จากนั้นโมเดลจะเรียก `read_url` ด้วย URL จากบทสนทนาหรือจากผลการค้นหา

*LangChain: tool read_url*

```python
import os

from langchain.chat_models import init_chat_model
from langchain_core.tools import tool

from reader import PageError, read_page


@tool
def read_url(url: str, max_chars: int = 20000) -> str:
    """Read a public web page and return its main content as Markdown, with its title and source URL."""
    try:
        page = read_page(url, max_chars=max_chars)
    except PageError as exc:
        return "Could not read the page: " + str(exc)
    return "# " + (page.get("title") or url) + "\nSource: " + page["final_url"] + "\n\n" + page["markdown"]


model = init_chat_model(os.environ.get("CHAT_MODEL", "openai:gpt-4.1-mini")).bind_tools([read_url])
reply = model.invoke("Summarise https://example.com/blog/first-post in three bullet points.")
print(reply.tool_calls)

```

## ฉันจะทำแบบเดียวกันใน LlamaIndex ได้อย่างไร?

LlamaIndex ใช้คลาส `Document` ของตัวเองกับ `text` และ `metadata` และ `FunctionTool.from_defaults` เพื่อแปลงฟังก์ชันเป็น tool helper ยังคงเหมือนเดิม สร้าง index จากเอกสารด้วย `VectorStoreIndex.from_documents` ซึ่งใช้ embedding model ที่การตั้งค่า LlamaIndex ของคุณระบุ

*LlamaIndex: index การ crawl และ tool read_url*

```python
import os
import time

import requests
from llama_index.core import Document, VectorStoreIndex
from llama_index.core.tools import FunctionTool

from reader import HEADERS, PageError, read_page


def crawl_pages(start_url, limit=200):
    job = requests.post("https://webreaderapi.com/api/v1/crawl", headers=HEADERS, json={"url": start_url, "limit": limit}, timeout=30).json()
    pages, cursor = [], None
    while True:
        params = {"cursor": cursor} if cursor else {}
        res = requests.get("https://webreaderapi.com/api/v1/jobs/" + job["job_id"], headers=HEADERS, params=params, timeout=30).json()
        pages += [r for r in res["results"] if "error" not in r]
        cursor = res.get("next_cursor")
        if not cursor and res["status"] == "done":
            return pages
        if not cursor:
            time.sleep(5)


pages = crawl_pages("https://docs.example.com/")
docs = [Document(text=p["markdown"], metadata={"source": p["final_url"], "title": p.get("title", "")}) for p in pages]
index = VectorStoreIndex.from_documents(docs)
print(index.as_query_engine().query("How do I install the product?"))


def read_url(url: str, max_chars: int = 20000) -> str:
    """Read a public web page and return its main content as Markdown."""
    try:
        return read_page(url, max_chars=max_chars)["markdown"]
    except PageError as exc:
        return "Could not read the page: " + str(exc)


read_tool = FunctionTool.from_defaults(fn=read_url, name="read_url")
print(os.environ.get("CHAT_MODEL", "set CHAT_MODEL for your agent"), read_tool.metadata.name)

```

## RAG index ขนาดเล็กต้อง crawl มากแค่ไหน?

น้อยกว่าที่คุณคิด เอกสารของผลิตภัณฑ์มักมีไม่กี่ร้อยหน้า และการ crawl ที่ตั้ง `include_paths` เป็นส่วน docs จะอ่านเฉพาะส่วนนั้น ที่ 1 เครดิตต่อหน้า ไซต์ docs ขนาด 300 หน้าคิดประมาณ 300 เครดิต; 10,000 หน้า (US$3.75) รีเฟรชได้หลายครั้ง

crawl ใหม่ตามตารางที่ตรงกับความถี่ในการเปลี่ยนแปลงของแหล่งข้อมูล และเปรียบเทียบ `final_url` และ `word_count` กับการรันครั้งก่อนเพื่อ re-embed เฉพาะหน้าที่เปลี่ยน เครดิตแบบเติมเงินไม่มีวันหมดอายุ: หน้าที่ไม่ได้ใช้จะยังคงอยู่ในบัญชีของคุณจนกว่าคุณจะใช้

## LangChain และ LlamaIndex: คำถามที่พบบ่อย

### มีแพ็กเกจ WebReaderAPI สำหรับ LangChain หรือ LlamaIndex ไหม?

ไม่มี helper และ tool ในหน้านี้คือการผสานรวมทั้งหมด คุณจึงปรับแต่งได้อย่างอิสระ WebReaderAPI เป็น API HTTPS ธรรมดาที่ไคลเอนต์ HTTP ของ Python ใดก็เรียกได้

### ต้องใช้ LangChain เวอร์ชันใด?

เวอร์ชันล่าสุดใดก็ได้ที่มี `langchain_core`, `langchain-text-splitters` และ `init_chat_model` tool decorator และคลาส `Document` มีความเสถียรตลอดหลายเวอร์ชันล่าสุด

### ฉันจะหลีกเลี่ยงการอ่านหน้าที่ยังไม่เปลี่ยนแปลงซ้ำได้อย่างไร?

เก็บ `final_url`, `word_count` และวันที่อ่านแต่ละครั้ง อ่านซ้ำตามตาราง และ re-embed หน้าเฉพาะเมื่อจำนวนคำหรือ content hash เปลี่ยน การอ่านซ้ำแต่ละครั้งเสีย 1 เครดิต ดังนั้นเลือกจังหวะที่ตรงกับแหล่งข้อมูล

### ถ้ามีบางหน้าถูกปฏิเสธล่ะ?

หน้าจะ raise `PageError` พร้อมรหัสเช่น `blocked_by_robots` และไม่เสียเครดิต หากเว็บไซต์ปฏิเสธคำขอของเรา เราจะส่งคำตอบของเว็บนั้นกลับไป: เราไม่แก้ CAPTCHA ไม่เข้าสู่ระบบบัญชี และไม่พยายามหลบเลี่ยงการบล็อกหรือ paywall

---

WebReaderAPI: WebReaderAPI คือ API อ่านหน้าเว็บสำหรับ AI agent ที่แปลงหน้าเว็บสาธารณะใด ๆ เป็น Markdown สะอาด จ่ายด้วยคริปโตโดยไม่ต้องอัปโหลดบัตรประชาชน เครดิตแบบเติมเงินเริ่มต้นที่ US$0.07/1K หน้า ไม่มีวันหมดอายุ และเคารพ robots.txt ไม่ต้อง KYC — ไม่ต้องใช้บัตรประชาชน ไม่ต้องเซลฟี่ ไม่ต้องเอกสาร จ่ายด้วยคริปโต
