惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
C
Check Point Blog
博客园 - 司徒正美
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
MyScale Blog
MyScale Blog
人人都是产品经理
人人都是产品经理
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
大猫的无限游戏
大猫的无限游戏
Last Week in AI
Last Week in AI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
宝玉的分享
宝玉的分享
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
云风的 BLOG
云风的 BLOG
A
About on SuperTechFans
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
爱范儿
爱范儿
N
Netflix TechBlog - Medium
WordPress大学
WordPress大学

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
SerpBase + LangChain: a 30-line DocumentLoader that calls...
dodou · 2026-06-27 · via DEV Community

dodou

Subtitle: A drop-in loader for LangChain that fetches live Google results as LangChain Document objects, ready for any RAG pipeline.

Meta description (~155 chars): A 30-line custom LangChain DocumentLoader for live Google results via SerpBase. Returns Document objects with source, title, rank metadata. Standard library only.

Target length: ~700 words.

Angle fit (per §3.5): #7 "SerpBase + [framework]" — LangChain recipe. Distinct from the on-site "SERP API for AI Agents" post (which is a feature overview) and from the MCP article in this series (which is a different agent stack). This post is a drop-in component.

Suggested target publications (DR 30-70, AI/RAG audience):

  • LangChain blog
  • LlamaIndex blog
  • Pinecone blog (Learn section)
  • Weaviate blog
  • dev.to (AI / LangChain columns)
  • Towards Data Science

Slug convention (for the host): langchain-document-loader-google-serp or serpbase-langchain-recipe if kebab.


LangChain ships with 100+ document loaders. Web pages, PDFs, Notion, Slack, GitHub. As of mid-2026 there is still no first-party loader for live Google results, which is exactly what most RAG systems need when the knowledge cutoff is the bottleneck.

This post shows a 30-line custom DocumentLoader that fetches Google results via the SerpBase API and returns them as LangChain Document objects, ready to feed into a splitter, vector store, or retriever.

The loader

import os
import json
import urllib.request
from typing import Iterator
from langchain_core.documents import Document
from langchain_core.document_loaders import BaseLoader

API_KEY = os.environ["SERPBASE_API_KEY"]
BASE = "https://api.serpbase.dev"


class SerpBaseSearchLoader(BaseLoader):
    def __init__(self, query: str, hl: str = "en", gl: str = "us", top_k: int = 5):
        self.query = query
        self.hl = hl
        self.gl = gl
        self.top_k = top_k

    def _search(self) -> dict:
        req = urllib.request.Request(
            f"{BASE}/google/search",
            data=json.dumps({"q": self.query, "hl": self.hl, "gl": self.gl}).encode(),
            headers={"Content-Type": "application/json", "X-API-Key": API_KEY},
            method="POST",
        )
        with urllib.request.urlopen(req, timeout=30) as r:
            return json.loads(r.read())

    def lazy_load(self) -> Iterator[Document]:
        data = self._search()
        for i, r in enumerate(data.get("organic", [])[: self.top_k], 1):
            yield Document(
                page_content=r.get("snippet", ""),
                metadata={
                    "source": r.get("link"),
                    "title": r.get("title"),
                    "rank": i,
                    "query": self.query,
                },
            )


# Usage
loader = SerpBaseSearchLoader("LangChain RAG 2026", top_k=8)
docs = list(loader.lazy_load())

lazy_load is the method LangChain calls when the loader is iterated. Each organic result becomes a Document with page_content set to the snippet and metadata carrying the source URL, title, and rank. Standard library only.

Drop it into a RAG pipeline

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)
splits = splitter.split_documents(docs)

vectorstore = Chroma.from_documents(splits, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

Each Document already carries the source URL in metadata["source"], so when the retriever returns chunks to the LLM, the source is preserved end-to-end. Citation at generation time is a one-line addition to the prompt.

Cost math

Workload Queries / day Queries / month Tier Cost
Personal RAG 30 900 Starter Boost $3
Team copilot 300 9,000 Starter $10
Production chat 3,000 90,000 Growth $50

Standard credits on Starter, Growth, Pro, Business, and Enterprise never expire. The $3 Starter Boost is a 1-month entry pack, available once per account per month.

Why use the loader vs raw curl

Three reasons that matter once you're past the prototype:

1. Standard interface. Anything that takes a BaseLoader (splitters, vector stores, RAG chains, evaluators) works without modification.

2. Metadata preservation. source, title, rank, and query travel with the chunk. Citation at generation time is a one-line addition to the prompt.

3. Composition. You can chain multiple SerpBase loaders for multi-query retrieval — SerpBaseSearchLoader("q1") + SerpBaseSearchLoader("q2") + a web loader — and treat them as one document stream.

What this does not do

  • JavaScript-rendered pages. This loader pulls Google SERP data, not arbitrary page content. For page content, pair it with a WebBaseLoader or PlaywrightLoader.
  • Multi-hop retrieval. Each loader call is one search. For multi-hop, call the loader multiple times in a chain.
  • Knowledge graph entities. The snippet is the page content; the knowledge_graph block from the API response is not extracted into Documents.

Try it

New accounts get 100 free searches on signup, no card. Full endpoint reference is in the SerpBase docs. For agents that don't speak LangChain, the SerpBase agent skill ships a similar pattern as a portable skill.