run.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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, RunConfig
  15. from agent.trace import (
  16. FileSystemTraceStore,
  17. Trace,
  18. Message,
  19. )
  20. from agent.llm import create_openrouter_llm_call
  21. async def main():
  22. # 路径配置
  23. base_dir = Path(__file__).parent
  24. project_root = base_dir.parent.parent
  25. prompt_path = base_dir / "test.prompt"
  26. feature_md_path = base_dir / "input_1" / "feature.md"
  27. image_path = base_dir / "input_1" / "image.png"
  28. output_dir = base_dir / "output_1"
  29. output_dir.mkdir(exist_ok=True)
  30. # Skills 目录(可选:用户自定义 skills)
  31. # 注意:内置 skills(agent/skills/core.md)会自动加载
  32. skills_dir = None # 或者指定自定义 skills 目录,如: project_root / "skills"
  33. print("=" * 60)
  34. print("特征提取任务 (Agent 模式)")
  35. print("=" * 60)
  36. print()
  37. # 1. 加载 prompt
  38. print("1. 加载 prompt...")
  39. prompt = SimplePrompt(prompt_path)
  40. # 提取 system prompt 和 user template
  41. system_prompt = prompt._messages.get("system", "")
  42. user_template = prompt._messages.get("user", "")
  43. # 2. 读取特征描述
  44. print("2. 读取特征描述...")
  45. with open(feature_md_path, 'r', encoding='utf-8') as f:
  46. feature_text = f.read()
  47. # 3. 构建任务文本(包含图片)
  48. print("3. 构建任务(文本 + 图片)...")
  49. # 使用 prompt 构建多模态消息
  50. temp_messages = prompt.build_messages(
  51. text=feature_text,
  52. images=image_path
  53. )
  54. # 提取用户消息(包含文本和图片)
  55. user_message_with_image = None
  56. for msg in temp_messages:
  57. if msg["role"] == "user":
  58. user_message_with_image = msg
  59. break
  60. if not user_message_with_image:
  61. raise ValueError("No user message found in prompt")
  62. print(f" - 任务已构建(包含图片: {image_path.name})")
  63. # 4. 创建 Agent Runner(配置 skills)
  64. print("4. 创建 Agent Runner...")
  65. print(f" - Skills 目录: {skills_dir}")
  66. print(f" - 模型: Claude Sonnet 4.5 (via OpenRouter)")
  67. runner = AgentRunner(
  68. trace_store=FileSystemTraceStore(base_path=".trace"),
  69. llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"),
  70. skills_dir=skills_dir, # 可选:加载额外的用户自定义 skills(内置 skills 会自动加载)
  71. debug=True # 启用 debug,输出到 .trace/
  72. )
  73. # 5. Agent 模式执行
  74. # 注意:使用 OpenRouter 时,模型在创建 llm_call 时已指定
  75. # 这里传入的 model 参数会被忽略(由 llm_call 内部控制)
  76. print(f"5. 启动 Agent 模式...")
  77. print()
  78. final_response = ""
  79. current_trace_id = None # 保存 trace_id 用于后续测试
  80. async for item in runner.run(
  81. messages=[user_message_with_image],
  82. config=RunConfig(
  83. system_prompt=system_prompt,
  84. model="anthropic/claude-sonnet-4.5",
  85. temperature=float(prompt.config.get('temperature', 0.3)),
  86. max_iterations=1000,
  87. name="特征提取任务",
  88. ),
  89. ):
  90. # 处理 Trace 对象(整体状态变化)
  91. if isinstance(item, Trace):
  92. current_trace_id = item.trace_id # 保存 trace_id
  93. if item.status == "running":
  94. print(f"[Trace] 开始: {item.trace_id[:8]}")
  95. elif item.status == "completed":
  96. print(f"[Trace] 完成")
  97. print(f" - Total messages: {item.total_messages}")
  98. print(f" - Total tokens: {item.total_tokens}")
  99. print(f" - Total cost: ${item.total_cost:.4f}")
  100. elif item.status == "failed":
  101. print(f"[Trace] 失败")
  102. # 处理 Message 对象(执行过程)
  103. elif isinstance(item, Message):
  104. if item.role == "assistant":
  105. content = item.content
  106. if isinstance(content, dict):
  107. text = content.get("text", "")
  108. tool_calls = content.get("tool_calls")
  109. if text and not tool_calls:
  110. # 纯文本回复(最终响应)
  111. final_response = text
  112. print(f"[Response] Agent 完成")
  113. elif text:
  114. print(f"[Assistant] {text[:100]}...")
  115. if tool_calls:
  116. for tc in tool_calls:
  117. tool_name = tc.get("function", {}).get("name", "unknown")
  118. print(f"[Tool Call] {tool_name}")
  119. elif item.role == "tool":
  120. content = item.content
  121. if isinstance(content, dict):
  122. tool_name = content.get("tool_name", "unknown")
  123. print(f"[Tool Result] {tool_name}")
  124. print(f" {item.description[:80]}...")
  125. # 6. 输出结果
  126. print()
  127. print("=" * 60)
  128. print("Agent 响应:")
  129. print("=" * 60)
  130. print(final_response)
  131. print("=" * 60)
  132. print()
  133. # 7. 保存结果
  134. output_file = output_dir / "result.txt"
  135. with open(output_file, 'w', encoding='utf-8') as f:
  136. f.write(final_response)
  137. print(f"✓ 结果已保存到: {output_file}")
  138. print()
  139. # 提示使用 API 可视化
  140. print("=" * 60)
  141. print("可视化 Step Tree:")
  142. print("=" * 60)
  143. print("1. 启动 API Server:")
  144. print(" python3 api_server.py")
  145. print()
  146. print("2. 浏览器访问:")
  147. print(" http://localhost:8000/api/traces")
  148. print()
  149. print(f"3. Trace ID: {current_trace_id}")
  150. print("=" * 60)
  151. if __name__ == "__main__":
  152. asyncio.run(main())