Procházet zdrojové kódy

feat: preset subagent system prompt

Talegorithm před 4 hodinami
rodič
revize
ddc9cc54d6

+ 31 - 0
README.md

@@ -317,6 +317,37 @@ agent/
 
 详细架构文档:[docs/README.md](./docs/README.md)
 
+## Agent 预设(Presets)
+
+预设定义不同类型 Agent 的配置模板(工具权限、system prompt、skills 等)。
+
+**项目级预设**:在项目目录创建 `presets.json`,支持从 `.prompt` 文件加载自定义 system prompt:
+
+```json
+{
+  "tool_research": {
+    "system_prompt_file": "tool_research.prompt",
+    "max_iterations": 50,
+    "skills": ["planning", "research", "browser"],
+    "description": "工具调研 Agent"
+  }
+}
+```
+
+**加载预设**:
+```python
+from agent.core.presets import load_presets_from_json
+
+load_presets_from_json("path/to/presets.json")
+```
+
+**使用预设**:LLM 调用 `agent` 工具时指定 `agent_type`:
+```python
+agent(task="调研视频生成工具", agent_type="tool_research")
+```
+
+详见 `examples/production/` 示例和 `agent/docs/architecture.md`。
+
 ## 交互式 CLI(Interactive CLI)
 
 框架提供交互式控制器,支持实时监控、手动干预和经验总结。

+ 10 - 1
agent/core/__init__.py

@@ -8,7 +8,14 @@ Agent Core - 核心引擎模块
 """
 
 from agent.core.runner import AgentRunner, BUILTIN_TOOLS, CallResult, RunConfig
-from agent.core.presets import AgentPreset, AGENT_PRESETS, get_preset, register_preset
+from agent.core.presets import (
+    AgentPreset,
+    AGENT_PRESETS,
+    get_preset,
+    register_preset,
+    load_system_prompt_from_file,
+    load_presets_from_json,
+)
 
 __all__ = [
     "AgentRunner",
@@ -19,4 +26,6 @@ __all__ = [
     "AGENT_PRESETS",
     "get_preset",
     "register_preset",
+    "load_system_prompt_from_file",
+    "load_presets_from_json",
 ]

+ 65 - 0
agent/core/presets.py

@@ -7,6 +7,7 @@ Agent Presets - Agent 类型预设配置
 
 from dataclasses import dataclass, field
 from typing import Optional, List
+from pathlib import Path
 
 
 @dataclass
@@ -21,6 +22,9 @@ class AgentPreset:
     max_iterations: int = 30
     temperature: Optional[float] = None
 
+    # System Prompt(完全自定义 system prompt;None = 使用默认模板 + skills)
+    system_prompt: Optional[str] = None
+
     # Skills(注入 system prompt 的 skill 名称列表;None = 加载全部)
     skills: Optional[List[str]] = None
 
@@ -70,3 +74,64 @@ def get_preset(name: str) -> AgentPreset:
 def register_preset(name: str, preset: AgentPreset) -> None:
     """注册自定义预设"""
     AGENT_PRESETS[name] = preset
+
+
+def load_system_prompt_from_file(path: str) -> str:
+    """
+    从 .prompt 文件加载 system prompt
+
+    Args:
+        path: .prompt 文件路径(相对或绝对)
+
+    Returns:
+        system prompt 文本
+
+    Raises:
+        FileNotFoundError: 文件不存在
+        ValueError: 文件格式错误或缺少 $system$ 分节
+    """
+    from agent.llm.prompts import load_prompt
+
+    prompt_path = Path(path)
+    if not prompt_path.is_absolute():
+        # 相对路径:相对于当前工作目录
+        prompt_path = Path.cwd() / prompt_path
+
+    config, messages = load_prompt(prompt_path)
+
+    if "system" not in messages:
+        raise ValueError(f".prompt 文件缺少 $system$ 分节: {path}")
+
+    return messages["system"]
+
+
+def load_presets_from_json(json_path: str) -> None:
+    """
+    从 JSON 文件加载预设配置
+
+    支持特殊字段:
+    - system_prompt_file: 从 .prompt 文件加载 system prompt(相对于 JSON 文件所在目录)
+
+    Args:
+        json_path: presets.json 文件路径
+    """
+    import json
+
+    json_path = Path(json_path)
+    if not json_path.exists():
+        raise FileNotFoundError(f"presets.json 不存在: {json_path}")
+
+    with open(json_path, "r", encoding="utf-8") as f:
+        presets_data = json.load(f)
+
+    base_dir = json_path.parent
+
+    for name, cfg in presets_data.items():
+        # 处理 system_prompt_file
+        if "system_prompt_file" in cfg:
+            prompt_file = cfg.pop("system_prompt_file")
+            prompt_path = base_dir / prompt_file
+            cfg["system_prompt"] = load_system_prompt_from_file(str(prompt_path))
+
+        preset = AgentPreset(**cfg)
+        register_preset(name, preset)

+ 17 - 3
agent/core/runner.py

@@ -2129,17 +2129,31 @@ class AgentRunner:
         """构建 system prompt(注入 skills)
 
         优先级:
+        1. base_prompt(来自消息)
+        2. config.system_prompt(显式指定)
+        3. preset.system_prompt(预设的完整 system prompt)
+        4. 默认模板 + skills
+
+        Skills 注入优先级:
         1. config.skills 显式指定 → 按名称过滤
         2. config.skills 为 None → 查 preset 的默认 skills 列表
         3. preset 也无 skills(None)→ 加载全部(向后兼容)
 
         Args:
-            base_prompt: 已有 system 内容(来自消息或 config.system_prompt),
-                         None 时使用 config.system_prompt
+            base_prompt: 已有 system 内容(来自消息),
+                         None 时使用 config.system_prompt 或 preset.system_prompt
         """
         from agent.core.presets import AGENT_PRESETS
 
-        system_prompt = base_prompt if base_prompt is not None else config.system_prompt
+        # 确定 system_prompt 来源
+        if base_prompt is not None:
+            system_prompt = base_prompt
+        elif config.system_prompt is not None:
+            system_prompt = config.system_prompt
+        else:
+            # 尝试从 preset 获取 system_prompt
+            preset = AGENT_PRESETS.get(config.agent_type)
+            system_prompt = preset.system_prompt if preset and preset.system_prompt else None
 
         # 确定要加载哪些 skills
         skills_filter: Optional[List[str]] = config.skills

+ 32 - 1
agent/docs/architecture.md

@@ -559,6 +559,7 @@ class AgentPreset:
     denied_tools: Optional[List[str]] = None   # 黑名单
     max_iterations: int = 30
     temperature: Optional[float] = None
+    system_prompt: Optional[str] = None        # 完全自定义 system prompt;None = 使用默认模板 + skills
     skills: Optional[List[str]] = None         # 注入 system prompt 的 skill 名称列表;None = 加载全部
     description: Optional[str] = None
 
@@ -592,7 +593,37 @@ AGENT_PRESETS = {
 
 **实现**:`agent/core/presets.py`
 
-**用户自定义**:项目级配置文件(如 `examples/how/presets.json`)可通过 `register_preset()` 注册额外预设。项目专用的 Agent 类型建议放在项目目录下,而非内置预设。
+**System Prompt 构建优先级**(`agent/core/runner.py:_build_system_prompt`):
+1. 消息中已有 system → 使用消息中的
+2. `config.system_prompt` 显式指定 → 使用 config
+3. `preset.system_prompt` 存在 → 使用 preset
+4. 默认模板 + skills
+
+**用户自定义**:项目级配置文件(如 `examples/production/presets.json`)可通过 `load_presets_from_json()` 加载预设。支持 `system_prompt_file` 字段从 `.prompt` 文件加载完整 system prompt。
+
+**示例**(`examples/production/presets.json`):
+```json
+{
+  "tool_research": {
+    "system_prompt_file": "tool_research.prompt",
+    "max_iterations": 50,
+    "skills": ["planning", "research", "browser"],
+    "description": "工具调研 Agent"
+  }
+}
+```
+
+**加载方式**:
+```python
+from agent.core.presets import load_presets_from_json
+
+load_presets_from_json("examples/production/presets.json")
+```
+
+**使用方式**:LLM 调用 `agent` 工具时指定 `agent_type` 参数:
+```python
+agent(task="调研视频生成工具", agent_type="tool_research")
+```
 
 ---
 

+ 15 - 0
agent/docs/tools.md

@@ -831,10 +831,20 @@ async def agent(
     task: Union[str, List[str]],
     messages: Optional[Union[Messages, List[Messages]]] = None,
     continue_from: Optional[str] = None,
+    agent_type: Optional[str] = None,
+    skills: Optional[List[str]] = None,
     context: Optional[dict] = None,
 ) -> Dict[str, Any]:
 ```
 
+**参数说明**:
+- `task`: 任务描述(字符串=单任务,列表=多任务并行)
+- `messages`: 预置消息(None/1D 列表/2D 列表)
+- `continue_from`: 继续已有 trace(仅单任务)
+- `agent_type`: 子 Agent 类型,决定 preset 和默认 skills(如 "tool_research")
+- `skills`: 附加到 system prompt 的 skill 名称列表,覆盖 preset 默认值
+- `context`: 框架自动注入的上下文
+
 **messages 参数**:
 - `None`:无预置消息
 - `Messages`(1D 列表):所有 agent 共享
@@ -842,6 +852,11 @@ async def agent(
 
 运行时判断:`messages[0]` 是 dict → 1D 共享;是 list → 2D per-agent。
 
+**agent_type 与 Presets**:
+- 通过 `agent_type` 参数指定预定义的 Agent 配置(工具权限、system prompt、skills 等)
+- 项目可在 `presets.json` 中定义自定义 preset,支持从 `.prompt` 文件加载 system prompt
+- 详见 `agent/docs/architecture.md` 的 "Agent 预设" 章节和 `examples/production/` 示例
+
 **单任务(delegate)**:
 - 适合委托专门任务(如代码分析、文档生成)
 - 完整工具权限,可执行复杂操作

+ 1 - 1
examples/production/config.py

@@ -16,7 +16,7 @@ RUN_CONFIG = RunConfig(
     max_iterations=1000,
 
     # 任务名称
-    name="Research Agent",
+    name="内容制作",
 
     # 知识管理配置
     knowledge=KnowledgeConfig(

+ 16 - 0
examples/production/presets.json

@@ -0,0 +1,16 @@
+{
+  "tool_research": {
+    "system_prompt_file": "tool_research.prompt",
+    "max_iterations": 50,
+    "temperature": 0.3,
+    "skills": ["planning", "research", "browser"],
+    "description": "工具调研 Agent - 为制作需求系统性搜索方法和工具"
+  },
+  "strategy_research": {
+    "system_prompt_file": "strategy_research.prompt",
+    "max_iterations": 50,
+    "temperature": 0.3,
+    "skills": ["planning", "research", "browser"],
+    "description": "策略调研 Agent - 为制作需求搜索制作策略和方法论"
+  }
+}

+ 7 - 9
examples/production/run.py

@@ -30,7 +30,6 @@ load_dotenv()
 
 from agent.llm.prompts import SimplePrompt
 from agent.core.runner import AgentRunner, RunConfig
-from agent.core.presets import AgentPreset, register_preset
 from agent.trace import (
     FileSystemTraceStore,
     Trace,
@@ -57,8 +56,8 @@ async def main():
     # 路径配置
     base_dir = Path(__file__).parent
     project_root = base_dir.parent.parent
-    prompt_path = base_dir / "research.prompt"
-    output_dir = base_dir / "output_1"
+    prompt_path = base_dir / "requirement.prompt"
+    output_dir = base_dir / "output"
     output_dir.mkdir(exist_ok=True)
 
     # 1. 配置日志
@@ -68,12 +67,11 @@ async def main():
     print("2. 加载 presets...")
     presets_path = base_dir / "presets.json"
     if presets_path.exists():
-        import json
-        with open(presets_path, "r", encoding="utf-8") as f:
-            project_presets = json.load(f)
-        for name, cfg in project_presets.items():
-            register_preset(name, AgentPreset(**cfg))
-        print(f"   - 已加载项目 presets: {list(project_presets.keys())}")
+        from agent.core.presets import load_presets_from_json
+        load_presets_from_json(str(presets_path))
+        print(f"   - 已加载项目 presets")
+    else:
+        print(f"   - 未找到 presets.json,跳过")
 
     # 3. 加载 prompt
     print("3. 加载 prompt...")

+ 6 - 3
gateway/docs/core/lifecycle.md

@@ -14,9 +14,12 @@
 
 Agent 生命周期管理,包括:
 
-- **Trace 注册和元数据管理**:管理 Trace 的注册信息和元数据
-- **Workspace 管理**:管理每个 Trace 的工作空间
-- **配置热重载**:监听配置文件变化并热重载
+- **Trace 注册**:调用 Agent 框架创建 Trace
+- **Trace 查询**:调用 Agent 框架查询 Trace 信息
+- **Workspace 管理**:确保 Workspace 目录存在和清理
+- **配置热重载**:监听 Agent 技能配置变化并热重载
+
+**说明:** Trace 元数据由 Agent 框架管理,Gateway 不维护副本
 
 ---