十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LangChain、LangGraph、Deep Agents、ADK 四大Agent框架对比与选型指南

LangChain、LangGraph、Deep Agents、ADK 四大Agent框架对比与选型指南 做 Agent 开发最难受的地方不是不会调大模型接口而是把“模型调用、工具调用、状态保存、条件分支、循环控制、人工确认、批量重试”这一整条链路串起来时代码越写越乱。今天直接对比四个经常被放在一起选型的东西LangChain、LangGraph、Deep Agents、ADK。先说结论方便你对号入座如果你要快速做原型、接 RAG、接 MCP 生态LangChain 最顺手如果你的业务本质是流程控制需要条件路由、循环、并行、人工审批LangGraph 图编排更稳如果你已经在 Google Cloud 体系里想省掉运维直接上托管ADK 更合适Deep Agents 目前更多是社区方向文档和接口还没有统一适合尝鲜和关注趋势但生产落地要谨慎。这篇文章会先把四个框架的定位和核心能力拉平再给一套“从安装到跑通再到接口封装和批量任务”的通用验证流程。后面会有可复制的 Python 示例、条件路由和中断机制的具体写法以及一组踩坑排查清单。读完你可以按自己的需求做一次选型判断不需要把四个框架全部深入学一遍。1. 四个框架到底是什么1.1 LangChain组件最全的 Agent 开发底座LangChain 不是一个单独的 Agent 运行时而是一整套 LLM 应用开发工具集。它有模型抽象层、提示词模板、输出解析、RAG 相关组件、工具调用封装、Memory 等。你可以在里面找到几乎所有标准零件。它的核心优势是生态成熟社区资料多文档、教程、第三方集成都是四个框架里最丰富的。很多本地知识库、RAG、客服问答项目都构建在 LangChain 之上。但它的问题是“框架感”偏重。当你只是调一个模型时引入大量抽象反而增加学习成本。更关键的是LangChain 原生的 Agent Executor 对复杂流程控制能力有限所以在多个工具、多轮决策、需要人工中断的 Agent 场景里大家开始转向 LangGraph。1.2 LangGraph把 Agent 当有向图来编排LangGraph 和 LangChain 是同一家公司开源的项目但定位完全不同。LangGraph 的思想是把 Agent 执行过程建模成一个有向图里面有节点Node和边Edge节点里执行具体的模型调用或工具调用边负责决定下一步走哪里。它可以做到条件分支、循环、并行执行、子图拆分还支持 checkpointer 保存执行状态以及 interrupt 机制实现人工介入。搜索热词里反复出现“LangGraph 和 LangChain 的区别”“conditional_edge 深度解析”“子图”“并行分支”这正好说明大家关注点已经不在“能不能调模型”上而是“流程能不能被精确控制”。LangGraph 就是冲这个来的。1.3 Deep Agents概念热度高但生态还没统一Deep Agents 这个名字目前还没有一个像 LangChain 那样统一的权威定义。它能火很大程度上来自多 Agent 分层协作、计划-执行式任务拆解等设计思想。社区里有一些仓库会以 Deep Agents 或类似命名做实现主打更深的推理链路、更细致的任务分解以及通过 interrupt 机制和用户交互确认每一步。但正因为缺乏统一标准不同仓库的 API、配置方式、运行方式可能都不同。你在一个项目里学会的用法换到另一个仓库不一定还能用。选它之前必须先把对应仓库的官方文档和 README 看一遍不能照搬别人的代码。1.4 ADKGoogle 的 Agent 开发工具包ADK 是 Google 开源的 Agent 开发套件全称是 Agent Development Kit。它面向的是想要“快速构建可落地 Agent”的开发者核心是多 Agent 工作流并提供代码执行器、MCP 支持、评估与复盘、以及和 Google Cloud 托管服务的集成。ADK 和 LangGraph 在概念上有重叠都有工作流编排、都有节点级控制都支持人工干预。差别主要在生态和运维侧ADK 与 Google 的模型服务、云上 Agent Engine 绑定更紧密适合本身就跑在 Google 生态里的团队LangGraph 更偏开源中立和 OpenAI、Anthropic、本地模型服务的结合方式更灵活。2. 核心能力速览下面的表格用于快速判断四个框架的位置。需要注意Deep Agents 因为生态不统一很多能力写的是“取决于具体实现”不要默认所有名为 Deep Agents 的项目都有同样的功能。对比项LangChainLangGraphDeep Agents社区实现ADK定位LLM 应用组件库Agent 图编排框架多 Agent 协作/分层拆解方向Agent 开发套件核心概念Chain、Tool、Memory、RAGState、Node、Edge、Conditional Edge计划-执行、分层 Agent、interruptAgent、Workflow、Code Executor是否开源开源开源开源但多个仓库并存开源条件路由支持但流程控制偏弱原生支持graph 条件边取决于实现支持 agent-to-agent 路由循环与重试依赖内部 Agent 逻辑原生支持循环和递归限制取决于实现支持多轮 agent 协作并行执行可写并行调用支持并行分支和 fan-out部分实现支持支持多 agent 并发子图/嵌套不太直观原生支持 subgraph部分实现支持Agent 间可嵌套中断/人工确认实现成本较高interrupt_before/interrupt_after部分实现支持 interrupt支持人类反馈环节MCP 支持有 MCP 适配工具可通过工具节点接入 MCP取决于实现原生支持 MCP学习成本中等组件多中等偏高需要图思维资料少成本高中等文档依赖 Google 生态适合场景原型、RAG、常规工具调用有条件分支/循环/人工审批的生产系统实验性多 Agent 项目Google Cloud 上的生产 Agent从表格可以明显看出LangChain 适合“搭积木”LangGraph 适合“画流程图”ADK 适合“在 Google 生态里做工程化”Deep Agents 适合“看趋势和做实验”。3. 适用场景与使用边界3.1 各自适合谁先看 LangChain。它适合做知识库问答、简单工具调用、快速验证 prompt 效果。比如你有一个 PDF 文档库想快速做一个带引用的问答机器人LangChain 的文档加载器和 RAG 组件能让你很快跑通。LangGraph 适合业务逻辑复杂的 Agent。判断标准很简单如果执行流程会出现“根据模型输出决定调不调工具”“调完工具再继续推理”“人工确认后才能提交订单”“多个步骤并行跑”这些情况直接用 LangGraph 更清晰因为图结构可以把这些控制显式表达出来。ADK 适合已经选定 Google 模型服务的团队。如果你大概率会把 Agent 部署到 Google Cloud又不想自己维护调度、日志、评估那套东西ADK 的云集成会省掉很多工程工作量。Deep Agents 适合三类人想了解多 Agent 架构方向的开发者、做技术调研的研究人员、以及愿意跟着开源仓库迭代折腾的玩家。如果团队要交付商业项目不建议把它当唯一依赖。3.2 使用边界和合规提醒Agent 框架本身只是工具风险来自你赋予它的能力。第一个边界是工具权限。Agent 可以调用搜索、发邮件、执行代码、改数据库。一旦接上这些工具必须做最小权限设计能只读就不要给写权限能只查自己的数据就不要给全量数据能走沙箱环境就不要直连生产系统。第二个边界是数据隐私。如果用云端模型服务prompt、工具返回、用户问题都会被送往第三方服务。敏感数据要在脱敏后进入 Agent私有数据优先走本地模型和私有化部署。第三个边界是版权与授权。如果 Agent 要处理文章、图片、音视频、人脸、声音等素材必须先确认素材来源合法并已获得授权。自动化生成内容再对外发布前要做人工复核避免批量产出有版权风险或误导性内容。第四个边界是自动化风险。批量任务意味着错误也会被批量放大。发送邮件、提交订单、发布公告这类操作一定要设计人工确认节点不要在无人看管的情况下直接执行。4. 环境准备与前置条件Agent 框架本身是 Python 库不直接加载大模型所以常规的 Python 环境足够。但运行时会调用模型服务模型是否跑在本地、显存占用多大取决于你选的推理后端跟框架关系不大。4.1 基础环境清单检查项建议操作系统Windows、macOS、Linux 均可生产环境推荐 LinuxPython 版本建议 3.10 或 3.11具体以各框架官方要求为准虚拟环境必须使用 venv 或 conda避免依赖冲突模型访问准备 OpenAI/Anthropic/Google/本地模型服务的 API Key 或 Endpoint包管理工具pip 或 uv磁盘空间框架本体很小几百 MB 足够本地模型另算端口本地 API 服务默认可用 8000、8080、7860 等冲突时更换4.2 模型推理的显存问题很多初学者会问用这些框架需要多大显存答案要拆开看。LangChain、LangGraph、ADK 这类框架本身占用几乎可以忽略真正吃显存的是你调用的大模型。如果调用云端 API本地不需要 GPU显存占用为零。如果调用本地模型比如在 Ollama、vLLM、llama.cpp 上跑 7B 或 14B 模型4G 到 12G 显存都有可能具体取决于模型量化方式和上下文长度。部署 Agent 前先单独把模型服务跑起来确认模型的响应速度和显存占用再把框架接上去。4.3 端口与进程检查启动 Agent 的 Web 服务或 API 后要会检查端口状态。Windows 上可以用 netstatLinux 上可以用 ss 命令。# 查看端口占用 netstat -ano | findstr 8000# Linux 查看端口占用 ss -lntp | grep 8000如果端口被占用更换端口即可不用重启机器。5. 安装部署与启动方式5.1 创建虚拟环境无论是哪个框架都建议先建虚拟环境再装依赖。python -m venv .venvWindows 激活方式.venv\Scripts\activateLinux/macOS 激活方式source .venv/bin/activate5.2 安装 LangChain 和 LangGraphLangChain 本身分多个包核心部分、模型适配、社区组件。一般按需安装即可。pip install langchain langchain-openai langgraph如果还需要文档加载、向量库、MCP 相关组件再单独装对应包。注意不同版本之间可能依赖冲突装完后先执行版本检查。python -c import langchain; print(langchain.__version__) python -c import langgraph; print(langgraph.__version__)5.3 安装 ADKADK 的安装名需要以官方文档为准常规方式是pip install google-adk装完后检查版本python -c import google.adk; print(google.adk.__version__)如果本机 Python 版本较旧或存在冲突建议先升级 pippip install --upgrade pip5.4 Deep Agents 的安装不同仓库安装方式不同。有的是直接 pip install有的是从 GitHub 仓库安装还有的需要先 clone 源码。不要想当然必须到对应仓库的 README 里看安装命令。我这边只能给一个通用模板# 以实际仓库文档为准 git clone https://your-target-repo-url.git cd your-target-repo pip install -r requirements.txt装完先跑仓库自带的 example不要直接用自己的业务代码否则很难判断是环境问题还是接口用法问题。5.5 启动一个最小 Agent 服务框架装好后最直接的方式是先用命令验证模型连通性。下面是一个 LangChain 最小调用示例用于确认 API Key 和模型服务正常from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, temperature0, ) response llm.invoke(你好用一句话说明什么是 Agent) print(response.content)如果这里能输出内容说明模型链路是通的后面接框架就不会有基础环境问题。如果这里报错优先检查 API Key、Endpoint、网络而不是框架版本。6. 功能测试与效果验证这一部分用 LangGraph 做主角因为它的流程控制能力最突出也是搜索热词最集中的部分。测试目标包括条件路由、循环检测、并行分支、子图、中断恢复。6.1 测试条件路由和工具调用先定义 Agent 的执行状态。状态是整个图共享的数据结构所有节点都能读写。from typing import TypedDict from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, START, END from langgraph.prebuilt import ToolNode, tools_condition class AgentState(TypedDict): messages: list next_action: str然后定义两个节点一个负责调用模型一个负责执行工具。def call_model(state: AgentState) - dict: llm ChatOpenAI(modelgpt-4o-mini, temperature0) response llm.invoke(state[messages]) return {messages: [response]}常见的查询工具可以写成普通 Python 函数返回值必须是字符串def get_weather(city: str) - str: # 测试函数实际可替换为真实天气 API return f{city} 今天晴天适合出门。 def get_time() - str: return 2025-06-01 10:00:00构建图并连接节点tools [get_weather, get_time] builder StateGraph(AgentState) builder.add_node(agent, call_model) builder.add_node(tools, ToolNode(tools)) builder.add_edge(START, agent) builder.add_conditional_edges(agent, tools_condition) builder.add_edge(tools, agent) graph builder.compile()这里的tools_condition是内置条件路由如果模型输出带 tool_calls就进入 tools 节点否则直接结束。tools节点执行完工具后再把结果返回给模型继续推理这样循环就能持续下去直到模型不再请求工具。执行测试result graph.invoke({ messages: [{role: user, content: 北京天气怎么样}] }) for message in result[messages]: print(message.content)判断成功的标准有三个模型生成了工具调用工具节点返回了真实结果结果回到模型后最终给出用户可读的答复。如果只看到工具调用但没有最终答复通常说明循环没有闭合。6.2 自定义条件路由让流程按状态走有些场景不能用内置条件自动判断需要根据业务自定义路由比如“需要人工确认”“需要走 fallback”“需要结束”。下面写一个自定义条件函数def custom_router(state: AgentState): if state.get(next_action) human_approval: return human_approval if state.get(next_action) fallback: return fallback return finish关键点是条件函数返回的字符串必须和图里已存在的节点名或 END 一一对应否则 LangGraph 会直接报错说找不到目标节点。这个错误排查时特别常见后面会放在排查清单里。6.3 测试并行分支并行分支适合把不需要依赖的任务同时执行比如同时查订单、查库存、查物流。LangGraph 支持在一个节点后连接多个节点让它们并行跑。def check_order(state: AgentState) - dict: return {order_result: 订单已支付} def check_inventory(state: AgentState) - dict: return {inventory_result: 库存 100 件} def merge_results(state: AgentState) - dict: combined f{state.get(order_result, )}{state.get(inventory_result, )} return {summary: combined}构建并行结构builder StateGraph(AgentState) builder.add_node(check_order, check_order) builder.add_node(check_inventory, check_inventory) builder.add_node(merge, merge_results) builder.add_edge(START, check_order) builder.add_edge(START, check_inventory) builder.add_edge(check_order, merge) builder.add_edge(check_inventory, merge)这样两个节点会并行执行最后由 merge 节点汇总。判断并行是否生效可以在两个函数里加上 sleep 并记录耗时对比串行和并行的总时间。6.4 测试子图子图的作用是把重复使用的流程抽出来避免主图越来越长。比如“数据清洗”在多个 Agent 里都会用到就可以单独建一个子图再在主图里用 add_node 挂载。cleanup_graph StateGraph(AgentState) # ... 往 cleanup_graph 里加节点和边 ... cleanup_app cleanup_graph.compile() builder.add_node(cleanup, cleanup_app)子图编译后可以当作普通节点用。这样主图保持简洁子图内部还能单独测试非常符合工程化习惯。6.5 测试中断和人工确认这是 LangGraph 和其他框架拉开差距的核心功能。假设用户要批量发送邮件不能直接让模型自动执行必须插入一个人工确认节点。构建图后通过 interrupt_before 指定在哪个节点前暂停builder.add_node(agent, call_model) builder.add_node(send_email, send_email_executor) builder.add_edge(START, agent) builder.add_edge(agent, send_email) builder.add_edge(send_email, END) app builder.compile(interrupt_before[send_email])执行到中断点不会真正执行 send_emailconfig {configurable: {thread_id: order-001}} result app.invoke( {messages: [{role: user, content: 发送邮件给 customerexample.com}]}, configconfig, ) print(app.get_state(config))get_state 返回的就是当前中断状态里面可以看到模型生成的邮件内容。人工确认后再恢复执行from langgraph.types import Command result app.invoke( Command(resumeconfirm), configconfig, )这个机制对“批量任务”“订单执行”“对外发布”这类场景极其重要。每一批动作都要有确认环节避免 Agent 自动执行了大量不可逆操作。6.6 用 ADK 做一个最小验证ADK 的验证核心是 Agent 的构建和 Runner 执行。下面是符合官方文档风格的示例具体参数名如果版本有变化以官方文档为准from google.adk.agents import Agent from google.adk.runners import Runner def query_order(order_id: str) - str: # 测试函数实际替换为订单系统接口 return f订单 {order_id} 已发货 root_agent Agent( nameorder_agent, modelgemini-2.0-flash, instruction你是订单助手只回答订单相关问题。, tools[query_order], ) runner Runner(agentroot_agent) result runner.run(帮我查订单 O-2025-001 的状态) print(result)判断成功的标准是Agent 能够理解用户意图正确调用 query_order 工具并返回自然语言结果。如果模型没有触发工具调用检查模型参数是否支持 function calling以及工具描述是否清晰。7. 接口 API 与批量任务Agent 跑通后的下一步就是把能力封装成接口再接入批处理系统。7.1 把 Agent 封装为 FastAPI 接口这里给出一个通用封装模板框架可以是 LangGraph也可以是 ADK重点是统一输入输出from fastapi import FastAPI from pydantic import BaseModel app FastAPI(titleAgent API) class AgentRequest(BaseModel): user_input: str thread_id: str default-thread class AgentResponse(BaseModel): answer: str status: str success app.post(/api/agent/run) def run_agent(req: AgentRequest): # 这里把 req.user_input 传给前面编译好的 graph 或 runner # 对应 LangGraph 使用 graph.invoke # 对应 ADK 使用 runner.run result 这里替换为真实 Agent 执行结果 return AgentResponse(answerresult)启动服务uvicorn main:app --host 0.0.0.0 --port 8000注意生产环境不要直接暴露在公网至少要加身份校验。7.2 调用接口测试启动服务后用 curl 测试curl -X POST http://127.0.0.1:8000/api/agent/run \ -H Content-Type: application/json \ -d {user_input: 查一下北京天气, thread_id: t001}返回正常时是 JSON 结构里面包含回答内容。如果接口超时检查模型服务响应时长和网络连通性。7.3 批量任务的队列设计批量任务不能直接 for 循环同步调用否则一个任务卡住后面全卡住。建议用任务队列加 Worker 的方式。一种轻量方案是使用 Redis 队列或 Python 内部的队列池。以通用伪代码为例import queue import threading task_queue queue.Queue() results {} def worker(): while True: task_id, input_text task_queue.get() try: result run_agent(input_text) results[task_id] {status: success, data: result} except Exception as exc: results[task_id] {status: failed, error: str(exc)} finally: task_queue.task_done() for i in range(4): threading.Thread(targetworker, daemonTrue).start()批量任务的核心不是如何跑得快而是如何保证任务能重试、能追踪、不丢数据。每个任务要有唯一 task_id任务状态要落到数据库或日志里失败要单独进入重试队列。7.4 Agent 与 MCP 的集成趋势MCP 正在成为 Agent 工具调用的公共协议。四个框架里LangChain、LangGraph、ADK 都已有 MCP 适配能力Deep Agents 要看具体实现。集成 MCP 的好处是不用为每个外部系统单独写工具封装而是用统一协议接入减少重复开发。判断框架是否适合你的团队可以看它对 MCP 的支持成熟度。如果只接一两个内部 API手写工具就够用如果后续要接大量第三方系统和插件生态优先选 MCP 支持成熟的框架。8. 资源占用与性能观察8.1 框架本身占用极低LangChain、LangGraph、ADK、Deep Agents 都是 Python 进程框架本身的 CPU 和内存占用通常只有几十到几百 MB。它们不加载大模型权重显存占用取决于使用的模型推理服务。不要被“Agent 框架很吃显存”这种说法误导。真正的性能瓶颈在三个地方第一模型调用次数第二单次模型调用的 token 数量第三工具接口的响应时间。以 LangGraph 为例一个复杂任务可能会多次调用模型先理解用户意图再决定工具调用工具返回后还要再理解结果最后生成最终答案。任何一环的 token 超长都会显著拉高延迟和费用。8.2 如何观察性能建议在本地启动服务后记录四个指标指标观察方式单轮任务耗时从请求发出到返回的时间模型调用次数查看 LangGraph 的状态日志或追踪平台token 消耗量打开模型服务日志或 LangSmith/Langfuse 面板工具调用失败率在工具节点外层包装 try-except 并记录日志如果你想做对比测试就用同一组问题分别跑 LangGraph 和 ADK记录消耗的 token 数和总耗时。但要注意结果不仅受框架影响还受模型版本、prompt 设计、工具描述质量影响。框架层面更值得对比的是“控制能力和可维护性”而不是几个毫秒的差异。8.3 如何降低资源消耗先把上下文控制住。Agent 每轮都会携带历史消息长时间对话会让 context 无限膨胀。常用的办法是只保留最近 N 轮消息或者对长历史做摘要或者只提取关键字段放到新的状态里。其次避免无效工具调用。工具描述写得越清晰模型越不会尝试调用不存在的工具。工具数量也不要一次挂太多否则模型选择困难错误率增加。最后临时性中间结果不要全部存进状态。LangGraph 的状态是共享的所有节点都能读也都会占内存。不需要下次用的数据在节点返回时直接丢弃。9. 常见问题与排查方法问题现象可能原因排查方式解决方案pip 安装报依赖冲突langchain-core 版本被其他库覆盖打印 pip list查看冲突包重建虚拟环境按官方要求锁定版本模型调用一直超时API Key 无效、Endpoint 不通、网络受限先用最小模型调用测试先修通模型链路再接框架LangGraph 条件边报找不到节点条件函数返回的字符串不是已有节点名打印条件函数返回值确保返回值与节点名或 END 一致Agent 无限循环不停止工具返回后模型继续要求调用工具检查工具返回值和模型日志增加 recursion_limit 限制检查工具是否返回了误导性内容并行分支没有真正并行节点之间隐式存在依赖在节点里加日志和时间戳检查 edges 是否有意外连线interrupt 被跳过interrupt_before 设置错误或 flow 路径变化打印图结构确认中断节点在实际执行路径上ADK 工具不被调用工具描述不清晰或模型不支持 function calling换一个更简单的工具测试精简工具描述确认模型类型MCP 连接失败服务地址错误、工具名不匹配、凭证缺失先单独测试 MCP server修好 server 再接入 Agent批量任务卡住没有超时控制、失败重试策略查看 Worker 日志给每个任务加超时失败自动重试Deep Agents 示例跑不起来仓库代码和当前依赖版本不兼容看仓库 Issues锁定仓库指定版本的依赖遇到问题最有效的排查路径是先看日志再看状态流最后才是找代码问题。不要在不知道状态数据的情况下盲目改流程。10. 最佳实践与使用建议10.1 从最小的图开始第一次用 LangGraph不要一上来就画一个包含 20 个节点的复杂图。先做“模型节点 工具节点 条件边”的最小闭环确认链路能跑通再加中断、子图、并行。10.2 把状态定义得足够小State 字段越少节点间耦合越低调试越容易。不要把 prompt、历史记录、中间结果全部塞进一个 state。每个节点只读自己需要的字段只返回真正需要更新的字段。10.3 对不可逆操作强制人工确认邮件发送、订单提交、文件删除、数据库更新、对外发布都要走 interrupt 或人工审核环节。这个习惯必须在一开始就建立不要等线上出问题再补。10.4 给 Agent 加权限边界Agent 工具的粒度要细。不要给一个“执行任意代码”的万能工具除非它跑在隔离沙箱里。工具最小权限原则每个工具只暴露必要参数只能访问必要的数据范围。10.5 建立评估集任何 Agent 改动都要回归测试。准备一组固定问题和期望行为每次改 prompt、改工具描述、换模型后都跑一遍评估集确认没有引入新的错误格式或不稳定输出。10.6 数据合规和隐私保护如果 Agent 处理用户数据、企业内部数据或受版权保护的资料先明确数据流向。本地部署模型可以减少数据外传风险但对模型能力和运维成本要求更高。对外提供 Agent 服务需要做好身份认证、访问控制和日志审计。11. 总结与下一步回到选型问题重点不是哪个框架最强而是哪个框架最匹配你的流程复杂度。快速原型和 RAG 场景选 LangChain复杂流程和人工审批场景选 LangGraphGoogle 云生态选 ADKDeep Agents 先花时间验证官方资料。建议从 LangGraph 开始验证因为它能覆盖最多真实业务问题而且文档和社区生态比 Deep Agents 成熟。最容易踩的坑是依赖版本冲突和条件路由返回错误节点名这两类问题都会在第一个项目里遇到。下一步可以按这个顺序推进先跑通一个带工具调用的最小 Agent再加入 interrupt 人工确认然后接 MCP 工具最后封装成 API 并接入批量任务队列配合 LangSmith 或 Langfuse 做全链路追踪和评估。这个链路全部跑通后你的 Agent 架构基本就完成了一次完整的生产化验证。
返回列表