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

update: extracted prompts to prompts.py

guantao 4 дней назад
Родитель
Сommit
111ced8b7e

+ 2 - 1
.claude/settings.local.json

@@ -13,7 +13,8 @@
       "Bash(curl:*)",
       "Bash(curl:*)",
       "Bash(tree:*)",
       "Bash(tree:*)",
       "Bash(xargs grep:*)",
       "Bash(xargs grep:*)",
-      "Bash(npm run:*)"
+      "Bash(npm run:*)",
+      "Bash(sed:*)"
     ],
     ],
     "deny": [],
     "deny": [],
     "ask": []
     "ask": []

+ 546 - 0
agent/core/prompts.py

@@ -0,0 +1,546 @@
+"""
+Agent 系统 Prompt 集中管理
+
+本文件集中管理 Agent 系统中使用的所有 prompt 模板,
+包括 runner.py、compaction.py、subagent.py、knowledge.py 等文件中的 prompt。
+
+## 📑 目录索引
+
+### 1. 系统级 Prompt (行 50+)
+- DEFAULT_SYSTEM_PREFIX                      # Agent 基础系统提示
+
+### 2. 研究流程 Prompt (行 60+)
+- RESEARCH_STAGE_PROMPT_TEMPLATE             # 调研阶段引导
+- PLANNING_STAGE_PROMPT                      # 计划阶段引导
+- RESEARCH_DECISION_GUIDE_TEMPLATE           # 调研决策阶段引导
+
+### 3. 压缩相关 Prompt (行 110+)
+- COMPRESSION_EVAL_PROMPT_TEMPLATE           # Level 2 压缩与经验评估
+- REFLECT_PROMPT                             # 经验反思提取
+- SUMMARY_HEADER_TEMPLATE                    # 压缩后的摘要头部
+
+### 4. 工具执行 Prompt (行 180+)
+- TRUNCATION_HINT                            # 响应截断提示
+- TOOL_INTERRUPTED_MESSAGE                   # 工具执行中断提示
+- AGENT_INTERRUPTED_SUMMARY                  # Agent 中断摘要
+- AGENT_CONTINUE_HINT_TEMPLATE               # Agent 继续执行提示
+
+### 5. 任务生成 Prompt (行 200+)
+- TASK_NAME_GENERATION_SYSTEM_PROMPT         # 任务名称生成
+- TASK_NAME_FALLBACK                         # 默认任务名称
+
+### 6. 经验管理 Prompt (行 210+)
+- EXPERIENCE_ENTRY_TEMPLATE                  # 经验条目格式
+- EXPERIENCE_SUMMARY_WITH_RESULTS            # 有结果的经验摘要
+- EXPERIENCE_SUMMARY_NO_RESULTS              # 无结果的经验摘要
+- EXPERIENCE_PARSE_WARNING                   # 经验解析警告
+
+### 7. 辅助函数 - 基础 Prompt 构建 (行 240+)
+- build_research_stage_prompt()              # 构建调研阶段 prompt
+- build_research_decision_guide()            # 构建调研决策引导
+- build_compression_eval_prompt()            # 构建压缩评估 prompt
+- build_summary_header()                     # 构建摘要头部
+- build_tool_interrupted_message()           # 构建工具中断消息
+- build_agent_continue_hint()                # 构建 Agent 继续提示
+- build_experience_entry()                   # 构建经验条目
+
+### 8. 子 Agent 相关 Prompt (行 320+)
+- EVALUATE_PROMPT_TEMPLATE                   # 评估任务 prompt
+- DELEGATE_RESULT_HEADER                     # 委托任务结果头部
+- DELEGATE_SAVED_KNOWLEDGE_HEADER            # 保存知识头部
+- DELEGATE_STATS_HEADER                      # 执行统计头部
+- EXPLORE_RESULT_HEADER                      # 探索结果头部
+- EXPLORE_BRANCH_TEMPLATE                    # 探索分支模板
+- EXPLORE_STATUS_SUCCESS                     # 成功状态
+- EXPLORE_STATUS_FAILED                      # 失败状态
+- EXPLORE_STATUS_ERROR                       # 错误状态
+- EXPLORE_SUMMARY_HEADER                     # 探索总结头部
+
+### 9. 辅助函数 - 子 Agent Prompt 构建 (行 380+)
+- build_evaluate_prompt()                    # 构建评估 prompt
+
+### 10. 知识管理相关 Prompt (行 400+)
+- KNOWLEDGE_SEMANTIC_ROUTE_PROMPT_TEMPLATE   # 知识语义路由
+- KNOWLEDGE_EVOLVE_PROMPT_TEMPLATE           # 知识进化重写
+- KNOWLEDGE_SLIM_PROMPT_TEMPLATE             # 知识库瘦身
+
+### 11. 辅助函数 - 知识管理 Prompt 构建 (行 450+)
+- build_knowledge_semantic_route_prompt()    # 构建知识路由 prompt
+- build_knowledge_evolve_prompt()            # 构建知识进化 prompt
+- build_knowledge_slim_prompt()              # 构建知识瘦身 prompt
+
+## 🔍 快速查找
+
+**按使用场景查找:**
+- 研究流程:第 2 节
+- 对话压缩:第 3 节
+- 工具调用:第 4 节
+- 经验管理:第 6 节
+- 子 Agent:第 8 节
+- 知识管理:第 10 节
+
+**按文件来源查找:**
+- runner.py → 第 1, 2, 4, 5 节
+- compaction.py → 第 3 节
+- subagent.py → 第 8 节
+- knowledge.py → 第 10 节
+
+## ⚠️ 重要提示
+
+1. **变量占位符**:所有 `{变量名}` 格式的占位符必须保留
+2. **特殊标记**:`[[EVALUATION]]`、`[[SUMMARY]]` 等标记不可删除
+3. **输出格式关键字**:代码解析依赖的关键字需要保持一致
+4. **使用辅助函数**:优先使用 `build_*()` 函数而非直接 `.format()`
+"""
+
+# ============================================================
+# 系统级 Prompt
+# ============================================================
+
+DEFAULT_SYSTEM_PREFIX = "你是最顶尖的AI助手,可以拆分并调用工具逐步解决复杂问题。"
+
+
+# ============================================================
+# 研究流程 Prompt - 调研阶段
+# ============================================================
+
+RESEARCH_STAGE_PROMPT_TEMPLATE = """## 📚 研究流程 - 执行调研
+
+现有信息不足,需要进行调研。
+
+{research_skill_content}
+
+**重要提示**:
+- 调研完成后,请使用 `save_knowledge` 工具保存调研结果
+- 系统会自动检测到 save_knowledge 调用,并进入下一阶段(计划)
+"""
+
+
+# ============================================================
+# 研究流程 Prompt - 计划阶段
+# ============================================================
+
+PLANNING_STAGE_PROMPT = """## 📋 研究流程 - 制定计划
+
+调研已完成(或无需调研),现在请制定执行计划。
+
+**请立即执行以下操作**:
+1. 使用 `goal` 工具创建目标树
+2. 将任务分解为可执行的子目标
+3. 为每个子目标设置合理的优先级
+
+注意:这是强制步骤,必须创建 goal tree 才能进入执行阶段。
+"""
+
+
+# ============================================================
+# 研究流程 Prompt - 调研决策阶段
+# ============================================================
+
+RESEARCH_DECISION_GUIDE_TEMPLATE = """---
+
+## 🤔 调研决策
+
+{experience_summary}
+
+### 决策指南
+
+**当前状态**:系统已自动检索知识库和经验库,相关内容已注入到上方的 GoalTree 中(查看 Current Goal 下的「📚 相关知识」部分)。
+
+**请根据已注入的知识和经验,选择下一步行动**:
+
+**选项 1: 知识充足,直接制定计划**
+- 如果上方显示的知识和经验已经足够完成任务
+- 直接使用 `goal` 工具制定执行计划
+
+**选项 2: 知识不足,需要调研** ⭐
+- 如果上方没有显示相关知识,或现有知识不足以完成任务
+- **立即调用 `agent` 工具启动调研子任务**:
+
+```python
+agent(
+    task=\"\"\"针对任务「{task_desc}」进行深入调研:
+
+1. 使用 web_search 工具搜索相关技术文档、教程、最佳实践
+2. 搜索关键词建议:
+   - 核心技术名称 + "教程"
+   - 核心技术名称 + "最佳实践"
+   - 核心技术名称 + "示例代码"
+3. 使用 read_file 工具查看项目中的相关文件
+4. 对每条有价值的信息,使用 save_knowledge 工具保存,标签类型选择:
+   - tool: 工具使用方法
+   - definition: 概念定义
+   - usercase: 使用案例
+   - strategy: 策略经验
+
+调研完成后,系统会自动进入计划阶段。
+\"\"\",
+    skills=["research"]  # 注入调研指南
+)
+```
+
+**重要提示**:
+- 如果 GoalTree 中没有显示「📚 相关知识」,说明知识库为空,必须先调研
+- 调研应该简洁高效,最多设立两个 goal
+"""
+
+
+# ============================================================
+# 压缩相关 Prompt - Level 2 压缩与经验评估
+# ============================================================
+
+COMPRESSION_EVAL_PROMPT_TEMPLATE = """请对以上对话历史进行压缩总结,并评价所引用的历史知识/经验。
+### 任务 1:评价已用知识
+本次任务参考了以下知识内容:{ex_reference_list}
+
+请对比"知识建议"与"实际执行轨迹",给出三色打分:
+[[EVALUATION]]
+ID: knowledge-xxx 或 research-xxx | Result: helpful/harmful/mixed | Reason: [优点]... [局限/修正]...
+
+### 任务 2:对话历史摘要
+要求:
+1. 保留关键决策、结论和产出(如创建的文件、修改的代码、得出的分析结论)
+2. 保留重要的上下文(如用户的要求、约束条件、之前的讨论结果)
+3. 省略中间探索过程、重复的工具调用细节
+4. 使用结构化格式(标题 + 要点 + 相关资源引用,若有)
+5. 控制在 2000 字以内
+格式要求:
+[[SUMMARY]]
+(此处填写结构化的摘要内容)
+
+当前 GoalTree 状态:
+{goal_tree_prompt}
+"""
+
+
+# ============================================================
+# 压缩相关 Prompt - 经验反思
+# ============================================================
+
+REFLECT_PROMPT = """请回顾以上整个执行过程,提取有价值的经验教训。
+你必须将经验与当前的任务意图(Intent)和环境状态(State)挂钩,以便未来精准检索。
+关注以下方面:
+1. 人工干预:用户中途的指令是否说明了原来的执行过程哪里有问题
+2. 弯路:哪些尝试是不必要的,有没有更直接的方法
+3. 好的决策:哪些判断和选择是正确的,值得记住
+4. 工具使用:哪些工具用法是高效的,哪些可以改进
+
+输出格式(严格遵守):
+- 在每条经验前加一个[]中添加自定义的标签,标签要求总结实际的内容为若干词语,包括:
+    - intent: 当前的goal
+    - state: 环境状态(如果与工具相关,可以在标签中加入工具的名称)
+- 经验标签可用自然语言描述
+- 每条经验单独成段,格式固定为:- 当 [条件] 时,应该 [动作](原因:[一句话说明])。具体案例:[案例]
+- 条目之间用一个空行分隔
+- 不输出任何标题、分类、编号、分隔线或其他结构
+- 不使用 markdown 加粗、表格、代码块等格式
+- 每条经验自包含,读者无需上下文即可理解
+- 只提取最有价值的 5-10 条,宁少勿滥
+
+示例(仅供参考格式,不要复制内容):
+- [intent:示例生成 state:用户提醒,指定样本] 当用户说"给我示例"时,应该用真实数据而不是编造(原因:编造的示例无法验证质量)。具体案例:training_samples.json 中的示例全是 LLM 自己编造的,用户明确要求"基于我指定的样本"。
+"""
+
+
+# ============================================================
+# 压缩相关 Prompt - 压缩后的摘要头部
+# ============================================================
+
+SUMMARY_HEADER_TEMPLATE = """## 对话历史摘要(自动压缩)
+
+{summary_text}
+
+---
+请基于以上摘要和当前 GoalTree 继续执行任务。"""
+
+
+# ============================================================
+# 工具执行 Prompt - 响应截断提示
+# ============================================================
+
+TRUNCATION_HINT = """你的响应因为 max_tokens 限制被截断,tool call 参数不完整,未执行。请将大内容拆分为多次小的工具调用(例如用 write_file 的 append 模式分批写入)。"""
+
+
+# ============================================================
+# 工具执行 Prompt - 工具执行中断提示
+# ============================================================
+
+TOOL_INTERRUPTED_MESSAGE = """⚠️ 工具 {tool_name} 执行被中断(进程异常退出),未获得执行结果。请根据需要重新调用。"""
+
+AGENT_INTERRUPTED_SUMMARY = "⚠️ 子Agent执行被中断(进程异常退出)"
+
+AGENT_CONTINUE_HINT_TEMPLATE = '使用 continue_from="{sub_trace_id}" 可继续执行,保留已有进度'
+
+
+# ============================================================
+# 任务生成 Prompt
+# ============================================================
+
+TASK_NAME_GENERATION_SYSTEM_PROMPT = "用中文为以下任务生成一个简短标题(10-30字),只输出标题本身:"
+
+TASK_NAME_FALLBACK = "未命名任务"
+
+
+# ============================================================
+# 经验保存 Prompt - 经验条目格式
+# ============================================================
+
+EXPERIENCE_ENTRY_TEMPLATE = """---
+id: {ex_id}
+trace_id: {trace_id}
+tags: {{intent: {intents}, state: {states}}}
+metrics: {{helpful: 1, harmful: 0}}
+created_at: {created_at}
+---
+{content}
+"""
+
+
+# ============================================================
+# 经验检索 Prompt - 经验摘要格式
+# ============================================================
+
+EXPERIENCE_SUMMARY_WITH_RESULTS = "✅ 已自动检索到 {count} 条相关经验(见上方 GoalTree 中的「📚 相关知识」)\n"
+
+EXPERIENCE_SUMMARY_NO_RESULTS = "❌ 未找到相关经验\n"
+
+
+# ============================================================
+# 经验评估 Prompt - 格式解析警告
+# ============================================================
+
+EXPERIENCE_PARSE_WARNING = "未能解析出符合格式的经验条目,请检查 REFLECT_PROMPT。"
+
+
+# ============================================================
+# 辅助函数:构建特定场景的 Prompt
+# ============================================================
+
+def build_research_stage_prompt(research_skill_content: str) -> str:
+    """构建调研阶段的引导 prompt"""
+    return RESEARCH_STAGE_PROMPT_TEMPLATE.format(
+        research_skill_content=research_skill_content
+    )
+
+
+def build_research_decision_guide(
+    experience_results: list,
+    task_desc: str
+) -> str:
+    """构建调研决策阶段的引导消息"""
+    if experience_results:
+        experience_summary = EXPERIENCE_SUMMARY_WITH_RESULTS.format(
+            count=len(experience_results)
+        )
+    else:
+        experience_summary = EXPERIENCE_SUMMARY_NO_RESULTS
+
+    # 截取任务描述前100字符
+    task_desc_short = task_desc[:100] if len(task_desc) > 100 else task_desc
+
+    return RESEARCH_DECISION_GUIDE_TEMPLATE.format(
+        experience_summary=experience_summary,
+        task_desc=task_desc_short
+    )
+
+
+def build_compression_eval_prompt(
+    goal_tree_prompt: str,
+    ex_reference_list: str
+) -> str:
+    """构建 Level 2 压缩 prompt(含经验评估)"""
+    return COMPRESSION_EVAL_PROMPT_TEMPLATE.format(
+        goal_tree_prompt=goal_tree_prompt,
+        ex_reference_list=ex_reference_list
+    )
+
+
+def build_summary_header(summary_text: str) -> str:
+    """构建压缩后的摘要头部"""
+    return SUMMARY_HEADER_TEMPLATE.format(summary_text=summary_text)
+
+
+def build_tool_interrupted_message(tool_name: str) -> str:
+    """构建工具中断消息"""
+    return TOOL_INTERRUPTED_MESSAGE.format(tool_name=tool_name)
+
+
+def build_agent_continue_hint(sub_trace_id: str) -> str:
+    """构建 Agent 继续执行提示"""
+    return AGENT_CONTINUE_HINT_TEMPLATE.format(sub_trace_id=sub_trace_id)
+
+
+def build_experience_entry(
+    ex_id: str,
+    trace_id: str,
+    intents: list,
+    states: list,
+    created_at: str,
+    content: str
+) -> str:
+    """构建经验条目"""
+    return EXPERIENCE_ENTRY_TEMPLATE.format(
+        ex_id=ex_id,
+        trace_id=trace_id,
+        intents=intents,
+        states=states,
+        created_at=created_at,
+        content=content
+    )
+
+# ============================================================
+# 子 Agent 相关 Prompt - 评估任务
+# ============================================================
+
+EVALUATE_PROMPT_TEMPLATE = """# 评估任务
+
+请评估以下任务的执行结果是否满足要求。
+
+## 目标描述
+
+{goal_description}
+
+## 执行结果
+
+{result_text}
+
+## 输出格式
+
+## 评估结论
+[通过/不通过]
+
+## 评估理由
+[详细说明通过或不通过原因]
+
+## 修改建议(如果不通过)
+1. [建议1]
+2. [建议2]
+"""
+
+
+# ============================================================
+# 子 Agent 相关 Prompt - 结果格式化
+# ============================================================
+
+DELEGATE_RESULT_HEADER = "## 委托任务完成\n"
+
+DELEGATE_SAVED_KNOWLEDGE_HEADER = "**保存的知识** ({count} 条):"
+
+DELEGATE_STATS_HEADER = "**执行统计**:"
+
+EXPLORE_RESULT_HEADER = "## 探索结果\n"
+
+EXPLORE_BRANCH_TEMPLATE = "### 方案 {branch_name}: {task}"
+
+EXPLORE_STATUS_SUCCESS = "**状态**: ✓ 完成"
+
+EXPLORE_STATUS_FAILED = "**状态**: ✗ 失败"
+
+EXPLORE_STATUS_ERROR = "**状态**: ✗ 异常"
+
+EXPLORE_SUMMARY_HEADER = "## 总结"
+
+
+# ============================================================
+# 辅助函数:构建子 Agent 相关 Prompt
+# ============================================================
+
+def build_evaluate_prompt(goal_description: str, result_text: str) -> str:
+    """构建评估 prompt"""
+    return EVALUATE_PROMPT_TEMPLATE.format(
+        goal_description=goal_description,
+        result_text=result_text or "(无执行结果)"
+    )
+
+
+# ============================================================
+# 知识管理相关 Prompt - 语义路由
+# ============================================================
+
+KNOWLEDGE_SEMANTIC_ROUTE_PROMPT_TEMPLATE = """你是一个知识检索专家。根据用户的当前任务需求,从下列原子知识元数据中挑选出最相关的最多 {routing_k} 个知识 ID。
+任务需求:"{query_text}"
+
+可选知识列表:
+{routing_data}
+
+请直接输出 ID 列表,用逗号分隔(例如: knowledge-20260302-001, research-20260302-002)。若无相关项请输出 "None"。
+"""
+
+
+# ============================================================
+# 知识管理相关 Prompt - 知识进化重写
+# ============================================================
+
+KNOWLEDGE_EVOLVE_PROMPT_TEMPLATE = """你是一个 AI Agent 知识库管理员。请根据反馈建议,对现有的知识内容进行重写进化。
+
+【原知识内容】:
+{old_content}
+
+【实战反馈建议】:
+{feedback}
+
+【重写要求】:
+1. 融合知识:将反馈中的避坑指南、新参数或修正后的选择逻辑融入原知识,使其更具通用性和准确性。
+2. 保持结构:如果原内容有特定格式(如 Markdown、代码示例等),请保持该格式。
+3. 语言:简洁直接,使用中文。
+4. 禁止:严禁输出任何开场白、解释语或额外的 Markdown 标题,直接返回重写后的正文。
+"""
+
+
+# ============================================================
+# 知识管理相关 Prompt - 知识库瘦身
+# ============================================================
+
+KNOWLEDGE_SLIM_PROMPT_TEMPLATE = """你是一个 AI Agent 知识库管理员。以下是当前知识库的全部条目,请执行瘦身操作:
+
+【任务】:
+1. 识别语义高度相似或重复的知识,将它们合并为一条更精炼、更通用的知识。
+2. 合并时保留 helpful 最高的那条的 ID 和 metrics(metrics 中 helpful/harmful 取各条之和)。
+3. 对于独立的、无重复的知识,保持原样不动。
+4. 保持原有的知识结构和格式。
+
+【当前知识库】:
+{entries_text}
+
+【输出格式要求】:
+严格按以下格式输出每条知识,条目之间用 === 分隔:
+ID: <保留的id>
+TAGS: <yaml格式的tags>
+METRICS: <yaml格式的metrics>
+SCORE: <评分>
+SCENARIO: <场景描述>
+CONTENT: <知识内容>
+===
+"""
+
+
+# ============================================================
+# 辅助函数:构建知识管理相关 Prompt
+# ============================================================
+
+def build_knowledge_semantic_route_prompt(
+    query_text: str,
+    routing_data: str,
+    routing_k: int
+) -> str:
+    """构建知识语义路由 prompt"""
+    return KNOWLEDGE_SEMANTIC_ROUTE_PROMPT_TEMPLATE.format(
+        query_text=query_text,
+        routing_data=routing_data,
+        routing_k=routing_k
+    )
+
+
+def build_knowledge_evolve_prompt(old_content: str, feedback: str) -> str:
+    """构建知识进化重写 prompt"""
+    return KNOWLEDGE_EVOLVE_PROMPT_TEMPLATE.format(
+        old_content=old_content,
+        feedback=feedback
+    )
+
+
+def build_knowledge_slim_prompt(entries_text: str) -> str:
+    """构建知识库瘦身 prompt"""
+    return KNOWLEDGE_SLIM_PROMPT_TEMPLATE.format(
+        entries_text=entries_text
+    )

+ 44 - 106
agent/core/runner.py

@@ -39,6 +39,29 @@ from agent.memory.models import Skill
 from agent.memory.protocols import MemoryStore, StateStore
 from agent.memory.protocols import MemoryStore, StateStore
 from agent.memory.skill_loader import load_skills_from_dir
 from agent.memory.skill_loader import load_skills_from_dir
 from agent.tools import ToolRegistry, get_tool_registry
 from agent.tools import ToolRegistry, get_tool_registry
+from agent.core.prompts import (
+    DEFAULT_SYSTEM_PREFIX,
+    RESEARCH_STAGE_PROMPT_TEMPLATE,
+    PLANNING_STAGE_PROMPT,
+    RESEARCH_DECISION_GUIDE_TEMPLATE,
+    TRUNCATION_HINT,
+    TOOL_INTERRUPTED_MESSAGE,
+    AGENT_INTERRUPTED_SUMMARY,
+    AGENT_CONTINUE_HINT_TEMPLATE,
+    TASK_NAME_GENERATION_SYSTEM_PROMPT,
+    TASK_NAME_FALLBACK,
+    EXPERIENCE_ENTRY_TEMPLATE,
+    EXPERIENCE_SUMMARY_WITH_RESULTS,
+    EXPERIENCE_SUMMARY_NO_RESULTS,
+    EXPERIENCE_PARSE_WARNING,
+    SUMMARY_HEADER_TEMPLATE,
+    build_research_stage_prompt,
+    build_research_decision_guide,
+    build_summary_header,
+    build_tool_interrupted_message,
+    build_agent_continue_hint,
+    build_experience_entry,
+)
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
@@ -741,31 +764,10 @@ class AgentRunner:
                 logger.warning(f"无法读取 research.md: {e}")
                 logger.warning(f"无法读取 research.md: {e}")
                 research_skill_content = "(无法加载 research.md 内容)"
                 research_skill_content = "(无法加载 research.md 内容)"
 
 
-            return f"""
-## 📚 研究流程 - 执行调研
-
-现有信息不足,需要进行调研。
-
-{research_skill_content}
-
-**重要提示**:
-- 调研完成后,请使用 `save_knowledge` 工具保存调研结果
-- 系统会自动检测到 save_knowledge 调用,并进入下一阶段(计划)
-"""
+            return build_research_stage_prompt(research_skill_content)
 
 
         elif stage == "planning":
         elif stage == "planning":
-            return f"""
-## 📋 研究流程 - 制定计划
-
-调研已完成(或无需调研),现在请制定执行计划。
-
-**请立即执行以下操作**:
-1. 使用 `goal` 工具创建目标树
-2. 将任务分解为可执行的子目标
-3. 为每个子目标设置合理的优先级
-
-注意:这是强制步骤,必须创建 goal tree 才能进入执行阶段。
-"""
+            return PLANNING_STAGE_PROMPT
 
 
         # research_decision 阶段的引导消息已移到 _build_research_decision_guide
         # research_decision 阶段的引导消息已移到 _build_research_decision_guide
         return ""
         return ""
@@ -775,60 +777,8 @@ class AgentRunner:
         experience_results = research_state.get("experience_results", [])
         experience_results = research_state.get("experience_results", [])
         task_desc = research_state.get("task_desc", "")
         task_desc = research_state.get("task_desc", "")
 
 
-        # 构建经验摘要
-        experience_summary = ""
-        if experience_results:
-            experience_summary = f"✅ 已自动检索到 {len(experience_results)} 条相关经验(见上方 GoalTree 中的「📚 相关知识」)\n"
-        else:
-            experience_summary = "❌ 未找到相关经验\n"
-
-        return f"""
----
-
-## 🤔 调研决策
-
-{experience_summary}
-
-### 决策指南
-
-**当前状态**:系统已自动检索知识库和经验库,相关内容已注入到上方的 GoalTree 中(查看 Current Goal 下的「📚 相关知识」部分)。
+        return build_research_decision_guide(experience_results, task_desc)
 
 
-**请根据已注入的知识和经验,选择下一步行动**:
-
-**选项 1: 知识充足,直接制定计划**
-- 如果上方显示的知识和经验已经足够完成任务
-- 直接使用 `goal` 工具制定执行计划
-
-**选项 2: 知识不足,需要调研** ⭐
-- 如果上方没有显示相关知识,或现有知识不足以完成任务
-- **立即调用 `agent` 工具启动调研子任务**:
-
-```python
-agent(
-    task=\"\"\"针对任务「{task_desc[:100]}」进行深入调研:
-
-1. 使用 web_search 工具搜索相关技术文档、教程、最佳实践
-2. 搜索关键词建议:
-   - 核心技术名称 + "教程"
-   - 核心技术名称 + "最佳实践"
-   - 核心技术名称 + "示例代码"
-3. 使用 read_file 工具查看项目中的相关文件
-4. 对每条有价值的信息,使用 save_knowledge 工具保存,标签类型选择:
-   - tool: 工具使用方法
-   - definition: 概念定义
-   - usercase: 使用案例
-   - strategy: 策略经验
-
-调研完成后,系统会自动进入计划阶段。
-\"\"\",
-    skills=["research"]  # 注入调研指南
-)
-```
-
-**重要提示**:
-- 如果 GoalTree 中没有显示「📚 相关知识」,说明知识库为空,必须先调研
-- 调研应该简洁高效,最多设立两个 goal
-"""
 
 
     async def _handle_research_flow_transition(
     async def _handle_research_flow_transition(
         self,
         self,
@@ -1284,10 +1234,7 @@ agent(
                     "[Runner] 响应被 max_tokens 截断,跳过 %d 个不完整的 tool calls",
                     "[Runner] 响应被 max_tokens 截断,跳过 %d 个不完整的 tool calls",
                     len(tool_calls),
                     len(tool_calls),
                 )
                 )
-                truncation_hint = (
-                    "你的响应因为 max_tokens 限制被截断,tool call 参数不完整,未执行。"
-                    "请将大内容拆分为多次小的工具调用(例如用 write_file 的 append 模式分批写入)。"
-                )
+                truncation_hint = TRUNCATION_HINT
                 history.append({
                 history.append({
                     "role": "assistant",
                     "role": "assistant",
                     "content": response_content,
                     "content": response_content,
@@ -1541,15 +1488,14 @@ agent(
                     states = [s.strip() for s in state_match.group(1).split(",")] if state_match and state_match.group(1) else []
                     states = [s.strip() for s in state_match.group(1).split(",")] if state_match and state_match.group(1) else []
 
 
                     ex_id = f"ex_{datetime.now().strftime('%m%d%H%M')}_{_uuid2.uuid4().hex[:4]}"
                     ex_id = f"ex_{datetime.now().strftime('%m%d%H%M')}_{_uuid2.uuid4().hex[:4]}"
-                    entry = f"""---
-id: {ex_id}
-trace_id: {trace_id}
-tags: {{intent: {intents}, state: {states}}}
-metrics: {{helpful: 1, harmful: 0}}
-created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
----
-- {content}
-- 经验ID: [{ex_id}]"""
+                    entry = build_experience_entry(
+                        ex_id=ex_id,
+                        trace_id=trace_id,
+                        intents=intents,
+                        states=states,
+                        created_at=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
+                        content=f"- {content}\n- 经验ID: [{ex_id}]"
+                    )
                     structured_entries.append(entry)
                     structured_entries.append(entry)
 
 
                 if structured_entries:
                 if structured_entries:
@@ -1602,7 +1548,7 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
 
 
                     logger.info(f"已提取并保存 {saved_count}/{len(structured_entries)} 条结构化经验到知识库")
                     logger.info(f"已提取并保存 {saved_count}/{len(structured_entries)} 条结构化经验到知识库")
                 else:
                 else:
-                    logger.warning("未能解析出符合格式的经验条目,请检查 REFLECT_PROMPT。")
+                    logger.warning(EXPERIENCE_PARSE_WARNING)
                     logger.debug(f"LLM Raw Output:\n{reflection_text}")
                     logger.debug(f"LLM Raw Output:\n{reflection_text}")
             else:
             else:
                 logger.warning("LLM 未生成反思内容")
                 logger.warning("LLM 未生成反思内容")
@@ -1673,10 +1619,7 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
             return history, head_seq, sequence
             return history, head_seq, sequence
 
 
         # --- Step 3: 存储 summary 消息 ---
         # --- Step 3: 存储 summary 消息 ---
-        summary_with_header = (
-            f"## 对话历史摘要(自动压缩)\n\n{summary_text}\n\n"
-            "---\n请基于以上摘要和当前 GoalTree 继续执行任务。"
-        )
+        summary_with_header = build_summary_header(summary_text)
 
 
         summary_msg = Message.create(
         summary_msg = Message.create(
             trace_id=trace_id,
             trace_id=trace_id,
@@ -1868,10 +1811,7 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
                     tc, goal_tree, assistant_msg,
                     tc, goal_tree, assistant_msg,
                 )
                 )
             else:
             else:
-                result_text = (
-                    f"⚠️ 工具 {tool_name} 执行被中断(进程异常退出),"
-                    "未获得执行结果。请根据需要重新调用。"
-                )
+                result_text = build_tool_interrupted_message(tool_name)
 
 
             synthetic_msg = Message.create(
             synthetic_msg = Message.create(
                 trace_id=trace_id,
                 trace_id=trace_id,
@@ -1943,14 +1883,12 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
         result: Dict[str, Any] = {
         result: Dict[str, Any] = {
             "mode": mode,
             "mode": mode,
             "status": "interrupted",
             "status": "interrupted",
-            "summary": "⚠️ 子Agent执行被中断(进程异常退出)",
+            "summary": AGENT_INTERRUPTED_SUMMARY,
             "task": task,
             "task": task,
         }
         }
         if sub_trace_id:
         if sub_trace_id:
             result["sub_trace_id"] = sub_trace_id
             result["sub_trace_id"] = sub_trace_id
-            result["hint"] = (
-                f'使用 continue_from="{sub_trace_id}" 可继续执行,保留已有进度'
-            )
+            result["hint"] = build_agent_continue_hint(sub_trace_id)
         if stats:
         if stats:
             result["stats"] = stats
             result["stats"] = stats
 
 
@@ -2147,7 +2085,7 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
         return self.tools.get_schemas(tool_names)
         return self.tools.get_schemas(tool_names)
 
 
     # 默认 system prompt 前缀(当 config.system_prompt 和前端都未提供 system message 时使用)
     # 默认 system prompt 前缀(当 config.system_prompt 和前端都未提供 system message 时使用)
-    DEFAULT_SYSTEM_PREFIX = "你是最顶尖的AI助手,可以拆分并调用工具逐步解决复杂问题。"
+    # 注意:此常量已迁移到 agent.core.prompts,这里保留引用以保持向后兼容
 
 
     async def _build_system_prompt(self, config: RunConfig, base_prompt: Optional[str] = None) -> Optional[str]:
     async def _build_system_prompt(self, config: RunConfig, base_prompt: Optional[str] = None) -> Optional[str]:
         """构建 system prompt(注入 skills)
         """构建 system prompt(注入 skills)
@@ -2185,7 +2123,7 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
             if skills_text:
             if skills_text:
                 system_prompt += f"\n\n## Skills\n{skills_text}"
                 system_prompt += f"\n\n## Skills\n{skills_text}"
         else:
         else:
-            system_prompt = self.DEFAULT_SYSTEM_PREFIX
+            system_prompt = DEFAULT_SYSTEM_PREFIX
             if skills_text:
             if skills_text:
                 system_prompt += f"\n\n## Skills\n{skills_text}"
                 system_prompt += f"\n\n## Skills\n{skills_text}"
 
 
@@ -2206,14 +2144,14 @@ created_at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
         raw_text = " ".join(text_parts).strip()
         raw_text = " ".join(text_parts).strip()
 
 
         if not raw_text:
         if not raw_text:
-            return "未命名任务"
+            return TASK_NAME_FALLBACK
 
 
         # 尝试使用 utility_llm 生成标题
         # 尝试使用 utility_llm 生成标题
         if self.utility_llm_call:
         if self.utility_llm_call:
             try:
             try:
                 result = await self.utility_llm_call(
                 result = await self.utility_llm_call(
                     messages=[
                     messages=[
-                        {"role": "system", "content": "用中文为以下任务生成一个简短标题(10-30字),只输出标题本身:"},
+                        {"role": "system", "content": TASK_NAME_GENERATION_SYSTEM_PROMPT},
                         {"role": "user", "content": raw_text[:2000]},
                         {"role": "user", "content": raw_text[:2000]},
                     ],
                     ],
                     model="gpt-4o-mini",  # 使用便宜模型
                     model="gpt-4o-mini",  # 使用便宜模型

+ 0 - 2
agent/tools/builtin/__init__.py

@@ -15,7 +15,6 @@ from agent.tools.builtin.file.grep import grep_content
 from agent.tools.builtin.bash import bash_command
 from agent.tools.builtin.bash import bash_command
 from agent.tools.builtin.skill import skill, list_skills
 from agent.tools.builtin.skill import skill, list_skills
 from agent.tools.builtin.subagent import agent, evaluate
 from agent.tools.builtin.subagent import agent, evaluate
-from agent.tools.builtin.experience import get_experience
 from agent.tools.builtin.search import search_posts, get_search_suggestions
 from agent.tools.builtin.search import search_posts, get_search_suggestions
 from agent.tools.builtin.sandbox import (sandbox_create_environment, sandbox_run_shell,
 from agent.tools.builtin.sandbox import (sandbox_create_environment, sandbox_run_shell,
                                          sandbox_rebuild_with_ports,sandbox_destroy_environment)
                                          sandbox_rebuild_with_ports,sandbox_destroy_environment)
@@ -36,7 +35,6 @@ __all__ = [
     # 系统工具
     # 系统工具
     "bash_command",
     "bash_command",
     "skill",
     "skill",
-    "get_experience",
     "search_knowledge",
     "search_knowledge",
     "save_knowledge",
     "save_knowledge",
     "list_knowledge",
     "list_knowledge",

+ 20 - 57
agent/tools/builtin/knowledge.py

@@ -14,6 +14,14 @@ from pathlib import Path
 from typing import List, Dict, Optional, Any
 from typing import List, Dict, Optional, Any
 from agent.tools import tool, ToolResult, ToolContext
 from agent.tools import tool, ToolResult, ToolContext
 from ...llm.openrouter import openrouter_llm_call
 from ...llm.openrouter import openrouter_llm_call
+from agent.core.prompts import (
+    KNOWLEDGE_SEMANTIC_ROUTE_PROMPT_TEMPLATE,
+    KNOWLEDGE_EVOLVE_PROMPT_TEMPLATE,
+    KNOWLEDGE_SLIM_PROMPT_TEMPLATE,
+    build_knowledge_semantic_route_prompt,
+    build_knowledge_evolve_prompt,
+    build_knowledge_slim_prompt,
+)
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
@@ -332,15 +340,11 @@ async def _route_knowledge_by_llm(query_text: str, metadata_list: List[Dict], k:
         } for m in metadata_list
         } for m in metadata_list
     ]
     ]
 
 
-    prompt = f"""
-你是一个知识检索专家。根据用户的当前任务需求,从下列原子知识元数据中挑选出最相关的最多 {routing_k} 个知识 ID。
-任务需求:"{query_text}"
-
-可选知识列表:
-{json.dumps(routing_data, ensure_ascii=False, indent=1)}
-
-请直接输出 ID 列表,用逗号分隔(例如: knowledge-20260302-001, research-20260302-002)。若无相关项请输出 "None"。
-"""
+    prompt = build_knowledge_semantic_route_prompt(
+        query_text=query_text,
+        routing_data=json.dumps(routing_data, ensure_ascii=False, indent=1),
+        routing_k=routing_k
+    )
 
 
     try:
     try:
         print(f"\n[Step 1: 知识语义路由] 任务: '{query_text}' | 候选总数: {len(metadata_list)} | 目标提取数: {routing_k}")
         print(f"\n[Step 1: 知识语义路由] 任务: '{query_text}' | 候选总数: {len(metadata_list)} | 目标提取数: {routing_k}")
@@ -364,20 +368,7 @@ async def _evolve_knowledge_with_llm(old_content: str, feedback: str) -> str:
     """
     """
     使用 LLM 进行知识进化重写(类似经验进化机制)
     使用 LLM 进行知识进化重写(类似经验进化机制)
     """
     """
-    prompt = f"""你是一个 AI Agent 知识库管理员。请根据反馈建议,对现有的知识内容进行重写进化。
-
-【原知识内容】:
-{old_content}
-
-【实战反馈建议】:
-{feedback}
-
-【重写要求】:
-1. 融合知识:将反馈中的避坑指南、新参数或修正后的选择逻辑融入原知识,使其更具通用性和准确性。
-2. 保持结构:如果原内容有特定格式(如 Markdown、代码示例等),请保持该格式。
-3. 语言:简洁直接,使用中文。
-4. 禁止:严禁输出任何开场白、解释语或额外的 Markdown 标题,直接返回重写后的正文。
-"""
+    prompt = build_knowledge_evolve_prompt(old_content, feedback)
     try:
     try:
         response = await openrouter_llm_call(
         response = await openrouter_llm_call(
             messages=[{"role": "user", "content": prompt}],
             messages=[{"role": "user", "content": prompt}],
@@ -417,15 +408,11 @@ async def _route_knowledge_by_llm(query_text: str, metadata_list: List[Dict], k:
         } for m in metadata_list
         } for m in metadata_list
     ]
     ]
 
 
-    prompt = f"""
-你是一个知识检索专家。根据用户的当前任务需求,从下列原子知识元数据中挑选出最相关的最多 {routing_k} 个知识 ID。
-任务需求:"{query_text}"
-
-可选知识列表:
-{json.dumps(routing_data, ensure_ascii=False, indent=1)}
-
-请直接输出 ID 列表,用逗号分隔(例如: knowledge-20260302-001, research-20260302-002)。若无相关项请输出 "None"。
-"""
+    prompt = build_knowledge_semantic_route_prompt(
+        query_text=query_text,
+        routing_data=json.dumps(routing_data, ensure_ascii=False, indent=1),
+        routing_k=routing_k
+    )
 
 
     try:
     try:
         print(f"\n[Step 1: 知识语义路由] 任务: '{query_text}' | 候选总数: {len(metadata_list)} | 目标提取数: {routing_k}")
         print(f"\n[Step 1: 知识语义路由] 任务: '{query_text}' | 候选总数: {len(metadata_list)} | 目标提取数: {routing_k}")
@@ -1038,31 +1025,7 @@ async def slim_knowledge(
             entries_text += f"Scenario: {data.get('scenario', 'N/A')}\n"
             entries_text += f"Scenario: {data.get('scenario', 'N/A')}\n"
             entries_text += f"Content: {data.get('content', '')[:200]}...\n\n"
             entries_text += f"Content: {data.get('content', '')[:200]}...\n\n"
 
 
-        prompt = f"""你是一个 AI Agent 知识库管理员。以下是当前知识库的全部条目,请执行瘦身操作:
-
-【任务】:
-1. 识别语义高度相似或重复的知识,将它们合并为一条更精炼、更通用的知识。
-2. 合并时保留 helpful 最高的那条的 ID 和 metrics(metrics 中 helpful/harmful 取各条之和)。
-3. 对于独立的、无重复的知识,保持原样不动。
-4. 保持原有的知识结构和格式。
-
-【当前知识库】:
-{entries_text}
-
-【输出格式要求】:
-严格按以下格式输出每条知识,条目之间用 === 分隔:
-ID: <保留的id>
-TAGS: <yaml格式的tags>
-METRICS: <yaml格式的metrics>
-SCORE: <评分>
-SCENARIO: <场景描述>
-CONTENT: <合并后的知识内容>
-===
-
-最后一行输出合并报告,格式:
-REPORT: 原有 X 条,合并后 Y 条,精简了 Z 条。
-
-禁止输出任何开场白或解释。"""
+        prompt = build_knowledge_slim_prompt(entries_text)
 
 
         print(f"\n[知识瘦身] 正在调用 {model} 分析 {len(parsed)} 条知识...")
         print(f"\n[知识瘦身] 正在调用 {model} 分析 {len(parsed)} 条知识...")
         response = await openrouter_llm_call(
         response = await openrouter_llm_call(

+ 23 - 35
agent/tools/builtin/subagent.py

@@ -14,6 +14,19 @@ from agent.trace.models import Trace, Messages
 from agent.trace.trace_id import generate_sub_trace_id
 from agent.trace.trace_id import generate_sub_trace_id
 from agent.trace.goal_models import GoalTree
 from agent.trace.goal_models import GoalTree
 from agent.trace.websocket import broadcast_sub_trace_started, broadcast_sub_trace_completed
 from agent.trace.websocket import broadcast_sub_trace_started, broadcast_sub_trace_completed
+from agent.core.prompts import (
+    EVALUATE_PROMPT_TEMPLATE,
+    DELEGATE_RESULT_HEADER,
+    DELEGATE_SAVED_KNOWLEDGE_HEADER,
+    DELEGATE_STATS_HEADER,
+    EXPLORE_RESULT_HEADER,
+    EXPLORE_BRANCH_TEMPLATE,
+    EXPLORE_STATUS_SUCCESS,
+    EXPLORE_STATUS_FAILED,
+    EXPLORE_STATUS_ERROR,
+    EXPLORE_SUMMARY_HEADER,
+    build_evaluate_prompt,
+)
 
 
 
 
 def _make_run_config(**kwargs):
 def _make_run_config(**kwargs):
@@ -128,7 +141,7 @@ def _get_allowed_tools(single: bool, context: dict) -> Optional[List[str]]:
 
 
 def _format_single_result(result: Dict[str, Any], sub_trace_id: str, continued: bool) -> Dict[str, Any]:
 def _format_single_result(result: Dict[str, Any], sub_trace_id: str, continued: bool) -> Dict[str, Any]:
     """格式化单任务(delegate)结果"""
     """格式化单任务(delegate)结果"""
-    lines = ["## 委托任务完成\n"]
+    lines = [DELEGATE_RESULT_HEADER]
     summary = result.get("summary", "")
     summary = result.get("summary", "")
     if summary:
     if summary:
         lines.append(summary)
         lines.append(summary)
@@ -138,13 +151,13 @@ def _format_single_result(result: Dict[str, Any], sub_trace_id: str, continued:
     saved_knowledge_ids = result.get("saved_knowledge_ids", [])
     saved_knowledge_ids = result.get("saved_knowledge_ids", [])
     if saved_knowledge_ids:
     if saved_knowledge_ids:
         lines.append("---\n")
         lines.append("---\n")
-        lines.append(f"**保存的知识** ({len(saved_knowledge_ids)} 条):")
+        lines.append(DELEGATE_SAVED_KNOWLEDGE_HEADER.format(count=len(saved_knowledge_ids)))
         for kid in saved_knowledge_ids:
         for kid in saved_knowledge_ids:
             lines.append(f"- {kid}")
             lines.append(f"- {kid}")
         lines.append("")
         lines.append("")
 
 
     lines.append("---\n")
     lines.append("---\n")
-    lines.append("**执行统计**:")
+    lines.append(DELEGATE_STATS_HEADER)
     stats = result.get("stats", {})
     stats = result.get("stats", {})
     if stats:
     if stats:
         lines.append(f"- 消息数: {stats.get('total_messages', 0)}")
         lines.append(f"- 消息数: {stats.get('total_messages', 0)}")
@@ -166,7 +179,7 @@ def _format_multi_result(
     tasks: List[str], results: List[Dict[str, Any]], sub_trace_ids: List[Dict]
     tasks: List[str], results: List[Dict[str, Any]], sub_trace_ids: List[Dict]
 ) -> Dict[str, Any]:
 ) -> Dict[str, Any]:
     """格式化多任务(explore)聚合结果"""
     """格式化多任务(explore)聚合结果"""
-    lines = ["## 探索结果\n"]
+    lines = [EXPLORE_RESULT_HEADER]
     successful = 0
     successful = 0
     failed = 0
     failed = 0
     total_tokens = 0
     total_tokens = 0
@@ -174,15 +187,15 @@ def _format_multi_result(
 
 
     for i, (task_item, result) in enumerate(zip(tasks, results)):
     for i, (task_item, result) in enumerate(zip(tasks, results)):
         branch_name = chr(ord('A') + i)
         branch_name = chr(ord('A') + i)
-        lines.append(f"### 方案 {branch_name}: {task_item}")
+        lines.append(EXPLORE_BRANCH_TEMPLATE.format(branch_name=branch_name, task=task_item))
 
 
         if isinstance(result, dict):
         if isinstance(result, dict):
             status = result.get("status", "unknown")
             status = result.get("status", "unknown")
             if status == "completed":
             if status == "completed":
-                lines.append("**状态**: ✓ 完成")
+                lines.append(EXPLORE_STATUS_SUCCESS)
                 successful += 1
                 successful += 1
             else:
             else:
-                lines.append("**状态**: ✗ 失败")
+                lines.append(EXPLORE_STATUS_FAILED)
                 failed += 1
                 failed += 1
 
 
             summary = result.get("summary", "")
             summary = result.get("summary", "")
@@ -198,13 +211,13 @@ def _format_multi_result(
                 total_tokens += tokens
                 total_tokens += tokens
                 total_cost += cost
                 total_cost += cost
         else:
         else:
-            lines.append("**状态**: ✗ 异常")
+            lines.append(EXPLORE_STATUS_ERROR)
             failed += 1
             failed += 1
 
 
         lines.append("")
         lines.append("")
 
 
     lines.append("---\n")
     lines.append("---\n")
-    lines.append("## 总结")
+    lines.append(EXPLORE_SUMMARY_HEADER)
     lines.append(f"- 总分支数: {len(tasks)}")
     lines.append(f"- 总分支数: {len(tasks)}")
     lines.append(f"- 成功: {successful}")
     lines.append(f"- 成功: {successful}")
     lines.append(f"- 失败: {failed}")
     lines.append(f"- 失败: {failed}")
@@ -259,32 +272,7 @@ def _build_evaluate_prompt(goal_description: str, messages: Optional[Messages])
                         parts.append(item.get("text", ""))
                         parts.append(item.get("text", ""))
         result_text = "\n".join(parts)
         result_text = "\n".join(parts)
 
 
-    lines = [
-        "# 评估任务",
-        "",
-        "请评估以下任务的执行结果是否满足要求。",
-        "",
-        "## 目标描述",
-        "",
-        goal_description,
-        "",
-        "## 执行结果",
-        "",
-        result_text or "(无执行结果)",
-        "",
-        "## 输出格式",
-        "",
-        "## 评估结论",
-        "[通过/不通过]",
-        "",
-        "## 评估理由",
-        "[详细说明通过或不通过原因]",
-        "",
-        "## 修改建议(如果不通过)",
-        "1. [建议1]",
-        "2. [建议2]",
-    ]
-    return "\n".join(lines)
+    return build_evaluate_prompt(goal_description, result_text)
 
 
 
 
 def _make_event_printer(label: str):
 def _make_event_printer(label: str):

+ 9 - 48
agent/trace/compaction.py

@@ -18,6 +18,11 @@ from typing import List, Dict, Any, Optional, Set
 
 
 from .goal_models import GoalTree
 from .goal_models import GoalTree
 from .models import Message
 from .models import Message
+from agent.core.prompts import (
+    COMPRESSION_EVAL_PROMPT_TEMPLATE,
+    REFLECT_PROMPT,
+    build_compression_eval_prompt,
+)
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
@@ -297,53 +302,8 @@ def needs_level2_compression(
 
 
 
 
 # ===== Level 2: 压缩 Prompt =====
 # ===== Level 2: 压缩 Prompt =====
-
-COMPRESSION_EVAL_PROMPT = """请对以上对话历史进行压缩总结,并评价所引用的历史知识/经验。
-### 任务 1:评价已用知识
-本次任务参考了以下知识内容:{ex_reference_list}
-
-请对比”知识建议”与”实际执行轨迹”,给出三色打分:
-[[EVALUATION]]
-ID: knowledge-xxx 或 research-xxx | Result: helpful/harmful/mixed | Reason: [优点]... [局限/修正]...
-
-### 任务 2:对话历史摘要
-要求:
-1. 保留关键决策、结论和产出(如创建的文件、修改的代码、得出的分析结论)
-2. 保留重要的上下文(如用户的要求、约束条件、之前的讨论结果)
-3. 省略中间探索过程、重复的工具调用细节
-4. 使用结构化格式(标题 + 要点 + 相关资源引用,若有)
-5. 控制在 2000 字以内
-格式要求:
-[[SUMMARY]]
-(此处填写结构化的摘要内容)
-
-当前 GoalTree 状态:
-{goal_tree_prompt}
-"""
-
-REFLECT_PROMPT = """请回顾以上整个执行过程,提取有价值的经验教训。
-你必须将经验与当前的任务意图(Intent)和环境状态(State)挂钩,以便未来精准检索。
-关注以下方面:
-1. 人工干预:用户中途的指令是否说明了原来的执行过程哪里有问题
-2. 弯路:哪些尝试是不必要的,有没有更直接的方法
-3. 好的决策:哪些判断和选择是正确的,值得记住
-4. 工具使用:哪些工具用法是高效的,哪些可以改进
-
-输出格式(严格遵守):
-- 在每条经验前加一个[]中添加自定义的标签,标签要求总结实际的内容为若干词语,包括:
-    - intent: 当前的goal
-    - state: 环境状态(如果与工具相关,可以在标签中加入工具的名称)
-- 经验标签可用自然语言描述
-- 每条经验单独成段,格式固定为:- 当 [条件] 时,应该 [动作](原因:[一句话说明])。具体案例:[案例]
-- 条目之间用一个空行分隔
-- 不输出任何标题、分类、编号、分隔线或其他结构
-- 不使用 markdown 加粗、表格、代码块等格式
-- 每条经验自包含,读者无需上下文即可理解
-- 只提取最有价值的 5-10 条,宁少勿滥
-
-示例(仅供参考格式,不要复制内容):
-- [intent:示例生成 state:用户提醒,指定样本] 当用户说"给我示例"时,应该用真实数据而不是编造(原因:编造的示例无法验证质量)。具体案例:training_samples.json 中的示例全是 LLM 自己编造的,用户明确要求"基于我指定的样本"。
-"""
+# 注意:这些 prompt 已迁移到 agent.core.prompts
+# COMPRESSION_EVAL_PROMPT 和 REFLECT_PROMPT 现在从 prompts.py 导入
 
 
 
 
 def build_compression_prompt(goal_tree: Optional[GoalTree], used_ex_ids: Optional[List[str]] = None) -> str:
 def build_compression_prompt(goal_tree: Optional[GoalTree], used_ex_ids: Optional[List[str]] = None) -> str:
@@ -356,7 +316,7 @@ def build_compression_prompt(goal_tree: Optional[GoalTree], used_ex_ids: Optiona
     if used_ex_ids:
     if used_ex_ids:
         ex_reference = ", ".join(used_ex_ids)
         ex_reference = ", ".join(used_ex_ids)
 
 
-    return COMPRESSION_EVAL_PROMPT.format(
+    return build_compression_eval_prompt(
         goal_tree_prompt=goal_prompt,
         goal_tree_prompt=goal_prompt,
         ex_reference_list=ex_reference,
         ex_reference_list=ex_reference,
     )
     )
@@ -365,3 +325,4 @@ def build_compression_prompt(goal_tree: Optional[GoalTree], used_ex_ids: Optiona
 def build_reflect_prompt() -> str:
 def build_reflect_prompt() -> str:
     """构建反思 prompt"""
     """构建反思 prompt"""
     return REFLECT_PROMPT
     return REFLECT_PROMPT
+