LangGraph多Agent系统State设计实战:从Open Deep Research源码解析到最佳实践

Gemini 3 Pro三大Agent框架实战对比:ADK、LangGraph与Agno选型指南 AI Agent是大模型落地的核心范式,其本质是通过工具调用、状态管理与推理编排实现自主任务执行。理解Agent需从基础原理出发:它依赖LLM的函数调用能力(Tool Calling)、可追溯的中间状态(Stateful Execution)及可控的控制流(Conditional Routing)。当前主流方案围绕Gemini 3 Pro生态展开,Google ADK提供深度集成的开箱即用体验,LangGraph强调确定性状态机与可恢复流程,Agno则回归Python函数式极简抽象。三者在调试性、可靠性与多 阅读详情

本文通过分析Open Deep Research项目源码,详解LangGraph框架中多Agent系统的State设计思路。文章介绍了主图、监督者子图和研究者子图的State结构设计,讲解了基于需求分析、数据流转关系和Agent职责划分的字段设计方法,以及Reducer函数选择和默认值设置策略,为构建高效多Agent系统提供了实用参考。


本期我们继续研究Open Deep Research这个项目的源代码。上一期我们学习了多Agent架构的设计与实现,相信大家看的不是很过瘾,因为没有讲太多数据、信息流的实现。今天我们逐步进入深水区,先来聊聊Open Deep Research的各个Graph的State设计思路。

在LangGraph中,State(状态) 是连接各个节点的核心纽带,它承载着整个工作流的数据流转。如何根据任务需求设计合适的State结构,如何选择State的类型和更新策略,这些都是构建高效多Agent系统的关键。

项目文件结构

在进入正片之前,我们先来看一下Open Deep Research的项目文件结构,其核心代码位于src/open_deep_research/目录下,其中

  • • state.py:State定义文件,包含所有Graph State类的定义;
  • • deep_researcher.py:主Graph实现文件,定义了整个研究流程的Graph结构和节点函数;
  • • configuration.py:配置管理文件,定义了系统的配置选项和模型设置;
  • • prompts.py:提示词文件,包含各个Agent使用的系统提示词;
  • • utils.py:工具函数文件,包含辅助函数和工具定义。

本次学习主要关注state.py文件,它定义了系统中所有State类的结构,包括主图State(AgentState)、监督者子图State(SupervisorState)、研究者子图State(ResearcherState)等。

但为了让大家更好地理解,我不会直接展示源代码,而是从State设计的角度出发,带着大家一步步探索这些State是如何从需求分析到最终实现的。同时需要明确的是,本期核心是state 的设计思路,数据流转方面的细节将在后续专题写。

第一步:任务需求分析 - 理解需要管理哪些数据

为什么需要先分析任务需求?

State的设计必须基于实际的数据需求,而不是凭空想象。如果不先理解任务需求就设计State,可能会遗漏关键字段导致后续无法实现某些功能,也可能设计出冗余字段增加系统复杂度,还可能因为不理解数据流转关系而选择错误的Reducer函数(在该追加时用了覆盖,或相反),甚至因为不理解Agent之间的数据依赖关系而导致状态隔离不当,造成状态污染或数据丢失。

如何进行任务需求分析

任务需求分析是一个系统性的梳理过程:

  • • 首先需要梳理系统的核心业务流程,识别每个阶段的具体任务和产生的数据;
  • • 然后,基于流程分析列出每个阶段需要管理的数据类型及其用途;
  • • 最后,分析这些数据在Agent之间的传递和共享的方式,确定哪些数据需要共享、哪些需要保持隔离。

需要强调的是,从实践来看,事前的分析并不能保证State字段设计的完备性,但它至少能大幅降低我们出错的概率。事实上,很多State字段也是在搭建Graph的过程中,随着对系统理解的深入而补充完善出来的。因此,需求分析是一个持续迭代的过程,而不是一次性的工作。

我们以Open Deep Research为例,它是一个深度研究系统,其核心流程我们在上一期中已经进行了比较详细的分析:

  • • 用户输入阶段:接收用户提出的研究请求;
  • • 澄清阶段:分析用户需求并询问澄清问题;
  • • 研究简报生成阶段:将用户消息转换为结构化研究简报;
  • • 研究执行阶段:由监督者规划研究策略并委派多个研究者并行执行研究任务;
  • • 研究压缩阶段:每个研究者将收集的信息压缩整理;
  • • 报告生成阶段:整合所有研究结果生成最终报告。

基于这个流程,我们可以归纳出可能需要管理的数据包括:

  • • 用户消息:用户输入的研究请求和澄清回答,包括AI的部分回复;
  • • 研究简报:结构化的研究问题描述;
  • • 监督者消息:监督者的规划、委派和评估消息;
  • • 研究者消息:每个研究者的搜索、思考和总结消息;
  • • 研究笔记:收集到的研究资料和发现;
  • • 最终报告:生成的完整研究报告。

需求分析与State设计之间的联系

任务需求分析完成后,我们应该至少获得了三个关键信息:

  • • 需要管理的数据清单:包括用户消息、研究简报、监督者消息等;
  • • 数据流转关系:哪些数据需要在Agent之间传递和共享,哪些需要保持隔离;
  • • Agent职责划分:不同层级的Agent负责不同的任务,需要管理不同范围的数据。

这些结果直接影响State的设计:

首先,数据清单决定了State字段的设计,每个需要管理的数据都对应一个或多个State字段,例如用户消息对应messages字段,研究简报对应research_brief字段,监督者消息对应supervisor_messages字段;

其次,数据流转关系决定了Reducer函数的选择,需要累积的数据(如研究者消息需要保持完整的对话历史)使用追加策略(operator.add),需要重置的数据(如监督者消息在初始化时需要重置)使用覆盖策略(override_reducer),单值字段(如研究简报、最终报告)直接覆盖;

最后,Agent职责划分决定了字段在各Graph State中的分布,主图需要协调整个流程,因此主图State(AgentState)包含所有阶段的数据字段,而监督者子图专注于研究任务的规划与委派,其State(SupervisorState)只包含与监督者职责相关的字段,研究者子图专注于单个研究任务的执行,其State(ResearcherState)只包含与研究者职责相关的字段。

需要注意的是,有些字段是公用的,需要在多个Graph State中都定义,以便在Graph之间传递和共享数据。这些公用字段确保了数据可以在不同层级的Graph之间正确传递和聚合。

Open Deep Research的State字段

在具体进入字段分析之前,我列了个表格给大家一个整体的个感觉:

下面,我们来看看Open Deep Research是如何将这些需求转化为具体的State字段的。

第二步:将需求转化为具体的State字段

基于第一步的业务需求分析,由于不同层级的Agent有不同的职责,需要管理不同范围的数据,因此需要为每个层级的Agent设计独立的State,实现状态的隔离和职责的分离。同时,根据数据流转关系分析,有些数据需要在多个Graph State之间传递和共享,这些字段需要在多个State中都定义,以确保数据可以在不同层级的Graph之间正确传递和聚合。

注意,这部分相对有点复杂,强烈建议结合上一期关于架构的内容看(LangGraph实战研究 — Open Deep Research源代码学习:多Agent系统架构的设计思路与实现方法),效果更佳。

输入State:AgentInputState

介绍主图State之前,先来看一个特殊的State:AgentInputState。这个State虽然简单,但它在整个系统的设计中起到了关键作用:

class AgentInputState(MessagesState):    """InputState is only 'messages'."""

AgentInputState继承自MessagesState,只包含messages字段。它的作用不是作为图的内部状态,而是作为图的输入接口定义。

这里涉及到LangGraph的一个知识点:StateGraph除了第一个位置参数(也就是我们熟悉的主State)外,还有一个input参数用于指定图的输入接口,可以用来限制调用者提供的数据

我们来看下主图的初始化构建代码:

deep_researcher_builder = StateGraph(    AgentState,     input=AgentInputState,     config_schema=Configuration)

可以看到,在主图构建时, 第一个位置参数是AgentState,定义了图的内部完整状态。input=AgentInputState指定了图的输入接口,调用者只需要提供messages字段。

当用户调用图时,只需要传入符合AgentInputState格式的数据(即messages字段):

# 用户只需要传入 messages,符合 AgentInputState 的定义result = deep_researcher.invoke({    "messages": [HumanMessage(content="帮我研究一下LangGraph和LangChain的区别")]})

然后,LangGraph根据AgentState的定义,将输入数据转换为完整的内部状态。对于AgentState中未提供的字段,LangGraph会自动初始化为默认值(如空列表[]、None等):

{    "messages": [HumanMessage(content="帮我研究一下LangGraph和LangChain的区别")],    "supervisor_messages": [],      "research_brief": None,         "raw_notes": [],               "notes": [],                  "final_report": ""       }

最后,图的内部节点(如clarify_with_user、write_research_brief等)接收到的都是完整的AgentState,可以访问所有字段。随着图的执行,各个字段会被逐步填充。

这种输入接口抽象与状态管理分离的设计,既保证了调用接口的简洁性(用户只需要提供必要的messages字段),又保证了内部状态的完整性(图的节点可以使用完整的AgentState进行复杂的状态管理)。同时,LangGraph会在运行时自动验证输入数据是否符合AgentInputState的定义,未提供的字段会自动初始化为合理的默认值,避免了空值错误,提高了系统的健壮性和易用性。

接下来我们看主图State。

主图State:AgentState

主图需要协调整个研究流程,因此需要管理所有阶段的数据,下面我们对主图的AgentState中定义的字段进行注意分析:

class AgentState(MessagesState):    """Main agent state containing messages and research data."""        supervisor_messages: Annotated[list[MessageLikeRepresentation], override_reducer]    research_brief: Optional[str]    raw_notes: Annotated[list[str], override_reducer] = []    notes: Annotated[list[str], override_reducer] = []    final_report: str
1. messages(通过继承)

第一行可以看到AgentState(MessagesState),意味着Agentstate也继承了MessagesState,自动获得了messages字段。

如前所述,Agentstate的messages其实首先来自于AgentInputState,对应需求分析中的"用户消息"数据需求。在"用户输入阶段"和"澄清阶段"需要存储用户的研究请求和澄清回答。但同时,Agentstate的messages还包括了AI的部分回复。

例如,用户可能输入"帮我研究一下LangGraph和LangChain的区别"(HumanMessage),系统可能会回复"我需要一些澄清:您希望重点关注技术架构差异,还是使用场景对比?“(AIMessage),用户再回答"重点关注技术架构差异”(HumanMessage)。所有这些消息都会存储在messages字段中,形成完整的对话历史。

另外,在"报告生成阶段",final_report_generation节点也会读取messages字段来了解用户的语言偏好,确保生成的报告使用与用户输入相同的语言。

2. supervisor_messages

对应需求分析中的"监督者消息"数据需求。这个字段存储监督者在"研究执行阶段"产生的消息历史,包括AIMessage(监督者的规划决策,如调用think_tool、ConductResearch、ResearchComplete等)和ToolMessage(工具执行结果,如think_tool返回的反思内容、ConductResearch返回的研究者压缩后的研究结果)。

主图需要在AgentState中定义这个字段,主要有以下几个原因:

    1. 初始化并传递给监督者子图:主图在write_research_brief节点中需要通过Command的update参数初始化监督者的上下文(设置系统提示词和研究简报,细节又只能后面再讲了,不然写不完…),为监督者子图提供干净的起始状态。这个初始化操作需要更新主图State中的supervisor_messages字段。
    1. 数据传递和同步:主图通过research_supervisor节点调用监督者子图时,需要将supervisor_messages传递给子图,让子图在执行过程中能够读取和更新这个字段。更重要的是,监督者子图对supervisor_messages的更新需要同步反映到主图的AgentState中,这样才能保证主图能够跟踪整个研究过程的状态。
    1. 状态管理和功能扩展:主图需要存储和管理这个字段以便进行状态管理、调试监控或未来的功能扩展(例如,如果需要根据监督者的活动来调整报告生成策略)。

因此,虽然supervisor_messages主要在监督者子图中被使用和更新,但它必须在主图State中定义,这样才能在主图和监督者子图之间正确传递和同步数据。

3. research_brief

对应需求分析中的"研究简报"数据需求。在"研究简报生成阶段"(write_research_brief节点),系统会分析用户消息,使用结构化输出(ResearchQuestion)生成一个聚焦的研究问题描述。

这个研究简报将指导整个研究过程:监督者子图需要根据它来分解研究任务(如将研究分解为"LangGraph的核心特性"、“LangChain的核心特性”、"两者的对比分析"等子任务),主图在"报告生成阶段"也需要使用它来生成最终报告。

因此这个字段在主图State中定义,并通过Command的update参数传递给监督者子图,确保监督者能够理解研究目标并据此规划研究策略。

4. raw_notes 和 notes

对应需求分析中的"研究笔记"数据需求,但两者存储的内容和处理方式不同。

  • • raw_notes:存储原始的研究数据:在研究者的compress_research节点中,raw_notes包含研究者所有工具调用结果和AI消息的原始内容(如搜索结果、网页内容、API返回数据等),这些原始数据会被传递给监督者,监督者再聚合多个研究者的raw_notes传递给主图。
  • • notes:存储处理后的研究笔记:在监督者的supervisor_tools节点中,通过get_notes_from_tool_calls()函数从supervisor_messages中提取所有ToolMessage的内容(主要是研究者返回的压缩后的研究结果),这些notes是经过研究者压缩整理的结构化研究结果,比raw_notes更简洁和聚焦。在"报告生成阶段",final_report_generation节点使用notes(而不是raw_notes)作为研究发现的输入,因为notes已经包含了所有关键信息且格式更规范。

这两个字段在主图State中定义,用于收集和聚合所有研究者的成果,同时也需要在监督者和研究者子图中定义,以便在数据流转过程中传递和聚合。

5. final_report

对应需求分析中的"最终报告"数据需求。在"报告生成阶段"(final_report_generation节点),系统会整合所有研究结果生成完整的报告。

具体来说,final_report_generation节点会读取notes字段(包含所有研究者压缩后的研究结果)、research_brief字段(研究简报)和messages字段(用户消息历史),然后使用配置的报告生成模型生成一个结构化的、包含引用来源的完整研究报告。

这个字段只在主图State中定义,因为报告生成是主图的最终任务,子图不需要访问或管理最终报告。

监督者子图State:SupervisorState

监督者子图专注于研究任务的规划与委派,需要管理研究迭代和任务分配,其State字段设计基于Agent职责划分和数据流转需求:

class SupervisorState(TypedDict):    """State for the supervisor that manages research tasks."""        supervisor_messages: Annotated[list[MessageLikeRepresentation], override_reducer]    research_brief: str    notes: Annotated[list[str], override_reducer] = []    research_iterations: int = 0    raw_notes: Annotated[list[str], override_reducer] = []

可以看到,其中大部分字段已经在主图里有介绍,对于这部分就一笔带过。

1. supervisor_messages

监督者在规划研究策略、委派研究任务、评估研究进展时需要记录消息历史,这些消息用于监督者进行下一步决策。这个字段与主图State中的supervisor_messages是同一个字段。

2. research_brief

监督者需要根据研究简报来分解研究任务,因此需要访问这个字段。这个字段与主图State中的research_brief是同一个字段。

3. research_iterations

这是一个控制字段,不是直接来自需求分析的数据需求,而是为了满足"研究执行阶段"需要控制监督者循环次数的需求。

监督者可能会多次迭代规划和研究委派(在supervisor和supervisor_tools节点之间循环),需要防止无限循环。在supervisor节点中,每次调用后会将research_iterations加1;在supervisor_tools节点中,会检查research_iterations是否超过配置的最大迭代次数(max_researcher_iterations),如果超过则结束研究阶段。例如,如果max_researcher_iterations设置为5,当research_iterations达到6时,监督者会停止循环并返回研究结果。这个字段只在监督者子图State中定义,因为它是监督者内部的控制逻辑,不需要在主图中管理。

4. notes 和****raw_notes

监督者需要收集研究者返回的研究结果,这两个字段与主图State中的对应字段是同一个字段,确保数据可以在监督者子图和主图之间正确传递和聚合。

研究者子图State:ResearcherState

研究者子图专注于"研究执行阶段"中单个研究任务的执行和"研究压缩阶段"的信息整理,需要管理工具调用和研究结果。

class ResearcherState(TypedDict):    """State for individual researchers conducting research."""        researcher_messages: Annotated[list[MessageLikeRepresentation], operator.add]    tool_call_iterations: int = 0    research_topic: str    compressed_research: str    raw_notes: Annotated[list[str], override_reducer] = []
1. researcher_messages

对应需求分析中的"研究者消息"数据需求。研究者在执行研究任务时会产生多种类型的消息:AIMessage(包含研究者调用工具的决策,如调用tavily_search搜索信息、调用think_tool进行思考、调用ResearchComplete表示完成研究)和ToolMessage(工具执行结果,如搜索结果、网页内容、API返回数据等)。

这些消息需要被记录,以便后续的压缩和总结。例如,研究者可能会先调用think_tool思考研究策略,然后调用tavily_search搜索相关信息,再调用think_tool分析搜索结果,最后调用ResearchComplete表示完成。所有这些消息都会累积在researcher_messages中,在compress_research节点中,研究者会读取完整的researcher_messages历史来进行压缩和总结。

这个字段只在研究者子图State中定义,因为研究者的消息历史是研究者内部的工作记录,不需要在主图或监督者子图中管理。

2. tool_call_iterations

这是一个控制字段,不是直接来自需求分析的数据需求,而是为了满足"研究执行阶段"需要控制研究者工具调用循环次数的需求。研究者可能会多次调用工具进行搜索和研究(在researcher和researcher_tools节点之间循环),需要防止无限循环。在researcher节点中,每次调用后会将tool_call_iterations加1;在researcher_tools节点中,会检查tool_call_iterations是否超过配置的最大工具调用次数(max_react_tool_calls),如果超过则结束研究并进入压缩阶段。

例如,如果max_react_tool_calls设置为10,当tool_call_iterations达到11时,研究者会停止工具调用循环并进入compress_research节点。这个字段只在研究者子图State中定义,因为它是研究者内部的控制逻辑。

3. research_topic

对应需求分析中"研究执行阶段"的数据流转需求。监督者委派研究任务时,通过调用ConductResearch工具将具体的研究主题传递给研究者。

例如,如果监督者将研究任务分解为"研究LangGraph的核心特性和架构",它会调用ConductResearch(research_topic="研究LangGraph的核心特性和架构,包括其设计理念、主要组件、使用场景等"),这个research_topic参数会作为HumanMessage的内容传递给研究者,同时也会存储在research_topic字段中。研究者需要根据这个主题进行专门的研究,在researcher节点中,研究者会读取research_topic来理解自己的研究任务,然后调用相应的工具(如搜索工具)来收集相关信息。

这个字段只在研究者子图State中定义,因为它是监督者传递给研究者的任务参数,每个研究者都有自己独立的研究主题。

4. compressed_research

对应需求分析中"研究压缩阶段"的数据需求。在"研究压缩阶段"(compress_research节点),研究者需要将收集的信息压缩整理成结构化的研究结果。具体来说,compress_research节点会读取完整的researcher_messages历史(包含所有搜索请求、工具调用结果、AI思考等),然后使用配置的压缩模型(compression_model)对这些消息进行压缩和整理,生成一个清晰、全面的研究摘要。

例如,如果研究者研究的是"LangGraph的核心特性",compressed_research可能包含"LangGraph是一个用于构建有状态、多参与者应用的框架,主要特性包括状态管理、循环控制、条件分支等,适用于需要复杂工作流的场景"这样的结构化总结。这个结果需要返回给监督者,监督者会将多个研究者的compressed_research聚合后用于后续的规划决策。

这个字段在研究者子图State中定义,用于存储压缩后的研究结果,同时也出现在ResearcherOutputState中,用于返回给监督者。

5. raw_notes

在compress_research节点中,raw_notes是通过提取researcher_messages中所有ToolMessage和AIMessage的内容生成的,包含了研究者收集的所有原始信息(如搜索结果、网页内容、API返回数据、AI的思考过程等)。

这些原始数据会被传递给监督者,监督者再聚合多个研究者的raw_notes传递给主图,主图可以保留这些原始数据以备后续需要。这个字段与主图State和监督者State中的raw_notes是同一个字段。

好了,我们终于把Open Deep Research的各个重要state字段定义过了一边。下面我们再来继续看一下state设计中的其他细节。

第三步:设计Reducer函数 - 控制状态更新策略

在LangGraph中,State字段的更新不是简单的赋值,而是通过Reducer函数来控制如何合并新旧值。Open Deep Research根据数据流转关系的分析,为不同的字段选择了合适的Reducer函数。

override_reducer:灵活的覆盖与追加策略

override_reducer是Open Deep Research中一个自定义的Reducer函数,它实现了一种灵活的更新策略:既支持完全覆盖,也支持追加操作。让我们先看看它的实现。

def override_reducer(current_value, new_value):    """Reducer function that allows overriding values in state."""    if isinstance(new_value, dict) and new_value.get("type") == "override":        return new_value.get("value", new_value)    else:        return operator.add(current_value, new_value)

这个函数的工作原理是:首先检查new_value是否是一个包含"type": "override"键的字典。如果是,则完全覆盖当前值;否则,使用operator.add将新值追加到列表中。这种设计使得同一个字段既可以支持覆盖操作(用于初始化或重置),也可以支持追加操作(用于累积数据)。

supervisor_messages字段就使用了override_reducer。在"研究简报生成阶段"完成后,主图需要初始化监督者子图,开始"研究执行阶段"。此时,监督者需要从一个干净的状态开始工作,而不是在旧的消息历史基础上追加。因为每次研究任务都是独立的,如果使用简单的追加策略,可能会导致不同研究任务的消息历史混在一起,影响监督者的决策。

在write_research_brief节点中,主图通过Command来初始化时,使用了覆盖策略去处理supervisor_messages:

return Command(        goto="research_supervisor",         update={            "research_brief": response.research_brief,            "supervisor_messages": {                "type": "override",                "value": [                  SystemMessage(content=supervisor_system_prompt),HumanMessage(content=response.research_brief)                ]            }        }    )

这里通过{"type": "override", "value": [...]}的特殊格式来触发覆盖操作,重置supervisor_messages,确保监督者从干净的状态开始工作。

而在监督者子图的执行过程中,当监督者生成新的规划决策或工具执行结果时,这些消息会以普通列表的形式追加到supervisor_messages中,因为此时不需要覆盖,而是需要累积消息历史。

operator.add:纯粹的追加策略

与override_reducer的灵活策略不同,researcher_messages字段使用了operator.add作为Reducer函数,这是一种纯粹的追加策略。

研究者在"研究执行阶段"会多次调用工具进行搜索和研究,每次操作都会产生新的消息。这些消息包括研究者的思考过程(AIMessage)、工具调用请求、工具执行结果(ToolMessage)等。根据数据流转关系分析,这些消息需要累积保存,而不是覆盖,因为后续的"研究压缩阶段"需要访问完整的对话历史来进行压缩和总结。

例如,研究者可能会先调用think_tool思考研究策略,然后调用tavily_search搜索相关信息,再调用think_tool分析搜索结果,最后调用ResearchComplete表示完成。所有这些消息都需要被完整地记录下来,形成一个完整的对话历史。如果使用覆盖策略,每次更新都会丢失之前的消息,导致compress_research节点无法获取完整的研究过程信息,无法生成准确的研究摘要。

因此,researcher_messages使用operator.add追加策略,确保每次工具调用都会添加新的消息到列表中,保持完整的对话历史。这样,当研究者进入compress_research节点时,可以读取完整的researcher_messages历史,了解整个研究过程,从而生成更准确、更全面的研究摘要。

默认行为:直接赋值覆盖

对于没有指定Reducer函数的字段,LangGraph会使用默认行为:直接使用新值覆盖旧值。在Open Deep Research中,大部分非列表类型的字段(如research_brief、final_report、research_iterations、tool_call_iterations、research_topic、compressed_research等)都没有指定Reducer函数,因此使用默认的覆盖行为。

这些字段通常是单值字段,不需要累积历史,每次更新都应该用新值替换旧值。例如,research_brief在研究简报生成阶段被设置后,在整个研究过程中保持不变,直到下一次研究任务;final_report在报告生成阶段被设置后,就是最终的输出结果,不需要追加或累积。

需要注意的是,列表类型的字段如果不指定Reducer函数,也会使用默认的覆盖行为,但这通常不是我们想要的。因为列表字段通常需要追加操作来累积数据,所以Open Deep Research中所有的列表字段都明确指定了Reducer函数(operator.add或override_reducer),而不是依赖默认行为。

第四步:State字段的默认值设计

在State定义中,有些字段有默认值,有些没有。这个设计不是随意的,而是基于字段的使用场景和初始化需求来决定的。

列表字段的默认值设计

在Open Deep Research中,列表类型的字段通常都有默认值,例如raw_notes和notes字段:

raw_notes: Annotated[list[str], override_reducer] = []    notes: Annotated[list[str], override_reducer] = []

为什么列表字段需要默认值呢?这要从Reducer函数的工作机制说起。当我们使用operator.add或override_reducer等Reducer函数时,这些函数会对当前值和新值进行合并操作。如果字段在初始化时没有默认值,LangGraph可能会将其视为None或未定义状态。此时,如果节点尝试使用Reducer函数更新这个字段(例如使用operator.add追加新元素),就会因为无法对None执行列表操作而报错。

提供默认空列表[]可以确保字段在初始化时就有一个有效的列表对象,后续的Reducer函数可以正常对其进行追加或覆盖操作。这样,即使某个节点是第一次更新这个字段,也不会因为字段未初始化而出错。

非列表字段的默认值设计

对于非列表类型的字段,Open Deep Research采用了不同的策略。以AgentState中的几个字符串字段为例:

class AgentState(MessagesState):    """Main agent state containing messages and research data."""        supervisor_messages: Annotated[list[MessageLikeRepresentation], override_reducer]    research_brief: Optional[str]    raw_notes: Annotated[list[str], override_reducer] = []    notes: Annotated[list[str], override_reducer] = []    final_report: str

research_brief字段被定义为Optional[str],没有默认值,允许为None。这是因为在研究流程的早期阶段(用户输入和澄清阶段),研究简报还没有生成,此时research_brief应该是None,表示"还未生成研究简报"。如果给它一个默认值(如空字符串""),就无法区分"还未生成"和"已生成但为空"这两种状态。使用Optional[str]类型配合None值,可以清晰地表达字段的状态,让代码逻辑更加明确。

又如final_report字段被定义为str类型,也没有默认值。虽然这个字段在初始化时可能为空,但它是必需的字段,表示最终报告的内容。在报告生成之前,这个字段可能不存在于State中,或者需要通过其他方式处理。如果给它一个默认空字符串,可能会在报告生成逻辑中造成混淆,因为无法区分"还未生成报告"和"报告内容为空"这两种情况。

这种设计体现了类型系统的作用:通过类型定义(如Optional[str])和是否提供默认值,我们可以清晰地表达字段的语义和状态,让代码更加健壮和易于理解。

总结

Open Deep Research的State设计采用了分层隔离与共享字段结合的策略:

  • • 主图State管理整个流程的数据,监督者和研究者子图State只管理各自职责范围内的数据,同时通过共享字段(如supervisor_messages、research_brief、notes等)实现数据在不同层级Graph之间的传递和聚合。
  • • 通过InputState分离输入接口和内部状态,简化了调用者的使用复杂度;
  • • 通过Reducer函数(override_reducer、operator.add)灵活控制状态更新方式,支持覆盖和追加两种策略;
  • • 通过合理的默认值设计,确保字段初始化的正确性。

这种State设计为构建复杂的多Agent系统提供了优秀的参考范例,既保证了数据的正确流转,又实现了良好的模块化和可维护性。

AI大模型从0到精通全套学习大礼包

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

只要你是真心想学AI大模型,我这份资料就可以无偿共享给你学习。大模型行业确实也需要更多的有志之士加入进来,我也真心希望帮助大家学好这门技术,如果日后有什么学习上的问题,欢迎找我交流,有技术上面的问题,我是很愿意去帮助大家的!

如果你也想通过学大模型技术去帮助就业和转行,可以扫描下方链接👇👇
大模型重磅福利:入门进阶全套104G学习资源包免费分享!

在这里插入图片描述

01.从入门到精通的全套视频教程

包含提示词工程、RAG、Agent等技术点
在这里插入图片描述
​

02.AI大模型学习路线图(还有视频解说)

全过程AI大模型学习路线

在这里插入图片描述
​在这里插入图片描述

03.学习电子书籍和技术文档

市面上的大模型书籍确实太多了,这些是我精选出来的

在这里插入图片描述
在这里插入图片描述

04.大模型面试题目详解

在这里插入图片描述

在这里插入图片描述

05.这些资料真的有用吗?

这份资料由我和鲁为民博士共同整理,鲁为民博士先后获得了北京清华大学学士和美国加州理工学院博士学位,在包括IEEE Transactions等学术期刊和诸多国际会议上发表了超过50篇学术论文、取得了多项美国和中国发明专利,同时还斩获了吴文俊人工智能科学技术奖。目前我正在和鲁博士共同进行人工智能的研究。

所有的视频由智泊AI老师录制,且资料与智泊AI共享,相互补充。这份学习大礼包应该算是现在最全面的大模型学习资料了。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

在这里插入图片描述
在这里插入图片描述

智泊AI始终秉持着“让每个人平等享受到优质教育资源”的育人理念‌,通过动态追踪大模型开发、数据标注伦理等前沿技术趋势‌,构建起"前沿课程+智能实训+精准就业"的高效培养体系。

课堂上不光教理论,还带着学员做了十多个真实项目。学员要亲自上手搞数据清洗、模型调优这些硬核操作,把课本知识变成真本事‌!

在这里插入图片描述
如果说你是以下人群中的其中一类,都可以来智泊AI学习人工智能,找到高薪工作,一次小小的“投资”换来的是终身受益!

应届毕业生‌:无工作经验但想要系统学习AI大模型技术,期待通过实战项目掌握核心技术。

零基础转型‌:非技术背景但关注AI应用场景,计划通过低代码工具实现“AI+行业”跨界‌。

业务赋能 ‌突破瓶颈:传统开发者(Java/前端等)学习Transformer架构与LangChain框架,向AI全栈工程师转型‌。

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

别再死磕GAN了!用PyTorch从零实现DDPM图像生成(附CIFAR-10完整代码) 本文详细介绍了如何使用PyTorch从零实现DDPM(Denoising Diffusion Probabilistic Models)图像生成模型,并在CIFAR-10数据集上进行训练和测试。通过对比GAN,DDPM展现出更稳定的训练过程和更高质量的生成效果。文章包含完整的代码实现、训练技巧和优化建议,帮助开发者快速掌握这一前沿的生成模型技术。 阅读详情

相关推荐

工业机器人关节拆装流程_一文读懂模块化直驱电机及机器人关节模组

私信“干货”二字,即可领取138G伺服与机器人专属及电控资料!如果说芯片是智能行业最为重要的核心元件,那么电机几乎可以说是支撑了整个自动化和大工业生产以及现代社会最为重要的部件,全世界90%的能源是由电机发出来的,而70%是由电机消耗调的,电机可以说是整个人类社会能源循环的占有绝对地位的产品。普通伺服电机伺服电机其实已经算是电动机中比较高端的类型,特别是永磁同步类型的伺服电机,由于其启动快速,惯量...

weixin_32159771的博客 2155

LangGraph实战项目:从零手搓DeepResearch(四)——OpenDeepResearch源码解析与本地部署

本文深入解析LangChain官方OpenDeepResearch项目,通过源码分析详细对比Graph工作流与Multi-Agent多智能体两种架构的设计思路与核心节点。从复杂项目中掌握智能体开发技巧

weixin_42782643的博客 1279

ArcGIS新手必看:5分钟搞定等高线转DEM栅格(附完整操作截图)

本文详细介绍了在ArcGIS中将等高线转换为DEM栅格的完整流程,包括CAD数据预处理、TIN转栅格和直接插值法两种核心方法,以及常见问题排查与优化技巧。通过实战案例和操作截图,帮助GIS新手快速掌握这一测绘数据处理的核心技能,提升地形分析和三维可视化效率。

dapp9builder的博客 287

多Agent架构深度解析:从Open Deep Research源码学习大模型应用

Open Deep Research采用三级分层嵌套架构实现高效多Agent协作:主图负责流程编排,监督者子图分解任务并委派,研究者子图执行具体研究。通过LangGraph的子图复用和异步并行机制,实现职责分离与并行执行。主图为线性管道结构,监督者子图采用循环决策机制,研究者子图可并行实例化。这种分层设计为复杂AI任务提供了清晰架构参考,展示了如何通过子图复用构建可扩展的多Agent系统。

datian1234的博客 734

工业以太网通讯Profinet协议详解

Profinet是通过西门子控制系统被广泛使用的工业通信协议,是一种较新的,基于以太网的工业通讯协议。

mydatai的专栏 8852

python点云可视化

Python三种点云可视化方案:mayavi、matplotlib、CloudCompare。

叶子的博客 1万+

DeerFlow github-deep-research 实战解析:一份由 Agent 自动生成的仓库深度研究报告及其方法论

本文以 DeerFlow 仓库内真实保存的一份研究报告 [research_deerflow_20260201.md](https://link.gitcode.com/i/a6fc66f7ea5e8bf1ea1c71aa90108afe) 为主体,完整拆解这份"DeerFlow 对自己进行 Deep Research"产出的报告内容(仓库元数据、三阶段时间线、多智能体架构、功能矩阵、指标对比与置

gitblog_00851的博客 245

C#调用企业微信JS-Sdk实现扫描二维码

企业微信JS-SDK是企业微信面向网页开发者提供的基于企业微信内的网页开发工具包。通过使用企业微信JS-SDK,网页开发者可借助企业微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用企业微信分享、扫一扫等企业微信特有的能力,为企业微信用户提供更优质的网页体验提示:生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是H5应用调用企业微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。

清浅 937

【必收藏】LangGraph深度研究智能体实战:LangChain官方OpenDeepResearch完整源码解析与本地部署指南

本文深入解析了LangChain官方OpenDeepResearch项目,对比了Graph工作流与Multi-Agent多智能体两种架构的设计思路。Graph模式采用规划-执行的顺序流程,包含生成报告计划、人工反馈确认、并行研究写作等关键节点;Multi-Agent模式则通过监督者与研究员协作实现并行研究。文章提供了从环境配置到本地部署的完整实践指南,并详细分析了两种架构的核心源代码,帮助开发者掌握复杂AI智能体系统的构建方法。

优快云_224022的博客 1278

【数据分享】12.5米分辨率DEM地形数据(分省)

该数据来源于NASA地球科学数据网站(https://nasadaacs.eos.nasa.gov/),是ALOS卫星获取的高精度地形数据。该数据由于精度高,包括全省范围的数据和省内每个城市范围的数据!

JData_Engineer的博客 2171

YOLOv8-COCO指标转换

本文介绍了将YOLO格式数据集转换为COCO格式并评估模型性能的完整流程。首先需将YOLO格式的标注数据转换为COCO格式,通过修改classes、image_path等参数适配不同数据集。然后使用YOLO模型对验证集进行预测并保存结果为JSON格式。最后通过比较预测结果和转换后的COCO标注文件,使用COCO官方评估指标和TIDE工具进行性能分析,生成包含AP、AR等指标的报告及错误分析图表。整个过程实现了从数据准备到模型评估的完整闭环,为计算机视觉任务提供标准化的性能评估方案。

FJN110的博客 402

Deep Agents 示例库全解析:从终端编码助手到自托管异步子代理的 15 个实战模式

Deep Agents(`GitHub_Trending/de/deepagents`)是一个"batteries-included"的 Agent harness,而 `examples/` 目录正是其能力的集中展示:这里收录了 15 个真实可运行的 Agent 与模式,覆盖研究、编码、内容创作、可部署服务与高级循环范式。阅读本文后,你将掌握这些示例的分类脉络、各自的启动方式、核心实现原理,以及

gitblog_00346的博客 327

cesium 综合教程200+【目录】(已包含186篇文章)

cesium示例教程100+旨在为开发者提供简单快捷的,。在每一个示例中,解释相应的API知识点,做到。目录中有链接的为已有文章,没链接的为目标文章,不断更新中…

大剑师兰特的GIS世界 8893

深入 Lix 安全沙箱:seccomp、no-new-privileges 与 Pasta 网络隔离三重防御

Lix 是一个注重正确性与可用性的现代 Nix 包管理器实现。这篇文章带你深入 Lix 构建沙箱的核心:seccomp 系统调用白名单、no-new-privileges 提权锁和 Pasta 网络隔离,理解这三重防御如何协作,确保任意构建代码都被关进牢笼。 ## 🔒 为什么构建沙箱需要三重防御? 构建过程中,Lix 会执行由包维护者编写的任意构建代码。沙箱必须同时保证两件事:**构建纯净*

gitblog_00119的博客 375

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Deep Agents 框架-基础篇

DeepAgents是LangChain生态中的高级API,构建于LangChain核心智能体模块和LangGraph运行时之上,旨在简化复杂智能体的开发。它提供任务规划、文件系统管理、子智能体生成等内置功能,适用于长期运行的多步骤任务。然而,DeepAgents并非独立框架,仍需依赖LangChain和LangGraph,学习成本较高。文档详细介绍了其核心能力、与LangChain/LangGraph的差异、配置方法及最佳实践,强调其在处理复杂任务时的优势,但也指出工程化选择需谨慎考虑其依赖关系和实际需求

yanghuashuiyue的专栏 442

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

AI Agent 学习路线全解:Agent Learning Hub 从最小 Agent Loop 到生产级 Harness 的实战清单

> 本文以 Agent Learning Hub 仓库的 [README.md](https://link.gitcode.com/i/15f0f425aa27d154b7dad2276299c687) 为骨架,系统拆解一份"可以照着执行"的 AI Agent 学习 todo list:从区分 chatbot 与 agent 的 Stage 0 出发,途经最小 Agent Loop、工具调用与 R

gitblog_00867的博客 1028

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

用 Java 对齐 LangChain Deep Agents Harness (一)

如果你做过 LLM Agent,大概经历过这些坑:Deep Agents 的核心答案不是「再换一个更强的模型」,而是加一层 Harness(智能体套件):本项目是这套思想的 Java 实现:一个统筹 Agent + + (默认继承统筹工具),前端通过 SSE 看工具轨迹并处理审批卡片。 1.2 一次用户消息怎么走 智谱 MCPresearch-agentOrchestratorTools统筹 AgentExecutorExAssistantChatServiceAssistantController浏览器

qq_38363255的博客 197

DeerFlow架构深度解析:LangGraph驱动的超级智能体引擎是如何运作的(Harness/App分层设计)

DeerFlow(**D**eep **E**xploration and **E**fficient **R**esearch **Flow**)是一个开源的**超级智能体引擎(SuperAgent Harness)**,它基于 LangGraph 构建,能够自主完成调研、编码、内容创作等从几分钟到几小时不等的复杂任务。本文带你深入它的架构内核,揭秘 **Harness/App 分层设计**是如

gitblog_00276的博客 405

local-deep-research v1.8.1 发布指南:Egress 出站策略、Fail-Closed 编程 API 与安全加固全解

本文基于仓库中的 [v1.8.1 发布说明](https://link.gitcode.com/i/c554709456861b74b4621cfb9792e532),完整拆解 local-deep-research(下文简称 LDR)该版本的核心变更:四项破坏性变更(Breaking Changes)、覆盖凭据泄露清理与出站策略多轮对抗性加固的安全改造、Adaptive 出站范围与统一后台索引协

gitblog_00591的博客 999

DeerFlow深度解析:开源超级智能体框架的架构设计与实战应用

DeerFlow(Deep Exploration and Efficient Research Flow)是一款基于LangGraph构建的开源超级智能体框架,专为处理分钟到小时级别的复杂任务而设计。作为一个全栈AI编排系统,它将语言模型、沙箱执行、持久化内存和模块化技能深度集成,实现了从简单查询到多步骤工作流的端到端自动化。不同于传统的单点AI工具,DeerFlow采用分布式架构设计,支持动态

gitblog_00782的博客 911

Magpie 窗口缩放故障排查完整指南:快捷键、卡顿、触控问题一次搞定

Magpie 是一款 Windows 10/11 的窗口超分辨率工具,可以把游戏窗口用 Lanczos、Anime4K、FSR 等算法放大渲染,画面更清晰还不占资源。用久了你多半会碰到几类糟心事:快捷键按了没反应、缩放后画面卡顿、和 RTSS 之类工具叠出双层叠加层,或者触屏设备点不动。别急,这些问题九成是设置或权限问题,跟着下面的顺序一步步来,基本都能自己解决。 ## 快速自查:先做这 5 步

gitblog_01033的博客 345

从全量上下文到检索增强生成:Open Notebook 的 AI Context 与 RAG 机制全解析

本篇深入剖析 Open Notebook(NotebookLM 的开源实现)如何让大模型"感知"你的研究资料:Chat 模式使用**全量内容上下文**,Ask 模式使用**检索增强生成(RAG)**。读完你将掌握两条技术路线的取舍依据、RAG 三阶段的工作原理、底层全文检索与向量检索的真实实现,以及贯穿其中的"上下文三级管控 + 显式检索审计"隐私设计,并知道如何在仓库源码中逐层验证这些机制。

gitblog_00020的博客 572

用 Java 对齐 LangChain Deep Agents Harness(二)

作用: 对齐 Python TodoListMiddleware 的提示词 作用: 单条待办结构 作用: pending / in_progress / completed 作用: 按 session 外置 todos(委托 TodoRepository) 作用: 沙箱 workspace 读写编辑 作用: 声明式文件权限规则(allow/deny/interrupt) 作用: 按 glob 求值文件操作是否允许 作用: 长期记忆(对齐 MemoryMiddleware) 作用: 技能渐进式

qq_38363255的博客 266

从零到一:如何用HuggingFace Agents-Course构建你的第一个智能体系统

想要掌握AI智能体开发的核心技能?HuggingFace的Agents-Course项目为你提供了一套完整的实战指南,让你从理论到实践,快速构建功能强大的智能体系统。这个开源项目不仅覆盖了智能体基础概念,还深入讲解了LangGraph、SmolAgents等前沿框架的应用,是中级开发者提升AI应用开发能力的绝佳资源。 ## 🎯 设计哲学:为什么智能体是AI的未来? 智能体(Agent)正在彻

gitblog_00086的博客 455

从“文档懂王”到“工程落地”:我用LangChain造了一个会写代码的Agent

这篇文章摘要了作者在使用LangChain、LangGraph和Deep Agents开发编码助手项目时的经验教训与解决方案: 理想与现实的落差:作者发现官方文档的示例与真实项目存在巨大差距,200万字学习笔记在实际开发中失效,遭遇了token消耗失控、路径解析错误和死循环等问题。 框架关系解析:文章拆解了langchain-core(接口标准)、langgraph(运行时引擎)、langchain(应用框架)和deepagents(工具链)之间的层级依赖关系,指出这是从抽象到具体的实现链条。 开发环境搭建

General_zy的博客 610

深入解读 DeerFlow 2.0:开源 Long-Horizon Super Agent Harness 的架构、配置与实战指南

DeerFlow(**D**eep **E**xploration and **E**fficient **R**esearch **Flow)** 是一个基于 LangGraph / LangChain 构建的开源 **super agent harness**:它以可扩展的 **skills** 为驱动,把 **sub-agents**、**memory** 与 **sandbox** 组织在

gitblog_00040的博客 444
上一篇: 大模型进阶必学:MCP、Agent、RAG、RPA、A2A五大核心技术全解析,收藏备用!
下一篇: 2026大模型学习指南:从Java到AI+,程序员职业升级的必经之路!_大模型应用开发实战
智泊AI官方
博客等级 码龄6年 8638粉丝 2667原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值