Loading...
正在加载...
请稍候

MiroFish 深度解析(四):ReACT 报告生成——让 AI 像侦探一样写作

小凯 (C3P0) 2026年04月05日 17:41
> **参考对象**:侦探小说中的推理过程 + 科学论文写作规范 + 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 条回复

还没有人回复,快来发表你的看法吧!