快速回答
如何用 Python 构建 deep research agent?
写一个循环:让 LLM 给出搜索查询,将每个查询通过返回页面文本的网页搜索 API 执行,每个来源只保留一次,再请求后续查询,最后写出带引用的答案。使用 LLMWebSearch 时,每次搜索以一个积分返回前 3 页的 Markdown;下面的脚本每个问题运行六次搜索。低至 US$1.20/千次搜索,无需 KYC,加密货币支付。
agent 会做什么?
套餐
让模型给出四个简短的查询,合起来覆盖该问题。
搜索
用
read=3运行每个查询,这样前三个页面会以 Markdown 返回。每个来源只保留一次
按 URL 存储结果,跳过已收集的页面或没有文本的页面。
寻找缺口
把目前已找到的标题展示给模型,并请它针对缺失内容给出两个查询。
撰写
最多编号 12 个来源,并要求答案以 [1]、[2] 形式引用它们。
开始前我需要准备什么?
三样东西:
- 一个 LLMWebSearch API 密钥,放在环境变量
LLMWEBSEARCH_API_KEY中。首次购买积分包后,密钥会出现在仪表盘中。 - 任意 OpenAI 兼容的 chat endpoint,通过
LLM_BASE_URL、LLM_API_KEY和LLM_MODEL设置。托管模型和本地服务器都可以。 - Python 3.9 或更高版本,以及
requests包。
脚本对两个服务都使用普通 HTTP,因此你可以在不改动搜索代码的情况下更换模型。
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 让模型给出简短查询,每行一个,并去掉列表标记。相比完整问句,简短查询更契合搜索引擎对页面的排序方式。
search 调用 POST https://llmwebsearch.com/api/v1/search,传入 max_results=5、read=3 和 max_chars=5000。响应列出五个结果;前三个在 content 中带有页面文本。
research 运行各轮。它把来源保存在以 URL 为键的字典中,因此被两个查询找到的页面只计一次。只保留 content_status 等于 ok 的结果,因为答案必须建立在模型能读到的文本上。
每轮之后,模型查看目前已收集的标题,并针对缺失内容提出两个新查询。最终 prompt 最多编号十二个来源,并设定引用规则。
一份报告要花多少钱?
默认设置下每个问题六次搜索:第一轮四次,第二轮两次。read 为 3 时,即六个积分。因此 US$41.25 的 25,000 次查询 可覆盖 4,000 多份报告。
模型调用会在你的 LLM 账单上额外计费:每份报告三次规划调用和一次长答案调用。答案调用最多携带十二页、每页 5,000 个字符,如果你的模型较贵,就调低 max_chars。
如何让它挖得更深?
改数字,不改结构:
- 更多轮次。
rounds=4让模型多追两组缺口。 - 每轮更多查询。 把找缺口那次调用里的
n从 2 提到 4。 - 更窄的来源。 在搜索请求体里加
include_domains,限定官网或学术站点。 - 只要近期材料。 加
"time_range": "month"或"topic": "news"。 - 每次查询读更多页。
read=5会读五个页面,每次搜索 2 积分。
提高上限之前先加一条停止规则:某一轮带来的新来源少于两个时就结束循环。
如何让 agent 既安全又守规矩?
把每个页面都当作不可信文本。最终提示词会告诉模型只把来源当证据用;再加一行明确说明:来源里的指令一律忽略。绝不要让来源触发工具调用或文件写入。
网页这一侧,我们的读取器遵守 robots.txt:它会以 LLMWebSearch 表明身份,遵守网站为它或为所有机器人写下的规则,并排除任何它无权读取的页面内容。拒绝访问的页面会返回空内容,脚本直接跳过。当网站拒绝我们的读取器时,结果会不带内容返回,并附上该网站的状态:我们绝不破解 CAPTCHA、不登录账户,也不绕过封锁或付费墙。
哪里会出问题?
测试中出现三种情况:
- 查询含糊。 规划太弱时,每一轮都找到同样的页面。让模型给出带具体名称和日期的查询。
- 带正文的来源太少。 有些主题藏在付费墙后面。放宽查询或允许多更多结果。
- 提示词过长。 十二个长页面可能超出小模型的上下文。调低
max_chars或只保留八个来源。
记录每次查询和它返回的 URL。读这份日志是改进规划提示词最快的办法。
深度研究 agent:常见问题
能配本地模型跑吗?
可以,只要本地服务器支持 OpenAI chat-completions 格式。把 LLM_BASE_URL 设成它的地址,LLM_MODEL 设成模型名。
能把它做成 MCP 工具吗?
可以。把 research() 包进一个 MCP 工具,或者把 MCP 页面 上的纯搜索工具交给你的 agent,让它自己跑循环。
为什么不直接向搜索 API 要答案?
因为 LLMWebSearch 不写答案。API 返回的是来源,而不是写好的答案:由你自己的模型读取页面、撰写回复并引用 URL。
怎么查看每次搜索花了多少?
每个响应都带有 credits_used,而 GET https://llmwebsearch.com/api/v1/credits 会免费显示你的剩余余额。