终于训练出最强坦克了 - V2EX
tylearymf

终于训练出最强坦克了

  •  
  •   tylearymf 7h 44m ago via iPhone 4959 views
    经过了 6 天的时间,这个版本的坦克差不多完美了

    https://imgur.com/a/Y4vZLZH

    我还搞了个逐帧回放的工具: https://github.com/tylearymf/agentank-replay-viewer

    欢迎大家来挑战我的坦克: https://agentank.ai/share/tanks/tnk_LwlLgzXJiBoJ065pI

    晚点再分享下经验
    41 replies    2026-05-26 16:11:42 +08:00
    diudiuu
        1
    diudiuu  
       7h 39m ago
    等级太高无法挑战
    hh4646908
        2
    hh4646908  
       7h 38m ago
    晚点是几点
    tylearymf
        3
    tylearymf  
    OP
       7h 15m ago via iPhone
    @diudiuu 你的是什么等级的,我还有好几个其他等级的坦克,代码是前几个版本的
    graetdk
        4
    graetdk  
       6h 52m ago
    很强,看到你一直在排行榜前面徘徊,刚刚被我超过去,现在你又第一了哈哈
    tylearymf
        5
    tylearymf  
    OP
       6h 30m ago
    @graetdk 哈哈,你搞的这个坦克对战可太有意思了
    graetdk
        6
    graetdk  
       6h 22m ago
    @tylearymf 门槛高了一些,但我确实觉得是有意思的
    xb3
        7
    xb3  
       6h 22m ago
    前几天玩,roll 到一个传送技能的坦克,让 ai 写了一个策略,测试了 100 把发现胜率在 70%-75%,再让 ai 写了个自动化脚本一直跑,第二天早上起床发现跑到总榜第二了,不过胜率降到了 60%-65%
    graetdk
        8
    graetdk  
       6h 21m ago
    @xb3 叫啥,我去打打
    tylearymf
        9
    tylearymf  
    OP
       6h 20m ago
    @xb3 不会是 keith 吧?
    doraemonki
        10
    doraemonki  
       6h 11m ago
    原来是你小子昨天一直逮着我虐
    tylearymf
        11
    tylearymf  
    OP
       6h 8m ago
    @doraemonki 你是哪个坦克的哈哈哈
    tylearymf
        12
    tylearymf  
    OP
       6h 6m ago
    @doraemonki 原来是你,ai 自动挑战的哈哈哈,有比我高的就打高的,没有比我高的就打离我最近的
    tylearymf
        13
    tylearymf  
    OP
       5h 47m ago
    我一开始不是让 AI 写一个“会打架”的坦克,而是问它:如果这是一个每帧决策的竞技系统,怎么设计一个能持续变强的 agent ?后来我发现最强的关键不是某个招式,而是三个东西:战场建模、优先级仲裁、回放驱动迭代。
    tylearymf
        14
    tylearymf  
    OP
       5h 46m ago
    现在这辆坦克每帧都会先构建上下文,更新敌人和子弹记忆,再按“活命、必杀、控星、隐身、移动”的顺序决策。每次输局我都会拆成一个具体失败类型,比如草丛反击、边缘陷阱、星线争夺、隐身后没离开暴露点,然后把它变成一个新的风险判断或回归测试。
    mindddd
        15
    mindddd  
       5h 44m ago
    好玩
    tylearymf
        16
    tylearymf  
    OP
       5h 42m ago   1
    可以,接着你可以这样讲,语气偏“技术分享”,但不至于太论文味:

    ---

    接下来我就把坦克拆成了一个真正的 agent 系统。

    它不是每一帧简单判断“敌人在不在前面,在就开火”。如果这么写,前期确实能赢一些弱对手,但很快就会遇到问题:敌人在草丛里看不见、子弹 1 帧飞两格、星星比击杀更重要、地图边缘看起来能走但下一帧必死。

    所以我把它拆成三层。

    第一层是**感知层**。

    每一帧开始时,我先把游戏状态整理成一个 `ctx`。这个 `ctx` 里面有我的位置、方向、敌人的位置、敌人的方向、星星位置、比分、地图、子弹、技能状态。

    同时还有一个跨帧记忆 `AG_MEM`。
    这个东西很重要,因为游戏里敌人可能会隐身,子弹也可能没有完整方向信息。如果只看当前帧,很容易误判。所以我会记住:

    ```text
    敌人上一次出现在哪里
    敌人上一次朝向哪里
    子弹上一帧在哪里
    我最近走过哪些位置
    我是不是刚开过隐身
    我是不是在原地绕圈
    我刚才有没有开火
    ```

    这一步其实就是把“游戏画面”变成“可计算的战场状态”。

    ---

    第二层是**风险评估层**。

    这个阶段我不是马上决定动作,而是先问几个问题:

    ```text
    我现在会不会被子弹打到?
    我下一步会不会踩进炮线?
    敌人一转头能不能打我?
    我走到边缘后还能不能脱离?
    我开隐身之后有没有离开暴露点?
    我去吃星会不会被草丛反杀?
    ```

    这个地方是后期变强的关键。

    比如有一局我以为代码里已经判断了“死路”,但还是跑到了地图边缘被打死。后来复盘发现,那一格从地图几何上看不是死路,因为它还有好几个出口;但从战术上看,它是死路,因为敌人下一步一移动,就能跟我同线,然后一转头开火,而我从那个格子逃走需要两帧。

    所以后来我加的就不是简单的 `safeExits <= 1`,而是类似:

    ```text
    如果我走到这个位置
    敌人下一步能不能移动到同线?
    敌人转头需要几帧?
    子弹飞到我这里需要几帧?
    我从这个位置脱离炮线需要几帧?
    ```

    如果敌人开火比我脱离更快,那这个格子就算不是墙,也应该判成危险格。

    这就是从“地图判断”升级成了“战术预测”。

    ---

    第三层是**优先级仲裁层**。

    也就是 `choose()`。

    我后来发现,很多坦克代码的问题不是没有策略,而是策略之间会互相抢优先级。
    比如:

    ```text
    我想隐身绕后
    但现在有子弹飞过来

    我想草丛反击
    但星星马上要被敌人吃掉

    我想追杀敌人
    但我已经领先,拖时间就能赢
    ```

    所以我把整个决策链排成了优先级:

    ```text
    先躲弹
    再看有没有必杀
    再看能不能安全开火
    再处理贴星封锁
    再处理近星争夺
    再处理草丛反击
    再处理隐身刺杀
    再处理普通追星和移动
    ```

    这里有个很重要的思想:

    > 最强的 agent 不是每次都选最激进动作,而是每一帧都知道当前最不能犯的错是什么。

    比如子弹来了,那就不要想击杀。
    星星马上要决定胜负,那就不要为了绕后丢星。
    敌人已经在近距离炮线里,那就不要原地隐身装聪明,要么开火,要么脱线。

    ---

    然后我会讲一个具体例子。

    比如草丛反击那一版,最开始的问题是:敌人藏起来后,我的坦克会进入一种“反伏击”逻辑,试图横向脱离或者预判敌人位置。但有时候星星就在附近,这时候最重要的不是躲草丛,而是抢星线。

    所以后面我加了一个 `nearStarContestAct`。

    它的作用不是“无脑吃星”,而是判断:

    ```text
    星星离我近不近?
    敌人有没有可能抢?
    我有没有一个安全格可以缩短到星星的距离?
    这个格子会不会进敌人炮线?
    这个动作会不会被 hidden ambush 逻辑抢掉?
    ```

    如果满足条件,就优先抢星位。

    这就是一个很典型的迭代:
    不是把草丛逻辑删掉,而是让它在更高优先级的控星逻辑面前退让。

    ---

    然后再讲隐身。

    我这辆坦克是 cloak 技能,但我后来发现,隐身不能当万能保命按钮。

    很多时候原地隐身其实没用,因为敌人已经知道你上一帧在哪里。你如果隐身后不移动,子弹照样打到你。

    所以现在隐身逻辑里面有几个不同模块:

    ```text
    能不能隐身接近
    隐身后要不要先换位
    有没有机会绕到背线
    同线时能不能直接开火
    敌人是否已经瞄准我
    我是不是为了隐身丢掉星星
    ```

    也就是说,隐身不是一个动作,而是一段战术流程:

    ```text
    开隐身
    离开暴露点
    绕到安全线
    确认敌人炮口风险
    再决定开火或继续换位
    ```

    这个也是后面从失败里磨出来的。

    ---

    最后我会讲整个训练闭环。

    我每次不是凭感觉调参数,而是这样做:

    ```text
    拉最近比赛
    筛失败局
    看死亡前几帧
    判断是哪类失败
    复现那个局面
    加一个很窄的规则
    跑回归测试
    跑模拟
    再发布
    ```

    比如一次失败可能最后变成一个新规则:

    ```text
    不要走进边缘同步炮线陷阱
    不要让草丛反击抢掉近星争夺
    隐身后必须离开暴露点
    同线近距离时必须在开火和脱线之间二选一
    星星被土堆挡住时,先找破土位
    ```

    这些规则单独看都不大,但叠起来之后,坦克就从“会打架”变成了“会做战术决策”。

    ---

    最后收束可以这样说:

    > 所以我觉得这件事最有意思的地方,不是 AI 一次性帮我写出了最强坦克,而是 AI 帮我搭了一个 agent 的思考框架。后面真正变强,是我不断用真实对局去撞这个系统,把每一次输局都转成一个更精确的判断。
    >
    > 到最后,这辆坦克其实不是靠某个神奇招式赢,而是靠一套越来越完整的决策系统赢:它知道什么时候活命,什么时候控星,什么时候开火,什么时候隐身,什么时候宁可不动也不能犯错。
    tylearymf
        17
    tylearymf  
    OP
       5h 40m ago
    ```mermaid
    flowchart TD
    A["每帧 onIdle"] --> B["构建战场上下文 ctx"]
    B --> C["更新记忆 AG_MEM"]
    C --> D["风险评估:子弹、炮线、陷阱、星星"]
    D --> E["choose 优先级决策链"]
    E --> F["guard 二次拦截"]
    F --> G["执行 go / turn / fire / cloak"]
    G --> H["回放复盘与回归测试"]
    H --> D
    ```
    tylearymf
        18
    tylearymf  
    OP
       5h 38m ago
    这套系统的好处是,它不是一坨互相缠在一起的逻辑,而是一个分层决策链。我要加新规则时,通常不是重写整个坦克,而是新增一个 xxxAct(ctx),然后把它插到 choose() 里合适的优先级位置。

    加规则本身很简单,难的是判断这个规则应该管哪一小类局面,以及它应该排在谁前面、谁后面。

    我现在加规则的方式有点像给 agent 加 middleware 。每个规则都只责一种战术形态,输入都是同一个 ctx ,输出都是统一格式的 action 。如果规则不触发就返回 null ,让后面的规则继续判断。这样扩展性很好。

    我不会把规则写得很宽。每条规则都尽量窄,只解决一种明确失败模式。因为规则越宽,越容易把原来能赢的局面截胡掉。
    tylearymf
        19
    tylearymf  
    OP
       5h 37m ago
    总的来说:不是“规则越多越强”,而是“规则越精确越强”。
    phpcyy
        20
    phpcyy  
       5h 30m ago
    https://agentank.ai/history/mat_5HKNkhPN2EbIhK272

    (⊙o⊙)…

    谁搞的地图,困局
    tylearymf
        21
    tylearymf  
    OP
       5h 29m ago
    这套系统像一条决策流水线。每个规则只负责识别一种局面:如果它发现自己该接管,就返回动作;否则就把决策权交给下一个规则。这样我加新规则时,不用重写整套系统,只要插入一个新的判断模块。
    tylearymf
        22
    tylearymf  
    OP
       5h 27m ago
    @phpcyy 哈哈哈,这得让作者来看看了 @graetdk ,话说你的坦克是 Taoqi 啊?
    daimon1
        23
    daimon1  
       5h 24m ago
    厉害!
    phpcyy
        24
    phpcyy  
       5h 24m ago
    @tylearymf 是的,打不过你了
    tylearymf
        25
    tylearymf  
    OP
       5h 19m ago
    @phpcyy 昨晚我挂了一晚上 ai 挑战,然后我们俩时不时互换一二名哈哈哈哈,跟你打要能赢只能看服务器那边的随机种子了,昨晚好像连输你 7 、8 把,现在我让 ai 在分析昨晚的战局。
    tylearymf
        26
    tylearymf  
    OP
       5h 18m ago
    @phpcyy 本来 61 的胜率,昨晚打完你之后,变成 59 了
    terrysnake
        27
    terrysnake  
       4h 58m ago
    我没 OP 强,我是黄金: http://agentank.ai/?invite=05911d56b6

    大家有兴趣来干我
    graetdk
        28
    graetdk  
       4h 54m ago
    @phpcyy 随机地图生成的锅,我优化一下算法
    graetdk
        29
    graetdk  
       4h 53m ago
    @terrysnake 你给的是邀请链接,不是坦克链接哥
    Cabana
        30
    Cabana  
       4h 37m ago
    哈哈,曾经用 codex /goal 模式上了王者, 但后面 context 爆炸,又给我跌成钻石了
    CL7
        31
    CL7  
       4h 37m ago
    酷啊,才知道有这样的平台,觉得这个创意太好了,之前直接写了一个类 claw 的产品 clclaw.ai ,理论上它能做任何事,但实际上很多事都做不好,感觉这样的平台真的太有创意,可以释放很多人无处安放的 AI 创造力
    allanwell
        32
    allanwell  
       4h 28m ago
    最高只到过第 8 ,然后迅速滑落,一直在 20-40 这个区间徘徊。。。
    kuhung
        33
    kuhung  
       4h 8m ago
    谢谢老哥的分享,这就去蒸馏(
    tylearymf
        34
    tylearymf  
    OP
       3h 43m ago
    ## 几个有意思的设计点

    ### 1. 未来一帧死亡预测器

    早期我只判断“当前位置有没有危险”,后来发现不够。
    有些格子现在看起来安全,但我一走过去,敌人下一步就能对齐我,然后转头开火。

    所以我加了一个短期预测:

    - 我走到这个格子
    - 敌人按照当前方向走一步
    - 敌人是否能和我同线
    - 敌人转头需要多久
    - 子弹飞到我这里需要多久
    - 我从这个格子脱离炮线需要多久

    如果敌人击杀我的时间更短,这个格子就被视为危险。

    这个点最有意思的是:
    它说明“地图上能走”不代表“战术上能走”。

    ---

    ### 2. 隐身不是按钮,而是状态机

    这辆坦克有隐身技能,但我很快发现,原地隐身没有意义。
    敌人虽然看不见我,但它知道我上一帧的位置,子弹还是能打到那里。

    所以我把隐身拆成几步:

    1. 判断是否值得开隐身
    2. 开隐身后立刻离开暴露点
    3. 侧向换位,避免仍在原炮线
    4. 判断是否已经形成击杀窗口
    5. 如果没有击杀窗口,就继续换位或脱离

    隐身的核心不是“消失”,而是制造位置差。

    ---

    ### 3. 草丛反击和抢星会打架

    有一类局面很有意思:敌人藏起来,我的系统会进入反伏击模式。
    但如果星星就在附近,反伏击未必是第一优先级。

    早期有一局就是这样:系统为了处理隐藏敌人,错过了更重要的星位。
    后来我加了一个仲裁逻辑:

    > 在关键星位附近,控星优先于反伏击。

    这不是说反伏击不重要,而是说不同规则之间必须有优先级。
    很多 bug 不是规则本身错,而是规则排队顺序错。

    ---

    ### 4. 躲子弹本质是时间竞速

    子弹一帧飞两格,所以不能只看“子弹现在在哪”。
    真正要算的是:

    - 子弹几帧后到我这里
    - 我转向需要几帧
    - 我移动出炮线需要几帧
    - 我移动过程中会不会穿过子弹轨迹

    如果子弹到达更快,我就不能选择那个动作。

    这让躲弹从简单坐标判断,变成了一个时间问题。

    ---

    ### 5. 星星不可达时,先创造条件

    有些地图里星星被土堆挡住,直接寻路会失败。
    早期系统会在附近绕圈,因为它知道星星重要,但不知道怎么到达。

    后来我加了一个目标分解逻辑:

    - 如果星星当前不可达
    - 找一块打掉后能打开路线的土堆
    - 先走到能射击那块土堆的位置
    - 打通路线后再重新追星

    这其实就是从“追目标”变成了“先创造追目标的条件”。

    ---

    ### 6. 每次输局都变成一个窄规则

    我不是一次性写一个大而全的智能体。
    后期基本是:

    - 看失败回放
    - 找死亡前几帧
    - 判断是哪类失败
    - 抽象成一个小规则
    - 加进决策流水线
    - 再用模拟验证

    每条规则都尽量窄。
    比如不是“不要靠边走”,而是“不要走进敌人下一步能对齐、转头、开火,而我又来不及脱离的边缘格”。

    窄规则的好处是副作用小,也更容易验证。
    terrysnake
        35
    terrysnake  
       1h 45m ago
    @graetdk fuck , 这链接不行啊,这个: https://agentank.ai/share/tanks/tnk_C0Mxx9byaqnBoDf87
    terrysnake
        36
    terrysnake  
       1h 44m ago
    怎么我变大师了。。。
    tylearymf
        37
    tylearymf  
    OP
       1h 28m ago
    @graetdk 能搞个模拟测时支持设定敌方技能和地图吗,现在有些东西测试不到
    graetdk
        39
    graetdk  
       1h 20m ago
    @tylearymf 直接实战测试吧
    tylearymf
        40
    tylearymf  
    OP
       1h 10m ago
    bravecarrot
        41
    bravecarrot  
       28 mins ago
    这个实在太无聊 太上头了
    About     Help     Advertise     Blog     API     FAQ     Solana     5293 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 569ms UTC 08:40 PVG 16:40 LAX 01:40 JFK 04:40
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86