<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>WZH 的博客</title><link>https://wangzh12023.github.io/blog/</link><description>Recent content on WZH 的博客 created by</description><generator>Hugo -- gohugo.io</generator><language>zh</language><managingEditor>wzh</managingEditor><webMaster>wzh</webMaster><copyright>2026 WZH All rights reserved</copyright><lastBuildDate>Sat, 22 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://wangzh12023.github.io/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>强化学习基础公式全解析：从 Policy 到 Q-Learning</title><link>https://wangzh12023.github.io/blog/blog/rl-basic-formulas/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/rl-basic-formulas/</guid><description>&lt;p&gt;强化学习（Reinforcement Learning, RL）的核心是 agent 在环境（Environment）中通过试错（trial and error）学习最优策略。本文系统梳理 RL 最基础、最核心的公式，从 Policy、Return 出发，经过 V/Q 函数、Bellman 方程，最终到 TD 学习和 Q-Learning，形成一条完整的公式链。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-基础表示"&gt;1. 基础表示&lt;/h2&gt;
&lt;h3 id="policy"&gt;Policy&lt;/h3&gt;
&lt;p&gt;策略定义了 agent 在给定状态下如何选择动作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;确定性策略&lt;/strong&gt;：状态到动作的映射&lt;/p&gt;
$$
A_t = \pi(S_t), \qquad \pi: \mathcal S \to \mathcal A
$$&lt;p&gt;&lt;strong&gt;随机策略&lt;/strong&gt;：给定状态下的动作概率分布&lt;/p&gt;
$$
A_t \sim \pi(\cdot \mid S_t), \qquad
\pi(a \mid s) = P(A_t = a \mid S_t = s)
$$&lt;p&gt;其中 $\sum_{a \in \mathcal A} \pi(a \mid s) = 1$。随机策略是 RL 的一般形式，确定性策略可视为其退化情形。&lt;/p&gt;
&lt;h3 id="discounted-return"&gt;Discounted Return&lt;/h3&gt;
&lt;p&gt;Return $G_t$ 是从时间 $t$ 开始累积的折扣奖励总和：&lt;/p&gt;
$$
G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \cdots
= \sum_{k=0}^{\infty} \gamma^k R_{t+k+1}
$$&lt;p&gt;&lt;strong&gt;递归形式&lt;/strong&gt;是最常用的表达：&lt;/p&gt;
$$
G_t = R_{t+1} + \gamma G_{t+1}
$$&lt;p&gt;其中 $\gamma \in [0, 1]$ 是 discount factor。&lt;/p&gt;
&lt;h3 id="rl-target"&gt;RL Target&lt;/h3&gt;
&lt;p&gt;RL 的目标是找到一个策略，使期望折扣回报最大化：&lt;/p&gt;
$$
\pi^* = \arg\max_{\pi} \mathbb E_{\pi} \left[ \sum_{t=0}^{\infty} \gamma^t R_{t+1} \right]
$$&lt;hr&gt;
&lt;h2 id="2"&gt;2. $V^\pi$&lt;/h2&gt;
&lt;p&gt;状态价值函数 $V^\pi(s)$ 表示从状态 $s$ 出发，按照策略 $\pi$ 行动所能获得的期望 return。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;期望形式&lt;/strong&gt;：&lt;/p&gt;
$$
V^\pi(s) = \mathbb E_\pi \left[ G_t \mid S_t = s \right]
$$&lt;p&gt;展开 return：&lt;/p&gt;
$$
V^\pi(s) = \mathbb E_\pi \left[ R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \cdots \mid S_t = s \right]
$$&lt;p&gt;&lt;strong&gt;按概率分布展开&lt;/strong&gt;（离散情况）：&lt;/p&gt;
$$
V^\pi(s) = \sum_g g \cdot P_\pi(G_t = g \mid S_t = s)
$$&lt;p&gt;&lt;strong&gt;Monte Carlo 估计&lt;/strong&gt;：从状态 $s$ 采样 $N$ 条 rollout，取 return 的平均值：&lt;/p&gt;
$$
\hat V^\pi(s) = \frac{1}{N} \sum_{i=1}^N G_t^{(i)} \approx V^\pi(s)
$$&lt;p&gt;$G_t$ 是一条具体 trajectory 的 return，而 $V^\pi(s)$ 是所有可能 returns 的期望。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="3"&gt;3. $Q^\pi$&lt;/h2&gt;
&lt;p&gt;动作价值函数 $Q^\pi(s, a)$ 表示从状态 $s$ 开始，先执行动作 $a$，之后按策略 $\pi$ 行动所能获得的期望 return。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;期望形式&lt;/strong&gt;：&lt;/p&gt;
$$
Q^\pi(s, a) = \mathbb E_\pi \left[ G_t \mid S_t = s, A_t = a \right]
$$&lt;p&gt;展开 return：&lt;/p&gt;
$$
Q^\pi(s, a) = \mathbb E_\pi \left[ R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \cdots \mid S_t = s, A_t = a \right]
$$&lt;p&gt;&lt;strong&gt;按概率分布展开&lt;/strong&gt;：&lt;/p&gt;
$$
Q^\pi(s, a) = \sum_g g \cdot P_\pi(G_t = g \mid S_t = s, A_t = a)
$$&lt;p&gt;&lt;strong&gt;Sampling&lt;/strong&gt;：&lt;/p&gt;
$$
\hat Q^\pi(s, a) = \frac{1}{N} \sum_{i=1}^N G_t^{(i)}
$$&lt;p&gt;其中 rollout 起点为 $(S_t = s, A_t = a)$，之后按 $\pi$ 行动。$Q^\pi$ 与 $V^\pi$ 的区别在于额外固定了第一步的 action。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="4--与--的关系"&gt;4. $V^\pi$ 与 $Q^\pi$ 的关系&lt;/h2&gt;
&lt;h3 id="从--得到"&gt;从 $Q^\pi$ 得到 $V^\pi$&lt;/h3&gt;
&lt;p&gt;$V^\pi(s)$ 是当前策略下所有动作价值的概率加权平均：&lt;/p&gt;
$$
V^\pi(s) = \mathbb E_{A \sim \pi(\cdot \mid s)} \left[ Q^\pi(s, A) \right]
$$&lt;p&gt;离散动作展开：&lt;/p&gt;
$$
V^\pi(s) = \sum_{a \in \mathcal A} \pi(a \mid s) Q^\pi(s, a)
$$&lt;h3 id="从--得到-1"&gt;从 $V^\pi$ 得到 $Q^\pi$&lt;/h3&gt;
&lt;p&gt;固定当前 action，再对下一状态求期望：&lt;/p&gt;
$$
Q^\pi(s, a) = \mathbb E \left[ R_{t+1} + \gamma V^\pi(S_{t+1}) \mid S_t = s, A_t = a \right]
$$&lt;p&gt;记期望即时奖励为 $R(s, a)$：&lt;/p&gt;
$$
Q^\pi(s, a) = R(s, a) + \gamma \mathbb E \left[ V^\pi(S_{t+1}) \mid s, a \right]
$$&lt;p&gt;对下一状态展开：&lt;/p&gt;
$$
Q^\pi(s, a) = R(s, a) + \gamma \sum_{s' \in \mathcal S} P(s' \mid s, a) V^\pi(s')
$$&lt;p&gt;若 reward 依赖于 $(s, a, s')$：&lt;/p&gt;
$$
Q^\pi(s, a) = \sum_{s'} P(s' \mid s, a) \left[ R(s, a, s') + \gamma V^\pi(s') \right]
$$&lt;h3 id="直接递归到"&gt;$Q^\pi$ 直接递归到 $Q^\pi$&lt;/h3&gt;
&lt;p&gt;将 $V^\pi(s') = \sum_{a'} \pi(a' \mid s') Q^\pi(s', a')$ 代入：&lt;/p&gt;
$$
Q^\pi(s, a) = R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) \sum_{a'} \pi(a' \mid s') Q^\pi(s', a')
$$&lt;p&gt;或紧凑形式：&lt;/p&gt;
$$
Q^\pi(s, a) = \mathbb E_\pi \left[ R_{t+1} + \gamma Q^\pi(S_{t+1}, A_{t+1}) \mid S_t = s, A_t = a \right]
$$&lt;hr&gt;
&lt;h2 id="5-bellman-expectation-equation"&gt;5. Bellman Expectation Equation&lt;/h2&gt;
&lt;p&gt;Bellman 方程的核心思想来自 $G_t = R_{t+1} + \gamma G_{t+1}$，将长期 return 改写为&amp;quot;一步奖励加下一状态价值&amp;quot;的递归形式。&lt;/p&gt;
&lt;h3 id="的-bellman-expectation-equation"&gt;$V^\pi$ 的 Bellman Expectation Equation&lt;/h3&gt;
&lt;p&gt;最紧凑的期望形式：&lt;/p&gt;
$$
V^\pi(s) = \mathbb E_\pi \left[ R_{t+1} + \gamma V^\pi(S_{t+1}) \mid S_t = s \right]
$$&lt;p&gt;先展开 action：&lt;/p&gt;
$$
V^\pi(s) = \sum_a \pi(a \mid s) \left[ R(s, a) + \gamma \mathbb E_{S' \sim P(\cdot \mid s, a)} V^\pi(S') \right]
$$&lt;p&gt;完全展开：&lt;/p&gt;
$$
V^\pi(s) = \sum_{a \in \mathcal A} \pi(a \mid s) \left[ R(s, a) + \gamma \sum_{s' \in \mathcal S} P(s' \mid s, a) V^\pi(s') \right]
$$&lt;p&gt;使用 $R(s, a, s')$ 时：&lt;/p&gt;
$$
V^\pi(s) = \sum_a \pi(a \mid s) \sum_{s'} P(s' \mid s, a) \left[ R(s, a, s') + \gamma V^\pi(s') \right]
$$&lt;p&gt;也可以写成 $V$-$Q$ 两层形式：&lt;/p&gt;
$$
V^\pi(s) = \sum_a \pi(a \mid s) Q^\pi(s, a), \qquad
Q^\pi(s, a) = R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V^\pi(s')
$$&lt;h3 id="的-bellman-expectation-equation-1"&gt;$Q^\pi$ 的 Bellman Expectation Equation&lt;/h3&gt;
&lt;p&gt;期望形式：&lt;/p&gt;
$$
Q^\pi(s, a) = \mathbb E_\pi \left[ R_{t+1} + \gamma Q^\pi(S_{t+1}, A_{t+1}) \mid S_t = s, A_t = a \right]
$$&lt;p&gt;完全展开：&lt;/p&gt;
$$
Q^\pi(s, a) = R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) \sum_{a'} \pi(a' \mid s') Q^\pi(s', a')
$$&lt;hr&gt;
&lt;h2 id="6-bellman-optimality-equation"&gt;6. Bellman Optimality Equation&lt;/h2&gt;
&lt;h3 id="optimal-value-functions"&gt;Optimal Value Functions&lt;/h3&gt;
&lt;h4 id="最优状态价值"&gt;最优状态价值&lt;/h4&gt;
$$
V^*(s) = \max_\pi V^\pi(s)
$$&lt;p&gt;与 optimal Q 的关系：&lt;/p&gt;
$$
V^*(s) = \max_{a \in \mathcal A} Q^*(s, a)
$$&lt;h4 id="最优动作价值"&gt;最优动作价值&lt;/h4&gt;
$$
Q^*(s, a) = \max_\pi Q^\pi(s, a)
$$&lt;p&gt;含义是：当前第一步 $a$ 已固定，从下一步开始采用最优策略。&lt;/p&gt;
&lt;p&gt;与 Bellman Expectation Equation 结构对应，但将固定策略下的加权平均替换为 $\max$ 操作。&lt;/p&gt;
&lt;h3 id="形式"&gt;$V^*$ 形式&lt;/h3&gt;
&lt;p&gt;期望形式：&lt;/p&gt;
$$
V^*(s) = \max_a \mathbb E \left[ R_{t+1} + \gamma V^*(S_{t+1}) \mid S_t = s, A_t = a \right]
$$&lt;p&gt;展开 transition：&lt;/p&gt;
$$
V^*(s) = \max_a \left[ R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V^*(s') \right]
$$&lt;h3 id="形式-1"&gt;$Q^*$ 形式&lt;/h3&gt;
&lt;p&gt;期望形式：&lt;/p&gt;
$$
Q^*(s, a) = \mathbb E \left[ R_{t+1} + \gamma \max_{a'} Q^*(S_{t+1}, a') \mid S_t = s, A_t = a \right]
$$&lt;p&gt;展开 transition：&lt;/p&gt;
$$
Q^*(s, a) = R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) \max_{a'} Q^*(s', a')
$$&lt;hr&gt;
&lt;h2 id="7-advantage-function"&gt;7. Advantage Function&lt;/h2&gt;
&lt;p&gt;Advantage 函数衡量某个动作相对于策略平均水平的优劣：&lt;/p&gt;
$$
A^\pi(s, a) = Q^\pi(s, a) - V^\pi(s)
$$&lt;p&gt;等价地：&lt;/p&gt;
$$
Q^\pi(s, a) = V^\pi(s) + A^\pi(s, a)
$$&lt;p&gt;由 $V^\pi(s) = \sum_a \pi(a \mid s) Q^\pi(s, a)$ 可得：&lt;/p&gt;
$$
\sum_a \pi(a \mid s) A^\pi(s, a) = 0
$$&lt;p&gt;即在策略自身的 action distribution 下，advantage 的期望为 0。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="8-从-value-得到-policy"&gt;8. 从 Value 得到 Policy&lt;/h2&gt;
&lt;p&gt;普通 $Q$ 上的 greedy policy：&lt;/p&gt;
$$
\pi_Q(s) = \arg\max_a Q(s, a)
$$&lt;p&gt;Optimal policy：&lt;/p&gt;
$$
\pi^*(s) = \arg\max_a Q^*(s, a)
$$&lt;p&gt;核心对比：&lt;/p&gt;
$$
V^\pi(s) = \sum_a \pi(a \mid s) Q^\pi(s, a)
\quad\Longleftrightarrow\quad
V^*(s) = \max_a Q^*(s, a)
$$&lt;p&gt;前者是 &lt;strong&gt;policy-weighted average&lt;/strong&gt;，后者是 &lt;strong&gt;greedy maximum&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="9-动态规划蒙特卡洛与时序差分"&gt;9. 动态规划、蒙特卡洛与时序差分&lt;/h2&gt;
&lt;p&gt;精确的 Bellman 方程包含期望运算，求解方式分为三类：已知模型的动态规划、无模型的蒙特卡洛采样、以及结合两者的时序差分学习。&lt;/p&gt;
&lt;h3 id="动态规划"&gt;动态规划&lt;/h3&gt;
&lt;p&gt;动态规划（Dynamic Programming, DP）假设已知完整的 MDP 模型（转移概率 $P$ 和奖励函数 $R$），利用 Bellman 期望方程迭代求解价值函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;策略评估&lt;/strong&gt;：反复应用 Bellman 期望方程，逐步逼近 $V^\pi$：&lt;/p&gt;
$$
V_{k+1}(s) = \sum_a \pi(a \mid s) \left[ R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V_k(s') \right]
$$&lt;p&gt;&lt;strong&gt;策略迭代&lt;/strong&gt;：交替进行策略评估和策略改进：&lt;/p&gt;
$$
\pi'(s) = \arg\max_a \left[ R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V^\pi(s') \right]
$$&lt;p&gt;&lt;strong&gt;值迭代&lt;/strong&gt;：直接使用 Bellman 最优方程迭代，不显式维护策略：&lt;/p&gt;
$$
V_{k+1}(s) = \max_a \left[ R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V_k(s') \right]
$$&lt;p&gt;DP 的局限在于需要完整的环境模型，而多数实际问题中 $P$ 和 $R$ 未知。&lt;/p&gt;
&lt;h3 id="蒙特卡洛"&gt;蒙特卡洛&lt;/h3&gt;
&lt;p&gt;蒙特卡洛（Monte Carlo, MC）方法不需要环境模型，直接从完整 episode 的采样 return 中学习。从状态 $s$ 采样 $N$ 条 rollout，取 return 的平均值作为 $V^\pi(s)$ 的估计：&lt;/p&gt;
$$
\hat V^\pi(s) = \frac{1}{N} \sum_{i=1}^N G_t^{(i)} \approx V^\pi(s)
$$&lt;p&gt;实际中通常采样多条 trajectory 做平均，以降低单条轨迹带来的高方差。当 $N$ 足够大时，$\hat V^\pi(s)$ 收敛到 $V^\pi(s)$。&lt;/p&gt;
&lt;p&gt;增量更新形式是上述批平均的流式等价，每条新 episode 到达时：&lt;/p&gt;
$$
V(S_t) \leftarrow V(S_t) + \alpha \left[ G_t - V(S_t) \right]
$$&lt;p&gt;其中 $G_t$ 是当前 episode 的折扣回报。MC 的估计是无偏的，但方差较大，且必须等到 episode 结束才能更新。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First-visit MC&lt;/strong&gt;：每个 episode 中只对状态 $s$ 第一次出现时进行更新。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every-visit MC&lt;/strong&gt;：每个 episode 中每次出现状态 $s$ 都进行更新。&lt;/p&gt;
&lt;h3 id="时序差分"&gt;时序差分&lt;/h3&gt;
&lt;p&gt;时序差分（Temporal Difference, TD）结合了 DP 的 bootstrap 和 MC 的采样思想，不需要环境模型，也不需要等到 episode 结束：&lt;/p&gt;
&lt;p&gt;Bellman expectation：&lt;/p&gt;
$$
V^\pi(s) = \mathbb E_\pi \left[ R_{t+1} + \gamma V^\pi(S_{t+1}) \mid S_t = s \right]
$$&lt;p&gt;&lt;strong&gt;单样本 TD target&lt;/strong&gt;：&lt;/p&gt;
$$
y_t^{\text{TD}} = R_{t+1} + \gamma V(S_{t+1})
$$&lt;p&gt;&lt;strong&gt;TD error&lt;/strong&gt;：&lt;/p&gt;
$$
\delta_t = y_t^{\text{TD}} - V(S_t) = R_{t+1} + \gamma V(S_{t+1}) - V(S_t)
$$&lt;p&gt;&lt;strong&gt;TD update&lt;/strong&gt;：&lt;/p&gt;
$$
V(S_t) \leftarrow V(S_t) + \alpha \delta_t
$$&lt;p&gt;完全写开：&lt;/p&gt;
$$
V(S_t) \leftarrow V(S_t) + \alpha \left[ R_{t+1} + \gamma V(S_{t+1}) - V(S_t) \right]
$$&lt;p&gt;TD 的方差比 MC 低，但引入 bootstrap 带来了偏差。三种方法的核心区别在于：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;是否需要模型&lt;/th&gt;
&lt;th&gt;是否需要完整 episode&lt;/th&gt;
&lt;th&gt;Bootstrap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DP&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MC&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TD&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="10-q-learning"&gt;10. Q-Learning&lt;/h2&gt;
&lt;p&gt;Q-Learning 以 Bellman &lt;strong&gt;optimality&lt;/strong&gt; equation 为目标，而非 Bellman expectation equation。&lt;/p&gt;
&lt;h3 id="目标方程"&gt;目标方程&lt;/h3&gt;
$$
Q^*(s, a) = \mathbb E \left[ R_{t+1} + \gamma \max_{a'} Q^*(S_{t+1}, a') \mid s, a \right]
$$&lt;h3 id="sample-td-target"&gt;Sample TD Target&lt;/h3&gt;
$$
y_t^Q = R_{t+1} + \gamma \max_{a'} Q(S_{t+1}, a')
$$&lt;h3 id="td-error"&gt;TD Error&lt;/h3&gt;
$$
\delta_t = y_t^Q - Q(S_t, A_t) = R_{t+1} + \gamma \max_{a'} Q(S_{t+1}, a') - Q(S_t, A_t)
$$&lt;h3 id="q-learning-update"&gt;Q-Learning Update&lt;/h3&gt;
$$
Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \delta_t
$$&lt;p&gt;完全写开：&lt;/p&gt;
$$
Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \left[ R_{t+1} + \gamma \max_{a'} Q(S_{t+1}, a') - Q(S_t, A_t) \right]
$$&lt;p&gt;四条公式的递进关系：&lt;/p&gt;
$$
\text{Bellman optimality equation} \;\to\; \text{sample target} \;\to\; \text{TD error} \;\to\; \text{update}
$$&lt;hr&gt;
&lt;h2 id="11--greedy-与-off-policy"&gt;11. $\varepsilon$-Greedy 与 Off-Policy&lt;/h2&gt;
&lt;p&gt;$\varepsilon$-greedy 策略：以概率 $1-\varepsilon$ 选择贪心动作，以概率 $\varepsilon$ 随机探索。&lt;/p&gt;
&lt;p&gt;若随机部分在所有 $|\mathcal A|$ 个动作中均匀采样：&lt;/p&gt;
$$
\pi_{\varepsilon}(a \mid s) =
\begin{cases}
1 - \varepsilon + \dfrac{\varepsilon}{|\mathcal A|}, &amp; a = \arg\max_{a'} Q(s, a') \\[6pt]
\dfrac{\varepsilon}{|\mathcal A|}, &amp; \text{otherwise}
\end{cases}
$$&lt;p&gt;Q-Learning 使用两套策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Behavior policy&lt;/strong&gt;：$\varepsilon$-greedy（用于生成数据）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target policy&lt;/strong&gt;：$\arg\max_a Q(s, a)$（用于计算 target）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此 Q-Learning 是 &lt;strong&gt;off-policy&lt;/strong&gt; 算法：数据由探索性的 behavior policy 生成，但 target 使用 greedy policy。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="12-q-learning-与-sarsa-的公式差异"&gt;12. Q-Learning 与 SARSA 的公式差异&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Q-Learning&lt;/strong&gt;（off-policy）：&lt;/p&gt;
$$
y_t^Q = R_{t+1} + \gamma \max_{a'} Q(S_{t+1}, a')
$$$$
Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \left[ R_{t+1} + \gamma \max_{a'} Q(S_{t+1}, a') - Q(S_t, A_t) \right]
$$&lt;p&gt;&lt;strong&gt;SARSA&lt;/strong&gt;（on-policy）：下一步动作由当前 behavior policy 实际采样&lt;/p&gt;
$$
A_{t+1} \sim \pi(\cdot \mid S_{t+1})
$$$$
y_t^{\text{SARSA}} = R_{t+1} + \gamma Q(S_{t+1}, A_{t+1})
$$$$
Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \left[ R_{t+1} + \gamma Q(S_{t+1}, A_{t+1}) - Q(S_t, A_t) \right]
$$&lt;p&gt;&lt;strong&gt;最核心的差别&lt;/strong&gt;：&lt;/p&gt;
$$
\boxed{\text{Q-Learning: } \max_{a'} Q(S_{t+1}, a')}
\qquad
\boxed{\text{SARSA: } Q(S_{t+1}, A_{t+1}), \quad A_{t+1} \sim \pi}
$$&lt;p&gt;前者对下一步做 greedy optimization，后者使用 behavior policy 实际选出的下一动作。这也是 off-policy 与 on-policy 差异在公式中的直接体现。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="13-核心公式关系图"&gt;13. 核心公式关系图&lt;/h2&gt;
&lt;p&gt;如果只保留一组需要反复记忆的公式，就是 RL 的基础公式链：&lt;/p&gt;
$$
G_t = R_{t+1} + \gamma G_{t+1}
$$$$
V^\pi(s) = \mathbb E_\pi[G_t \mid S_t = s]
$$$$
Q^\pi(s, a) = \mathbb E_\pi[G_t \mid S_t = s, A_t = a]
$$$$
V^\pi(s) = \sum_a \pi(a \mid s) Q^\pi(s, a)
$$$$
Q^\pi(s, a) = R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V^\pi(s')
$$$$
V^\pi(s) = \sum_a \pi(a \mid s) \left[ R(s, a) + \gamma \sum_{s'} P(s' \mid s, a) V^\pi(s') \right]
$$$$
V^*(s) = \max_a Q^*(s, a)
$$$$
Q^*(s, a) = \mathbb E \left[ R_{t+1} + \gamma \max_{a'} Q^*(S_{t+1}, a') \mid s, a \right]
$$$$
A^\pi(s, a) = Q^\pi(s, a) - V^\pi(s)
$$$$
\delta_t^V = R_{t+1} + \gamma V(S_{t+1}) - V(S_t)
$$$$
\delta_t^Q = R_{t+1} + \gamma \max_{a'} Q(S_{t+1}, a') - Q(S_t, A_t)
$$&lt;p&gt;从 &lt;strong&gt;Policy / Return → $V^\pi$ → $Q^\pi$ → Bellman Expectation → Bellman Optimality → TD → Q-Learning&lt;/strong&gt;，构成了强化学习最基础、最核心的公式链条。&lt;/p&gt;</description></item><item><title>用 ComfyUI 生成图片和视频：从 Workflow 到集群部署</title><link>https://wangzh12023.github.io/blog/blog/comfyui-image-video-workflow/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/comfyui-image-video-workflow/</guid><description>&lt;p&gt;最近在集群上搭了一套 ComfyUI 环境，用 FLUX.2 生成图片，也准备了 MiniMax H3 的文生视频和图生视频 Workflow。整个过程比想象中有意思：它没有把所有参数塞进一个很长的配置文件，而是把模型、提示词、采样器、VAE 和输出等步骤做成一个个节点，再像拼积木一样把它们连起来。&lt;/p&gt;
&lt;p&gt;这篇文章一方面介绍 ComfyUI 的基本概念和常见模块，另一方面也记录一下我自己的使用方式：在集群计算节点上申请 GPU 并运行 ComfyUI Server，通过 SSH 端口转发到 Mac，最后在本地浏览器里编辑和执行 Workflow。&lt;/p&gt;
&lt;h2 id="comfyui-是什么"&gt;ComfyUI 是什么？&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/Comfy-Org/ComfyUI"&gt;ComfyUI&lt;/a&gt; 是一个基于节点图（node graph）的生成式 AI 工作流工具。官方把它定位为一个模块化的 AI 内容创作引擎，除了图片，也支持视频、音频、3D 等任务。&lt;/p&gt;
&lt;p&gt;如果以前用过 Stable Diffusion WebUI，可能会习惯在一个页面里填写提示词、采样步数、分辨率，然后点击生成。ComfyUI 的思路不太一样：&lt;strong&gt;它把一次生成任务拆成很多可以连接、替换和复用的模块。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;例如，一个最基本的文生图流程大致是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;加载模型
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── 文本编码器 ──&amp;gt; 编码正向/负向提示词 ──┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── 去噪模型 ────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── VAE ────────────────────────────────┐│
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;空 Latent ───────────────────────────&amp;gt; KSampler
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; VAE Decode
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Save Image
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个节点两侧都有输入输出接口，接口的颜色和类型需要对应。模型接到采样器的 &lt;code&gt;model&lt;/code&gt;，提示词编码结果接到 &lt;code&gt;positive&lt;/code&gt; 或 &lt;code&gt;negative&lt;/code&gt;，采样器输出的 latent 再交给 VAE 解码。连线正确，数据就会沿着图向后流动。&lt;/p&gt;
&lt;p&gt;这也是我觉得 ComfyUI 很好玩的地方。它不像在使用一个只有“生成”按钮的黑盒，更像是在桌面上搭一条小型生产线。简单任务可以只用几个节点，复杂任务则可以继续加入 LoRA、ControlNet、局部重绘、放大、补帧、视频编码等模块。&lt;/p&gt;
&lt;h2 id="从最小的文生图-workflow-开始"&gt;从最小的文生图 Workflow 开始&lt;/h2&gt;
&lt;p&gt;下面这张图来自 ComfyUI 官方的&lt;a href="https://docs.comfy.org/zh/tutorials/basic/text-to-image"&gt;文生图基础教程&lt;/a&gt;。这是一个很典型的 Stable Diffusion 文生图 Workflow：左侧加载 checkpoint，中间准备提示词和 latent，KSampler 完成采样，最后通过 VAE Decode 和 Save Image 得到图片。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wangzh12023.github.io/blog/images/comfyui/basic-workflow-overview.jpg" alt="ComfyUI 基础文生图 Workflow"&gt;&lt;/p&gt;
&lt;p&gt;图里从 A 到 F 的六个部分分别是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Load Checkpoint&lt;/code&gt;：加载模型，并输出 &lt;code&gt;MODEL&lt;/code&gt;、&lt;code&gt;CLIP&lt;/code&gt; 和 &lt;code&gt;VAE&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Empty Latent Image&lt;/code&gt;：创建初始潜在空间，同时定义图片宽高和批量大小。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLIP Text Encode&lt;/code&gt;：把正向、负向提示词转换成模型能够使用的条件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;KSampler&lt;/code&gt;：从噪声开始，按照提示词条件反复去噪。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VAE Decode&lt;/code&gt;：把 latent 解码成真正能看到的像素图像。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Save Image&lt;/code&gt;：预览并保存结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;导入工作流有几种常用方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把包含 Workflow 元数据的 PNG 直接拖到画布中；&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;Workflow -&amp;gt; Open&lt;/code&gt; 打开 Workflow JSON 或 PNG；&lt;/li&gt;
&lt;li&gt;从 &lt;code&gt;Workflow -&amp;gt; Browse Workflow Templates&lt;/code&gt; 选择官方模板；&lt;/li&gt;
&lt;li&gt;把 GUI 格式的 JSON 放进 &lt;code&gt;ComfyUI/user/default/workflows/&lt;/code&gt;，再从 Workflow 侧边栏打开。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我自己的 Workflow 单独留了一份在项目的 &lt;code&gt;workflows/&lt;/code&gt; 目录中，同时把日常需要在 WebUI 里直接打开的版本放到 ComfyUI 的用户工作流目录。这样既方便备份，也方便后面让 GPT 或 Codex 修改节点和模型路径。&lt;/p&gt;
&lt;h2 id="几个最重要的模块"&gt;几个最重要的模块&lt;/h2&gt;
&lt;p&gt;第一次看到 ComfyUI 的节点图可能会觉得线很多，但真正理解下面几个模块以后，大部分基础 Workflow 都能看懂。&lt;/p&gt;
&lt;h3 id="去噪模型unetdit-和-model"&gt;去噪模型：UNet、DiT 和 MODEL&lt;/h3&gt;
&lt;p&gt;在传统 Stable Diffusion Workflow 里，经常会看到 &lt;code&gt;UNet&lt;/code&gt; 这个名字。它是扩散过程中的去噪主干：输入某一步的噪声 latent、当前时间步和文本条件，预测应该如何减少噪声。KSampler 会反复调用它，逐步把随机噪声变成具有结构的图像。&lt;/p&gt;
&lt;p&gt;不过需要注意，&lt;strong&gt;“UNet”在 ComfyUI 生态里有时也被当作去噪模型的习惯性统称。&lt;/strong&gt; FLUX.2、MiniMax H3 等较新的模型使用的是 Transformer/DiT 一类架构，并不等于经典 Stable Diffusion UNet。界面上仍可能通过 &lt;code&gt;UNETLoader&lt;/code&gt; 加载，连接出去的类型通常也统一显示为 &lt;code&gt;MODEL&lt;/code&gt;。理解 Workflow 时，把它看成“负责扩散去噪的主模型”更准确。&lt;/p&gt;
&lt;h3 id="clip-与文本编码器"&gt;CLIP 与文本编码器&lt;/h3&gt;
&lt;p&gt;生成模型不能直接理解自然语言字符串，因此提示词要先经过文本编码器，变成一组语义向量，再作为 conditioning 送入采样流程。&lt;/p&gt;
&lt;p&gt;SD1.5 的基础流程里常把这一部分叫作 &lt;code&gt;CLIP Text Encode&lt;/code&gt;。新模型不一定只使用 CLIP，例如我的 FLUX.2 Workflow 使用 Mistral 系列文本编码器，MiniMax H3 使用 Qwen3-VL 32B 文本编码器。节点名称和底层模型会变化，但它们承担的核心职责相似：&lt;strong&gt;把“我想生成什么”转换成去噪模型能使用的条件。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;传统文生图里通常有两路条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;positive&lt;/code&gt;：希望画面中出现的主体、环境、风格、镜头和光线；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;negative&lt;/code&gt;：希望模型避免的内容，例如模糊、错误肢体、文字水印等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同模型的提示词习惯并不完全相同。不能把 SD1.5 时代的“关键词堆叠”机械套到所有新模型上，有些新模型更适合完整、结构清楚的自然语言描述。&lt;/p&gt;
&lt;h3 id="latent模型真正工作的画布"&gt;Latent：模型真正工作的“画布”&lt;/h3&gt;
&lt;p&gt;扩散模型通常不直接在完整 RGB 像素上反复去噪，而是在压缩后的潜在空间（latent space）中工作。可以把它理解成一张信息更紧凑的“草图”或“蓝图”。&lt;/p&gt;
&lt;p&gt;文生图一般从随机 latent 开始；图生图则先用 VAE Encode 把输入图片压进 latent，再加入一定噪声后继续采样。因此图生图中的 &lt;code&gt;denoise&lt;/code&gt; 很关键：数值越小越保留原图，越接近 1，模型自由发挥的程度越高。&lt;/p&gt;
&lt;h3 id="ksampler真正执行生成的核心"&gt;KSampler：真正执行生成的核心&lt;/h3&gt;
&lt;p&gt;KSampler 是基础 Workflow 中最核心的节点之一。它接收：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;去噪模型 &lt;code&gt;model&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;正向和负向条件；&lt;/li&gt;
&lt;li&gt;初始 &lt;code&gt;latent_image&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;seed&lt;/code&gt;、&lt;code&gt;steps&lt;/code&gt;、&lt;code&gt;cfg&lt;/code&gt;、采样器和调度器等参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中几个参数最值得记住：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;th&gt;实际理解&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;seed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;初始化随机噪声&lt;/td&gt;
&lt;td&gt;相同模型、参数和 seed 更容易复现结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;去噪迭代次数&lt;/td&gt;
&lt;td&gt;不是越高越好，超过模型合适范围只会更慢&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cfg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;提示词引导强度&lt;/td&gt;
&lt;td&gt;太高可能让画面生硬或失真；不同模型推荐值差异很大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sampler_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;采样算法&lt;/td&gt;
&lt;td&gt;决定每一步如何沿去噪轨迹更新&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scheduler&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;噪声调度方式&lt;/td&gt;
&lt;td&gt;决定时间步和噪声强度如何分配&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;denoise&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;去噪强度&lt;/td&gt;
&lt;td&gt;文生图一般为 1；图生图常小于 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果 Workflow 使用的是 &lt;code&gt;SamplerCustom&lt;/code&gt;、独立 Scheduler 和 Guider 节点，不必慌张，它只是把 KSampler 内部的几个步骤进一步拆开了，方便更细粒度地控制。&lt;/p&gt;
&lt;h3 id="vae-encode--decode"&gt;VAE Encode / Decode&lt;/h3&gt;
&lt;p&gt;VAE 是像素空间和潜在空间之间的桥梁：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VAE Encode&lt;/code&gt;：图片 → latent，常见于图生图、局部重绘和参考图流程；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VAE Decode&lt;/code&gt;：latent → 图片，是输出最终结果前的必要步骤。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;视频模型也有类似的编解码过程，只不过 latent 多了时间维度。MiniMax H3 还把视频和音频分别交给 video VAE、audio VAE 处理，因此我的 H3 模型目录里会同时出现两套 VAE。&lt;/p&gt;
&lt;h3 id="lora-与其他控制节点"&gt;LoRA 与其他控制节点&lt;/h3&gt;
&lt;p&gt;LoRA 可以在不替换基础模型的情况下调整风格、角色或特定能力。ControlNet、参考图编码、遮罩和预处理器则会给生成过程增加姿态、边缘、深度或局部区域等约束。&lt;/p&gt;
&lt;p&gt;这些模块正是节点式工作流的优势：不需要重写整条链路，只要把新模块接到合适的位置即可。&lt;/p&gt;
&lt;h2 id="我使用的图片模型flux2-dev-fp8"&gt;我使用的图片模型：FLUX.2 Dev FP8&lt;/h2&gt;
&lt;p&gt;这次图片生成使用的是 &lt;strong&gt;FLUX.2 Dev&lt;/strong&gt;。官方的 &lt;a href="https://docs.comfy.org/tutorials/flux/flux-2-dev"&gt;FLUX.2 ComfyUI 教程&lt;/a&gt;提供了文生图和多参考图模板；我采用的是适合当前集群环境的 FP8 Workflow，主要文件如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/diffusion_models/flux2_dev_fp8mixed.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/text_encoders/mistral_3_small_flux2_fp8.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/vae/flux2-vae.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/loras/Flux2TurboComfyv2.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择 FP8 的主要原因不是“量化后画质更好”，而是它在 A6000 和当前 PyTorch/CUDA 组合下更实用，可以减少显存、内存和加载压力。具体使用时仍然要在速度、显存占用和精度之间做取舍。&lt;/p&gt;
&lt;p&gt;对应的图片 Workflow 可以概括成四个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;模型加载&lt;/strong&gt;：加载 FLUX.2 diffusion model、Mistral 文本编码器、VAE 和可选 Turbo LoRA；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;条件构造&lt;/strong&gt;：编码提示词，准备分辨率、批量大小和初始 latent；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;采样生成&lt;/strong&gt;：设置 seed、steps、guidance 和 scheduler，执行去噪；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解码保存&lt;/strong&gt;：通过 FLUX.2 VAE 解码，再预览或保存图片。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面是 ComfyUI 官方 FLUX.2 文生图模板给出的示例结果：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wangzh12023.github.io/blog/images/comfyui/flux2-text-to-image-workflow.webp" alt="FLUX.2 Dev 文生图示例"&gt;&lt;/p&gt;
&lt;p&gt;我的 Workflow 文件名是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;workflows/image_flux2_fp8.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开以后最常修改的通常不是节点拓扑，而是提示词、分辨率、seed、采样参数以及 LoRA 强度。节点搭好以后，后续生成基本就是在同一张图上不断迭代。&lt;/p&gt;
&lt;h2 id="我使用的视频模型minimax-h3"&gt;我使用的视频模型：MiniMax H3&lt;/h2&gt;
&lt;p&gt;视频部分使用的是 &lt;strong&gt;MiniMax H3 FL2VA&lt;/strong&gt;，准备了两条 Workflow：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;workflows/video_minimax_h3_t2v_fp8_cluster.json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;workflows/video_minimax_h3_i2v_fp8_cluster.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;T2V&lt;/code&gt;（Text to Video）：只有文本提示词，从噪声开始生成视频；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;I2V&lt;/code&gt;（Image to Video）：增加一张起始图片，让画面主体和构图更可控。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我选择 FL2VA，是因为这一套权重可以覆盖文生视频和首帧/末帧条件视频。此次没有下载 Ref2VA，所以这套环境暂时不包含多参考图片、参考视频和参考音频驱动的 Workflow。&lt;/p&gt;
&lt;p&gt;这里也记录一下当时的真实状态：&lt;strong&gt;模型下载、文件校验和 Workflow 改写已经完成，但 MiniMax H3 还没有实际完成一次生成验证。&lt;/strong&gt; 所以这部分更准确地说是“已经准备就绪”，不等于整条 T2V/I2V 链路已经跑通。以后第一次成功生成后，还需要把实际耗时、显存峰值和最终参数补回来。&lt;/p&gt;
&lt;p&gt;使用的主要模型文件是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/diffusion_models/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; minimax_h3_fl2va_pruned_fp8_scaled.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/text_encoders/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI/models/vae/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; minimax_h3_video_vae_fp16.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; minimax_h3_audio_vae_fp32.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MiniMax H3 Workflow 比图片 Workflow 更长，但仍然可以按功能分区理解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;加载区&lt;/strong&gt;：加载 H3 diffusion model、Qwen3-VL 文本编码器和视频/音频 VAE；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输入区&lt;/strong&gt;：填写提示词，选择 T2V 或上传 I2V 首帧；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;规格区&lt;/strong&gt;：设置宽高、时长、帧率以及帧数等参数；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;条件与采样区&lt;/strong&gt;：将文本、图像和时间信息组成 conditioning，再执行视频 latent 的采样；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解码输出区&lt;/strong&gt;：分别解码视频与音频，最后保存或封装输出文件。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;视频的计算量远大于单张图片。分辨率、帧数和时长稍微增加，显存占用和生成时间都会明显上涨。第一次跑新 Workflow 时，最好先用较短时长和较低分辨率确认整条链路能够工作，再逐渐提高参数。&lt;/p&gt;
&lt;p&gt;这次使用 &lt;code&gt;pruned_fp8_scaled&lt;/code&gt;，是因为集群保留了 &lt;code&gt;torch==2.5.1+cu121&lt;/code&gt;，而官方模板中的 &lt;code&gt;pruned_int8_convrot&lt;/code&gt; 更适合较新的 PyTorch/cu130 组合。模型变体必须和硬件、驱动、PyTorch 以及 ComfyUI 版本一起考虑，不能只看文件名里哪个精度更低。&lt;/p&gt;
&lt;h2 id="在集群上运行-comfyui"&gt;在集群上运行 ComfyUI&lt;/h2&gt;
&lt;p&gt;我的工作目录是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/home/wangzh/personal/comfyui-lab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;主要环境为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI: v0.30.2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Conda env: comfyui
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PyTorch: 2.5.1+cu121
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;torchvision: 0.20.1+cu121
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;torchaudio: 2.5.1+cu121
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPU: NVIDIA A6000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之所以使用 ComfyUI &lt;code&gt;v0.30.2&lt;/code&gt;，是因为 MiniMax H3 需要 &lt;code&gt;0.30.0+&lt;/code&gt;；同时集群驱动是 NVIDIA 535 / CUDA 12.2，所以没有为了追新而强行升级整套 CUDA 依赖。&lt;/p&gt;
&lt;h3 id="登录节点负责提交计算节点负责生成"&gt;登录节点负责提交，计算节点负责生成&lt;/h3&gt;
&lt;p&gt;集群通常有登录节点和计算节点。比较合适的分工是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;登录节点：准备环境、下载模型、编辑脚本、提交和查看 Slurm 作业；&lt;/li&gt;
&lt;li&gt;计算节点：获得 GPU 后，真正运行 ComfyUI Server 和模型推理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，不应该在登录节点上直接占用 GPU 或长期跑推理服务。我的启动脚本是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/home/wangzh/personal/comfyui-lab/scripts/run_comfyui_server.sbatch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;脚本默认申请的资源包括：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;partition=normal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;account=wangzh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpu=1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cpus-per-task=2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mem=120G
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;time=02:00:00
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cluster port=48188
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen=127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;例如要启动一个三小时的 ComfyUI 服务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sbatch --time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;03:00:00 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /home/wangzh/personal/comfyui-lab/scripts/run_comfyui_server.sbatch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;作业开始后，ComfyUI 会在获得 GPU 的计算环境中监听 &lt;code&gt;127.0.0.1:48188&lt;/code&gt;。只监听回环地址不会把服务直接暴露到公网或整个集群网络，后面通过 SSH 隧道访问即可。&lt;/p&gt;
&lt;h3 id="从-mac-建立-ssh-端口转发"&gt;从 Mac 建立 SSH 端口转发&lt;/h3&gt;
&lt;p&gt;我在 Mac 上使用的命令是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh -N -L 28188:127.0.0.1:48188 A6000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在 Mac 浏览器中打开：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://127.0.0.1:28188
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这条命令可以拆开理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-N&lt;/code&gt;：只建立隧道，不在远端执行 shell 命令；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-L&lt;/code&gt;：创建本地端口转发；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;28188&lt;/code&gt;：Mac 上监听的本地端口；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;127.0.0.1:48188&lt;/code&gt;：从 SSH 远端视角访问的 ComfyUI 地址；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A6000&lt;/code&gt;：我在 SSH 配置里使用的主机别名。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整个访问链路可以理解为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mac 浏览器
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ http://127.0.0.1:28188
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mac 本地端口 28188
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ SSH tunnel
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A6000 对应的远端环境
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ 127.0.0.1:48188
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ComfyUI Server + Slurm GPU
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有一个容易踩坑的地方：&lt;code&gt;127.0.0.1:48188&lt;/code&gt; 是相对于 SSH 最终连接到的远端主机而言的。如果 &lt;code&gt;A6000&lt;/code&gt; 只会登录到登录节点，而 ComfyUI 实际跑在另一台计算节点，那么还需要让 SSH 经过跳板机连接到计算节点，或者使用集群提供的二段转发脚本。我的环境里可以用项目中的脚本根据 job id 打印正确命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/home/wangzh/personal/comfyui-lab/scripts/print_tunnel_command.sh &amp;lt;job-id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不同集群的网络策略不一样，最可靠的原则是：&lt;strong&gt;先确认 ComfyUI 到底在哪台主机监听，再让隧道的远端终点落到那台主机。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="在-mac-webui-中实际操作"&gt;在 Mac WebUI 中实际操作&lt;/h2&gt;
&lt;p&gt;SSH 隧道建立以后，虽然浏览器开在 Mac 上，但所有模型加载和推理仍发生在集群 GPU 上。Mac 只负责显示 WebUI、上传输入、修改参数和查看结果，因此不需要本地拥有大显存。&lt;/p&gt;
&lt;p&gt;我的日常操作大概是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在登录节点提交 Slurm 作业，等待 GPU 分配；&lt;/li&gt;
&lt;li&gt;确认 ComfyUI Server 已在计算节点启动；&lt;/li&gt;
&lt;li&gt;在 Mac 上执行 SSH 端口转发；&lt;/li&gt;
&lt;li&gt;打开 &lt;code&gt;http://127.0.0.1:28188&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;从 Workflow 面板加载 FLUX.2、H3 T2V 或 H3 I2V；&lt;/li&gt;
&lt;li&gt;修改提示词、图片、分辨率、时长和采样参数；&lt;/li&gt;
&lt;li&gt;点击 &lt;code&gt;Queue&lt;/code&gt;，观察节点依次执行并等待输出；&lt;/li&gt;
&lt;li&gt;保存满意的结果，同时保存对应 Workflow 和 seed。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果一个节点变红，通常可以从三类问题开始排查：模型文件名不匹配、模型目录放错，或者 Workflow 引用了当前环境没有安装的自定义节点。模型很大时，还要留意系统内存、显存以及模型加载时间，不要看到页面暂时没响应就重复点击 Queue。&lt;/p&gt;
&lt;h2 id="让-gpt-或-codex-帮忙搭-workflow"&gt;让 GPT 或 Codex 帮忙搭 Workflow&lt;/h2&gt;
&lt;p&gt;ComfyUI Workflow 本质上是 JSON，因此非常适合让 AI 帮忙做机械工作，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据现有 Workflow 替换模型文件名；&lt;/li&gt;
&lt;li&gt;把 T2V Workflow 改成 I2V；&lt;/li&gt;
&lt;li&gt;增加 LoRA、保存节点、预览节点或固定 seed；&lt;/li&gt;
&lt;li&gt;整理节点位置和分组，让画布更容易读；&lt;/li&gt;
&lt;li&gt;批量检查 Workflow 引用的模型是否真实存在；&lt;/li&gt;
&lt;li&gt;生成不同显存配置对应的 Workflow 版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不过有两个细节需要说清楚。&lt;/p&gt;
&lt;p&gt;第一，给 AI 的应该是 &lt;strong&gt;GUI Workflow JSON&lt;/strong&gt;，而不是只供 API 调用的 prompt JSON。前者包含节点位置、连线、分组和控件值，才能在 WebUI 里正常显示为一张可编辑的节点图。&lt;/p&gt;
&lt;p&gt;第二，文件中的模型名必须和 &lt;code&gt;ComfyUI/models/...&lt;/code&gt; 下的实际文件名完全对应。我的 MiniMax H3 官方模板原本引用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;minimax_h3_fl2va_pruned_int8_convrot.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了适配集群环境，两个 Workflow 都改成了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;minimax_h3_fl2va_pruned_fp8_scaled.safetensors
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成后把 JSON 放到 &lt;code&gt;ComfyUI/user/default/workflows/&lt;/code&gt;，就可以在 WebUI 的 Workflow 列表中直接打开；也可以保存在项目目录，再通过 &lt;code&gt;Workflow -&amp;gt; Open&lt;/code&gt; 导入。&lt;/p&gt;
&lt;p&gt;AI 可以帮忙把积木搭好，但第一次执行仍然要人工检查模型版本、输入输出类型、分辨率、帧数和显存占用。一个 JSON 在结构上合法，不代表它一定适合当前机器。&lt;/p&gt;
&lt;h2 id="一些实际使用建议"&gt;一些实际使用建议&lt;/h2&gt;
&lt;h3 id="先跑通最小版本再追求画质"&gt;先跑通最小版本，再追求画质&lt;/h3&gt;
&lt;p&gt;第一次接触某个模型时，先用官方模板和默认参数跑通。确认模型能加载、采样器能执行、VAE 能解码、结果能保存之后，再增加 LoRA、参考图、放大和后处理。否则一开始堆太多节点，出错时很难知道问题在哪一段。&lt;/p&gt;
&lt;h3 id="把-workflow-和模型清单一起保存"&gt;把 Workflow 和模型清单一起保存&lt;/h3&gt;
&lt;p&gt;只保存 JSON 不够。几个月后重新打开时，最常见的问题就是忘了它依赖哪个模型、模型应该放在哪个目录。最好同时记录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ComfyUI 版本；&lt;/li&gt;
&lt;li&gt;Workflow 文件；&lt;/li&gt;
&lt;li&gt;模型文件名与目录；&lt;/li&gt;
&lt;li&gt;PyTorch/CUDA 环境；&lt;/li&gt;
&lt;li&gt;关键生成参数；&lt;/li&gt;
&lt;li&gt;一张成功输出作为基准。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这次下载完成后，&lt;code&gt;ComfyUI/models&lt;/code&gt; 大约占用了 95 GB。大模型环境很难靠“缺什么再随便下一个”来维护，提前写清清单会省掉很多时间。&lt;/p&gt;
&lt;h3 id="图片记录-seed视频先压低成本"&gt;图片记录 seed，视频先压低成本&lt;/h3&gt;
&lt;p&gt;图片生成中，满意的构图可以先固定 seed，再微调提示词和参数。视频则建议先降低时长和分辨率做预览，因为一次失败生成的成本远高于单张图片。确认动作、镜头和主体稳定以后，再提高规格输出最终版本。&lt;/p&gt;
&lt;h3 id="不要盲目照搬参数"&gt;不要盲目照搬参数&lt;/h3&gt;
&lt;p&gt;网上经常会看到“某个 sampler 最好”“steps 必须多少”“cfg 越高越听话”一类经验。它们往往只对某个具体模型和 Workflow 成立。Stable Diffusion、FLUX.2 和 MiniMax H3 的推荐参数可以完全不同，优先参考模型官方模板，再在自己的硬件上做小范围实验。&lt;/p&gt;
&lt;h2 id="常用链接"&gt;常用链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.comfy.org/"&gt;ComfyUI 官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Comfy-Org/ComfyUI"&gt;ComfyUI 官方 GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.comfy.org/zh"&gt;ComfyUI 中文文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.comfy.org/zh/tutorials/basic/text-to-image"&gt;官方文生图基础教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.comfy.org/zh/tutorials/basic/image-to-image"&gt;官方图生图基础教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.comfy.org/tutorials/flux/flux-2-dev"&gt;FLUX.2 Dev 官方教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://comfyanonymous.github.io/ComfyUI_examples/"&gt;ComfyUI 官方示例集合&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/Comfy-Org/flux2-dev"&gt;Comfy-Org FLUX.2 Dev 模型文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/Comfy-Org/MiniMax-H3"&gt;Comfy-Org MiniMax H3 模型文件&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;ComfyUI 的门槛主要来自第一眼看到的节点和连线，但它的核心逻辑其实很清楚：&lt;strong&gt;加载模型，准备条件，在 latent 中采样，再把结果解码并保存。&lt;/strong&gt; 图片和视频的差别主要在模型、条件、latent 维度和输出编码，Workflow 的组织方式是相通的。&lt;/p&gt;
&lt;p&gt;对我来说，集群上的这套用法也很舒服。GPU 和大模型留在服务器，Mac 只通过 SSH 隧道访问 WebUI；Workflow 可以交给 GPT 或 Codex 辅助搭建，自己则在浏览器里调整和试验。环境配置完成以后，生成图片和视频就不再是一串难以维护的命令，而是一张可以看见、可以修改、也可以保存下来的流程图。&lt;/p&gt;
&lt;p&gt;从这个角度看，ComfyUI 最吸引人的地方可能不只是“能生成图片和视频”，而是它让生成过程本身也变成了一件可以观察和搭建的东西。&lt;/p&gt;</description></item><item><title>GSPO：Group Sequence Policy Optimization 详解</title><link>https://wangzh12023.github.io/blog/blog/gspo/</link><pubDate>Tue, 18 Aug 2026 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/gspo/</guid><description>&lt;p&gt;GSPO（&lt;strong&gt;Group Sequence Policy Optimization&lt;/strong&gt;）是 Qwen 团队在 2025 年提出的一种用于 LLM 强化学习后训练的策略优化算法。它直接建立在 GRPO 的框架之上，但做了一个非常关键的改变：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GRPO 在 token level 计算 importance ratio 并进行 clipping；GSPO 将 importance ratio、clipping 和主要优化单位统一提升到了 sequence level。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此，理解 GSPO 最重要的并不是记住一个新的 loss，而是理解这一变化：&lt;/p&gt;
$$
\boxed{
\text{token-level policy correction}
\quad\longrightarrow\quad
\text{sequence-level policy correction}
}
$$&lt;p&gt;Qwen 团队提出 GSPO 的主要目标，是解决大规模 LLM RL，特别是 &lt;strong&gt;长 CoT + MoE 模型&lt;/strong&gt;训练过程中 GRPO 出现的高方差和训练不稳定问题。原论文报告 GSPO 相比 GRPO 有更好的训练稳定性和效率，并且不再需要 Qwen 此前为 MoE RL 引入的 Routing Replay。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="1-gspo-从哪里来"&gt;1. GSPO 从哪里来？&lt;/h1&gt;
&lt;p&gt;从算法演化关系看，可以简单理解成：&lt;/p&gt;
$$
\boxed{
\text{PPO}
\rightarrow
\text{GRPO}
\rightarrow
\text{GSPO}
}
$$&lt;p&gt;但三者解决的问题不同。&lt;/p&gt;
&lt;h2 id="11-ppo"&gt;1.1 PPO&lt;/h2&gt;
&lt;p&gt;对于一个 prompt：&lt;/p&gt;
$$
x
$$&lt;p&gt;模型生成 response：&lt;/p&gt;
$$
y=(y_1,\dots,y_T)
$$&lt;p&gt;语言模型定义：&lt;/p&gt;
$$
\pi_\theta(y|x) =
\prod_{t=1}^{T}
\pi_\theta(y_t|x,y_{&amp;lt;t})
$$&lt;p&gt;PPO 对每一个 token 定义 importance ratio：&lt;/p&gt;
$$
w_t(\theta) =
\frac{
\pi_\theta(y_t|x,y_{&amp;lt;t})
}{
\pi_{\theta_{\mathrm{old}}}(y_t|x,y_{&amp;lt;t})
}
$$&lt;p&gt;然后执行 clipped policy optimization：&lt;/p&gt;
$$
J_{\mathrm{PPO}}(\theta) =
\mathbb{E}
\left[
\frac1T
\sum_{t=1}^{T}
\min
\left(
w_t\hat A_t,
\operatorname{clip}(w_t,1-\epsilon,1+\epsilon)\hat A_t
\right)
\right]
$$&lt;p&gt;PPO 的重要特点是：&lt;/p&gt;
$$
\boxed{\text{token-level advantage}+\text{token-level ratio}}
$$&lt;p&gt;其中 $(\hat A_t)$ 通常需要 Value Model / Critic 进行估计。对于 LLM，这意味着除了 Policy Model，通常还需要维护一个规模相当大的 Value Model，带来显著的计算和显存开销。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="2-grpo-做了什么"&gt;2. GRPO 做了什么？&lt;/h1&gt;
&lt;p&gt;GRPO 最重要的变化其实不是 importance ratio，而是：&lt;/p&gt;
$$
\boxed{\text{去掉 Value Model}}
$$&lt;p&gt;对于同一个 prompt $(x)$，从 old policy 中采样 $(G)$ 个 response：&lt;/p&gt;
$$
y_1,\dots,y_G
\sim
\pi_{\theta_{\mathrm{old}}}(\cdot|x)
$$&lt;p&gt;分别得到：&lt;/p&gt;
$$
r_1,\dots,r_G
$$&lt;p&gt;然后使用组内 reward normalization：&lt;/p&gt;
$$
\hat A_i =
\frac{
r_i-\operatorname{mean}(r_1,\dots,r_G)
}{
\operatorname{std}(r_1,\dots,r_G)
}
$$&lt;p&gt;于是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reward 高于组平均值：&lt;/li&gt;
&lt;/ul&gt;
$$
\hat A_i&gt;0
$$&lt;p&gt;希望提高这个 response 的概率；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reward 低于组平均值：&lt;/li&gt;
&lt;/ul&gt;
$$
\hat A_i&amp;lt;0
$$&lt;p&gt;希望降低这个 response 的概率。&lt;/p&gt;
&lt;p&gt;GRPO 的关键特点是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一个 response 中的所有 token 都共享同一个 sequence-level advantage：&lt;/p&gt;
&lt;/blockquote&gt;
$$
\hat A_{i,t}=\hat A_i
$$&lt;p&gt;但是它仍然为每个 token 计算独立 importance ratio：&lt;/p&gt;
$$
w_{i,t} =
\frac{
\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
}{
\pi_{\theta_{\mathrm{old}}}(y_{i,t}|x,y_{i,&amp;lt;t})
}
$$&lt;p&gt;所以 GRPO objective 是：&lt;/p&gt;
$$
J_{\mathrm{GRPO}}(\theta) =
\mathbb{E}
\left[
\frac1G
\sum_{i=1}^{G}
\frac1{|y_i|}
\sum_{t=1}^{|y_i|}
\min
\left(
w_{i,t}\hat A_i,
\operatorname{clip}(w_{i,t},1-\epsilon,1+\epsilon)\hat A_i
\right)
\right]
$$&lt;p&gt;也就是说：&lt;/p&gt;
$$
\boxed{
\text{sequence-level reward/advantage} +
\text{token-level importance ratio}
}
$$&lt;p&gt;这正是 GSPO 认为有问题的地方。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="3-gspo-认为-grpo-的核心问题是什么"&gt;3. GSPO 认为 GRPO 的核心问题是什么？&lt;/h1&gt;
&lt;p&gt;GSPO 论文提出了一个核心原则：&lt;/p&gt;
$$
\boxed{
\text{Unit of Optimization}
\approx
\text{Unit of Reward}
}
$$&lt;p&gt;即：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;reward 如果是针对整条 sequence 给出的，那么用于 off-policy correction 和 clipping 的单位也应该对应整条 sequence。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GRPO 的 reward 是：&lt;/p&gt;
$$
r(x,y_i)
$$&lt;p&gt;也就是说 verifier 实际评价的是：&lt;/p&gt;
$$
\boxed{\text{整个 response}}
$$&lt;p&gt;例如数学 RLVR：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“最终答案对不对？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;reward 可能就是：&lt;/p&gt;
$$
r(x,y) =
\begin{cases}
1 &amp; \text{correct}\\
0 &amp; \text{wrong}
\end{cases}
$$&lt;p&gt;reward 并没有告诉模型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;token 37 是好的；&lt;/li&gt;
&lt;li&gt;token 82 是坏的；&lt;/li&gt;
&lt;li&gt;token 151 应该增加概率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是 GRPO 的 off-policy correction 却变成：&lt;/p&gt;
$$
w_{i,1},w_{i,2},\dots,w_{i,T}
$$&lt;p&gt;即：&lt;/p&gt;
$$
\boxed{\text{一个 sequence reward，却产生了大量 token-wise importance weights}}
$$&lt;p&gt;GSPO 作者认为，这会向 gradient 中引入大量没有可靠统计支撑的 token-level variance，且这种噪声随着 response 变长而累积。&lt;/p&gt;
&lt;p&gt;这里需要一个准确性上的区分：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“token-level importance sampling 本身在强化学习中是不成立的”并不是一个普遍结论。&lt;/strong&gt; Per-decision importance sampling 在合适的 RL formulation 中完全可以有理论依据。&lt;/p&gt;
&lt;p&gt;更准确地说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这是 GSPO 作者针对当前 GRPO formulation 提出的批评：GRPO 给 sequence-level reward/advantage，却使用每个位置单独的一次 token sample 构造 token ratio 并直接用来重新加权梯度；他们认为这种设计在大规模 LLM RL 中会产生高方差和不稳定性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 GSPO 论文的算法观点，而不应扩展成“所有 token-level IS 都是错误的”。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="4-gspo-的核心sequence-level-importance-ratio"&gt;4. GSPO 的核心：Sequence-level Importance Ratio&lt;/h1&gt;
&lt;p&gt;对于 response：&lt;/p&gt;
$$
y_i=(y_{i,1},\dots,y_{i,T_i})
$$&lt;p&gt;完整 sequence probability：&lt;/p&gt;
$$
\pi_\theta(y_i|x) =
\prod_{t=1}^{T_i}
\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
$$&lt;p&gt;如果直接构造整个 trajectory 的 likelihood ratio：&lt;/p&gt;
$$
R_i =
\frac{
\pi_\theta(y_i|x)
}{
\pi_{\theta_{\mathrm{old}}}(y_i|x)
}
$$&lt;p&gt;那么：&lt;/p&gt;
$$
R_i =
\prod_{t=1}^{T_i}
\frac{
\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
}{
\pi_{\theta_{\mathrm{old}}}(y_{i,t}|x,y_{i,&amp;lt;t})
}
$$&lt;p&gt;也就是：&lt;/p&gt;
$$
R_i =
\prod_t w_{i,t}
$$&lt;p&gt;但是这里立刻出现一个问题：&lt;/p&gt;
&lt;h3 id="sequence-越长product-的数值波动越严重"&gt;sequence 越长，product 的数值波动越严重。&lt;/h3&gt;
&lt;p&gt;例如：&lt;/p&gt;
$$
1.01^{1000}\approx 20959
$$&lt;p&gt;即使每个 token 的概率只发生很小的变化，乘 1000 次以后整个 sequence ratio 都可能变得极端。&lt;/p&gt;
&lt;p&gt;因此 GSPO &lt;strong&gt;并不直接使用原始 trajectory ratio&lt;/strong&gt;，而是使用长度归一化：&lt;/p&gt;
$$
\boxed{
s_i(\theta) =
\left(
\frac{
\pi_\theta(y_i|x)
}{
\pi_{\theta_{\mathrm{old}}}(y_i|x)
}
\right)^{1/T_i}
}
$$&lt;p&gt;展开：&lt;/p&gt;
$$
s_i(\theta) =
\left(
\prod_{t=1}^{T_i}w_{i,t}
\right)^{1/T_i}
$$&lt;p&gt;也就是说：&lt;/p&gt;
$$
\boxed{
s_i =
\operatorname{GeometricMean}
(w_{i,1},\dots,w_{i,T_i})
}
$$&lt;p&gt;或者在 log space：&lt;/p&gt;
$$
\boxed{
\log s_i =
\frac1{T_i}
\sum_{t=1}^{T_i}
\left[
\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t}) -
\log\pi_{\theta_{\mathrm{old}}}(y_{i,t}|x,y_{i,&amp;lt;t})
\right]
}
$$&lt;p&gt;最终：&lt;/p&gt;
$$
s_i =
\exp(\log s_i)
$$&lt;p&gt;这就是 GSPO 最核心的公式。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="5-为什么一定要做-length-normalization"&gt;5. 为什么一定要做 Length Normalization？&lt;/h1&gt;
&lt;p&gt;如果直接：&lt;/p&gt;
$$
R_i =
\frac{\pi_\theta(y_i|x)}
{\pi_{\mathrm{old}}(y_i|x)}
$$&lt;p&gt;那么不同长度 response 的 ratio 无法直接使用相同 clipping range。&lt;/p&gt;
&lt;p&gt;例如两个 sequence 的平均 token probability change 完全相同：&lt;/p&gt;
$$
w_t=1.001
$$&lt;p&gt;但一个长度：&lt;/p&gt;
$$
T=100
$$&lt;p&gt;另一个：&lt;/p&gt;
$$
T=2000
$$&lt;p&gt;则：&lt;/p&gt;
$$
R_{100}=1.001^{100}
$$&lt;p&gt;而：&lt;/p&gt;
$$
R_{2000}=1.001^{2000}
$$&lt;p&gt;两者会出现非常大的差异。&lt;/p&gt;
&lt;p&gt;但做 geometric mean 后：&lt;/p&gt;
$$
s =
R^{1/T}
1.001
$$&lt;p&gt;于是：&lt;/p&gt;
$$
\boxed{\text{sequence length 对 importance ratio scale 的影响基本被消除}}
$$&lt;p&gt;Qwen 论文明确指出，length normalization 的目的就是降低 variance，同时让不同长度 response 的 importance ratio 落在统一的 numerical range 中。&lt;/p&gt;
&lt;p&gt;因此严格来说，GSPO 使用的是：&lt;/p&gt;
$$
\boxed{\text{length-normalized sequence likelihood ratio}}
$$&lt;p&gt;而不是原始 importance sampling 中未经修改的：&lt;/p&gt;
$$
\frac{\pi_\theta(y|x)}
{\pi_{\mathrm{old}}(y|x)}
$$&lt;p&gt;这个区别很重要。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="6-gspo-objective"&gt;6. GSPO Objective&lt;/h1&gt;
&lt;p&gt;GSPO 保留了 GRPO 的 group advantage：&lt;/p&gt;
$$
\hat A_i =
\frac{
r(x,y_i)-\operatorname{mean}_j r(x,y_j)
}{
\operatorname{std}_j r(x,y_j)
}
$$&lt;p&gt;但是将 token ratio 替换成 sequence ratio：&lt;/p&gt;
$$
s_i(\theta) =
\left(
\frac{\pi_\theta(y_i|x)}
{\pi_{\mathrm{old}}(y_i|x)}
\right)^{1/T_i}
$$&lt;p&gt;最终 objective：&lt;/p&gt;
$$
\boxed{
J_{\mathrm{GSPO}}(\theta) =
\mathbb{E}
\left[
\frac1G
\sum_{i=1}^{G}
\min
\left(
s_i(\theta)\hat A_i,
\operatorname{clip}
\left(
s_i(\theta),
1-\epsilon,
1+\epsilon
\right)
\hat A_i
\right)
\right]
}
$$&lt;p&gt;与 GRPO 对比：&lt;/p&gt;
&lt;h3 id="grpo"&gt;GRPO&lt;/h3&gt;
$$
\frac1T
\sum_t
\min
\left(
w_{i,t}A_i,
\operatorname{clip}(w_{i,t})A_i
\right)
$$&lt;h3 id="gspo"&gt;GSPO&lt;/h3&gt;
$$
\min
\left(
s_iA_i,
\operatorname{clip}(s_i)A_i
\right)
$$&lt;p&gt;所以最本质的变化就是：&lt;/p&gt;
$$
\boxed{
{w_{i,1},w_{i,2},\dots,w_{i,T}}
\rightarrow
s_i
}
$$&lt;p&gt;整条 sequence 只对应一个 importance ratio。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="7-sequence-level-clipping-到底是什么意思"&gt;7. Sequence-level Clipping 到底是什么意思？&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
$$
\hat A_i&gt;0
$$&lt;p&gt;说明这个 response 比同组其他 response 更好。&lt;/p&gt;
&lt;p&gt;我们希望：&lt;/p&gt;
$$
\pi_\theta(y_i|x)\uparrow
$$&lt;p&gt;如果：&lt;/p&gt;
$$
s_i&gt;1+\epsilon
$$&lt;p&gt;意味着 current policy 已经把这条 response 的相对概率提高得足够多。&lt;/p&gt;
&lt;p&gt;于是：&lt;/p&gt;
$$
\operatorname{clip}(s_i) =
1+\epsilon
$$&lt;p&gt;后续不再继续鼓励它。&lt;/p&gt;
&lt;p&gt;反过来，如果：&lt;/p&gt;
$$
\hat A_i&amp;lt;0
$$&lt;p&gt;说明这是一个较差 response，我们希望：&lt;/p&gt;
$$
\pi_\theta(y_i|x)\downarrow
$$&lt;p&gt;当：&lt;/p&gt;
$$
s_i&amp;lt;1-\epsilon
$$&lt;p&gt;说明它已经被降低得足够多，于是停止进一步惩罚。&lt;/p&gt;
&lt;p&gt;所以 PPO、GRPO 和 GSPO 都可以理解为：&lt;/p&gt;
$$
\boxed{\text{不要让一次 policy update 离 rollout policy 太远}}
$$&lt;p&gt;区别只是这个“距离”在哪里判断：&lt;/p&gt;
$$
\begin{array}{c|c}
\text{Algorithm} &amp; \text{Clipping Granularity}\\
\hline
\text{PPO} &amp; Token\\
\text{GRPO} &amp; Token\\
\text{GSPO} &amp; Sequence
\end{array}
$$&lt;hr&gt;
&lt;h1 id="8-gspo-与-grpo-最大的数学区别gradient-weight"&gt;8. GSPO 与 GRPO 最大的数学区别：Gradient Weight&lt;/h1&gt;
&lt;p&gt;这一部分实际上是理解 GSPO 最关键的地方。&lt;/p&gt;
&lt;p&gt;先暂时忽略 clipping。&lt;/p&gt;
&lt;p&gt;GSPO：&lt;/p&gt;
$$
J =
s_i(\theta)\hat A_i
$$&lt;p&gt;所以：&lt;/p&gt;
$$
\nabla_\theta J =
\hat A_i\nabla_\theta s_i
$$&lt;p&gt;利用：&lt;/p&gt;
$$
\nabla s=s\nabla\log s
$$&lt;p&gt;得到：&lt;/p&gt;
$$
\nabla_\theta J =
s_i\hat A_i
\nabla_\theta\log s_i
$$&lt;p&gt;而：&lt;/p&gt;
$$
\log s_i =
\frac1{T_i}
\sum_t
\left(
\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t}) -
\log\pi_{\mathrm{old}}(\cdots)
\right)
$$&lt;p&gt;old policy 与 $(\theta)$ 无关，所以：&lt;/p&gt;
$$
\nabla_\theta\log s_i =
\frac1{T_i}
\sum_t
\nabla_\theta
\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
$$&lt;p&gt;最终：&lt;/p&gt;
$$
\boxed{
\nabla_\theta J_{\mathrm{GSPO}} =
s_i\hat A_i
\frac1{T_i}
\sum_t
\nabla_\theta
\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
}
$$&lt;p&gt;注意：&lt;/p&gt;
$$
s_i\hat A_i
$$&lt;p&gt;对于这条 response 中所有 token 是&lt;strong&gt;完全相同的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;因此每个 token gradient：&lt;/p&gt;
$$
\nabla\log\pi_\theta(y_{i,t}|\cdots)
$$&lt;p&gt;都获得同样的 sequence-level weight：&lt;/p&gt;
$$
\boxed{s_i\hat A_i}
$$&lt;hr&gt;
&lt;h1 id="9-再看-grpo-的-gradient"&gt;9. 再看 GRPO 的 Gradient&lt;/h1&gt;
&lt;p&gt;GRPO：&lt;/p&gt;
$$
J =
\frac1T
\sum_t w_{i,t}\hat A_i
$$&lt;p&gt;因此：&lt;/p&gt;
$$
\boxed{
\nabla_\theta J_{\mathrm{GRPO}} =
\hat A_i
\frac1T
\sum_t
w_{i,t}
\nabla_\theta
\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
}
$$&lt;p&gt;这里最大的区别出现了。&lt;/p&gt;
&lt;p&gt;GRPO：&lt;/p&gt;
$$
w_{i,1},
w_{i,2},
\dots,
w_{i,T}
$$&lt;p&gt;每个 token 的 gradient 权重都不一样：&lt;/p&gt;
$$
w_{i,t}\hat A_i
$$&lt;p&gt;而 GSPO：&lt;/p&gt;
$$
s_i,s_i,\dots,s_i
$$&lt;p&gt;所有 token 都使用：&lt;/p&gt;
$$
s_i\hat A_i
$$&lt;p&gt;所以：&lt;/p&gt;
$$
\boxed{
\begin{aligned}
\text{GRPO: }&amp;
w_{i,t}\hat A_i
\nabla\log\pi_\theta(y_{i,t})\\[2mm]
\text{GSPO: }&amp;
s_i\hat A_i
\nabla\log\pi_\theta(y_{i,t})
\end{aligned}
}
$$&lt;p&gt;这实际上比单纯说“GSPO 是 sequence clipping”更能说明算法本质。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="10-一个直观例子"&gt;10. 一个直观例子&lt;/h1&gt;
&lt;p&gt;假设一条 response 有四个 token，对应 old policy → current policy 的 token ratios：&lt;/p&gt;
$$
[1.10,\ 0.90,\ 1.05,\ 0.95]
$$&lt;p&gt;GRPO 会分别使用：&lt;/p&gt;
$$
1.10,\quad0.90,\quad1.05,\quad0.95
$$&lt;p&gt;来 weight 四个 token 的 gradients。&lt;/p&gt;
&lt;p&gt;而 GSPO：&lt;/p&gt;
$$
s =
(1.10\times0.90\times1.05\times0.95)^{1/4}
$$&lt;p&gt;大约为：&lt;/p&gt;
$$
s\approx0.997
$$&lt;p&gt;于是四个 token 都使用：&lt;/p&gt;
$$
0.997\hat A
$$&lt;p&gt;作为 sequence-level coefficient。&lt;/p&gt;
&lt;p&gt;从整条 response 看：&lt;/p&gt;
$$
s\approx1
$$&lt;p&gt;意味着：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;old policy 和 current policy 对这条完整 response 的平均 likelihood 基本没有变化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GSPO 因此不会因为其中某一个 token 的 ratio 是 1.10、另一个是 0.90，就对不同 token 施加非常不同的 off-policy correction。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="11-gspo-其实非常接近一种-sequence-level-reinforce"&gt;11. GSPO 其实非常接近一种 Sequence-level REINFORCE&lt;/h1&gt;
&lt;p&gt;这是从公式可以直接得到的一个理解。&lt;/p&gt;
&lt;p&gt;考虑：&lt;/p&gt;
$$
\theta=\theta_{\mathrm{old}}
$$&lt;p&gt;此时：&lt;/p&gt;
$$
s_i=1
$$&lt;p&gt;忽略 clipping：&lt;/p&gt;
$$
\nabla J_{\mathrm{GSPO}} =
\hat A_i
\frac1T
\sum_t
\nabla_\theta\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
$$&lt;p&gt;而：&lt;/p&gt;
$$
\sum_t
\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t}) =
\log\pi_\theta(y_i|x)
$$&lt;p&gt;于是：&lt;/p&gt;
$$
\nabla J =
\frac{\hat A_i}{T}
\nabla_\theta
\log\pi_\theta(y_i|x)
$$&lt;p&gt;所以从这个角度，可以将 GSPO 理解为：&lt;/p&gt;
$$
\boxed{
\text{Group-normalized sequence REINFORCE} +
\text{sequence-level off-policy correction} +
\text{PPO-style clipping}
}
$$&lt;p&gt;其中 group baseline 来自同 prompt 的多个 sampled responses。&lt;/p&gt;
&lt;p&gt;这个理解通常比单独记忆 GSPO loss 更容易把 GSPO 放到 RL 的整体框架里。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="12-为什么-gspo-对-long-cot-更稳定"&gt;12. 为什么 GSPO 对 Long CoT 更稳定？&lt;/h1&gt;
&lt;p&gt;假设一个 reasoning response 有：&lt;/p&gt;
$$
T=8000
$$&lt;p&gt;个 tokens。&lt;/p&gt;
&lt;p&gt;GRPO 会产生：&lt;/p&gt;
$$
8000
$$&lt;p&gt;个不同的：&lt;/p&gt;
$$
w_t
$$&lt;p&gt;因此 gradient 类似：&lt;/p&gt;
$$
\sum_{t=1}^{8000}
w_t A\nabla\log\pi_t
$$&lt;p&gt;其中某些：&lt;/p&gt;
$$
w_t\gg1
$$&lt;p&gt;某些：&lt;/p&gt;
$$
w_t\ll1
$$&lt;p&gt;而且不同 token 会单独触发 clipping。&lt;/p&gt;
&lt;p&gt;随着 sequence 变长，这种 token-level variation 会不断累积。&lt;/p&gt;
&lt;p&gt;GSPO 则先将它们压缩成：&lt;/p&gt;
$$
s =
\exp
\left(
\frac1T
\sum_t\log w_t
\right)
$$&lt;p&gt;然后：&lt;/p&gt;
$$
\nabla J
\propto
sA
\frac1T
\sum_t\nabla\log\pi_t
$$&lt;p&gt;因此它实际上在问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“current policy 整体上对这条 reasoning trajectory 的 likelihood 改变了多少？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“第 5387 个 token 的 probability 改了多少？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对于只有 sequence-level verifier reward 的数学、代码等 RLVR 场景，这种 granularity 与 reward granularity 更自然地对齐。这正是 GSPO 的核心设计逻辑。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="13-为什么-gspo-对-moe-特别重要"&gt;13. 为什么 GSPO 对 MoE 特别重要？&lt;/h1&gt;
&lt;p&gt;这是 GSPO 论文非常重要的一部分。&lt;/p&gt;
&lt;p&gt;对于 Dense Transformer：&lt;/p&gt;
$$
x
\rightarrow
\text{固定的全部参数}
$$&lt;p&gt;每次 forward 使用的 network structure 基本一致。&lt;/p&gt;
&lt;p&gt;但对于 MoE：&lt;/p&gt;
$$
x_t
\rightarrow
\text{Router}
\rightarrow
\text{Expert}_{k_1},\text{Expert}_{k_2}
$$&lt;p&gt;每个 token 激活哪些 experts 是动态的。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
$$
\pi_{\mathrm{old}}
$$&lt;p&gt;生成 rollout 时可能使用：&lt;/p&gt;
$$
E_3,E_7
$$&lt;p&gt;而做几次 gradient update 以后，同样的 token 在：&lt;/p&gt;
$$
\pi_\theta
$$&lt;p&gt;里可能变成：&lt;/p&gt;
$$
E_2,E_7
$$&lt;p&gt;Qwen 在 Qwen3-30B-A3B-Base 上观察到：一次 RL gradient update 后，对于同一个 rollout sample，新旧 policy 激活的 experts 中大约有 &lt;strong&gt;10% 发生变化&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这会使：&lt;/p&gt;
$$
\frac{
\pi_\theta(y_t|x,y_{&amp;lt;t})
}{
\pi_{\mathrm{old}}(y_t|x,y_{&amp;lt;t})
}
$$&lt;p&gt;发生明显波动。&lt;/p&gt;
&lt;p&gt;问题不仅仅是参数改变了，而是：&lt;/p&gt;
$$
\boxed{\text{实际参与计算的 expert network 也可能改变}}
$$&lt;p&gt;因此 token ratio 可能非常 noisy。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="14-routing-replay-是什么"&gt;14. Routing Replay 是什么？&lt;/h1&gt;
&lt;p&gt;在 GSPO 之前，Qwen 为解决这个问题采用过 &lt;strong&gt;Routing Replay&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;rollout 时记录：&lt;/p&gt;
$$
\pi_{\mathrm{old}}
$$&lt;p&gt;每个 token 激活了哪些 experts。&lt;/p&gt;
&lt;p&gt;计算 current policy probability 时，不允许 router 重新选择 experts，而是 replay old routing：&lt;/p&gt;
$$
\text{route}_{\theta}
\leftarrow
\text{route}_{\theta_{\mathrm{old}}}
$$&lt;p&gt;于是比较：&lt;/p&gt;
$$
\pi_\theta(y_t)
$$&lt;p&gt;与：&lt;/p&gt;
$$
\pi_{\mathrm{old}}(y_t)
$$&lt;p&gt;时，两者使用相同的 expert topology。&lt;/p&gt;
&lt;p&gt;这样：&lt;/p&gt;
$$
w_t =
\frac{\pi_\theta(y_t)}
{\pi_{\mathrm{old}}(y_t)}
$$&lt;p&gt;会稳定很多。&lt;/p&gt;
&lt;p&gt;论文实验中，GRPO 在 Qwen 的 MoE setting 下如果去掉 Routing Replay，training reward 明显恶化；加入 Routing Replay 后才可以正常训练。&lt;/p&gt;
&lt;p&gt;但 Routing Replay 有代价：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rollout 需要额外缓存 routing information；&lt;/li&gt;
&lt;li&gt;增加通信和 memory overhead；&lt;/li&gt;
&lt;li&gt;training pipeline 更复杂；&lt;/li&gt;
&lt;li&gt;current policy 不能完全自由使用当前 router；&lt;/li&gt;
&lt;li&gt;一定程度上限制 MoE 自身动态 routing 的能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id="15-gspo-为什么可以不需要-routing-replay"&gt;15. GSPO 为什么可以不需要 Routing Replay？&lt;/h1&gt;
&lt;p&gt;因为 GSPO 不关心单个 token：&lt;/p&gt;
$$
w_t
$$&lt;p&gt;而只关心：&lt;/p&gt;
$$
s_i =
\exp
\left(
\frac1T\sum_t\log w_t
\right)
$$&lt;p&gt;单个 token 因为 expert routing change 导致：&lt;/p&gt;
$$
w_t
$$&lt;p&gt;突然变大或者变小，对整个 sequence 的影响会被 sequence aggregation 稀释。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
$$
w=
[
1.00,
1.01,
0.99,
1.02,
\boxed{1.30},
1.00,
0.98,\dots
]
$$&lt;p&gt;GRPO 会直接让：&lt;/p&gt;
$$
1.30
$$&lt;p&gt;参与这个 token 的梯度。&lt;/p&gt;
&lt;p&gt;GSPO 使用的是：&lt;/p&gt;
$$
\exp(\operatorname{mean}\log w_t)
$$&lt;p&gt;如果 sequence 很长，一个 token 的异常值影响相对有限。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
$$
\boxed{
\text{GSPO 对 individual token likelihood fluctuation 更不敏感}
}
$$&lt;p&gt;Qwen 的实验显示 GSPO 可以在不使用 Routing Replay 的情况下稳定训练其 MoE 模型。作者将这一点视为 GSPO 对大规模 MoE RL 最重要的优势之一。&lt;/p&gt;
&lt;p&gt;这里同样需要保持表述准确：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;实验表明 GSPO 在 Qwen 的 MoE RL setting 中解决了 Routing Replay 依赖；这不等价于已经证明所有 MoE、所有 RL pipeline 都绝不会出现 routing-related instability。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h1 id="16-一个非常反直觉的实验gspo-clip-得更多反而训得更好"&gt;16. 一个非常反直觉的实验：GSPO Clip 得更多，反而训得更好&lt;/h1&gt;
&lt;p&gt;Qwen 论文里有一个很有意思的结果。&lt;/p&gt;
&lt;p&gt;平均 clipping fraction：&lt;/p&gt;
$$
\text{GRPO}\approx0.0013
$$&lt;p&gt;而：&lt;/p&gt;
$$
\text{GSPO}\approx0.15
$$&lt;p&gt;也就是说，GSPO 大约有：&lt;/p&gt;
$$
15%
$$&lt;p&gt;的 tokens 因为所在 sequence 被 clipping，而 GRPO 只有大约：&lt;/p&gt;
$$
0.13%
$$&lt;p&gt;的 token 被 clip。&lt;/p&gt;
&lt;p&gt;GSPO clipping 的数据明显更多。&lt;/p&gt;
&lt;p&gt;但实验中 GSPO 的 training efficiency 反而更高。&lt;/p&gt;
&lt;p&gt;作者据此认为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GRPO 虽然“用了更多 token”，但其中相当一部分 token-level gradient signal 本身非常 noisy；GSPO 丢掉了更多 off-policy sequences，却留下了质量更可靠的 gradient。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以：&lt;/p&gt;
$$
\boxed{
\text{More training tokens}
\not\Rightarrow
\text{Better gradient estimation}
}
$$&lt;p&gt;重要的是：&lt;/p&gt;
$$
\text{signal quality}
$$&lt;p&gt;而不是单纯 sample utilization。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="17-gspo-的-clip-range-和-grpo-完全不是一个量级"&gt;17. GSPO 的 Clip Range 和 GRPO 完全不是一个量级&lt;/h1&gt;
&lt;p&gt;这一点实现时非常重要。&lt;/p&gt;
&lt;p&gt;Qwen 的实验中：&lt;/p&gt;
&lt;p&gt;GSPO 使用 asymmetric clipping：&lt;/p&gt;
$$
\epsilon_{\mathrm{low}} =
3\times10^{-4}
$$$$
\epsilon_{\mathrm{high}} =
4\times10^{-4}
$$&lt;p&gt;大致就是：&lt;/p&gt;
$$
s_i
\in
[
1-3\times10^{-4},
1+4\times10^{-4}
]
$$&lt;p&gt;而 GRPO 使用：&lt;/p&gt;
$$
0.2,\quad0.27
$$&lt;p&gt;这种量级。&lt;/p&gt;
&lt;p&gt;不要看到 GSPO 也是 PPO-style clipping，就直接照搬：&lt;/p&gt;
$$
\epsilon=0.2
$$&lt;p&gt;原因是两种 ratio 根本不是同一个量：&lt;/p&gt;
&lt;p&gt;GRPO：&lt;/p&gt;
$$
w_t
$$&lt;p&gt;GSPO：&lt;/p&gt;
$$
s=
\exp
\left(
\operatorname{mean}_t\log w_t
\right)
$$&lt;p&gt;GSPO 的 sequence-normalized ratio 通常非常接近：&lt;/p&gt;
$$
1
$$&lt;p&gt;所以 clipping range 会小几个数量级。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="18-gspo-完整训练流程"&gt;18. GSPO 完整训练流程&lt;/h1&gt;
&lt;p&gt;对于一个训练 batch：&lt;/p&gt;
&lt;h2 id="step-1采样-prompt"&gt;Step 1：采样 Prompt&lt;/h2&gt;
$$
x\sim\mathcal D
$$&lt;hr&gt;
&lt;h2 id="step-2rollout"&gt;Step 2：Rollout&lt;/h2&gt;
&lt;p&gt;使用：&lt;/p&gt;
$$
\pi_{\theta_{\mathrm{old}}}
$$&lt;p&gt;对同一个 prompt 生成 $(G)$ 条 response：&lt;/p&gt;
$$
y_1,\dots,y_G
$$&lt;hr&gt;
&lt;h2 id="step-3计算-reward"&gt;Step 3：计算 Reward&lt;/h2&gt;
&lt;p&gt;例如数学 RLVR：&lt;/p&gt;
$$
r_i =
\mathbb{1}[\text{answer correct}]
$$&lt;p&gt;或者：&lt;/p&gt;
$$
r_i =
r_{\mathrm{correct}} +
r_{\mathrm{format}}
+\cdots
$$&lt;hr&gt;
&lt;h2 id="step-4计算-group-advantage"&gt;Step 4：计算 Group Advantage&lt;/h2&gt;
$$
\mu_r =
\frac1G
\sum_i r_i
$$$$
\sigma_r =
\operatorname{std}(r_1,\dots,r_G)
$$$$
\hat A_i =
\frac{r_i-\mu_r}{\sigma_r}
$$&lt;p&gt;实践实现中还需要处理：&lt;/p&gt;
$$
\sigma_r=0
$$&lt;p&gt;的 degenerate group，例如所有 response 都正确或者全部错误。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="step-5记录-old-policy-log-probabilities"&gt;Step 5：记录 Old-policy Log Probabilities&lt;/h2&gt;
&lt;p&gt;对于每个 token：&lt;/p&gt;
$$
\log p_{i,t}^{old} =
\log
\pi_{\theta_{\mathrm{old}}}
(y_{i,t}|x,y_{i,&amp;lt;t})
$$&lt;hr&gt;
&lt;h2 id="step-6current-policy-forward"&gt;Step 6：Current Policy Forward&lt;/h2&gt;
&lt;p&gt;计算：&lt;/p&gt;
$$
\log p_{i,t}^{new} =
\log
\pi_\theta
(y_{i,t}|x,y_{i,&amp;lt;t})
$$&lt;hr&gt;
&lt;h2 id="step-7计算-sequence-log-ratio"&gt;Step 7：计算 Sequence Log Ratio&lt;/h2&gt;
$$
\Delta_{i,t} =
\log p_{i,t}^{new}
\log p_{i,t}^{old}
$$&lt;p&gt;然后：&lt;/p&gt;
$$
\log s_i =
\frac1{T_i}
\sum_t
\Delta_{i,t}
$$&lt;hr&gt;
&lt;h2 id="step-8exponentiate"&gt;Step 8：Exponentiate&lt;/h2&gt;
$$
s_i =
\exp(\log s_i)
$$&lt;hr&gt;
&lt;h2 id="step-9sequence-level-clipping"&gt;Step 9：Sequence-level Clipping&lt;/h2&gt;
$$
L_i =
\min
\left(
s_i\hat A_i,
\operatorname{clip}
(s_i,1-\epsilon_l,1+\epsilon_h)
\hat A_i
\right)
$$&lt;hr&gt;
&lt;h2 id="step-10aggregate"&gt;Step 10：Aggregate&lt;/h2&gt;
$$
J =
\frac1G
\sum_iL_i
$$&lt;p&gt;训练代码通常写成需要 minimize 的 loss：&lt;/p&gt;
$$
\boxed{
L_{\mathrm{GSPO}} =
-J_{\mathrm{GSPO}}
}
$$&lt;hr&gt;
&lt;h2 id="step-11backpropagation"&gt;Step 11：Backpropagation&lt;/h2&gt;
&lt;p&gt;因为：&lt;/p&gt;
$$
s_i =
\exp
\left(
\frac1T
\sum_t\log\pi_\theta(y_t|\cdots)
-\text{constant}
\right)
$$&lt;p&gt;gradient 会自动传回每个 response token。&lt;/p&gt;
&lt;p&gt;然后：&lt;/p&gt;
$$
\theta
\leftarrow
\theta+\eta\nabla_\theta J
$$&lt;p&gt;完成 policy update。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="19-用伪代码看-gspo"&gt;19. 用伪代码看 GSPO&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; prompts &lt;span style="color:#f92672"&gt;in&lt;/span&gt; dataloader:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 1. rollout with old policy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; responses &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rollout(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; policy_old,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prompts,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num_generations&lt;span style="color:#f92672"&gt;=&lt;/span&gt;G,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 2. rewards&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rewards &lt;span style="color:#f92672"&gt;=&lt;/span&gt; verifier(prompts, responses)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 3. group-relative advantages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; advantages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; group_normalize(rewards)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 4. old log probs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; torch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;no_grad():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; old_logp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; policy_old&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log_probs(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prompts,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; responses,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 5. current log probs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_logp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; policy&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log_probs(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prompts,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; responses,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# [B, T]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; token_log_ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new_logp &lt;span style="color:#f92672"&gt;-&lt;/span&gt; old_logp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 6. sequence-level ratio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seq_log_ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; masked_mean(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; token_log_ratio,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response_mask,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dim&lt;span style="color:#f92672"&gt;=-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seq_ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; torch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exp(seq_log_ratio)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 7. GSPO clipping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; unclipped &lt;span style="color:#f92672"&gt;=&lt;/span&gt; seq_ratio &lt;span style="color:#f92672"&gt;*&lt;/span&gt; advantages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipped_ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; torch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;clamp(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seq_ratio,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; eps_low,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; eps_high,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipped &lt;span style="color:#f92672"&gt;=&lt;/span&gt; clipped_ratio &lt;span style="color:#f92672"&gt;*&lt;/span&gt; advantages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; objective &lt;span style="color:#f92672"&gt;=&lt;/span&gt; torch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;minimum(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; unclipped,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipped,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 8. optimize&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# -------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; loss &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;objective&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mean()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; loss&lt;span style="color:#f92672"&gt;.&lt;/span&gt;backward()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; optimizer&lt;span style="color:#f92672"&gt;.&lt;/span&gt;step()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从实现层面看，GSPO 与 GRPO 的区别实际上非常集中：&lt;/p&gt;
&lt;p&gt;GRPO：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; exp(new_logp &lt;span style="color:#f92672"&gt;-&lt;/span&gt; old_logp) &lt;span style="color:#75715e"&gt;# [B, T]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后 token-wise clip。&lt;/p&gt;
&lt;p&gt;GSPO：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new_logp &lt;span style="color:#f92672"&gt;-&lt;/span&gt; old_logp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;seq_log_ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mean(log_ratio, dim&lt;span style="color:#f92672"&gt;=&lt;/span&gt;response_tokens)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; exp(seq_log_ratio) &lt;span style="color:#75715e"&gt;# [B]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后 sequence-wise clip。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="20-gspo-并没有改变-group-relative-advantage"&gt;20. GSPO 并没有改变 Group Relative Advantage&lt;/h1&gt;
&lt;p&gt;这一点很容易混淆。&lt;/p&gt;
&lt;p&gt;GSPO 并不是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“把 GRPO 完全重新设计了一遍。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;实际上 GSPO 仍然保留：&lt;/p&gt;
$$
G\text{ responses / prompt}
$$&lt;p&gt;以及：&lt;/p&gt;
$$
\hat A_i =
\frac{r_i-\mu_r}{\sigma_r}
$$&lt;p&gt;所以：&lt;/p&gt;
$$
\boxed{
\textbf{Group}
}
$$&lt;p&gt;这个部分基本继承自 GRPO。&lt;/p&gt;
&lt;p&gt;GSPO 真正改变的是：&lt;/p&gt;
$$
\boxed{
\textbf{Sequence}
}
$$&lt;p&gt;也就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sequence likelihood ratio；&lt;/li&gt;
&lt;li&gt;sequence clipping；&lt;/li&gt;
&lt;li&gt;sequence optimization weighting。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以它的名字非常准确：&lt;/p&gt;
$$
\boxed{
\underbrace{\text{Group}}_{\text{GRPO-style advantage}} +
\underbrace{\text{Sequence}}_{\text{sequence importance ratio}} +
\underbrace{\text{Policy Optimization}}_{\text{PPO-style clipped objective}}
}
$$&lt;hr&gt;
&lt;h1 id="21-ppogrpogspo-的核心对比"&gt;21. PPO、GRPO、GSPO 的核心对比&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;PPO&lt;/th&gt;
&lt;th&gt;GRPO&lt;/th&gt;
&lt;th&gt;GSPO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Multiple responses/group&lt;/td&gt;
&lt;td&gt;不要求&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Value Model&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;需要&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;不需要&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;不需要&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advantage&lt;/td&gt;
&lt;td&gt;token/state level&lt;/td&gt;
&lt;td&gt;sequence group advantage&lt;/td&gt;
&lt;td&gt;sequence group advantage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reward granularity&lt;/td&gt;
&lt;td&gt;sequence / process&lt;/td&gt;
&lt;td&gt;通常 sequence&lt;/td&gt;
&lt;td&gt;通常 sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Importance ratio&lt;/td&gt;
&lt;td&gt;token&lt;/td&gt;
&lt;td&gt;token&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;sequence&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ratio&lt;/td&gt;
&lt;td&gt;(w_t)&lt;/td&gt;
&lt;td&gt;(w_{i,t})&lt;/td&gt;
&lt;td&gt;(s_i)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clipping&lt;/td&gt;
&lt;td&gt;token&lt;/td&gt;
&lt;td&gt;token&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;sequence&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;同 sequence token gradient weight&lt;/td&gt;
&lt;td&gt;不同&lt;/td&gt;
&lt;td&gt;不同&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;相同&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-CoT stability&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;较容易出现 ratio noise&lt;/td&gt;
&lt;td&gt;更稳定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MoE routing sensitivity&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;明显降低&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing Replay&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Qwen MoE 中需要&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;不需要&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Critic overhead&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此最简洁的关系是：&lt;/p&gt;
$$
\boxed{
\text{GRPO} =
\text{Group Advantage} +
\text{Token Ratio}
}
$$&lt;p&gt;而：&lt;/p&gt;
$$
\boxed{
\text{GSPO} =
\text{Group Advantage} +
\text{Sequence Ratio}
}
$$&lt;hr&gt;
&lt;h1 id="22-gspo-token-是什么"&gt;22. GSPO-token 是什么？&lt;/h1&gt;
&lt;p&gt;GSPO 论文还提出了一个变体：&lt;/p&gt;
$$
\boxed{\text{GSPO-token}}
$$&lt;p&gt;为什么还需要 token variant？&lt;/p&gt;
&lt;p&gt;因为有些任务并不是只有 sequence-level credit。&lt;/p&gt;
&lt;p&gt;例如 multi-turn agent：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Think
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Action
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Observation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Think
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Action
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Observation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可能希望：&lt;/p&gt;
$$
A_{i,t}
$$&lt;p&gt;在不同 token 或不同阶段上不同。&lt;/p&gt;
&lt;p&gt;普通 GSPO：&lt;/p&gt;
$$
A_{i,t}=A_i
$$&lt;p&gt;所有 token 完全共享一个 advantage。&lt;/p&gt;
&lt;p&gt;GSPO-token 为此定义：&lt;/p&gt;
$$
s_{i,t}(\theta) =
\operatorname{sg}[s_i(\theta)]
\cdot
\frac{
\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
}{
\operatorname{sg}
[
\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
]
}
$$&lt;p&gt;其中：&lt;/p&gt;
$$
\operatorname{sg}[\cdot]
$$&lt;p&gt;表示 stop-gradient / detach。&lt;/p&gt;
&lt;p&gt;注意：&lt;/p&gt;
$$
\frac{
\pi_\theta
}{
\operatorname{sg}[\pi_\theta]
}
$$&lt;p&gt;在数值上永远是：&lt;/p&gt;
$$
1
$$&lt;p&gt;因此：&lt;/p&gt;
$$
s_{i,t}
$$&lt;p&gt;&lt;strong&gt;numerically 等于&lt;/strong&gt;：&lt;/p&gt;
$$
s_i
$$&lt;p&gt;但 gradient 可以从对应 token 的：&lt;/p&gt;
$$
\pi_\theta(y_{i,t})
$$&lt;p&gt;向后传播。&lt;/p&gt;
&lt;p&gt;于是 GSPO-token 可以使用：&lt;/p&gt;
$$
A_{i,t}
$$&lt;p&gt;而不是：&lt;/p&gt;
$$
A_i
$$&lt;p&gt;从而实现更细粒度 credit assignment。&lt;/p&gt;
&lt;p&gt;如果设置：&lt;/p&gt;
$$
A_{i,t}=A_i
$$&lt;p&gt;论文证明 GSPO-token 与普通 GSPO 在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;objective numerical value；&lt;/li&gt;
&lt;li&gt;clipping condition；&lt;/li&gt;
&lt;li&gt;theoretical gradient；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上都是等价的。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="23-gspo-对-rl-infrastructure-的潜在意义"&gt;23. GSPO 对 RL Infrastructure 的潜在意义&lt;/h1&gt;
&lt;p&gt;现代 LLM RL 经常是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inference Engine
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↓ rollout
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SGLang / vLLM
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Training Engine
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Megatron / FSDP / ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;问题是 inference engine 与 training engine 之间可能存在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BF16 / FP8 difference；&lt;/li&gt;
&lt;li&gt;kernel difference；&lt;/li&gt;
&lt;li&gt;tensor parallel implementation difference；&lt;/li&gt;
&lt;li&gt;MoE routing difference；&lt;/li&gt;
&lt;li&gt;numerical precision difference。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;于是：&lt;/p&gt;
$$
\log p_{\mathrm{inference}}
$$&lt;p&gt;和：&lt;/p&gt;
$$
\log p_{\mathrm{training}}
$$&lt;p&gt;可能存在微小偏差。&lt;/p&gt;
&lt;p&gt;对于 GRPO：&lt;/p&gt;
$$
w_t =
\exp(
\log p_t^{new} -
\log p_t^{old}
)
$$&lt;p&gt;每一个 token 的微小误差都会直接进入：&lt;/p&gt;
$$
w_t
$$&lt;p&gt;甚至改变 token 是否被 clipping。&lt;/p&gt;
&lt;p&gt;因此很多 RL infrastructure 会：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;rollout engine 负责生成，但 training engine 再 recompute 一次 old log probabilities。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GSPO 使用：&lt;/p&gt;
$$
\frac1T
\sum_t
(\log p_t^{new}-\log p_t^{old})
$$&lt;p&gt;单 token numerical mismatch 会被 sequence aggregation 平滑，因此 Qwen 认为 GSPO 对 inference/training engine 的 probability discrepancy 更 tolerant，有可能直接使用 inference engine 返回的 likelihood，而不再由 training engine recompute。&lt;/p&gt;
&lt;p&gt;论文对此使用的是“makes it possible / potential”式表述，因此更准确的理解是：&lt;/p&gt;
$$
\boxed{
\text{GSPO 有潜力简化 rollout-training probability synchronization}
}
$$&lt;p&gt;而不是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“GSPO 已经证明 old-logprob recomputation 永远都不需要。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h1 id="24-qwen-的实验结果"&gt;24. Qwen 的实验结果&lt;/h1&gt;
&lt;p&gt;原论文主要使用：&lt;/p&gt;
$$
\text{Qwen3-30B-A3B-Base}
$$&lt;p&gt;构造 cold-start RL model。&lt;/p&gt;
&lt;p&gt;评测包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AIME 2024；&lt;/li&gt;
&lt;li&gt;LiveCodeBench；&lt;/li&gt;
&lt;li&gt;CodeForces。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在相同 training compute 和 query consumption 下，GSPO 的 reward、AIME、LiveCodeBench 和 CodeForces performance curves 整体高于 GRPO + Routing Replay。&lt;/p&gt;
&lt;p&gt;Qwen 同时表示 GSPO 被应用到了后续 Qwen3 系列模型的 RL 训练中。&lt;/p&gt;
&lt;p&gt;不过原始 GSPO paper 本身只有 7 页，其 empirical evidence 主要集中在 Qwen 自己的大规模 MoE setting，因此不能从这篇论文单独推出：&lt;/p&gt;
$$
\text{GSPO 在所有 dense / MoE / task / scale 上都优于 GRPO}
$$&lt;p&gt;更准确的结论应该是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在 Qwen 报告的大规模长序列 MoE RL setting 中，GSPO 展现出了明显的稳定性和效率优势。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h1 id="25-gspo-的局限"&gt;25. GSPO 的局限&lt;/h1&gt;
&lt;p&gt;GSPO 解决 GRPO 问题的方法非常直接：&lt;/p&gt;
$$
\boxed{
\text{不要相信单 token ratio，直接看整个 sequence}
}
$$&lt;p&gt;但这样也产生了另一端的问题：&lt;/p&gt;
&lt;h2 id="251-一个坏-token-可能导致整条-sequence-被-clip"&gt;25.1 一个坏 token 可能导致整条 sequence 被 clip&lt;/h2&gt;
&lt;p&gt;假设 sequence 大部分 token 很正常：&lt;/p&gt;
$$
w_t\approx1
$$&lt;p&gt;但存在几个 extreme token。&lt;/p&gt;
&lt;p&gt;这些 token 会影响：&lt;/p&gt;
$$
s_i =
\exp(\operatorname{mean}\log w_t)
$$&lt;p&gt;一旦：&lt;/p&gt;
$$
s_i
$$&lt;p&gt;越过 clipping boundary：&lt;/p&gt;
$$
\boxed{\text{整条 response 都停止贡献相应 gradient}}
$$&lt;p&gt;而不是只 clip problematic tokens。&lt;/p&gt;
&lt;p&gt;因此 GSPO 的 sequence coherence 很强，但 credit assignment 比 token-level 方法粗。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="26-这也是后来-saposspo-等方法继续改-gspo-的原因"&gt;26. 这也是后来 SAPO、SSPO 等方法继续改 GSPO 的原因&lt;/h1&gt;
&lt;p&gt;截至 2026 年，GSPO 已经不是这一方向的终点。&lt;/p&gt;
&lt;p&gt;Qwen 团队成员随后提出 &lt;strong&gt;SAPO（Soft Adaptive Policy Optimization）&lt;/strong&gt;，明确指出 GSPO 的 hard sequence clipping 存在这样的 trade-off：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当 sequence 中只有少量 token 非常 off-policy 时，GSPO 可能 suppress 整个 sequence 的 gradient。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SAPO 因此尝试做到：&lt;/p&gt;
$$
\boxed{
\text{sequence coherence} +
\text{token adaptivity}
}
$$&lt;p&gt;通过 soft gating 而不是 GSPO 的 hard clipping，在保留 sequence-level stability 的同时尽量保留有效 token 的 gradient。&lt;/p&gt;
&lt;p&gt;另一条路线是 &lt;strong&gt;SSPO（Subsentence-level Policy Optimization）&lt;/strong&gt;，将 optimization granularity 设在：&lt;/p&gt;
$$
\text{token}
&amp;lt;
\boxed{\text{subsentence}}
&amp;lt;
\text{sequence}
$$&lt;p&gt;希望在 GRPO 和 GSPO 两种极端之间取得平衡。SSPO 作者的实验同样指出，GSPO 的整条 sequence clipping 可能降低 sampled data utilization。&lt;/p&gt;
&lt;p&gt;因此从今天看，GSPO 真正重要的贡献可能并不只是某个具体 loss，而是提出了一个更一般的问题：&lt;/p&gt;
$$
\boxed{
\text{LLM RL 的 optimization granularity 应该是什么？}
}
$$&lt;p&gt;可以是：&lt;/p&gt;
$$
\text{Token}
$$&lt;p&gt;也可以是：&lt;/p&gt;
$$
\text{Subsentence}
$$&lt;p&gt;或者：&lt;/p&gt;
$$
\text{Reasoning Step}
$$&lt;p&gt;或者：&lt;/p&gt;
$$
\text{Think-Action}
$$&lt;p&gt;或者：&lt;/p&gt;
$$
\text{Whole Sequence}
$$&lt;p&gt;这已经成为后续很多 RLVR / Agent RL 工作继续探索的设计维度。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="27-应该怎样真正理解-gspo"&gt;27. 应该怎样真正理解 GSPO？&lt;/h1&gt;
&lt;p&gt;如果已经理解 PPO 和 GRPO，可以把 GSPO 压缩成下面这一条逻辑链。&lt;/p&gt;
&lt;p&gt;GRPO：&lt;/p&gt;
$$
r(x,y)
$$&lt;p&gt;产生：&lt;/p&gt;
$$
A(y)
$$&lt;p&gt;但是 optimization 使用：&lt;/p&gt;
$$
w_t =
\frac{\pi_\theta(y_t|y_{&amp;lt;t})}
{\pi_{\mathrm{old}}(y_t|y_{&amp;lt;t})}
$$&lt;p&gt;于是：&lt;/p&gt;
$$
\nabla J_{\mathrm{GRPO}}
\sim
A(y)
\sum_t
w_t
\nabla\log\pi_\theta(y_t|y_{&amp;lt;t})
$$&lt;p&gt;GSPO 认为这里存在：&lt;/p&gt;
$$
\boxed{
\text{Reward granularity}
\neq
\text{Importance-weight granularity}
}
$$&lt;p&gt;于是将：&lt;/p&gt;
$$
w_t
$$&lt;p&gt;替换成：&lt;/p&gt;
$$
s(y) =
\left(
\frac{\pi_\theta(y|x)}
{\pi_{\mathrm{old}}(y|x)}
\right)^{1/T}
$$&lt;p&gt;得到：&lt;/p&gt;
$$
\nabla J_{\mathrm{GSPO}}
\sim
s(y)A(y)
\frac1T
\sum_t
\nabla\log\pi_\theta(y_t|y_{&amp;lt;t})
$$&lt;p&gt;于是：&lt;/p&gt;
$$
\boxed{
\text{Reward}
\rightarrow
\text{Advantage}
\rightarrow
\text{Importance Ratio}
\rightarrow
\text{Clipping}
}
$$&lt;p&gt;全部围绕：&lt;/p&gt;
$$
\boxed{\text{sequence}}
$$&lt;p&gt;这就是 GSPO 的核心。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="28-一张公式图记住-gspo"&gt;28. 一张公式图记住 GSPO&lt;/h1&gt;
$$
\boxed{
x
\overset{\pi_{\theta_{\mathrm{old}}}}{\longrightarrow}
{y_1,\dots,y_G}
}
$$&lt;p&gt;得到：&lt;/p&gt;
$$
\boxed{
r_1,\dots,r_G
}
$$&lt;p&gt;计算：&lt;/p&gt;
$$
\boxed{
A_i =
\frac{r_i-\mu_r}{\sigma_r}
}
$$&lt;p&gt;然后对每条 sequence：&lt;/p&gt;
$$
\boxed{
\log s_i =
\frac1{|y_i|}
\sum_t
\left(
\log\pi_\theta(y_{i,t}) -
\log\pi_{\mathrm{old}}(y_{i,t})
\right)
}
$$$$
\boxed{
s_i=e^{\log s_i}
}
$$&lt;p&gt;最后：&lt;/p&gt;
$$
\boxed{
J_{\mathrm{GSPO}} =
\frac1G
\sum_i
\min
\left(
s_iA_i,
\operatorname{clip}(s_i)A_i
\right)
}
$$&lt;p&gt;其 gradient：&lt;/p&gt;
$$
\boxed{
\nabla J_{\mathrm{GSPO}}
\propto
\frac1G
\sum_i
s_iA_i
\frac1{|y_i|}
\sum_t
\nabla\log\pi_\theta(y_{i,t}|x,y_{i,&amp;lt;t})
}
$$&lt;p&gt;与 GRPO 唯一最关键的对比：&lt;/p&gt;
$$
\boxed{
\underbrace{w_{i,t}}_{\text{GRPO: token-specific}}
\quad\longrightarrow\quad
\underbrace{s_i}_{\text{GSPO: sequence-shared}}
}
$$&lt;p&gt;如果只记住 GSPO 的一个公式和一个思想，就记这一行。&lt;/p&gt;</description></item><item><title>PPTAgent 与 DeepPresenter：论文讲解、代码解析与 Agent Harness 架构</title><link>https://wangzh12023.github.io/blog/blog/pptagent-deeppresenter/</link><pubDate>Sat, 15 Aug 2026 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/pptagent-deeppresenter/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文结合 &lt;code&gt;paper/&lt;/code&gt; 目录下的两篇论文（&lt;code&gt;2501.03936.pdf&lt;/code&gt; — PPTAgent，&lt;code&gt;2602.22839.pdf&lt;/code&gt; — DeepPresenter）、&lt;code&gt;PPTAgent/&lt;/code&gt; 仓库代码（&lt;code&gt;pptagent/&lt;/code&gt; 旧版核心库 + &lt;code&gt;deeppresenter/&lt;/code&gt; 当前运行时）以及 &lt;code&gt;PPTea-main/&lt;/code&gt; 评测/实验代码，对两代系统的生成流程、评测流程、Agent Harness 主循环与框架架构进行系统讲解，并与&amp;quot;直接让 CodeX/LLM 生成 PPT&amp;quot;的方式做对比。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="1-项目背景与两代系统总览"&gt;1. 项目背景与两代系统总览&lt;/h2&gt;
&lt;p&gt;仓库 &lt;code&gt;PPTAgent/&lt;/code&gt;（https://github.com/icip-cas/PPTAgent）包含两代论文的完整代码：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;PPTAgent&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;DeepPresenter&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;论文&lt;/td&gt;
&lt;td&gt;&amp;ldquo;PPTAgent: Generating and Evaluating Presentations Beyond Text-to-Slides&amp;rdquo;（EMNLP 2025）&lt;/td&gt;
&lt;td&gt;&amp;ldquo;DeepPresenter: Environment-Grounded Reflection for Agentic Presentation Generation&amp;rdquo;（ACL 2026）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;arXiv 编号&lt;/td&gt;
&lt;td&gt;2501.03936&lt;/td&gt;
&lt;td&gt;2602.22839&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;核心思想&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;两阶段、基于编辑&lt;/strong&gt;（edit-based）：先分析参考演示文稿提取布局与模式，再通过编辑动作修改参考幻灯片&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;双智能体 + 环境接地反思&lt;/strong&gt;：Researcher 自主调研写文稿，Presenter 自由式设计 HTML 幻灯片，通过 &lt;code&gt;inspect&lt;/code&gt; 观察渲染产物进行反思修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;生成范式&lt;/td&gt;
&lt;td&gt;模板复用/编辑式：在已有 PPTX 参考模板上执行编辑 API&lt;/td&gt;
&lt;td&gt;自由式（free-form）：从零写 HTML/CSS，渲染为图片再转 PPTX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖&lt;/td&gt;
&lt;td&gt;参考演示文稿（reference presentation）+ 输入文档&lt;/td&gt;
&lt;td&gt;用户指令 +（可选附件）+ 网络检索 + 工具环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;角色&lt;/td&gt;
&lt;td&gt;planner / content_organizer / layout_selector / editor / coder / schema_extractor&lt;/td&gt;
&lt;td&gt;Researcher（调研+文稿）、Presenter（视觉设计），可选 Planner、SubAgent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;评测&lt;/td&gt;
&lt;td&gt;PPTEval：Content / Design / Coherence 三维度（MLLM-as-a-judge）&lt;/td&gt;
&lt;td&gt;Constraint（规则验证）/ Content / Style 三维度 + Diversity（Vendi Score），GPT-5 作为 judge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;对应代码&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/&lt;/code&gt;（旧版核心库）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/&lt;/code&gt;（当前运行时）+ &lt;code&gt;PPTea-main/sarl/&lt;/code&gt;（评测）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;时间线关系&lt;/strong&gt;：PPTAgent 是 2025 年 1 月开源的初代系统（基于编辑 API 的两阶段方案）；DeepPresenter 是 2025 年 12 月发布的重构版（&amp;ldquo;Agentic&amp;rdquo; 方案），保留了 &lt;code&gt;pptagent&lt;/code&gt; 作为 MCP server（&lt;code&gt;pptagent-mcp&lt;/code&gt;）供新系统调用。&lt;code&gt;deeppresenter/&lt;/code&gt; 是当前的主产品面，&lt;code&gt;pptagent/&lt;/code&gt; 是仍在包内、但主要用于 MCP server 入口的旧核心库。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2-pptagent两阶段编辑式生成"&gt;2. PPTAgent：两阶段编辑式生成&lt;/h2&gt;
&lt;h3 id="21-问题定义与核心思想"&gt;2.1 问题定义与核心思想&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;传统范式（text-to-slides）&lt;/strong&gt; 把生成演示文稿当作&amp;quot;从文档做抽象式摘要&amp;quot;，用预定义规则或模板把 LLM 输出转成幻灯片：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;S = {e1, e2, ..., en} = f(C) （公式 1：从内容 C 生成 n 个幻灯片元素）
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中每个元素要手动指定类型、内容、样式属性（如 &lt;code&gt;(Textbox, &amp;quot;Hello&amp;quot;, {border, size, position...})&lt;/code&gt;）。这种方式的缺陷：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要手工指定样式属性，自动化困难；&lt;/li&gt;
&lt;li&gt;输出文本密集、版式单调（图 1 右侧：Content: Tedious Text / Design: Boring layout / Coherence: Abrupt Start）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PPTAgent 的核心洞察&lt;/strong&gt;：人类制作 PPT 的流程通常是——&lt;strong&gt;挑选优秀的示例幻灯片作为参考，然后把关键内容总结并迁移到这些参考幻灯片上&lt;/strong&gt;（Duarte, 2010）。因此 PPTAgent 把幻灯片生成分解为：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;A = {a1, a2, ..., am} = g(C, Rj) （公式 2：给定内容 C 与第 j 个参考幻灯片 Rj，生成 m 个可执行编辑动作）
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;即：&lt;strong&gt;不是从零创建幻灯片，而是在参考幻灯片上执行一系列可执行的编辑动作&lt;/strong&gt;（如 replace_span、replace_image 等），从而保留参考幻灯片精心设计的版式与风格。&lt;/p&gt;
&lt;p&gt;论文的三大贡献：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PPTAgent&lt;/strong&gt;：把自动演示文稿生成重新定义为&amp;quot;以参考演示文稿为引导的编辑式过程&amp;quot;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPTEval&lt;/strong&gt;：三维度（Content / Design / Coherence）的评测框架；&lt;/li&gt;
&lt;li&gt;发布 &lt;strong&gt;Zenodo10K&lt;/strong&gt; 数据集（从 Zenodo 爬取的 10,448 份跨领域演示文稿）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="22-stage-ipresentation-analysis演示文稿分析"&gt;2.2 Stage I：Presentation Analysis（演示文稿分析）&lt;/h3&gt;
&lt;p&gt;对应代码：&lt;code&gt;pptagent/induct.py&lt;/code&gt;（&lt;code&gt;SlideInducter&lt;/code&gt; 类）与 &lt;code&gt;pptagent/model_utils.py&lt;/code&gt;（聚类算法）。&lt;/p&gt;
&lt;p&gt;目标：分析参考演示文稿，提取&lt;strong&gt;幻灯片的版面类型（functional type）与内容模式（content schema）&lt;/strong&gt;，为后续的参考选择与幻灯片生成提供指导。&lt;/p&gt;
&lt;h4 id="step-1幻灯片分类slide-clustering"&gt;Step 1：幻灯片分类（Slide Clustering）&lt;/h4&gt;
&lt;p&gt;幻灯片按功能分为两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结构型幻灯片（structural slides）&lt;/strong&gt;：支撑演示文稿组织的（如开场、目录、章节页、结尾）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内容型幻灯片（content slides）&lt;/strong&gt;：传达具体信息的（如要点页）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;分类方法（论文 2.2 节）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结构型&lt;/strong&gt;：用 LLM 的长上下文能力分析整份演示文稿的文本，识别结构型幻灯片、标注其结构角色（Opening / TOC / Section Outline / Ending）并按功能分组。对应 &lt;code&gt;induct.py&lt;/code&gt; 的 &lt;code&gt;category_split()&lt;/code&gt;（&lt;code&gt;induct.py:95-110&lt;/code&gt;），使用 &lt;code&gt;prompts/category_split.txt&lt;/code&gt;，输出 &lt;code&gt;functional_cluster&lt;/code&gt;（类别 → 幻灯片索引列表）与 &lt;code&gt;content_slides_index&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内容型&lt;/strong&gt;：把幻灯片转成图片，用 ViT 做分层聚类（hierarchical clustering）把相似版面聚到一起。对应 &lt;code&gt;layout_split()&lt;/code&gt;（&lt;code&gt;induct.py:112-151&lt;/code&gt;）：
&lt;ol&gt;
&lt;li&gt;用 ViT（&lt;code&gt;google/vit-base-patch16-224-in21k&lt;/code&gt;）对模板图片提取 embedding（&lt;code&gt;get_image_embedding()&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;按 &lt;code&gt;(layout_name, content_type)&lt;/code&gt;（text/image）预分组；&lt;/li&gt;
&lt;li&gt;组内两两计算余弦相似度（&lt;code&gt;images_cosine_similarity()&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;用贪婪聚合聚类 &lt;code&gt;get_cluster()&lt;/code&gt;（&lt;code&gt;model_utils.py:291-345&lt;/code&gt;）聚类，相似度阈值 &lt;code&gt;sim_bound=0.65&lt;/code&gt;（论文 Algorithm 1）——聚类前把文本替换为占位符 &amp;ldquo;a&amp;rdquo;、图片替换为纯色背景以只关注版面；&lt;/li&gt;
&lt;li&gt;每簇选 shape 最多的幻灯片作为模板幻灯片；&lt;/li&gt;
&lt;li&gt;用视觉模型（&lt;code&gt;ASK_CATEGORY_PROMPT&lt;/code&gt;）生成一行版面模式描述（如 &amp;ldquo;One Large Left-Aligned Image with a Right-Aligned Text Block&amp;rdquo;），并追加 &lt;code&gt;:text&lt;/code&gt; 或 &lt;code&gt;:image&lt;/code&gt; 后缀。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-2schema-提取schema-extraction"&gt;Step 2：Schema 提取（Schema Extraction）&lt;/h4&gt;
&lt;p&gt;对每个版面，取其模板幻灯片，提取所有段落文本与图片描述，调用 &lt;code&gt;schema_extractor&lt;/code&gt; 智能体生成结构化 JSON schema（&lt;code&gt;content_induct()&lt;/code&gt;，&lt;code&gt;induct.py:175-208&lt;/code&gt;）。每个元素用 &lt;code&gt;(category, description, content)&lt;/code&gt; 表示，例如：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Category Description Data
Title Main title Sample Library
Date Date of the event 15 February 2018
Image Primary image to Picture: Children in a li-
illustrate the slide brary with ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对应数据模型：&lt;code&gt;pptagent/presentation/layout.py&lt;/code&gt; 中的 &lt;code&gt;Element&lt;/code&gt;（name/data/type/suggested_characters/variable_length）与 &lt;code&gt;Layout&lt;/code&gt;。Stage I 的最终产物是 &lt;code&gt;slide_induction.json&lt;/code&gt;（见 &lt;code&gt;scripts/template_induct.py&lt;/code&gt; 与 &lt;code&gt;templates/*/slide_induction.json&lt;/code&gt;），包含每个版式的 elements、template_id、slides、functional_keys 与语言检测结果。&lt;/p&gt;
&lt;h3 id="23-stage-iipresentation-generation演示文稿生成"&gt;2.3 Stage II：Presentation Generation（演示文稿生成）&lt;/h3&gt;
&lt;p&gt;对应代码：&lt;code&gt;pptagent/pptgen.py&lt;/code&gt;（&lt;code&gt;PPTGen&lt;/code&gt; 抽象基类与 &lt;code&gt;PPTAgent&lt;/code&gt; 具体实现）。&lt;/p&gt;
&lt;h4 id="step-1大纲生成outline-generation"&gt;Step 1：大纲生成（Outline Generation）&lt;/h4&gt;
&lt;p&gt;用 LLM 生成结构化大纲（&lt;code&gt;generate_outline()&lt;/code&gt;，&lt;code&gt;pptgen.py:239-256&lt;/code&gt;），每个条目对应一张新幻灯片，包含：&lt;strong&gt;参考幻灯片（基于 Stage I 的功能描述选择）+ 该幻灯片相关的文档内容&lt;/strong&gt;。大纲以结构化输出（&lt;code&gt;Outline.response_model(source_doc)&lt;/code&gt;，见 &lt;code&gt;response/outline.py&lt;/code&gt;）生成。&lt;/p&gt;
&lt;p&gt;随后 &lt;code&gt;_add_functional_layouts()&lt;/code&gt;（&lt;code&gt;pptgen.py:267-318&lt;/code&gt;）自动插入结构型幻灯片：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TOC（目录）与 Opening（开场）插在位置 0；&lt;/li&gt;
&lt;li&gt;Ending（结尾）插在最后；&lt;/li&gt;
&lt;li&gt;每个新主题章节前插入 Section Outline（章节页）；&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;edit_distance&lt;/code&gt; 模糊匹配参考稿中对应的功能版式名。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-2幻灯片生成slide-generation编辑式流水线"&gt;Step 2：幻灯片生成（Slide Generation）——编辑式流水线&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;generate_slide()&lt;/code&gt;（&lt;code&gt;pptgen.py:392-432&lt;/code&gt;）对大纲中的每个条目执行：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择版面&lt;/strong&gt; &lt;code&gt;_select_layout()&lt;/code&gt;（&lt;code&gt;pptgen.py:434-467&lt;/code&gt;）：先用 &lt;code&gt;content_organizer&lt;/code&gt; 从检索内容中提取关键点，再由 &lt;code&gt;layout_selector&lt;/code&gt; 根据内容与图片匹配情况选择最佳版式（&lt;code&gt;LayoutChoice.response_model(layouts)&lt;/code&gt; 结构化输出），文本内容选 &lt;code&gt;:text&lt;/code&gt; 版式、含图片的选 &lt;code&gt;:image&lt;/code&gt; 版式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;生成内容&lt;/strong&gt; &lt;code&gt;_generate_content()&lt;/code&gt;（&lt;code&gt;pptgen.py:469-491&lt;/code&gt;）：&lt;code&gt;editor&lt;/code&gt; 智能体按照 schema 生成结构化内容（&lt;code&gt;EditorOutput.response_model(elements)&lt;/code&gt;），再经 &lt;code&gt;_validate_content()&lt;/code&gt;（&lt;code&gt;pptgen.py:531-571&lt;/code&gt;）校验（图片是否存在、字符数是否超限，超长文本用 &lt;code&gt;length_rewrite()&lt;/code&gt; 改写），最后 &lt;code&gt;_generate_commands()&lt;/code&gt;（&lt;code&gt;pptgen.py:573-589&lt;/code&gt;）把内容差异转成命令序列：对每个元素计算 &lt;code&gt;quantity_change = len(new) - len(old)&lt;/code&gt;，产出 &lt;code&gt;(element_name, type, quantity_change, old_data, new_data)&lt;/code&gt; 命令元组。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;编辑幻灯片&lt;/strong&gt; &lt;code&gt;_edit_slide()&lt;/code&gt;（&lt;code&gt;pptgen.py:493-529&lt;/code&gt;）：这是&lt;strong&gt;自校正 REPL 循环&lt;/strong&gt;——&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;coder&lt;/code&gt; 智能体依据 API 文档（&lt;code&gt;CodeExecutor.get_apis_docs()&lt;/code&gt; 内省 API 签名生成）与模板幻灯片的 HTML 表示，把命令翻译成 API 调用序列；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CodeExecutor.execute_actions()&lt;/code&gt;（&lt;code&gt;apis.py:127-203&lt;/code&gt;）用 &lt;code&gt;eval(line, SAFE_EVAL_GLOBALS, ...)&lt;/code&gt; 逐行执行 API 调用（&lt;code&gt;replace_paragraph&lt;/code&gt;、&lt;code&gt;replace_image&lt;/code&gt;、&lt;code&gt;del_paragraph&lt;/code&gt;、&lt;code&gt;del_image&lt;/code&gt;、&lt;code&gt;clone_paragraph&lt;/code&gt;），出错则返回 &lt;code&gt;(api_lines, traceback)&lt;/code&gt; 作为反馈；&lt;/li&gt;
&lt;li&gt;LLM 分析反馈修正动作，最多重试 &lt;code&gt;retry_times&lt;/code&gt;（默认 3）次，直到生成有效幻灯片。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="编辑-api-与-html-渲染coderender"&gt;编辑 API 与 HTML 渲染（CodeRender）&lt;/h4&gt;
&lt;p&gt;论文的关键设计之一：&lt;strong&gt;把参考幻灯片渲染成 HTML 表示&lt;/strong&gt;（&lt;code&gt;SlidePage.to_html()&lt;/code&gt;，&lt;code&gt;presentation.py:193-216&lt;/code&gt;），比直接操作 PPTX 的 XML（1006 行冗长冗余，见论文 Figure 11）更精确直观，让 LLM 能理解元素结构并精确修改。&lt;/p&gt;
&lt;p&gt;五个编辑 API（&lt;code&gt;pptagent/apis.py&lt;/code&gt;）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;实现位置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;replace_paragraph&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;替换段落内容（markdown→HTML→TextBlock 富文本解析）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apis.py:403-438&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;replace_image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;替换图片资源（等比缩放居中，表格图片转真表格）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apis.py:441-473&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;del_paragraph&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除段落&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apis.py:357-384&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;del_image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除图片元素&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apis.py:387-400&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clone_paragraph&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;复制段落（插入 XML 到末段之后）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apis.py:476-512&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Closure 模式&lt;/strong&gt;：编辑动作不直接应用到 PPTX，而是修改 &lt;code&gt;SlidePage&lt;/code&gt; 表示并排队 &lt;code&gt;Closure&lt;/code&gt; 对象（&lt;code&gt;shapes.py:218-246&lt;/code&gt;），&lt;code&gt;SlidePage.build()&lt;/code&gt; 时按 CLONE → REPLACE/STYLE → DELETE/POST_PROCESS → MERGE 的顺序执行（&lt;code&gt;shapes.py:622-642&lt;/code&gt;）。这保证了删除段落时索引处理的正确性。&lt;/p&gt;
&lt;h3 id="24-ppteval-评测框架"&gt;2.4 PPTEval 评测框架&lt;/h3&gt;
&lt;p&gt;对应代码：&lt;code&gt;pptagent/ppteval/ppteval.py&lt;/code&gt; 与 &lt;code&gt;pptagent/prompts/ppteval/*.txt&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;PPTEval 采用 &lt;strong&gt;MLLM-as-a-judge&lt;/strong&gt; 范式，评估三个维度（1-5 分制）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;评分标准&lt;/th&gt;
&lt;th&gt;评测对象&lt;/th&gt;
&lt;th&gt;Prompt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文本简洁、语法正确、有相关图片支撑&lt;/td&gt;
&lt;td&gt;幻灯片级（逐页）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ppteval_content.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Design&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;配色和谐、版面可读、视觉元素（几何形状等）提升吸引力&lt;/td&gt;
&lt;td&gt;幻灯片级（逐页）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ppteval_style.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Coherence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;结构递进、包含必要的背景信息&lt;/td&gt;
&lt;td&gt;整个演示文稿级&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ppteval_coherence.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;评测流程（&lt;code&gt;ppteval.py&lt;/code&gt;）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;eval_slide()&lt;/code&gt;（&lt;code&gt;ppteval.py:54-82&lt;/code&gt;）：对每张幻灯片图片，先用&lt;strong&gt;视觉模型&lt;/strong&gt;生成内容描述（&lt;code&gt;content_descriptor&lt;/code&gt;）与风格描述（&lt;code&gt;style_descriptor&lt;/code&gt;），再用&lt;strong&gt;文本模型&lt;/strong&gt;分别对描述评分（&lt;code&gt;text_scorer&lt;/code&gt; / &lt;code&gt;vision_scorer&lt;/code&gt;）。这种&amp;quot;&lt;strong&gt;感知（VLM）与判断（LLM）分离&lt;/strong&gt;&amp;ldquo;的设计是 PPTEval 的关键。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eval_coherence()&lt;/code&gt;（&lt;code&gt;ppteval.py:85-108&lt;/code&gt;）：提取整份演示文稿文本，先用 &lt;code&gt;ppt_extractor&lt;/code&gt; 抽取幻灯片描述与背景元数据，再用 &lt;code&gt;logic_scorer&lt;/code&gt; 评一致性。&lt;/li&gt;
&lt;li&gt;聚合：Content/Design 取所有幻灯片的平均分，Coherence 为整体分。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;与人类评分的一致性&lt;/strong&gt;（论文 5.5 节）：招募 4 名研究生评 250 份演示文稿（50 份真实 + 200 份生成），Fleiss&amp;rsquo; Kappa 平均 0.59；Pearson 相关 0.71、Spearman 相关 0.74，显著优于其他评测方法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;与传统指标对比&lt;/strong&gt;（论文 Figure 7 热力图）：PPL 与 FID 与 Content/Design 几乎不相关（-0.02/-0.09），说明传统指标（PPL、ROUGE-L、FID）无法评估演示文稿质量——KCTV 拿到高 ROUGE-L（16.76）但低 Content（2.55），PPTAgent 则相反。&lt;/p&gt;
&lt;h3 id="25-实验结果与消融"&gt;2.5 实验结果与消融&lt;/h3&gt;
&lt;p&gt;主结果（论文 Table 3，Qwen2.5_LM + Qwen2-VL_VM 配置）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;SR(%)&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Design&lt;/th&gt;
&lt;th&gt;Coherence&lt;/th&gt;
&lt;th&gt;Avg&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DocPres（规则）&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;2.98&lt;/td&gt;
&lt;td&gt;2.37&lt;/td&gt;
&lt;td&gt;3.28&lt;/td&gt;
&lt;td&gt;2.87&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KCTV（模板）&lt;/td&gt;
&lt;td&gt;88.0&lt;/td&gt;
&lt;td&gt;2.55&lt;/td&gt;
&lt;td&gt;2.95&lt;/td&gt;
&lt;td&gt;3.36&lt;/td&gt;
&lt;td&gt;2.95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PPTAgent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;95.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.28&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.27&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.48&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.67&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;消融（论文 Table 4）说明四个组件的贡献：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;w/o CodeRender&lt;/strong&gt;（用 Guo et al. 的表示替换 HTML 渲染）：SR 从 95.0% 掉到 74.6% —— HTML 渲染显著降低交互复杂度；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;w/o Schema&lt;/strong&gt;（去掉 schema 引导）：SR 从 95.0% 掉到 78.8% —— schema 对生成鲁棒性关键；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;w/o Outline / w/o Structure&lt;/strong&gt;：Coherence 从 4.48 掉到 3.36/3.45 —— 大纲与结构型幻灯片分析对连贯性至关重要；&lt;/li&gt;
&lt;li&gt;自校正机制（论文 Figure 6）：所有模型都能修正超过一半的错误，GPT-4o 自校正能力最强。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-deeppresenter环境接地反思的双智能体框架"&gt;3. DeepPresenter：环境接地反思的双智能体框架&lt;/h2&gt;
&lt;h3 id="31-动机与核心贡献"&gt;3.1 动机与核心贡献&lt;/h3&gt;
&lt;p&gt;DeepPresenter 指出现有演示文稿智能体的两个根本缺陷：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;依赖预定义工作流与固定模板&lt;/strong&gt;（如 PPTAgent 的编辑式流程、KCTV 的模板填充），无法适应多样化的用户意图，产出文本密集、研究深度不足、视觉设计与叙事脱节的幻灯片；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内省式反思（introspective self-reflection）失效&lt;/strong&gt;：智能体操作的是中间表示（HTML/markdown），而用户感知的是&lt;strong&gt;渲染后的产物&lt;/strong&gt;。很多缺陷（图片断裂、元素溢出、低对比度）只在感知状态（渲染后的幻灯片）中显现，内省反思无法察觉。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三大贡献：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;DeepPresenter&lt;/strong&gt;：通过共享观察空间协调两个专职智能体（Researcher + Presenter）的智能体框架；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境接地反思（Environment-Grounded Reflection）&lt;/strong&gt;：把自校正建立在渲染后产物的感知状态上，而非内部信号上；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DeepPresenter-9B&lt;/strong&gt;：用&amp;quot;外在验证（extrinsic verification）&amp;ldquo;合成的轨迹进行监督微调，小模型以极低代价接近大模型性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="32-任务形式化"&gt;3.2 任务形式化&lt;/h3&gt;
&lt;p&gt;把演示文稿生成形式化为&lt;strong&gt;交互式智能体任务&lt;/strong&gt;：给定指令 I 与配备工具库 T 和文件系统 F 的智能体环境 E，生成高质量演示文稿 P。生成过程是多步轨迹：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;τ = {(r1, a1, o1), ..., (rT, aT, oT)}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;每步：智能体生成推理轨迹 r_t，选择动作 a_t ∈ T，从 E 收到观察 o_t。轨迹分解为两个连续阶段：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;τ = τ_R ∘ τ_P
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;τ_R：Researcher 轨迹；&lt;/li&gt;
&lt;li&gt;τ_P：Presenter 轨迹。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两个智能体通过 F 通信：Researcher 把结构化文稿 M 和相关资产持久化到文件系统，Presenter 消费它们。&lt;/p&gt;
&lt;h3 id="33-双智能体协作researcher--presenter"&gt;3.3 双智能体协作：Researcher + Presenter&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Researcher Agent&lt;/strong&gt;（对应 &lt;code&gt;deeppresenter/agents/research.py&lt;/code&gt; + &lt;code&gt;roles/Research.yaml&lt;/code&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不遵循预定义工作流，而是&lt;strong&gt;自主规划探索&lt;/strong&gt;：执行多步检索（&lt;code&gt;search_web&lt;/code&gt;、&lt;code&gt;search_images&lt;/code&gt;、&lt;code&gt;search_papers&lt;/code&gt;、&lt;code&gt;fetch_url&lt;/code&gt;）、文档解析（&lt;code&gt;convert_to_markdown&lt;/code&gt;）、必要时创建辅助资产（&lt;code&gt;image_generation&lt;/code&gt;、matplotlib 绘图）；&lt;/li&gt;
&lt;li&gt;探索深度与策略&lt;strong&gt;适配用户意图&lt;/strong&gt;：技术性演讲需要调研相关工作，大众向演讲更重可理解的例子与生动插图；&lt;/li&gt;
&lt;li&gt;最终把内容组织成按叙事流排布的结构化 Markdown 文稿 M（用 &lt;code&gt;---&lt;/code&gt; 分页，图片本地化并相对路径引用），持久化到 F；&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;inspect_manuscript&lt;/code&gt; 获取文稿诊断（页数、语言、图片资源可用性），最后调用 &lt;code&gt;finalize&lt;/code&gt; 返回文稿路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Presenter Agent&lt;/strong&gt;（对应 &lt;code&gt;deeppresenter/agents/design.py&lt;/code&gt; + &lt;code&gt;roles/Design.yaml&lt;/code&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不填充预定义模板，而是&lt;strong&gt;从零生成幻灯片&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;先制定全局设计计划（&lt;code&gt;designplan&lt;/code&gt;：配色、字体、网格系统、字号规范），建立与主题共鸣的视觉基调（可持续主题用大地色系、学术教程用极简布局）；&lt;/li&gt;
&lt;li&gt;把每张幻灯片生成为独立的 HTML 文件（&lt;code&gt;slides/slide_01.html&lt;/code&gt;、&lt;code&gt;slide_02.html&lt;/code&gt;&amp;hellip;），遵循设计计划把文稿内容翻译成视觉元素；&lt;/li&gt;
&lt;li&gt;每张幻灯片生成后调用 &lt;code&gt;inspect_slide&lt;/code&gt;（渲染成像素图片）观察后渲染缺陷（溢出、重叠、低对比度），用 &lt;code&gt;thinking&lt;/code&gt;（模型原生推理）规划针对性修改，然后 &lt;code&gt;edit&lt;/code&gt; 修复；&lt;/li&gt;
&lt;li&gt;全部完成后 &lt;code&gt;finalize&lt;/code&gt; 返回幻灯片目录。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;多智能体并行扩展&lt;/strong&gt;（&lt;code&gt;main.py&lt;/code&gt; 中 &lt;code&gt;multiagent_mode&lt;/code&gt;）：父智能体可通过 &lt;code&gt;delegate_subagent&lt;/code&gt; 本地工具把长文档/多主题调研、&amp;gt;=3 张幻灯片的批量生成&lt;strong&gt;并行委派&lt;/strong&gt;给隔离工作区中的 SubAgent 实例（&lt;code&gt;agents/subagent.py&lt;/code&gt;，max_turns=10），结果通过文件 + &lt;code&gt;finalize&lt;/code&gt; 回传。论文 Figure 8(a) 的工具使用分析证实了角色分工：Researcher 大量使用 Retrieve 类工具（26.8%），Presenter 大量使用 File（40%）与 Reason（19.3%）类工具。&lt;/p&gt;
&lt;h3 id="34-环境接地反思environment-grounded-reflection"&gt;3.4 环境接地反思（Environment-Grounded Reflection）&lt;/h3&gt;
&lt;p&gt;这是 DeepPresenter 最核心的方法论创新（论文 Figure 2 对比）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;自反思（Self-Reflection）&lt;/th&gt;
&lt;th&gt;环境接地反思（Env-Grounded Reflection）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;触发&lt;/td&gt;
&lt;td&gt;不确定性（Uncertain ❓）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inspect&lt;/code&gt; 工具调用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;输入&lt;/td&gt;
&lt;td&gt;内部信号（无外部观察）&lt;/td&gt;
&lt;td&gt;渲染后的幻灯片图像 / 文稿诊断&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;缺陷&lt;/td&gt;
&lt;td&gt;发现不了后渲染缺陷（溢出、重叠、低对比度、断裂图片）&lt;/td&gt;
&lt;td&gt;能发现&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;实现上是 &lt;strong&gt;&lt;code&gt;inspect&lt;/code&gt; 工具&lt;/strong&gt;作为显式的观察接口（&lt;code&gt;deeppresenter/tools/reflect.py&lt;/code&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;inspect_slide(html_file, aspect_ratio)&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;reflect.py:28-62&lt;/code&gt;）：用 Node 管道（html2pptx）校验 HTML 合法性；若 &lt;code&gt;REFLECTIVE_DESIGN&lt;/code&gt;（&lt;code&gt;design_agent&lt;/code&gt; 是多模态且 &lt;code&gt;heavy_reflect&lt;/code&gt;）开启，还用 Playwright 把 HTML 渲染为 PDF→JPEG，以 &lt;code&gt;ImageContent&lt;/code&gt;（base64 JPEG）返回给多模态设计智能体，使其&lt;strong&gt;真正&amp;quot;看到&amp;quot;渲染后的幻灯片&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;inspect_manuscript(md_file)&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;reflect.py:66-117&lt;/code&gt;）：解析 Markdown 文稿，统计页数、用 fastText LID 模型检测语言、校验所有图片引用（标记外链、缺失文件、缺失 alt 文本、重复使用），返回结构化诊断。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由此形成 &lt;strong&gt;observe（观察）→ reflect（反思）→ revise（修正）&lt;/strong&gt; 闭环，观察结果与用户感知一致。&lt;/p&gt;
&lt;p&gt;论文中的 &lt;code&gt;think&lt;/code&gt; 工具并非一个注册的 MCP 工具，而是通过：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;模型原生的 reasoning 字段（&lt;code&gt;ChatMessage.reasoning&lt;/code&gt;，&lt;code&gt;agent.py:183-186&lt;/code&gt; 保留）；&lt;/li&gt;
&lt;li&gt;Agent Harness 本身的 think-act-observe 循环结构实现。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="35-数据合成与轨迹蒸馏deeppresenter-9b"&gt;3.5 数据合成与轨迹蒸馏（DeepPresenter-9B）&lt;/h3&gt;
&lt;p&gt;为了在推理时降低闭源模型的高成本，DeepPresenter 训练了紧凑模型 DeepPresenter-9B。训练管线（论文 Figure 3）三步：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1：任务构建（Query Construction）&lt;/strong&gt;
从 PersonaHub、arXiv、FinePDFs-Edu 三来源构建 1,152 个任务（1,024 训练 + 128 评测）。每个任务附加&lt;strong&gt;可验证约束&lt;/strong&gt;（页数、语言、宽高比），如：&amp;ldquo;I&amp;rsquo;m an English teacher&amp;hellip; Please create a 14-slide presentation in 4:3 aspect ratio, with all content in Chinese.&amp;quot;（统计见论文 Table 1：中英各半、三来源各半、自由/受限宽高比混合）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2：验证引导的轨迹合成（Verification-Guided Trajectory Synthesis）&lt;/strong&gt;
关键问题：&lt;strong&gt;自验证偏差（self-verification bias）&lt;/strong&gt;——智能体在自己产生的轨迹状态内评判自己的输出，验证与自我合理化纠缠，导致有缺陷的输出被接受。
解决方案：&lt;strong&gt;外在验证（extrinsic verification）&lt;/strong&gt;——在隔离上下文中产生验证信号。智能体调用 &lt;code&gt;inspect&lt;/code&gt; 得到观察 o_t 后，&lt;strong&gt;独立的 critic 模型&lt;/strong&gt;（论文用 Gemini-3-Pro，&lt;code&gt;PPTea-main/sarl/coldstart/process_oversight.py&lt;/code&gt; 实现）基于 o_t 与中间产物做验证，输出识别缺陷（如低对比度）并给出可操作修改建议（如调整文字颜色）的推理轨迹，作为 &lt;code&gt;think&lt;/code&gt; 调用注入智能体上下文，引导其修正后继续 rollout。
论文 Figure 4 显示外在验证在各类缺陷（尤其是版面 layout 308 vs 212、渲染 render 101 vs 43）上检出数量远超自验证，说明自验证系统性漏检。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3：轨迹过滤（Trajectory Filtering）&lt;/strong&gt;
三级过滤（&lt;code&gt;PPTea-main/sarl/evaluation/&lt;/code&gt; 中的评分 + &lt;code&gt;trajectory_collect.py&lt;/code&gt; 的阈值）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;规则验证约束符合度（页数/宽高比/语言）；&lt;/li&gt;
&lt;li&gt;用 GLM-4.6 评估一致性，删除未按外在验证轨迹做对齐修改的（反思-动作不一致）轨迹；&lt;/li&gt;
&lt;li&gt;用 GLM-4.6V 评估输出质量，过滤有关键缺陷（元素重叠、图片断裂）的轨迹。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最终 802 条轨迹通过过滤，在 GLM-4.6V-Flash 上用 MS-SWIFT 微调（batch 32、lr 1e-5、5 epochs、8×A800 约 80 GPU 小时），得到 DeepPresenter-9B。&lt;/p&gt;
&lt;p&gt;论文 Figure 5 展示过滤前的失败分布：质量错误 43.0%（自由式生成难保质量）、环境错误 32.3%（长时程脆弱性：上下文溢出与基础设施故障）、约束违规 13.5%、一致性错误 11.2%。&lt;/p&gt;
&lt;h3 id="36-实验结果"&gt;3.6 实验结果&lt;/h3&gt;
&lt;p&gt;评测协议：128 个 held-out 任务，四个维度：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Constraint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;规则验证：约束满足比例（页数/语言/宽高比），0-5 分&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Content &amp;amp; Style&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;沿用 Zheng et al. (2025) 的 MLLM 评测框架，GPT-5 为 judge，0-5 分&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Diversity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DINOv2 特征 + Vendi Score（特征相似矩阵的特征值熵），0-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;主结果（论文 Table 2）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;框架&lt;/th&gt;
&lt;th&gt;模型&lt;/th&gt;
&lt;th&gt;Constraint&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Style&lt;/th&gt;
&lt;th&gt;Avg&lt;/th&gt;
&lt;th&gt;Diversity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gamma（商业）&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;4.93&lt;/td&gt;
&lt;td&gt;4.08&lt;/td&gt;
&lt;td&gt;4.08&lt;/td&gt;
&lt;td&gt;4.36&lt;/td&gt;
&lt;td&gt;0.52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPTAgent&lt;/td&gt;
&lt;td&gt;Gemini-3-Pro&lt;/td&gt;
&lt;td&gt;4.22&lt;/td&gt;
&lt;td&gt;3.09&lt;/td&gt;
&lt;td&gt;4.30&lt;/td&gt;
&lt;td&gt;3.87&lt;/td&gt;
&lt;td&gt;0.19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KCTV&lt;/td&gt;
&lt;td&gt;Claude-Sonnet-4.5&lt;/td&gt;
&lt;td&gt;4.88&lt;/td&gt;
&lt;td&gt;2.90&lt;/td&gt;
&lt;td&gt;3.99&lt;/td&gt;
&lt;td&gt;3.92&lt;/td&gt;
&lt;td&gt;0.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeepPresenter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gemini-3-Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.70&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.25&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.37&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.44&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.79&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeepPresenter-9B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;微调&lt;/td&gt;
&lt;td&gt;4.77&lt;/td&gt;
&lt;td&gt;3.52&lt;/td&gt;
&lt;td&gt;4.29&lt;/td&gt;
&lt;td&gt;4.19&lt;/td&gt;
&lt;td&gt;0.53&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DeepPresenter + Gemini-3-Pro 达到 SOTA（4.44），超过商业系统 Gamma（4.36）与所有开源基线；&lt;/li&gt;
&lt;li&gt;Content 提升最大：Researcher 做意图自适应检索与综合，而非依赖固定工作流或用户提供材料；&lt;/li&gt;
&lt;li&gt;Style 提升来自内容感知设计与环境接地反思；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diversity 0.79 是模板方法的 2 倍以上&lt;/strong&gt;（0.17-0.35），自由式生成带来视觉多样性；&lt;/li&gt;
&lt;li&gt;DeepPresenter-9B 以 802 条轨迹达到 4.19，超过所有开源基线，接近 GPT-5（4.22）而成本低得多（论文 Figure 6 的帕累托前沿）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;消融（论文 Table 3，Gemini-3-Pro）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;w/o Grounded Reflection：4.44 → 4.32（关闭 inspect 后反思局限在渲染前产物）；&lt;/li&gt;
&lt;li&gt;w/o Dual-Agent：4.44 → 4.04（双智能体把长时程执行分解为专业化子任务贡献显著）；&lt;/li&gt;
&lt;li&gt;训练策略：w/o Trajectory Filtering 使 DeepPresenter-9B 从 4.19 → 4.03；extrinsic verification 带来比纯微调高 67% 的提升（Table 4：+0.20 vs +0.12）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;人类评估（附录 A.1，2 名研究生评 32 份）：DeepPresenter 4.22 vs PPTAgent 3.46 / KCTV 3.48 / Gamma 4.09，相对排序与自动评测一致。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="4-代码架构总览两条代码路径"&gt;4. 代码架构总览：两条代码路径&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;PPTAgent/ （仓库根目录）
├── deeppresenter/ ← 当前主产品面（Agentic 运行时）
│ ├── main.py ← AgentLoop 编排入口
│ ├── agents/ ← 智能体（agent.py 基类 + research/design/pptagent/planner/subagent）
│ ├── tools/ ← MCP 工具服务器（search/any2markdown/reflect/task/tool_agents）
│ ├── roles/ ← 角色定义（Research.yaml/Design.yaml/PPTAgent.yaml/Planner.yaml/SubAgent.yaml）
│ ├── utils/ ← 配置/常量/日志/webview/mineru/mcp_client
│ ├── html2pptx/ ← Node.js HTML→PPTX 转换管道
│ ├── cli/ ← Typer CLI（onboard/generate/serve/config/clean）
│ └── docker/ ← 沙箱 Docker 镜像与本地运行脚本
│
├── pptagent/ ← 旧版核心库（PPTAgent 论文的生成+评测）
│ ├── pptgen.py ← Stage II 生成流水线（PPTGen/PPTAgent）
│ ├── induct.py ← Stage I 版面归纳（SlideInducter）
│ ├── apis.py ← 编辑 API 与 CodeExecutor
│ ├── agent.py ← 通用 LLM 智能体（YAML 角色 + Jinja2）
│ ├── presentation/ ← PPTX 解析/HTML 渲染/Closure 构建
│ ├── document/ ← 文档解析（markdown→Document）
│ ├── ppteval/ ← PPTEval 评测框架
│ ├── roles/ prompts/ ← 角色与提示词模板
│ ├── mcp_server.py ← pptagent-mcp（模板式幻灯片生成 MCP server）
│ └── templates/ ← 预处理的参考模板（beamer/cip/default/hit/thu/ucas）
│
└── PPTea-main/ ← 评测/蒸馏实验基础设施（独立仓库，deeppresenter 是软链接）
└── sarl/
├── evaluation/ ← 各框架生成适配器 + 两阶段评分管线
├── coldstart/ ← SFT 轨迹收集与蒸馏训练
├── dataset/ ← 数据集构建（typings.py 数据模型）
└── analysis/ ← 论文图表（帕累托/工具使用/缺陷分布）
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="5-agent-harness-主循环详解"&gt;5. Agent Harness 主循环详解&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Agent Harness&lt;/strong&gt;（&lt;code&gt;deeppresenter/agents/agent.py&lt;/code&gt;，462 行）是整个 DeepPresenter 的核心：一个通用的 &lt;strong&gt;think → act → observe&lt;/strong&gt; ReAct 式工具调用循环，所有具体智能体（Research/Design/PPTAgent/Planner/SubAgent）都复用这个基类。&lt;/p&gt;
&lt;h3 id="51-通用智能体基类-agent"&gt;5.1 通用智能体基类 Agent&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;初始化&lt;/strong&gt;（&lt;code&gt;agent.py:57-136&lt;/code&gt;）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从 &lt;code&gt;roles/&amp;lt;ClassName&amp;gt;.yaml&lt;/code&gt; 加载角色配置（&lt;code&gt;RoleConfig&lt;/code&gt;）：system prompt（分语言）、Jinja2 instruction 模板、&lt;code&gt;use_model&lt;/code&gt;（用哪个 LLM 字段）、&lt;code&gt;ToolSet&lt;/code&gt;（包含/排除哪些 MCP server 与工具）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;self.llm = config[role_config.use_model]&lt;/code&gt;（research_agent / design_agent / long_context_model）；&lt;/li&gt;
&lt;li&gt;记录 &lt;code&gt;context_window&lt;/code&gt;（默认 40k = CONTEXT_LENGTH_LIMIT 200k / max_context_folds 5）、&lt;code&gt;max_context_turns&lt;/code&gt;（5）、&lt;code&gt;max_turns&lt;/code&gt;（可选上限）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_setup_toolset()&lt;/code&gt;（&lt;code&gt;agent.py:138-155&lt;/code&gt;）从 &lt;code&gt;agent_env&lt;/code&gt; 解析工具列表（&lt;code&gt;&amp;quot;all&amp;quot;&lt;/code&gt; 展开为所有已连接 server，再减排除项），生成 OpenAI function-tool 字典列表；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拼接系统提示词&lt;/strong&gt;：角色 system prompt + &lt;code&gt;AGENT_PROMPT&lt;/code&gt;（环境描述与工具调用规则：充分探索、并行工具调用、每轮最多 7 个工具、截断策略）+ &lt;code&gt;MA_RESEACHER_PROMPT&lt;/code&gt;/&lt;code&gt;MA_RRESENTER_PROMPT&lt;/code&gt;（多智能体委派指南）+ &lt;code&gt;OFFLINE_PROMPT&lt;/code&gt;（离线模式）+ &lt;code&gt;CONTEXT_MODE_PROMPT&lt;/code&gt;（上下文折叠模式）；&lt;/li&gt;
&lt;li&gt;初始化 &lt;code&gt;chat_history = [SYSTEM 消息]&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="52-actionllm-思考与工具调用生成"&gt;5.2 action：LLM 思考与工具调用生成&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;action()&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;agent.py:191-240&lt;/code&gt;）——每一轮循环的 LLM 步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;递增 &lt;code&gt;turn_count&lt;/code&gt;，执行 &lt;code&gt;max_turns&lt;/code&gt; 上限（剩余 &amp;lt;2 轮时注入 &amp;ldquo;finish now&amp;rdquo; 提示）；&lt;/li&gt;
&lt;li&gt;首次调用时把渲染好的 Jinja2 instruction 作为 USER 消息追加；&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;self.llm.run(messages=self.chat_history, tools=self.tools)&lt;/code&gt; —— &lt;strong&gt;OpenAI 原生 function calling&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;记录 token 用量到 &lt;code&gt;self.cost&lt;/code&gt; 与 &lt;code&gt;self.context_length&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;把 assistant 消息（content + tool_calls + 可选的 reasoning）追加到历史并返回。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="53-execute工具执行与观察收集"&gt;5.3 execute：工具执行与观察收集&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;execute()&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;agent.py:250-348&lt;/code&gt;）——每一轮循环的动作步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;取出 assistant 消息的 &lt;code&gt;tool_calls&lt;/code&gt;，用 JSON schema 校验参数，强制 &lt;code&gt;MAX_TOOLCALL_PER_TURN&lt;/code&gt;（默认 7）；&lt;/li&gt;
&lt;li&gt;检测特殊工具 &lt;strong&gt;&lt;code&gt;finalize&lt;/code&gt;&lt;/strong&gt;：暂存其 &lt;code&gt;outcome&lt;/code&gt; 参数与 &lt;code&gt;finish_id&lt;/code&gt;，并注入 &lt;code&gt;agent_name&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并行执行所有工具&lt;/strong&gt;：&lt;code&gt;asyncio.gather(self.agent_env.tool_execute(t)...)&lt;/code&gt;（&lt;code&gt;agent.py:292&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;观察归一化：含图片的结果按模型类型格式化（Gemini/Qwen 转 &lt;code&gt;role=USER&lt;/code&gt;，Claude 转 &lt;code&gt;image&lt;/code&gt;+&lt;code&gt;source.base64&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;观察追加到 &lt;code&gt;chat_history&lt;/code&gt;，错误记录到 &lt;code&gt;error_history&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;若 &lt;code&gt;finalize&lt;/code&gt; 被调用且其观察文本等于 outcome，&lt;strong&gt;返回 outcome 字符串（表示循环完成）&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文预算告警&lt;/strong&gt;（&lt;code&gt;agent.py:325-336&lt;/code&gt;）：context 超 50% 注入 &lt;code&gt;HALF_BUDGET_NOTICE_MSG&lt;/code&gt;，超 80% 注入 &lt;code&gt;URGENT_BUDGET_NOTICE_MSG&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文溢出处理&lt;/strong&gt;（&lt;code&gt;agent.py:341-347&lt;/code&gt;）：&lt;code&gt;context_length &amp;gt; context_window&lt;/code&gt; 时，若启用折叠则 &lt;code&gt;compact_history()&lt;/code&gt;，否则抛 RuntimeError；&lt;/li&gt;
&lt;li&gt;返回 outcome 字符串或观察 ChatMessage 列表。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="54-上下文管理与-compact_history"&gt;5.4 上下文管理与 compact_history&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;compact_history()&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;agent.py:356-401&lt;/code&gt;）——防止上下文溢出的核心机制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;保留 &lt;code&gt;keep_head=10&lt;/code&gt; + &lt;code&gt;keep_tail=4&lt;/code&gt; 条消息，中间的折叠；&lt;/li&gt;
&lt;li&gt;先保存完整历史（&lt;code&gt;message_only=True&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;MEMORY_COMPACT_MSG&lt;/code&gt;（&lt;code&gt;constants.py:154-184&lt;/code&gt; 的详细摘要指令）配合 &lt;code&gt;self.chat_history + [summary_ask]&lt;/code&gt; 请求 LLM 总结；&lt;/li&gt;
&lt;li&gt;LLM 的摘要消息（可能含 tool_calls）被执行；追加 &lt;code&gt;CONTINUE_MSG&lt;/code&gt;（最后折叠时 &lt;code&gt;LAST_ITER_MSG&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;重构历史为 &lt;code&gt;head + tail + [summary_ask, summary_message, *observations]&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;受 &lt;code&gt;max_context_turns&lt;/code&gt;（5 次折叠）限制。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;配套的 &lt;code&gt;_split_history()&lt;/code&gt;（&lt;code&gt;agent.py:403-421&lt;/code&gt;）保证 tool-call/tool-result 消息配对保持在 head 中，用 &lt;code&gt;HIST_LOST_MSG&lt;/code&gt; 标记截断点。&lt;/p&gt;
&lt;h3 id="55-loop各智能体的主循环"&gt;5.5 loop：各智能体的主循环&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;loop()&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;agent.py:242-249&lt;/code&gt;）是抽象异步生成器，所有具体智能体实现它，但模式相同：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;action(&lt;span style="color:#f92672"&gt;**&lt;/span&gt;kwargs) &lt;span style="color:#75715e"&gt;# 思考 + 生成工具调用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; agent_message &lt;span style="color:#75715e"&gt;# 流式输出进度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; outcome &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;chat_history[&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool_calls) &lt;span style="color:#75715e"&gt;# 行动 + 观察&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; isinstance(outcome, list):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; item &lt;span style="color:#f92672"&gt;in&lt;/span&gt; outcome:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; item &lt;span style="color:#75715e"&gt;# 流式输出观察&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; outcome
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt; &lt;span style="color:#75715e"&gt;# finalize → 循环结束&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是标准的 &lt;strong&gt;ReAct 式 harness&lt;/strong&gt;：action（LLM）→ execute（工具）→ 观察 → 重复直到 &lt;code&gt;finalize&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;各具体智能体的 loop：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Research&lt;/strong&gt;（&lt;code&gt;research.py:8-24&lt;/code&gt;）：&lt;code&gt;loop(req, outline_path)&lt;/code&gt; 跑通用循环，action 注入 deepresearch prompt + 附件 + 大纲路径；最终 finalize 返回 &lt;code&gt;.md&lt;/code&gt; 文稿路径；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design&lt;/strong&gt;（&lt;code&gt;design.py:5-20&lt;/code&gt;）：&lt;code&gt;loop(req, markdown_file)&lt;/code&gt; 创建 &lt;code&gt;slides/&lt;/code&gt; 目录跑循环，&lt;code&gt;while True&lt;/code&gt; 收到字符串 outcome 后跳出再 yield 一次（HTML 目录）；逐页 write + inspect_slide + 修复；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPTAgent&lt;/strong&gt;（&lt;code&gt;pptagent.py:5-29&lt;/code&gt;）：&lt;code&gt;loop(req, markdown_file)&lt;/code&gt; 通过 &lt;code&gt;pptagent&lt;/code&gt; MCP 工具（list_templates/set_template/create_slide/write_slide/generate_slide）做模板式生成；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planner&lt;/strong&gt;（&lt;code&gt;planner.py:8-48&lt;/code&gt;）：两阶段生成器——阶段 1 跑循环产出 outline JSON 路径；阶段 2 是&lt;strong&gt;交互式修订循环&lt;/strong&gt;（&lt;code&gt;feedback = yield outcome&lt;/code&gt;，CLI 通过 &lt;code&gt;.asend(feedback)&lt;/code&gt; 推送修订指令，非空则追加为 USER 消息重新跑循环）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SubAgent&lt;/strong&gt;（&lt;code&gt;subagent.py:46-51&lt;/code&gt;）：通用循环，从 Context 文件读委派任务，产出 deliverable 文件后 finalize。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="6-agent-harness-框架架构模块与角色"&gt;6. Agent Harness 框架架构：模块与角色&lt;/h2&gt;
&lt;h3 id="61-编排层-agentloopmainpy"&gt;6.1 编排层 AgentLoop（main.py）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;deeppresenter/main.py&lt;/code&gt;（233 行）是顶层编排入口，&lt;code&gt;AgentLoop.run()&lt;/code&gt; 是 async generator，逐步 yield 进度 &lt;code&gt;ChatMessage&lt;/code&gt; 与最终产物路径。管线如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;AgentLoop.run()
├── 1. 设置阶段（main.py:58-84）
│ ├── 可选校验 LLM
│ ├── 附件复制到 workspace/attachments/（request.copy_to_workspace）
│ ├── 写入 .input_request.json
│ ├── 打开 AgentEnv 异步上下文
│ └── [multiagent_mode] 注册 delegate_subagent 本地工具
│
├── 2. 可选 Planner 阶段（main.py:87-110）
│ └── planner.loop(request) → outline JSON（可交互修订）
│
├── 3. Research 阶段（main.py:112-139）
│ └── research_agent.loop(request, outline_path) → manuscript.md
│
├── 4. 生成阶段，按 convert_type 分支（main.py:141-221）
│ ├── PPTAGENT：PPTAgent.loop(request, md_file) → .pptx
│ └── DEEPPRESENTER：Design.loop(request, md_file) → slides/*.html
│ └── 导出：convert_html_to_pptx()（Node html2pptx）
│ └── 失败回退：PlaywrightConverter.convert_to_pdf → .pdf
│
└── 5. 收尾（main.py:222-224）
└── save_results() 写 intermediate_output.json（outline/manuscript/pptx/final 路径）
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;每个子阶段都 &lt;code&gt;save_history()&lt;/code&gt; / &lt;code&gt;save_results()&lt;/code&gt;（在 &lt;code&gt;finally&lt;/code&gt; 中），日志写到 &lt;code&gt;workspace/.history/deeppresenter-loop.log&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="62-环境层-agentenv-与工具执行envpy"&gt;6.2 环境层 AgentEnv 与工具执行（env.py）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;deeppresenter/agents/env.py&lt;/code&gt;（454 行）管理 MCP server、工具注册、沙箱与异步工具执行：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;__init__&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;env.py:54-109&lt;/code&gt;）：加载 &lt;code&gt;mcp.json&lt;/code&gt; 的 &lt;code&gt;MCPServer&lt;/code&gt; 定义（离线模式跳过 network server），计算 docker-in-docker 的 &lt;code&gt;HOST_WORKSPACE&lt;/code&gt; 卷映射，构建 &lt;code&gt;envs&lt;/code&gt; 字典（WORKSPACE/HOST_WORKSPACE/WORKSPACE_ID/CONFIG_FILE/PACKAGE_DIR&amp;hellip;）传给 MCPClient，避免全局环境变量污染；注册工具注册表（&lt;code&gt;_local_tools&lt;/code&gt;/&lt;code&gt;_tools_dict&lt;/code&gt;/&lt;code&gt;_server_tools&lt;/code&gt;/&lt;code&gt;_tool_to_server&lt;/code&gt;）；&lt;code&gt;async_tool_mode&lt;/code&gt; 开启时注册 &lt;code&gt;gather&lt;/code&gt; 工具；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;__aenter__&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;env.py:228-266&lt;/code&gt;）：清理同名陈旧 docker 容器，并行连接所有 MCP server，缓存全部工具规格到 &lt;code&gt;.tools.json&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;__aexit__&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;env.py:268-300&lt;/code&gt;）：断开 server，写 &lt;code&gt;tool_history.jsonl&lt;/code&gt; 与 &lt;code&gt;tools_time_cost.json&lt;/code&gt;（工具调用的完整审计日志）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;register_tool&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;env.py:347-372&lt;/code&gt;）：把 Python 可调用对象注册为本地工具（用 FastMCP 的 typeadapter 从类型注解自动生成 JSON schema），用于 &lt;code&gt;delegate_subagent&lt;/code&gt; 与 &lt;code&gt;gather&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tool_execute&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;env.py:111-226&lt;/code&gt;）：统一工具执行路径——jsonschema 校验参数 → &lt;code&gt;_execute_tool&lt;/code&gt; → 包装成 &lt;code&gt;ChatMessage(role=TOOL)&lt;/code&gt;。&lt;strong&gt;结果截断&lt;/strong&gt;（&lt;code&gt;env.py:186-203&lt;/code&gt;）：文本超 &lt;code&gt;TOOL_CUTOFF_LEN&lt;/code&gt;（4096 字符）在最后一个换行截断并附 &lt;code&gt;CUTOFF_WARNING&lt;/code&gt;，全文保存到本地文件供 &lt;code&gt;read_file&lt;/code&gt; 按偏移读取；图片结果转 &lt;code&gt;image_url&lt;/code&gt; 块。记录每个工具耗时/成功/失败；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;_execute_tool&lt;/code&gt;&lt;/strong&gt;（&lt;code&gt;env.py:403-423&lt;/code&gt;）异步工具模式：非白名单工具（gather/finalize/inspect_slide 除外）限时 5 秒，超时返回占位符并后台继续，智能体之后用 &lt;code&gt;gather&lt;/code&gt; 收集结果——这允许智能体&lt;strong&gt;并行执行多个长时程任务&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工具调用路径：LLM 原生 function calling → &lt;code&gt;Agent.execute&lt;/code&gt; → &lt;code&gt;agent_env.tool_execute&lt;/code&gt; → 本地 Python 可调用 或 &lt;code&gt;MCPClient.session.call_tool&lt;/code&gt;（&lt;code&gt;utils/mcp_client.py&lt;/code&gt;，stdio/SSE 子进程连接，&lt;code&gt;MCP_CALL_TIMEOUT&lt;/code&gt; 默认 1800 秒）。&lt;/p&gt;
&lt;h3 id="63-mcp-工具服务器tools"&gt;6.3 MCP 工具服务器（tools/）&lt;/h3&gt;
&lt;p&gt;每个文件是独立的 FastMCP server（按 &lt;code&gt;mcp.json&lt;/code&gt; 以子进程启动），提供以下工具：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;类别&lt;/th&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Search&lt;/code&gt;（&lt;code&gt;search.py&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;Retrieve&lt;/td&gt;
&lt;td&gt;&lt;code&gt;search_web&lt;/code&gt; / &lt;code&gt;search_images&lt;/code&gt; / &lt;code&gt;fetch_url&lt;/code&gt; / &lt;code&gt;download_file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SerpAPI 优先、Tavily 备选；Playwright 渲染网页 + trafilatura/markdownify 提取；图片下载校验（WEBP→PNG）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Any2Markdown&lt;/code&gt;（&lt;code&gt;any2markdown.py&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;File&lt;/td&gt;
&lt;td&gt;&lt;code&gt;convert_to_markdown&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PDF/DOCX 转 Markdown：MinerU（在线 API 或离线部署）或 MarkItDown；base64 图片落盘、链接改绝对路径、报告图片尺寸&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DeepPresenter&lt;/code&gt;（&lt;code&gt;reflect.py&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reason&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;inspect_slide&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;inspect_manuscript&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;环境接地反思的两个观察接口（见 3.4 节）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Task&lt;/code&gt;（&lt;code&gt;task.py&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;finalize&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;循环终止工具，按智能体类型做最终校验（Planner 要 .json；Research 要 .md 并重写图片绝对路径+注入宽高比到 alt；PPTAgent 要有效 .pptx；Design 要 slide_*.html 目录）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ToolAgents&lt;/code&gt;（&lt;code&gt;tool_agents.py&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;Create/Reason&lt;/td&gt;
&lt;td&gt;&lt;code&gt;image_generation&lt;/code&gt; / &lt;code&gt;image_caption&lt;/code&gt; / &lt;code&gt;document_summary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;条件注册：配置了 t2i_model 才提供文生图；vision_model 提供图片分类+描述（Table/Chart/Logo + &amp;lt;50 词）；multiagent 模式提供长文档摘要&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pptagent&lt;/code&gt;（&lt;code&gt;pptagent/mcp_server.py&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;模板生成&lt;/td&gt;
&lt;td&gt;&lt;code&gt;list_templates&lt;/code&gt; / &lt;code&gt;set_template&lt;/code&gt; / &lt;code&gt;create_slide&lt;/code&gt; / &lt;code&gt;write_slide&lt;/code&gt; / &lt;code&gt;generate_slide&lt;/code&gt; / &lt;code&gt;markdown_table_to_image&lt;/code&gt; / &lt;code&gt;save_generated_slides&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;旧版模板式生成，仅供 PPTAgent 智能体&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sandbox&lt;/code&gt;（&lt;code&gt;docker/server.ts&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;File&lt;/td&gt;
&lt;td&gt;&lt;code&gt;read_file&lt;/code&gt; / &lt;code&gt;write_file&lt;/code&gt; / &lt;code&gt;move_file&lt;/code&gt; / &lt;code&gt;edit_file&lt;/code&gt; / &lt;code&gt;create_directory&lt;/code&gt; / &lt;code&gt;list_directory&lt;/code&gt; / &lt;code&gt;execute_command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DesktopCommanderMCP 沙箱（Docker 或本地 Node 进程），&lt;code&gt;execute_command&lt;/code&gt; 使智能体成为&amp;quot;沙箱化代码智能体&amp;rdquo;（可跑 shell/python/node/渲染 mermaid），&lt;code&gt;docker/config.json&lt;/code&gt; 屏蔽危险命令（format/mkfs/dd/useradd&amp;hellip;）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;工具按论文 Table 8 分为五类：&lt;strong&gt;Retrieve&lt;/strong&gt;（信息获取）、&lt;strong&gt;File&lt;/strong&gt;（文档操作）、&lt;strong&gt;Reason&lt;/strong&gt;（检查与反思）、&lt;strong&gt;Control&lt;/strong&gt;（任务管理）、&lt;strong&gt;Create&lt;/strong&gt;（代码执行与资产生成）。&lt;/p&gt;
&lt;h3 id="64-角色定义roles"&gt;6.4 角色定义（roles/）&lt;/h3&gt;
&lt;p&gt;每个角色是一个 YAML，定义 system prompt（中英）、Jinja2 instruction 模板、use_model 与 toolset：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;角色文件&lt;/th&gt;
&lt;th&gt;智能体&lt;/th&gt;
&lt;th&gt;模型&lt;/th&gt;
&lt;th&gt;工具集亮点&lt;/th&gt;
&lt;th&gt;指令要点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Research.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Research&lt;/td&gt;
&lt;td&gt;research_agent&lt;/td&gt;
&lt;td&gt;除 pptagent 外所有 server；排除 inspect_slide&lt;/td&gt;
&lt;td&gt;深度调研（广→窄）、信息美学、Markdown 文稿（&lt;code&gt;---&lt;/code&gt; 分页、图片本地化）、inspect_manuscript、finalize 返回 .md&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Design.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Design&lt;/td&gt;
&lt;td&gt;design_agent（多模态）&lt;/td&gt;
&lt;td&gt;sandbox + delegate_subagent + inspect_slide + finalize&lt;/td&gt;
&lt;td&gt;HTML/CSS 固定版式设计、global.css、逐页生成 + inspect_slide 质量检查、按宽高比固定 body 尺寸&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PPTAgent.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PPTAgent&lt;/td&gt;
&lt;td&gt;research_agent&lt;/td&gt;
&lt;td&gt;pptagent + sandbox + finalize&lt;/td&gt;
&lt;td&gt;从 Markdown 做模板式生成、表格转图片、finalize 返回 .pptx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Planner.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Planner&lt;/td&gt;
&lt;td&gt;research_agent&lt;/td&gt;
&lt;td&gt;除 tool_agents/deeppresenter 外所有；排除 search_images&lt;/td&gt;
&lt;td&gt;设计 JSON 大纲 &lt;code&gt;{&amp;quot;slides&amp;quot;:[{index,title,context}]}&lt;/code&gt;、finalize 返回 .json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SubAgent.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SubAgent&lt;/td&gt;
&lt;td&gt;design_agent&lt;/td&gt;
&lt;td&gt;除 pptagent 外所有；排除 delegate_subagent（禁递归）&lt;/td&gt;
&lt;td&gt;从 Context 文件完成单个委派子任务、产出自包含 deliverable、finalize&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;附加动态提示词片段（&lt;code&gt;utils/constants.py&lt;/code&gt;）：&lt;code&gt;AGENT_PROMPT&lt;/code&gt;（环境描述+工具调用规则）、&lt;code&gt;MA_RESEACHER_PROMPT&lt;/code&gt;/&lt;code&gt;MA_RRESENTER_PROMPT&lt;/code&gt;（多智能体并行委派指南）、&lt;code&gt;OFFLINE_PROMPT&lt;/code&gt;、&lt;code&gt;CONTEXT_MODE_PROMPT&lt;/code&gt;、上下文预算告警与 &lt;code&gt;MEMORY_COMPACT_MSG&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="65-配置与常量utils"&gt;6.5 配置与常量（utils/）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;utils/config.py&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;Endpoint&lt;/code&gt;（单端点，路由 litellm 或 AsyncOpenAI，支持 tool-calling/结构化输出/纯对话）、&lt;code&gt;LLM&lt;/code&gt;（多端点交替重试 + 并发信号量 + 多模态自动检测 + &lt;code&gt;generate_image&lt;/code&gt; + &lt;code&gt;validate()&lt;/code&gt;）、&lt;code&gt;DeepPresenterConfig&lt;/code&gt;（&lt;code&gt;multiagent_mode&lt;/code&gt;/&lt;code&gt;offline_mode&lt;/code&gt;/&lt;code&gt;async_tool_mode&lt;/code&gt;/&lt;code&gt;context_folding&lt;/code&gt;/&lt;code&gt;context_window&lt;/code&gt;/&lt;code&gt;max_context_folds&lt;/code&gt;/&lt;code&gt;heavy_reflect&lt;/code&gt; + 三个 LLM 字段）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;utils/typings.py&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;Role&lt;/code&gt;（SYSTEM/USER/ASSISTANT/TOOL）、&lt;code&gt;ChatMessage&lt;/code&gt;（统一消息模型，content 归一为 &lt;code&gt;{type:text/image_url}&lt;/code&gt; 块列表）、&lt;code&gt;ToolSet&lt;/code&gt;/&lt;code&gt;RoleConfig&lt;/code&gt;、&lt;code&gt;Cost&lt;/code&gt;、&lt;code&gt;ConvertType&lt;/code&gt;（DEEPPRESENTER/PPTAGENT）、&lt;code&gt;PowerPointType&lt;/code&gt;（16:9/4:3/A1-A4）、&lt;code&gt;InputRequest&lt;/code&gt;（instruction/attachments/num_pages/template/powerpoint_type/convert_type/enable_planner/extra_info，&lt;code&gt;copy_to_workspace&lt;/code&gt; 复制附件）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;utils/constants.py&lt;/code&gt;&lt;/strong&gt;：全部可调常量（&lt;code&gt;WORKSPACE_BASE&lt;/code&gt;、&lt;code&gt;TOOL_CUTOFF_LEN=4096&lt;/code&gt;、&lt;code&gt;MAX_TOOLCALL_PER_TURN=7&lt;/code&gt;、&lt;code&gt;MAX_SUBAGENT_TURNS=10&lt;/code&gt;、&lt;code&gt;CONTEXT_LENGTH_LIMIT=200k&lt;/code&gt;、&lt;code&gt;MCP_CALL_TIMEOUT=1800s&lt;/code&gt;、&lt;code&gt;PIXEL_MULTIPLE=16&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;utils/webview.py&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;PlaywrightConverter&lt;/code&gt;（共享 headless Chromium，HTML→按宽高比分页 PDF→pdf2image 栅格化为 slide_NN.jpg）与 &lt;code&gt;convert_html_to_pptx&lt;/code&gt;（调 Node &lt;code&gt;html2pptx_cli.js&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;utils/mineru_api.py&lt;/code&gt;&lt;/strong&gt;：MinerU PDF 解析（在线 mineru.net API 或离线自部署端点）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="66-沙箱与-htmlpptx-转换"&gt;6.6 沙箱与 HTML→PPTX 转换&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;沙箱&lt;/strong&gt;：DesktopCommanderMCP 的 Docker 镜像（&lt;code&gt;docker/SandBox.Dockerfile&lt;/code&gt;）或集群本地模式（&lt;code&gt;run_sandbox_local.sh&lt;/code&gt;，SLURM 无 Docker 环境下用本地 Node 进程），提供通用代码执行能力；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTML→PPTX&lt;/strong&gt;（&lt;code&gt;html2pptx/&lt;/code&gt;）：Node CLI 用 pptxgenjs + 自定义 &lt;code&gt;html2pptx.js&lt;/code&gt; 转换器，支持 16:9/4:3/A1-A4 布局、&lt;code&gt;--validate&lt;/code&gt;/&lt;code&gt;--soft&lt;/code&gt; 选项，依赖 playwright 与 sharp；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置示例&lt;/strong&gt;：&lt;code&gt;config.yaml.example&lt;/code&gt;（LLM 块 + 模式开关）、&lt;code&gt;mcp.json.example&lt;/code&gt;（7 个 MCP server，&lt;code&gt;$VAR&lt;/code&gt; 占位符由 &lt;code&gt;MCPServer._process_escape&lt;/code&gt; 从 AgentEnv.envs 解析）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="67-完整端到端流程图"&gt;6.7 完整端到端流程图&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pptagent generate &amp;#34;主题&amp;#34; -f 附件.pdf --planner
└─ CLI commands.generate → AgentLoop(config, request)
└─ AgentLoop.run()
├─ AgentEnv.__aenter__：并行连接 7 个 MCP server，缓存工具规格
├─ [enable_planner] Planner.loop：action/execute 循环 → outline.json → finalize
│ └─ CLI 交互式修订（_edit_outline：Rich 表格展示，y 批准或自然语言修订）
├─ Research.loop：action → [search_web, fetch_url, convert_to_markdown,
│ image_generation...] → execute（并行、4096 字符截断）→ 观察
│ → inspect_manuscript → finalize(manuscript.md)
│ [context &amp;gt;40k 触发 compact_history 摘要折叠]
├─ convert_type 分支：
│ ├─ PPTAGENT：PPTAgent.loop → list_templates → set_template
│ │ → create_slide → write_slide → generate_slide → finalize(.pptx)
│ └─ DEEPPRESENTER：Design.loop
│ → read manuscript → write global.css
│ → [逐页] write slide_NN.html → inspect_slide（渲染+校验；
│ heavy_reflect 时多模态智能体&amp;#34;看到&amp;#34;渲染 JPEG 并修复）
│ → finalize(slides/) [多智能体：delegate_subagent 并行生成]
└─ 导出：convert_html_to_pptx(slides/, out.pptx, 宽高比, soft)
└─ node html2pptx_cli.js → pptxgenjs → .pptx
[失败回退：PlaywrightConverter.convert_to_pdf → .pdf]
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="7-pptea-main评测与蒸馏实验基础设施"&gt;7. PPTea-main：评测与蒸馏实验基础设施&lt;/h2&gt;
&lt;h3 id="71-pptea-main-是什么"&gt;7.1 PPTea-main 是什么&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PPTea-main 不是独立产品，而是 DeepPresenter 项目的实验/评测/蒸馏基础设施&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;deeppresenter/&lt;/code&gt; 是指向 &lt;code&gt;../PPTAgent/deeppresenter&lt;/code&gt; 的&lt;strong&gt;软链接&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sarl/&lt;/code&gt; 包（0.1.0，docstring &amp;ldquo;SARL Package&amp;rdquo;）大量 import &lt;code&gt;deeppresenter.*&lt;/code&gt; 与 &lt;code&gt;pptagent.*&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;它实现了 project-demand.md 描述的完整闭环：&lt;strong&gt;各 Agent Harness 生成 → Workspace 对齐 → PPTEval 评分 → 分析 → 轨迹蒸馏&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="72-评测流程两阶段评分管线"&gt;7.2 评测流程（两阶段评分管线）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;PPTea-main/sarl/evaluation/&lt;/code&gt; 提供各竞争框架的&lt;strong&gt;生成适配器&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文件&lt;/th&gt;
&lt;th&gt;框架&lt;/th&gt;
&lt;th&gt;机制&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deeppresenter_gen.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DeepPresenter&lt;/td&gt;
&lt;td&gt;调 &lt;code&gt;deeppresenter.main.AgentLoop.run()&lt;/code&gt;，写 &lt;code&gt;.datapoint.json&lt;/code&gt; 后立即 &lt;code&gt;score_workspace()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;codex_gen.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Codex CLI（GPT-5）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;codex exec --sandbox danger-full-access&lt;/code&gt; + &lt;code&gt;pptx-generator&lt;/code&gt; Skill（&lt;code&gt;../Deeppresenter-skills/skills/pptx-generator&lt;/code&gt;），&lt;code&gt;verify_workspace_ready()&lt;/code&gt; 校验 PPTea 兼容别名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pptagent_gen.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PPTAgent（旧基线）&lt;/td&gt;
&lt;td&gt;包装 &lt;code&gt;pptagent.pptgen.PPTAgent&lt;/code&gt;，模板归纳生成，soffice 转 PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gamma.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gamma（商业）&lt;/td&gt;
&lt;td&gt;Gamma 公开 REST API，轮询完成后下载 PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kctv.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;KCTV（基线）&lt;/td&gt;
&lt;td&gt;两步 LLM：提取结构化 JSON → LaTeX，xelatex 渲染 PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 —— Content &amp;amp; Style 评分&lt;/strong&gt;（&lt;code&gt;score_exp.py&lt;/code&gt; → &lt;code&gt;score_workspace()&lt;/code&gt;）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读 &lt;code&gt;.datapoint.json&lt;/code&gt; 与 &lt;code&gt;intermediate_output.json&lt;/code&gt; 找最终 PDF；&lt;/li&gt;
&lt;li&gt;定位幻灯片图片目录 &lt;code&gt;.slide_images-pdf-{stem}/slide_XX.jpg&lt;/code&gt;（&lt;strong&gt;所有框架的评测输入统一归一化为这个格式&lt;/strong&gt;）；&lt;/li&gt;
&lt;li&gt;校验 PPTea 文稿别名 &lt;code&gt;.slides.md&lt;/code&gt;（必须等于 &lt;code&gt;manuscript.md&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确定性约束检查&lt;/strong&gt;：&lt;code&gt;dp.verify()&lt;/code&gt; 用 PyPDF 查页数、mediabox 查宽高比、fasttext LID 查语言 → 0-1 分 ×5；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逐页 VLM 评分&lt;/strong&gt;（8 并发，GPT-5 多模态 judge）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;content_descriptor&lt;/code&gt; 描述内容 → &lt;code&gt;text_scorer&lt;/code&gt; 打 Content 分；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style_descriptor&lt;/code&gt; 描述风格 → &lt;code&gt;vision_scorer&lt;/code&gt; 打 Style 分；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;写 &lt;code&gt;slide_evals.json&lt;/code&gt;（逐页）与 &lt;code&gt;evals.json&lt;/code&gt;（平均：constraint/content/style）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 —— 约束 VLM 评测&lt;/strong&gt;（&lt;code&gt;score_exp_complex.py&lt;/code&gt; → &lt;code&gt;score_workspace_constraints()&lt;/code&gt;）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;仅对通过 Phase 1 阈值的 workspace 运行（默认 min_content=3.5 / min_style=3.5 / min_constraint=1.0）；&lt;/li&gt;
&lt;li&gt;对 DataPoint 中的每个 &lt;code&gt;Constraint&lt;/code&gt;（STYLE 类评估所有页，其余评估指定页），用 &lt;code&gt;prompt/judge_constraints.txt&lt;/code&gt; VLM judge 判定 satisfied(1.0)/partially(0.5)/not(0.0)；&lt;/li&gt;
&lt;li&gt;写 &lt;code&gt;constraint_evals.json&lt;/code&gt;，更新 &lt;code&gt;evals.json&lt;/code&gt; 的 &lt;code&gt;constraint_vlm&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;辅助评测设施&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;divesity.py&lt;/code&gt;：DINOv2 特征 + Vendi Score 的幻灯片风格多样性指标（0-1）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;plot_score_dist.py&lt;/code&gt;：分数分布直方图（确定过滤阈值）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;review_server.py&lt;/code&gt;：FastAPI 人工审核面板（8080 端口，缩略图+分数网格、逐 workspace 审核、reasonable/partially/unreasonable 三档判定）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finish_codex_benchmark.py&lt;/code&gt;：Codex workspace 的确定性终结器（校验语义产物存在、重跑 pptxgen html validate/render + convert + package，验证 PPTea 别名；&lt;strong&gt;明确拒绝合成内容&lt;/strong&gt;，只做确定性渲染/转换/打包）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="73-数据模型与-workspace-对齐"&gt;7.3 数据模型与 Workspace 对齐&lt;/h3&gt;
&lt;p&gt;核心数据模型（&lt;code&gt;sarl/dataset/typings.py&lt;/code&gt;）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DataPoint: &lt;span style="color:#75715e"&gt;# 一个评测任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prompt: str &lt;span style="color:#75715e"&gt;# 用户指令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; language: &lt;span style="color:#e6db74"&gt;&amp;#34;zh&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: &lt;span style="color:#e6db74"&gt;&amp;#34;arXiv&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;finepdfs&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;personahub&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;|...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aspect_ratio: PowerPointType &lt;span style="color:#75715e"&gt;# 16:9 | 4:3 | A1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; page_low, page_high: int &lt;span style="color:#75715e"&gt;# 页数约束&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attachments: list[str] &lt;span style="color:#75715e"&gt;# 附件路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; constraints: list[Constraint] &lt;span style="color:#75715e"&gt;# 结构约束（STYLE/COVER/AGENDA/VISUAL_CHART/...）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: str &lt;span style="color:#75715e"&gt;# md5(prompt+attachments)[:8]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Workspace 对齐协议&lt;/strong&gt;（所有框架必须产出）：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;workspace/{task_id}/
.datapoint.json # 输入任务
.slides.md # == manuscript.md（PPTea 文稿别名）
manuscript.md # 完整幻灯片文稿
slide_manifest.json # 幻灯片结构清单
design-system.json # 品牌/排版配置
slides/global.css + slide_01.html... # HTML 幻灯片源码
renders/html/ slide_01.png + renders/pptx/ slide_01.png # 渲染截图
.slide_images-pdf-{stem}/slide_XX.jpg # 评测图片（评分唯一输入）
delivery/ presentation.pptx + presentation.pdf + source.zip # 最终交付
intermediate_output.json / run.json / qa/ / evals.json / slide_evals.json / constraint_evals.json
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="74-轨迹蒸馏与冷启动"&gt;7.4 轨迹蒸馏与冷启动&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sarl/coldstart/&lt;/code&gt; 实现 SFT 蒸馏管线（把大模型 DeepPresenter 蒸馏为 Qwen3-VL-4B）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trajectory_collect.py&lt;/code&gt;&lt;/strong&gt;：把完成的 DeepPresenter workspace 转成 SFT 轨迹，应用质量过滤（&lt;code&gt;constraint==1.0, content&amp;gt;=3.9, style&amp;gt;=3.9, constraint_vlm&amp;gt;=0.65&lt;/code&gt;），过滤重复输出、消息去重、注入合成 &lt;code&gt;thinking&lt;/code&gt; 工具，导出 &lt;code&gt;data/stage1/trajectories_*.json&lt;/code&gt;——&lt;strong&gt;评测分数闭环回到训练数据筛选&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;coldstart.sh&lt;/code&gt;&lt;/strong&gt;：Megatron SFT 训练 Qwen3-VL-4B-Instruct（4 GPU、TP=4、56K 上下文、3 epochs、lr 1e-5）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;process_oversight.py&lt;/code&gt;&lt;/strong&gt;：外在验证/过程监督——VLM critic（&lt;code&gt;vl_oversight&lt;/code&gt;）审查 Design Agent 的 HTML 幻灯片的版面/渲染/风格问题（severity 0-3）+ &lt;code&gt;agent_watch&lt;/code&gt; 幻觉检测 + &lt;code&gt;critic_follow&lt;/code&gt; 计划遵循检查（论文 3.2 节 extrinsic verification 的实现）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sarl/analysis/efficiency.py&lt;/code&gt;：成本-性能帕累托图（论文 Figure 6 数据）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="8-与直接让-codex-生成-ppt-的对比"&gt;8. 与直接让 CodeX 生成 PPT 的对比&lt;/h2&gt;
&lt;h3 id="81-直接-codex-方式的做法"&gt;8.1 直接 CodeX 方式的做法&lt;/h3&gt;
&lt;p&gt;&amp;ldquo;直接让 CodeX 生成 PPT，给他参考图附件&amp;quot;的做法是：把任务提示 + 参考图片作为附件给 CodeX，让它用通用编码能力（python-pptx / html / marp 等）直接写代码生成 PPTX。在我们的评测中，对应 &lt;code&gt;codex_gen.py&lt;/code&gt;：&lt;code&gt;codex exec --sandbox danger-full-access&lt;/code&gt; + &lt;code&gt;pptx-generator&lt;/code&gt; Skill（把 DeepPresenter 流程蒸馏为 Codex 可用的 Skill 文档 + 确定性脚本）。&lt;/p&gt;
&lt;h3 id="82-本质区别一research-与-design-的解耦"&gt;8.2 本质区别一：Research 与 Design 的解耦&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;DeepPresenter&lt;/strong&gt;：两个专职智能体、两段轨迹、一个共享文件系统。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Researcher 用意图自适应策略做&lt;strong&gt;多步检索综合&lt;/strong&gt;（web/图片/论文/附件解析），产出结构化文稿 M（页面/主题/证据/资产绑定）；&lt;/li&gt;
&lt;li&gt;Presenter 在独立轨迹中基于 M 做&lt;strong&gt;内容驱动的视觉设计&lt;/strong&gt;，每页 inspect 修复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;直接 CodeX&lt;/strong&gt;：单一 agent 用统一上下文同时承担调研与设计。问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调研深度受上下文窗口限制，长文档/多主题调研容易浅尝辄止；&lt;/li&gt;
&lt;li&gt;&amp;ldquo;调研&amp;quot;与&amp;quot;设计&amp;quot;互相抢占 token 预算，设计阶段上下文已接近极限（对应 DeepPresenter 论文统计的 32.3% 环境错误：上下文溢出）；&lt;/li&gt;
&lt;li&gt;附件证据使用浅层：实测（&lt;code&gt;experiment-codex-vs-deeppresenter-finalcheck-20260813.md&lt;/code&gt;）中 Codex 对 14 页试卷附件只做&amp;quot;题目级裁剪+通用标题+两条短要点&amp;rdquo;，而 DeepPresenter 把 955 行 Markdown 解析成概念级教学图（station model、seismogram S-P timing、subduction quakes&amp;hellip;），3-4 条因果要点 + 与论点直接绑定的可读图。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="83-本质区别二环境接地反思-vs-内省反思"&gt;8.3 本质区别二：环境接地反思 vs 内省反思&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;DeepPresenter&lt;/strong&gt; 的 &lt;code&gt;inspect_slide&lt;/code&gt; 把 HTML 渲染成像素图交给多模态智能体&amp;quot;亲眼看&amp;rdquo;，&lt;code&gt;inspect_manuscript&lt;/code&gt; 给结构化诊断（页数/语言/资源缺失）。反思条件是&lt;strong&gt;渲染后的感知状态&lt;/strong&gt;，与用户看到的一致，能发现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;后渲染缺陷（元素溢出、重叠、低对比度、断裂图片）；&lt;/li&gt;
&lt;li&gt;图片路径前缀缺失（论文 Figure 2 例子：&amp;ldquo;fig1.jpg&amp;rdquo; missing &amp;ldquo;images/&amp;rdquo; prefix）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;直接 CodeX&lt;/strong&gt; 的反思大多是内省式的：看自己的代码和中间文本（HTML/代码），&amp;ldquo;我觉得没问题&amp;rdquo;。问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自验证偏差（self-verification bias）：在自己的轨迹状态内评判自己的输出；&lt;/li&gt;
&lt;li&gt;代码级合法（HTML 语法正确、布局坐标在界内）≠ 渲染级正确（溢出/重叠/可读性）；&lt;/li&gt;
&lt;li&gt;实测中 Codex 的 QA 检查聚焦路径/可读性/转换成功，&lt;strong&gt;抓不到核心内容失败&lt;/strong&gt;：&amp;ldquo;这个视觉真的支撑了本页论点吗？&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="84-本质区别三受控工具生态-vs-通用编码环境"&gt;8.4 本质区别三：受控工具生态 vs 通用编码环境&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;DeepPresenter&lt;/strong&gt; 提供 5 类 20+ 个受控 MCP 工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retrieve（search_web/images/papers、fetch_url、document_analyze、image_caption）；&lt;/li&gt;
&lt;li&gt;File（convert_to_markdown、read/write/move/edit/download_file、execute_command、目录管理）；&lt;/li&gt;
&lt;li&gt;Reason（thinking、inspect_slide、inspect_manuscript）；&lt;/li&gt;
&lt;li&gt;Control（todo_create/update/list、finalize）；&lt;/li&gt;
&lt;li&gt;Create（image_generation）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工具的&lt;strong&gt;语义边界明确&lt;/strong&gt;（如 &lt;code&gt;search_web&lt;/code&gt; 封装了检索+结果归一化）、&lt;strong&gt;有校验&lt;/strong&gt;（&lt;code&gt;finalize&lt;/code&gt; 按角色校验产物、&lt;code&gt;download_file&lt;/code&gt; 校验图片格式与路径、工具输出 4096 字符截断+全文落盘）、&lt;strong&gt;有审计&lt;/strong&gt;（tool_history.jsonl、tools_time_cost.json）、&lt;strong&gt;有沙箱&lt;/strong&gt;（危险命令黑名单）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;直接 CodeX&lt;/strong&gt; 只有一个通用 sandbox + 文件系统 + shell。能力等价但缺少：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语义化的检索工具（检索质量依赖模型自己拼 URL/API）；&lt;/li&gt;
&lt;li&gt;专门的渲染观察接口（没有 inspect，只能靠写脚本截图再读，或干脆不检查）；&lt;/li&gt;
&lt;li&gt;按角色约束的终止校验（finalize 的产物类型验证）；&lt;/li&gt;
&lt;li&gt;上下文管理（工具截断、压缩折叠、预算告警）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="85-本质区别四评测闭环"&gt;8.5 本质区别四：评测闭环&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;PPTAgent/DeepPresenter 自带评测框架（PPTEval / Constraint+Content+Style+Diversity），评测分数驱动实验迭代；&lt;/li&gt;
&lt;li&gt;本项目的蒸馏管线（&lt;code&gt;trajectory_collect.py&lt;/code&gt;）把&lt;strong&gt;评测分数作为 SFT 轨迹过滤阈值&lt;/strong&gt;（constraint==1.0、content&amp;gt;=3.9、style&amp;gt;=3.9、constraint_vlm&amp;gt;=0.65），形成&amp;quot;评测→过滤→训练→再评测&amp;quot;闭环；&lt;/li&gt;
&lt;li&gt;Codex 方式是通用 agent，没有与演示文稿语义绑定的评测反馈回路。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="86-实测对比数据"&gt;8.6 实测对比数据&lt;/h3&gt;
&lt;p&gt;12 样本实测（&lt;code&gt;codex-skill-ppt-additional-analysis*.md&lt;/code&gt;）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;Codex+Skill&lt;/th&gt;
&lt;th&gt;DeepPresenter&lt;/th&gt;
&lt;th&gt;差距&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content&lt;/td&gt;
&lt;td&gt;2.62&lt;/td&gt;
&lt;td&gt;4.33&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;主要差距&lt;/strong&gt;（受众改写、证据选择、有意义的视觉）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Style&lt;/td&gt;
&lt;td&gt;3.96&lt;/td&gt;
&lt;td&gt;4.45&lt;/td&gt;
&lt;td&gt;较小（页数/渲染/基本布局已不是瓶颈）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;单样本细看（&lt;code&gt;07bbf73b&lt;/code&gt;，14 页附件 deck）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Codex 逐页 Content：&lt;code&gt;4,3,3,2,2,3,2,2,2,2,2,2,2,3&lt;/code&gt;——中段大面积 2/5 塌陷；&lt;/li&gt;
&lt;li&gt;DeepPresenter 逐页 Content：&lt;code&gt;3,3,3,3,3,4,5,5,5,4,5,5,4,3&lt;/code&gt;——多数页 4-5/5；&lt;/li&gt;
&lt;li&gt;Codex 页级样式 Style 4.0（结构有效、视觉一致），但&amp;quot;每页一个 PDF 裁剪图 + 通用证据标题 + 两条短要点&amp;rdquo;，视觉被评价为&amp;quot;小、难读、与页主题弱相关甚至离题&amp;rdquo;；&lt;/li&gt;
&lt;li&gt;单页 A1 海报任务（&lt;code&gt;c5cae881&lt;/code&gt;）两者打平（4.0/4.0/1.0）——因为单页合成任务无多页证据路由问题，Skill 足以匹配。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：直接 CodeX（即使配上 Skill）在&amp;quot;多页、附件密集、需要把附件内容转成教学产物&amp;quot;的任务上，与 DeepPresenter 的核心差距在&lt;strong&gt;语义内容质量&lt;/strong&gt;（证据提取、论点-证据绑定、视觉信息增益），而非确定性约束或转换稳定性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="9-从论文到代码的对应关系速查表"&gt;9. 从论文到代码的对应关系速查表&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;论文概念&lt;/th&gt;
&lt;th&gt;代码位置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PPTAgent Stage I 幻灯片分类&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/induct.py:95-110&lt;/code&gt;（category_split，&lt;code&gt;prompts/category_split.txt&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPTAgent Stage I 版面聚类&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/induct.py:112-151&lt;/code&gt; + &lt;code&gt;model_utils.py:291-345&lt;/code&gt;（get_cluster，sim_bound=0.65）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPTAgent Stage I Schema 提取&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/induct.py:175-208&lt;/code&gt;（content_induct）+ &lt;code&gt;presentation/layout.py&lt;/code&gt;（Element/Layout）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPTAgent Stage II 大纲生成&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/pptgen.py:239-318&lt;/code&gt;（generate_outline + _add_functional_layouts）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPTAgent Stage II 版面选择/内容生成&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptgen.py:434-467&lt;/code&gt; / &lt;code&gt;469-491&lt;/code&gt;（_select_layout / _generate_content）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;编辑 API&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/apis.py&lt;/code&gt;（replace_paragraph/replace_image/del_paragraph/del_image/clone_paragraph）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自校正 REPL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptgen.py:493-529&lt;/code&gt;（_edit_slide）+ &lt;code&gt;apis.py:127-203&lt;/code&gt;（execute_actions）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML 渲染（CodeRender）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/presentation/presentation.py:193-216&lt;/code&gt;（SlidePage.to_html）+ &lt;code&gt;shapes.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Closure 延迟构建&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/presentation/shapes.py:218-246&lt;/code&gt;（Closure）+ &lt;code&gt;presentation.py:122-144&lt;/code&gt;（build）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPTEval&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/ppteval/ppteval.py&lt;/code&gt; + &lt;code&gt;prompts/ppteval/*.txt&lt;/code&gt;（三维度 prompt）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;多样性指标&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pptagent/ppteval/divesity.py&lt;/code&gt;（Vendi Score）+ &lt;code&gt;sarl/evaluation/divesity.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Harness 主循环&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/agents/agent.py&lt;/code&gt;（action:191-240 / execute:250-348 / compact_history:356-401 / loop:242-249）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AgentLoop 编排&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/main.py:43-224&lt;/code&gt;（run）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AgentEnv 与工具执行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/agents/env.py&lt;/code&gt;（tool_execute:111-226 / register_tool:347-372）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP 客户端&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/utils/mcp_client.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inspect_slide / inspect_manuscript&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/tools/reflect.py:28-62 / 66-117&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;finalize 终止校验&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/tools/task.py:58-111&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;角色定义&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/roles/*.yaml&lt;/code&gt; + &lt;code&gt;utils/constants.py&lt;/code&gt;（动态提示词片段）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;上下文折叠&lt;/td&gt;
&lt;td&gt;&lt;code&gt;agent.py:356-401&lt;/code&gt;（compact_history）+ &lt;code&gt;constants.py:154-184&lt;/code&gt;（MEMORY_COMPACT_MSG）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;多智能体并行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/agents/subagent.py&lt;/code&gt;（delegate_subagent）+ &lt;code&gt;main.py:74-78&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML→PPTX&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/utils/webview.py:169-233&lt;/code&gt; + &lt;code&gt;html2pptx/html2pptx_cli.js&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;沙箱&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deeppresenter/docker/server.ts&lt;/code&gt;（DesktopCommanderMCP）+ &lt;code&gt;run_sandbox_local.sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;外在验证（extrinsic verification）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PPTea-main/sarl/coldstart/process_oversight.py&lt;/code&gt;（vl_oversight/agent_watch/critic_follow）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;轨迹过滤/蒸馏&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sarl/coldstart/trajectory_collect.py&lt;/code&gt; + &lt;code&gt;coldstart.sh&lt;/code&gt;（Qwen3-VL-4B SFT）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;评测两阶段管线&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sarl/evaluation/score_exp.py&lt;/code&gt;（Phase 1）+ &lt;code&gt;score_exp_complex.py&lt;/code&gt;（Phase 2）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;约束验证&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sarl/dataset/typings.py&lt;/code&gt;（DataPoint.verify）+ &lt;code&gt;prompt/judge_constraints.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;人工审核&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sarl/evaluation/review_server.py&lt;/code&gt;（FastAPI）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex 基线&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sarl/evaluation/codex_gen.py&lt;/code&gt; + &lt;code&gt;../Deeppresenter-skills/skills/pptx-generator&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="10-总结与启示"&gt;10. 总结与启示&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;两代系统的演进主线&lt;/strong&gt;：PPTAgent（2025）证明&amp;quot;编辑式生成 + 参考模板&amp;quot;能大幅超越纯摘要式生成，但受限于依赖参考演示文稿与固定工作流；DeepPresenter（2026）转向&amp;quot;双智能体 + 自由式生成 + 环境接地反思&amp;quot;，把生成从&amp;quot;模板填充&amp;quot;解放为&amp;quot;内容驱动的自主设计与修正&amp;quot;，并进一步用外在验证合成轨迹蒸馏出 9B 小模型。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Agent Harness 的本质&lt;/strong&gt;：一个带上下文管理的 think-act-observe 工具调用循环（&lt;code&gt;Agent.action → execute → 观察 → 直到 finalize&lt;/code&gt;），配上&lt;strong&gt;角色化提示词、MCP 工具生态、沙箱执行、上下文折叠、多智能体委派&lt;/strong&gt;，就构成了 DeepPresenter 的通用智能体框架——这套框架不限于 PPT 生成，可复用于任意&amp;quot;长时程、工具密集、需要迭代反思&amp;quot;的任务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;与直接 CodeX 的差距不在&amp;quot;有没有 agent&amp;quot;，而在&amp;quot;agent 的观察与反思是否接地&amp;quot;&lt;/strong&gt;：DeepPresenter 的 &lt;code&gt;inspect&lt;/code&gt; 让智能体&amp;quot;亲眼看到&amp;quot;渲染产物，Researcher/Presenter 解耦让每段轨迹专注且上下文充足，受控工具 + finalize 校验让长时程执行可审计。这些正是直接 CodeX（哪怕配上 Skill）难以在通用环境中复现的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对本项目的意义&lt;/strong&gt;（&lt;code&gt;project-demand.md&lt;/code&gt;）：把 DeepPresenter/PPTAgent 流程蒸馏为 &lt;code&gt;pptx-generator&lt;/code&gt; Skill 供 Codex/CC 使用，本质上是在&amp;quot;通用 Agent Harness（Codex）&amp;ldquo;里重建 DeepPresenter 的关键机制：Workspace 对齐（&lt;code&gt;.slides.md&lt;/code&gt;/&lt;code&gt;.slide_images-pdf-*&lt;/code&gt; 归一化）、确定性管道（research/html/qa/convert/package）、评测对齐（pptx-evaluator + GPT-5）。实测表明机械对齐已达标（页数/渲染/打包），剩余差距集中在&lt;strong&gt;附件语义化与证据绑定&lt;/strong&gt;——这正是 DeepPresenter 论文里 Researcher 环节（意图自适应检索 + 结构化文稿）与&amp;quot;证据有信息增益&amp;quot;评估准则的体现，也是下一步迭代（topic map、证据绑定 QA、对象级 PDF 裁剪）应聚焦的方向。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Use scp tool</title><link>https://wangzh12023.github.io/blog/blog/use-scp-tool/</link><pubDate>Mon, 23 Dec 2024 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/use-scp-tool/</guid><description>&lt;p&gt;Today I have to do the task to transfer the prepared data from one server to another. And I find that we can use the tool &lt;code&gt;scp&lt;/code&gt; to transfer files between two different host or between server and local computer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scp -r path/to/local usernameToObject@ObjectIp:ObjectPathToSave &lt;span style="color:#75715e"&gt;#recursively transfer files in the dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#Some other command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scp file user@host:/path/to/file &lt;span style="color:#75715e"&gt;# copying a file to the remote system using scp command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scp user@host:/path/to/file /local/path/to/file &lt;span style="color:#75715e"&gt;# copying a file from the remote system using scp command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scp &amp;lt;options&amp;gt; source_path destination_path &lt;span style="color:#75715e"&gt;# if we just want to transfer files in the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r &lt;span style="color:#75715e"&gt;# transfer directory &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-v &lt;span style="color:#75715e"&gt;# see the transfer details&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-C &lt;span style="color:#75715e"&gt;# copy files with compression&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-l &lt;span style="color:#ae81ff"&gt;800&lt;/span&gt; &lt;span style="color:#75715e"&gt;# limit bandwidth with 800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-p &lt;span style="color:#75715e"&gt;# preserving the original attributes of the copied files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P &lt;span style="color:#75715e"&gt;# connection port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-q &lt;span style="color:#75715e"&gt;# hidden the output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Gkxx__的 .vscode</title><link>https://wangzh12023.github.io/blog/blog/gkxx-vscode-config/</link><pubDate>Fri, 23 Aug 2024 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/gkxx-vscode-config/</guid><description>&lt;p&gt;翻到已经结课的cs100，Update一下gkxx__的配置文件&lt;/p&gt;
&lt;p&gt;&lt;del&gt;&lt;code&gt;你们已经长大了，应该学着自己写configure files了&lt;/code&gt;&lt;/del&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All in &lt;code&gt;.vscode&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;c_cpp_properties.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;configurations&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Win32&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;compilerPath&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Your_Path\\mingw64\\bin\\gcc.exe&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cStandard&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;c17&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cppStandard&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;c++17&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;intelliSenseMode&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;windows-gcc-x64&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;compilerArgs&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-Wall&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-Wpedantic&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-Wextra&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;files.associations&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;*.go&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;go&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;iostream&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;array&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;deque&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;unordered_map&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;vector&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;string_view&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;initializer_list&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;stdexcept&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;iosfwd&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;atomic&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;bit&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;*.tcc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cctype&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;clocale&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cmath&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;compare&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;concepts&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cstdarg&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cstddef&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cstdint&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cstdio&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cstdlib&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cwchar&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cwctype&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;exception&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;algorithm&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;functional&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;iterator&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;memory_resource&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;numeric&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;optional&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;random&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;system_error&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;tuple&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type_traits&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;utility&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;istream&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;limits&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;new&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;numbers&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ostream&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;streambuf&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;typeinfo&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;stdbool.h&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;c&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;map&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;set&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cpp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tasks.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;tasks&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cppbuild&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;label&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;C/C++: gcc.exe 生成活动文件&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Your_Path\\mingw64\\bin\\gcc.exe&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-fdiagnostics-color=always&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-g&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;${file}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-o&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;${fileDirname}\\${fileBasenameNoExtension}.exe&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;options&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;cwd&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;${fileDirname}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;problemMatcher&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;$gcc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;group&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;isDefault&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;detail&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;调试器生成的任务。&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>由一个 docker search 产生的连锁反应</title><link>https://wangzh12023.github.io/blog/blog/docker-search-chain-reaction/</link><pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/docker-search-chain-reaction/</guid><description>&lt;p&gt;有时候菜的想发颠。&lt;/p&gt;
&lt;p&gt;网络问题总是层出不穷，dns解析不了，docker无法拉取镜像源&amp;hellip;&lt;/p&gt;
&lt;p&gt;莫名其妙的改了VMware的虚拟网络设置和Ubuntu的Ip&amp;amp;DNS。结果一顿操作给干连不了网了，&lt;code&gt;docker search &amp;lt;&amp;gt;&lt;/code&gt; 显示：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Error response from daemon: Get &amp;quot;https://index.docker.io/v1/search?q=nginx&amp;amp;n=25&amp;quot;: dial tcp: lookup index.docker.io on 8.8.4.4:53: read udp 192.168.1.11:37017-&amp;gt;8.8.4.4:53: i/o timeout&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;查询后发现需要配置镜像源：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vim /etc/docker/darmon.json
{
&amp;#34;registry-mirrors&amp;#34;:[
&amp;#34;...&amp;#34;
]
}
# 重启一下
systemctl daemon-reloa
systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;经配置镜像源后问题似乎得到了&amp;hellip;似乎产生了新的问题。
&lt;code&gt;ping bing.com&lt;/code&gt; 显示&lt;code&gt;ping: bing.com: Temporary failure in name resolution&lt;/code&gt;，经过查询是DNS解析问题，先通过&lt;code&gt;vim /etc/resolv.conf&lt;/code&gt;配置了两个DNS：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;nameserver 8.8.8.8
nameserver 8.8.4.4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;嘿，结果不行。由于昨夜头脑比较混乱，第二天打开虚拟网络设置-&amp;gt;for i in all network: delete-&amp;gt;应用-&amp;gt;还原默认设置-&amp;gt;重新配置虚拟机的网络为&amp;quot;桥接&amp;quot;，参考&lt;a href="https://stackoverflow.com/questions/53687051/linux-command-line-error-message-temporary-failure-in-name-resolution"&gt;stackoverflow&lt;/a&gt;，将answer中的DNS部分替换为上面的dns，结果成功ping成功，并且成功search到docker镜像，但是问题就像趵突泉的泉水一样，一直涌现，在&lt;code&gt;docker pull &amp;lt;&amp;gt;&lt;/code&gt;拉取镜像的时候又提示超时：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;error pulling image configuration: download failed after attempts=6: dial tcp &amp;lt;...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是为什么呢？明明可以&lt;code&gt;search&lt;/code&gt; 却不能&lt;code&gt;pull&lt;/code&gt;??能&lt;code&gt;search&lt;/code&gt;说明是能够连接到docker hub的，但是pull的时候超时又说明访问有问题，经过排查后，借鉴&lt;a href="https://www.cnblogs.com/lxzcloud/p/18354640"&gt;这篇博客&lt;/a&gt; 后，发现最终还是镜像源问题，更改镜像源后问题解决。&lt;/p&gt;</description></item><item><title>Use zsh terminal</title><link>https://wangzh12023.github.io/blog/blog/use-zsh-terminal/</link><pubDate>Sun, 11 Aug 2024 00:00:00 +0000</pubDate><author>wzh</author><guid>https://wangzh12023.github.io/blog/blog/use-zsh-terminal/</guid><description>&lt;p&gt;One day I find that the terminal style between mine and other&amp;rsquo;s are different and I wonder how they do that, so, then I find zsh&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install zsh&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt install zsh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使用镜像源安装oh-my-zsh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sh -c &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;curl -fsSL https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#编辑theme主题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim ~/.zshrc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ZSH_THEME=&amp;#34;powerlevel10k/powerlevel10k&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;We may also need to config windows terminal&amp;rsquo;s file&lt;code&gt;settings.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>