ไม่ต้อง KYC — ไม่ต้องใช้บัตรประชาชน ไม่ต้องเซลฟี่ ไม่ต้องใช้เอกสาร จ่ายด้วยคริปโต: BTC, USDT, USDC, ETH, SOL, LTC
ภาษา: ไทย
รับ API key

คู่มือ · Python · ประมาณ 60 บรรทัด ใช้ LLM ตัวใดก็ได้

สร้าง deep research agent ใน Python ด้วย web search API

Deep research คือ loop ไม่ใช่โมเดล คู่มือนี้จะสร้างตัวหนึ่งที่คุณอ่านจบได้ในไม่กี่นาที: วางแผนคำค้นหา ค้นหาเว็บพร้อมเนื้อหาหน้าเว็บ เก็บแต่ละแหล่งไว้ครั้งเดียว มองหาช่องว่าง และเขียนคำตอบพร้อมการอ้างอิงแบบมีหมายเลข

อัปเดตล่าสุด:

คำตอบสั้น

ฉันจะสร้าง deep research agent ใน Python ได้อย่างไร

เขียน loop ที่ถาม LLM ให้สร้างคำค้นหา รันแต่ละคำผ่าน web search API ที่คืนเนื้อหาหน้าเว็บ เก็บแต่ละแหล่งไว้ครั้งเดียว ถามคำค้นหาติดตามผล แล้วเขียนคำตอบที่มีการอ้างอิง ด้วย LLMWebSearch การค้นหาแต่ละครั้งจะคืน 3 หน้าแรกเป็น Markdown ในราคาหนึ่งเครดิต สคริปต์ด้านล่างรันหกการค้นหาต่อหนึ่งคำถาม เริ่มต้นที่ US$1.20/1K การค้นหา ไม่ต้อง KYC จ่ายด้วยคริปโต

Agent จะทำอะไร

  1. แพ็กเกจ

    ถามโมเดลให้สร้างคำค้นหาสั้น ๆ สี่คำที่ครอบคลุมคำถามด้วยกัน

  2. ค้นหา

    รันแต่ละคำค้นหาด้วย read=3 เพื่อให้ได้สามหน้าแรกกลับมาเป็น Markdown

  3. เก็บแต่ละแหล่งไว้ครั้งเดียว

    เก็บผลลัพธ์ตาม URL และข้ามหน้าที่เก็บไปแล้วหรือไม่มีข้อความ

  4. มองหาช่องว่าง

    แสดงชื่อเรื่องที่พบ到目前为止ให้โมเดลดู แล้วถามคำค้นหาใหม่สองคำเกี่ยวกับสิ่งที่ยังขาด

  5. เขียน

    ใส่หมายเลขแหล่งข้อมูลสูงสุด 12 แหล่ง แล้วขอคำตอบที่อ้างอิงเป็น [1], [2]

ต้องเตรียมอะไรก่อนเริ่ม

สามอย่าง:

  • API key ของ LLMWebSearch ใน environment variable LLMWEBSEARCH_API_KEY key จะปรากฏในแดชบอร์ดหลังซื้อแพ็กแรก
  • chat endpoint ที่รองรับ OpenAI ตัวใดก็ได้ ตั้งค่าด้วย LLM_BASE_URL, LLM_API_KEY และ LLM_MODEL ทั้งโมเดลแบบ hosted และเซิร์ฟเวอร์ในเครื่องใช้ได้
  • Python 3.9 หรือใหม่กว่า พร้อมแพ็กเกจ requests

สคริปต์ใช้ HTTP ธรรมดาสำหรับทั้งสองบริการ คุณจึงสลับโมเดลได้โดยไม่ต้องแก้โค้ดค้นหา

Python: deep_research.py
import os

import requests

SEARCH = "https://llmwebsearch.com/api/v1/search"
SEARCH_HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}
# Any OpenAI-compatible chat endpoint works here: set your own base URL, key and model name.
LLM_URL = os.environ.get("LLM_BASE_URL", "https://llm.example.com/v1") + "/chat/completions"
LLM_HEADERS = {"Authorization": "Bearer " + os.environ.get("LLM_API_KEY", "")}
MODEL = os.environ.get("LLM_MODEL", "your-model-name")


def ask_llm(prompt):
    body = {"model": MODEL, "messages": [{"role": "user", "content": prompt}]}
    resp = requests.post(LLM_URL, headers=LLM_HEADERS, json=body, timeout=120)
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]


def plan_queries(question, n=4):
    text = ask_llm(f"Write {n} short web search queries, one per line, to answer: {question}")
    queries = [line.strip("-*0123456789. ").strip() for line in text.splitlines()]
    return [q for q in queries if q][:n]


def search(query):
    body = {"q": query, "max_results": 5, "read": 3, "max_chars": 5000}
    resp = requests.post(SEARCH, headers=SEARCH_HEADERS, json=body, timeout=60)
    resp.raise_for_status()
    return resp.json()["results"]


def research(question, rounds=2):
    sources = {}  # url -> result, so the same page is never cited twice
    queries = plan_queries(question)
    for _ in range(rounds):
        for query in queries:
            for r in search(query):
                if r.get("content_status") == "ok" and r["url"] not in sources:
                    sources[r["url"]] = r
        notes = "\n".join(f"- {r['title']}" for r in sources.values())
        queries = plan_queries(f"{question}\nAlready found:\n{notes}\nWhat is still missing?", n=2)
    numbered = list(sources.values())[:12]
    context = "\n\n".join(
        f"[{i}] {r['title']} ({r['url']})\n{r['content']}" for i, r in enumerate(numbered, 1)
    )
    prompt = (
        "Answer the question using only the sources below. Cite them as [1], [2]. "
        "Say so when the sources disagree or do not cover a point.\n\n"
        f"Question: {question}\n\nSources:\n{context}"
    )
    return ask_llm(prompt), [r["url"] for r in numbered]


if __name__ == "__main__":
    answer, urls = research("What changed in the EU rules for general-purpose AI models in 2025?")
    print(answer)
    for i, url in enumerate(urls, 1):
        print(f"[{i}] {url}")

แต่ละส่วนทำงานอย่างไร

plan_queries ขอคำค้นหาสั้น ๆ จากโมเดล บรรทัดละคำ และตัดเครื่องหมาย list ออก คำค้นหาสั้น ๆ เข้ากับวิธีที่ search engine จัดอันดับหน้าเว็บได้ดีกว่าคำถามเต็มประโยค

search เรียก POST https://llmwebsearch.com/api/v1/search ด้วย max_results=5, read=3 และ max_chars=5000 ผลลัพธ์มีห้ารายการ โดยสามรายการแรกมีเนื้อหาหน้าเว็บอยู่ใน content

research รันเป็นรอบ ๆ เก็บแหล่งข้อมูลใน dictionary ที่ใช้ URL เป็น key หน้าที่พบจากสองคำค้นหาจึงนับครั้งเดียว เก็บเฉพาะผลลัพธ์ที่ content_status เท่ากับ ok เพราะคำตอบต้องอ้างอิงจากข้อความที่โมเดลอ่านได้

หลังแต่ละรอบ โมเดลจะเห็นชื่อเรื่องที่เก็บได้到目前为止และเสนอคำค้นหาใหม่สองคำสำหรับสิ่งที่ยังขาด prompt สุดท้ายใส่หมายเลขแหล่งข้อมูลสูงสุดสิบสองแหล่งและกำหนดกติกาการอ้างอิง

หนึ่งรายงานมีค่าใช้จ่ายเท่าไร

หกการค้นหาต่อคำถามด้วยการตั้งค่าเริ่มต้น: สี่ครั้งในรอบแรกและสองครั้งในรอบที่สอง เมื่อ read อยู่ที่ 3 นั่นคือหกเครดิต ค้นหา 25,000 ครั้ง ที่ US$41.25 จึงครอบคลุมมากกว่า 4,000 รายงาน

การเรียกโมเดลมีค่าใช้จ่ายเพิ่มบนบิล LLM ของคุณ: การเรียกวางแผนสามครั้งและการเรียกคำตอบยาวหนึ่งครั้งต่อรายงาน การเรียกคำตอบมีเนื้อหาสูงสุดสิบสองหน้าครั้งละ 5,000 ตัวอักษร ดังนั้นลด max_chars ลงถ้าโมเดลของคุณมีราคาแพง

ทำอย่างไรให้ค้นได้ลึกขึ้น?

เปลี่ยนตัวเลข ไม่ใช่โครงสร้าง:

  • เพิ่มรอบ rounds=4 ให้โมเดลตามช่องว่างเพิ่มอีกสองชุด
  • เพิ่มคำค้นหาต่อรอบ ปรับ n ในคำสั่งหาช่องว่างจาก 2 เป็น 4
  • จำกัดแหล่งข้อมูลให้แคบลง เพิ่ม include_domains ใน body ของการค้นหาเพื่อเจาะเว็บไซต์ทางการหรือวิชาการ
  • เอาเฉพาะเนื้อหาใหม่ เพิ่ม "time_range": "month" หรือ "topic": "news"
  • เพิ่มหน้าเว็บต่อคำค้นหา read=5 อ่านห้าหน้า ที่ 2 เครดิตต่อการค้นหา

เพิ่มกฎหยุดก่อนจะเพิ่มขีดจำกัด: จบลูปเมื่อรอบหนึ่งได้แหล่งข้อมูลใหม่น้อยกว่าสองแหล่ง

ทำอย่างไรให้เอเจนต์ปลอดภัยและสุภาพ?

ถือว่าทุกหน้าเว็บเป็นข้อความที่ไม่น่าไว้วางใจ พรอมป์ต์สุดท้ายบอกโมเดลให้ใช้แหล่งข้อมูลเป็นหลักฐานเท่านั้น; เพิ่มบรรทัดชัดเจนว่าต้องเพิกเฉยต่อคำสั่งที่อยู่ในแหล่งข้อมูล ห้ามให้แหล่งข้อมูลทริกเกอร์ tool call หรือการเขียนไฟล์

ฝั่งเว็บ ตัวอ่านของเราเคารพ robots.txt: แนะนำตัวว่าเป็น LLMWebSearch ทำตามกฎที่เว็บไซต์เขียนไว้สำหรับมันหรือสำหรับ robots ทั้งหมด และละเว้นเนื้อหาของหน้าใดก็ตามที่มันไม่ได้รับอนุญาตให้อ่าน หน้าที่ปฏิเสธการเข้าถึงจะส่งกลับมาโดยไม่มีเนื้อหา และสคริปต์ก็ข้ามไปเลย เมื่อเว็บไซต์ปิดกั้นตัวอ่านของเรา ผลลัพธ์จะกลับมาโดยไม่มีเนื้อหาและมีสถานะของเว็บไซต์: เราไม่แก้ CAPTCHA ไม่ลงชื่อเข้าใช้บัญชี และไม่หลบเลี่ยงการบล็อกหรือ paywall

มีอะไรที่อาจผิดพลาดได้?

มีสามอย่างที่เจอตอนทดสอบ:

  • คำค้นหากำกวม ถ้าแผนอ่อน ทุกรอบจะเจอหน้าเดิม ขอให้โมเดลสร้างคำค้นหาที่ใช้ชื่อและวันที่เฉพาะเจาะจง
  • แหล่งข้อมูลที่มีข้อความน้อยเกินไป บางหัวข้ออยู่หลัง paywall ขยายคำค้นหาหรืออนุญาตผลลัพธ์มากขึ้น
  • พรอมป์ต์ยาวเกินไป หน้าที่ยาวสิบสองหน้าอาจเกิน context ของโมเดลเล็ก ลด max_chars ลงหรือเก็บไว้แปดแหล่ง

ล็อกทุกคำค้นหาและ URL ที่ได้มา การอ่านล็อกนั้นคือวิธีที่เร็วที่สุดในการปรับพรอมป์ต์วางแผน

เอเจนต์วิจัยเชิงลึก: คำถามที่พบบ่อย

รันด้วยโมเดลโลคอลได้ไหม?

ได้ ถ้าเซิร์ฟเวอร์โลคอลรองรับรูปแบบ OpenAI chat-completions ตั้ง LLM_BASE_URL เป็นที่อยู่ของมัน และ LLM_MODEL เป็นชื่อโมเดล

แปลงเป็น MCP tool ได้ไหม?

ได้ ห่อ research() ใน MCP tool หรือให้เอเจนต์ของคุณใช้ search tool ธรรมดาจาก หน้า MCP แล้วปล่อยให้มันรันลูปเอง

ทำไมไม่ถาม search API ให้ตอบคำถามโดยตรงเลย?

เพราะ LLMWebSearch ไม่ได้เขียนคำตอบ API ส่งคืนแหล่งข้อมูล ไม่ใช่คำตอบที่เขียนไว้: โมเดลของคุณเองอ่านหน้าเว็บ เขียนคำตอบ และอ้างอิง URL

ดูได้อย่างไรว่าแต่ละการค้นหาใช้ไปเท่าไร?

ทุกการตอบกลับมี credits_used และ GET https://llmwebsearch.com/api/v1/credits แสดงยอดคงเหลือที่เหลืออยู่โดยไม่มีค่าใช้จ่าย

เริ่มต้นที่ US$1.20/1K การค้นหา · ไม่ต้อง KYC

รับ API key