run.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """
  2. 特征提取示例
  3. 使用 Agent 模式 + Skills + 多模态支持
  4. """
  5. import os
  6. import sys
  7. import asyncio
  8. from pathlib import Path
  9. # 添加项目根目录到 Python 路径
  10. sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  11. from dotenv import load_dotenv
  12. load_dotenv()
  13. from agent.prompts import SimplePrompt
  14. from agent.runner import AgentRunner
  15. from agent.storage import MemoryTraceStore
  16. from agent.llm.providers.openrouter import create_openrouter_llm_call
  17. async def main():
  18. # 路径配置
  19. base_dir = Path(__file__).parent
  20. project_root = base_dir.parent.parent
  21. prompt_path = base_dir / "test.prompt"
  22. feature_md_path = base_dir / "input_1" / "feature.md"
  23. image_path = base_dir / "input_1" / "image.png"
  24. output_dir = base_dir / "output_1"
  25. output_dir.mkdir(exist_ok=True)
  26. # Skills 目录
  27. skills_dir = project_root / "agent" / "skills"
  28. print("=" * 60)
  29. print("特征提取任务 (Agent 模式)")
  30. print("=" * 60)
  31. print()
  32. # 1. 加载 prompt
  33. print("1. 加载 prompt...")
  34. prompt = SimplePrompt(prompt_path)
  35. # 提取 system prompt 和 user template
  36. system_prompt = prompt._messages.get("system", "")
  37. user_template = prompt._messages.get("user", "")
  38. # 2. 读取特征描述
  39. print("2. 读取特征描述...")
  40. with open(feature_md_path, 'r', encoding='utf-8') as f:
  41. feature_text = f.read()
  42. # 3. 构建任务文本(包含图片)
  43. print("3. 构建任务(文本 + 图片)...")
  44. # 使用 prompt 构建多模态消息
  45. temp_messages = prompt.build_messages(
  46. text=feature_text,
  47. images=image_path
  48. )
  49. # 提取用户消息(包含文本和图片)
  50. user_message_with_image = None
  51. for msg in temp_messages:
  52. if msg["role"] == "user":
  53. user_message_with_image = msg
  54. break
  55. if not user_message_with_image:
  56. raise ValueError("No user message found in prompt")
  57. print(f" - 任务已构建(包含图片: {image_path.name})")
  58. # 4. 创建 Agent Runner(配置 skills)
  59. print("4. 创建 Agent Runner...")
  60. print(f" - Skills 目录: {skills_dir}")
  61. print(f" - 模型: Claude Sonnet 4.5 (via OpenRouter)")
  62. runner = AgentRunner(
  63. trace_store=MemoryTraceStore(),
  64. llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"),
  65. skills_dir=str(skills_dir), # 恢复加载 skills,测试 Claude 是否能处理
  66. debug=True # 启用 debug,输出到 .trace/
  67. )
  68. # 5. Agent 模式执行
  69. # 注意:使用 OpenRouter 时,模型在创建 llm_call 时已指定
  70. # 这里传入的 model 参数会被忽略(由 llm_call 内部控制)
  71. print(f"5. 启动 Agent 模式...")
  72. print()
  73. final_response = ""
  74. async for event in runner.run(
  75. task="[图片和特征描述已包含在 messages 中]", # 占位符
  76. messages=[user_message_with_image], # 传入包含图片的用户消息
  77. system_prompt=system_prompt,
  78. model="anthropic/claude-sonnet-4.5", # OpenRouter 模型名称
  79. temperature=float(prompt.config.get('temperature', 0.3)),
  80. max_iterations=10,
  81. # tools 参数不传入,测试自动加载内置工具
  82. ):
  83. event_type = event.type
  84. event_data = event.data
  85. if event_type == "trace_started":
  86. print(f"[Trace] 开始: {event_data.get('trace_id', '')[:8]}")
  87. elif event_type == "memory_loaded":
  88. exp_count = event_data.get('experiences_count', 0)
  89. if exp_count > 0:
  90. print(f"[Memory] 加载 {exp_count} 条经验")
  91. elif event_type == "step_started":
  92. step_type = event_data.get('step_type', '')
  93. print(f"[Step] {step_type}...")
  94. elif event_type == "thought":
  95. content = event_data.get('content', '')
  96. if content:
  97. print(f"[Thought] {content[:100]}...")
  98. elif event_type == "tool_execution":
  99. tool_name = event_data.get('tool_name', '')
  100. print(f"[Tool] 执行 {tool_name}")
  101. elif event_type == "conclusion":
  102. final_response = event_data.get('content', '') # 修正:字段名是 content 不是 response
  103. print(f"[Conclusion] Agent 完成")
  104. elif event_type == "trace_completed":
  105. print(f"[Trace] 完成")
  106. print(f" - Total tokens: {event_data.get('total_tokens', 0)}")
  107. print(f" - Total cost: ${event_data.get('total_cost', 0.0):.4f}")
  108. # 6. 输出结果
  109. print()
  110. print("=" * 60)
  111. print("Agent 响应:")
  112. print("=" * 60)
  113. print(final_response)
  114. print("=" * 60)
  115. print()
  116. # 7. 保存结果
  117. output_file = output_dir / "result.txt"
  118. with open(output_file, 'w', encoding='utf-8') as f:
  119. f.write(final_response)
  120. print(f"✓ 结果已保存到: {output_file}")
  121. print()
  122. # 8. 提示查看 debug 文件
  123. print("Debug 文件:")
  124. print(f" - 完整可折叠: {Path.cwd() / '.trace' / 'tree.md'}")
  125. print(f" - 简洁文本: {Path.cwd() / '.trace' / 'tree.txt'}")
  126. if __name__ == "__main__":
  127. asyncio.run(main())