Co-authored-by: Alice <alice@prismshadow.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
405 lines
16 KiB
Markdown
405 lines
16 KiB
Markdown
---
|
||
title: "在 AMD GPU 上用 PenguinHarness 实现 Agent 自我进化"
|
||
date: 2026-07-22
|
||
category: practice
|
||
author: 高钰洋(AMD)、张宁(AMD)、郑耀威(PrismShadow)
|
||
excerpt: "通过本地 Qwen3:8B 与 Fireworks API 的双模型分工,完整演示 PenguinHarness 从基线评测、Trace 分析到 Agent 优化与回滚的自我进化闭环。"
|
||
description: "介绍 PenguinHarness 如何通过 Benchmark、Trace、可编辑的 Agent State 与 Snapshot 回滚构建自我进化闭环,并用本地 Qwen3:8B 与 Fireworks API 完成一次双模型实验。"
|
||
---
|
||
*AMD × PrismShadow——高钰洋、张宁(AMD),郑耀威(PrismShadow)。*
|
||
|
||
[PenguinHarness](https://github.com/Prism-Shadow/penguin-harness) 是一个开源的 Agent Harness。它把模型接入、Agent 配置、工作区工具、Session、Trace、Skill 和 Benchmark 放在同一套运行环境中,并同时提供 CLI 与 Web UI。在线模型和通过 OpenAI 兼容接口暴露的本地模型,都可以作为其中的推理后端。
|
||
|
||
这个项目比较特别的一点,是它把 Agent 的行为定义为一组可以读取、修改和版本化的状态文件,而不是一段只能由开发者手工维护的固定提示词。角色说明、工作方式、可复用 Skill 和运行参数都属于 Agent State;一次任务又会留下完整的 Session 与 Trace。因此,另一个 Agent 可以先评测目标 Agent,再根据真实运行记录修改它的状态,最后用同一套评测验证修改是否有效。
|
||
|
||
这就是 PenguinHarness 所说的“自我进化”:它不重新训练模型,也不更新模型权重,而是持续改进模型外部的 Agent Harness,并用可重复的结果决定新版本能否被保留。
|
||
|
||
## PenguinHarness 如何实现自我进化
|
||
|
||
一个 Agent 的主要可编辑状态包括:
|
||
|
||
- `AGENTS.md`:角色、边界和工作流程;
|
||
- `skills/`:可复用能力;
|
||
- `system_config.yaml`:版本和运行配置。
|
||
|
||
围绕这些状态,PenguinHarness 把自我进化组织成三个角色:
|
||
|
||
- **Target Agent**:真正执行任务、接受评测和改进的目标 Agent;
|
||
- **Evaluator**:在隔离工作区中运行一个 Benchmark Case,并根据私有 Rubric 评分;
|
||
- **Optimizer**:读取基线分数及其关联 Trace,提出改进假设并修改 Target Agent State。
|
||
|
||
完整闭环如下:
|
||
|
||
1. 为目标能力建立多 Case Benchmark。
|
||
2. 对 Target Agent 重复运行,得到可追溯的基线。
|
||
3. 从分数和对应 Trace 中定位稳定的失败模式。
|
||
4. 保存 Snapshot,并修改 Agent State。
|
||
5. 使用相同 Benchmark 和相同模型重新评测候选版本。
|
||
6. 总分严格提高则保留新版本,否则恢复原状态。
|
||
|
||
这个流程主要由内置 Skill 编排:
|
||
|
||
- `agent-creation`:根据需求创建初始 Agent;
|
||
- `benchmark-design`:设计多 Case Benchmark,并建立完整基线;
|
||
- `agent-evaluation`:隔离执行并评分一次 Case 运行;
|
||
- `agent-optimization`:分析基线和 Trace,修改 Agent State,并完成候选版本评测与回滚。
|
||
|
||
这里的关键不只是“让另一个模型改写提示词”,而是让每次修改都经过同条件复测。Benchmark 提供度量,Trace 提供证据,Snapshot 提供恢复点,版本号则把分数与实际 Agent State 对应起来。优化没有带来严格提升时,候选修改不会被当成进化成果。
|
||
|
||
为了把这套机制完整跑一遍,本文采用双模型分工:AMD GPU 上通过 Ollama 运行的 Qwen3:8B 作为 Target Agent 的模型;通过 Fireworks API 调用的模型则用于运行 `default_agent`,负责创建 Agent、设计 Benchmark 和执行优化。我们先测出 v1 的基线,再让 Optimizer 根据真实 Trace 改进它,最后由同一 Benchmark 决定接受新版本还是回滚。这个例子关注的是自我进化闭环本身,而不是比较模型排行榜上的能力高低。
|
||
|
||
## 本文要完成的实验
|
||
|
||
我们创建一个 `meeting-summary-agent`。它读取少量文本文件,并在工作区中生成:
|
||
|
||
```markdown
|
||
# 摘要
|
||
|
||
## 已确认
|
||
|
||
## 待办
|
||
|
||
## 未确定
|
||
```
|
||
|
||
Benchmark 包含两个 Case:
|
||
|
||
| Case | 任务 |
|
||
|---|---|
|
||
| 单份会议纪要 | 提取已确认事项、两个待办和一个未确定项 |
|
||
| 草案与正式决定 | 同时读取草案和正式决定,并以正式决定为准 |
|
||
|
||
每个 Case 独立运行 3 次,因此一次完整评测共有 6 次 Target Agent 运行。
|
||
|
||
完整流程如下:
|
||
|
||
1. 配置本地 Qwen3:8B 与 Fireworks API 模型。
|
||
2. 创建 v1 Agent。
|
||
3. 导出 v1 Snapshot。
|
||
4. 创建并运行 Benchmark。
|
||
5. 查看基线和 Trace。
|
||
6. 优化 Agent。
|
||
7. 使用相同 Benchmark 重新评测候选版本。
|
||
8. 接受新版本或回滚。
|
||
|
||
---
|
||
|
||
## 第一步:配置 AMD GPU 上的 Qwen3:8B 与 Fireworks API
|
||
|
||
本实验使用两类模型:
|
||
|
||
| 用途 | Agent | 模型 |
|
||
|---|---|---|
|
||
| 创建 Agent、设计 Benchmark 和执行优化 | `default_agent` | Fireworks API 模型 |
|
||
| 接受评测与进化 | `meeting-summary-agent` | AMD GPU 上的 Qwen3:8B |
|
||
|
||
### 准备本地 Qwen3:8B
|
||
|
||
本地模型通过 Ollama 运行。AMD 驱动、ROCm 和 Ollama 的安装不是本文重点,这里不做详细介绍;只需提前确认 Qwen3:8B 已经能够被 Ollama 正常调用。具体安装方式可以参考 [Ollama Linux 文档](https://docs.ollama.com/linux) 和 [GPU 支持文档](https://docs.ollama.com/gpu)。
|
||
|
||
### 获取 Fireworks API
|
||
|
||
通过 AMD AI Developer Program,AMD 与 Fireworks AI 合作,为符合条件的开发者提供价值 50 美元的免费 Fireworks 额度。Fireworks 通过 OpenAI 兼容端点提供开源权重模型。可参阅 [Fireworks API 获取指南](https://penguin.ooo/blog/fireworks-credits-amd),了解额度兑换和 API Key 获取步骤。
|
||
|
||
### 在 Web UI 中注册模型
|
||
|
||
安装并启动 PenguinHarness:
|
||
|
||
```bash
|
||
curl -fsSL https://penguin.ooo/install.sh | sh
|
||
penguin web
|
||
```
|
||
|
||
打开 Web UI 的 **Models** 页面,添加本地 Qwen3:8B:
|
||
|
||
<img width="491" height="481" alt="PenguinHarness 本地 Qwen3:8B 模型配置" src="https://github.com/user-attachments/assets/a0d866e9-21e6-4b89-8ec1-b50710aed0db" />
|
||
|
||
然后配置 Fireworks API Key,并将 DeepSeek V4 Flash 设置为默认模型:
|
||
|
||
<img width="498" height="479" alt="PenguinHarness Fireworks API 模型配置" src="https://github.com/user-attachments/assets/3b392317-615d-46d3-95c9-f9e3b4ad61a5" />
|
||
|
||
这样,新建 `default_agent` 顶层 Chat 时可以直接使用 Project Default,也就是 Fireworks 模型;Benchmark 在运行 `meeting-summary-agent` 时,则显式指定下面这组本地模型配置:
|
||
|
||
```text
|
||
provider: custom
|
||
model_id: qwen3:8b
|
||
```
|
||
|
||
后续的 baseline 和 candidate 都必须沿用这组 `(provider, model_id)`,否则分数不能直接比较。
|
||
|
||
---
|
||
|
||
## 第二步:创建 v1 Agent
|
||
|
||
在 PenguinHarness Web UI 中创建一个新的 Agent:`meeting-summary-agent`。
|
||
|
||
使用 `default_agent` 新建一个顶层 Chat,模型选择刚刚设为 Project Default 的 Fireworks 模型。然后调用 `agent-creation` Skill,并输入下面的 Prompt,生成 `meeting-summary-agent` 的 v1 版本。v1 只定义基本职责和安全边界,不提前写入完整总结流程,这样 Benchmark 才能真实暴露它缺少的工作习惯。
|
||
|
||
<details>
|
||
<summary><strong>展开:创建 v1 Agent 的完整 Prompt</strong></summary>
|
||
|
||
```text
|
||
请使用 agent-creation Skill 配置 Agent `meeting-summary-agent`。
|
||
|
||
目标:
|
||
这是一个简单的本地文件总结 Agent。它读取当前工作区中的任务说明和文本文件,并创建题目要求的总结文件。
|
||
|
||
请将 v1 保持简洁:
|
||
|
||
1. 在 AGENTS.md 中只写清:
|
||
- 读取当前工作区中的任务和相关文件;
|
||
- 根据文件内容生成简洁总结;
|
||
- 只在当前工作区工作;
|
||
- 不访问外部服务;
|
||
- 不泄露环境变量、凭证或无关文件。
|
||
|
||
2. 不要预先加入完整的文件总结工作流,例如:
|
||
- 强制列出并读取全部材料;
|
||
- 系统区分草案与正式决定;
|
||
- 强制将信息分为已确认、待办和未确定;
|
||
- 完成后逐项核对输出。
|
||
|
||
3. 不要安装业务 Skill。
|
||
4. 不要故意要求 Agent 犯错。
|
||
5. 不修改稳定的 system_prompt。
|
||
6. 设置:
|
||
- name: Meeting Summary Agent
|
||
- description: Summarizes a small set of local text files.
|
||
|
||
最后报告修改的 Agent State 文件和当前 State version。
|
||
```
|
||
|
||
</details>
|
||
|
||
|
||
创建完成后,可以在 Agent 列表中看到新增的 `meeting-summary-agent`:
|
||
|
||
<img width="1376" height="464" alt="Agent 列表中的 meeting-summary-agent" src="https://github.com/user-attachments/assets/7e3f70d2-2164-4f90-8507-6c2d1cd9085c" />
|
||
|
||
然后进入 Agent 设置页面并导出 v1 Snapshot。它是后续 Candidate 失败时的回滚基础。
|
||
|
||
<img width="790" height="407" alt="导出 v1 Agent State Snapshot" src="https://github.com/user-attachments/assets/6f0c4745-3fd5-4c66-b302-bd58e42ce646" />
|
||
|
||
---
|
||
|
||
## 第三步:创建 Benchmark
|
||
|
||
仍然在使用 Fireworks 模型的 `default_agent` 顶层 Chat 中调用 `benchmark-design` Skill,并输入下面的 Prompt 来创建并校准 v1 版本的 Benchmark。
|
||
|
||
Benchmark ID 使用:
|
||
|
||
```text
|
||
simple-file-summary-2case-v1
|
||
```
|
||
|
||
两个 Case 的总分为 100 分,每个 Case 运行 3 次。Target Agent 只能看到公开题面,不能看到私有 Rubric。
|
||
|
||
<details>
|
||
<summary><strong>展开:创建并校准 Benchmark 的完整 Prompt</strong></summary>
|
||
|
||
```text
|
||
请使用 benchmark-design Skill,为下面的 Test Agent 创建并校准 Benchmark。
|
||
|
||
Test Agent:
|
||
meeting-summary-agent
|
||
|
||
Benchmark ID:
|
||
simple-file-summary-2case-v1
|
||
|
||
评测模型:
|
||
provider: custom
|
||
model_id: qwen3:8b
|
||
|
||
能力目标:
|
||
读取少量本地文本文件,在工作区根目录创建 SUMMARY.md;
|
||
准确区分已确认事实、待办事项和未确定信息;
|
||
当草案与明确的正式决定冲突时,以正式决定为准;
|
||
不得猜测或修改输入材料。
|
||
|
||
统一要求:
|
||
1. 每个 Case 的 statement 中提供 README.md 和 materials/*.txt。
|
||
2. Target Agent 必须创建 SUMMARY.md。
|
||
3. SUMMARY.md 包含:
|
||
- # 摘要
|
||
- ## 已确认
|
||
- ## 待办
|
||
- ## 未确定
|
||
4. 不得修改 README.md 或 materials/。
|
||
5. runs = 3。
|
||
6. 两个 Rubric 的最高分合计为 100。
|
||
7. Statement 不得泄露私有 Rubric 或标准答案。
|
||
|
||
请创建以下两个 Case。
|
||
|
||
CASE-001:单份会议纪要,最高 45 分
|
||
|
||
materials/meeting.txt:
|
||
|
||
产品周会,日期 2026-08-03。
|
||
|
||
正式决定:2026-08-10 开放内部试用。
|
||
|
||
小林负责整理使用说明,截止 2026-08-06。
|
||
小周负责完成冒烟测试,截止 2026-08-08。
|
||
|
||
移动端导出是否包含在本次试用中,尚未决定。
|
||
|
||
Rubric 应检查:
|
||
- SUMMARY.md 是否存在;
|
||
- 标题和分类是否正确;
|
||
- 内部试用日期是否准确;
|
||
- 两个待办的负责人、事项和截止日期是否完整;
|
||
- 移动端导出是否保留为未确定;
|
||
- 是否没有编造信息;
|
||
- 输入文件是否保持不变。
|
||
|
||
CASE-002:草案与正式决定,最高 55 分
|
||
|
||
materials/plan_draft.txt:
|
||
|
||
项目草案,日期 2026-08-01。
|
||
草案计划在 2026-08-15 上线。
|
||
初步负责人为小林。
|
||
|
||
materials/final_decision.txt:
|
||
|
||
正式决定,日期 2026-08-04。
|
||
由于测试延期,上线日期改为 2026-08-22。
|
||
小林负责发布准备,截止 2026-08-20。
|
||
邮件宣传时间尚未确定。
|
||
|
||
Rubric 应检查:
|
||
- SUMMARY.md 是否存在;
|
||
- 标题和分类是否正确;
|
||
- 是否使用正式上线日期 2026-08-22;
|
||
- 是否没有把草案日期当成当前决定;
|
||
- 是否准确提取发布准备任务和截止日期;
|
||
- 邮件宣传时间是否保留为未确定;
|
||
- 是否没有编造信息;
|
||
- 输入文件是否保持不变。
|
||
|
||
完成完整的 2 Cases × 3 runs 基线,将结果写入 scoreboard.yaml。
|
||
|
||
最后报告:
|
||
- Benchmark 路径;
|
||
- 总分;
|
||
- 两个 Case 的三次原始分数与均分;
|
||
- 运行波动;
|
||
- 全部 Test Session ID。
|
||
```
|
||
|
||
</details>
|
||
|
||
完成后,会得到如下图所示的 Benchmark 结构:
|
||
|
||
<img width="635" height="350" alt="生成后的 Benchmark 结构" src="https://github.com/user-attachments/assets/f44b9bbd-4b38-4c14-aa3a-2d95f44165cf" />
|
||
|
||
在 Web UI 中查看运行输出,并在 Benchmark 页面检查总分、每个 Case 的均分,以及对应的 Session 和 Trace。
|
||
|
||
<img width="550" height="235" alt="Benchmark 基线评分" src="https://github.com/user-attachments/assets/5dbfb515-198d-4d29-9ff3-01eccd61d630" />
|
||
|
||
可以看到,整体评分为 84 分。由于任务较为简单,baseline 已经进入 80 分区间,但仍有优化空间。后续我们会继续优化 Agent,以展示完整的自我进化过程。
|
||
|
||
|
||
---
|
||
|
||
## 第四步:优化 Agent
|
||
|
||
基线建立后,在使用 Fireworks 模型的 `default_agent` 顶层 Chat 中调用 `agent-optimization` Skill,并输入下面的 Prompt。Optimizer 会分析全部 6 次运行及其 Trace,提出一个可泛化的行为假设,再修改 `AGENTS.md` 或创建一个职责明确、范围有限的 Skill。
|
||
|
||
<details>
|
||
<summary><strong>展开:优化 Agent 的完整 Prompt</strong></summary>
|
||
|
||
```text
|
||
请使用 agent-optimization Skill,以 Benchmark optimization mode 优化目标 Agent。
|
||
|
||
Test Agent:
|
||
meeting-summary-agent
|
||
|
||
Benchmark:
|
||
simple-file-summary-2case-v1
|
||
|
||
优化目标:
|
||
提高读取少量本地文件并生成可靠总结的稳定性。
|
||
|
||
规则:
|
||
1. 使用 scoreboard.yaml 中当前版本的完整基线作为 reference。
|
||
2. 保持相同模型:
|
||
- provider: custom
|
||
- model_id: qwen3:8b
|
||
3. 不修改 Case、Statement、Rubric 或 runs。
|
||
4. 分析全部 2 个 Case、每个 Case 的 3 次运行和全部 score-linked Trace。
|
||
5. 本轮只提出一个可证伪、可跨 Case 泛化的行为假设。
|
||
6. 只做支持该假设的最小 Agent State 修改。
|
||
7. 优先修改 AGENTS.md;只有确实需要复用能力时,才创建职责明确、范围有限的 Skill。
|
||
8. 不得写入 Case ID、人物名、具体日期、标准答案或私有 Rubric。
|
||
9. Candidate 必须运行完整的 2 Cases × 3 runs。
|
||
10. Candidate 总分严格高于 reference 才接受;相同或下降必须回滚。
|
||
11. 本次最多接受一个新版本。
|
||
|
||
最后报告:
|
||
- reference 总分和各 Case 均分;
|
||
- 从 Trace 中发现的稳定失败模式;
|
||
- 行为假设;
|
||
- 修改的 Agent State 文件;
|
||
- candidate 总分和各 Case 均分;
|
||
- 接受或回滚原因;
|
||
- 全部 Test Session ID。
|
||
```
|
||
|
||
</details>
|
||
|
||
一种可能的优化方向,是加入简洁的工作流程或执行约束。
|
||
|
||
具体修改内容应由真实 Trace 决定,而不能把 Benchmark 的答案直接写入 Agent State。
|
||
|
||
---
|
||
|
||
## 第五步:比较并保留新版本
|
||
|
||
Optimizer 会使用同样的两个 Case、同样的 Qwen3:8B 和同样的 3 次重复运行评测 Candidate。
|
||
|
||
接受规则很简单:
|
||
|
||
```text
|
||
candidate 总分 > reference 总分
|
||
→ 保留新版本
|
||
|
||
candidate 总分 <= reference 总分
|
||
→ 回滚到 v1
|
||
```
|
||
|
||
优化完成后可以看到,Agent 修改了 `AGENTS.md`,新增了工作流程,并重新运行全部 Case,得到新的评测分数:
|
||
|
||
<img width="857" height="413" alt="Agent 优化结果与更新后的 Agent State" src="https://github.com/user-attachments/assets/f046ca42-e7ef-4063-8c10-babce816eba4" />
|
||
|
||
如果 v2 被接受,再从 Agent Overview 导出 v2 Snapshot。如果还需要继续优化,可以基于已接受的版本重复上述流程。
|
||
|
||
打开 Benchmark 页面,选择 **MEETING SUMMARY AGENT**,可以查看两轮评测形成的进化记录:
|
||
|
||
<img width="628" height="515" alt="Benchmark 页面中的两轮进化记录" src="https://github.com/user-attachments/assets/58be7385-8746-4931-92e6-f563dc26e804" />
|
||
|
||
> 由于示例任务较为简单,一轮优化后分数便接近满分。在更复杂的真实场景中,自我进化能力的价值会体现得更加明显。
|
||
|
||
---
|
||
|
||
## 结语
|
||
|
||
这个实验展示的并不是 Qwen3:8B 在运行中重新训练了自己,而是 PenguinHarness 让 Agent 的工作方式进入了一个可验证闭环:
|
||
|
||
```text
|
||
行为被 Benchmark 测量
|
||
→ 失败可以回溯到 Trace
|
||
→ 工作流程被写入 Agent State
|
||
→ 新版本重新接受完整评测
|
||
→ 只有真实提升才被保留
|
||
```
|
||
|
||
对于本地模型来说,这种方式尤其有价值:不需要准备训练数据或微调权重,也能通过更清晰的工作流程,提高 Agent 完成任务的稳定性。
|
||
|
||
## 参考资料
|
||
|
||
- [PenguinHarness GitHub](https://github.com/Prism-Shadow/penguin-harness)
|
||
- [PenguinHarness 自我进化文档](https://penguin.ooo/docs/self-improvement/)
|
||
- [Fireworks API 免费额度兑换与 API Key 获取](https://penguin.ooo/blog/fireworks-credits-amd)
|