run.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. """
  2. 集成测试 2 - 完全开放的任务
  3. 测试场景:只给任务目标,不给任何步骤提示
  4. 目标:验证 Agent 能否自主分析、规划和实现完整功能
  5. 测试内容:
  6. - Agent 是否会主动使用 goal 工具规划任务
  7. - Agent 是否能自主决定实现步骤
  8. - Agent 是否会使用 subagent 工具评估结果
  9. - Agent 能否完成一个完整的功能实现
  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. project_dir = base_dir / "project"
  30. print("=" * 80)
  31. print("集成测试 2 - 完全开放任务:实现待办事项管理工具")
  32. print("=" * 80)
  33. print()
  34. # 1. 加载 prompt
  35. print("1. 加载任务 prompt...")
  36. prompt = SimplePrompt(prompt_path)
  37. system_prompt = prompt._messages.get("system", "")
  38. user_prompt = prompt._messages.get("user", "")
  39. print(f" ✓ 任务已加载(无步骤提示)")
  40. print()
  41. # 2. 创建 Agent Runner
  42. print("2. 创建 Agent Runner...")
  43. print(f" - 模型: Claude Sonnet 4.5 (via OpenRouter)")
  44. print()
  45. runner = AgentRunner(
  46. trace_store=FileSystemTraceStore(base_path=".trace"),
  47. llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"),
  48. skills_dir=str(project_root / "agent" / "skills"),
  49. debug=False
  50. )
  51. # 3. 运行 Agent
  52. print("3. 启动 Agent 执行任务...")
  53. print("=" * 80)
  54. print()
  55. current_trace_id = None
  56. goal_used = False
  57. subagent_used = False
  58. evaluate_used = False
  59. delegate_used = False
  60. iteration_count = 0
  61. tool_calls_count = {}
  62. async for item in runner.run(
  63. task=user_prompt,
  64. system_prompt=system_prompt,
  65. model="anthropic/claude-sonnet-4.5",
  66. temperature=0.3,
  67. max_iterations=50, # 增加迭代次数,因为任务更复杂
  68. ):
  69. # 处理 Trace 对象
  70. if isinstance(item, Trace):
  71. current_trace_id = item.trace_id
  72. if item.status == "running":
  73. print(f"[Trace] 开始: {item.trace_id[:8]}...")
  74. elif item.status == "completed":
  75. print()
  76. print("=" * 80)
  77. print(f"[Trace] 完成")
  78. print(f" - 总消息数: {item.total_messages}")
  79. print(f" - 总 Token 数: {item.total_tokens}")
  80. print(f" - 总成本: ${item.total_cost:.4f}")
  81. print("=" * 80)
  82. elif item.status == "failed":
  83. print()
  84. print(f"[Trace] 失败: {item.error}")
  85. # 处理 Message 对象
  86. elif isinstance(item, Message):
  87. if item.role == "assistant":
  88. iteration_count += 1
  89. content = item.content
  90. if isinstance(content, dict):
  91. text = content.get("text", "")
  92. tool_calls = content.get("tool_calls")
  93. # 显示 Agent 的思考
  94. if text and not tool_calls:
  95. print(f"\n[{iteration_count}] Agent 回复:")
  96. print(f" {text[:200]}{'...' if len(text) > 200 else ''}")
  97. elif text:
  98. print(f"\n[{iteration_count}] Agent 思考:")
  99. print(f" {text[:150]}{'...' if len(text) > 150 else ''}")
  100. # 显示工具调用
  101. if tool_calls:
  102. for tc in tool_calls:
  103. tool_name = tc.get("function", {}).get("name", "unknown")
  104. args = tc.get("function", {}).get("arguments", {})
  105. # 如果 args 是字符串,尝试解析为 JSON
  106. if isinstance(args, str):
  107. import json
  108. try:
  109. args = json.loads(args)
  110. except:
  111. args = {}
  112. # 统计工具使用
  113. tool_calls_count[tool_name] = tool_calls_count.get(tool_name, 0) + 1
  114. # 检测关键工具使用
  115. if tool_name == "goal":
  116. goal_used = True
  117. # 显示 goal 操作
  118. if isinstance(args, dict):
  119. if args.get("add"):
  120. print(f" → goal(add): {args['add'][:80]}...")
  121. elif args.get("done"):
  122. print(f" → goal(done): {args['done'][:80]}...")
  123. elif args.get("focus"):
  124. print(f" → goal(focus): {args['focus']}")
  125. else:
  126. print(f" → goal(...)")
  127. elif tool_name == "subagent":
  128. subagent_used = True
  129. if isinstance(args, dict):
  130. mode = args.get("mode", "unknown")
  131. if mode == "evaluate":
  132. evaluate_used = True
  133. target = args.get("target_goal_id", "?")
  134. print(f" → subagent(evaluate): 评估目标 {target}")
  135. elif mode == "delegate":
  136. delegate_used = True
  137. task = args.get("task", "")
  138. print(f" → subagent(delegate): {task[:60]}...")
  139. else:
  140. print(f" → subagent({mode})")
  141. else:
  142. print(f" → subagent(...)")
  143. else:
  144. # 其他工具简化显示
  145. if tool_name in ["read_file", "write_file", "edit_file"]:
  146. if isinstance(args, dict):
  147. file_path = args.get("file_path", "")
  148. if file_path:
  149. file_name = Path(file_path).name
  150. print(f" → {tool_name}: {file_name}")
  151. else:
  152. print(f" → {tool_name}")
  153. else:
  154. print(f" → {tool_name}")
  155. elif tool_name == "bash_command":
  156. if isinstance(args, dict):
  157. cmd = args.get("command", "")
  158. print(f" → bash: {cmd[:60]}...")
  159. else:
  160. print(f" → bash")
  161. else:
  162. print(f" → {tool_name}")
  163. elif item.role == "tool":
  164. # 工具返回结果(简化显示)
  165. pass
  166. # 4. 测试结果总结
  167. print()
  168. print("=" * 80)
  169. print("测试结果总结")
  170. print("=" * 80)
  171. print()
  172. print("功能使用情况:")
  173. print(f" {'✓' if goal_used else '✗'} Goal 工具: {'已使用' if goal_used else '未使用'}")
  174. print(f" {'✓' if subagent_used else '✗'} SubAgent 工具: {'已使用' if subagent_used else '未使用'}")
  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. # 检查是否生成了主要文件
  187. expected_files = ["todo.py", "test_todo.py"]
  188. for file_name in expected_files:
  189. file_path = project_dir / file_name
  190. if file_path.exists():
  191. print(f" ✓ {file_name} 已生成")
  192. else:
  193. print(f" ✗ {file_name} 未生成")
  194. print()
  195. print("=" * 80)
  196. print("集成测试 2 完成")
  197. print("=" * 80)
  198. if __name__ == "__main__":
  199. asyncio.run(main())