orchestrator.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. """使用多 Agent 模式的主系统编排逻辑"""
  2. from datetime import datetime
  3. from typing import Dict, Any, List
  4. from models import ContentNode, ContentLevel, ColumnPlan
  5. from agents import (
  6. PlannerAgent,
  7. WriterAgent,
  8. ReflectionWriterAgent
  9. )
  10. from config import get_settings, get_word_count
  11. class ColumnWriterOrchestrator:
  12. """
  13. 提供多 Agent 模式的专栏写作系统
  14. 架构设计:
  15. 1. PlannerAgent → PlanAndSolveAgent(任务分解和规划)
  16. 2. WriterAgent → ReActAgent(推理和工具调用)
  17. 3. 评审+修改 → ReflectionAgent(自我反思优化)
  18. """
  19. def __init__(self, use_reflection_mode: bool = False):
  20. """
  21. 初始化编排器
  22. Args:
  23. use_reflection_mode: 是否使用 ReflectionAgent 模式
  24. - True: 使用 ReflectionAgent(自动评审和优化)
  25. - False: 使用 ReActAgent + 独立评审流程
  26. """
  27. self.settings = get_settings()
  28. self.use_reflection_mode = use_reflection_mode
  29. # 创建各个 Agent
  30. print("\n 初始化专栏写作系统...")
  31. print(f" 模式选择: {'ReflectionAgent(自我反思)' if use_reflection_mode else 'ReActAgent(推理行动)+ 评审'}")
  32. # 规划 Agent - 使用 PlanAndSolveAgent
  33. self.planner = PlannerAgent()
  34. # 写作 Agent - 根据模式选择
  35. if use_reflection_mode:
  36. self.writer = ReflectionWriterAgent()
  37. print(" WriterAgent: ReflectionAgent(内置评审优化)")
  38. else:
  39. self.writer = WriterAgent(enable_search=self.settings.enable_search)
  40. print(" WriterAgent: ReActAgent(推理-行动-搜索)")
  41. # 统计信息
  42. self.stats = {
  43. 'total_generations': 0,
  44. 'total_reviews': 0,
  45. 'total_revisions': 0,
  46. 'total_rewrites': 0,
  47. 'start_time': None,
  48. 'end_time': None
  49. }
  50. print("▸ 系统初始化完成\n")
  51. def create_column(self, main_topic: str) -> Dict[str, Any]:
  52. """
  53. 创建完整专栏
  54. Args:
  55. main_topic: 专栏主题
  56. Returns:
  57. 包含专栏完整信息的字典
  58. """
  59. self.stats['start_time'] = datetime.now()
  60. print(f"\n{'='*70}")
  61. print(f"▸ 开始创建专栏:{main_topic}")
  62. print(f"{'='*70}\n")
  63. # Step 1: 规划专栏结构(使用 PlanAndSolveAgent)
  64. print("▸ 第一步:规划专栏结构(PlanAndSolveAgent)")
  65. print("-" * 70)
  66. column_plan = self.planner.plan_column(main_topic)
  67. print(f" 标题:{column_plan.column_title}")
  68. print(f" 话题数:{column_plan.get_topic_count()} 个")
  69. print(f" 目标读者:{column_plan.target_audience}\n")
  70. # Step 2: 为每个子话题创建内容树
  71. mode_name = "ReflectionAgent" if self.use_reflection_mode else "ReActAgent"
  72. print(f"▸️ 第二步:撰写专栏文章({mode_name})")
  73. print("-" * 70)
  74. content_trees = self._write_topics_sequential(column_plan)
  75. # Step 3: 组装完整专栏
  76. print("\n▸ 第三步:组装专栏内容")
  77. print("-" * 70)
  78. full_column = self._assemble_column(column_plan, content_trees)
  79. self.stats['end_time'] = datetime.now()
  80. duration = (self.stats['end_time'] - self.stats['start_time']).total_seconds()
  81. print(f"\n{'='*70}")
  82. print(f"▸ 专栏创建完成!耗时 {duration:.1f} 秒")
  83. print(f"{'='*70}\n")
  84. # 添加统计信息
  85. full_column['creation_stats'] = self.stats
  86. full_column['agent_modes'] = {
  87. 'planner': 'PlanAndSolveAgent',
  88. 'writer': 'ReflectionAgent' if self.use_reflection_mode else 'ReActAgent'
  89. }
  90. return full_column
  91. def _write_topics_sequential(self, column_plan: ColumnPlan) -> List[ContentNode]:
  92. """顺序写作各个话题"""
  93. content_trees = []
  94. for idx, topic in enumerate(column_plan.topics, 1):
  95. print(f"\n{'─'*70}")
  96. print(f"▸ 正在写作第 {idx}/{column_plan.get_topic_count()} 个话题")
  97. print(f" 话题:{topic['title']}")
  98. print(f"{'─'*70}")
  99. tree = self._write_topic_tree(topic, column_plan)
  100. content_trees.append(tree)
  101. # 显示进度
  102. progress = idx / column_plan.get_topic_count() * 100
  103. print(f"\n▸ 总体进度:{progress:.0f}% ({idx}/{column_plan.get_topic_count()})")
  104. return content_trees
  105. def _write_topic_tree(
  106. self,
  107. topic: Dict[str, Any],
  108. column_context: ColumnPlan
  109. ) -> ContentNode:
  110. """递归写作话题树"""
  111. root = ContentNode(
  112. id=topic['id'],
  113. title=topic['title'],
  114. level=ContentLevel.TOPIC,
  115. description=topic['description']
  116. )
  117. context = {
  118. 'column_title': column_context.column_title,
  119. 'column_description': column_context.column_description,
  120. 'target_audience': column_context.target_audience,
  121. 'current_topic': topic
  122. }
  123. self._recursive_write(root, context, level=1)
  124. return root
  125. def _recursive_write(
  126. self,
  127. node: ContentNode,
  128. context: Dict[str, Any],
  129. level: int
  130. ):
  131. """递归写作核心逻辑"""
  132. if level > self.settings.max_depth:
  133. indent = " " * level
  134. print(f"{indent}▸️ 达到最大深度 {self.settings.max_depth},停止展开")
  135. return
  136. indent = " " * level
  137. print(f"\n{indent}{'┈'*40}")
  138. print(f"{indent}▸ Level {level}: {node.title}")
  139. print(f"{indent}{'┈'*40}")
  140. if self.use_reflection_mode:
  141. # 模式1: 使用 ReflectionAgent(内置评审优化)
  142. self._write_with_reflection(node, context, level, indent)
  143. else:
  144. # 模式2: 使用 ReActAgent(推理-行动)
  145. self._write_with_react(node, context, level, indent)
  146. def _write_with_reflection(
  147. self,
  148. node: ContentNode,
  149. context: Dict[str, Any],
  150. level: int,
  151. indent: str
  152. ):
  153. """使用 ReflectionAgent 模式写作"""
  154. print(f"{indent}▸️ 使用 ReflectionAgent 生成并优化内容...")
  155. content_data = self.writer.generate_and_refine_content(node, context, level)
  156. self.stats['total_generations'] += 1
  157. # ReflectionAgent 已经完成了自我评审和优化
  158. node.content = content_data['content']
  159. node.metadata = content_data.get('metadata', {})
  160. node.metadata['agent_mode'] = 'ReflectionAgent'
  161. node.metadata['auto_refined'] = True
  162. word_count = content_data.get('word_count', len(content_data['content']))
  163. print(f"{indent} 字数:{word_count}")
  164. print(f"{indent}▸ 内容已通过自我反思优化")
  165. # 处理子节点
  166. self._process_children(node, content_data, context, level, indent)
  167. def _write_with_react(
  168. self,
  169. node: ContentNode,
  170. context: Dict[str, Any],
  171. level: int,
  172. indent: str
  173. ):
  174. """使用 ReActAgent 模式写作"""
  175. print(f"{indent}▸️ 使用 ReActAgent 生成内容(推理-行动)...")
  176. content_data = self.writer.generate_content(node, context, level)
  177. self.stats['total_generations'] += 1
  178. node.content = content_data['content']
  179. node.metadata = content_data.get('metadata', {})
  180. node.metadata['agent_mode'] = 'ReActAgent'
  181. word_count = content_data.get('word_count', len(content_data['content']))
  182. print(f"{indent} 字数:{word_count}")
  183. print(f"{indent}▸ ReActAgent 完成推理和行动")
  184. # 处理子节点
  185. self._process_children(node, content_data, context, level, indent)
  186. def _process_children(
  187. self,
  188. node: ContentNode,
  189. content_data: Dict[str, Any],
  190. context: Dict[str, Any],
  191. level: int,
  192. indent: str
  193. ):
  194. """处理子节点"""
  195. if content_data.get('needs_expansion') and level < self.settings.max_depth:
  196. subsections = content_data.get('subsections', [])
  197. if subsections:
  198. print(f"{indent}▸ 需要展开 {len(subsections)} 个子节点")
  199. for subsection in subsections:
  200. child = ContentNode(
  201. id=subsection['id'],
  202. title=subsection['title'],
  203. level=ContentLevel(level + 1),
  204. description=subsection['description']
  205. )
  206. node.add_child(child)
  207. # 递归写作子节点
  208. self._recursive_write(child, context, level + 1)
  209. def _assemble_column(
  210. self,
  211. plan: ColumnPlan,
  212. trees: List[ContentNode]
  213. ) -> Dict[str, Any]:
  214. """组装完整专栏"""
  215. articles = []
  216. for tree in trees:
  217. article_content = self._tree_to_markdown(tree)
  218. articles.append({
  219. 'id': tree.id,
  220. 'title': tree.title,
  221. 'content': article_content,
  222. 'metadata': tree.metadata,
  223. 'word_count': tree.count_words()
  224. })
  225. return {
  226. 'column_info': {
  227. 'title': plan.column_title,
  228. 'description': plan.column_description,
  229. 'target_audience': plan.target_audience,
  230. 'topic_count': plan.get_topic_count()
  231. },
  232. 'articles': articles,
  233. 'statistics': self._calculate_statistics(trees)
  234. }
  235. def _tree_to_markdown(self, node: ContentNode, depth: int = 0) -> str:
  236. """将内容树转换为markdown"""
  237. markdown = []
  238. heading_level = "#" * (depth + 1)
  239. markdown.append(f"{heading_level} {node.title}\n")
  240. if node.content:
  241. markdown.append(node.content)
  242. markdown.append("\n")
  243. for child in node.children:
  244. child_md = self._tree_to_markdown(child, depth + 1)
  245. markdown.append(child_md)
  246. return "\n".join(markdown)
  247. def _calculate_statistics(self, trees: List[ContentNode]) -> Dict[str, Any]:
  248. """计算统计信息"""
  249. total_words = 0
  250. total_nodes = 0
  251. def count_tree(node: ContentNode):
  252. nonlocal total_words, total_nodes
  253. total_nodes += 1
  254. total_words += len(node.content) if node.content else 0
  255. for child in node.children:
  256. count_tree(child)
  257. for tree in trees:
  258. count_tree(tree)
  259. return {
  260. 'total_articles': len(trees),
  261. 'total_nodes': total_nodes,
  262. 'total_words': total_words,
  263. 'avg_words_per_article': total_words // len(trees) if trees else 0
  264. }