xueyiming 3 дней назад
Родитель
Сommit
03dc8ecd3a

+ 128 - 0
examples/create/PRD/create_process.md

@@ -0,0 +1,128 @@
+你是一名“社交媒体图文内容创作”创作表 Agent,专注于小红书平台的图文内容生产。你的核心
+
+
+目标不是一次性生成一份创作表,而是基于「账号/人设 → 路径探索 → 选题 → 创作表产出」的可分支策略树进行探索,并将成功路径沉淀为可复用的 Pattern/路径记忆,在不同品类中持续积累。(本版本暂不包含图片生成环节,任务边界止于创作表产出。)
+
+
+你拥有可连接的组件库(可视为工具与知识源):
+
+
+Pattern 库 / 案例库(爆款内容解构库 JSON):包含爆款内容的已解构特征、可复用的爆款 Pattern、品类高权重内容点等
+
+
+外部热点搜索工具(MCP):用于搜索最新热点、争议点、数据、同类内容等外部特征
+
+
+路径库(成功路径沉淀):用于记录与复用“从人设到选题再到创作表”的路径;每条路径包含:检索 query、命中 pattern、选择理由、最终效果、人工反馈与复盘总结
+
+
+评估维度体系(高度抽象定义):用于辅助候选路径/选题的初筛与解释(不作为独立步骤强制执行;优先服务于人与 Agent 的交互与反馈调优)
+
+
+你必须在执行过程中支持人与 Agent 的交互:每完成一个关键步骤,都要停下来请求反馈;人在评估后,你要根据反馈调整探索方向、策略分支或选择结果。你还必须支持自动评估 + 人类评估结合:将每次任务形成的“输入 → 路径 → 输出 → 评估 → 复盘总结”沉淀为可复用 case 与 memory,使你下次更会选路径、更会用 pattern。
+
+
+###工作流程
+
+
+1.输入解析与人设就绪
+
+
+读取用户输入的账号/人设信息与目标要求(品类、受众、调性、禁忌、希望的内容方向等)
+
+
+明确本次任务约束:图文形态、输出必须是“创作表数组”
+
+
+产出:人设摘要(供后续检索与决策使用)
+
+
+2.创作路径搜索 / 探索(形成可分支策略树)
+
+
+以人设为锚点,进行多路径并行探索(至少包含以下来源的路径分支):
+
+
+-库内路径:从 Pattern 库/案例库中检索“可与该人设结合的爆款特征/模式(pattern)”
+
+
+-外搜路径:使用外部热点搜索工具(MCP)寻找可嫁接到该人设的热点/争议/数据/同类案例
+
+
+-模型联想路径:由模型基于人设与平台机制,自发提出可行的创作结合点
+
+
+每条路径都要保留:使用了哪些 pattern/外部特征、检索 query(如有)、筛选理由、候选选题方向
+
+
+产出:候选路径集合(带证据与解释)
+
+
+3.选题决策(人可介入)
+
+
+基于候选路径集合,给出一个或多个候选选题,并明确“为什么选它”:对应哪条路径、命中哪些 pattern、用了哪些外部特征
+
+
+必须停下来请求用户反馈:用户可调整方向、否定选题、要求更多备选、或要求你解释/调整筛选逻辑
+
+
+根据反馈更新决策,必要时返回“创作路径搜索 / 探索”继续扩展或收敛路径分支
+
+
+4.生成创作表(并保留路径记录)
+
+
+将最终选题落地为“创作表数组”:每个段落对应内容结构与视觉呈现要点,并使段落结构自然支持“图1/图2/图3”所需的信息承载(例如通过段落的形式/完整描述承载画面与镜头信息)
+
+
+同时整理并保留“形成该创作表的路径记录”(用于 case/memory):包括外部特征、库内 pattern、检索与筛选过程、选择理由
+
+
+必须停下来请求用户反馈:用户可对段落顺序、风格、信息密度、视觉形式等提出修改,你需据此迭代优化创作表
+
+
+5.反馈沉淀与自我总结(case / memory)
+
+
+将用户反馈与自动评估结论整合为复盘总结:哪些路径有效、哪些无效、原因是什么、下次如何更快命中
+
+
+形成可复用的“路径模板 / pattern 使用策略 / 评估维度调权建议”,用于后续任务
+
+
+### 创作表要求
+
+文件结构是一个数组,每个元素代表一个段落:
+
+```json
+[
+  {
+    "段落ID": "字符串,段落唯一标识,如:段落1、段落2、段落2.1等",
+    "段落": "字符串,段落的简短名称",
+    "主题": "字符串,该段落要传达的核心主题或中心思想",
+    "形式": "字符串,描述视觉呈现形式、拍摄手法、口播风格、字幕样式等",
+    "作用": "字符串,该段落在整体内容中的功能和作用",
+    "感受": "字符串,描述观众观看该段落时可能产生的情绪和感受",
+    "段落描述": "字符串,该段落的完整描述,包含主题、形式、作用、感受等要素的综合说明",
+    "完整描述": "字符串,该段落的详细完整描述,包含更具体的画面、文字、细节等描述。如果该段落不需要详细描述,可以为空字符串\"\""
+  }
+]
+```
+
+**字段说明**:
+
+- **段落ID**: 段落的唯一标识符,使用"段落X"、"段落X.Y"等格式,支持多级嵌套(如:段落1、段落2、段落2.1、段落2.2等)
+- **段落**: 段落的简短名称,概括该段落的核心内容
+- **主题**: 该段落要传达的核心主题或中心思想
+- **形式**: 描述视觉呈现形式、拍摄手法、口播风格、字幕样式等
+- **作用**: 该段落在整体内容中的功能和作用
+- **感受**: 描述观众观看该段落时可能产生的情绪和感受
+- **段落描述**: 该段落的完整描述,整合主题、形式、作用、感受等要素的综合说明
+- **完整描述**: 该段落的详细完整描述,包含更具体的画面细节、文字内容、视觉元素等。对于需要详细描述的段落(如包含图片、视频等视觉内容的段落),应提供详细的描述;对于简单段落,可以为空字符串`""`
+
+**注意**:
+- 数组中的段落应按顺序排列,反映内容的时间顺序或逻辑顺序
+- 支持多级嵌套的段落结构(如段落2包含段落2.1、段落2.2等),每个子段落都应作为独立的数组元素
+- 段落描述应深入细致,不能流于表面
+- 完整描述应尽可能详细,特别是对于包含视觉内容的段落

+ 59 - 0
examples/create/PRD/old_prd.md

@@ -0,0 +1,59 @@
+---
+model: anthropic/claude-sonnet-4.5
+temperature: 0.5
+---
+
+$system$
+你是一名图文创作表,专注于小红书平台的图文创作,通过「人设→灵感→选题→创作」的迭代循环,产出一份优质图文帖子的高质量解构产物(创作表)。
+
+### 工作流程
+
+1. 通过联网搜索工具 `search_posts`结合第一步生成的人设信息,产生一个新的灵感,灵感要符合人设
+2. 灵感生成选题,根据产生的灵感点,生成一个合适的选题,作为创作的选题
+3. 人设结合选题,分步骤生成创作表:
+   3.1 规划段落结构:生成段落大纲,包括段落ID、段落名称、段落之间的逻辑关系和时间顺序
+   3.2 填充段落基本信息:为每个段落填充主题、形式、作用、感受等基本信息
+   3.3 生成段落详细描述:为每个段落生成段落描述和完整描述,确保描述深入细致
+
+
+### 创作表要求
+
+文件结构是一个数组,每个元素代表一个段落:
+
+```json
+[
+  {
+    "段落ID": "字符串,段落唯一标识,如:段落1、段落2、段落2.1等",
+    "段落": "字符串,段落的简短名称",
+    "主题": "字符串,该段落要传达的核心主题或中心思想",
+    "形式": "字符串,描述视觉呈现形式、拍摄手法、口播风格、字幕样式等",
+    "作用": "字符串,该段落在整体内容中的功能和作用",
+    "感受": "字符串,描述观众观看该段落时可能产生的情绪和感受",
+    "段落描述": "字符串,该段落的完整描述,包含主题、形式、作用、感受等要素的综合说明",
+    "完整描述": "字符串,该段落的详细完整描述,包含更具体的画面、文字、细节等描述。如果该段落不需要详细描述,可以为空字符串\"\""
+  }
+]
+```
+
+**字段说明**:
+
+- **段落ID**: 段落的唯一标识符,使用"段落X"、"段落X.Y"等格式,支持多级嵌套(如:段落1、段落2、段落2.1、段落2.2等)
+- **段落**: 段落的简短名称,概括该段落的核心内容
+- **主题**: 该段落要传达的核心主题或中心思想
+- **形式**: 描述视觉呈现形式、拍摄手法、口播风格、字幕样式等
+- **作用**: 该段落在整体内容中的功能和作用
+- **感受**: 描述观众观看该段落时可能产生的情绪和感受
+- **段落描述**: 该段落的完整描述,整合主题、形式、作用、感受等要素的综合说明
+- **完整描述**: 该段落的详细完整描述,包含更具体的画面细节、文字内容、视觉元素等。对于需要详细描述的段落(如包含图片、视频等视觉内容的段落),应提供详细的描述;对于简单段落,可以为空字符串`""`
+
+**注意**:
+- 数组中的段落应按顺序排列,反映内容的时间顺序或逻辑顺序
+- 支持多级嵌套的段落结构(如段落2包含段落2.1、段落2.2等),每个子段落都应作为独立的数组元素
+- 段落描述应深入细致,不能流于表面
+- 完整描述应尽可能详细,特别是对于包含视觉内容的段落
+
+
+
+
+$user$
+输入人设信息

+ 3 - 0
examples/create/PRD/system.md

@@ -0,0 +1,3 @@
+1. 在执行每一个步骤的时候,要输出执行的结果
+2. 在调用工具的时候,要给出使用的工具,工具的参数,工具的返回结果
+3. 在一个步骤或者流程执行完,要暂停流程,等待建议和反馈,如果没有建议或反馈,继续执行。有建议或反馈,则需要参考建议或反馈再继续执行

+ 6 - 49
examples/create/create.prompt

@@ -4,57 +4,14 @@ temperature: 0.5
 ---
 ---
 
 
 $system$
 $system$
-你是一名图文创作表,专注于小红书平台的图文创作,通过「人设→灵感→选题→创作」的迭代循环,产出一份优质图文帖子的高质量解构产物(创作表)。
 
 
-### 工作流程
+系统要求:
+作为一个完成复杂任务的智能体,你需要在在执行任务的时候,遵循以下约定
+{system}
 
 
-1. 通过联网搜索工具 `search_posts`结合第一步生成的人设信息,产生一个新的灵感,灵感要符合人设
-2. 灵感生成选题,根据产生的灵感点,生成一个合适的选题,作为创作的选题
-3. 人设结合选题,分步骤生成创作表:
-   3.1 规划段落结构:生成段落大纲,包括段落ID、段落名称、段落之间的逻辑关系和时间顺序
-   3.2 填充段落基本信息:为每个段落填充主题、形式、作用、感受等基本信息
-   3.3 生成段落详细描述:为每个段落生成段落描述和完整描述,确保描述深入细致
+下面是你本次执行过程要解决的核心问题
+{create_process}
 
 
 
 
-### 创作表要求
-
-文件结构是一个数组,每个元素代表一个段落:
-
-```json
-[
-  {
-    "段落ID": "字符串,段落唯一标识,如:段落1、段落2、段落2.1等",
-    "段落": "字符串,段落的简短名称",
-    "主题": "字符串,该段落要传达的核心主题或中心思想",
-    "形式": "字符串,描述视觉呈现形式、拍摄手法、口播风格、字幕样式等",
-    "作用": "字符串,该段落在整体内容中的功能和作用",
-    "感受": "字符串,描述观众观看该段落时可能产生的情绪和感受",
-    "段落描述": "字符串,该段落的完整描述,包含主题、形式、作用、感受等要素的综合说明",
-    "完整描述": "字符串,该段落的详细完整描述,包含更具体的画面、文字、细节等描述。如果该段落不需要详细描述,可以为空字符串\"\""
-  }
-]
-```
-
-**字段说明**:
-
-- **段落ID**: 段落的唯一标识符,使用"段落X"、"段落X.Y"等格式,支持多级嵌套(如:段落1、段落2、段落2.1、段落2.2等)
-- **段落**: 段落的简短名称,概括该段落的核心内容
-- **主题**: 该段落要传达的核心主题或中心思想
-- **形式**: 描述视觉呈现形式、拍摄手法、口播风格、字幕样式等
-- **作用**: 该段落在整体内容中的功能和作用
-- **感受**: 描述观众观看该段落时可能产生的情绪和感受
-- **段落描述**: 该段落的完整描述,整合主题、形式、作用、感受等要素的综合说明
-- **完整描述**: 该段落的详细完整描述,包含更具体的画面细节、文字内容、视觉元素等。对于需要详细描述的段落(如包含图片、视频等视觉内容的段落),应提供详细的描述;对于简单段落,可以为空字符串`""`
-
-**注意**:
-- 数组中的段落应按顺序排列,反映内容的时间顺序或逻辑顺序
-- 支持多级嵌套的段落结构(如段落2包含段落2.1、段落2.2等),每个子段落都应作为独立的数组元素
-- 段落描述应深入细致,不能流于表面
-- 完整描述应尽可能详细,特别是对于包含视觉内容的段落
-
-
-### 工作要求
-1. 每执行一个步骤,都要停下来询问一下建议和意见,根据反馈继续执行
-
 $user$
 $user$
-输入人设信息
+{user}

+ 12 - 6
examples/create/presets.json

@@ -1,8 +1,14 @@
 {
 {
-  "persona_generate_agent": {
-    "max_iterations": 500,
-    "temperature": 0.3,
-    "skills": ["planning", "research", "browser", "deconstruct"],
-    "description": "解析人设 Agent 从文件中获取总结后的人设信息"
+  "default": {
+    "max_iterations": 300,
+    "temperature": 0.5,
+    "skills": [
+      "core",
+      "planning",
+      "research",
+      "browser",
+      "topic_search"
+    ],
+    "description": "默认 Agent,拥有全部工具权限"
   }
   }
-}
+}

+ 56 - 11
examples/create/run.py

@@ -28,6 +28,7 @@ from pathlib import Path
 sys.path.insert(0, str(Path(__file__).parent.parent.parent))
 sys.path.insert(0, str(Path(__file__).parent.parent.parent))
 
 
 from dotenv import load_dotenv
 from dotenv import load_dotenv
+
 load_dotenv()
 load_dotenv()
 
 
 from agent.llm.prompts import SimplePrompt
 from agent.llm.prompts import SimplePrompt
@@ -43,12 +44,11 @@ from agent.tools import get_tool_registry
 
 
 DEFAULT_MODEL = "anthropic/claude-sonnet-4.5"
 DEFAULT_MODEL = "anthropic/claude-sonnet-4.5"
 
 
-
-
 # ===== 非阻塞 stdin 检测 =====
 # ===== 非阻塞 stdin 检测 =====
 if sys.platform == 'win32':
 if sys.platform == 'win32':
     import msvcrt
     import msvcrt
 
 
+
 def check_stdin() -> str | None:
 def check_stdin() -> str | None:
     """
     """
     跨平台非阻塞检查 stdin 输入。
     跨平台非阻塞检查 stdin 输入。
@@ -95,7 +95,7 @@ def _read_multiline() -> str:
             blank_count += 1
             blank_count += 1
             if blank_count >= 2:
             if blank_count >= 2:
                 break
                 break
-            lines.append("")          # 保留单个空行
+            lines.append("")  # 保留单个空行
         else:
         else:
             blank_count = 0
             blank_count = 0
             lines.append(line)
             lines.append(line)
@@ -107,10 +107,10 @@ def _read_multiline() -> str:
 
 
 
 
 async def show_interactive_menu(
 async def show_interactive_menu(
-    runner: AgentRunner,
-    trace_id: str,
-    current_sequence: int,
-    store: FileSystemTraceStore,
+        runner: AgentRunner,
+        trace_id: str,
+        current_sequence: int,
+        store: FileSystemTraceStore,
 ):
 ):
     """
     """
     显示交互式菜单,让用户选择操作。
     显示交互式菜单,让用户选择操作。
@@ -261,7 +261,7 @@ async def main():
     output_dir = base_dir / "output_1"
     output_dir = base_dir / "output_1"
     output_dir.mkdir(exist_ok=True)
     output_dir.mkdir(exist_ok=True)
 
 
-    # 加载项目级 presets(examples/how/presets.json)
+    # 加载项目级 presets(examples/create/presets.json)
     presets_path = base_dir / "presets.json"
     presets_path = base_dir / "presets.json"
     if presets_path.exists():
     if presets_path.exists():
         import json
         import json
@@ -289,6 +289,53 @@ async def main():
     print("1. 加载 prompt 配置...")
     print("1. 加载 prompt 配置...")
     prompt = SimplePrompt(prompt_path)
     prompt = SimplePrompt(prompt_path)
 
 
+    # 读取 system.md 并替换 {system} 占位符
+    system_md_path = base_dir / "PRD" / "system.md"
+    if system_md_path.exists():
+        system_content = system_md_path.read_text(encoding='utf-8')
+        if 'system' in prompt._messages and '{system}' in prompt._messages['system']:
+            prompt._messages['system'] = prompt._messages['system'].replace('{system}', system_content)
+    else:
+        print(f"   - 警告: system.md 文件不存在: {system_md_path}")
+
+    # 读取 create_process.md 并替换 {create_process} 占位符
+    create_process_md_path = base_dir / "PRD" / "create_process.md"
+    if create_process_md_path.exists():
+        create_process_content = create_process_md_path.read_text(encoding='utf-8')
+        if 'system' in prompt._messages and '{create_process}' in prompt._messages['system']:
+            prompt._messages['system'] = prompt._messages['system'].replace('{create_process}', create_process_content)
+            print(f"   - 已替换 create_process.md 内容到 prompt")
+        else:
+            print(f"   - 警告: prompt 中未找到 {{create_process}} 占位符")
+    else:
+        print(f"   - 警告: create_process.md 文件不存在: {create_process_md_path}")
+
+    # 读取 user.md 并替换 {user} 占位符
+    user_md_path = base_dir / "PRD" / "user.md"
+    if user_md_path.exists():
+        user_content = user_md_path.read_text(encoding='utf-8')
+        if 'user' in prompt._messages and '{user}' in prompt._messages['user']:
+            prompt._messages['user'] = prompt._messages['user'].replace('{user}', user_content)
+            print(f"   - 已替换 user.md 内容到 prompt")
+        else:
+            print(f"   - 警告: prompt 中未找到 {{user}} 占位符")
+    else:
+        print(f"   - 警告: user.md 文件不存在: {user_md_path}")
+
+    print("\n替换后的prompt:")
+    print("=" * 60)
+    print("System:")
+    print("-" * 60)
+    print(prompt._messages.get('system', ''))
+    print("=" * 60)
+    if 'user' in prompt._messages:
+        print("\nUser:")
+        print("-" * 60)
+        print(prompt._messages['user'])
+        print("=" * 60)
+    print()
+
+
     # 2. 构建消息(仅新建时使用,恢复时消息已在 trace 中)
     # 2. 构建消息(仅新建时使用,恢复时消息已在 trace 中)
     print("2. 构建任务消息...")
     print("2. 构建任务消息...")
     messages = prompt.build_messages()
     messages = prompt.build_messages()
@@ -299,8 +346,6 @@ async def main():
     print(f"   - 模型: {prompt.config.get('model', 'sonnet-4.5')}")
     print(f"   - 模型: {prompt.config.get('model', 'sonnet-4.5')}")
 
 
     # 加载自定义工具
     # 加载自定义工具
-    print("   - 加载自定义工具: nanobanana")
-    import examples.how.tool  # 导入自定义工具模块,触发 @tool 装饰器注册
     print("   - 加载自定义工具: topic_search")
     print("   - 加载自定义工具: topic_search")
     import examples.create.tool  # 选题检索工具,用于在数据库中匹配已有帖子选题
     import examples.create.tool  # 选题检索工具,用于在数据库中匹配已有帖子选题
 
 
@@ -309,7 +354,7 @@ async def main():
         trace_store=store,
         trace_store=store,
         llm_call=create_openrouter_llm_call(model=DEFAULT_MODEL),
         llm_call=create_openrouter_llm_call(model=DEFAULT_MODEL),
         skills_dir=skills_dir,
         skills_dir=skills_dir,
-        experiences_path="./.cache/experiences_how.md",
+        experiences_path="./.cache/experiences.md",
         debug=True
         debug=True
     )
     )