Skip to content

Commit 6e93745

Browse files
lusaltiaclaude
andcommitted
perf: parallelize report generation phases to reduce total time
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c6782d0 commit 6e93745

1 file changed

Lines changed: 85 additions & 54 deletions

File tree

review_radar/agent.py

Lines changed: 85 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -317,72 +317,103 @@ def _on_progress(fetched, total, platform, country):
317317
c_data = self._apply_semantic_dedup_pain_points(c_data, pp_merge_map)
318318
aggregated["by_country"][c_code]["combined"] = c_data
319319

320-
# ── Phase 4: 生成报告(多国家动态章节)──
320+
# ── Phase 4: 生成报告(多国家动态章节,并发优化)──
321321
self.on_event("phase", {"phase": "Phase 4: 生成报告", "phase_number": 4, "total_phases": 5})
322322

323-
# Step 0: 执行摘要
324-
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "生成执行摘要"})
325-
exec_summary_result = tool_generate_report(
326-
app_name=display_name, analysis_data=aggregated,
327-
report_step="executive_summary", countries=countries, platforms=platforms,
328-
)
329-
self.on_event("tool_result", {"tool": "generate_report", "message": exec_summary_result.get("message", "")})
330-
331-
# Step 1: 大纲
332-
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "生成大纲"})
333-
outline_result = tool_generate_report(
334-
app_name=display_name, analysis_data=aggregated,
335-
report_step="outline", countries=countries, platforms=platforms,
336-
)
337-
outline = outline_result.get("outline", "")
338-
self.on_event("tool_result", {"tool": "generate_report", "message": outline_result.get("message", "")})
339-
340-
chapters = []
323+
from concurrent.futures import ThreadPoolExecutor, as_completed
341324

342-
# 执行摘要作为第一个章节
343-
chapters.append(exec_summary_result.get("chapter_content", ""))
325+
# Wave 1: 执行摘要、大纲、总览 并发生成
326+
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "并发生成执行摘要+大纲+总览"})
344327

345-
# Step 2: 总览
346-
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "生成总览"})
347-
overview = tool_generate_report(
348-
app_name=display_name, analysis_data=aggregated,
349-
report_step="overview", countries=countries, platforms=platforms,
350-
)
351-
chapters.append(overview.get("chapter_content", ""))
352-
self.on_event("tool_result", {"tool": "generate_report", "message": overview.get("message", "")})
328+
def _gen_exec_summary():
329+
return tool_generate_report(
330+
app_name=display_name, analysis_data=aggregated,
331+
report_step="executive_summary", countries=countries, platforms=platforms,
332+
)
353333

354-
# Step 3: 各国家章节
355-
for c_code in countries:
356-
c_name = COUNTRIES.get(c_code, c_code)
357-
self.on_event("tool_call", {"tool": "generate_report", "input_summary": f"生成 {c_name} 分析"})
358-
ch = tool_generate_report(
334+
def _gen_outline():
335+
return tool_generate_report(
359336
app_name=display_name, analysis_data=aggregated,
360-
report_step="country", countries=countries, platforms=platforms,
361-
country_code=c_code, outline=outline, sample_reviews=all_reviews,
337+
report_step="outline", countries=countries, platforms=platforms,
362338
)
363-
chapters.append(ch.get("chapter_content", ""))
364-
self.on_event("tool_result", {"tool": "generate_report", "message": ch.get("message", "")})
365339

366-
# Step 4: 跨国对比(多国家时)
367-
if len(countries) > 1:
368-
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "生成跨国对比"})
369-
cross = tool_generate_report(
340+
def _gen_overview():
341+
return tool_generate_report(
370342
app_name=display_name, analysis_data=aggregated,
371-
report_step="cross_country", countries=countries, platforms=platforms,
343+
report_step="overview", countries=countries, platforms=platforms,
372344
)
373-
chapters.append(cross.get("chapter_content", ""))
374-
self.on_event("tool_result", {"tool": "generate_report", "message": cross.get("message", "")})
375345

376-
# Step 5: 行动建议
377-
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "生成行动建议"})
378-
action = tool_generate_report(
379-
app_name=display_name, analysis_data=aggregated,
380-
report_step="action", countries=countries, platforms=platforms,
381-
)
382-
chapters.append(action.get("chapter_content", ""))
383-
self.on_event("tool_result", {"tool": "generate_report", "message": action.get("message", "")})
346+
with ThreadPoolExecutor(max_workers=3) as executor:
347+
f_exec = executor.submit(_gen_exec_summary)
348+
f_outline = executor.submit(_gen_outline)
349+
f_overview = executor.submit(_gen_overview)
350+
351+
exec_summary_result = f_exec.result()
352+
outline_result = f_outline.result()
353+
overview_result = f_overview.result()
354+
outline = outline_result.get("outline", "")
355+
356+
self.on_event("tool_result", {"tool": "generate_report", "message": "执行摘要+大纲+总览 生成完成"})
357+
358+
# Wave 2: 各国家章节 + 跨国对比 + 行动建议 并发生成
359+
wave2_tasks = {}
360+
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "并发生成国家章节+跨国对比+行动建议"})
361+
362+
with ThreadPoolExecutor(max_workers=max(len(countries) + 2, 4)) as executor:
363+
# 各国家章节(依赖 outline,但彼此独立)
364+
for c_code in countries:
365+
def _gen_country(cc=c_code):
366+
return tool_generate_report(
367+
app_name=display_name, analysis_data=aggregated,
368+
report_step="country", countries=countries, platforms=platforms,
369+
country_code=cc, outline=outline, sample_reviews=all_reviews,
370+
)
371+
wave2_tasks[executor.submit(_gen_country)] = ("country", c_code)
372+
373+
# 跨国对比(多国家时)
374+
if len(countries) > 1:
375+
def _gen_cross():
376+
return tool_generate_report(
377+
app_name=display_name, analysis_data=aggregated,
378+
report_step="cross_country", countries=countries, platforms=platforms,
379+
)
380+
wave2_tasks[executor.submit(_gen_cross)] = ("cross_country", None)
381+
382+
# 行动建议
383+
def _gen_action():
384+
return tool_generate_report(
385+
app_name=display_name, analysis_data=aggregated,
386+
report_step="action", countries=countries, platforms=platforms,
387+
)
388+
wave2_tasks[executor.submit(_gen_action)] = ("action", None)
389+
390+
# 收集 Wave 2 结果,按类型归位
391+
country_chapters = {} # c_code -> content
392+
cross_chapter = ""
393+
action_chapter = ""
394+
for future in wave2_tasks:
395+
task_type, task_key = wave2_tasks[future]
396+
result = future.result()
397+
if task_type == "country":
398+
country_chapters[task_key] = result.get("chapter_content", "")
399+
elif task_type == "cross_country":
400+
cross_chapter = result.get("chapter_content", "")
401+
elif task_type == "action":
402+
action_chapter = result.get("chapter_content", "")
403+
404+
self.on_event("tool_result", {"tool": "generate_report", "message": "国家章节+跨国对比+行动建议 生成完成"})
405+
406+
# 按正确顺序组装章节
407+
chapters = []
408+
chapters.append(exec_summary_result.get("chapter_content", ""))
409+
chapters.append(overview_result.get("chapter_content", ""))
410+
for c_code in countries:
411+
chapters.append(country_chapters.get(c_code, ""))
412+
if cross_chapter:
413+
chapters.append(cross_chapter)
414+
chapters.append(action_chapter)
384415

385-
# Step 6: 格式化
416+
# Wave 3: 格式化(依赖所有章节)
386417
self.on_event("tool_call", {"tool": "generate_report", "input_summary": "格式化报告"})
387418
final = tool_generate_report(
388419
app_name=display_name, analysis_data=aggregated,

0 commit comments

Comments
 (0)