> **参考对象**:侦探小说中的推理过程 + 科学论文写作规范 + ReACT(Reasoning + Acting)框架
---
## 引子:为什么 AI 写的报告缺乏"说服力"?
传统 AI 生成报告的流程:
1. 给定主题
2. LLM 基于训练数据生成内容
3. 输出报告
**问题**:
- 内容可能包含"幻觉"(训练数据中的错误信息)
- 无法引用具体的事实来源
- 缺乏深度分析,只是表面总结
- 无法回答"你是怎么得出这个结论的"
**MiroFish 的解决方案**:让 AI 像侦探一样写作——先思考,再行动,再观察,再思考,循环往复。
---
## 第一部分:什么是 ReACT?
ReACT(**Re**asoning + **Act**ing)是一种让 LLM 交替进行推理和行动的框架。
### ReACT 的核心循环
```
┌─────────────────────────────────────────┐
│ ReACT 循环 │
├─────────────────────────────────────────┤
│ │
│ Thought(思考) │
│ ↓ 我需要了解 X,才能写 Y │
│ │
│ Action(行动) │
│ ↓ 调用工具获取 X 的信息 │
│ │
│ Observation(观察) │
│ ↓ 工具返回:X 的值为 ... │
│ │
│ [重复 Thought → Action → Observation] │
│ │
│ Final Answer(最终答案) │
│ ↓ 基于所有观察生成最终内容 │
│ │
└─────────────────────────────────────────┘
```
### 传统方式 vs ReACT
**传统方式**:
```
用户:写一篇关于甲醛事件的报告
LLM:[直接生成内容]
结果:可能包含不准确的信息,无法验证来源
```
**ReACT 方式**:
```
用户:写一篇关于甲醛事件的报告
LLM Thought:我需要先了解事件的基本事实
LLM Action:调用 insight_forge 工具搜索"甲醛事件"
Observation:返回 15 条相关事实,包括事件时间线、关键实体...
LLM Thought:我需要了解各方立场
LLM Action:调用 panorama_search 工具搜索各方反应
Observation:返回学生、校方、媒体、政府的立场分布...
LLM Thought:我需要采访仿真中的 Agent 获取第一手观点
LLM Action:调用 interview_agents 工具
Observation:返回 5 个 Agent 的采访记录...
[多次循环后...]
LLM Final Answer:[基于所有观察生成报告]
结果:每个结论都有事实支撑,可追溯来源
```
---
## 第二部分:MiroFish 的 ReACT 实现
### Report Agent 架构
```python
class ReportAgent:
"""
报告生成 Agent
采用 ReACT 模式:
1. 规划报告大纲
2. 逐章节生成
3. 每章节多次调用工具获取数据
4. 反思检查
5. 生成最终报告
"""
def __init__(
self,
llm_client: LLMClient,
zep_tools: ZepToolsService,
max_iterations: int = 15,
max_tool_calls_per_section: int = 5
):
self.llm = llm_client
self.tools = zep_tools
self.max_iterations = max_iterations
self.max_tool_calls = max_tool_calls_per_section
```
### 工作流程
```
┌─────────────────────────────────────────────────────────────┐
│ Report Agent 工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 规划阶段 │
│ └── LLM 分析模拟需求,生成报告大纲 │
│ └── 2-5 个章节,每个章节有明确目标 │
│ ↓ │
│ 2. 逐章节生成 │
│ └── 对每个章节: │
│ └── ReACT 循环(最多 5 次工具调用) │
│ └── Thought → Action → Observation │
│ ↓ │
│ 3. 反思阶段 │
│ └── 检查内容完整性和准确性 │
│ └── 如有缺失,补充调用工具 │
│ ↓ │
│ 4. 整合阶段 │
│ └── 合并所有章节 │
│ └── 添加执行摘要 │
│ ↓ │
│ 5. 输出报告 │
│ └── 结构化 JSON 格式 │
│ └── 包含所有引用的来源 │
│ │
└─────────────────────────────────────────────────────────────┘
```
### 规划阶段:生成报告大纲
```python
def _plan_report(
self,
simulation_requirement: str,
graph_id: str
) -> ReportPlan:
"""
规划报告大纲
输出示例:
{
"title": "甲醛超标事件舆情预测报告",
"sections": [
{
"id": "background",
"title": "事件背景",
"objective": "描述事件发生的时间、地点、主要参与者",
"required_info": ["事件时间线", "关键实体", "触发原因"]
},
{
"id": "stakeholders",
"title": "各方立场分析",
"objective": "分析学生、校方、媒体、政府的立场和诉求",
"required_info": ["各方声明", "立场分布", "利益诉求"]
},
{
"id": "prediction",
"title": "舆情演化预测",
"objective": "预测未来 72 小时的舆情走向",
"required_info": ["仿真数据", "传播路径", "情感趋势"]
}
]
}
"""
```
### 章节生成:ReACT 循环
```python
async def _generate_section(
self,
section: SectionPlan,
context: GenerationContext
) -> SectionContent:
"""
生成单个章节(ReACT 模式)
"""
iterations = 0
tool_calls = 0
observations = []
while iterations < self.max_iterations and tool_calls < self.max_tool_calls:
# 1. Thought:思考下一步需要什么信息
thought = self._generate_thought(
section=section,
context=context,
observations=observations
)
# 2. Action:选择并调用工具
action = self._select_action(thought)
if action.type == "finish":
# 生成最终内容
break
# 3. Observation:获取工具结果
observation = await self._execute_action(action)
observations.append(observation)
tool_calls += 1
iterations += 1
# 生成最终内容
content = self._generate_final_content(
section=section,
observations=observations
)
return SectionContent(
title=section.title,
content=content,
sources=self._extract_sources(observations)
)
```
---
## 第三部分:可用工具详解
Report Agent 可以调用四种工具:
### 1. QuickSearch(快速搜索)
**适用场景**:需要快速查找某个具体信息
```python
{
"name": "quick_search",
"description": "快速检索某个具体事实,适合简单查询",
"parameters": {
"query": "搜索关键词",
"limit": "返回结果数量(默认10)"
}
}
```
**使用示例**:
```
Thought:我需要知道甲醛事件发生的具体时间
Action:调用 quick_search,query="甲醛事件发生时间"
Observation:返回 "2024年3月15日,学生张三在微博上发布检测报告"
```
### 2. PanoramaSearch(广度搜索)
**适用场景**:需要了解事件的完整发展脉络
```python
{
"name": "panorama_search",
"description": "广角全景搜索,获取事件全貌和时间线",
"parameters": {
"query": "搜索关键词",
"include_expired": "是否包含过期事实(默认True)"
}
}
```
**使用示例**:
```
Thought:我需要了解甲醛事件的完整发展过程
Action:调用 panorama_search,query="甲醛事件发展"
Observation:返回时间线:
- 3月1日:学生发现异常
- 3月5日:自行检测
- 3月15日:微博曝光
- 3月16日:校方回应
- 3月18日:媒体报道
```
### 3. InsightForge(深度洞察检索)
**适用场景**:需要深入分析某个话题,获取丰富素材
```python
{
"name": "insight_forge",
"description": "最强大的深度检索,自动分解问题并多维度分析",
"parameters": {
"query": "分析问题",
"simulation_requirement": "模拟需求描述"
}
}
```
**工作原理**:
```
输入:"分析甲醛事件中各方的立场"
LLM 自动分解为子问题:
1. "学生的立场是什么?诉求有哪些?"
2. "校方的立场是什么?采取了哪些措施?"
3. "媒体的报道角度是什么?"
4. "政府的态度如何?"
并行检索:
- 语义搜索:找到相关事实
- 实体分析:识别关键实体
- 关系链追踪:发现影响路径
整合输出:
- 各方立场总结
- 关键事实列表
- 关系网络图
```
### 4. InterviewAgents(深度采访)
**适用场景**:需要获取仿真中 Agent 的第一手观点
```python
{
"name": "interview_agents",
"description": "采访仿真中的Agent,获取真实回答(非LLM模拟)",
"parameters": {
"interview_requirement": "采访需求描述",
"max_agents": "采访Agent数量(默认5)"
}
}
```
**使用示例**:
```
Thought:我想了解学生对校方的真实看法
Action:调用 interview_agents
interview_requirement="采访学生Agent,了解他们对校方回应的态度"
Observation:返回5个Agent的采访记录:
- Agent-1(学生):"校方在推诿责任,我们需要第三方检测"
- Agent-2(学生):"至少校方回应了,比沉默好"
- ...
```
---
## 第四部分:ReACT 循环实例
### 场景:生成"各方立场分析"章节
```
═══════════════════════════════════════════════════════════════
ReACT 循环开始
═══════════════════════════════════════════════════════════════
【迭代 1】
Thought:
我需要了解甲醛事件中涉及哪些主要实体(学生、校方、媒体、政府)。
应该先获取事件的整体信息。
Action:
调用 insight_forge
query="甲醛事件的主要参与方"
Observation:
找到以下实体:
- 学生群体(张三等)
- 中国科学技术大学校方
- 北京日报等媒体
- 教育局等政府部门
关系网络:学生→曝光→校方→回应→媒体→报道→政府→关注
【迭代 2】
Thought:
我了解了主要参与方。现在我需要深入了解每一方的具体立场和诉求。
让我搜索校方的具体回应。
Action:
调用 quick_search
query="校方回应 甲醛"
Observation:
校方声明要点:
1. 已成立专项调查组
2. 承诺整改
3. 否认早期知情
【迭代 3】
Thought:
我需要了解学生的具体诉求,以及仿真中Agent的真实想法。
让我采访一些学生Agent。
Action:
调用 interview_agents
interview_requirement="采访学生Agent,了解他们对事件的看法和对校方的态度"
Observation:
Agent-5(学生):"我们要求第三方检测,不相信校方的自查"
Agent-12(学生):"更关注健康赔偿问题"
Agent-23(学生):"希望事情不要被压下去"
【迭代 4】
Thought:
我现在有了校方声明和学生诉求。还需要了解媒体角度和政府立场。
让我用广度搜索获取更全面的信息。
Action:
调用 panorama_search
query="媒体报道 政府回应"
Observation:
媒体报道角度:
- 北京日报:关注学生健康,质疑校方监管
- 自媒体:批评校方反应迟缓
政府态度:
- 教育局:已介入调查
- 卫健委:关注公共卫生问题
【迭代 5】
Thought:
我已经收集了足够的信息来撰写这一章节:
- 主要参与方(学生、校方、媒体、政府)
- 各方具体立场和诉求
- 仿真Agent的真实观点
- 媒体和政府的角色
可以生成最终内容了。
Action:
调用 finish_section
Final Content:
【各方立场分析】
甲醛事件涉及四方主要力量:学生群体、校方、媒体和政府。
各方的立场和诉求存在明显差异...
[详细内容...]
【引用来源】
1. insight_forge 检索结果
2. 校方声明原文
3. Agent-5, Agent-12, Agent-23 采访记录
4. panorama_search 媒体报道汇总
═══════════════════════════════════════════════════════════════
ReACT 循环结束
═══════════════════════════════════════════════════════════════
```
---
## 第五部分:反思与质量检查
### 反思机制
生成每个章节后,Report Agent 会进行反思检查:
```python
def _reflect_on_section(
self,
section: SectionContent,
plan: SectionPlan
) -> ReflectionResult:
"""
反思检查
检查项:
1. 内容完整性:是否覆盖了计划中的所有要点?
2. 事实准确性:是否有明确的事实来源?
3. 逻辑连贯性:论证是否清晰?
4. 深度充分性:分析是否深入?
"""
```
### 质量评分
```python
class SectionQualityScore:
completeness: float # 完整性(0-1)
accuracy: float # 准确性(0-1)
coherence: float # 连贯性(0-1)
depth: float # 深度(0-1)
@property
def overall(self) -> float:
return (self.completeness + self.accuracy +
self.coherence + self.depth) / 4
```
### 自动修正
如果质量评分低于阈值,Report Agent 会自动补充调用工具:
```python
if quality.completeness < 0.8:
# 内容不完整,需要补充信息
missing_points = self._identify_missing_points(section, plan)
for point in missing_points:
# 针对缺失点调用工具
observation = await self._search_for_point(point)
if quality.depth < 0.7:
# 深度不够,需要更深入的分析
observation = await self.tools.insight_forge(
query=f"深入分析 {section.title}"
)
```
---
## 第六部分:输出格式
### 报告结构
```json
{
"title": "甲醛超标事件舆情预测报告",
"summary": "执行摘要(200字以内)",
"sections": [
{
"id": "background",
"title": "事件背景",
"content": "章节正文...",
"sources": [
{"tool": "insight_forge", "query": "..."},
{"tool": "quick_search", "query": "..."}
]
},
{
"id": "stakeholders",
"title": "各方立场分析",
"content": "章节正文...",
"sources": [
{"tool": "interview_agents", "agents": [5, 12, 23]},
{"tool": "panorama_search", "query": "..."}
]
}
],
"metadata": {
"graph_id": "...",
"simulation_id": "...",
"generation_time": "2024-03-20T10:30:00Z",
"total_tool_calls": 23,
"quality_score": 0.92
}
}
```
### 可追溯性
每个结论都有明确的来源:
| 结论 | 来源 |
|------|------|
| "学生主要诉求是第三方检测" | Interview: Agent-5 |
| "校方否认早期知情" | QuickSearch: 校方声明 |
| "事件在3月15日曝光" | PanoramaSearch: 时间线 |
| "媒体普遍持批评态度" | InsightForge: 媒体分析 |
---
## 尾声:ReACT 的启示
MiroFish 的 ReACT 报告生成机制给我们的启示:
### 1. LLM 不是知识库,是推理引擎
不要期望 LLM 记住所有事实,而是让它学会**如何查找事实**。
### 2. 写作是迭代过程,不是一次性生成
好的写作需要:
- 规划大纲
- 收集素材
- 撰写草稿
- 反思修改
- 定稿
ReACT 模拟了这个过程。
### 3. 可追溯性比"听起来对"更重要
读者可以问:"你是怎么得出这个结论的?"
ReACT 报告可以回答:"基于这些工具调用和观察结果。"
---
**从"生成内容"到"生成可信内容",
这是 AI 写作的一次重要进化。**
---
*本文是 MiroFish 深度解析系列的第四篇,下一篇将是技术架构总结。*
#MiroFish #ReACT #AI写作 #报告生成 #LLM
登录后可参与表态
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!