run.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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.llm.prompts import SimplePrompt
  14. from agent.core.runner import AgentRunner
  15. from agent.execution import MemoryTraceStore, Trace, Step
  16. from agent.llm 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 目录(可选:用户自定义 skills)
  27. # 注意:内置 skills(agent/skills/core.md)会自动加载
  28. skills_dir = None # 或者指定自定义 skills 目录,如: project_root / "skills"
  29. print("=" * 60)
  30. print("特征提取任务 (Agent 模式)")
  31. print("=" * 60)
  32. print()
  33. # 1. 加载 prompt
  34. print("1. 加载 prompt...")
  35. prompt = SimplePrompt(prompt_path)
  36. # 提取 system prompt 和 user template
  37. system_prompt = prompt._messages.get("system", "")
  38. user_template = prompt._messages.get("user", "")
  39. # 2. 读取特征描述
  40. print("2. 读取特征描述...")
  41. with open(feature_md_path, 'r', encoding='utf-8') as f:
  42. feature_text = f.read()
  43. # 3. 构建任务文本(包含图片)
  44. print("3. 构建任务(文本 + 图片)...")
  45. # 使用 prompt 构建多模态消息
  46. temp_messages = prompt.build_messages(
  47. text=feature_text,
  48. images=image_path
  49. )
  50. # 提取用户消息(包含文本和图片)
  51. user_message_with_image = None
  52. for msg in temp_messages:
  53. if msg["role"] == "user":
  54. user_message_with_image = msg
  55. break
  56. if not user_message_with_image:
  57. raise ValueError("No user message found in prompt")
  58. print(f" - 任务已构建(包含图片: {image_path.name})")
  59. # 4. 创建 Agent Runner(配置 skills)
  60. print("4. 创建 Agent Runner...")
  61. print(f" - Skills 目录: {skills_dir}")
  62. print(f" - 模型: Claude Sonnet 4.5 (via OpenRouter)")
  63. runner = AgentRunner(
  64. trace_store=MemoryTraceStore(),
  65. llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"),
  66. skills_dir=skills_dir, # 可选:加载额外的用户自定义 skills(内置 skills 会自动加载)
  67. debug=True # 启用 debug,输出到 .trace/
  68. )
  69. # 5. Agent 模式执行
  70. # 注意:使用 OpenRouter 时,模型在创建 llm_call 时已指定
  71. # 这里传入的 model 参数会被忽略(由 llm_call 内部控制)
  72. print(f"5. 启动 Agent 模式...")
  73. print()
  74. final_response = ""
  75. async for item in runner.run(
  76. task="[图片和特征描述已包含在 messages 中]", # 占位符
  77. messages=[user_message_with_image], # 传入包含图片的用户消息
  78. system_prompt=system_prompt,
  79. model="anthropic/claude-sonnet-4.5", # OpenRouter 模型名称
  80. temperature=float(prompt.config.get('temperature', 0.3)),
  81. max_iterations=10,
  82. # tools 参数不传入,测试自动加载内置工具
  83. ):
  84. # 处理 Trace 对象(整体状态变化)
  85. if isinstance(item, Trace):
  86. if item.status == "in_progress":
  87. print(f"[Trace] 开始: {item.trace_id[:8]}")
  88. elif item.status == "completed":
  89. print(f"[Trace] 完成")
  90. print(f" - Total tokens: {item.total_tokens}")
  91. print(f" - Total cost: ${item.total_cost:.4f}")
  92. elif item.status == "failed":
  93. print(f"[Trace] 失败")
  94. # 处理 Step 对象(执行过程)
  95. elif isinstance(item, Step):
  96. if item.step_type == "memory_read":
  97. exp_count = item.data.get('experiences_count', 0)
  98. if exp_count > 0:
  99. print(f"[Memory] 加载 {exp_count} 条经验")
  100. elif item.step_type == "thought":
  101. if item.status == "completed":
  102. content = item.data.get('content', '')
  103. if content:
  104. print(f"[Thought] {content[:100]}...")
  105. elif item.step_type == "action":
  106. tool_name = item.data.get('tool_name', '')
  107. print(f"[Tool] 执行 {tool_name}")
  108. elif item.step_type == "result":
  109. tool_name = item.data.get('tool_name', '')
  110. print(f"[Tool] {tool_name} 完成")
  111. elif item.step_type == "response":
  112. final_response = item.data.get('content', '')
  113. print(f"[Response] Agent 完成")
  114. # 6. 输出结果
  115. print()
  116. print("=" * 60)
  117. print("Agent 响应:")
  118. print("=" * 60)
  119. print(final_response)
  120. print("=" * 60)
  121. print()
  122. # 7. 保存结果
  123. output_file = output_dir / "result.txt"
  124. with open(output_file, 'w', encoding='utf-8') as f:
  125. f.write(final_response)
  126. print(f"✓ 结果已保存到: {output_file}")
  127. print()
  128. # 8. 提示查看 debug 文件
  129. print("Debug 文件:")
  130. print(f" - 完整可折叠: {Path.cwd() / '.trace' / 'tree.md'}")
  131. print(f" - 简洁文本: {Path.cwd() / '.trace' / 'tree.txt'}")
  132. if __name__ == "__main__":
  133. asyncio.run(main())