run.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. """
  2. 集成测试 4 - 复杂文档生成任务
  3. 测试场景:复杂的技术文档生成,需要多步骤、信息收集和质量验证
  4. 目标:验证 Agent 在复杂任务中是否会使用 goal 和 subagent 工具
  5. 任务特点:
  6. - 需要先读取参考文档
  7. - 需要生成 5 个不同的文档
  8. - 需要理解技术规范并应用
  9. - 需要创建图表(Mermaid)
  10. - 需要保证文档质量和一致性
  11. """
  12. import os
  13. import sys
  14. import asyncio
  15. from pathlib import Path
  16. # 添加项目根目录到 Python 路径
  17. sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  18. from dotenv import load_dotenv
  19. load_dotenv()
  20. from agent.llm.prompts import SimplePrompt
  21. from agent.core.runner import AgentRunner
  22. from agent.execution import FileSystemTraceStore, Trace, Message
  23. from agent.llm import create_openrouter_llm_call
  24. async def main():
  25. # 路径配置
  26. base_dir = Path(__file__).parent
  27. project_root = base_dir.parent.parent
  28. prompt_path = base_dir / "task.prompt"
  29. output_dir = base_dir / "output"
  30. print("=" * 80)
  31. print("集成测试 4 - 复杂文档生成:项目管理工具技术文档")
  32. print("=" * 80)
  33. print()
  34. # 1. 加载 prompt
  35. print("1. 加载任务...")
  36. prompt = SimplePrompt(prompt_path)
  37. system_prompt = prompt._messages.get("system", "")
  38. user_prompt = prompt._messages.get("user", "")
  39. print(f" ✓ 任务类型: 复杂文档生成")
  40. print(f" ✓ 需要生成 5 个文档")
  41. print(f" ✓ 需要读取参考文档")
  42. print(f" ✓ 无工具提示,无步骤提示")
  43. print()
  44. # 2. 创建 Agent Runner
  45. print("2. 创建 Agent Runner...")
  46. print(f" - 模型: Claude Sonnet 4.5")
  47. print()
  48. runner = AgentRunner(
  49. trace_store=FileSystemTraceStore(base_path=".trace"),
  50. llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"),
  51. skills_dir=str(project_root / "agent" / "skills"),
  52. debug=False
  53. )
  54. # 3. 运行 Agent
  55. print("3. 启动 Agent...")
  56. print("=" * 80)
  57. print()
  58. current_trace_id = None
  59. goal_used = False
  60. subagent_used = False
  61. evaluate_used = False
  62. delegate_used = False
  63. iteration_count = 0
  64. tool_calls_count = {}
  65. async for item in runner.run(
  66. task=user_prompt,
  67. system_prompt=system_prompt,
  68. model="anthropic/claude-sonnet-4.5",
  69. temperature=0.5,
  70. max_iterations=50,
  71. ):
  72. # 处理 Trace 对象
  73. if isinstance(item, Trace):
  74. current_trace_id = item.trace_id
  75. if item.status == "running":
  76. print(f"[Trace] 开始: {item.trace_id[:8]}...")
  77. elif item.status == "completed":
  78. print()
  79. print("=" * 80)
  80. print(f"[Trace] 完成")
  81. print(f" - 总消息数: {item.total_messages}")
  82. print(f" - 总 Token 数: {item.total_tokens}")
  83. print(f" - 总成本: ${item.total_cost:.4f}")
  84. print("=" * 80)
  85. elif item.status == "failed":
  86. print()
  87. print(f"[Trace] 失败: {item.error}")
  88. # 处理 Message 对象
  89. elif isinstance(item, Message):
  90. if item.role == "assistant":
  91. iteration_count += 1
  92. content = item.content
  93. if isinstance(content, dict):
  94. text = content.get("text", "")
  95. tool_calls = content.get("tool_calls")
  96. # 显示 Agent 的思考
  97. if text and not tool_calls:
  98. print(f"\n[{iteration_count}] Agent 回复:")
  99. print(f" {text[:200]}{'...' if len(text) > 200 else ''}")
  100. elif text:
  101. print(f"\n[{iteration_count}] Agent 思考:")
  102. print(f" {text[:150]}{'...' if len(text) > 150 else ''}")
  103. # 显示工具调用
  104. if tool_calls:
  105. for tc in tool_calls:
  106. tool_name = tc.get("function", {}).get("name", "unknown")
  107. args = tc.get("function", {}).get("arguments", {})
  108. # 如果 args 是字符串,尝试解析为 JSON
  109. if isinstance(args, str):
  110. import json
  111. try:
  112. args = json.loads(args)
  113. except:
  114. args = {}
  115. # 统计工具使用
  116. tool_calls_count[tool_name] = tool_calls_count.get(tool_name, 0) + 1
  117. # 检测关键工具使用
  118. if tool_name == "goal":
  119. goal_used = True
  120. if isinstance(args, dict):
  121. if args.get("add"):
  122. print(f" → goal(add): {args['add'][:80]}...")
  123. elif args.get("done"):
  124. print(f" → goal(done): {args['done'][:80]}...")
  125. elif args.get("focus"):
  126. print(f" → goal(focus): {args['focus']}")
  127. else:
  128. print(f" → goal(...)")
  129. elif tool_name == "subagent":
  130. subagent_used = True
  131. if isinstance(args, dict):
  132. mode = args.get("mode", "unknown")
  133. if mode == "evaluate":
  134. evaluate_used = True
  135. target = args.get("target_goal_id", "?")
  136. print(f" → subagent(evaluate): 评估目标 {target}")
  137. elif mode == "delegate":
  138. delegate_used = True
  139. task = args.get("task", "")
  140. print(f" → subagent(delegate): {task[:60]}...")
  141. else:
  142. print(f" → subagent({mode})")
  143. else:
  144. print(f" → subagent(...)")
  145. else:
  146. # 其他工具简化显示
  147. if tool_name in ["read_file", "write_file", "edit_file"]:
  148. if isinstance(args, dict):
  149. file_path = args.get("file_path", "")
  150. if file_path:
  151. file_name = Path(file_path).name
  152. print(f" → {tool_name}: {file_name}")
  153. else:
  154. print(f" → {tool_name}")
  155. else:
  156. print(f" → {tool_name}")
  157. elif tool_name == "bash_command":
  158. if isinstance(args, dict):
  159. cmd = args.get("command", "")
  160. print(f" → bash: {cmd[:60]}...")
  161. else:
  162. print(f" → bash")
  163. else:
  164. print(f" → {tool_name}")
  165. # 4. 测试结果总结
  166. print()
  167. print("=" * 80)
  168. print("测试结果总结")
  169. print("=" * 80)
  170. print()
  171. print("功能使用情况:")
  172. print(f" {'✓' if goal_used else '✗'} Goal 工具: {'已使用' if goal_used else '未使用'}")
  173. print(f" {'✓' if subagent_used else '✗'} SubAgent 工具: {'已使用' if subagent_used else '未使用'}")
  174. if subagent_used:
  175. print(f" - Evaluate 模式: {'已使用' if evaluate_used else '未使用'}")
  176. print(f" - Delegate 模式: {'已使用' if delegate_used else '未使用'}")
  177. print()
  178. print("工具调用统计:")
  179. for tool_name, count in sorted(tool_calls_count.items()):
  180. print(f" - {tool_name}: {count} 次")
  181. print()
  182. print(f"总迭代次数: {iteration_count}")
  183. print()
  184. # 5. 验证结果
  185. print("验证生成的文档:")
  186. expected_docs = [
  187. "系统架构设计",
  188. "数据库设计",
  189. "API接口",
  190. "前端组件",
  191. "部署运维"
  192. ]
  193. if output_dir.exists():
  194. files = list(output_dir.glob("*.md"))
  195. if files:
  196. for file in files:
  197. size = file.stat().st_size
  198. print(f" ✓ {file.name} ({size} bytes)")
  199. print(f"\n 总计: {len(files)} 个文档")
  200. else:
  201. print(f" ✗ 输出目录为空")
  202. else:
  203. print(f" ✗ 输出目录不存在")
  204. print()
  205. print("=" * 80)
  206. print("集成测试 4 完成")
  207. print("=" * 80)
  208. if __name__ == "__main__":
  209. asyncio.run(main())