run.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. """
  2. 广告调控 Agent — auto_put_ad_mini 入口
  3. 运行方式:
  4. cd /Users/liulidong/project/agent/Agent
  5. python examples/auto_put_ad_mini/run.py
  6. """
  7. import asyncio
  8. import os
  9. import sys
  10. from pathlib import Path
  11. # 代理设置
  12. os.environ.setdefault("HTTP_PROXY", "http://127.0.0.1:29758")
  13. os.environ.setdefault("HTTPS_PROXY", "http://127.0.0.1:29758")
  14. # 添加项目根目录到 Python 路径
  15. sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  16. from dotenv import load_dotenv
  17. load_dotenv()
  18. from agent.core.runner import AgentRunner
  19. from agent.trace import FileSystemTraceStore, Trace, Message
  20. from agent.llm import create_openrouter_llm_call
  21. from agent.utils import setup_logging
  22. # 导入配置
  23. from examples.auto_put_ad_mini.config import (
  24. MAIN_CONFIG, SKILLS_DIR, TRACE_STORE_PATH, LOG_LEVEL, LOG_FILE,
  25. )
  26. # 导入自定义工具(触发 @tool 注册)
  27. from examples.auto_put_ad_mini.tools.data_query import fetch_creative_data, merge_creative_data
  28. from examples.auto_put_ad_mini.tools.roi_calculator import calculate_roi_metrics
  29. from examples.auto_put_ad_mini.tools.ad_decision import (
  30. analyze_ads, get_ads_for_review, apply_decisions,
  31. query_ad_detail, modify_decisions,
  32. )
  33. from examples.auto_put_ad_mini.tools.report_generator import generate_report, compare_decisions
  34. from examples.auto_put_ad_mini.tools.guardrails import validate_decisions
  35. from examples.auto_put_ad_mini.tools.execution_engine import execute_decisions, check_execution_feedback
  36. from examples.auto_put_ad_mini.tools.im_approval import send_approval_request, check_approval_status
  37. async def init_project_env(messages=None):
  38. """供 api_server 可视化调用:返回 (runner, messages, config)"""
  39. base_dir = Path(__file__).parent
  40. system_prompt = _load_system_prompt(base_dir)
  41. _load_presets(base_dir)
  42. store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
  43. runner = AgentRunner(
  44. trace_store=store,
  45. llm_call=create_openrouter_llm_call(model=MAIN_CONFIG.model),
  46. skills_dir=SKILLS_DIR if Path(SKILLS_DIR).exists() else None,
  47. logger_name="agents.auto_put_ad_mini",
  48. )
  49. config = MAIN_CONFIG
  50. if system_prompt:
  51. config.system_prompt = system_prompt
  52. if not messages:
  53. messages = [{"role": "user", "content": "分析广告"}]
  54. if system_prompt:
  55. has_system = any(m.get("role") == "system" for m in messages)
  56. if not has_system:
  57. messages = [{"role": "system", "content": system_prompt}] + messages
  58. return runner, messages, config
  59. def _load_system_prompt(base_dir: Path) -> str:
  60. prompt_path = base_dir / "prompts" / "system.prompt"
  61. if prompt_path.exists():
  62. return prompt_path.read_text(encoding="utf-8")
  63. return ""
  64. def _load_presets(base_dir: Path):
  65. presets_path = base_dir / "presets.json"
  66. if presets_path.exists():
  67. from agent.core.presets import load_presets_from_json
  68. load_presets_from_json(str(presets_path))
  69. async def main():
  70. base_dir = Path(__file__).parent
  71. setup_logging(level=LOG_LEVEL, file=LOG_FILE)
  72. system_prompt = _load_system_prompt(base_dir)
  73. _load_presets(base_dir)
  74. store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
  75. runner = AgentRunner(
  76. trace_store=store,
  77. llm_call=create_openrouter_llm_call(model=MAIN_CONFIG.model),
  78. skills_dir=SKILLS_DIR if Path(SKILLS_DIR).exists() else None,
  79. logger_name="agents.auto_put_ad_mini",
  80. )
  81. config = MAIN_CONFIG
  82. if system_prompt:
  83. config.system_prompt = system_prompt
  84. print("=" * 50)
  85. print(" 广告智能调控助手已启动")
  86. print("=" * 50)
  87. print("请输入指令(输入 'exit' 退出):")
  88. print("指令示例:")
  89. print(" - 分析广告 → 全量分析")
  90. print(" - 广告 XXXXX 降价10% → 定向操作")
  91. print(" - 广告 XXXXX 不要暂停 → 修改决策")
  92. print()
  93. step_count = 0
  94. session_trace_id = None # 会话级 trace_id,保持多轮对话记忆
  95. while True:
  96. try:
  97. user_input = input("\n> ").strip()
  98. if not user_input:
  99. continue
  100. if user_input.lower() in ("exit", "quit", "q"):
  101. print("退出系统")
  102. break
  103. messages = [{"role": "user", "content": user_input}]
  104. config.trace_id = session_trace_id
  105. print(f"\n🚀 执行: {user_input}")
  106. print("=" * 70)
  107. print(" 流程:数据拉取 → ROI计算 → 分类(A/B/C) → AI推理 → 保存决策 → 护栏验证 → 生成报告")
  108. print("=" * 70)
  109. print()
  110. step_count = 0
  111. async for item in runner.run(messages=messages, config=config):
  112. if isinstance(item, Trace):
  113. if session_trace_id is None:
  114. session_trace_id = item.trace_id
  115. if item.status == "completed":
  116. print(f"\n✅ [Trace] 完成")
  117. elif item.status == "failed":
  118. print(f"\n❌ [Trace] 失败")
  119. session_trace_id = None # 失败后重置,下次开新会话
  120. elif isinstance(item, Message):
  121. if item.role == "assistant" and item.content:
  122. content = item.content
  123. text = content.get("text", "") if isinstance(content, dict) else content
  124. if text and text.strip():
  125. print(f"\n💭 {text}\n")
  126. elif item.role == "tool" and item.content:
  127. content = item.content
  128. if isinstance(content, dict):
  129. tool_name = content.get("tool_name", "unknown")
  130. result = content.get("result", content.get("text", str(content)))
  131. # 识别关键步骤
  132. if tool_name == "fetch_creative_data":
  133. step_count += 1
  134. print(f"\n{'='*70}")
  135. print(f"📌 步骤 {step_count}: 数据拉取")
  136. print(f"{'='*70}")
  137. elif tool_name == "calculate_roi_metrics":
  138. step_count += 1
  139. print(f"\n{'='*70}")
  140. print(f"📌 步骤 {step_count}: ROI 计算")
  141. print(f"{'='*70}")
  142. elif tool_name == "get_ads_for_review":
  143. step_count += 1
  144. print(f"\n{'='*70}")
  145. print(f"📌 步骤 {step_count}: 广告分类(A/B/C)")
  146. print(f"{'='*70}")
  147. elif tool_name == "query_ad_detail":
  148. step_count += 1
  149. print(f"\n{'='*70}")
  150. print(f"📌 步骤 {step_count}: 查询广告详情")
  151. print(f"{'='*70}")
  152. elif tool_name == "apply_decisions":
  153. step_count += 1
  154. print(f"\n{'='*70}")
  155. print(f"📌 步骤 {step_count}: 保存智能引擎决策")
  156. print(f"{'='*70}")
  157. elif tool_name == "modify_decisions":
  158. step_count += 1
  159. print(f"\n{'='*70}")
  160. print(f"📌 步骤 {step_count}: 修改已有决策")
  161. print(f"{'='*70}")
  162. elif tool_name == "validate_decisions":
  163. step_count += 1
  164. print(f"\n{'='*70}")
  165. print(f"📌 步骤 {step_count}: 安全护栏验证")
  166. print(f"{'='*70}")
  167. elif tool_name == "execute_decisions":
  168. step_count += 1
  169. print(f"\n{'='*70}")
  170. print(f"📌 步骤 {step_count}: 分级执行")
  171. print(f"{'='*70}")
  172. elif tool_name == "send_approval_request":
  173. step_count += 1
  174. print(f"\n{'='*70}")
  175. print(f"📌 步骤 {step_count}: IM 审批请求")
  176. print(f"{'='*70}")
  177. elif tool_name == "generate_report":
  178. step_count += 1
  179. print(f"\n{'='*70}")
  180. print(f"📌 步骤 {step_count}: 生成最终报告")
  181. print(f"{'='*70}")
  182. elif tool_name == "check_execution_feedback":
  183. step_count += 1
  184. print(f"\n{'='*70}")
  185. print(f"📌 步骤 {step_count}: 执行效果检查")
  186. print(f"{'='*70}")
  187. # 打印简化结果
  188. if isinstance(result, str):
  189. text = result
  190. else:
  191. text = str(result)
  192. if len(text) > 500:
  193. text = text[:500] + "..."
  194. print(f" {text}")
  195. else:
  196. text = str(content)
  197. if len(text) > 300:
  198. text = text[:300] + "..."
  199. print(f" [工具] {text}")
  200. print("\n" + "=" * 50)
  201. print("✅ 完成")
  202. print("=" * 50)
  203. except KeyboardInterrupt:
  204. print("\n用户中断,退出")
  205. break
  206. except Exception as e:
  207. print(f"\n❌ 失败: {e}")
  208. import traceback
  209. traceback.print_exc()
  210. if __name__ == "__main__":
  211. asyncio.run(main())