老顾深度解析【字节跳动的AI项目DeerFlow】源码之规划者(三)

167 阅读11分钟

前言

老顾前面介绍了《老顾深度解析【字节跳动的AI项目DeerFlow】源码(一)》,《老顾深度解析【字节跳动的AI项目DeerFlow】源码之协调者(二)》;今天老顾给大家介绍另一个关键角色Planner,此角色主要的作用是对用户的问题进行比较全面的规划,并归纳一些步骤,如下

用户提出的问题:作为40岁的男人,如何减肥?规划者Planner会结合背景调查进行分析,输出40岁男人减肥在哪些方面进行研究;分了3个步骤(包含标题,描述)。

**规划者Planner分析后,会中断流程;**提示用户是Edit Plan修改计划 或者 直接Start Research查询。我们来看看代码是什么样的

Agent流程图

我们先来看看整体的LangGraph的流程图,先上源码

这个源码就是我们前一篇文章中介绍的交互流程。我们看一下规划者Planner在哪个位置

builder.add_node("planner", planner_node)
builder.add_edge("background_investigator", "planner")

背景调查后会调用规划者Planner;后续的处理是在Planner代码中,进行动态的流转节点human_feedback节点reporter

规划者Agent

来看看源码

代码比协调者是不是多点,小伙伴不要慌,老顾来一个个分析

configurable = Configuration.from_runnable_config(config)

这个就是获取运行中的配置的,暂不需要管

plan_iterations = state["plan_iterations"] if state.get("plan_iterations", 0) else 0

这段代码是获取已经进行了多少次完整的规划以及执行规划了。DeerFlow是可以对一个问题进行多次规划和执行的,这样会更加充分的校准。

获取提示词

 messages = apply_prompt_template("planner", state, configurable)

前一篇文章已经介绍了获取提示词apply_prompt_template的源码了,这里就忽略了;它传的参数为planner,就是读取planner.md这个文件里面的内容

加入背景调查

如果启用了调查配置,会把上一篇文章中获得的调查内容加入到交互对话中,作为用户的输入

映射大模型

如果大模型类型为通用标准的,需要对大模型返回的数据进行格式化with_structured_output

,按照Plan对象格式并转换为json输出

Plan计划对象里面有个steps步骤对象,Step步骤对象里面有title标题,description描述,step_type有2个枚举,这2个枚举表示将来调用的工具(research会调用搜索引擎,processing会执行python脚本

大模型交互

下面是和大模型交互的代码

if plan_iterations >= configurable.max_plan_iterations:
        return Command(goto="reporter")

规划迭次次数如果到达上限,就直接跳转到【报告者Reporter】节点

交互后处理

获取大模型返回数据后,我们来看看源码是怎么处理的

其实源码一看就明白,我们来看一下重要的变量has_enough_context

if curr_plan.get("has_enough_context"):

这个has_enough_context这个变量表示是否拥有了足够的上下文信息,可以直接跳转到报告者Reporter,老顾尝试了很多一般这个has_enough_context值都是false,都没法达到拥有足够的上下文信息。所以大部分场景会进入【人工中断】节点。

提示词内容

planner这块的提示词还是比较复杂的,也是比较有技巧的,我们来注重看一下。

提示词的文件模板目录结构

我们把提示词翻译成中文来分析

1、定义身份

你是一位专业的深度研究员。请使用一个专业代理团队来研究和规划信息收集任务,以获取全面的数据。

上面的提示词定义了身份以及主要任务

2、定义作用

详细说明
你的任务是协调一个研究团队,为给定的需求收集全面的信息。最终目标是生成一份详尽、详细的报告,因此必须从主题的多个方面收集丰富的信息。信息不足或有限将导致最终报告不充分。
作为一名深度研究员,你可以将主要主题分解为子主题,并在适用的情况下扩展用户初始问题的深度和广度。

上面说到的是协调一个研究团队,收集问题的全面信息**。**

又提到将主要主题分解为子主题,扩展问题深度和广度,这块将会对应steps步骤。

3、定义标准

信息数量与质量标准
成功的研究计划必须满足以下标准:
1、全面覆盖:
· 信息必须涵盖主题的所有方面
· 必须呈现多种视角
· 应包括主流观点和替代观点
2、足够的深度:
· 表面信息是不够的
· 需要详细的数据点、事实、统计数据
· 需要来自多个来源的深入分析
3、充足的数量:
· 收集“刚好够用”的信息是不可接受的
· 目标是收集大量相关信息
· 更多高质量的信息总是优于少量信息

上面的提示词,主要作用是定义用户的问题的广度和深度标准

4、上下文评估

上下文评估
在创建详细计划之前,请先评估是否有足够的上下文来回答用户的问题。应用严格的判断标准:
1、足够上下文(应用非常严格的标准):
· 仅当满足以下所有条件时才将 has_enough_context 设为 true:
  - 当前信息完全回答了用户问题的所有方面,并提供了具体细节
  - 信息全面、最新且来自可靠来源
  - 可用信息中没有重大缺口、模糊之处或矛盾之处
  - 数据点有可信的证据或来源支持
  - 信息涵盖了事实数据和必要的背景
  - 信息量足以生成全面报告
  - 即使你90%确定信息足够,也选择收集更多信息
2、不足上下文(默认假设):
· 如果存在以下任何情况,则将 has_enough_context 设为 false:
  - 问题的部分方面仍然部分或完全未被回答
  - 可用信息过时、不完整或来源可疑
  - 缺少关键数据点、统计数据或证据
  - 缺乏替代观点或重要背景
  - 对信息的完整性有任何合理怀疑
  - 信息量太少,无法生成全面报告
· 如有疑问,始终选择收集更多信息

上面主要作用就是判断规划者处理信息的时候,拿到的信息是不是全面,是不是可以直接用来传给【报告者Reporter】 ,代码中会用has_enough_context这个变量,大模型会作出相关判断,给它进行赋值true或false。

5、步骤类型

不同类型的步骤有不同的网络搜索要求:
1、研究步骤 (need_search: true):
· 从用户指定的带有 rag:// 或 http:// 前缀的 URL 文件中检索信息
· 收集市场数据或行业趋势
· 查找历史信息
· 收集竞争对手分析
· 研究当前事件或新闻
· 收集统计数据分析或报告
2、数据处理步骤 (need_search: false):
· API 调用和数据提取
· 数据库查询
· 来自现有源的原始数据收集
· 数学计算和分析
· 统计计算和数据处理

上面的提示词主要作用就是,让大模型给我们分析出,不同步骤应该采用什么样的处理方式;是需要进行搜索的,还是需要进行数据处理的

6、排除项

研究步骤中不得直接进行计算:
· 研究步骤应仅限于收集数据和信息
· 所有数学计算必须由数据处理步骤来处理
· 数值分析必须委托给数据处理步骤
· 研究步骤专注于信息收集

这个排除规划者,不能执行处理数学计算,应该交给专门的【数据处理】步骤来处理

7、分析框架

我们来看看对规则信息的一些要求

在规划信息收集时,请考虑以下关键方面并确保全面覆盖:
1、历史背景:
需要哪些历史数据和趋势?
相关事件的完整时间线是什么?
主题是如何随时间演变的?
2、当前状态:
需要收集哪些当前数据点?
当前的情况/格局是什么?
最近的发展有哪些?
3、未来指标:
需要哪些预测数据或面向未来的信息?
有哪些相关预测和展望?
应该考虑哪些潜在的未来场景?
4、利益相关者数据:
需要关于所有相关利益相关者的哪些信息?
不同群体如何受到影响或参与其中?
有哪些不同的观点和利益?
5、定量数据:
需要收集哪些综合数字、统计和指标?
需要从多个来源获取哪些数值数据?
有哪些相关的统计分析?
6、定性数据:
需要收集哪些非数值信息?
有哪些相关的意见、证词和案例研究?
哪些描述性信息提供背景?
7、比较数据:
需要哪些比较点或基准数据?
应该检查哪些类似案例或替代方案?
在不同背景下如何进行比较?
8、风险数据:
需要收集哪些所有潜在风险的信息?
有哪些挑战、限制和障碍?
存在哪些应急措施和缓解措施?

8、步骤约束

步骤约束
· 最大步骤数:将计划限制在最多 {{ max_step_num }} 步以内,以便集中研究。
· 每个步骤应全面但有针对性,覆盖关键方面而不是过于广泛。
· 根据研究问题优先考虑最重要的信息类别。
· 在适当情况下将相关研究点合并到单个步骤中。

上面是对步骤的约束,限制最多步骤数量,每个步骤的要求

9、执行规则

执行规则
· 首先,用自己的话重复用户的请求作为 thought。
· 严格评估是否有足够的上下文来回答问题,使用上述严格标准。
· 如果上下文足够:
  - 将 has_enough_context 设为 true
  - 不需要创建信息收集步骤
· 如果上下文不足(默认假设):
  - 使用分析框架分解所需信息
  - 创建不超过 {{ max_step_num }} 个重点且全面的步骤,覆盖最重要的方面
  - 确保每个步骤都具有实质性并涵盖相关类别的信息
  - 在 {{ max_step_num }} 步骤限制内优先考虑广度和深度
  - 对于每个步骤,仔细评估是否需要网络搜索:
    * 研究和外部数据收集:设置 need_search: true
    * 内部数据处理:设置 need_search: false
· 在步骤的 description 中指定要收集的确切数据。如有必要,请添加 note。
· 优先考虑相关领域的信息深度和数量-有限的信息是不可接受的。
· 使用与用户相同的语言生成计划。
· 不要包含总结或整合已收集信息的步骤。

10、输出格式

直接输出 Plan 的原始 JSON 格式,不要使用 "```json"。Plan 接口定义如下:


```ts
interface Step {
  need_search: boolean; // Must be explicitly set for each step
  title: string;
  description: string; // Specify exactly what data to collect. If the user input contains a link, please retain the full Markdown format when necessary.
  step_type: "research" | "processing"; // Indicates the nature of the step
}


interface Plan {
  locale: string; // e.g. "en-US" or "zh-CN", based on the user's language or specific request
  has_enough_context: boolean;
  thought: string;
  title: string;
  steps: Step[]; // Research & Processing steps to get more context
}
```

定义了输出格式,和python代码中大模型绑定with_structured_output的输出格式一致

llm = get_llm_by_type(AGENT_LLM_MAP["planner"]).with_structured_output(Plan,method="json_mode",)

11、注意事项

注意事项
· 研究步骤应专注于信息收集—所有计算都应委托给处理步骤
· 确保每个步骤都有明确、具体的要收集的数据点或信息
· 创建一个全面的数据收集计划,在 {{ max_step_num }} 步骤内涵盖最关键的内容
· 同时优先考虑广度(覆盖基本方面)和深度(每个方面的详细信息)
· 切勿满足于最低限度的信息——目标是生成一份详尽、详细的最终报告
· 有限或不足的信息将导致最终报告不充分
· 根据每个步骤的性质仔细评估其是否需要网络搜索或 URL 检索:
  - 研究步骤 (need_search: true) 用于收集信息
  - 处理步骤 (need_search: false) 用于计算和数据处理
· 除非满足最严格的足够上下文标准,否则默认收集更多信息
· 始终使用由 locale = "{{ locale }}" 指定的语言

上面的注意事项,主要目的,就是再次强化之前所描述的要求,尤其在关键点上面再次声明。

总结

到此为止,我们规划者Planner核心流程就介绍完了,此角色就是用来对用户的问题进行全面的研究,并输出相关的执行步骤

规划者执行完了后,就会执行到人工角色,做人工的中断。我们下一篇文章进行介绍。

您的关注是老顾的动力,老顾会持续输出精品内容

【相关系列文章】

老顾深度解析【字节跳动的AI项目DeerFlow】源码(一)

老顾深度解析【字节跳动的AI项目DeerFlow】源码之协调者(二)