File size: 39,106 Bytes
2f59739
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
# EasyR1-V4-Embody 当前实现与两篇论文的完整串讲

本文档把三件事串起来讲清楚:

1. arXiv:2505.22050, **Reinforced Reasoning for Embodied Planning**。
2. arXiv:2605.27140v1, **StepOPSD: Step-Aware Online Preference Distillation for Agent Reinforcement Learning**。
3. 当前仓库 `EasyR1-V4-Embody` 的代码实现,尤其是 `grpo_step`、`rule` step reward、`forward_proxy`、residual gate / prompt gate。

结论先放在前面:

```text
2505.22050 是一个 embodied VLM 训练 recipe:
SFT 初始化 + rule-based reward + GRPO/RFT,让 Qwen2.5-VL 学会输出多步可执行计划。

2605.27140 StepOPSD 是一个 agent RL 信用分配算法:
把 OPSD teacher-student logp gap 放到 step/action span 上,做 GRPO advantage shaping。

当前 EasyR1-V4-Embody 介于两者之间:
任务设定、数据和输出形式更像 2505.22050;
算法改动、step-level advantage shaping 和 forward_proxy 更像 StepOPSD;
同时又额外实现了 rule step reward、GT-reference teacher、additive advantage、action_id/action_name span control、residual/prompt gates。
```

---

## 1. 三个对象各自解决什么问题

### 1.1 2505.22050 解决的是“怎么训练 embodied planner”

这篇论文的主问题是:开源 VLM 在具身场景里很难做长程、多步、视觉条件下的 planning。模型要看当前视觉 observation、历史动作、自然语言任务,然后输出后续 action sequence。

它的方案是两阶段:

```text
Stage 1: SFT
  用强闭源模型 Gemini-2.0-flash 蒸馏出高质量 reasoning + plan 数据。
  让 Qwen2.5-VL-7B 先学会任务分解、空间常识、输出格式。

Stage 2: RFT / GRPO
  构造 ALFRED 轨迹分解数据。
  对模型输出的多步 action plan 设计 rule-based reward。
  用 GRPO 做 reinforcement fine-tuning。
```

它的 reward 是规则式的:

```text
R = R_format + R_accuracy

R_format:
  JSON 结构是否正确;
  必需字段是否存在;
  action_id / action_name 是否有效匹配。

R_accuracy:
  按 action sequence 和 gold sequence 做 prefix matching。
  若连续匹配 n 步,gold 总长为 k:
  R(n; k) = n(n + 1) / (k(k + 1))
```

所以 2505.22050 的重点不是“OPSD 信号怎么改 advantage”,而是“具身规划任务上,SFT + 规则奖励 + GRPO 这条 pipeline 能不能训动”。

### 1.2 StepOPSD 解决的是“长轨迹 sparse reward 怎么分给关键 step”

StepOPSD 的主问题是 agent RL 的 credit assignment:

```text
一条长 rollout 可能因为一个局部 action 错了而失败。
标准 GRPO 只有一个 terminal reward。
这个 reward 被广播到整条 response 的所有 token。
结果是:模型知道整条轨迹不好,但不知道是哪一步导致不好。
```

StepOPSD 的核心流程:

```text
rollout
-> trajectory reward / GRPO advantage
-> parse action-centered step spans
-> hindsight teacher context rescoring
-> compute token-level logp gap Delta
-> convert Delta into bounded multiplicative weights
-> reshape GRPO advantage
-> policy update
```

它的信号是:

```text
Delta_{k,j}
  = log pi_T(z_{k,j} | hindsight context, prefix)
  - log pi_S(z_{k,j} | causal context, prefix)
```

它的 advantage 注入方式是:

```text
w_raw = 2 * sigmoid(sign(A) * Delta)
w     = clip(w_raw, 1 - alpha_clip, 1 + alpha_clip)

A_tilde = (1 - lambda_mix) * A + lambda_mix * (w * A)
```

关键性质:

```text
w 始终为正。
因此 StepOPSD 只改变原始 GRPO advantage 的 magnitude,不改变 sign。
它是 sign-preserving 的 credit redistribution。
```

StepOPSD 的 hindsight 来源主要是同一个 GRPO group 中的 successful peer trajectory;teacher 是 stale reference policy,避免 moving target。

### 1.3 当前代码解决的是“one-shot embodied JSON plan 内部的 step credit assignment”

当前仓库的任务形态:

```text
输入:
  图像 + human instruction + action history + action list

输出:
  一次性生成完整 JSON:
  {
    "visual_state_description": "...",
    "reasoning_and_reflection": "...",
    "language_plan": [...],
    "executable_plan": [
      {"action_id": 133, "action_name": "..."},
      ...
    ]
  }
```

注意:当前代码不是多轮在线环境交互。它是一行样本生成一整条后续 trajectory plan。

代码里的核心目标:

```text
原来只有整条 trajectory 的 scalar reward。
现在希望在同一条 response 内部,把不同 step 的 token 赋予不同 advantage。

A_token = A^E + omega * A^S

A^E:
  原始 GRPO episode advantage。
  来自整条轨迹 scalar reward 的组内归一化。

A^S:
  新增 step-level per-token advantage。
  可以来自 rule action_id 匹配,也可以来自 forward_proxy teacher-student logp contrast。
```

因此,当前实现和 2505.22050 的任务设定很近,和 StepOPSD 的算法思想也很近。

---

## 2. 当前代码端到端数据流

### 2.1 Dataset:把 EB-ALFRED 样本变成 VLM prompt

主要文件:

```text
verl/utils/dataset.py
```

当前 embodied dataset 的 `__getitem__` 做了这些事:

1. 从 parquet 行里读:

```text
instruction
history
action_id       # 可用动作列表
image
gt_bbox
gt_action
gt_input_text
gt_action_close / gt_action_open 等字段保留在 row_dict 中
```

2. 构造 prompt:

```text
You are Embodied-R1 ...
Given the current visual state <image> ...
Current context: {history}

Action Descriptions and Validity Rules
...

The available action names are:
{actionlist}

Output ONLY a valid JSON object:
  visual_state_description
  reasoning_and_reflection
  language_plan
  executable_plan
```

3. 把 `<image>` 替换为 Qwen-VL 视觉占位:

```text
<|vision_start|><|image_pad|><|vision_end|>
```

4. 用 processor 编码图像和 prompt,生成:

```text
input_ids
attention_mask
position_ids
raw_prompt_ids
multi_modal_data = {"images": raw_images}
ground_truth = json.dumps(gt)
```

这里的 `ground_truth` 不是直接的 `executable_plan` list,而是一个包装后的 JSON,内部包含:

```text
action
gt_bbox
input_text
gt_open_ans
```

其中 `input_text` 里还能解析出 GT 的 `executable_plan`。

### 2.2 Rollout:模型一次性生成 response

训练主循环在:

```text
verl/trainer/ray_trainer.py
```

核心顺序:

```text
prepare_rollout_engine
-> _make_batch_data
-> release_rollout_engine
-> _balance_batch
-> compute_reward
-> compute_old_log_probs
-> compute_ref_log_probs
-> build step_adv_raw if adv_estimator == grpo_step
-> compute_advantage
-> update actor
```

这里的 response 是完整 JSON plan,不是一步环境 action。

### 2.3 Trajectory-level reward:verify model 给整条计划打分

主要文件:

```text
verl/workers/reward/function.py
verl/workers/reward/verify.py
```

`compute_reward_batch` 的行为是:

1. decode response。
2. 尝试解析 JSON。
3. 从 response 中提取:

```text
executable_plan
```

4. 从 ground truth 中提取:

```text
ground_truth_open = json.loads(ground_truth["input_text"])["executable_plan"]
```

5. 构造 verify prompt:

```text
Sentence 1: {GT executable_plan}
Sentence 2: {pred executable_plan}

You are judging whether a predicted embodied action trajectory matches
the ground-truth trajectory at the intent level.

Focus on FUNCTIONAL EQUIVALENCE ...
Compare mainly by action_name, not exact action_id.
Be lenient about extra/missing find steps ...
Only output: True or False.
```

6. 调用 `ask_llm`,用 verify VLM 生成一个 token,取 True / False 相关概率。

7. 得到:

```text
format = 1.0 if JSON parse ok else 0.0
accuracy = verify probability, False 会转成负值
overall = 0.8 * accuracy + 0.2 * format
```

8. 把 `overall` 写到最后一个 response token:

```text
reward_tensor[i, cur_response_length - 1] = score["overall"]
```

这意味着整条 trajectory 的 reward 在张量里仍然是一个 terminal scalar。

### 2.4 原始 GRPO:A^E 怎么来

主要文件:

```text
verl/trainer/core_algos.py
```

标准 GRPO advantage 逻辑是:

```text
scores = token_level_rewards.sum(-1)

按 uid 分组:
  同一个 prompt 的 n 条 rollout 共享 uid。

对每个 uid group:
  A^E_i = (R_i - mean(R_group)) / (std(R_group) + eps)

然后:
  A^E_i 广播到该 response 的所有有效 token。
```

所以没有 step reward 时,同一条 response 里的每个 token 都拿同一个 advantage。

这正是当前工作要改的地方。

### 2.5 grpo_step:在 A^E 上加 A^S

主要文件:

```text
verl/trainer/core_algos.py
verl/trainer/ray_trainer.py
verl/trainer/step_reward.py
```

新增 estimator:

```text
AdvantageEstimator.GRPO_STEP = "grpo_step"
```

核心函数:

```python
episode_adv, _ = compute_grpo_outcome_advantage(...)

if step_adv_raw is None:
    return episode_adv, episode_adv

step_adv = step_adv_raw * response_mask
advantages = episode_adv + step_advantage_w * step_adv
return advantages, advantages
```

公式就是:

```text
A_token = A^E + omega * A^S_token
```

其中:

```text
A^E:
  仍然是原始 GRPO,完全复用。

A^S:
  shape = (bs, response_length)
  response 内不同 token 可以不同。
  解析失败、scaffolding、非目标 token 为 0。
```

这个点非常关键:当前实现不是额外加一个 KL loss,也不是重写 GRPO,而是在 advantage 估计阶段加一条旁路信号。

---

## 3. step_adv_raw 的两条来源

当前代码把 `step_adv_raw` 做成可切换的:

```yaml
algorithm.adv_estimator: grpo_step
algorithm.step_reward_kind: rule | forward_proxy
```

### 3.1 Rule:硬规则 step reward

文件:

```text
verl/trainer/step_reward.py
```

入口:

```text
build_step_adv_raw
-> build_step_adv_vector
-> compute_step_match_rewards
```

流程:

1. decode response。
2. 容错解析 `executable_plan`。
3. 解析 GT:

```text
gt_steps_from_close(gt_close)
```

4. 对 predicted steps 和 GT steps 做匹配。

支持三种匹配:

```text
exact:
  pred[i] == gt[i] 才算对。

prefix:
  最长正确前缀;第一个错后面全算错。

lcs:
  longest common subsequence,对顺序扰动更宽松。
```

默认匹配键:

```yaml
algorithm.step_match_key: action_id
```

reward 转 advantage:

```text
匹配:+1
不匹配:-1
scaffolding / 非 step token:0
解析失败:整条 A^S = 0,退化为纯 GRPO
```

这条路和 2505.22050 很接近:都是用 GT action sequence 做 rule-based correctness signal。

但也有差别:

```text
2505.22050:
  rule reward 先变成 response-level scalar reward,再进入 GRPO。
  prefix reward R(n;k) 是整条 response 的 reward。

当前代码 rule:
  rule reward 直接变成 per-token step advantage A^S。
  一条 response 内部可以前两步 +1,第三步 -1。
```

也就是说,当前 rule 比 2505.22050 更细:不是只给整条轨迹一个分,而是把 step 对错广播到对应 token。

### 3.2 Forward Proxy:GT-aware teacher-student logp contrast

文件:

```text
verl/trainer/teacher_proxy.py
verl/workers/reward/function.py
verl/workers/reward/verify.py
verl/trainer/step_reward.py
```

配置:

```yaml
algorithm.step_reward_kind: forward_proxy
algorithm.step_squash: contrast
algorithm.step_teacher_path: ...
algorithm.step_score_source: action_name | action_id | semantic
algorithm.step_credit_target: action_name | action_id | semantic
```

#### 3.2.1 为什么要跑在 reward actor 上

最初如果在 driver 上做 teacher forward,会遇到:

```text
driver 进程没有 GPU。
verl/Ray 中 GPU 分给 worker actor。
teacher.to("cuda") 会失败。
```

所以当前代码把 forward_proxy 放到 reward actor:

```text
ray.get(self.reward_fn.compute_step_adv.remote(...))
```

reward actor 本来就有 verify model 的 GPU 资源,因此可以 lazy-load teacher scorer。

#### 3.2.2 TeacherLogpScorer 做什么

`TeacherLogpScorer.logp_teacher_student` 对同一段 predicted response tokens 跑两次 forward:

```text
teacher context:
  image + "Here is a reference successful language plan:"
  + GT reference plan
  + transition
  + predicted response tokens

student context:
  image + "Problem: {instruction}"
  + student instruction
  + predicted response tokens
```

返回:

```text
teacher_logp[t] = log p_model(response_token_t | image, GT context, response_prefix)
student_logp[t] = log p_model(response_token_t | image, problem context, response_prefix)
```

然后:

```text
Delta_t = teacher_logp[t] - student_logp[t]
```

这个 Delta 的语义是:

```text
如果模型看了 GT 后更支持这个 response token,Delta 为正。
如果模型看了 GT 后更不支持这个 response token,Delta 为负。
```

#### 3.2.3 当前代码里的一个重要现实:teacher 不一定等于 policy

`teacher_proxy.py` 和 `config.py` 的注释里仍然写着:

```text
teacher should be same path as policy
same tokenizer, true OPSD self-distillation
```

但当前运行脚本 `examples/qwen25_vl_3b_Domain.sh` 实际是:

```text
policy  = Qwen2.5-VL-3B-RobotGPT-R1
teacher = Qwen2.5-VL-3B-Instruct
```

这意味着当前 forward_proxy 的真实语义不是严格的“policy 自蒸馏 OPSD”,而是:

```text
冻结外部 Instruct teacher 在 GT context 和 no-GT context 下的 logp contrast。
```

这点要在论文/报告中说准。

如果 teacher 等于 policy:

```text
更像原始 OPSD / self-distillation。
但实测容易因为 policy 对自己生成的 token 过度自信而 logp diff 塌平。
```

如果 teacher 是未微调 Instruct:

```text
信号更容易有波动。
但它不再代表 policy 自己的 preference shift;
而是外部 teacher 的 GT-conditioned preference shift。
```

当前 `step_adv_heatmaps/_diag.txt` 中能看到 forward_proxy 已有波动,例如:

```text
std ~= 0.9 - 2.3
mean 通常为正
min/max 可到约 -15 / +13
```

这说明“信号活了”,但不自动说明“信号方向一定奖对惩错”。

#### 3.2.4 Delta 怎么变成 step score

文件:

```text
verl/trainer/step_reward.py
build_step_adv_vector_from_logp
```

先选 score tokens:

```yaml
step_score_source:
  action_name  # 默认
  action_id
  semantic     # action_id + action_name
```

对这些 token 聚合:

```text
contrast 模式:
  token_signal = teacher_logp - student_logp
  raw_step = robust_mean(token_signal over score tokens)
  score = tanh(normalize(raw_step) / score_tau)

prob 模式:
  score = 2 * exp(mean teacher_logp) - 1
```

代码和实验笔记都说明:`prob` 容易恒平,因为 GT-conditioned teacher 对很多 token 都很自信;真正有意义的是 `contrast`。

#### 3.2.5 score 写回哪些 token

再选 credit target:

```yaml
step_credit_target:
  action_name
  action_id
  semantic
```

默认 `action_name`,一些 ablation 用:

```yaml
step_score_source: semantic
step_credit_target: action_id
step_action_name_weight: 0.0
```

这个设计很重要:

```text
score_source 决定“用哪些 token 判断这一步好坏”。
credit_target 决定“训练时把 advantage 写到哪些 token 上”。
```

例如:

```text
score_source = semantic:
  用 action_id + action_name 一起估计这步是否被支持。

credit_target = action_id:
  主要更新离散动作选择,而不是训练自然语言措辞。
```

这是当前实现相对 StepOPSD 的一个具身 JSON plan 特化点。

---

## 4. Token span 对齐:当前实现的工程核心

step reward 最终要进入 PPO/GRPO loss,因此必须是 token 级。

当前代码做了以下事情:

```text
response_ids
-> decode response text
-> extract executable_plan
-> locate each step's action_id / action_name character span
-> map character span back to token indices
-> write step score into selected token positions
```

主要函数:

```text
extract_plan_steps
pred_step_token_spans
_token_char_offsets
_find_action_id_value_span
_find_action_name_value_span
_select_span_tokens
```

### 4.1 JSON 解析

`extract_plan_steps` 能处理:

```text
正常 JSON dict
带 json 标记的 fenced code block
前后有散文的 response
尾部 <|im_end|> / <|endoftext|>
bare list
```

解析失败返回 `None`,后续整条 A^S 为 0。

### 4.2 char offset

`_token_char_offsets` 先尝试:

```text
tokenizer(text, return_offsets_mapping=True)
```

如果 re-tokenize 后 input_ids 和原始 response_ids 一致,就用 tokenizer offset。

如果不一致,则降级为 prefix decode:

```text
逐 token decode ids[:t+1]
用字符串长度差构造 offsets
```

这样比“decode 后重编码”更稳,因为 Qwen/VL tokenizer 在 special token、空格清理、JSON 标点附近可能 round-trip 不一致。

### 4.3 step span

代码先找到 `"executable_plan":` 后面的 list 起点,然后按顺序找每一步:

```text
action_id value span
action_name value span
```

每个 step 得到:

```python
StepTokenSpans(
    action_id_tokens=[...],
    action_name_tokens=[...],
)
```

然后根据配置选择:

```text
action_id tokens
action_name tokens
semantic tokens = action_id + action_name
```

### 4.4 当前 span 设计与 StepOPSD 的差别

StepOPSD 面向的是一般 agent trajectory,常见 span 是:

```text
<action>...</action>
clean_step_no_observation
```

当前代码面向的是 embodied JSON plan,span 是:

```text
action_id value
action_name value
```

所以当前实现对 `executable_plan` 的结构假设更强,但也更精确:可以只训练 action id,不训练 JSON scaffold 或语言描述。

---

## 5. Gate 扩展:控制 forward_proxy 信号进来的位置和强度

当前代码不止有 plain forward_proxy,还实现了两类 gate。

### 5.1 Residual contrast gate

配置:

```yaml
algorithm.step_gate: residual_contrast
algorithm.step_gate_residual: response_median
algorithm.step_gate_threshold: 0.0
algorithm.step_gate_tau: 1.0
algorithm.step_budget_tau: 1.0
algorithm.step_min_score_tokens: 2
```

逻辑:

1. 先对 token_signal 去 response-level median:

```text
d'_t = d_t - median(d over valid response tokens)
```

2. 每步算 raw score:

```text
raw_k = robust_mean(d'_t over score tokens)
soft_score_k = tanh(z_k / score_tau)
```

3. 再用 unsigned contrast 估计 importance:

```text
imp_k = robust_mean(abs(d'_t) over score tokens)
```

4. 组合三个 gate:

```text
decision_gate = sigmoid((imp_z - threshold) / gate_tau)
budget_gate   = clamp(softmax(imp / budget_tau) * num_steps, 0, 1)
confidence    = len_gate * var_gate

gate_k = decision_gate * budget_gate * confidence
```

5. 最终:

```text
A^S_k = gate_k * soft_score_k
```

直觉:

```text
soft_score 决定方向:支持还是反对。
gate 决定强度:这一步是否值得更新。
```

### 5.2 Prompt gate

配置:

```yaml
algorithm.step_gate: prompt
algorithm.step_prompt_gate_mode: generation
algorithm.step_prompt_gate_model_path: ...
algorithm.step_prompt_kl_weight: ...
algorithm.step_use_prompt_causal_gate: true
algorithm.step_use_prompt_redundancy_gate: true
```

`PromptGateScorer` 会让 judge 输出每个 predicted step 的:

```json
{
  "decision_gate": 0.0,
  "redundancy_gate": 0.0,
  "causal_gate": 0.0,
  "prompt_kl_score": 0.0,
  "reason": "..."
}
```

代码把 gate 合成:

```text
gate = decision * (1 - redundancy) * (0.5 + 0.5 * causal)
```

并可把 prompt score 加进 supervised KL score:

```text
supervised_scores =
  step_supervised_kl_weight * supervised_scores
  + step_prompt_kl_weight * prompt_scores
```

这个版本的目标是处理 residual contrast 看不懂的情况:

```text
某步 KL 波动很大,但其实只是冗余 find;
某步看起来错,但由于前一步已经错了,后续动作不该被强烈惩罚;
某步是关键 causal action,应该放大。
```

这已经超出 StepOPSD 原始设计,属于当前实现的额外探索。

---

## 6. 当前实现与 2505.22050 的详细对比

### 6.1 共同点

两者共同点很多:

```text
都做 embodied planning。
都使用 Qwen2.5-VL 系列。
都要求模型输出结构化 multi-step plan。
都使用 GRPO/RFT。
都重视 action sequence 的正确性。
都有格式约束。
都不直接在真实机器人上训练。
```

### 6.2 数据和任务形式

2505.22050:

```text
训练:
  SFT 数据来自 Gemini-2.0-flash 蒸馏。
  RFT 数据来自 ALFRED 轨迹分解。

评测:
  Embench。
  EB-ALFRED seen。
  EB-Habitat unseen。

模型:
  Qwen2.5-VL-7B。
```

当前代码:

```text
训练文件:
  eb_alfred_success_opsd_cot_multimodal_v2_embody.parquet

输入:
  当前图像 + instruction + history + action list。

输出:
  一次性完整 JSON plan。

policy:
  Qwen2.5-VL-3B-RobotGPT-R1。

teacher for forward_proxy:
  Qwen2.5-VL-3B-Instruct。
```

因此,当前代码更像把 2505.22050 的 embodied planning setting 改成了 3B policy + EasyR1/verl 风格训练。

### 6.3 Reward 设计差异

2505.22050 的 reward:

```text
R_total = R_format + R_accuracy
R_accuracy = prefix curve n(n+1)/k(k+1)
```

它是 response-level reward。即使 accuracy 来自 step prefix,最后仍然变成一个 scalar reward 给 GRPO。

当前代码的 reward 分两层:

```text
trajectory-level reward:
  verify model 判断 pred plan 与 GT plan 是否 functional equivalent。
  overall = 0.8 * verify + 0.2 * format。
  写到最后一个 token。

step-level A^S:
  rule: action_id exact/prefix/lcs -> per-token +/-1。
  forward_proxy: teacher-student logp contrast -> per-token [-1,1]。
```

也就是说,当前代码比 2505.22050 多了一个显式 step advantage 通道。

### 6.4 GRPO 使用方式差异

2505.22050:

```text
GRPO 直接用 composite reward。
每条 sampled response 得一个 reward。
组内归一化后更新整条 response。
```

当前代码:

```text
GRPO 仍然用 trajectory reward 得到 A^E。
但在 compute_advantage 之前额外构造 step_adv_raw。
最终 A = A^E + omega * A^S。
```

所以当前实现是:

```text
GRPO + per-token step advantage shaping
```

而不是单纯的:

```text
GRPO + rule scalar reward
```

### 6.5 输出格式差异

2505.22050 论文要求输出类似:

```text
visual_state_description
reasoning_and_reflection
language_plan
executable_plan
```

当前代码的 prompt 也要求这些字段,而且 reward JSON parser 优先取 `executable_plan`。

但当前代码的 step credit 只关注 `executable_plan` 中的:

```text
action_id
action_name
```

不会给 `visual_state_description`、`reasoning_and_reflection`、`language_plan` 里的 token 直接加 step advantage。

这和当前方法目标一致:训练动作决策,而不是训练解释文本。

---

## 7. 当前实现与 StepOPSD 的详细对比

### 7.1 最大共同点

两者都可以概括为:

```text
step-aware advantage shaping for GRPO。
```

更具体:

```text
都不是把 teacher signal 单独做一个 KL/distillation loss。
都在 rollout 完成后处理 sampled response。
都解析 step/action span。
都把局部 step 信号注入 policy gradient 的 advantage 通道。
都试图修正 trajectory-level sparse reward 的信用分配问题。
```

如果当前论文主方法强调 `forward_proxy`,那和 StepOPSD 的相似度很高,不能写成“完全不同路线”。

### 7.2 Hindsight / teacher 来源

StepOPSD:

```text
teacher context = causal prefix + peer-trajectory hindsight
teacher model   = stale reference policy

peer-trajectory hindsight:
  同一个 GRPO group 中,如果有成功 rollout,
  用第一个成功 peer 给失败 trajectory 提供 hindsight。
```

当前 forward_proxy:

```text
teacher context = image + GT reference plan + transition
student context = image + problem instruction
teacher model   = step_teacher_path 指定的模型
```

当前脚本实际:

```text
teacher = 未微调 Qwen2.5-VL-3B-Instruct
policy  = Qwen2.5-VL-3B-RobotGPT-R1
```

差异:

```text
StepOPSD 更通用:
  不要求数据集中有显式 GT action plan。
  只要 group 里有 successful peer。

当前代码监督更强:
  直接使用数据集 GT reference plan。
  更适合 EB-ALFRED 这种有 reference trajectory 的任务。
```

### 7.3 Delta 到 advantage 的变换方式

StepOPSD:

```text
Delta -> token weight w
w > 0
A_tilde = (1-lambda)A + lambda(wA)
```

性质:

```text
只改变 A 的大小。
不改变 A 的正负。
如果整条 trajectory 的 GRPO advantage 是负的,
局部 step 也不会被改成正方向,只能少罚或多罚。
```

当前代码:

```text
Delta -> step scalar A^S_k = tanh(...)
A = A^E + omega * A^S_k
```

性质:

```text
可以改变局部 token 的训练方向。
如果整条 trajectory A^E 为负,但某一步 rule/teacher 认为是对的,
该 step 的 token 可能被加到正方向。

如果整条 trajectory A^E 为正,但某一步是错的,
该 step 的 token 可能被拉成负方向。
```

这是当前实现和 StepOPSD 最核心的算法差异:

```text
StepOPSD:
  sign-preserving multiplicative reweighting。

当前代码:
  additive local step advantage。
```

### 7.4 step 粒度

StepOPSD:

```text
token-level Delta
token-level weight
step normalization 用来控制每个 step 的 credit budget
```

当前代码:

```text
先把 token_signal 聚合成 step scalar。
再把 step scalar 写回 action_id/action_name/semantic tokens。
```

当前代码更强调:

```text
step 是决策单位。
token 只是承载这个 step 决策的优化位置。
```

这和 embodied action plan 更匹配,因为 `{"action_id": 133, "action_name": ...}` 整体是一个动作选择。

### 7.5 span 定义

StepOPSD:

```text
ALFWorld:
  action_only

Search-QA:
  clean_step_no_observation
```

当前代码:

```text
pred_step_token_spans:
  action_id_tokens
  action_name_tokens
  semantic_tokens = union
```

这不是泛化的 agent transcript span,而是 embodied JSON plan 的结构化 span。

### 7.6 normalization / clipping

StepOPSD 有两个核心 knob:

```text
alpha_clip:
  控制局部 weight trust region。

lambda_mix:
  控制 shaped signal 与原始 advantage 的混合强度。
```

当前代码的 knob:

```text
step_advantage_w:
  A^S 总权重 omega。

step_score_tau:
  tanh 温度。

step_score_norm:
  none / per_response。

step_gate:
  none / residual_contrast / prompt。

step_budget_tau:
  residual gate 的 per-response budget 控制。
```

当前代码没有实现 StepOPSD 同款:

```text
w = clip(2 * sigmoid(sign(A) * Delta), 1-alpha, 1+alpha)
```

也没有完全等价的:

```text
equal_step_mean_abs
```

但 residual gate 里的 budget gate 有类似“不要让所有 step 都满强度更新”的意图。

### 7.7 对原始 rollout 的干预

两者都不改 rollout:

```text
先采样 rollout。
再做 post-rollout step credit。
最后更新 policy。
```

这点是共同点。

---

## 8. 当前实现的优点、风险和需要说准的地方

### 8.1 优点

#### 优点 1:把 trajectory reward 和 step credit 分开

当前实现没有破坏原始 verify reward:

```text
verify reward 仍然决定整条 trajectory 的 A^E。
step reward 只作为 A^S 叠加。
```

因此:

```text
omega = 0 可以退回纯 GRPO。
解析失败可以 A^S=0,不影响主训练。
```

#### 优点 2:rule step reward 对当前任务非常强

因为 action space 是离散的 `action_id`,且 GT 中有 reference trajectory:

```text
action_id exact/prefix/lcs 是直接的 correctness signal。
```

相比 forward_proxy,它:

```text
不需要额外 teacher。
不占 GPU。
不会自蒸馏塌平。
不会把“像正确动作的错误动作”误判为正。
```

#### 优点 3:forward_proxy 是一个活的软信号对照

当前诊断显示 teacher-student logp diff 不再全平:

```text
std 约 1-2
min/max 有明显波动
```

这意味着 forward_proxy 至少具备可训练信号,不是全 0 对照。

#### 优点 4:action_id/action_name 分离很适合 embodied plan

当前代码可以:

```text
用 semantic tokens 算分。
只把 credit 写到 action_id token。
不给 JSON scaffold 梯度。
```

这比直接对整段 JSON 做 KL 更贴近“动作选择”。

### 8.2 风险

#### 风险 1:forward_proxy 的 Delta 不等于动作正确性

Delta 表示:

```text
teacher 看 GT 后是否更愿意生成这个 token。
```

它不一定表示:

```text
这个 action 是否真的等于 GT action。
```

典型问题:

```text
GT 是 find DiningTable。
预测是 find Sofa。
teacher 可能因为 "find a furniture" 这个模式合理而给正 Delta。
```

所以 forward_proxy 的正确性需要专门验证,不能只看 diff std。

#### 风险 2:外部 teacher 改变了 OPSD 语义

如果 teacher 是 `Qwen2.5-VL-3B-Instruct`,policy 是 `RobotGPT-R1`:

```text
Delta = Instruct(GT context) - Instruct(no-GT context)
```

而不是:

```text
Delta = policy_or_stale_ref(GT context) - policy(causal context)
```

这在论文写法上必须说明,否则会被质疑“这不是 StepOPSD/OPSD 的同模型 rescoring”。

#### 风险 3:additive advantage 可能过强

当前:

```text
A = A^E + omega * A^S
```

如果 `omega=1`,而 A^E 的 group-normalized magnitude 也大约在 0-1 附近,A^S 可能显著改变更新方向。

这既是能力,也是风险:

```text
能力:
  能在失败轨迹里保留正确 step。

风险:
  如果 A^S 判错,会直接反向更新局部动作。
```

StepOPSD 的 sign-preserving 设计更保守,当前 additive 设计更激进。

#### 风险 4:rule exact 可能太硬

`action_id` exact 对当前任务很干净,但也可能:

```text
对等价替代路径不宽容。
对多余 find / 顺序轻微变化不宽容。
对 object instance 探索不宽容。
```

代码已经提供 `prefix` 和 `lcs`,但默认 `exact`,需要用实验比较。

---

## 9. 三方总表

| 维度 | 2505.22050 | StepOPSD | 当前 EasyR1-V4-Embody |
|---|---|---|---|
| 主问题 | 训练 embodied VLM planner | agent RL credit assignment | one-shot embodied JSON plan 的 step credit assignment |
| 基础算法 | SFT + GRPO/RFT | GRPO + step-aware OPSD shaping | GRPO + additive step advantage |
| 模型 | Qwen2.5-VL-7B | Qwen3-1.7B / Qwen2.5-3B | Qwen2.5-VL-3B RobotGPT-R1 |
| 任务 | Embench / EB-ALFRED / EB-Habitat | ALFWorld / Search-QA | EB-ALFRED parquet embodied planning |
| 输出 | structured reasoning + executable_plan | agent trajectory / actions / search steps | JSON with executable_plan |
| trajectory reward | rule format + prefix accuracy | env/QA reward | verify VLM functional equivalence + format |
| step 信号 | prefix correctness 汇总成 scalar | teacher-student logp gap | rule action_id 或 forward_proxy logp gap |
| step 信号进入方式 | 作为 response reward 的一部分 | multiplicative reweight A | additive A = A^E + omega A^S |
| 是否保留 A 符号 | GRPO scalar reward 决定 | 是 | 否,可能局部翻转 |
| teacher / hindsight | Gemini 用于 SFT,不是 RFT teacher | successful peer + stale ref | GT reference + configured teacher |
| span | action sequence prefix | action-centered step | action_id/action_name token span |
| 是否需要 GT step | 需要 gold sequence | 不需要显式 GT,依赖 peer success | rule 需要;forward_proxy 使用 GT context |
| 是否额外 KL loss | 否 | 否 | 否 |
| 最大风险 | reward 仍较粗,长程困难 | 与当前方法撞车点强 | forward_proxy 正确性、additive 过强、GT 依赖 |

---

## 10. 应该如何给当前方法定位

### 10.1 不建议的写法

如果主方法是 forward_proxy,不建议写:

```text
We propose to use OPSD-style teacher-student logp gap for step-level GRPO advantage shaping.
```

这个表述和 StepOPSD 撞得太正。

也不建议写:

```text
Our method is fundamentally different from StepOPSD.
```

因为两者确实同属 step-aware OPSD advantage shaping。

### 10.2 更准确的写法

可以这样定位:

```text
We study step-level credit assignment for one-shot embodied trajectory planning,
where a VLM generates a structured JSON executable plan in a single response.
Unlike general multi-turn agent trajectories, the decision variables are explicit
action_id/action_name fields. We inject step-local advantages into GRPO by mapping
either GT action matching or GT-reference-privileged teacher contrast onto these
structured action spans.
```

中文表达:

```text
我们不是提出“OPSD 信号用于 advantage shaping”这个大方向本身;
这个方向 StepOPSD 已经非常接近。

我们的具体切入点是:
在 one-shot embodied JSON trajectory planning 中,
利用显式 action_id/action_name 结构,把 GT-reference 或 rule step signal
映射到动作字段 token,并以 additive local step advantage 的方式注入 GRPO。
```

### 10.3 当前实现最清楚的贡献点

可以强调:

1. **任务形态差异**:

```text
one-shot embodied trajectory planning,不是一般 multi-turn agent transcript。
```

2. **结构化 action span**:

```text
显式区分 action_id 和 action_name。
可以 score semantic tokens,但只 credit action_id。
```

3. **additive local advantage**:

```text
允许局部 step 改变更新方向。
这和 StepOPSD 的 sign-preserving multiplicative reweighting 不同。
```

4. **rule vs forward_proxy 的系统比较**:

```text
当任务有干净离散 action_id GT 时,hard rule step reward 可能比 KL soft proxy 更可靠。
forward_proxy 作为软信号和无 step verifier 场景的泛化对照。
```

5. **gate 机制**:

```text
residual gate / prompt gate 用来控制 soft KL 信号进入 action tokens 的强度。
```

---

## 11. 建议补的实验和分析

### 11.1 必做:四个主 baseline

建议最小实验表:

```text
1. GRPO
2. GRPO + rule step reward
3. GRPO + forward_proxy additive
4. GRPO + forward_proxy + residual gate
```

如果资源允许,再加:

```text
5. GRPO + forward_proxy + prompt gate
6. GRPO + StepOPSD-style multiplicative reweighting
```

### 11.2 强烈建议实现 StepOPSD-style multiplicative baseline

为了和 StepOPSD 讲清楚,建议在当前代码里加一个模式:

```text
step_injection_mode:
  additive      # current
  multiplicative_stepopsd
```

multiplicative 公式:

```text
Delta_step 或 Delta_token 来自 forward_proxy。
w = clip(2 * sigmoid(sign(A^E) * Delta), 1 - alpha_clip, 1 + alpha_clip)
A = (1 - lambda_mix) * A^E + lambda_mix * (w * A^E)
```

然后比较:

```text
additive 是否真的优于 sign-preserving?
additive 的 sign flip 是否带来收益?
```

这个实验对论文非常关键,因为它直接回应 StepOPSD。

### 11.3 sign flip 统计

当前 additive 最大差异是可能局部翻转方向。建议统计:

```text
sign_flip_ratio =
  mean[ sign(A^E + omega*A^S) != sign(A^E) over action tokens ]
```

并分组看:

```text
成功 trajectory vs 失败 trajectory
正确 step vs 错误 step
Heat/Cool/Clean/PickTwo 等长程任务
```

如果能证明:

```text
失败轨迹中的正确前缀 step 被 additive 保留下来;
成功轨迹中的错误/冗余 step 被局部压低;
```

那就是相对 StepOPSD 的强证据。

### 11.4 forward_proxy 正确性分析

不要只看:

```text
teacher-student diff std
```

还要看:

```text
rule match = 1 的 step,forward_proxy A^S 分布。
rule match = 0 的 step,forward_proxy A^S 分布。
```

理想情况:

```text
correct steps: mean A^S > 0
wrong steps:   mean A^S < 0
```

如果 wrong steps 也大量为正,说明 forward_proxy 更像 style/trajectory prior,而不是 correctness signal。

### 11.5 rule mode 消融

比较:

```text
exact
prefix
lcs
```

可能结论:

```text
exact:
  信号干净但太硬。

prefix:
  更符合 embodied execution,一旦前面错了后面不该继续强判。

lcs:
  对顺序和多余 find 更宽容,但可能奖励不可执行的乱序计划。
```

### 11.6 credit target 消融

比较:

```text
score_source=action_name, credit_target=action_name
score_source=semantic,    credit_target=action_id
score_source=semantic,    credit_target=semantic
```

重点看:

```text
只训练 action_id 是否比训练 action_name 更稳定。
action_name token 是否引入措辞/格式梯度噪声。
```

---

## 12. 当前代码路径速查

### 12.1 数据和 prompt

```text
verl/utils/dataset.py
  embodied prompt 构造
  image processor
  multi_modal_data
  ground_truth 包装
```

### 12.2 trajectory reward

```text
verl/workers/reward/function.py
  compute_reward_batch
  verify prompt
  overall = 0.8 * accuracy + 0.2 * format
  reward 写最后一个 token

verl/workers/reward/verify.py
  ask_llm
  load_verify / load_verify_qwen3
```

### 12.3 step reward / step advantage

```text
verl/trainer/step_reward.py
  extract_plan_steps
  compute_step_match_rewards
  pred_step_token_spans
  build_step_adv_vector
  build_step_adv_vector_from_logp
  build_step_adv_raw
```

### 12.4 forward_proxy teacher

```text
verl/trainer/teacher_proxy.py
  TeacherLogpScorer
  PromptGateScorer

verl/workers/reward/verify.py
  step_logp_vl

verl/workers/reward/function.py
  AutoRewardManager.compute_step_adv
```

### 12.5 GRPO 接线

```text
verl/trainer/core_algos.py
  AdvantageEstimator.GRPO_STEP
  compute_grpo_step_outcome_advantage

verl/trainer/ray_trainer.py
  compute_advantage
  _build_step_adv
  _dump_adv_heatmaps
  _save_total_adv_heatmaps
```

### 12.6 配置和脚本

```text
verl/trainer/config.py
  AlgorithmConfig 中所有 step_* 字段

examples/qwen25_vl_3b_Domain.sh
  当前 forward_proxy 主运行脚本

examples/qwen25_vl_3b_residual_gate_ablation.sh
  residual gate 消融

examples/qwen25_vl_3b_prompt_gate_ablation.sh
  prompt gate 消融
```

---

## 13. 最后总结

如果用一句话串起来:

```text
2505.22050 告诉我们 embodied planning 可以用 SFT + rule reward + GRPO 训;
StepOPSD 告诉我们长轨迹 agent RL 的关键是 step-aware advantage shaping;
当前 EasyR1-V4-Embody 把这两个方向接到一起:
在 one-shot embodied JSON plan 上,用 verify model 给整轨 reward,
再用 rule 或 GT-aware forward_proxy 给 executable_plan 的 action spans 加 step-local advantage。
```

当前实现最应该讲清楚的不是“我们用了 GRPO”,也不是“我们用了 OPSD”,而是:

```text
我们如何把 embodied JSON plan 中的结构化动作字段变成可训练的 token-level step credit;
以及 additive step advantage 相比 StepOPSD sign-preserving reweighting 的差异、收益和风险。
```

当前代码已经具备一套完整实验框架:

```text
GRPO
GRPO + rule
GRPO + forward_proxy
GRPO + residual gate
GRPO + prompt gate
```

下一步最有价值的是补:

```text
StepOPSD-style multiplicative baseline
sign-flip analysis
forward_proxy correctness-vs-rule correlation
rule exact/prefix/lcs 消融
credit target 消融
```

这些实验能把“和两篇论文的关系”从文字解释变成可验证证据。