# LangChain 和 LlamaIndex 中的网页搜索：一个工具和一个 retriever

> 面向 LangChain 和 LlamaIndex 的网页搜索：一个 search_web 工具、一个每读取一页就返回一个 Document 的 retriever，以及一个 LlamaIndex FunctionTool。无需 KYC，支持加密货币支付。

- URL: https://llmwebsearch.com/zh/docs/langchain/
- 最后更新: 2026-10-22
- 发布者: LLMWebSearch (https://llmwebsearch.com)

两种形式可覆盖大多数框架。工具让 agent 自行决定何时搜索。retriever 把实时网页接入检索链，其中每个被读取的页面都会变成一个 Document，并在 metadata 中带上其 URL。

**快速回答 — 如何为 LangChain 或 LlamaIndex 添加实时网页搜索？**

将 **LLMWebSearch** 的 `/search` 调用包装进 LangChain `@tool`、LangChain retriever 或 LlamaIndex `FunctionTool`。它们都会返回带排名的来源，其中前 3 个页面为 Markdown 及其 URL，可直接用于引用。无需安装我们的包：下面的代码就是集成方式。一次搜索花费 1 积分，低至 US$1.20/千次搜索（截至 2026 年 10 月）。无需 KYC；用加密货币支付。

## 各个包装器的用途

| 属性 | 值 |
| --- | --- |
| LangChain 工具 | agent 在判断需要网页时调用 `search_web` |
| LangChain retriever | 链会为每个问题获取最新文档，无需询问 |
| LlamaIndex FunctionTool | 同一个 `search_web` 函数，供 LlamaIndex agents 使用 |
| 软件包 | `langchain-core` 或 `llama-index-core`，外加 `requests` |
| 密钥 | 环境变量中的 `LLMWEBSEARCH_API_KEY` |
| 计费 | 1 积分支付一次查询：最多 20 条排名结果，其中前 3 条的页面会被读取并以 Markdown 返回。读取 4 到 10 个页面为 2 积分。以错误结束的调用不收费 |

## 如何为 LangChain agent 构建搜索工具？

用 `langchain_core.tools` 中的 `@tool` 装饰一个函数。LangChain 会读取名称、带类型的参数和 docstring 来向模型描述该工具，因此请保持 docstring 简短精确。函数返回一个带编号来源的字符串，适用于所有聊天模型，并让 URL 紧邻文本。

用 `.invoke()` 直接调用它来测试，然后把它传入你 agent 的 tools 列表。

*LangChain 工具：search_web*

```python
import os

import requests
from langchain_core.tools import tool

API = "https://llmwebsearch.com/api/v1/search"
HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}


@tool
def search_web(query: str, read: int = 3) -> str:
    """Search the live web. Returns numbered sources with URLs; the first `read` include page text."""
    body = {"q": query, "max_results": 5, "read": max(0, min(read, 10)), "max_chars": 5000}
    resp = requests.post(API, headers=HEADERS, json=body, timeout=60)
    resp.raise_for_status()
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


print(search_web.invoke({"query": "postgres connection pool size"})[:500])

```

## 如何把实时网页用作 retriever？

继承 `BaseRetriever`，并为每个读取的页面返回一个 `Document`。页面文本放在 `page_content` 中；URL、标题、排名和日期放在 `metadata` 中，需要引用来源的链会在这里查找它们。无内容的结果会被跳过，因为 retriever 应当交给模型可以引用的文本。

retriever 会对每个问题运行。对于关于时事话题的问答链来说这没问题，但对于大多数轮次都无需搜索的聊天来说则很浪费；这种情况下请使用工具。

*LangChain retriever：LLMWebSearchRetriever*

```python
import os
from typing import List

import requests
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from langchain_core.retrievers import BaseRetriever


class LLMWebSearchRetriever(BaseRetriever):
    """Live web search results as Documents, one per page that was read."""

    max_results: int = 5
    read: int = 3
    max_chars: int = 6000

    def _get_relevant_documents(self, query: str, *, run_manager: CallbackManagerForRetrieverRun) -> List[Document]:
        resp = requests.post(
            "https://llmwebsearch.com/api/v1/search",
            headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
            json={"q": query, "max_results": self.max_results, "read": self.read, "max_chars": self.max_chars},
            timeout=60,
        )
        resp.raise_for_status()
        docs = []
        for r in resp.json()["results"]:
            if r["content_status"] != "ok":
                continue
            meta = {"source": r["url"], "title": r["title"], "position": r["position"], "published_at": r.get("published_at")}
            docs.append(Document(page_content=r["content"], metadata=meta))
        return docs


retriever = LLMWebSearchRetriever(read=3)
for doc in retriever.invoke("pgbouncer transaction mode limitations"):
    print(doc.metadata["position"], doc.metadata["source"], len(doc.page_content))

```

## 如何把同样的搜索提供给 LlamaIndex agent？

编写一个普通函数，并用 `llama_index.core.tools` 中的 `FunctionTool.from_defaults` 包装它。LlamaIndex 会根据函数名、签名和 docstring 构建工具的名称和描述。调用该工具会返回一个 `ToolOutput`，其中 `content` 是 agent 将读取的文本。

该函数与 LangChain 版本相同，因此同时使用这两个框架的团队可以共享它。

*LlamaIndex：FunctionTool*

```python
import os

import requests
from llama_index.core.tools import FunctionTool


def search_web(query: str, read: int = 3) -> str:
    """Search the live web and return numbered sources; the first `read` include their page text."""
    resp = requests.post(
        "https://llmwebsearch.com/api/v1/search",
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": max(0, min(read, 10)), "max_chars": 5000},
        timeout=60,
    )
    resp.raise_for_status()
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


search_tool = FunctionTool.from_defaults(fn=search_web)
print(search_tool.metadata.name)
print(search_tool.call(query="postgres connection pool size").content[:300])

```

## 如何控制上下文窗口？

在调用 API 时设置 `max_chars`，而不是事后裁剪：传输的数据更少，框架也不会保留长版本。每页 5,000 个字符、3 页约为 4,000 个 token，对大多数模型来说很充裕。

对于将实时网络与你自己的文档结合的检索链，给网页文档较低的权重或单独的提示词部分。网页会变化，也可能出错；你自己的文档通常是参考依据。

## 我可以把检索器返回的内容存入向量数据库吗？

可以，对我们来说没问题。我们不会用你的查询或 API 返回的内容训练任何模型，也不会自行添加任何禁止存储结果的规则；你读取的页面所属网站的权利仍然适用。将 URL 和 `published_at` 与每个分块一起存储，这样 agent 可以引用该页面，你也可以删除过期的分块。

大多数团队会将高频问题的网页结果缓存一天或一周。这能减少重复搜索，每避免一次搜索就节省一个积分。

## LangChain 和 LlamaIndex：常见问题

### 有 langchain-llmwebsearch 包吗？

没有。我们未发布任何包。本页的代码足够短，可以直接自己维护：复制它、修改默认值，并保存在你的代码库中。

### 我可以把工具改成异步的吗？

可以。将 `requests` 替换为 `httpx.AsyncClient`，并用 `async def` 定义函数。LangChain 的 `@tool` 直接装饰异步函数；在 LlamaIndex 中，将异步版本作为 `async_fn` 传给 `FunctionTool.from_defaults`。

### 如何读取 agent 在其他地方找到的页面？

添加第二个工具，将 URL 提交到 `https://llmwebsearch.com/api/v1/extract`。读取你已持有 URL 的页面：每开始一组 3 个返回内容的页面计 1 积分，每次调用最多 20 个 URL；被拒绝或失败的 URL 不计入。[extract 参考](https://llmwebsearch.com/zh/docs/extract/) 展示了该请求。

---

LLMWebSearch: LLMWebSearch 是一款面向 AI 智能体的网页搜索 API，返回排序后的搜索结果，并附带热门页面的 Markdown 格式内容，采用加密货币支付，无需上传证件。预付费积分低至 US$1.20/千次搜索，永不过期。无 KYC——无需证件、无需自拍、无需提交任何文件。加密货币支付。
