Refine OpenClaw payloads and reorganize docs
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
# Summary Loop 工作说明
|
||||
|
||||
## 1. 目的
|
||||
|
||||
本文档说明 `scripts/run_summary_loop.py` 如何把以下流程串成一个最小闭环:
|
||||
|
||||
`提取 JSON -> LLM 生成摘要 JSON -> validator 校验 -> 失败则修复重试`
|
||||
|
||||
这个脚本的目标不是单次调用 LLM,而是让 LLM 输出进入一个“生成后验收”的自动反馈回路。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心思路
|
||||
|
||||
这个闭环由三部分组成:
|
||||
|
||||
- 提取结果
|
||||
- 来自 `outputs/reference/extracted/*.json` 或 `outputs/freshrss/extracted/*.json`
|
||||
- 提供标题、链接、正文、质量标记
|
||||
|
||||
- LLM 摘要
|
||||
- 基于提取结果和 prompt 生成 `result.json`
|
||||
|
||||
- validator
|
||||
- 检查 `result.json` 是否符合结构和业务规则
|
||||
- 不通过则返回错误列表
|
||||
|
||||
因此,LLM 不是“自己知道哪里错了”,而是脚本在每轮生成后用 validator 明确指出错误,再要求它修复。
|
||||
|
||||
---
|
||||
|
||||
## 3. 运行顺序
|
||||
|
||||
脚本入口:
|
||||
|
||||
- `scripts/run_summary_loop.py`
|
||||
|
||||
执行顺序如下:
|
||||
|
||||
1. 读取提取结果 JSON
|
||||
2. 读取摘要 prompt 模板
|
||||
3. 从提取结果中裁剪出摘要真正需要的输入字段
|
||||
4. 调用 LLM 生成摘要 JSON
|
||||
5. 解析模型输出中的 JSON
|
||||
6. 将结果写入输出文件
|
||||
7. 调用 validator 校验结果
|
||||
8. 如果通过,结束
|
||||
9. 如果失败,构造修复 prompt,再次调用 LLM
|
||||
|
||||
---
|
||||
|
||||
## 4. 输入来源
|
||||
|
||||
脚本主要使用两个输入文件:
|
||||
|
||||
- 提取结果:`outputs/reference/extracted/read-flow-2026.extracted.json`
|
||||
- 摘要 prompt:`outputs/prompts/llm-summary-prompt.txt`
|
||||
|
||||
提取结果不会整包无差别塞给 LLM,而是先裁剪成更小的摘要输入:
|
||||
|
||||
- `article.title`
|
||||
- `article.url`
|
||||
- `article.plain_text`
|
||||
- `article.quality_flags`
|
||||
- `warnings`
|
||||
|
||||
这样做是为了减少 payload,降低模型超时概率,也让 prompt 更聚焦。
|
||||
|
||||
---
|
||||
|
||||
## 5. 首次生成
|
||||
|
||||
第一次生成时,脚本会把:
|
||||
|
||||
- prompt 模板
|
||||
- 结构化文章输入
|
||||
|
||||
拼成一个完整请求,发给 LLM。
|
||||
|
||||
对应函数:
|
||||
|
||||
- `build_initial_prompt(...)`
|
||||
- `call_llm(...)`
|
||||
|
||||
模型返回后,脚本会尝试提取一个 JSON 对象。
|
||||
|
||||
如果模型输出不是合法 JSON:
|
||||
|
||||
- 这一轮直接视为失败
|
||||
- 会生成一份失败校验结果
|
||||
- 然后进入修复重试
|
||||
|
||||
---
|
||||
|
||||
## 6. validator 如何加入流程
|
||||
|
||||
validator 不是附加步骤,而是主流程里的硬门槛。
|
||||
|
||||
对应函数:
|
||||
|
||||
- `validate_llm_result(...)`
|
||||
|
||||
校验内容包括两层:
|
||||
|
||||
### 6.1 结构校验
|
||||
|
||||
- 必填字段是否存在
|
||||
- 字段类型是否正确
|
||||
- `category` 是否属于允许枚举
|
||||
- `summary` 长度是否合规
|
||||
- `highlights` / `keywords` / `topics` 数量是否合规
|
||||
|
||||
### 6.2 业务校验
|
||||
|
||||
- `keywords` 和 `topics` 不能重复
|
||||
- 列表内部不能重复
|
||||
- `title` 和 `url` 必须与提取结果一致
|
||||
|
||||
只有 validator 返回 `valid: true`,这一轮结果才会被接受。
|
||||
|
||||
---
|
||||
|
||||
## 7. LLM 如何知道自己生成错了
|
||||
|
||||
LLM 本身不会主动知道哪些字段不合规。
|
||||
|
||||
脚本会在校验失败后,把以下信息重新发给 LLM:
|
||||
|
||||
- validator 错误列表
|
||||
- 原始提取结果
|
||||
- 当前错误的摘要 JSON
|
||||
|
||||
然后要求它:
|
||||
|
||||
- 只修复错误字段
|
||||
- 保留已经正确的字段
|
||||
- 继续只输出合法 JSON
|
||||
|
||||
对应函数:
|
||||
|
||||
- `build_repair_prompt(...)`
|
||||
|
||||
也就是说:
|
||||
|
||||
- prompt 负责提出目标
|
||||
- validator 负责判错
|
||||
- repair prompt 负责把错误喂回模型
|
||||
|
||||
这三者一起形成自动修复回路。
|
||||
|
||||
---
|
||||
|
||||
## 8. 时序图
|
||||
|
||||
```text
|
||||
Extracted JSON
|
||||
|
|
||||
v
|
||||
run_summary_loop.py
|
||||
|
|
||||
|-- 读取 prompt 模板
|
||||
|-- 构造摘要输入
|
||||
|
|
||||
v
|
||||
LLM
|
||||
|
|
||||
v
|
||||
摘要 JSON
|
||||
|
|
||||
v
|
||||
validator
|
||||
|
|
||||
|-- valid = true ------> 结束
|
||||
|
|
||||
|-- valid = false
|
||||
| |
|
||||
| |-- errors
|
||||
| v
|
||||
| repair prompt
|
||||
| |
|
||||
+------> LLM 重试
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 生成的中间文件
|
||||
|
||||
每次执行脚本都会在输出目录下留下调试痕迹:
|
||||
|
||||
- `outputs/reference/summary/result.loop.attempt-1.raw.txt`
|
||||
- 模型原始输出
|
||||
|
||||
- `outputs/reference/summary/result.loop.attempt-1.json`
|
||||
- 提取出的 JSON 结果
|
||||
|
||||
- `outputs/reference/summary/result.loop.attempt-1.validation.json`
|
||||
- 这一轮的校验报告
|
||||
|
||||
- `outputs/reference/summary/result.loop.json`
|
||||
- 当前最终结果
|
||||
|
||||
这些文件的价值是:
|
||||
|
||||
- 可以回看模型原始输出
|
||||
- 可以定位是 JSON 解析失败还是 schema 校验失败
|
||||
- 可以看每轮修复到底修了什么
|
||||
|
||||
---
|
||||
|
||||
## 10. 当前脚本参数
|
||||
|
||||
当前脚本支持:
|
||||
|
||||
- `--extracted`
|
||||
- `--prompt`
|
||||
- `--output`
|
||||
- `--max-retries`
|
||||
- `--timeout`
|
||||
- `--api-key`
|
||||
- `--model`
|
||||
- `--api-url`
|
||||
|
||||
这意味着它既可以走环境变量,也可以直接用命令行传入模型配置。
|
||||
|
||||
---
|
||||
|
||||
## 11. 一句话结论
|
||||
|
||||
`run_summary_loop.py` 的本质不是“调一次 LLM”,而是“让 LLM 生成结果后必须经过 validator 验收,失败就拿着错误清单继续修”,直到结果通过或达到重试上限。
|
||||
Reference in New Issue
Block a user