ARTICLE DETAIL

资讯详情

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

DeerFlow 2.0实战:从Deep Research到Super Agent Harness的Agent编排

DeerFlow 2.0实战:从Deep Research到Super Agent Harness的Agent编排 1. 项目概述如果你最近在折腾AI Agent应该对Deep Research这种形态不陌生——给定一个研究主题智能体自主规划子任务、检索网页、阅读多篇资料、交叉验证最后产出一份结构化报告。这个流程很诱人但真要落地到自己的业务里你会发现坑比想象中多长任务跑到一半看不到进度、中间环节无法人工纠偏、工具调度逻辑写死之后根本没法扩展、流式输出到手还得自己拆报文。DeerFlow 2.0就是在这些痛点上长出来的项目。它有两个核心关键词Deep Research和Super Agent Harness。前一个解决智能体能不能自主完成长链路研究工作的问题后一个解决这套能力能不能被复用、被观测、被二次开发的问题。简单说2.0版本把一套原本偏研究演示的流程重构成了一个可扩展的Agent运行框架——研究能力只是这个框架上的第一个应用。这篇文章写给三类人想把Deep Research能力集成到自己产品里的后端工程师、基于DeerFlow做智能体二次开发的技术负责人、以及想理解Agent编排框架设计思路的AI应用开发者。我会从架构演进讲到代码实操覆盖图状态设计、SSE流式接口封装、人机协同和可观测性这几个硬核主题最后再把我踩过的坑一并倒出来。2. Deep Research模块拆解一次完整的研究闭环2.1 从Prompt到Pipeline研究任务的工程化很多人第一次用Deep Research类产品会觉得它不过是把几个Prompt串起来。真去读DeerFlow的源码你会发现事情远没那么简单。一个标准的研究任务被拆成了五个可独立观测的阶段研究规划、任务拆分、并行检索、内容阅读与信息抽取、报告生成与校验。这五个阶段对应着图里的五个节点node每个节点都是一个独立的处理单元输入输出都是结构化的状态对象。规划节点负责任务拆解比如对比DeerFlow 2.0与LangGraph的架构差异会被拆成DeerFlow 2.0架构特性梳理、LangGraph编排机制分析、两者在状态管理与工具调度上的对比等多个子问题检索节点针对每个子问题去搜索拿回一批候选链接阅读节点抓取网页正文用LLM抽取关键信息最后汇总节点把抽取结果按报告大纲重组。这么设计的核心收益在于每个环节都具备可观测性和可干预性。任务跑到一半你想知道现在读到哪了、检索到了哪些链接、抽取结果是否可信图状态里全都有。我在实际部署中把每一步的状态快照接入日志系统整个研究过程就是一条完整的时间线这对排查问题和向用户展示进度都极有价值。2.2 搜索与阅读没有好检索就没有好报告研究类Agent最容易翻车的地方在于检索质量。DeerFlow默认接的是搜索引擎API但代码里把搜索抽象成了工具接口意味着你可以换掉它——换成内部文档搜索、学术搜索引擎、甚至多个数据源聚合。我自己在私有化部署时就接了一个企业知识库搜索让研究Agent直接基于内部资料生成竞品分析报告。阅读环节同样值得细看。抓回来的网页是HTML需要先做正文提取再分段喂给LLM做信息抽取。这里有个工程细节直接塞整篇正文会把上下文窗口打爆还会稀释注意力。DeerFlow的做法是先把正文按标题切成多个片段每个片段独立抽取要点最后再合并去重。这种方式在长文档场景下效果明显更好而且天然支持并发——多个片段可以并行调用LLM大幅压缩了整条链路的总耗时。2.3 为什么流式输出是刚需研究任务动辄几分钟起步如果让用户干等一个HTTP响应返回体验会很糟。DeerFlow 2.0把整条链路的中间结果都设计成了流式事件任务进入新阶段、搜索完成、某篇文章读完、报告开始逐段生成这些都会实时推给前端。前端可以渲染一个研究过程实时看板用户看到的不是一个静止的loading而是Agent正在一步步工作的完整过程。我封装SSE接口时最大的体会是流式输出的价值不只是快而是过程可见。用户能看到Agent搜了哪些网站、读了哪些文章、下一步准备干什么这种可视化对信任感的建立至关重要——尤其是当报告结论比较激进时用户能顺着研究过程去溯源、去复核而不是面对一个黑盒结果。3. Super Agent Harness架构升级的核心设计3.1 从研究工具到Agent运行框架2.0版本最大的变化不是Deep Research变强了而是多出了一个叫Super Agent Harness的抽象层。Harness直译是马具在AI Agent语境里可以理解为拴住Agent的那套牵引和控制系统——它负责Agent的启动、状态维护、工具调度、流程控制、人工介入和可观测性采集。以前你想基于DeerFlow做一个自己的Agent要么改源码要么在最外层包一层不够灵活的调用壳核心链路基本动不了。2.0提供的Harness把这层彻底解耦了Deep Research只是Harness上的一个预设工作流workflow你可以完全抛开它定义自己的节点和边构建一个属于你自己的Agent应用同时继续享用框架自带的状态管理、事件流和观测能力。3.2 图状态Agent的记忆与通行证模块化设计中最关键的数据结构是围绕有状态图stateful graph的状态对象——例如DeepResearchState类的实例。它贯穿整条工作流的所有节点像是所有节点共享的工作台每个节点从上面取输入再把输出放回去。class DeepResearchState(TypedDict): task: str # 原始研究任务 plan: list[dict] # 规划阶段产出的子任务列表 reflections: list[str] # 自我反思/校验意见 search_queries: list[str] # 实际执行的检索词 search_results: list[dict] # 检索返回的候选结果 visited_urls: list[str] # 已访问的链接 research_data: list[dict] # 已抽取的结构化信息 report: str # 最终报告 route: Literal[continue, finalize] # 当前流程走向字段命名要具体避免把所有中间结果堆在一个泛化的 memory 字段里这样后续要持久化、要节流、要做分支判断都会很痛苦。例如研究报告的最终覆盖度不够需要在某个节点让它重新补充检索时你首先得能精确知道research_data里现在有什么、缺什么这只有把状态字段设计得足够细才能做到。3.3 节点与边流程控制的可编程化图编排框架的本质是节点是函数边是路由逻辑。DeerFlow 2.0在LangGraph这类框架上重新组织了这套规则但把节点边界划分得更清晰。一个节点只做一类事规划节点只规划检索节点只检索从来不让一个节点既调LLM又调搜索API再做判断。这种划分有实际好处。第一每个节点的输入输出都是确定的结构化数据出问题能快速定位是哪个环节挂了。第二节点可以单独替换——比如想把规划模型从GPT换成本地部署的DeepSeek只需要改节点内部的实现其他节点完全不用动。第三方便做观测每个节点的起止时间、Token消耗、返回内容都能精确采集。路由逻辑是另一个容易被忽略的设计点。比如route字段决定流程是继续研究还是进入报告生成判断依据可能是研究深度是否达标。这个判断本身也是可编程的你可以让一个专门的路由节点用LLM判断也可以硬编码规则——比如每轮反思后是否新增了检索词。灵活性的代价是理解成本我在给团队做二次开发培训时反复强调的就是先把这张图画清楚再写代码。3.4 人机协同不是全自动而是该交给人时交给人很多Agent项目过于追求全自动结果就是错误被一路放大出了篓子用户只能看到一份漂亮的错误报告。DeerFlow 2.0在人机协同上做得很务实关键节点支持人工审批流程可以在必要时暂停并征求用户意见。典型场景是研究报告的反思与复盘环节。反思节点可能会提出目前检索到的信息不足以支撑结论建议补充搜索或者发现两个信息来源矛盾需要人工判断这些检查点都会决定流程走向直接继续、补充检索、或者停下来进入human_review状态。这不是性能退化而是可靠性设计。面向企业的Agent应用用户不会接受黑盒全自动他们要的是可控的协作——Agent把90%的脏活累活干完剩下10%的关键决策交给人。部署这类系统时我的建议是不做永久性阻断而是允许跳过、允许超时自动放行。4. 二次开发实操基于Harness构建自定义Agent4.1 最小复刻构建你自己的Agent图理解框架最快的方式是亲手搭一个最小Agent。DeerFlow 2.0暴露的构建函数接收一个状态类型、节点集合以及路由逻辑然后返回可执行的图对象。from typing import TypedDict, Literal from deerflow import build_harness, NodeContext class MyAgentState(TypedDict): question: str search_summary: str answer: str route: Literal[reply, tool_call] def analyze_node(state: MyAgentState, ctx: NodeContext) - dict: # 用LLM分析问题是否需要外部工具 result ctx.llm.chat( messages[{role: user, content: f判断此问题是否需要检索外部信息: {state[question]}}] ) if 需要 in result: return {route: tool_call} return {route: reply} def tool_node(state: MyAgentState, ctx: NodeContext) - dict: # 调用搜索工具并把结果写入状态 ctx.log_debug(tool_call invoked) result ctx.tools[search].run(state[question]) return {search_summary: result} def reply_node(state: MyAgentState, ctx: NodeContext) - dict: prompt f基于以下信息回答问题:\n{state[search_summary]}\n问题: {state[question]} return {answer: ctx.llm.chat([{role: user, content: prompt}])} graph build_harness( state_typeMyAgentState, nodes{analyze: analyze_node, tool: tool_node, reply: reply_node}, routes{ analyze: lambda s: s[route] tool_call and tool or reply, tool: lambda s: reply, }, ) result graph.invoke({ question: DeerFlow 2.0的Harness层包含哪些核心组件, })NodeContext是节点上下文对象承载LLM客户端、工具集、日志和观测上报能力。所有节点不自己实例化模型客户端而是从上下文里拿这样测试时替换成Mock非常方便。4.2 注册自定义工具扩展Agent的能力边界Harness的工具机制是把技能以统一接口注册进上下文让所有节点都能调用。工具类名是自定义的不一定与某个官网名称相同比如CompanyDocsTool、TrendSearchTool。每个工具类都要求实现_run方法并在类上声明名称和描述供LLM做函数调用function calling时识别。class CompanyDocsTool: name company_docs_search description 在内部知识库中检索公司制度、技术文档和项目资料 def __init__(self, api_endpoint: str): self.api_endpoint api_endpoint def _run(self, query: str, top_k: int 5): # 调用内部知识库检索接口 resp requests.post(self.api_endpoint, json{query: query, top_k: top_k}) return resp.json()[results]工具不像节点那样直接拿state而是只接收调用参数、返回字符串结果行为更像函数。这样设计是为了让LLM做工具选择时意图更清晰也让工具可以被不同节点复用。我强烈建议你在description里写得足够详细注明什么时候该用这个工具、什么时候不该用LLM的工具选择准确率会明显上升。4.3 封装SSE流式接口把图跑起来图的invoke是普通接口适合调试和离线任务。线上服务需要的是流式体验。DeerFlow 2.0的事件流设计把图的执行过程映射为SSE事件流与前端通过标准EventSource连接按行解析事件即可实现过程实时可见。服务端可以封装一个 FastAPI 接口内部用graph.stream或类似方式按节点粒度产出事件。实际项目里更推荐先把事件写进队列或 Topic再由独立的推送服务转发到SSE长连接这样解耦了图执行和网络IO也方便日后扩展多端推送。import json from fastapi import FastAPI from fastapi.responses import StreamingResponse from deerflow import create_event_adapter app FastAPI() def event_source(task: str): adapter create_event_adapter() for event in graph.stream({task: task}): # 统一封装为SSE数据帧 yield adapter.encode(event) app.post(/research/stream) def research_stream(task: str): return StreamingResponse( event_source(task), media_typetext/event-stream, headers{ Cache-Control: no-cache, Connection: keep-alive, X-Accel-Buffering: no, }, )4.4 流式消息解析前端接住每一帧数据SSE协议本身不复杂但DeerFlow事件带有很多类型——单是研究流程就有阶段变更、子任务完成、搜索命中、阅读小结、反思意见、最终报告增量等。如果你在前端用同一个handler处理所有事件很快就会陷入switch-case地狱。正确做法是先解析event字段再根据事件类型做分支分发。前端伪代码大致如下const es new EventSource(/research/stream); es.addEventListener(phase, (e) { const data JSON.parse(e.data); renderPhase(data.current_phase); }); es.addEventListener(search, (e) { const data JSON.parse(e.data); appendSearchResult(data.query, data.results); }); es.addEventListener(token, (e) { const data JSON.parse(e.data); streamReport(data.delta); });事件类型要提前约定好服务端和前端共用一套枚举。我踩过一个很真实的坑最初把所有消息都放在data字段里前端统一处理结果新增一种事件类型就得改前端解析逻辑而且调试成本很高。后来改成event字段标识类型 data字段承载序列化负载前端按需订阅后面加新事件基本不需要动老代码。5. 可观测性设计与问题排查实录5.1 让Agent的每一步都有迹可循Agent应用的可观测性比传统后端服务更复杂不仅要看请求耗时和错误码还要看LLM的输入输出、工具调用的参数与结果、状态对象的迁移过程、人机交互的审批记录。DeerFlow 2.0把观测埋点做到了图执行的每个关键位置每个节点开始和结束时记录时间戳、入参出参、Token消耗路由返回决定后记录路由原因人工审核通过后记录审批意见。我建议部署时做两层采集第一层是日志采集把图执行的原始事件写进文件或日志采集器第二层是结构化指标比如节点耗时分布、工具调用成功率、研究深度轮次均长。有了这些数据你才能回答产品经理最常问的问题为什么这单研究任务跑了10分钟哪个环节最慢是不是该换更快的模型了5.2 状态快照追踪脑回路的最佳方式排查问题最有用的手段是回放图状态。每一次状态流转我都建议存一份快照包含当前节点、完整state字段、时间戳。出问题时你只要把快照拉出来就能看清Agent的脑回路它是基于什么信息做的判断为什么走到了错误分支是不是某个状态字段被污染了{ ts: 2025-06-12T10:24:31.882Z, node: reflection, state: { task: 对比DeerFlow与LangGraph, research_data: [...], reflections: [当前信息不足需要补充关于可观测性的资料], route: continue } }这份快照还是提示词调优和工具参数优化的依据。我常常对比多份成功/失败快照找出Agent在什么条件下会走偏然后针对性地调整节点内提示词或补充工具描述。5.3 高频问题与排查速查表症状可能原因排查动作任务卡住不往下走路由逻辑条件恒为false或节点内提示词导致LLM输出与预期不一致检查快照中route字段的实际值与路由函数条件是否匹配工具调用没有任何返回工具name与LLM函数调用声明不一致或工具执行抛了未捕获异常查看工具调用日志确认请求参数是否合法、工具是否注册SSE连接频繁断开服务端超时配置太短或中间代理未关闭缓冲调大读超时在响应头加X-Accel-Buffering: no并关掉其他代理缓冲报告质量忽高忽低检索阶段命中低质量内容或者阅读节点抽取不完整检查visited_urls和research_data的覆盖率增加过滤规则人工审批节点迟迟不通过审批事件没推送到前端或事件类型不匹配检查事件流stage回调是否被订阅核对前后端事件枚举5.4 再补一个我经常用的调试技巧本地调试图流程时根本不用每次都跑完整的SSE。我通常会在服务端暴露一个debug接口直接返回所有节点执行完后的完整state快照前端没接好之前也能快速验证图逻辑是否正确。等图逻辑没问题了再上SSE层调流式体验这样把逻辑问题和传输问题分开排Debug效率能提高不少。6. 写在最后的实操心得动手玩DeerFlow 2.0这段时间我最大的感受是这个框架的价值不在某个单点功能而在它对Agent应用开发方式的重新组织——状态先行、节点解耦、路由可编程、事件全链路可见。基于它做二次开发你不需要从零设计Agent编排方案而是把精力花在真正有价值的事情上定义你的业务节点、调优检索与阅读策略、打磨人工审批体验。如果你正准备把Deep Research能力接到自己的产品里我的建议是先从一个小场景跑通闭环比如只做行业新闻自动汇总研究把检索源换成你关注的媒体RSS把报告结构固定成简报模板。跑通之后再逐步加节点、加工具、加人机协同环节。这个框架允许你以很小的成本起步再按需长成一个复杂的Agent系统不至于一上来就被架构复杂度淹没。最后再分享一个很实用的小经验无论你基于它做什么Agent都要在设计阶段就把事件类型和状态字段定清楚先画图、再定事件枚举、最后写节点实现。凡是这个顺序反着来后面都会在联调阶段吃大亏——我改过三轮事件协议才稳定下来提前规划真的能少走很多弯路。
返回列表