Просмотр исходного кода

feat(budget): Step 4 完成 - 启用多 Agent 架构

- config.py: 新增 MAIN_CONFIG + BUDGET_CONFIG, 工具白名单更新
- presets.json: budget 角色配置更新(工具列表+skills)
- prompts/main.prompt: 新增 Main Agent prompt(任务拆解+调度)
- run.py: 改为 Main Agent 入口, 加载 presets.json, 导入新工具
刘立冬 1 месяц назад
Родитель
Сommit
24f1e5c201

+ 34 - 9
examples/auto_put_ad/config.py

@@ -7,9 +7,6 @@ from agent.core.runner import RunConfig, KnowledgeConfig
 # ===== 工具白名单 =====
 # 只暴露业务工具,避免 LLM 误调 IM/知识库/浏览器等非业务工具
 ANALYSIS_TOOLS = [
-    # 预算出价
-    "account_evaluate",
-    "budget_calculate_from_data",
     # 数据查询
     "data_query",
     "data_aggregate",
@@ -30,7 +27,6 @@ ANALYSIS_TOOLS = [
 
 EXECUTION_TOOLS = ANALYSIS_TOOLS + [
     # 执行类工具(仅执行 Agent 使用)
-    "execute_adjustment_plan",
     "bid_adjustment_execute",
     "ad_create",
     "ad_update",
@@ -40,14 +36,40 @@ EXECUTION_TOOLS = ANALYSIS_TOOLS + [
     "monitor_circuit_break",
 ]
 
-# ===== 分析 Agent 配置(默认,只输出方案不执行) =====
-RUN_CONFIG = RunConfig(
+# ===== Main Agent 配置(统一入口) =====
+MAIN_CONFIG = RunConfig(
     model="qwen/qwen3.5-plus-02-15",
     temperature=0.3,
     max_iterations=50,
-    name="自动化投放系统",
-    tools=ANALYSIS_TOOLS,
-    skills=["planning", "ad_domain", "budget_strategy"],
+    name="投放决策中枢",
+    tools=ANALYSIS_TOOLS + ["agent"],  # 加入 agent 工具用于调度子 Agent
+    skills=["planning", "ad_domain"],   # Main Agent 只需要通用知识
+    extra_llm_params={"extra_body": {"enable_thinking": True}},
+    knowledge=KnowledgeConfig(
+        enable_extraction=False,
+        enable_completion_extraction=False,
+        enable_injection=False,
+        owner="ad_placement_team",
+    ),
+)
+
+# ===== Budget Agent 配置 =====
+BUDGET_CONFIG = RunConfig(
+    model="qwen/qwen3.5-plus-02-15",
+    temperature=0.3,
+    max_iterations=30,
+    name="预算出价Agent",
+    tools=[
+        # 配置层
+        "load_strategy_config", "update_strategy_config", "get_config_history",
+        # 数据获取
+        "get_ad_performance", "get_account_summary", "data_query",
+        # 计算
+        "compute_budget_thresholds", "classify_ads", "compute_bid_adjustment",
+        # 只读 API
+        "ad_get_list", "ad_get_report",
+    ],
+    skills=["ad_domain", "budget_strategy"],  # 只注入预算相关知识
     extra_llm_params={"extra_body": {"enable_thinking": True}},
     knowledge=KnowledgeConfig(
         enable_extraction=False,
@@ -74,6 +96,9 @@ EXECUTE_CONFIG = RunConfig(
     ),
 )
 
+# 向后兼容:默认使用 Main Agent
+RUN_CONFIG = MAIN_CONFIG
+
 # 基础设施配置
 SKILLS_DIR = str(Path(__file__).parent / "skills")
 TRACE_STORE_PATH = ".trace"

+ 9 - 3
examples/auto_put_ad/presets.json

@@ -20,9 +20,15 @@
   },
   "budget": {
     "system_prompt_file": "prompts/budget.prompt",
-    "max_iterations": 100,
-    "temperature": 0.2,
-    "skills": ["planning", "budget_strategy"],
+    "max_iterations": 30,
+    "temperature": 0.3,
+    "tools": [
+      "load_strategy_config", "update_strategy_config", "get_config_history",
+      "get_ad_performance", "get_account_summary", "data_query",
+      "compute_budget_thresholds", "classify_ads", "compute_bid_adjustment",
+      "ad_get_list", "ad_get_report"
+    ],
+    "skills": ["ad_domain", "budget_strategy"],
     "description": "预算出价 Agent - 预算分配与 ROI 优化"
   },
   "execute": {

+ 55 - 0
examples/auto_put_ad/prompts/main.prompt

@@ -0,0 +1,55 @@
+你是投放决策中枢,负责任务拆解与全局调度。
+
+## 当前可用 Agent
+
+✅ **budget** — 预算出价分析(完整可用)
+   - 职责:预算分配、出价调整、ROI优化
+   - 输入:预算金额、账户ID
+   - 输出:出价调整方案
+
+🟡 **audience** — 人群定向分析(基础可用,执行受限)
+   - 职责:受众分析、定向策略
+   - 状态:基础功能可用,执行需人工确认
+
+🟡 **data_analyst** — 数据查询与分析(只读)
+   - 职责:数据查询、效果分析
+   - 状态:只读工具,不执行写操作
+
+❌ **creative** — 素材分析(未就绪,禁止调度)
+❌ **monitor** — 监控(未就绪,禁止调度)
+❌ **system_ops** — API操作执行(未就绪,禁止调度)
+
+## 工作流程
+
+### 1. 理解用户意图,拆解为子任务
+
+用户输入示例:
+- "今天小程序预算10w" → 调度 budget Agent
+- "分析账户昨日投放效果" → 调度 data_analyst Agent
+- "优化人群定向" → 调度 audience Agent
+
+### 2. 调度对应 Agent 执行分析
+
+使用 `agent` 工具调度子 Agent:
+```
+agent(preset="budget", message="今天小程序预算10w")
+```
+
+### 3. 汇总各 Agent 输出,形成完整方案
+
+- 整合各 Agent 的分析结果
+- 识别冲突和依赖关系
+- 形成统一的执行方案
+
+### 4. 等待用户确认后,调度执行
+
+- 展示完整方案给用户
+- 等待用户确认
+- 确认后调度 System Ops Agent 执行(当前未就绪,需人工执行)
+
+## 约束
+
+- 只调度标记为 ✅ 或 🟡 的 Agent
+- 禁止调度标记为 ❌ 的 Agent
+- 每个子任务明确指定 Agent 和输入
+- 汇总时保留各 Agent 的原始输出

+ 22 - 15
examples/auto_put_ad/run.py

@@ -27,7 +27,7 @@ from agent.llm import create_openrouter_llm_call
 from agent.utils import setup_logging
 
 # 导入配置(使用绝对路径导入)
-from examples.auto_put_ad.config import RUN_CONFIG, SKILLS_DIR, TRACE_STORE_PATH, LOG_LEVEL, LOG_FILE
+from examples.auto_put_ad.config import MAIN_CONFIG, SKILLS_DIR, TRACE_STORE_PATH, LOG_LEVEL, LOG_FILE
 
 # 导入自定义工具(触发 @tool 注册)
 from examples.auto_put_ad.tools.ad_api import (
@@ -39,7 +39,12 @@ from examples.auto_put_ad.tools.audience_tools import (
     audience_build_targeting, audience_recommend_targeting,
 )
 from examples.auto_put_ad.tools.budget_calc import (
-    account_evaluate, bid_adjustment_execute, budget_calculate_from_data,
+    get_ad_performance, get_account_summary,
+    compute_budget_thresholds, classify_ads, compute_bid_adjustment,
+    bid_adjustment_execute,
+)
+from examples.auto_put_ad.tools.strategy_config import (
+    load_strategy_config, update_strategy_config, get_config_history,
 )
 from examples.auto_put_ad.tools.data_query import (
     data_aggregate, data_query, get_ad_current_status,
@@ -53,21 +58,22 @@ async def init_project_env(messages=None):
     """供 api_server 可视化调用:返回 (runner, messages, config)"""
     base_dir = Path(__file__).parent
 
-    # 读取 system prompt
-    task_prompt_path = base_dir / "task.prompt"
+    # 读取 main.prompt
+    main_prompt_path = base_dir / "prompts" / "main.prompt"
     system_prompt = ""
-    if task_prompt_path.exists():
-        system_prompt = task_prompt_path.read_text(encoding="utf-8")
+    if main_prompt_path.exists():
+        system_prompt = main_prompt_path.read_text(encoding="utf-8")
 
     store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
     runner = AgentRunner(
         trace_store=store,
-        llm_call=create_openrouter_llm_call(model=RUN_CONFIG.model),
+        llm_call=create_openrouter_llm_call(model=MAIN_CONFIG.model),
         skills_dir=SKILLS_DIR if Path(SKILLS_DIR).exists() else None,
+        presets_path=base_dir / "presets.json",  # 启用多 Agent 预设
         logger_name="agents.auto_put_ad",
     )
 
-    config = RUN_CONFIG
+    config = MAIN_CONFIG
     if system_prompt:
         config.system_prompt = system_prompt
 
@@ -85,23 +91,24 @@ async def main():
     # 初始化日志
     setup_logging(level=LOG_LEVEL, file=LOG_FILE)
 
-    # 读取 system prompt
-    task_prompt_path = base_dir / "task.prompt"
+    # 读取 main.prompt
+    main_prompt_path = base_dir / "prompts" / "main.prompt"
     system_prompt = ""
-    if task_prompt_path.exists():
-        system_prompt = task_prompt_path.read_text(encoding="utf-8")
+    if main_prompt_path.exists():
+        system_prompt = main_prompt_path.read_text(encoding="utf-8")
 
-    # 创建 Runner
+    # 创建 Runner(启用多 Agent)
     store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
     runner = AgentRunner(
         trace_store=store,
-        llm_call=create_openrouter_llm_call(model=RUN_CONFIG.model),
+        llm_call=create_openrouter_llm_call(model=MAIN_CONFIG.model),
         skills_dir=SKILLS_DIR if Path(SKILLS_DIR).exists() else None,
+        presets_path=base_dir / "presets.json",  # 启用多 Agent 预设
         logger_name="agents.auto_put_ad",
     )
 
     # 如果有 system_prompt,注入到 config
-    config = RUN_CONFIG
+    config = MAIN_CONFIG
     if system_prompt:
         config.system_prompt = system_prompt