LangChain DeepAgents 接入 Tavily Search API 构建深度研究智能体|附完整代码实现|收藏级教程 1. 为什么需要 DeepAgents 来做深度研究智能体如果你用过普通的 ReAct Agent 做资料检索大概率遇到过这种情况问一个稍微复杂点的问题比如「对比埃菲尔铁塔和哈利法塔的高度并写份报告」Agent 搜了两下就开始编中间步骤全乱最后输出一段看起来像模像样但数据对不上的文字。这不是模型不行是普通 Agent 缺少任务规划和过程管理能力。LangChain 团队开源的 DeepAgents 就是冲着这个痛点来的。它基于 LangChain 和 LangGraph 构建内置了任务规划write_todos、文件系统、子智能体这几样能力专门处理长周期、高复杂度的任务。简单说普通 Agent 是「想到哪做到哪」DeepAgents 是「先列待办、再逐条执行、做完打勾」整个过程你能看得见。这套东西适合谁我梳理了三类第一类是做研究型应用的开发者需要 Agent 自动完成多步检索、交叉验证、生成结构化报告第二类是想把搜索能力接进自己系统的团队Tavily Search API 提供的是面向 AI 优化的搜索结果比直接爬网页干净得多第三类是已经在用 Cherry Studio、OpenWebUI 这类客户端想给自己搭一个「深度研究」按钮的人。这篇要做的就是把 Tavily Search API 封装成 MCP Server用 DeepAgents 编排它最后再包一层 OpenAI 协议接口让任何支持 OpenAI 协议的客户端都能调用。整条链路我会给出可复制的依赖清单、配置代码和验证动作你跟着敲一遍就能跑通。核心检索词先明确LangChain DeepAgents 接入 Tavily Search API 构建深度研究智能体本质是「规划型 Agent 搜索工具 协议封装」三件事的组合。下面从环境准备开始。2. 前置准备依赖清单与 TaoToken 接入配置在写 Agent 代码之前得先把模型调用这条链路打通。DeepAgents 本身不绑定模型它通过 LangChain 的 init_chat_model 来初始化所以只要你的模型服务兼容 OpenAI 协议就能用。这里我用 TaoToken 来做模型接入原因是它同时提供 OpenAI 兼容接口和 Claude Code 这类编码场景的接入方式一个 Key 能覆盖对话和 Agent 两种用途省得来回切配置。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 注意 API 地址后面不加 UTM 参数。先装依赖。我实测下来这套版本组合是能跑通的直接抄pip install tavily-python0.7.12 \ mcp1.9.2 \ langchain1.1.3 \ langchain-mcp-adapters0.1.4 \ langgraph1.0.5 \ fastapi0.115.14 \ uvicorn0.34.0装完之后确认一下 deepagents 是否可用pip install deepagents python -c from deepagents import create_deep_agent; print(ok)接下来配置模型环境变量。DeepAgents 走的是 LangChain 的 init_chat_model所以设置 OPENAI_BASE_URL 和 OPENAI_API_KEY 就行export OPENAI_BASE_URLhttps://taotoken.net/api export OPENAI_API_KEY你的TaoToken Key如果你是在代码里写死就放在 import 之前import os os.environ[OPENAI_BASE_URL] https://taotoken.net/api os.environ[OPENAI_API_KEY] 你的TaoToken Key模型 ID 这块要注意DeepAgents 对模型的工具调用能力有要求建议选支持 function calling 的模型。在 init_chat_model 里写成openai:模型名的格式比如from langchain.chat_models import init_chat_model llm init_chat_model(openai:claude-sonnet-4, temperature0)TaoToken 的 Key 在控制台创建地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建完记得复制保存页面关了就看不到了。如果你还没决定用哪个模型可以先去模型对话页面 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 试一下不同模型的工具调用表现再决定 Agent 用哪个。Tavily 那边也需要一个 API Key去 Tavily 官网注册后能拿到tvly-开头的 Key。这个 Key 是给 MCP Server 用的和模型 Key 是两回事别搞混。环境准备好之后下一步就是把 Tavily 封装成 MCP Server。3. 可复制配置把 Tavily Search API 封装成 MCP ServerMCP Server 的作用是把 Tavily 的搜索和网页提取能力暴露成标准工具DeepAgents 通过 MCP 协议去调用。这样做的好处是工具和 Agent 解耦以后想换搜索源只改 MCP Server 就行Agent 代码不用动。新建一个文件tavily_mcp_server.py完整代码如下from mcp.server.fastmcp import FastMCP from typing import Literal from tavily import TavilyClient mcp FastMCP(Web-Search-Server) tavily_client TavilyClient(api_keytvly-你的key) mcp.tool() def web_search( query: str, max_results: int 5, topic: Literal[general, news, finance] general, include_raw_content: bool False, ): Run a web search return tavily_client.search( query, max_resultsmax_results, include_raw_contentinclude_raw_content, topictopic, ) mcp.tool() def extract(url: str): Extract web page content from URL. return tavily_client.extract(url) if __name__ __main__: mcp.settings.port 6030 mcp.run(sse)这里封装了两个工具web_search负责搜索extract负责把某个 URL 的正文抓下来。DeepAgents 在做研究时典型流程就是先搜一批结果再对其中最有价值的链接做 extract 拿全文。启动 MCP Serverpython tavily_mcp_server.py看到类似Uvicorn running on http://0.0.0.0:6030的输出就说明起来了。SSE 端点是http://localhost:6030/sse这个地址后面 Agent 配置里要用。如果你想把这段配置固化下来可以写一个mcp_config.json{ mcpServers: { web-search: { url: http://localhost:6030/sse, transport: sse } } }注意这里的 transport 是sse不是stdio。因为我们是把 MCP Server 当独立进程跑通过 HTTP SSE 通信这样 Agent 和 Server 可以分开部署。工具注册这块有个细节DeepAgents 通过MultiServerMCPClient来拉取 MCP 工具它会自动把 MCP 的 tool schema 转成 LangChain 的 tool 格式。你不需要手动写 tool 定义只要 Server 那边mcp.tool()装饰器写对了Agent 这边get_tools()就能拿到。配置写完之后先别急着搭 Agent单独测一下 MCP Server 能不能正常返回。可以用 curl 或者写个最小客户端验证确认web_search能返回结果再往下走。这一步能省掉后面很多排查时间。4. 验证请求搭建 DeepAgents 并跑通端到端查询现在把 Agent 搭起来。新建deep_agent_demo.pyimport os, asyncio from langchain_core.messages import AIMessageChunk os.environ[OPENAI_BASE_URL] https://taotoken.net/api os.environ[OPENAI_API_KEY] 你的TaoToken Key from deepagents import create_deep_agent from langchain_mcp_adapters.client import MultiServerMCPClient from langchain.chat_models import init_chat_model system_prompt 你是一位研究专家。你的工作是根据用户的要求进行彻底的研究然后写一份润色的报告。 ## 工作流程 1. 理解核心需求识别关键要素。 2. 制定任务规划明确待办事项。 3. 逐步研究记录发现验证结论。 4. 整体结果和审查必要时重新制定解决链路。 5. 输出详细研究报告。 async def main(): llm init_chat_model(openai:claude-sonnet-4, temperature0) client MultiServerMCPClient( { web-search: { url: http://localhost:6030/sse, transport: sse, } } ) tools await client.get_tools() agent create_deep_agent( modelllm, toolstools, system_promptsystem_prompt, ) async for stream_type, chunk in agent.astream( input{ messages: [ {role: user, content: 埃菲尔铁塔与最高建筑相比有多高} ] }, stream_mode[updates, messages], ): if stream_type messages and type(chunk[0]) is AIMessageChunk: content chunk[0].content if not content: continue print(content, end, flushTrue) elif stream_type updates: if model in chunk: model chunk[model] if messages in model: for message in model[messages]: for tool_call in message.tool_calls: name tool_call[name] args tool_call[args] if name write_todos: todos args[todos] lines [ f {t[content]} -- {t[status]} for t in todos ] print(f\n TODO:\n \n.join(lines) \n) else: print(f\n Call MCP: {name}, args: {args}\n) if __name__ __main__: asyncio.run(main())跑起来python deep_agent_demo.py预期输出分三段。第一段是 TODO 列表你会看到 Agent 先规划出「搜索埃菲尔铁塔高度」「搜索世界最高建筑」「对比分析」「撰写报告」这几条待办状态从in_progress逐步变成completed。第二段是 MCP 调用日志能看到web_search被调用了好几次每次的 query 都不一样。第三段是最终报告包含数据对比表格和结论。验证成功的检查点有三个一是 TODO 列表确实出现了并且状态在流转说明规划能力生效二是 MCP 调用日志里能看到web_search和extract被真实调用说明工具注册成功三是最终报告里的数据能对上比如埃菲尔铁塔 330 米、哈利法塔 828 米、差值 498 米说明搜索结果被正确消费了。如果这三条都满足说明 DeepAgents Tavily 这条链路是通的。接下来可以把它包成 OpenAI 协议接口方便在客户端里用。封装用 FastAPI核心是把 Agent 的流式输出转成 OpenAI 的 SSE 格式。关键代码结构如下from fastapi import FastAPI, HTTPException, Header, Depends from fastapi.responses import StreamingResponse from pydantic import BaseModel from typing import List, Dict, Any, Optional, Generator import time, uuid app FastAPI(titleOpenAI Compatible Chat API) api_key sk-你的自定义key class ChatCompletionRequest(BaseModel): model: str messages: List[Dict[str, Any]] temperature: Optional[float] 1.0 max_tokens: Optional[int] None stream: Optional[bool] False async def verify_auth(authorization: Optional[str] Header(None)) - bool: if not authorization: return False token authorization[7:] if authorization.startswith(Bearer ) else authorization return token api_key app.post(/v1/chat/completions) async def chat_completions( request: ChatCompletionRequest, auth_result: bool Depends(verify_auth), ): if not auth_result: raise HTTPException(status_code401, detailInvalid authentication credentials) if not request.stream: raise HTTPException(status_code400, detailOnly streaming is supported) request_id fchatcmpl-{uuid.uuid4().hex[:8]} return StreamingResponse( handle_stream_response(request.messages, request.model, request_id), media_typetext/event-stream, )handle_stream_response里把 Agent 的每个 chunk 包成chat.completion.chunk格式最后发一个data: [DONE]。启动服务uvicorn openai_api:app --host 0.0.0.0 --port 8000然后在 Cherry Studio 里添加一个 OpenAI 连接Base URL 填http://localhost:8000/v1API Key 填你上面设的sk-开头的自定义 key模型名随便填一个比如agent_model就能对话了。提问之后你会看到 TODO 列表和报告一起流式输出。5. 本篇常见错排查401、local proxy failed 与 choices 解析这一节把几个高频报错单独拎出来说都是我实际踩过的。401 Invalid authentication credentials这个报错出现在两个地方要分开看。如果是调用 TaoToken 时报 401检查OPENAI_API_KEY是不是复制完整了TaoToken 的 Key 通常比较长容易漏字符。另外确认OPENAI_BASE_URL是https://taotoken.net/api不要多加/v1init_chat_model 会自己拼路径。如果是调用你自己封装的 FastAPI 服务报 401检查客户端里填的 Key 和代码里api_key变量是否一致注意Bearer前缀有没有带上。local proxy failed / connection refused这个一般是 MCP Server 没起来或者端口对不上。先确认tavily_mcp_server.py在跑curl http://localhost:6030/sse能连上。如果 Agent 和 MCP Server 不在同一台机器localhost要换成实际 IP。还有一种情况是 MCP Server 起来了但 Agent 配置里 transport 写成了stdioSSE 服务用 stdio 连肯定失败改回sse。reading choices / KeyError: choices这个报错通常出现在客户端侧原因是你的 FastAPI 返回的 chunk 格式不符合 OpenAI 规范。检查ChatCompletionChunk里choices字段是不是 list每个元素有没有index、delta、finish_reason这三个字段。少一个客户端解析就会挂。另外delta里放的是{content: msg}不是直接放字符串。OAuth / token 过期类报错如果你用的是需要 OAuth 的模型服务注意 token 有效期。TaoToken 的 Key 是长期有效的但如果你在代码里用了其他临时凭证过期后会报认证失败。排查方法是单独用 curl 打一下模型接口确认 Key 本身没问题再排查 Agent 侧。Agent 不调用工具直接编答案这个不是报错但很常见。原因是 system_prompt 里没强调「必须使用搜索工具验证」或者模型本身工具调用能力弱。解决办法是在 system_prompt 里明确写「所有事实性数据必须通过 web_search 获取不得凭记忆回答」另外换一个 function calling 支持更好的模型。TODO 列表不出现DeepAgents 的 write_todos 是内置工具正常情况下会自动调用。如果不出现检查create_deep_agent时有没有误传tools参数覆盖了内置工具。内置工具和自定义工具是叠加的不需要手动加 write_todos。排查的时候有个通用思路先单独测 MCP Server再单独测模型调用最后测 Agent 编排。三层分开验证比一上来就跑全链路容易定位问题。6. 把这条链路用起来从验证到长期运行跑通之后你会发现这套东西的价值不只是「能搜能写」而是整个过程可观测、可干预。TODO 列表让你知道 Agent 现在在干嘛MCP 调用日志让你知道它搜了什么最终报告让你知道结论从哪来。这比黑盒式的 Agent 靠谱得多。如果你打算长期用有几个方向可以继续做。一是把 MCP Server 部署到独立服务上Agent 通过内网地址连避免每次本地起进程。二是给 Agent 加文件系统工具让它把中间研究结果落盘长任务中断后能续上。三是把 OpenAI 协议接口那层的 api_key 换成从环境变量读别写死在代码里。模型这块如果你要跑长时间的编码或 Agent 任务可以了解一下 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它针对的就是这类持续调用的场景。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有不同语言的调用示例。API Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 建议给 Agent 单独建一个 Key方便按项目统计用量。最后说个实际经验DeepAgents 的规划能力很依赖 system_prompt 的质量。我试过把工作流程写得很细像上面那样分五步Agent 的 TODO 列表就很有条理写得太笼统它规划出来的待办就会漏步骤。如果你发现报告质量不稳定先回去改 system_prompt比换模型见效快。