orchestrator.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. """三种 Multi-Agent 模式的真实执行引擎 — 全部真实 LLM 调用"""
  2. import json, time, uuid
  3. from agent import Agent
  4. # ── Agent 定义 ──
  5. SUPERVISOR = Agent(
  6. name="Supervisor", icon="👔",
  7. system_prompt=(
  8. "你是多 Agent 团队的主管。你的职责是拆解任务、分配给专家、整合结果。\n\n"
  9. "你有两个专家:\n"
  10. "- Researcher: 信息搜索专家,擅长用 web_search 搜索真实信息\n"
  11. "- Coder: 数据分析专家,擅长用 calculator 和 run_python 做计算和分析\n\n"
  12. "工作流程:\n"
  13. "1. 收到任务后,先分析需要哪些子任务\n"
  14. "2. 把子任务分配给合适的专家(通过给专家发送清晰的指令)\n"
  15. "3. 收到专家结果后,整合成高质量的最终答案\n\n"
  16. "重要:你不要自己搜索或计算,必须委托给专家。你只负责调度和整合。"
  17. ),
  18. tool_names=[],
  19. )
  20. RESEARCHER = Agent(
  21. name="Researcher", icon="🔍",
  22. system_prompt=(
  23. "你是信息搜索专家。你的唯一工具是 web_search。\n\n"
  24. "规则:\n"
  25. "1. 收到任务后,用 web_search 搜索,只搜索 1-2 次,不要重复搜索\n"
  26. "2. 第一次搜索用核心关键词,第二次只在第一次结果不够时才搜\n"
  27. "3. 返回结构化的搜索结果,包含关键数据\n"
  28. "4. 不要编造数据,搜不到就说搜不到\n"
  29. "5. 搜索完成后立即返回结果,不要继续搜索"
  30. ),
  31. tool_names=["web_search"],
  32. )
  33. CODER = Agent(
  34. name="Coder", icon="💻",
  35. system_prompt=(
  36. "你是数据分析师。你的工具是 calculator 和 run_python。\n\n"
  37. "规则:\n"
  38. "1. 收到数据后,用 calculator 做简单计算,用 run_python 做复杂分析\n"
  39. "2. 返回清晰的计算结果和分析结论\n"
  40. "3. 数据来自上一步的搜索结果,不要自己搜索\n"
  41. "4. 如果需要生成报告,用 run_python 格式化输出"
  42. ),
  43. tool_names=["calculator", "run_python"],
  44. )
  45. DEBATE_PRO = Agent(
  46. name="正方辩手", icon="🟢",
  47. system_prompt=(
  48. "你是正方辩手。针对给定辩题,你需要搜索资料并提出支持性论点。\n\n"
  49. "规则:\n"
  50. "1. 用 web_search 搜索真实案例和数据支持你的论点\n"
  51. "2. 每个论点要有事实依据,不能空谈\n"
  52. "3. 提出 2-3 个核心论点,每个论点配真实数据\n"
  53. "4. 论证要有力,语言要有说服力"
  54. ),
  55. tool_names=["web_search"],
  56. )
  57. DEBATE_CON = Agent(
  58. name="反方辩手", icon="🔴",
  59. system_prompt=(
  60. "你是反方辩手。针对给定辩题,你需要搜索资料并提出反对性论点。\n\n"
  61. "规则:\n"
  62. "1. 用 web_search 搜索真实案例和数据支持你的论点\n"
  63. "2. 每个论点要有事实依据,不能空谈\n"
  64. "3. 提出 2-3 个核心论点,每个论点配真实数据\n"
  65. "4. 要有力反驳正方观点,论证要犀利"
  66. ),
  67. tool_names=["web_search"],
  68. )
  69. DEBATE_JUDGE = Agent(
  70. name="裁判", icon="⚖️",
  71. system_prompt=(
  72. "你是中立裁判,综合正反双方的论据做出评判。\n\n"
  73. "规则:\n"
  74. "1. 用 calculator 或 run_python 做数据验证\n"
  75. "2. 逐点评判双方论据的强弱\n"
  76. "3. 给出结论,说明胜方理由\n"
  77. "4. 保持客观,不偏袒任何一方"
  78. ),
  79. tool_names=["calculator", "run_python"],
  80. )
  81. PIPELINE_SEARCHER = Agent(
  82. name="搜索 Agent", icon="🔍",
  83. system_prompt=(
  84. "你是信息搜索专家。\n\n"
  85. "规则:\n"
  86. "1. 用 web_search 搜索任务所需的信息\n"
  87. "2. 搜索多个角度,确保信息全面\n"
  88. "3. 返回结构化的搜索结果,标注来源\n"
  89. "4. 如果一次搜索不够,可以多次搜索"
  90. ),
  91. tool_names=["web_search"],
  92. )
  93. PIPELINE_ANALYZER = Agent(
  94. name="分析 Agent", icon="📊",
  95. system_prompt=(
  96. "你是数据分析专家。\n\n"
  97. "规则:\n"
  98. "1. 接收搜索 Agent 的结果\n"
  99. "2. 用 run_python 做数据处理和对比分析\n"
  100. "3. 用 calculator 做数值计算\n"
  101. "4. 输出结构化的分析结论"
  102. ),
  103. tool_names=["calculator", "run_python"],
  104. )
  105. PIPELINE_REPORTER = Agent(
  106. name="报告 Agent", icon="📝",
  107. system_prompt=(
  108. "你是报告撰写专家。\n\n"
  109. "规则:\n"
  110. "1. 接收分析 Agent 的结论\n"
  111. "2. 用 run_python 生成格式化报告\n"
  112. "3. 报告要有:标题、摘要、正文、结论、建议\n"
  113. "4. 语言专业但易读"
  114. ),
  115. tool_names=["run_python"],
  116. )
  117. # ── 执行引擎 ──
  118. def _emit(emit, event_type, data):
  119. if emit:
  120. data["type"] = event_type
  121. data["timestamp"] = time.time()
  122. emit(data)
  123. def run_supervisor(query: str, emit=None) -> dict:
  124. """Supervisor 模式:主管拆任务 → Researcher + Coder → 主管整合"""
  125. trace_id = str(uuid.uuid4())[:8]
  126. t_start = time.time()
  127. def agent_emit(event_type, data):
  128. data["trace_id"] = trace_id
  129. data["mode"] = "supervisor"
  130. _emit(emit, "agent_event", data)
  131. # Step 1: Supervisor 分析任务
  132. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "Supervisor", "icon": "👔", "action": "分析任务并拆解"})
  133. supervisor_analysis = SUPERVISOR.chat(
  134. [{"role": "user", "content": f"任务:{query}\n\n请分析这个任务,拆成子任务,说明每个子任务交给哪个专家。"}],
  135. emit=agent_emit
  136. )
  137. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "Supervisor", "result": supervisor_analysis[:500]})
  138. # Step 2: Researcher 搜索信息
  139. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "Researcher", "icon": "🔍", "action": "搜索信息"})
  140. research_result = RESEARCHER.chat(
  141. [{"role": "user", "content": f"请搜索以下任务所需的信息:\n{query}\n\n{supervisor_analysis}"}],
  142. emit=agent_emit
  143. )
  144. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "Researcher", "result": research_result[:500]})
  145. # Step 3: Coder 分析计算
  146. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "Coder", "icon": "💻", "action": "数据分析与计算"})
  147. coder_result = CODER.chat(
  148. [{"role": "user", "content": f"原始任务:{query}\n\n研究结果:\n{research_result}\n\n请基于以上数据做分析和计算。"}],
  149. emit=agent_emit
  150. )
  151. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "Coder", "result": coder_result[:500]})
  152. # Step 4: Supervisor 整合
  153. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "Supervisor", "icon": "👔", "action": "整合最终答案"})
  154. final_answer = SUPERVISOR.chat(
  155. [{"role": "user", "content": (
  156. f"原始任务:{query}\n\n"
  157. f"研究专家的结果:\n{research_result}\n\n"
  158. f"数据分析的结果:\n{coder_result}\n\n"
  159. f"请整合以上信息,给出最终的完整答案。"
  160. )}],
  161. emit=agent_emit
  162. )
  163. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "Supervisor", "result": final_answer[:800]})
  164. total_ms = int((time.time() - t_start) * 1000)
  165. _emit(emit, "trace_complete", {"trace_id": trace_id, "mode": "supervisor", "total_ms": total_ms})
  166. return {"trace_id": trace_id, "answer": final_answer, "total_ms": total_ms}
  167. def run_pipeline(query: str, emit=None) -> dict:
  168. """Pipeline 模式:搜索 → 分析 → 报告"""
  169. trace_id = str(uuid.uuid4())[:8]
  170. t_start = time.time()
  171. def agent_emit(event_type, data):
  172. data["trace_id"] = trace_id
  173. data["mode"] = "pipeline"
  174. _emit(emit, "agent_event", data)
  175. # Step 1: 搜索
  176. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "搜索 Agent", "icon": "🔍", "action": "信息采集"})
  177. search_result = PIPELINE_SEARCHER.chat(
  178. [{"role": "user", "content": f"请搜索以下任务的信息:\n{query}"}],
  179. emit=agent_emit
  180. )
  181. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "搜索 Agent", "result": search_result[:500]})
  182. # Step 2: 分析
  183. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "分析 Agent", "icon": "📊", "action": "数据分析"})
  184. analysis_result = PIPELINE_ANALYZER.chat(
  185. [{"role": "user", "content": f"原始任务:{query}\n\n搜索结果:\n{search_result}\n\n请做数据分析。"}],
  186. emit=agent_emit
  187. )
  188. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "分析 Agent", "result": analysis_result[:500]})
  189. # Step 3: 生成报告
  190. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "报告 Agent", "icon": "📝", "action": "生成报告"})
  191. report = PIPELINE_REPORTER.chat(
  192. [{"role": "user", "content": f"原始任务:{query}\n\n分析结果:\n{analysis_result}\n\n请生成最终报告。"}],
  193. emit=agent_emit
  194. )
  195. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "报告 Agent", "result": report[:800]})
  196. total_ms = int((time.time() - t_start) * 1000)
  197. _emit(emit, "trace_complete", {"trace_id": trace_id, "mode": "pipeline", "total_ms": total_ms})
  198. return {"trace_id": trace_id, "answer": report, "total_ms": total_ms}
  199. def run_debate(query: str, emit=None) -> dict:
  200. """Debate 模式:正方 → 反方 → 二次交锋 → 裁判"""
  201. trace_id = str(uuid.uuid4())[:8]
  202. t_start = time.time()
  203. def agent_emit(event_type, data):
  204. data["trace_id"] = trace_id
  205. data["mode"] = "debate"
  206. _emit(emit, "agent_event", data)
  207. # Step 1: 正方立论
  208. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "正方辩手", "icon": "🟢", "action": "立论陈词"})
  209. pro_round1 = DEBATE_PRO.chat(
  210. [{"role": "user", "content": f"辩题:{query}\n\n你是正方,请搜索资料并提出你的核心论点。"}],
  211. emit=agent_emit
  212. )
  213. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "正方辩手", "result": pro_round1[:500]})
  214. # Step 2: 反方反驳
  215. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "反方辩手", "icon": "🔴", "action": "反驳 + 立论"})
  216. con_round1 = DEBATE_CON.chat(
  217. [{"role": "user", "content": f"辩题:{query}\n\n正方论点:\n{pro_round1}\n\n你是反方,请搜索资料反驳正方并提出你的论点。"}],
  218. emit=agent_emit
  219. )
  220. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "反方辩手", "result": con_round1[:500]})
  221. # Step 3: 正方回应
  222. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "正方辩手", "icon": "🟢", "action": "回应反驳"})
  223. pro_round2 = DEBATE_PRO.chat(
  224. [{"role": "user", "content": f"辩题:{query}\n\n你的论点:\n{pro_round1}\n\n反方反驳:\n{con_round1}\n\n请回应反驳并强化你的论点。"}],
  225. emit=agent_emit
  226. )
  227. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "正方辩手", "result": pro_round2[:500]})
  228. # Step 4: 反方回应
  229. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "反方辩手", "icon": "🔴", "action": "二次反驳"})
  230. con_round2 = DEBATE_CON.chat(
  231. [{"role": "user", "content": f"辩题:{query}\n\n你的论点:\n{con_round1}\n\n正方回应:\n{pro_round2}\n\n请做最终反驳。"}],
  232. emit=agent_emit
  233. )
  234. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "反方辩手", "result": con_round2[:500]})
  235. # Step 5: 裁判评判
  236. _emit(emit, "step_start", {"trace_id": trace_id, "agent": "裁判", "icon": "⚖️", "action": "综合评判"})
  237. verdict = DEBATE_JUDGE.chat(
  238. [{"role": "user", "content": (
  239. f"辩题:{query}\n\n"
  240. f"正方第一轮:\n{pro_round1}\n\n"
  241. f"反方第一轮:\n{con_round1}\n\n"
  242. f"正方第二轮:\n{pro_round2}\n\n"
  243. f"反方第二轮:\n{con_round2}\n\n"
  244. f"请综合评判,给出最终结论。"
  245. )}],
  246. emit=agent_emit
  247. )
  248. _emit(emit, "step_end", {"trace_id": trace_id, "agent": "裁判", "result": verdict[:800]})
  249. total_ms = int((time.time() - t_start) * 1000)
  250. _emit(emit, "trace_complete", {"trace_id": trace_id, "mode": "debate", "total_ms": total_ms})
  251. return {"trace_id": trace_id, "answer": verdict, "total_ms": total_ms}