run_execute.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. """
  2. 执行 Agent — 运行入口
  3. 运行方式:
  4. cd /Users/liulidong/project/agent/Agent
  5. python examples/auto_put_ad/run_execute.py
  6. 用途:
  7. 读取运营确认后的调整方案(Excel 文件),执行出价调整和广告关停。
  8. 与 run.py 的区别:
  9. - run.py → 分析 Agent,只输出方案不执行
  10. - run_execute.py → 执行 Agent,读取确认方案并调用 API
  11. """
  12. import asyncio
  13. import os
  14. import sys
  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.core.runner import AgentRunner
  21. from agent.trace import FileSystemTraceStore, Trace, Message
  22. from agent.llm import create_openrouter_llm_call
  23. from agent.utils import setup_logging
  24. # 导入配置(使用执行 Agent 配置)
  25. from examples.auto_put_ad.config import EXECUTE_CONFIG, SKILLS_DIR, TRACE_STORE_PATH, LOG_LEVEL, LOG_FILE
  26. # 导入自定义工具(触发 @tool 注册)
  27. from examples.auto_put_ad.tools.ad_api import (
  28. account_get_info, ad_batch_update_status, ad_create, ad_get_list,
  29. ad_get_report, ad_update, asset_get_list, audience_get_list,
  30. creative_create, creative_get_report, creative_update,
  31. )
  32. from examples.auto_put_ad.tools.audience_tools import (
  33. audience_build_targeting, audience_recommend_targeting,
  34. )
  35. from examples.auto_put_ad.tools.budget_calc import (
  36. account_evaluate, bid_adjustment_execute, budget_calculate_from_data,
  37. )
  38. from examples.auto_put_ad.tools.data_query import (
  39. data_aggregate, data_query, get_ad_current_status,
  40. )
  41. from examples.auto_put_ad.tools.monitor_tools import (
  42. monitor_check_metrics, monitor_circuit_break,
  43. )
  44. # 导入执行 Agent 工具
  45. from examples.auto_put_ad.tools.execute_agent import (
  46. execute_adjustment_plan,
  47. )
  48. def _find_latest_excel() -> str:
  49. """找到 outputs/ 目录下最新的调整方案 Excel 文件"""
  50. outputs_dir = Path(__file__).parent / "outputs"
  51. if not outputs_dir.exists():
  52. return ""
  53. xlsx_files = sorted(outputs_dir.glob("adjustment_plan_*.xlsx"), reverse=True)
  54. return str(xlsx_files[0]) if xlsx_files else ""
  55. async def init_project_env(messages=None):
  56. """供 api_server 可视化调用:返回 (runner, messages, config)"""
  57. base_dir = Path(__file__).parent
  58. # 读取 execute prompt
  59. prompt_path = base_dir / "prompts" / "execute.prompt"
  60. system_prompt = ""
  61. if prompt_path.exists():
  62. system_prompt = prompt_path.read_text(encoding="utf-8")
  63. store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
  64. runner = AgentRunner(
  65. trace_store=store,
  66. llm_call=create_openrouter_llm_call(model=EXECUTE_CONFIG.model),
  67. skills_dir=SKILLS_DIR if Path(SKILLS_DIR).exists() else None,
  68. logger_name="agents.auto_put_ad.execute",
  69. )
  70. config = EXECUTE_CONFIG
  71. if system_prompt:
  72. config.system_prompt = system_prompt
  73. if not messages:
  74. latest_excel = _find_latest_excel()
  75. if latest_excel:
  76. messages = [{
  77. "role": "user",
  78. "content": f"请执行以下调整方案(dry-run 模式先验证):\n文件路径: {latest_excel}",
  79. }]
  80. else:
  81. messages = [{"role": "user", "content": "没有找到调整方案文件,请先运行分析 Agent 生成方案"}]
  82. return runner, messages, config
  83. async def main():
  84. """主函数"""
  85. base_dir = Path(__file__).parent
  86. # 初始化日志
  87. setup_logging(level=LOG_LEVEL, file=LOG_FILE)
  88. # 读取 execute prompt
  89. prompt_path = base_dir / "prompts" / "execute.prompt"
  90. system_prompt = ""
  91. if prompt_path.exists():
  92. system_prompt = prompt_path.read_text(encoding="utf-8")
  93. # 创建 Runner
  94. store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
  95. runner = AgentRunner(
  96. trace_store=store,
  97. llm_call=create_openrouter_llm_call(model=EXECUTE_CONFIG.model),
  98. skills_dir=SKILLS_DIR if Path(SKILLS_DIR).exists() else None,
  99. logger_name="agents.auto_put_ad.execute",
  100. )
  101. config = EXECUTE_CONFIG
  102. if system_prompt:
  103. config.system_prompt = system_prompt
  104. print("=" * 60)
  105. print(" 执行 Agent 已启动")
  106. print("=" * 60)
  107. # 查找最新方案文件
  108. latest_excel = _find_latest_excel()
  109. if latest_excel:
  110. print(f"最新方案文件: {latest_excel}")
  111. else:
  112. print("未找到方案文件,请先运行 run.py 生成方案")
  113. print()
  114. print("请输入执行指令(输入 'exit' 退出):")
  115. print("示例:")
  116. print(f" - 执行最新方案(dry-run)")
  117. print(f" - 执行方案 outputs/adjustment_plan_xxx.xlsx")
  118. print(f" - 确认关停")
  119. print()
  120. while True:
  121. try:
  122. user_input = input("\n> ").strip()
  123. if not user_input:
  124. continue
  125. if user_input.lower() in ("exit", "quit", "q"):
  126. print("退出系统")
  127. break
  128. # 自动注入最新 Excel 路径(如果用户没指定)
  129. if "最新" in user_input and latest_excel:
  130. user_input += f"\n\n最新方案文件路径: {latest_excel}"
  131. messages = [{"role": "user", "content": user_input}]
  132. config.trace_id = None
  133. print(f"\n执行任务: {user_input[:80]}...\n")
  134. async for item in runner.run(messages=messages, config=config):
  135. if isinstance(item, Trace):
  136. print(f"[Trace] 状态: {item.status}")
  137. elif isinstance(item, Message):
  138. if item.role == "assistant" and item.content:
  139. content = item.content
  140. if isinstance(content, dict):
  141. text = content.get("text", "")
  142. else:
  143. text = content
  144. if text and text.strip():
  145. print(f"\n{text}\n")
  146. elif item.role == "tool" and item.content:
  147. content = item.content
  148. if isinstance(content, str):
  149. text = content
  150. elif isinstance(content, dict):
  151. text = content.get("text", str(content))
  152. else:
  153. text = str(content)
  154. if len(text) > 500:
  155. text = text[:500] + "..."
  156. print(f" [Tool] {text}")
  157. print("\n" + "=" * 60)
  158. print("任务完成")
  159. print("=" * 60)
  160. except KeyboardInterrupt:
  161. print("\n用户中断,退出系统")
  162. break
  163. except Exception as e:
  164. print(f"\n执行失败: {e}")
  165. import traceback
  166. traceback.print_exc()
  167. if __name__ == "__main__":
  168. asyncio.run(main())