Không cần KYC — không ID, không ảnh selfie, không giấy tờ. Thanh toán bằng crypto: BTC, USDT, USDC, ETH, SOL, LTC
Ngôn ngữ: Tiếng Việt
Lấy khóa API

Hướng dẫn · Python · khoảng 60 dòng, bất kỳ LLM nào

Xây dựng deep research agent bằng Python với một web search API

Deep research là một vòng lặp, không phải một mô hình. Hướng dẫn này xây dựng một vòng lặp bạn có thể đọc trong vài phút: nó lập kế hoạch truy vấn, tìm kiếm web kèm nội dung trang, giữ mỗi nguồn một lần, tìm các khoảng trống và viết câu trả lời với trích dẫn được đánh số.

Cập nhật lần cuối: · 6 phút đọc

Trả lời nhanh

Làm sao để xây dựng một deep research agent bằng Python?

Viết một vòng lặp yêu cầu LLM đưa ra các truy vấn tìm kiếm, chạy từng truy vấn qua một web search API trả về nội dung trang, giữ mỗi nguồn một lần, yêu cầu các truy vấn tiếp theo, rồi viết câu trả lời có trích dẫn. Với LLMWebSearch, mỗi lần tìm kiếm trả về 3 trang đầu dưới dạng Markdown với một credit; đoạn script bên dưới chạy sáu lần tìm kiếm cho mỗi câu hỏi. Từ 1,20 US$/1K lượt tìm kiếm, không cần KYC, thanh toán bằng crypto.

Agent sẽ làm gì?

  1. Gói

    Yêu cầu mô hình đưa ra bốn truy vấn ngắn cùng bao quát câu hỏi.

  2. Tìm kiếm

    Chạy từng truy vấn với read=3, để ba trang đầu trả về dưới dạng Markdown.

  3. Giữ mỗi nguồn một lần

    Lưu kết quả theo URL và bỏ qua các trang đã thu thập hoặc không có nội dung.

  4. Tìm khoảng trống

    Cho mô hình xem các tiêu đề đã tìm thấy và yêu cầu hai truy vấn về những gì còn thiếu.

  5. Viết

    Đánh số tối đa 12 nguồn và yêu cầu một câu trả lời trích dẫn chúng dưới dạng [1], [2].

Tôi cần chuẩn bị gì trước khi bắt đầu?

Ba thứ:

  • Một khóa API LLMWebSearch trong biến môi trường LLMWEBSEARCH_API_KEY. Khóa xuất hiện trong dashboard sau gói đầu tiên của bạn.
  • Một chat endpoint tương thích OpenAI bất kỳ, đặt bằng LLM_BASE_URL, LLM_API_KEY và LLM_MODEL. Mô hình lưu trữ và máy chủ cục bộ đều dùng được.
  • Python 3.9 trở lên với gói requests.

Script dùng HTTP thuần cho cả hai dịch vụ, nên bạn có thể đổi mô hình mà không cần sửa code tìm kiếm.

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}")

Từng phần hoạt động thế nào?

plan_queries yêu cầu mô hình đưa ra các truy vấn ngắn, mỗi dòng một truy vấn, và loại bỏ dấu đầu dòng. Truy vấn ngắn khớp với cách công cụ tìm kiếm xếp hạng trang tốt hơn so với câu hỏi đầy đủ.

search gọi POST https://llmwebsearch.com/api/v1/search với max_results=5, read=3 và max_chars=5000. Phản hồi liệt kê năm kết quả; ba kết quả đầu mang nội dung trang trong content.

research chạy các vòng. Nó giữ nguồn trong một dictionary khóa theo URL, nên một trang được hai truy vấn tìm ra chỉ tính một lần. Chỉ các kết quả có content_status bằng ok được giữ lại, vì câu trả lời phải dựa trên nội dung mà mô hình đọc được.

Sau mỗi vòng, mô hình xem các tiêu đề đã thu thập và đề xuất hai truy vấn mới cho những gì còn thiếu. Prompt cuối cùng đánh số tối đa mười hai nguồn và đặt ra quy tắc trích dẫn.

Một báo cáo tốn bao nhiêu?

Sáu lần tìm kiếm cho mỗi câu hỏi với cài đặt mặc định: bốn ở vòng đầu và hai ở vòng thứ hai. Với read ở mức 3, đó là sáu credit. 25.000 lượt tìm kiếm với 41,25 US$ vì vậy đủ cho hơn 4.000 báo cáo.

Các lần gọi mô hình tốn thêm trên hóa đơn LLM của bạn: ba lần gọi lập kế hoạch và một lần gọi trả lời dài cho mỗi báo cáo. Lần gọi trả lời mang tối đa mười hai trang, mỗi trang 5.000 ký tự, nên hãy giảm max_chars nếu mô hình của bạn đắt.

Làm thế nào để tôi khiến nó đào sâu hơn?

Thay đổi các con số, không thay đổi cấu trúc:

  • Nhiều vòng hơn. rounds=4 cho phép model truy thêm hai bộ khoảng trống nữa.
  • Nhiều truy vấn hơn mỗi vòng. Tăng n trong lệnh gọi tìm khoảng trống từ 2 lên 4.
  • Nguồn hẹp hơn. Thêm include_domains vào phần body của tìm kiếm để chỉ lấy các trang chính thức hoặc học thuật.
  • Chỉ tài liệu gần đây. Thêm "time_range": "month" hoặc "topic": "news".
  • Nhiều trang hơn mỗi truy vấn. read=5 đọc năm trang, với 2 credit cho mỗi lần tìm kiếm.

Thêm một quy tắc dừng trước khi nâng các giới hạn: kết thúc vòng lặp khi một vòng mang về ít hơn hai nguồn mới.

Làm thế nào để tôi giữ agent an toàn và lịch sự?

Coi mọi trang là văn bản không đáng tin. Prompt cuối cùng bảo model chỉ dùng các nguồn làm bằng chứng; thêm một dòng rõ ràng rằng phải bỏ qua mọi chỉ dẫn nằm trong nguồn. Đừng bao giờ để một nguồn kích hoạt lệnh gọi công cụ hay ghi tệp.

Về phía web, Trình đọc của chúng tôi tôn trọng robots.txt: nó tự giới thiệu là LLMWebSearch, tuân theo các quy tắc mà một trang viết cho nó hoặc cho tất cả robot, và bỏ qua nội dung của bất kỳ trang nào nó không được phép đọc. Những trang từ chối truy cập sẽ trả về mà không có nội dung và script chỉ đơn giản bỏ qua chúng. Khi một trang từ chối trình đọc của chúng tôi, kết quả trả về không có nội dung kèm trạng thái của trang: chúng tôi không bao giờ giải CAPTCHA, đăng nhập vào tài khoản hay lách qua một chặn chặn hoặc paywall.

Có thể có gì sai?

Ba điều xuất hiện khi thử nghiệm:

  • Truy vấn mơ hồ. Nếu kế hoạch yếu, mỗi vòng đều tìm ra cùng những trang đó. Yêu cầu model đưa ra các truy vấn dùng tên và ngày cụ thể.
  • Quá ít nguồn có văn bản. Một số chủ đề nằm sau paywall. Mở rộng truy vấn hoặc cho phép nhiều kết quả hơn.
  • Prompt quá dài. Mười hai trang dài có thể vượt quá context của một model nhỏ. Giảm max_chars hoặc giữ tám nguồn.

Ghi log mỗi truy vấn và các URL mà nó trả về. Đọc log đó là cách nhanh nhất để cải thiện prompt lập kế hoạch.

Agent nghiên cứu sâu: câu hỏi thường gặp

Tôi có thể chạy cái này với model cục bộ không?

Có, nếu server cục bộ nói định dạng chat-completions của OpenAI. Đặt LLM_BASE_URL thành địa chỉ của nó và LLM_MODEL thành tên model.

Tôi có thể biến nó thành công cụ MCP không?

Có. Bọc research() trong một công cụ MCP, hoặc cấp cho agent công cụ tìm kiếm đơn giản từ trang MCP và để nó tự chạy vòng lặp.

Tại sao không hỏi thẳng API tìm kiếm để lấy câu trả lời?

Vì LLMWebSearch không viết câu trả lời. API trả về các nguồn, không phải một câu trả lời được viết sẵn: model của chính bạn đọc các trang, viết câu trả lời và trích dẫn các URL.

Làm thế nào để tôi xem mỗi lần tìm kiếm tốn bao nhiêu?

Mỗi phản hồi đều kèm credits_used, và GET https://llmwebsearch.com/api/v1/credits hiển thị số dư còn lại của bạn mà không tốn phí.

Từ 1,20 US$/1K lượt tìm kiếm · không cần KYC

Lấy khóa API