前言
之前我在想网络上信息鱼龙混杂,AI大模型容易出现幻觉,我能否做一个程序进行对我想要获取的信息或研究进行收集整理呢?甚至他能够越用越好呢?我不断获取到网上的信息让这个引擎做到"取其精华,取其糟粕"。很明显这是一个大工程。
价值在何处
价值转换为更通俗的就是:我用这个系统会发生什么,发生这的事件对我有什么用?
我想要一个能够能够输入主题后,然后其能够搜索互联网上的信息,生成一份研究报告的系统。
听起来好像很简单。那么如果要加上一个准确,可信,解惑,时效性,可进化,自适应这些关联词是否就很难。没错我就是想要做这么一个引擎,网络上有用的信息很多,迷惑人的也很多,我要找到这些信息,转化为让自己准确判断信息的得了"助手"。这个助手我要他像一个得力助手一样,这样看来好像是个机器人,也更像是我们所说的agent,那么我就要做这么一个agent。
ScoutLoop

scout中文意思为"侦察",Loop循环。agent的本质不就是感知 -> 规划 -> 行动 -> 再感知的循环吗。
所以我取名为ScoutLoop。
OODA架构的选型
要想实现准确,可信,解惑,可进化,自适应 这几个标签,单纯的接入搜索引擎然后大模型输出肯定是不行的。所以当时我想的是采用的是**"分层工作流 + 多智能体协作 + 质量反馈闭环"** 的架构,核心目标不是让模型一次性生成答案,而是模拟一个完整的研究过程:**先规划、再检索、整理证据、审查质量,不足就补充研究,最后再输出报告。**当然这只是初次想法建成,后面很多想法是突然迸发的。
OODA的概念:
Observe:调用工具、获取环境信息、检索数据
Orient:LLM 理解上下文、梳理现状、识别目标与约束
Decide:规划下一步动作,选择工具、编排任务
Act:执行调用、发起请求、输出结果
OODA的这个思想和我想做的程序想法很相似,所以一开始我的方向确实是,按照这个方式来的。
为什么选择 OODA,而不是单层 ReAct?
ReAct 更适合解决一个局部问题:模型面对某个子问题时,应该调用什么工具、何时结束。
OODA 的 Critic 可以从全局视角判断缺口,并动态追加子问题;
OODA是一个更宏观的布局。因此有了一下布局。
|---------|----------------------------|-------------------|
| OODA 阶段 | 项目节点 | 职责 |
| Observe | Planer/Scout | 搜索网页、论文、新闻等信息 |
| Orient | Analyst | 提取结构化笔记、实体和属性 |
| Decide | Critic | 对照验收标准审查覆盖度、矛盾和缺口 |
| Act | Orchestrator / Synthesizer | 继续补搜或生成报告 |
这是典型的职责分离设计。
Planner:定义研究边界
Planner 生成研究方面、子问题和验收标准。
原因:如果没有研究框架,后续搜索容易变成随机堆资料;有了验收标准,Critic 才有明确依据判断"是否完成"。
其中这里也有很多的坑:比如研究依据太过苛刻,引擎很难得到有效资料通过验收标准,像一个在难为人的老板。
Scout:只负责找资料
每个 Scout 只处理一个子问题,输出原始搜索结果。
原因:
- 降低单个 Agent 的上下文复杂度;
- 可并行处理多个问题;
- 搜索和知识整理分离,便于替换数据源或调整检索策略。
这里搜索接口就是"tavily",存在的坑也很多:对于有些网站其实"tavily"可能也搜索不到,无法爬取,以及如果不对搜索源进行限制,搜索出来的内容质量可能会较差,这就很考验信息源了。
Analyst:只负责结构化知识
Analyst 将原始网页资料转成带来源的 ResearchNote,并聚合实体属性。
原因:搜索结果是噪声较多的非结构化内容,不能直接给 Critic 或报告生成器使用。先沉淀为结构化笔记,后续审查和复用更稳定。
Critic:负责质量控制,而不是生成内容
Critic 不负责"写得漂亮",而是负责判断:
- 子问题是否被回答;
- 哪些研究方面已经达标;
- 多个来源是否有潜在冲突;
- 是否要继续追加验证问题;
- 是否应该结束研究。
原因:把"生成"与"审核"分离,避免同一个模型既当运动员又当裁判,至少在流程上提供独立的质量关卡和退出控制。
Synthesizer:只负责最终表达
它基于已经整理和审查过的笔记生成报告。
原因:报告生成不应直接依赖未经审查的网页搜索内容,否则容易把噪声或冲突信息直接写入结果。
多agent框架的选型
LangGraph 是该项目的Agent 工作流编排框架,不是简单的 LLM SDK。
选择它是因为项目有几个典型需求:
1. 工作流不是线性的
项目存在循环:
Critic 不通过
→ 追加子问题
→ Orchestrator 再调度
→ Scout 再搜索
→ Analyst 再整理
→ Critic 再审查
LangGraph 的状态图和条件边适合表达这种"节点 + 路由 + 循环"的结构。
2. 需要并行 Scout
项目使用 Send API 将多个子问题并行发送到 Scout 子图:
一个研究主题
→ 拆成多个子问题
→ 多个 Scout 并行搜索
→ Reducer 汇总结果
相比手写 asyncio 调度,LangGraph 将图拓扑、状态传递、汇聚逻辑统一管理,代码职责更清晰。
3. 需要状态隔离
主图的 AuroraState 保存全局状态,例如研究主题、笔记、当前轮次和质量结果。
每个 Scout 使用独立的 ScoutState,保存自己的子问题、工具结果、局部预算和执行状态。
原因是并行 Scout 如果共享可写状态,容易互相覆盖数据或引发并发更新错误。当前设计只允许 Scout 通过 scout_results 的 Reducer 向主图回传结果。
4. 需要暂停和恢复交互
半交互模式下,Critic 认为信息不足时可以通过 interrupt 暂停,等待用户决定继续、停止或修改补充问题。
这适合研究类任务,因为"是否继续投入成本"有时应该由用户决定,而不是完全交给模型。
宏观上的功能
输入:一个研究主题,可选研究方面、子问题和交互模式。
中间产物:研究计划、子问题状态、来源、ResearchNote、实体聚合、候选矛盾、质量评估和事件流。
输出:带来源依据和质量信息的 Markdown 研究报告,以及可查询的任务历史和长期知识。