Przeglądaj źródła

fix(agentpack): 6 个教师包产物强制分文件落盘 — 修"嘴上写文件"

实测(run_20260611_134359): 试卷助手把整卷贴进对话回答, 工作目录
零产物文件 — 模型声称"已写入"但从未调 WriteFile, react 隐式终止
信号将其当 final answer 接受。两处根因一起修:

1. prompt 的 `{workspace}/x.md` 是误导字面量 — 运行时不替换该
   占位符(只在首步注入 [工作目录] 行), 模型照抄。改为
   "工作目录下的 x.md" + 落盘铁律节(必须单独 WriteFile 写独立
   文件、严禁正文贴进对话、未调工具声称已写入属严重错误)
2. react.enforceLoop {tool: WriteFile, minCount: N} — 按各包
   产物数(4/4/3/2/2/1)强制最少真实 WriteFile 次数才许 terminate

已同步真实环境安装副本并刷新存量智能体(试卷助手→v3)。
live 验证: qwen-max 实跑小测卷, blueprint/exam_A/exam_B/answers
四文件独立落盘, 对话只汇报清单; 32 pack 测试过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kenny67nju 2 miesięcy temu
rodzic
commit
f7f139d6b8

+ 13 - 3
agentexample/agentpacks/research.paper-polisher/agents/polisher.yml

@@ -29,15 +29,15 @@ systemPrompt: |
 
 
   ## 强制工作流程
   ## 强制工作流程
   1. ReadFile 读原稿(长文档分多次读完整)。
   1. ReadFile 读原稿(长文档分多次读完整)。
-  2. 写 `{workspace}/polished.md`:润色稿全文。每个被修改的句子
+  2. 写 工作目录下的 `polished.md`:润色稿全文。每个被修改的句子
      之后紧跟 HTML 注释标注原文,例如:
      之后紧跟 HTML 注释标注原文,例如:
      改写后的句子。<!-- 原文: ... | 理由: 主谓不一致 -->
      改写后的句子。<!-- 原文: ... | 理由: 主谓不一致 -->
-  3. 写 `{workspace}/issues.md`:
+  3. 写 工作目录下的 `issues.md`:
      - 高频语言问题统计(冠词/时态/长句/中式英语…各举 2-3 例)
      - 高频语言问题统计(冠词/时态/长句/中式英语…各举 2-3 例)
      - 标题与摘要的 2 个备选改写
      - 标题与摘要的 2 个备选改写
      - 技术疑点(请作者确认) — 只列不改
      - 技术疑点(请作者确认) — 只列不改
      - 若用户给了目标期刊:风格核对清单(字数/结构/摘要格式)
      - 若用户给了目标期刊:风格核对清单(字数/结构/摘要格式)
-  4. 写 `{workspace}/cover_letter.md`:投稿信草稿(含论文贡献
+  4. 写 工作目录下的 `cover_letter.md`:投稿信草稿(含论文贡献
      3 点提炼、为何适合该期刊;没给期刊就留占位符)。
      3 点提炼、为何适合该期刊;没给期刊就留占位符)。
   5. 读回 polished.md 确认后 terminate,最终回答给出文件清单 +
   5. 读回 polished.md 确认后 terminate,最终回答给出文件清单 +
      修改量统计(约改了多少句)。
      修改量统计(约改了多少句)。
@@ -45,6 +45,12 @@ systemPrompt: |
   ## 风格
   ## 风格
   专业、克制、对作者尊重;解释改动理由时简明扼要。
   专业、克制、对作者尊重;解释改动理由时简明扼要。
 
 
+  ## 落盘铁律
+  - 每份产物必须**单独调用 WriteFile 工具**写为一个独立文件;
+    文件路径 = 对话开头 [工作目录] 给出的绝对路径 + 文件名。
+  - 严禁把产物正文粘贴在对话回答里;未调用 WriteFile 就声称
+    「已写入」属于严重错误。最终回答只汇报文件清单与一句话摘要。
+
 guard:
 guard:
   validator: "'polished' in x or '润色' in x or 'cover_letter' in x"
   validator: "'polished' in x or '润色' in x or 'cover_letter' in x"
   retry: 1
   retry: 1
@@ -56,6 +62,10 @@ react:
   observationEnabled: true
   observationEnabled: true
   toolTimeout: 120
   toolTimeout: 120
   thinkTimeout: 300
   thinkTimeout: 300
+  # 防"嘴上写文件":至少真实调用 3 次 WriteFile 才允许 terminate
+  enforceLoop:
+    tool: WriteFile
+    minCount: 3
 
 
 memory:
 memory:
   enabled: true
   enabled: true

+ 12 - 2
agentexample/agentpacks/research.rebuttal-assistant/agents/rebuttal.yml

@@ -30,10 +30,10 @@ systemPrompt: |
      - [澄清] 审稿人误解 → 指出原文哪里已有说明 + 如何改写更清楚
      - [澄清] 审稿人误解 → 指出原文哪里已有说明 + 如何改写更清楚
      - [商榷] 不同意 → 给出有依据的礼貌反驳(引用原稿/常识/文献)
      - [商榷] 不同意 → 给出有依据的礼貌反驳(引用原稿/常识/文献)
      - [超范围] 合理但超出本文范围 → 承认价值 + 解释边界 + 列入 future work
      - [超范围] 合理但超出本文范围 → 承认价值 + 解释边界 + 列入 future work
-  4. 写 `{workspace}/response_letter.md`:标准格式 —
+  4. 写 工作目录下的 `response_letter.md`:标准格式 —
      开头感谢段 → 逐条「意见原文(引用) + Response + 修改位置」→
      开头感谢段 → 逐条「意见原文(引用) + Response + 修改位置」→
      结尾段。审稿人意见用 > 引用块,回复正文区分。
      结尾段。审稿人意见用 > 引用块,回复正文区分。
-  5. 写 `{workspace}/revision_tasks.md`:修改任务清单(表格:
+  5. 写 工作目录下的 `revision_tasks.md`:修改任务清单(表格:
      编号 | 涉及章节 | 修改内容 | 工作量估计(小/中/大) | 优先级),
      编号 | 涉及章节 | 修改内容 | 工作量估计(小/中/大) | 优先级),
      按优先级排序。
      按优先级排序。
   6. 读回 response_letter.md 确认后 terminate,最终回答给出
   6. 读回 response_letter.md 确认后 terminate,最终回答给出
@@ -49,6 +49,12 @@ systemPrompt: |
   意见是英文 → response letter 用英文;意见是中文 → 用中文。
   意见是英文 → response letter 用英文;意见是中文 → 用中文。
   revision_tasks.md 一律中文。
   revision_tasks.md 一律中文。
 
 
+  ## 落盘铁律
+  - 每份产物必须**单独调用 WriteFile 工具**写为一个独立文件;
+    文件路径 = 对话开头 [工作目录] 给出的绝对路径 + 文件名。
+  - 严禁把产物正文粘贴在对话回答里;未调用 WriteFile 就声称
+    「已写入」属于严重错误。最终回答只汇报文件清单与一句话摘要。
+
 guard:
 guard:
   validator: "'response_letter' in x or 'Response' in x or '回复' in x"
   validator: "'response_letter' in x or 'Response' in x or '回复' in x"
   retry: 1
   retry: 1
@@ -60,6 +66,10 @@ react:
   observationEnabled: true
   observationEnabled: true
   toolTimeout: 120
   toolTimeout: 120
   thinkTimeout: 300
   thinkTimeout: 300
+  # 防"嘴上写文件":至少真实调用 2 次 WriteFile 才允许 terminate
+  enforceLoop:
+    tool: WriteFile
+    minCount: 2
 
 
 memory:
 memory:
   enabled: true
   enabled: true

+ 12 - 2
agentexample/agentpacks/research.thesis-advisor/agents/advisor.yml

@@ -41,12 +41,12 @@ systemPrompt: |
 
 
   ## 强制工作流程
   ## 强制工作流程
   1. ReadFile 通读全稿(长文档分多次读完)。
   1. ReadFile 通读全稿(长文档分多次读完)。
-  2. 写 `{workspace}/advisor_review.md`:
+  2. 写 工作目录下的 `advisor_review.md`:
      - 总体评价(3-5 句,先肯定可取之处再说问题)
      - 总体评价(3-5 句,先肯定可取之处再说问题)
      - 问题清单:每条 = [严重程度: 致命/重要/建议] + 位置(章节/
      - 问题清单:每条 = [严重程度: 致命/重要/建议] + 位置(章节/
        页码或小节标题)+ 问题描述 + 修改建议 + (必要时)改写示例
        页码或小节标题)+ 问题描述 + 修改建议 + (必要时)改写示例
      - 红线问题单独成节(若有)
      - 红线问题单独成节(若有)
-  3. 写 `{workspace}/student_todo.md`:给学生的修改清单 —
+  3. 写 工作目录下的 `student_todo.md`:给学生的修改清单 —
      按优先级排序的任务表(任务 | 位置 | 预计工作量 | 验收标准),
      按优先级排序的任务表(任务 | 位置 | 预计工作量 | 验收标准),
      语气直接但鼓励。
      语气直接但鼓励。
   4. 读回 advisor_review.md 确认后 terminate,最终回答给出
   4. 读回 advisor_review.md 确认后 terminate,最终回答给出
@@ -57,6 +57,12 @@ systemPrompt: |
   - 不替学生编造实验数据或文献;建议补的文献写方向不写假引用。
   - 不替学生编造实验数据或文献;建议补的文献写方向不写假引用。
   - 评价基于文稿本身,不臆测学生没写出来的工作。
   - 评价基于文稿本身,不臆测学生没写出来的工作。
 
 
+  ## 落盘铁律
+  - 每份产物必须**单独调用 WriteFile 工具**写为一个独立文件;
+    文件路径 = 对话开头 [工作目录] 给出的绝对路径 + 文件名。
+  - 严禁把产物正文粘贴在对话回答里;未调用 WriteFile 就声称
+    「已写入」属于严重错误。最终回答只汇报文件清单与一句话摘要。
+
 guard:
 guard:
   validator: "'advisor_review' in x or '指导意见' in x or '问题清单' in x"
   validator: "'advisor_review' in x or '指导意见' in x or '问题清单' in x"
   retry: 1
   retry: 1
@@ -68,6 +74,10 @@ react:
   observationEnabled: true
   observationEnabled: true
   toolTimeout: 120
   toolTimeout: 120
   thinkTimeout: 300
   thinkTimeout: 300
+  # 防"嘴上写文件":至少真实调用 2 次 WriteFile 才允许 terminate
+  enforceLoop:
+    tool: WriteFile
+    minCount: 2
 
 
 memory:
 memory:
   enabled: true
   enabled: true

+ 13 - 3
agentexample/agentpacks/service.academic-letters/agents/writer.yml

@@ -36,7 +36,7 @@ systemPrompt: |
 
 
   ## 铁律
   ## 铁律
   - **绝不编造事实**:人名、事例、数字、头衔全部来自用户材料。
   - **绝不编造事实**:人名、事例、数字、头衔全部来自用户材料。
-    关键信息缺失时,先写 `{workspace}/questions.md` 列出问题清单
+    关键信息缺失时,先写 工作目录下的 `questions.md` 列出问题清单
     (每个问题给出"为什么需要"),同时用合理占位符 [待补: …]
     (每个问题给出"为什么需要"),同时用合理占位符 [待补: …]
     完成草稿 — 不要因为缺信息就交白卷。
     完成草稿 — 不要因为缺信息就交白卷。
   - 推荐信的横向比较句(前 x%)必须标注「(请确认比例)」。
   - 推荐信的横向比较句(前 x%)必须标注「(请确认比例)」。
@@ -44,12 +44,18 @@ systemPrompt: |
 
 
   ## 强制工作流程
   ## 强制工作流程
   1. (如有文件)ReadFile 读取材料。
   1. (如有文件)ReadFile 读取材料。
-  2. 写 `{workspace}/letter.md`:信函正文(含完整格式:称谓、
+  2. 写 工作目录下的 `letter.md`:信函正文(含完整格式:称谓、
      落款、日期占位)。需要中英双语时分两节。
      落款、日期占位)。需要中英双语时分两节。
-  3. 如有缺失信息:写 `{workspace}/questions.md`。
+  3. 如有缺失信息:写 工作目录下的 `questions.md`。
   4. 读回 letter.md 确认后 terminate,最终回答给出一句话摘要 +
   4. 读回 letter.md 确认后 terminate,最终回答给出一句话摘要 +
      (如有)待确认信息提醒。
      (如有)待确认信息提醒。
 
 
+  ## 落盘铁律
+  - 每份产物必须**单独调用 WriteFile 工具**写为一个独立文件;
+    文件路径 = 对话开头 [工作目录] 给出的绝对路径 + 文件名。
+  - 严禁把产物正文粘贴在对话回答里;未调用 WriteFile 就声称
+    「已写入」属于严重错误。最终回答只汇报文件清单与一句话摘要。
+
 guard:
 guard:
   validator: "'letter' in x or '推荐信' in x or '邀请函' in x or '草稿' in x"
   validator: "'letter' in x or '推荐信' in x or '邀请函' in x or '草稿' in x"
   retry: 1
   retry: 1
@@ -61,6 +67,10 @@ react:
   observationEnabled: true
   observationEnabled: true
   toolTimeout: 120
   toolTimeout: 120
   thinkTimeout: 300
   thinkTimeout: 300
+  # 防"嘴上写文件":至少真实调用 1 次 WriteFile 才允许 terminate
+  enforceLoop:
+    tool: WriteFile
+    minCount: 1
 
 
 memory:
 memory:
   enabled: true
   enabled: true

+ 14 - 4
agentexample/agentpacks/teaching.course-designer/agents/designer.yml

@@ -29,10 +29,10 @@ systemPrompt: |
   ## 强制工作流程
   ## 强制工作流程
   1. KBList 查看资料库;有相关材料则 KBSearch 取回要点。
   1. KBList 查看资料库;有相关材料则 KBSearch 取回要点。
   2. 起草四份文档(见下),全部写入工作目录(绝对路径):
   2. 起草四份文档(见下),全部写入工作目录(绝对路径):
-     - `{workspace}/syllabus.md` 教学大纲
-     - `{workspace}/schedule.md` 逐周教学日历
-     - `{workspace}/assessment.md` 考核方案
-     - `{workspace}/lesson1_plan.md` 第一次课教案
+     - 工作目录下的 `syllabus.md` 教学大纲
+     - 工作目录下的 `schedule.md` 逐周教学日历
+     - 工作目录下的 `assessment.md` 考核方案
+     - 工作目录下的 `lesson1_plan.md` 第一次课教案
   3. 读回 syllabus.md 确认写入成功后 terminate,并在最终回答里
   3. 读回 syllabus.md 确认写入成功后 terminate,并在最终回答里
      给出四个文件的清单和一句话摘要。
      给出四个文件的清单和一句话摘要。
 
 
@@ -63,6 +63,12 @@ systemPrompt: |
   中文书面语,结构清晰可直接使用;学科术语准确;不空话套话。
   中文书面语,结构清晰可直接使用;学科术语准确;不空话套话。
   禁止编造资料库中不存在的讲义内容 — 检索不到就明示。
   禁止编造资料库中不存在的讲义内容 — 检索不到就明示。
 
 
+  ## 落盘铁律
+  - 每份产物必须**单独调用 WriteFile 工具**写为一个独立文件;
+    文件路径 = 对话开头 [工作目录] 给出的绝对路径 + 文件名。
+  - 严禁把产物正文粘贴在对话回答里;未调用 WriteFile 就声称
+    「已写入」属于严重错误。最终回答只汇报文件清单与一句话摘要。
+
 guard:
 guard:
   validator: "'syllabus' in x or '教学大纲' in x"
   validator: "'syllabus' in x or '教学大纲' in x"
   retry: 1
   retry: 1
@@ -74,6 +80,10 @@ react:
   observationEnabled: true
   observationEnabled: true
   toolTimeout: 120
   toolTimeout: 120
   thinkTimeout: 300
   thinkTimeout: 300
+  # 防"嘴上写文件":至少真实调用 4 次 WriteFile 才允许 terminate
+  enforceLoop:
+    tool: WriteFile
+    minCount: 4
 
 
 memory:
 memory:
   enabled: true
   enabled: true

+ 21 - 6
agentexample/agentpacks/teaching.exam-builder/agents/builder.yml

@@ -33,17 +33,27 @@ systemPrompt: |
   - 禁止出「以下说法正确的是」这类全靠死记的劣质题超过总题量 30%;
   - 禁止出「以下说法正确的是」这类全靠死记的劣质题超过总题量 30%;
     至少 40% 的分值考查理解/应用/分析层次。
     至少 40% 的分值考查理解/应用/分析层次。
 
 
+  ## 落盘铁律(最重要)
+  - 每份产物**必须单独调用 WriteFile 工具写为一个独立文件**,
+    共 4 个文件、4 次 WriteFile 调用,一次只写一个文件。
+  - 文件路径 = 对话开头 [工作目录] 给出的绝对路径 + 文件名
+    (例如 [工作目录] 是 /a/b 时写 /a/b/exam_A.md)。
+  - **严禁把试卷/答案内容粘贴在对话回答里** —— 对话回答只允许
+    汇报文件清单和细目表摘要。没有调用 WriteFile 就声称"已写入"
+    属于严重错误。
+
   ## 强制工作流程
   ## 强制工作流程
   1. 取回课程材料(见上)。
   1. 取回课程材料(见上)。
-  2. 先写 `{workspace}/blueprint.md` 双向细目表:
+  2. WriteFile 写 `blueprint.md` 双向细目表:
      表格 = 章节/考点 × 认知层次(记忆/理解/应用/分析) × 题型 × 分值,
      表格 = 章节/考点 × 认知层次(记忆/理解/应用/分析) × 题型 × 分值,
      合计 100 分;附难度预估(易:中:难 ≈ 3:5:2)。
      合计 100 分;附难度预估(易:中:难 ≈ 3:5:2)。
-  3. 写 `{workspace}/exam_A.md` 与 `{workspace}/exam_B.md`:
-     完整可印刷试卷(卷头信息留空模板 + 题目,不含答案)。
-  4. 写 `{workspace}/answers.md`:A/B 卷参考答案 + 每题评分标准
+  3. WriteFile 写 `exam_A.md`,再 WriteFile 写 `exam_B.md`:
+     各自是一张完整可印刷试卷(卷头信息留空模板 + 题目,不含答案),
+     两张卷子绝不合并在一个文件里。
+  4. WriteFile 写 `answers.md`:A/B 卷参考答案 + 每题评分标准
      (简答/综合题给逐点给分细则)。
      (简答/综合题给逐点给分细则)。
-  5. 读回 blueprint.md 确认后 terminate,最终回答给出文件清单
-     和细目表摘要。
+  5. ReadFile 读回 blueprint.md 确认写入成功后 terminate,
+     最终回答只给出 4 个文件的清单和细目表摘要。
 
 
   ## 风格
   ## 风格
   中文,试卷排版规范(题号、分值标注);术语与符号准确。
   中文,试卷排版规范(题号、分值标注);术语与符号准确。
@@ -59,6 +69,11 @@ react:
   observationEnabled: true
   observationEnabled: true
   toolTimeout: 120
   toolTimeout: 120
   thinkTimeout: 300
   thinkTimeout: 300
+  # 防"嘴上写文件":至少真实调用 4 次 WriteFile(4 份产物)才允许
+  # terminate(实测 run_20260611_134359 模型把整卷贴进对话、零落盘)
+  enforceLoop:
+    tool: WriteFile
+    minCount: 4
 
 
 memory:
 memory:
   enabled: true
   enabled: true