DuckDuckGo search node with duckduckgo-search

Every research pipeline starts with a query. We will use DuckDuckGo through the duckduckgo-search package. Note the two spellings: you install duckduckgo-search with pip, and you import it as duckduckgo_search with an underscore. It is free, it needs no API key, and it returns titles, URLs, and snippets in a clean shape we can feed straight into the next node.

mini-perplexity.ipynb
python
# pip install duckduckgo-search
from duckduckgo_search import DDGS

# A raw call so you can see the shape of the data
ddgs = DDGS()
results = ddgs.text(
    "What is the latest model from OpenAI?",
    max_results=5,
)

for r in results:
    print(r["title"])
    print(r["href"])
    print(r["body"][:120])
    print("---")

Each result is a dict with title, href, and body. The body is a snippet, not the full page. We scrape the page separately when wiring the fetch node.

mini-perplexity.ipynb
python
def search_node(state: ResearchState) -> ResearchState:
    """Node for performing web search."""
    print("Searching the web...")
    state["current_step"] = "searching"

    try:
        ddgs = DDGS()
        results = list(ddgs.text(
            state["question"],
            max_results=5,
            region="wt-wt",
            safesearch="moderate",
        ))
        state["search_results"] = results
        print(f"Found {len(results)} search results")

    except Exception as e:
        print(f"Search error: {e}")
        state["search_results"] = []

    return state

The node signature is the LangGraph convention: take state, mutate it, return it. We wrap the DDGS call in a try block so a bad request does not kill the whole graph.

The "wt-wt" region code means worldwide with no localization. Without it, DuckDuckGo tries to guess your location and biases results toward that region. For a research tool you usually want the broadest possible result set, so worldwide is the safer default.

Quiz: Quiz

Loading practice…

AI prompt: Try it: pick good search queries

Loading practice…