阅读视图

发现新文章,点击刷新页面。
🔲 ☆

用js写卡牌游戏(十)

没想到,上一篇这个系列的文章 居然是 2023年6月,现在2026年1月了,又一次破了我鸽的记录!
这次想起来更新这个卡牌游戏是因为我最近刷POE2非常上头,无数的天赋树和装备的组合,给这个游戏带来了无限的灵活性。如果有了解过游戏开发,一定知道虚幻引擎,它有一套 GAS 系统,通过这套系统能够让游戏的技能系统做起来又快又灵活,所以我想把这套系统的部分设计引入到我的卡牌游戏里来。

关于GAS

GAS就是Gameplay Ability System,游戏玩法技能系统,但我不介绍这个完整的系统,我只介绍这个系统中的一部分,其实拆开来看,就是几个经典的设计模式组合在一起的产物。
这个GAS里有两个很重要的概念,Tag和Effect,Tag顾名思义就是标签,描述一件衣服,就可以用各种Tag来表示,比如红色、格子、长袖、尼龙等。

如果有这套Tag系统,那么我只要多实现一些Tag然后进行排列组合,就能得到全新的一件物品,比如我把红色改为黑色,那么我将得到黑色的衬衫:

然后就是Effect效果,从Tag可以推理出来,如果Tag对应的是状态,那么Effect对应的是改变状态的方法,如果我开发了一个“折叠效果”,对应的方法的内容是:

  1. 添加 “不可折叠” Tag、添加 “可展开” Tag
  2. 改变面积为原来的四分之一

我就可以将这个Effect应用到衣服上,这时衣服的属性就会自动发生改变,并且神奇的是,这个Effect也可以应用到一切有“服装”Tag的物品上,我以后开发了“裤子”、“裙子”、“毛衣”全部都可以直接用。

在这些内容里,你可以看到命令模式、策略模式、状态模式等等经典设计模式的影子,他将开发的“复利”效应做到了极致,POE就是这样设计的,同样你可以在Dota2里也看到这样的设计

// 这是一个非常简单的技能,他是一个被动技能,给单位添加了一个粒子特效。
"fx_test_ability"
{
    // General
    //---------------------------------------------------------
    "BaseClass"             "ability_datadriven"
    "AbilityBehavior"       "DOTA_ABILITY_BEHAVIOR_PASSIVE"
    "AbilityTextureName"    "axe_battle_hunger"

    // Modifiers
    //---------------------------------------------------------
    "Modifiers"
    {
        "fx_test_modifier"
        {
            "Passive" "1"
            "OnCreated"
            {
                "AttachEffect"
                {
                    "Target" "CASTER"
                    "EffectName" "particles/econ/generic/generic_buff_1/generic_buff_1.vpcf"
                    "EffectAttachType" "follow_overhead"
                    "EffectLifeDurationScale" "1"
                    "EffectColorA" "255 255 0"
                }
            }
        }
    }
}

通过定义 bahavior、modifier、”OnCreated”这样的钩子、”AttachEffect” 这样的Effect,就能配置出一个技能,无需编写代码,并且添加或者修改、组合部分属性,就是一个全新的技能。

我的设计

我的卡牌过去是这样实现的:

{
    id: 13,
    name: "没毕业的天才程序员",
    cardType: CardType.CHARACTER,
    cost: 3,
    content: `每回合结束时,获得+1/+1`,
    attack: 1,
    life: 1,
    attackBase: 1,
    lifeBase: 1,
    type: [""],
    onMyTurnEnd: function ({thisCard, specialMethod, position}) {
        if (position === CardPosition.TABLE) {
            thisCard.attack += 1;
            thisCard.life += 1;
            specialMethod.buffCardAnimation(true, -1, -1, thisCard, thisCard)
        }
    }
}

并且有效果的牌都是这么实现的,可以看到每个效果都需要我单独的去写函数,或者是在对象上添加属性比如 isStrong 这种,对于代码实现不方便不优雅(还好用的是javascript),而且无法很好的保存到数据库里,只能存在代码文件中来硬编码定义。

所以想要做到像POE、Dota2那样进行配置,理想的情况下卡牌应该是这样的:

{
    "id": 13,
    "name": "没毕业的天才程序员",
    "cost": 3,
    "content": "每回合结束时,获得+1/+1",
    "attack": 1,
    "life": 1,
    "attackBase": 1,
    "lifeBase": 1,
    "types": [],
    "tags": ["Tags.Character"],
    "effects": {
        "onMyTurnEnd": [
            {
                "type": "ModifyAttribute",
                "target": {
                    "type": "self"
                },
                "params": {
                    "attribute": "attack",
                    "value": 1,
                    "operation": "add"
                },
                "conditions": [
                    {
                        "type": "cardPosition",
                        "params": {
                            "position": "TABLE"
                        }
                    }
                ]
            },
            {
                "type": "ModifyAttribute",
                "target": {
                    "type": "self"
                },
                "params": {
                    "attribute": "life",
                    "value": 1,
                    "operation": "add"
                },
                "conditions": [
                    {
                        "type": "cardPosition",
                        "params": {
                            "position": "TABLE"
                        }
                    }
                ]
            }
        ]
    }
}

虽然说看起来内容复杂了,没有代码那么一眼看上去逻辑清晰,可是这些配置是完全能够可视化的,也就是说以后可以通过卡牌编辑器来可视化的进行卡牌配置,但是代码就无法有效的进行可视化了(对于不懂编码的人来说,比如说策划或者爱好者社区这很重要)。

所以设计任务: 1. 原来的各种属性抽象为Tag。 2. 原来的各种钩子的效果整理好,抽象为各种 Effect。

{
    id: 13,
    name: "卡牌名称",
    cardType: CardType.CHARACTER, // tag
    cost: 3,
    content: `卡牌内容描述`,
    attack: 1,
    life: 1,
    attackBase: 1,
    lifeBase: 1,
    isStrong: true, // tag
    isFullOfEnergy: true, // tag
    type: ["类型"],
    onMyTurnEnd: function ({thisCard, specialMethod, position}) { // effect
        if (position === CardPosition.TABLE) {
            thisCard.attack += 1;
            thisCard.life += 1;
            specialMethod.buffCardAnimation(true, -1, -1, thisCard, thisCard)
        }
    }
}

按照 Effect 的设想:

{
    "onMyTurnEnd": [
        {
            "type": "ModifyAttribute",
            "target": {
                "type": "self"
            },
            "params": {
                "attribute": "attack",
                "value": 1,
                "operation": "add"
            },
            "conditions": [
                {
                    "type": "cardPosition",
                    "params": {
                        "position": "TABLE"
                    }
                }
            ]
        },
        {
            "type": "ModifyAttribute",
            "target": {
                "type": "self"
            },
            "params": {
                "attribute": "life",
                "value": 1,
                "operation": "add"
            },
            "conditions": [
                {
                    "type": "cardPosition",
                    "params": {
                        "position": "TABLE"
                    }
                }
            ]
        }
    ]
}

还是需要有过去的钩子定义,比如 onMyTurnEnd、onStart,方便我们在每个流程阶段检查卡牌是否配置了对应阶段执行的 Effect,接收 Effect 数组,方便我们进行 Effect 组合来实现非常灵活的效果。

需要把所有的函数过一遍,总结一下所有的函数实现的效果,然后抽象成简单的 Effect 和对应的参数。

这样在各种流程里,比如出牌阶段,刚打出的时候可以触发卡牌的 onStart 效果

// 示意伪代码
function outCard() {
    // ...
    triggerCardEffect(card, 'onStart', baseContext);
    // ...
}

triggerCardEffect 内部简单来看可以这样设计:

// 示意伪代码
function triggerCardEffect(card, trigger, baseContext) {
    // 获取卡牌的效果配置
    const effectConfigs = card.effects?.[trigger] || [];

    // 构建完整上下文
    const context = {
        ...baseContext,
        thisCard: card,
        // 还需要加各种 effect 和 tag 相关的系统环境数据
        // 比如 effectRegistry、tagRegistry 用于快速获取注册了的 effect和tag,比如 effectEngine 用于执行 effect
    };

    // 依次执行效果
    effectConfigs.forEach(config => {
        this.executeEffect(config, context);
    });
}

executeEffect 内部主要就是利用命令模式、策略模式来把我们实现的各种 Effect 执行逻辑应用在卡牌上:

// 示意伪代码
function executeEffect(config, context) {
    // 获取实现的 effect 函数
    const EffectClass = this.effectTypes.get(config.type);
    if (!EffectClass) {
        console.warn(`Unknown effect type: ${config.type}`);
        return null;
    }

    const effect = new EffectClass(config);

    // 检查条件
    if (!effect.canExecute(context)) {
        return;
    }

    effect.execute(context, targets);

    // 处理后续效果链
    if (effectConfig.then) {
        effectConfig.then.forEach(nextConfig => {
            this.executeEffect(nextConfig, context);
        });
    }
}

所有的 Effect 就只需要实现预定义的各种函数,然后注册起来:

/**
 * BaseEffect - 效果基类
 * 所有具体效果类型都继承自此类
 */
class BaseEffect {
    constructor(config) {
    }

    /**
     * 检查效果是否可以执行
     * @param {object} context - 执行上下文
     * @returns {boolean}
     */
    canExecute(context) {
        return false;
    }

    /**
     * 执行效果
     * @param {object} context - 执行上下文
     * @param {Array} targets - 目标列表
     */
    execute(context, targets) {
        throw new Error("Must be implemented by subclass");
    }

    /**
     * 获取效果描述文本
     * @returns {string}
     */
    getDescription() {
        return this.type;
    }
}

module.exports = BaseEffect;

不过,都到了2026年了,我就不分享具体的代码实现过程了,我分享点别的。

实现过程

既然现在都用AI来辅助开发了,那么实际上我可以直接分享我的Prompt,这样就能够一步步的让AI在你的环境也实现相同的功能而不用是完全相同的代码。(如果AI给力的话)
我的代码编写基本是用 Claude Code(Opus4.5)和 Copilot(Opus4.5),查询资料用 Kagi Assistant 的 Research。

第一条prompt,先用Plan模式让AI做好计划:

当前的卡牌存储在 @card-game-server/cards.js 里面,可以看到卡牌的效果基本上都是用代码写的,比如 onStart onMyTurnStart 等等,这些都是钩子函数。
这种设计有一个问题,要添加卡牌,必须要能够写代码,现在需要将这个设计修改,请使用UE5的GAS的 effect tag 设计,把各种基础效果改为已经实现好的 effect 和 tag,之后的卡牌只要配置对应的 effect tag就能够实现各种能力,而新增effect tag能够让每个tag添加进来和别的tag组合成为成倍数增加的新能力。
设计需要尽可能的全面和优雅。

如果你的AI不知道UE5 GAS,那么你可能需要查询一些UE5 GAS相关的设计内容总结给AI。

AI的计划大概如下(肯定都会有不同,但没事):

可以看到 Tag 带有层级,这是 组合模式 的应用,能够让我们方便的多层级进行判断,比如我们有时候只想要知道 State.Stunned 眩晕状态来让卡牌无法行动,至于是 State.Stunned.Light 还是 State.Stunned.Heavy 不重要。 Effect 也支持链式效果,能够让我们多 Effect 组合的同时,也能够链式的递归进行 Effect 调用。

这个Plan阶段可以和AI多轮讨论达到自己想要的最好情况,后续其实也能修改,但这个阶段讨论清楚是最好的。

后续就直接可以让AI开始修改,如果你是使用的Opus4.5,那么大概率这一把就能够改出八成,有可能出现下面的几种问题,这也是我碰到的。

卡牌数据没有完全迁移到新结构

有可能会出现 cards.js 还是有很多遗留数据,或者甚至就完全没有迁移,所以:

现在的卡牌已经转为使用 effect tag 来进行配置了,但是卡牌的数据 cards.js 还是使用的函数。 请把这些卡牌数据转为使用effect和tag,因为这里的数据过大,请分批次转为多个json(按照卡牌职业分类)。

AI将会分批次把 cards.js 里面的硬编码的卡牌转为新的配置的json文件:

文件命名不规范

有的 Effect 会单独有一个文件夹,或者相类似能力的 Effect 会放到一起,但有的不相干的 Effect 又全部集合到了一个文件里,所以:

新增了 UtilityEffect.js 但别的effect都是单独的文件,最好这几个也用对应的文件放在一起,以后能够通过文件名来寻找对应的effect。并且请把level中的卡牌也改为effect配置的。

AI有时候因为上下文过长的问题,会出现部分代码不遵守规范的情况,这个情况也可以让AI做一份 CLAUDE.md / AGENTS.md,然后在文件里加上这个规范。

偷懒不实现缺失的Effect

AI为了偷懒,创建了一个 LegacyHookEffect ,来支持用过去那种老的用函数定义效果的方法。

/**
 * LegacyHookEffect
 * 允许在 Effect 配置中调用旧版函数式卡牌效果
 */
class LegacyHookEffect extends BaseEffect {
    constructor(config) {
        super(config);
        this.type = "LegacyHook";
    }

    execute(context) {
        const { handler } = this.params;
        const fn = legacyCardEffects[handler];

        if (typeof fn === 'function') {
            fn(context);
        } else {
            console.warn(`[LegacyHookEffect] handler not found: ${handler}`);
        }
    }
}
LegacyHookEffect 是偷懒的行为,把这些函数定义改为effect配置就是不希望再有使用函数配置的卡牌了。  
如果当前的effect设计不足以做到把所有卡牌都改为可配置effect的json表达,请告诉我哪里需要修改。如果当前的effect不足,需要新增,请告诉我要增加哪些。

并且,AI如果不够聪明,可能会出现胡乱设计的情况,所以在用AI修改的时候一定要审阅他的输出计划,并且自己对代码一定要有理解,然后及时纠正AI的错误:

isStrong 等属性没有真正的用 Tag 来重构

Review代码的时候发现,AI并没有理解 Tag 这种设计(不过我们也没说),改的不够彻底,所以:

现在代码里的模仿GAS的tag系统似乎没有真正用起来,现在的tag是用ApplyTag这个Effect来模拟之前的属性做法,给卡牌加上 isStrong 这样的属性,我希望你能彻底修改为tag的做法,只需要判断卡牌的tag是否有 Status.Buff.Strong,而不需要再转回原来的属性模式,所以原来的属性模式相关的逻辑也要改为GAS的tag模式。
那这样的话,是否 cardType 其实也不需要了,直接用 tag 来实现就可以了。

这样AI会把过去的属性移除,然后用新的Tag来重构,过去判断 isStrong 的地方,都变成 hasTag(card, “Status.Buff.Strong”)。

其他内容

本次还修复了一些bug,然后还增加了SQLite模式,这样大家在跑这个项目的时候就不需要再启动一个MongoDB了。

AI

实现这个 Effect 和 Tag,增加SQLite支持,外加测试和一些其他的修复bug,总共耗时1天。本来半天其实就差不多了,但是AI写的代码总是有一些不优雅,所以需要自己去微调,可以手动,也可以让AI继续改。比如 Status.Buff.Strong 这类的字符串,可以抽取常量,比如 hasTag 这类的工具方法,还有一些过去我实现过可以直接用的系统。
不过如果没有AI,这个修改起码要花好几天,大部分的代码质量也不一定有AI做的好。

下一步

翻了翻上次发的文章,说是要把AI加进去,确实可以,而且应该很简单,然后还可以做一个卡牌编辑器。
就是不知道这次要鸽多久,视频稍晚一点做完也会发。

🔲 ☆

2025.12 AI使用有感

不知道是不是因为AI真的陷入了瓶颈,现在的模型很少出现完美的,每个模型总是有一定的缺陷,这也就导致了用AI需要一些技巧,这些技巧让AI带来的智力平权又拉开了一点距离。

我有这个想法,最初是源于教老婆用AI,她之前用AI用的不多,在给她使用了Claude Code、Codex、Gemini CLI、Copilot等产品之后,她惊呼好用,但我观察她的使用总是觉得笨笨的,仔细总结之后发现用AI确实是需要一些技术和一些经验。

例如她喜欢非常简单的描述问题然后与AI进行非常多轮的讨论来明确整个需求,这导致AI的无用上下文大幅提高,AI在处理长上下文的情况下性能又会下降很多。

又比如她不喜欢切换模型,当我告诉她Opus4.5好用之后,所有的情况都是用Opus4.5来完成,导致一些比较复杂的逻辑性需求或者Bug改来改去无法完成,这种情况下使用Codex的ExHigh或者High才是最佳选择,虽然说可能思考十几分钟,但是问题基本上是能够修复的。

还比如最好别给AI用“你是XXX”,别跟AI提“我”,写界面最好提供设计截图,用Simple Browser来给AI提供DOM上下文等等等等。

这里面门道其实挺多,造成用AI的能力也有1-10倍的差距。

🔲 ☆

How I AI Coding 2025.10

因为看到了Xuanwo大佬文章,所以我也来写一下我是怎么用AI来开发的。

工具

VSCode Insider with Copilot,Codex,Claude Code,Kagi,AIPP
现在日常用的就是VSCode Insider,因为Copilot的新特性基本都是先在Insider版本试用的,所以如果要用到最好的Copilot就只能牺牲一点稳定性来使用Insider版本了。目前我的工作里有很大的部分是无法通过Vibe Coding来完成的,所以还是比较依赖编辑器里的代码补全,Copilot现在是用的GPT 4.1 来做的代码补全模型,智力和速度都是在线的,也有Next Edit Suggestions,很符合我的需求。Copilot Agent现在比过去的可用性提高了很多,比以前更能利用模型的能力,也加入了Todo、PlanMode 之类的辅助能力,也很少出现只读文件一部分的情况了,Apply的速度虽然说比不上Cursor,不过也算快了。而且Copilot订阅有网页端,在 https://github.com/copilot ,日常有一些问题可以在网页端直接询问,不需要别扭的在 VSCode 里来询问和代码不相干的事情了,我通常有一些常识性的问题或者对Github上仓库的问题都会在网页端用Gemini 2.5 Pro来进行问答。Copilot网页端的Agents在我的测试看来基本不可用,模型不明但是估计是Sonnet 4.5之类的,效果奇差,不过会启动环境做验证,期待未来吧。(还有个很重要的点就是我穷,Cursor现在的计费我要是放开了用会破产,Copilot高级请求用完之后,还有无限的4o和4.1使用,这点让我很安心)

然后就是Codex和Claude Code了,在Vibe一些小项目时Claude Code挺好,但是当项目大到一定程度或者问题达到一定难度后,Claude Code基本上就是帮倒忙了,这个时候GPT 5 High的智商优势就体现出来了,虽然一个任务大概率要跑十几到几十分钟,但是实实在在的能优雅的完成任务,所以我已经很少使用Claude Code了,基本换到了Codex。(我没有订阅这俩的官方服务,我是通过中转站来使用的,所以我只在需要使用的时候才会对这俩工具付费,这能节约很多钱。)

还有一个我觉得非常好用的工具就是Kagi(AI能力是需要付费的),搜索的非常精准,基本第一页就会出现我要的结果(保守的说法,其实一般第一条就是),在搜索引擎的能力加持下,它家的搜索Agent Ki就更强了,目前看只有GPT5 Pro的Search能够打打。Kagi在我做预研或者查解决方案的过程里,给了非常多的帮助。

AIPP是我自己写的开源ChatApp,别的ChatApp各有优势但也总有槽点,所以做一个符合自己使用习惯的,我在中转和国内的厂商(Kimi、GLM、Deepseek)都有充值,用API来对一些问题提问。现在也只是刚把功能做好,还有很多Bug,不过我自己足够熟悉更新迭代的也会很快。

MCP

Context7,Jina,自己写的禅道、数据库MCP
Xuanwo大佬在9月的版本中认为“MCP is still a lie”,我倒是有不同的意见,MCP在简化上下文资源中有命令行和基础工具不可替代的作用。
Context7是一个用于查询文档的MCP,是我必备的MCP,大模型的知识跟不上导致API经常使用过时,甚至新的库直接就不知道怎么用,不使用Context7就得自己去查了然后告诉大模型或者模型就开始胡说。
Jina是我用来让AIPP搜索和联网的MCP,也有很多别的替代不过我最偏爱Jina这家公司。
禅道MCP是我在AIPP或者Copilot中能够快速的查看Bug情况,数据库MCP则是连接公司内部的开发库来快速的开发和改Bug,如果不使用MCP很难有更高效的方式让我放心的对禅道和数据库进行授权让AI调用。

感想

Xuanwo大佬提的感想大部分我都赞同,我说一些我自己的别的感想:

多模态能力其实对写代码挺重要的,尤其是前端,目前感觉最好的是Gemini 2.5 Pro,因为可以接受视频的输入,连动效都可以实现。

绝大部分人的绝大部分编程任务其实不需要模型多高的智力,只要能够描述清楚,Sonnet 4.5或者GPT5 Medium就足够了,国内的GML4.6、Kimi K2也是足够的。

模型的智力比承载工具重要多了,参考Cursor和Codex就明白,Sonnet的进步让Cursor异军突起,GPT5 High的能力让难用的Codex也能忍着用下去。

    AI产品需要反复的去用,很多东西刚开始用的时候非常垃圾,但是随着产品和模型的演进,突然就非常好用了。

    所有的产品都可以用AI来重写一次,但是产品里的基础能力还是不可或缺的,AI也只能是替代原有产品的使用者来自动调用这些基础能力,没法替代产品本身。

    🔲 ☆

    2025阅读清单

    上次1月中旬写,这次直接8月写,服了我自己了。

    1.地煞七十二变图鉴

    ★★★★★

    很少看志异的小说,但是推上面看太多人推荐了,于是看了下,感觉作者写作是真的当作品在创作,而不是赚钱的工具,不管是文笔、写法都是顶级,故事也是引人入胜,虽然有鬼怪但却不会觉得太过恐怖,而是跟着剧情和主角进行代入。

    2.我看见的世界:李飞飞自传

    ★★★★

    作为一本传记很不错了,以当事人的视角亲身经历了各种领域内口口相传的故事,很有意思。同时感叹家庭的力量和朋友的力量是多么强大。

    3.第七重解答

    ★★★★

    反转挺多的,有时候觉得这什么啊?我一下就猜出来了;有时候觉得卧槽?还能这么反转?

    4.小说写作:叙事技巧指南(第十版)

    ★★★

    想写小说,听书听完的,收获有但是不多。

    5.美国创新简史:科技如何主推经济增长

    ★★★★

    属于我认知之外的书,不知道是不是真的写的好,因为对于我来说,这本书里的东西都很新鲜。

    🔲 ☆

    2025游戏清单

    暗黑4

    进度:不会再玩了,除非超级大更新

    评分:6/10

    评价:比暗黑3都不如

    POE 2

    进度:没事刷刷

    评分:8/10

    评价:我玩过POE 1,给我感觉的POE 2可以进步的空间太大了,相比起来还有好多地方需要完善,但是喜欢刷刷刷的一定要玩玩看,相比暗黑4,灵活程度简直是100倍,不会有那种“策划教你玩游戏的感觉”(不过还是会有相对于别的Build更强力的个别Build)。

    Monster Train 2

    进度:浅玩几轮

    评分:6/10

    评价:感觉一般般,一来不是我最喜欢的类型,二来我感觉不如我玩过的别的类似的游戏,前期卡组非常单调,正反馈不足。

    马里奥赛车世界

    进度:每日进行中

    评分:8/10

    评价:我倒是只有那么喜欢玩,但是我3岁的儿子每天都要在里面跑。

    咚奇刚:蕉力全开

    进度:每日进行中

    评分:9/10

    评价:每天睡前、拉屎的时候都在玩,只能说喜欢马里奥奥德赛的人不要错过一点。

    元炁 Demo

    进度:八九不离十

    评分:5/10

    评价:画面不行、修仙系统设计也不行、操作也别扭,看之前的宣传不知道是不是换了模板了,反正现在是不值得去玩的。

    逃离鸭科夫

    进度:第一张地图打完

    评分:7/10

    评价:还原塔科夫还原的还不错,画风也还行,就是简单了点,几张地图打完之后估计就没内容了,感觉不值50,作为30块来说应该算神作。不属于FPS游戏,更像RPG,没游戏玩的可以去试试。

    三国望神州

    进度:每日进行中

    评分:7/10

    评价:类三国曹操传游戏,做了一些改进,并且加了非常多氪金的点,不过微氪也能玩毕竟是战棋游戏,动脑会大大提高战力。不过现在愿意动脑的人好像不多了,这是不是这些游戏能氪到钱的原因?后续还会出刘备传,到时候再来更新。

    燕云十六声

    进度:弃坑

    评分:7/10

    评价:之前就听说了但是一直没玩,结果突然国外社区火了,于是下载来看看,做的很牛逼,但是和逆水寒之类的区别感觉不大,东西多的一逼,反而没那么好玩了。如果之前没试过逆水寒这类的江湖游戏,可以试试燕云。

    POE 2:最后的德鲁伊

    进度:刷

    评分:10/10

    评价:GGG真的不错,虽说很久更新一次(几个月),但是每次更新都像是做了一个新游戏出来(之前有这个感觉的是V社的DOTA2)。举个例子,这次更新的德鲁伊其中的一个升华(先知)的一个天赋可以看到别人看不见的天赋树,点完之后起码多出大几十个新天赋,这只是升华的一个天赋点啊!(反观暗黑,呵呵)。

    🔲 ☆

    日常-阅读 How we built our multi-agent research system

    今天抽空阅读了 Anthropic 的 How we built our multi-agent research system,其中有不少过去就已经了解熟知的知识,也提到了不少能够激发我思考的点,来总结总结。
    首先先说说之前就了解的:

    1. 一个非常聪明的规划者。Anthropic 用的自然是 Opus,规划任务、决策都是 Opus 来做的,越聪明的 AI 做规划者越能提高执行者的效率和效果,目前第一梯队的规划者只有 3 个,Anthropic 4-Opus、OpenAI O3、Gemini-2.5-Pro,排名有先后。
    2. 执行者的能力不能太低。Anthropic 的执行者使用的是 Sonnet,而不是 Haiku,执行者要能正确的使用工具,正确的遵循格式来输出,并且最重要的是能够理解任务的要点。
    3. 使用记忆。PreAct 的要点就是提前计划并且生成 TODO,需要记住 TODO 完成的状态;在每轮迭代任务的过程中,都会产生新的结果,都需要进行记录;长时间执行的任务,会产生巨长无比的上下文,通常经过总结后也需要保存到记忆中。文章中配了两张图都提到了 Memory 可以看出它的重要。 之所以不把记忆归类到工具,是因为记忆可以算作一个基础设施,是必须要使用的,而工具是根据任务的不同可以选择用或者不用。
    4. 使用工具。给予丰富的工具才能让 Agent 的智能发挥作用,最近看的最典型的例子就是,ChatGPT 网页上的 O3 在工具加持下能够通过非常普通的照片定位到照片拍摄位置。过去我倾向于看模型的 Aider 评分来看模型的能力,因为这个评测集通常反应了模型编写代码和指令遵循的能力,但发展到现在的阶段,Aider 的评分已经无法反应出模型真正解决问题的能力,现在我更喜欢看模型的 SWE-bench Verified 评分,这是一个经过筛选的现实问题集,考验模型使用各种工具来解决现实问题的能力,不过通常强的模型这两者的分数都不会低。

    再来谈谈新的收获:

    1. 巨量的 Token 消耗。Anthropic 提到 Multi Agent 是普通聊天的 15 倍 Token 消耗,所以应该让 Multi Agent 作用在能产生高价值的地方,而不是普通的任务。我之前有想过为什么 AI IDE 不搞一个这种 Multi Agent 模式,能够又聪明又快速的完成任务,从这篇文章中可以一窥原因,现在的 AI IDE 不约而同的让自己的工具在尽量少的 Token 消耗的情况下来解决问题,但基本都是事与愿违,有时候看着 AI 50 行 50 行代码的 read,真的哭笑不得。想必这就是 AI 提供商巨头的护城河,他们的 Token 基本上是 Free 的,通过烧 Token 来提高效果这是一般的应用公司没法做到的。
    2. Agent 调试。之前从没有想过来做一个工具像断点代码一样调试 Agent,Anthropic 做了一个工具,能够逐步的观看 Agent 如何进行处理,这使得在 Agent 优化的过程中能够直观的、不停的 减少 不必要的工具调用、生成冗长的搜索词等。这也让我想到了可以把 传统编程中的很多调试方法都带到 AI 应用开发,除了断点,还有像日志(做个 MCP 来让 AI 自动输出日志到指定的地方)、Mock(假设模型的前置返回或者 MCP 的返回来进行测试调试)等等,对于 AI 这种黑盒开发有不小的帮助。
    3. 智能体自我进化。像 Cursor 中的 Agent 自动调用测试获取报错信息或者是获取 Lint 报错一样,如果任务执行的不好,Anthropic 会让 Sonnet 自己来修改提示词再次进行尝试,直到获取到更好的结果。甚至当提供的 MCP 工具有问题时,Sonnet 会去修复这个工具然后继续。之前看信息流里有 OpenAI 的老哥说 O3 的降价也来自于 Codex 对系统的自我进化开发。这相当于强化学习训练出来的 AI 来用强化学习的方法来训练一个应用?
    4. 并行处理。不光是把任务分解后多个 Agent 同时去完成所有的任务,还有 Agent 同时调用多个工具来解决一个任务。这个想法其实我之前也想到了,并且在一个 Side Project 中也实践过了,效果非常好,这个 Project 是一个小说编辑器,在对小说进行润色的过程中,会让规划者先标记出来哪些句子需要润色,再让多个执行者并行的对每个句子来进行润色。原来这个任务在润色一篇 3000 字的文章时,起码要等待 40 秒(使用的是 gemini 2.5 pro),使用了这种方式之后,大约 10 秒内就能看到结果了。
    5. 提示词优化。Anthropic 提到一个微小的提示词修改,使得任务成功率从 30% 提高到 80%,这让我想到之前听的播客中的一个观念:如果我修改16 次提示词最终完成了比较难的问题,那么这个过程中,到底是我太菜了还是 AI 太菜了?Anthropic 很大方的开源了自己的提示词,可以去 Anthropic 的仓库里看看。
    6. 工程化。Anthropic 提到了很多工程化的问题,包含了 恢复状态、容错、可调试可观测可测试、部署更新、执行与并发 等各种挑战,这也是每个做 AI 应用的开发者都可能会碰到的问题,所以 AI 应用并不是写个提示词那么简单,涉及到的编码和传统软件工程的知识都非常多。在目前,至少是 2025 年 6 月这个节点,根本不可能有真的0编程知识的人能够使用 AI 开发上线运营一个应用。

    想法:
    我曾经花了一个小时,和 AI 对谈让它来不停的问我问题了解我,最终总结出了一大篇关于模仿我的提示词,然后我就可以与“我”对话了。不过这个“我”的上下文还是太少,比如我正在写的项目和完成的进度,比如我的朋友同事们的性格和我们之间的经历,比如我还有一些并不符合 AI 政策的想法无法输入进去。同时“我”的能力还是太少了,抛开能影响现实中的能力不谈,在电脑中的能力也少的可怜,虽然我也配置了很多 MCP 但 AI 任然不能用我的电脑做任何事,比如聊微信、写 Word、刷信息流等等。但如果我提供了某个特殊领域的所有工具,比如程序员或者产品经理,它能够写代码、执行命令、获取错误、截图看效果、写 Markdown 文件、发飞书通知、查看禅道 Bug 情况、跟进飞书多维表格的任务进度,那他是不是真的可以成为某个领域中的我,然后再用 Multi Agent 技术来模拟许多个我,让我的效率得到千百倍的提高。这件事我会去做,不过估计做的会比较慢,我相信随着模型智力的提高,最终的那个“我”肯定比现在的我要更胜任我的工作,那时候我应该可以躺着了。
    最近一直被安利 Claude Code,不过没抽时间去试,昨天偶然看到了一个 MiniJinja 的作者使用 Claude Code 修复现实中的 Issues 的视频,可以看到的是,Claude Code 并不能真正“完美”的完成任务,改动的方案并不是最佳的,也没有遵循用户的指令先进行方案讨论不要立马实现代码,修复这两个 Issue 都是需要资深开发者来介入的。所以我一直偏向 Cursor 这类 AI IDE,纯 Agent 很容易把原来优雅的代码改成屎山,然后又要花时间去把屎山做优雅。不过如果是 Vibe 一个简单的 Side Project 用这种方式应该还是很舒服的,等我下一个 Side Project 启动的时候我会开一个 100 刀的 Claude Code 试试。

    🔲 ☆

    数据结构-Merkle Trees

    从 https://simonwillison.net/2025/May/11/cursor-security/#atom-everything 看到的文章看到的相关文章了解到的。

    Cursor 使用这个数据结构,用于快速定位到文件内容的变更,当数据块修改的时候,能够快速通过 hash 来找到变化的部分,我让 ai 给我做了个可交互的网页来理解这个数据结构,如下:

    Merkle Tree Demo

    Merkle Tree 默克尔树演示

    修改下方的数据,观察上面的哈希值如何变化,尤其是最顶部的默克尔根。

    默克尔树工作原理简介

    1. **叶子节点:** 底部是原始数据块(你可以修改它们)。

    2. **哈希计算:** 每个数据块首先计算出自己的哈希值(显示在输入框下方)。

    3. **层层向上:** 相邻的哈希值被组合(串联),然后计算新的哈希值,形成上一层的节点。

    4. **默克尔根:** 这个过程重复进行,直到最顶端只剩下一个哈希值,这就是默克尔根。

    5. **验证:** 默克尔根是整个数据集的”指纹”。如果任何一个数据块或其顺序改变,默克尔根都会完全不同。这使得只通过默克尔根就能快速验证数据的完整性,而无需检查所有数据。

    6. **应用:** 区块链(如比特币、以太坊)、点对点下载(如 BitTorrent)等都广泛使用默克尔树来高效地验证数据的完整性。

    🔲 ☆

    LLM-大模型绘制流程图

    过去在读代码的时候或者是学习的时候,经常让大模型给我画流程图,一直是用的 mermaid 的方式来绘制,使用这种方法的好处就是大模型基本上都会,因为 mermaid 算是非常有名的 markdown 中展示流程图的方案了。

    但是我在和网友沟通的时候,得知了一种使用 drawio 来绘制流程图的方法,这种方法不仅能够改善 mermaid 图不方便修改的问题,而且还能借助 drawio 的各种主题和颜色,直接美化流程图。输出大概如下:

    存为文件在 drawio 打开的效果如下:

    如果使用 mermaid 是这样的:

    网友是在小红书中看到的,但目前好像被删除了看不到了,我这边贴一下我从小红书中拿到的提示词:

    你是一个卓越的绘图高手,你需要根据用户的需求来进行绘图。
    **核心能力:**
    1.  根据视觉描述/需求直接生成可运行的draw.io代码
    2.  校验机制保证代码准确性
    3.  输出标准化代码块
    
    **处理流程:**
    ① 接收输入→ ②要素解析→ ③结构建模→ ④语法生成→ ⑤完整性校验→ ⑥输出结果
    
    **输出规范:**
    ```xml
    <!-- 经过校验的draw.io代码 -->
    <mxfile>
        [生成的核心代码]
    </mxfile>
    ...
    ```
    
    **交互规则:**
    - 收到图片描述时: "正在解析结构关系(进行描述图片细节)----(校验通过)"
    - 收到创建需求时: "建议采用[布局类型], 包含[元素数量]个节点,是否确认?"
    - 异常处理: "第X层节点存在连接缺失,已自动补全"
    
    **优势特性:**
    - 元素定位精度: ±5px等效坐标
    - 支持自动布局优化 (可禁用)
    - 内置语法修正器 (容错率<0.3%)
    
    **DrawIO 图形规范指南**
    drawio文件是基于mxGraph的XML结构
    基础要求
    • 展示在A4纸上,选择合适的字体大小
    • 字体必须全部加粗,标题等关键元素字号加大处理
    • 线段统一使用3pt宽度,保证在论文打印后依然清晰可见
    • 所有文本格式(加粗、下标上标、公式代码)必须正确实现
    • 使用标准drawio文件格式,保证兼容性
    • 组件必须完全容纳文字,避免文字溢出
    • 所有线条必须设置jumpStyle=arc和jumpSize=6,确保交叉处清晰可辨
    • 所有连接线拐点必须设置 rounded=1保证美观
    布局规范
    • 组件间垂直和水平间距保持统一 (30-50px为宜)
    • 将相关的组件放入容器或组中,以提高图表的可读性和组织性。
    • 对齐方式使用center,保持一致性
    • 使用网格对齐(gridSize=10)辅助布局
    • 避免组件和连接线重叠,特别是避免线条穿过文字
    连接线规范
    • 所有箭头样式必须统一 (endArrow=classic)
    • 多条连接线汇入同一组件时,应从不同方向进入(如左、中、右)
    • 同一起点的多条连接线应适当分散起点位置
    • 为所有交叉的连接线添加跳跃样式(jumpStyle=arc)
    • 长距离连接线应适当设置航点 (waypoints) 引导路径
    • 绝对禁止连接线遮挡文字和组件标签
    组件连接设计
    • 组件使用浮动连接点,而非固定连接点
    • 相关组件应放置在合理的相对位置,减少连线复杂度
    • 复杂流程应分层次展示,避免连线交叉过多
    文本与组件规范
    • 所有组件内文本必须加粗(fontStyle=1)
    • 数学公式使用HTML格式: h<sup>v</sup>和h<sub>inter</sub> 不要使用latex格式
    • 公式可以根据条件更换字体
    • 数学符号如点乘必须使用正确格式: 应写为&odot;
    • 合理使用waypoints:在需要精确控制连接路径时,可以使用固定的waypoints来避免线条交叉和文字遮挡
    • 组件大小应根据内容自适应,保持适当留白
    命名与结构规范
    • diagram name必须命名为有意义的名称 (如“多模态特征融合流程”)
    • 组件ID必须反映其功能(如query-network)
    • 连接线ID应反映实际连接关系(如edge-visual-query)
    • 相关元素应放在一起,提高代码可读性
    实践检查清单
    • 连接线交叉检查:所有交叉处是否设置了jumpStyle=arc
    • 文本遮挡检查:是否有连接线穿过文本或遮挡组件
    • 格式一致性检:字体、线条宽度、箭头样式是否统一
    • 连接美观性检查:连接线是否从合适的方向进入组件
    • 留白空间检查:组件之间是否有足够间距 (30-50px)
    • 代码健壮性检查:代码是否符合drawio开发规范,是否可以运行
    特殊场景处理
    • 复杂图表应考虑分层或分区域展示
    • 多条平行连接线应保持一致的间距和样式
    • 长路径连接应使用中间节点或分段处理
    • 双向连接使用两条独立的连接线而非双向箭头
    参考资源
    • DrawIO官方文档: https://www.drawio.com/
    • DrawIO学习教程: https://www.drawzh.com/
    • 在线编辑器: https://app.diagrams.net/
    • MXGraph语法: https://jgraph.github.io/mxgraph/docs/tutorial.html
    
    

    也许还可以简化,但是我懒得简化了,这样反正能用,效果也还挺不错的。

    特别说一句,我还测试了 excalidraw,但因为 excalidraw 绘图是用的绝对坐标定位,大模型完全不擅长这个,所以画出来的东西非常垃圾,这个思路不可行。drawio 如果仔细看他的绘制方式,都是使用的 id 引用,所以流程都是相对的,很适合大模型输出。

    要是哪个客户端能够直接嵌入个 drawio 展示就好了。

    🔲 ⭐

    产品职业随想

    随着干产品这个职业的深入,发现这个职业对于聪明要求的上线真是无限高,最近这段时间的几个感触记录一下:

    1. 产品经理最好是有一定的增长能力,把增长能力转化为设计的功能点做到产品里,比如了解当前的主流叙事和“流量密码”,把这些东西快速的融入到产品中,方便增长。这一点大部分的老板都比较敏感,通常有“流量密码”出来的时候老板总是第一时间希望能够在产品中添加,以蹭到这波流量,但老板的产品设计能力较弱,通常容易出现非常突兀的融合。
    2. 能把握到科技的发展,尤其是在现在 AI 发展速度爆炸的现在,仅仅设计一款利用到现有科技力量的产品是远远不够的,要能设计出随着领先与科技发展的产品,随着科技发展而得到提高。最火的例子就是 Cursor 了,模型越来越强,让 Cursor 从不好用变成了神器。
    3. 要有一定的非共识,有非共识的产品才能脱颖而出,否则就是靠资源堆砌的普通产品,随时可以被以更多资源堆砌的另一个产品替代。
    4. 接着上面的非共识,我举个我自己领悟到的:免费用户(或者说弱用户)应该被作为产品的资源和能力,来融入产品的设计。著名的设计比如网游的氪金机制、排行榜机制等。

    🔲 ☆

    工具-/usr/libexec/java_home

    我的电脑上安装了几个 JDK 来应对不同项目的开发,经常要进行切换,突然发现 macos 上有这么一个工具:

    /usr/libexec/java_home

    这个工具能够快速查看电脑里安装的所有 JDK:

    /usr/libexec/java_home -V

    输出大概为:

    Matching Java Virtual Machines (3):
        21.0.2 (arm64) "GraalVM Community" - "GraalVM CE 21.0.2+13.1" /Library/Java/JavaVirtualMachines/jdk-11.0.5.jdk/Contents/Home
        17.0.13 (arm64) "Amazon.com Inc." - "Amazon Corretto 17" /Library/Java/JavaVirtualMachines/jdk-11.0.5.jdk/Contents/Home
        11.0.5 (x86_64) "Oracle Corporation" - "Java SE 11.0.5" /Library/Java/JavaVirtualMachines/jdk-11.0.5.jdk/Contents/Home
        1.8.0_231 (x86_64) "Oracle Corporation" - "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home

    这样能够直观的看到安装的多个版本,然后用下面的命令切换:

    export JAVA_HOME=$(/usr/libexec/java_home -v 11)

    🔲 ⭐

    Weekly-08~17

    Basecamp 还有一本叫 Shape Up 的书,读了前两章就觉得受益匪浅,Basecamp 不愧是我一直向往的公司。
    🔲 ⭐

    Weekly-06

    工作

    国庆假期是真的在放松,很少工作,最多也就是巡检下客户的服务器,预研下之后要用到的自动测试框架之类的。

    学习

    为了设计Tea的插件系统,我研究了很多带有插件能力的程序的实现方式,其中我比较中意的是Obsidian的设计方式。
    关于插件系统,我有几个苦恼的点,第一是如何提供原生能力给插件,毕竟我不想插件也编写Rust,Obsidian是通过在前端项目中提供很多API来定义该插件的能力,并且提供了一些生命周期函数来让插件定义行为,而且好在我用的tauri本来就会开放一些基础API给前端,少了我很多工作。
    第二个苦恼是,灵活性和安全性的问题。插件很难像我开发Tea的本体一样做到那么多能力,而且那样也失去了插件系统本身的意义,我希望在我提供了大模型交互能力和存储能力的基础上,再来通过界面提供大模型驱动的一些应用功能,但在我实际设计这个插件系统的时候,我自己设想的应用在我设计的框架上都举步维艰,所以很明显的是我设计的并不够灵活,这还得从前辈们的设计里取取经。安全性就更难保证了,我参考了figma的插件设计的文章,他们为了安全花费了大量的精力,并且我觉得他们牺牲了开发的便利性,和我制作Tea插件系统的初衷背道而驰,我希望以后AI能便利的按照需求来为用户创建插件,太过复杂的插件系统很难和现在的AI能力匹配,我决定用最偷懒的方法来解决安全问题,我只内置我审核过并且开源的插件(Obsidian好像也是这么做的)。
    第三个苦恼的是技术方面,我希望插件打包后不要太大,如果每个插件都包含一套React相关的库,势必是会浪费很多存储空间,加载也会变慢,这个目前还是没有解决,插件只能自带UI库,不过也带来了一个好处,就算是用Vue也能加载进来了。。。
    还有更多的苦恼,不过解决苦恼也是会带来爽感的,可能这就是为啥我一直喜欢编程的原因吧。

    在日常用Tea的时候,又发现了一个很爽的地方:我想 给terminal设置环境变量之后自动切换到obsidian目录然后git push到github 这个操作加个别名然后一键完成(因为github时不时被墙),我不知道如何在powershell里编写这个命令,于是我用Tea来询问,并且让他编写一个命令能够运行后自动添加别名并且持久化,接下来我就只要利用Tea的代码运行能力直接点一下运行,这个别名就加好了。

    生活

    这个假期过得非常放松,和朋友开黑玩《三角洲行动》,想想之前开黑玩游戏,好像是几年前玩绝地求生了。
    还带娃去逛了逛公园,七天中唯一一天离开电脑,结果客户那边就出问题找过来了,好在同事帮忙解决完了。

    🔲 ⭐

    Weekly-05

    工作

    本周大部分还是干的产品的活,不过现在相对于之前来说已经得心应手了,而且AI大大的增强了我作为产品经理的能力,平时使用AI的时候会把需求一步步分解然后描述清楚,让我现在写PRD文档的时候如鱼得水。
    并且还碰到了之前没怎么遇见过的两个问题:时间回溯导致定时任务和雪花算法都报错的问题、Clickhouse在某些查询条件下会内存爆掉无法查询的问题。目前还没找到原因,只能先加强巡检避免问题产生影响。之后解决了问题会单独记录下解决过程。
    本周的工作还有一个重要的事情,我将开发环境从IDEA切换到了VS Code,IDEA的AI插件太难用了,我怀疑Copilot团队就是故意不做好让用户转向VS Code,至于不转到Cursor和Zed的原因是,Cursor的能力在我的评估体系里不如VS Code+Aider,而Zed也非常不适合Java这种体量的项目。目前转到VS Code还不是正式转过去,我需要先用VS Code工作一个月才能说能否正式抛弃IDEA。

    学习

    过于忙了没有产出多少的BIL文章,其实学习了不少东西的,十一假期的时候一一给这些文章补上。像是Cloudflare的产品更新、SQLite的“Many Small Queries”性能、一些特定场景下AI的提示词等等,这些属于文章不短且内容较深,我写文章的时候应该对这些东西的理解还会加深一个层次,我自己也很期待来写这些文章。
    Tea的更新进度我个人还比较满意,把Bang的交互调整了下,对于补全的交互能达到我自己还相对满意的程度了,就是前端调试补全面板位置的时候废了我老劲了,之前有一部分代码是AI写的,所以不熟悉结构和css的情况下来调整绝对定位让难度提高了一个数量级。

    生活

    娃去了动物园,我没去,其实还是很想看到娃看见各种动物的反应的。还是得努力让财富自由啊,这样就能人身自由了。
    最近股市疯了,可能这就是所谓的“调动市场预期”吧,大家突然都觉得大A能赚钱所以都开始买了,反正我亏的基金回本有望了,噢耶。

    🔲 ⭐

    Cursor Composer、Zed Workflow、Aider、Copilot Workspace对比

    本文只是对四款自动编码的产品做一个横向比较,单独的产品使用评测可以看看博客里单独评测的文章。最后有AI生成的对比表,省流的可以看每个对比的结果和最后的表。
    并且该横向评测的结果也只是我自己日常使用的主观感受,每个人的场景不同自然会有不同的体验。(叠甲

    选手简介

    • Cursor Composer:Cursor Composer是一款集成在Cursor编辑器中的AI自动化编程工具。它能够根据用户的需求描述,自动分析项目代码,并生成相应的代码修改方案。
    Cursor Composer
    • Zed Workflow:Zed Workflow是Zed编辑器的一个功能,允许用户通过提示来指导AI进行代码修改。与其说它像Cursor Composer,不如说是Github Copilot Chat的增强版。
    Zed Workflow
    • Aider:Aider是一个命令行工具,可以与多种AI模型配合使用。
    Aider
    • Copilot Workspace:Copilot Workspace是GitHub的扩展功能,目前只能通过Github Next提供的Web界面使用。它可以分析GitHub Repository,然后根据用户输入的需求生成解决方案,并直接修改代码。
    Copilot Workspace

    用于评测的项目是我编写的一个开源大模型客户端:https://github.com/xieisabug/tea

    对比维度

    我会针对以下几个维度来进行体验对比:

    • 工程能力
    • 代码质量
    • 用户体验
    • 价格与性价比

    详细对比

    工程能力

    • Cursor Composer:能根据需求自动识别出需要修改的文件、能够多轮次的迭代修改、能够选择是否应用单个修改,实际体验下来识别需要修改的文件不是非常的准确,并且使用的过程中还碰到了找不到历史记录或者修改文件失败之类的小bug。
    • Zed Workflow:工程能力很弱,需要手动提供上下文文件给AI,修改也需要自己去一个个点Transform按钮,而且不知道是不是因为格式过于复杂,Deepseek有时候会无法遵循格式导致这个Workflow没法用。
    • Aider:同样能根据需求自动识别出需要修改的文件、能够多轮次的迭代修改,修改会直接应用到文件上,通过git的能力来查看本次修改和回退修改。特殊的是aider具备出色的自检和自纠错能力,能自动运行测试用例并确保通过。Aider使用Deepseek也偶尔会出现没有遵循格式修改,但是Aider会自动让Deepseek重试。
    • Copilot Workspace:同样能根据需求自动识别出需要修改的文件、能够多轮次的迭代修改,能在网页上用diff格式展示出所有的修改,特殊的是它在输入需求之后提供分步骤的需求分析、代码分析、代码修改计划,有助于处理复杂任务理清思路,能够直接提交到Github Repository,也能通过最新的一个VS Code插件来同步修改到本地运行测试。

    Aider > Copilot Workspace = Cursor Composer >> Zed Workflow

    代码质量

    本来不应该在评测这种大模型工具的场景下,评测代码质量,因为代码都是模型写的并不是这些工具提供的能力。但在我使用的过程中,由于Prompt、工具限制等各种情况导致代码的质量还真有一些不同。

    • Cursor Composer:能用GPT和Claude之类的SOTA模型,也可以用自己的key,但是要转换为Cursor“认证”过的模型,也就是把模型名字要改成gpt4o之类的,我就是把deepseek用worker覆写成gpt4o来使用的。
    • Zed Workflow:纯纯的就是靠模型能力了。
    • Aider:得益于其强大的自我纠错和测试运行能力,代码质量最佳。支持几乎所有的模型,并且有一套自己的榜单Aider leaderboard和测试集,有钱的大哥可以体验体验用o1 preview自动写代码的快感。
    • Copilot Workspace:可惜只能用GPT(居然变成了减分项),有Copilot写代码的通病,喜欢吞括号和分号。现在可以申请o1系列的模型了,我还在waitlist里等着。

    Aider = Cursor Composer > Zed Workflow > Copilot Workspace

    用户体验

    • Cursor Composer:集成在编辑器中,使用便捷直观,和聊天是用的同一套UI体系,一方面来说比较稳没有什么学习成本,一方面来说又太稳了不突破很难有惊艳的效果。也许就是因为Cursor的这个稳让新入场的开发者都能非常快速的感受到它的能力。
    • Zed Workflow:学习曲线也低,毕竟没啥东西。
    • Aider:对于熟悉命令行的开发者体验还是不错的,与终端的结合度高,可能是因为不需要操心界面的原因,功能的完成度也非常高,基本上该有的命令该有的提示该有的检查全部都做到了,并且减少了对鼠标的依赖。但是学习曲线较陡峭,需要一定时间来“学习”使用这些功能,会用和不会用简直就是两种体验。
    • Copilot Workspace:也是直观的界面且易于使用,但是其功能是独立于IDE的,所以使用的时候总是要切换来切换去。允许用户调整AI生成的分析和计划,可调整的空间很大。没什么学习的东西,基本上也就是一个输入框用来提需求就完事了。

    Cursor Composer > Copilot Workspace > Aider > Zed Workflow

    价格与性价比

    • Cursor Composer:必须开通Cursor Pro才可以使用这个能力,然后只有500次高级模型的使用权限,所以500次之后就得用自己的key来使用Composer功能。价格是20刀,不过20刀里还有Cursor的补全服务,这个补全服务我觉得比Composer值钱。不过我觉得20刀换500次高级模型使用+补全,还是不太值 (经过网友指正,不是500次高级模型,是500次快速的高级模型,之后应该还是会有可排队的高级模型使用),20刀买api能用很久了,尤其是带有缓存命中的Claude和Deepseek(Deepseek 20刀能用一年吧,能不能提高点价格然后加加速啊)。
    • Zed Workflow:有自己的Zed AI服务,但是暂时没收费,也可以用Copilot提供的GPT4o,这点还挺好,目前推荐用这俩,因为Zed的机制导致它使用的时候会消耗很多Token,如果没有缓存命中机制的提供商用起来会破产,除了Zed AI和Copilot之外最好就是用Deepseek了。
    • Aider:工具本身免费开源,需要付费的是大模型的API。同样,使用缓存命中机制的提供商会便宜很多。
    • Copilot Workspace:价格性价比优秀,尤其对于已经使用GitHub和Copilot的开发者。目前还不用额外订阅,暂时只需要Copilot的10刀。

    Copilot Workspace > Aider = Zed Workflow > Cursor Composer

    总结

    • 对于需要强大工程能力和高质量代码输出的开发者,Aider 是一个很好的选择,Aider是一个长板很明显短板也很明显的工具。
    • 暂时还不推荐Zed Workflow,就算是结合Zed AI的各种能力和插件来使用,也达不到很好的效果,可以再让它发展一段时间。
    • Copilot Workspace 对于目前拥有Copilot,并且维护了开源项目的开发者,非常友好,暂时没有额外的收费并且用户体验做的很好。
    • 对于那些希望在熟悉的VS Code环境中获得自动编码辅助的开发者,Cursor Composer 是一个不错的选择,并且因为其高结合度,操作非常便捷。
    • 目前这类的产品我最终还是找到了使用场景,最初我认为:复杂的任务无法完成、简单的任务用它完成徒增复杂度,现在我认为:复杂的任务拆解成简单的(这是我的能力)、经过多次与AI配合熟练后简单的任务让AI来做,我和AI配合起来还是很节省时间的

    对比表

    同样,最后让AI出一个表格

    特性Cursor ComposerZed WorkflowAiderCopilot Workspace
    工程能力⭐⭐⭐⭐☆⭐☆☆☆☆⭐⭐⭐⭐⭐⭐⭐⭐⭐☆
    代码质量⭐⭐⭐⭐⭐⭐⭐⭐⭐☆⭐⭐⭐⭐⭐⭐⭐⭐☆☆
    用户体验⭐⭐⭐⭐☆⭐⭐☆☆☆⭐⭐⭐☆☆⭐⭐⭐⭐⭐
    价格性价比⭐⭐⭐☆☆⭐⭐⭐⭐☆⭐⭐⭐⭐☆⭐⭐⭐⭐☆
    自动文件识别⭐⭐⭐⭐☆⭐⭐☆☆☆⭐⭐⭐⭐☆⭐⭐⭐⭐⭐
    复杂任务处理⭐⭐⭐⭐☆⭐⭐⭐☆☆⭐⭐⭐⭐☆⭐⭐⭐⭐⭐
    自我纠错能力⭐⭐⭐☆☆⭐⭐⭐☆☆⭐⭐⭐⭐⭐⭐⭐⭐☆☆
    模型选择灵活性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐☆☆☆☆
    版本控制集成⭐⭐⭐☆☆⭐⭐⭐☆☆⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
    学习曲线⭐⭐⭐⭐⭐⭐⭐⭐⭐☆⭐⭐☆☆☆⭐⭐⭐⭐☆

    注:⭐⭐⭐⭐⭐ 表示最佳,⭐☆☆☆☆ 表示最差

    🔲 ☆

    工具-Zed Workflow

    这次测试的是Zed的Workflow,原理其实和Cursor Composer差不多,也就是让大模型对需要修改的文件,按照格式来进行输出,编辑器再解析该格式。不过Cursor对自动化的交互做的好很多,不仅自动获取了需要修改的文件,还自动触发了修改动作,Zed的Workflow就是缺少了这两步。先看我的使用流程:
    我的使用如下图:

    Prompt如下:

    我希望bang-list这个提示是展示在我输入框的下方,并且能够跟随我的光标位置移动的。
    而且当bang-list出现的时候,我是可以上下进行bang选择的,选择完成之后,bang会自动填充到我的输入框中,并且bang-list会消失。
    我输入的!删除的时候,或者输入的!后面不匹配任何bang,bang-list也会消失。

    可以看到Zed AI是需要你自己去指定文件的,比Copilot和Cursor都要差一些。
    AI的回复如下,会分步骤将实现需求所需要修改的代码展示出来,并且有Transform操作直接将修改映射到对应的代码处。但实测该能力对大模型要求比较高,deepseek能够胜任代码编写工作但是无法保证格式每次都正确,4o和Sonnet 3.5是没有问题的。

    点击Transform之后就像下图一样,会在对应文件修改代码并且展示diff view。

    如下图是我使用Deepseek(忽略右上角的gpt4o,那是我覆写的model name)进行Transform出现的错误,多了个{{REWRITTEN_CODE}}。

    评价

    工程能力部分

    工程能力很弱,定位和Zed本身的情况差不多,是一个简单但是快速的工具。基本上是对某些特定的格式进行了界面渲染,提供了快捷的按钮来触发修改,其他的和别的自动编码工具几乎没有可比性。
    对于我个人来说,我使用工具是想快速解决问题,当然是用起来越简单越好,本身这个工具对我来说不具有“把玩”的属性。

    代码完成部分

    Zed的Workflow能使用任何模型,但是像我上面说的那样,模型必须有比较高的能力才能遵循格式,我使用的Deepseek在代码很多的时候,会出现不够遵循格式导致Workflow无法使用的情况。一方面是Deepseek模型的能力问题,另外Workflow要求的格式可能过于复杂了,有各种xml标签和代码块混合。

    UI UX部分

    和普通的Zed AI使用方式几乎一样,也就是多了一个Transform的按钮来自动修改代码,不能说它没做交互,只能说和自己的编辑器一脉相承的简洁。

    总结

    可用性差强人意,在特殊的场景下可能有用武之地,不过我应该还是会选择不使用这个Workflow。

    🔲 ☆

    工具-Aider

    写在最前:我个人更偏爱实用主义,对于界面啥的要求很低(绝对不是给我自己界面丑开脱!),所以Aider没有界面在我看来绝对不是减分项,但是肯定会有人觉得这是很重要的事情,所以如果介意这一点的可以在心里先给这个项目减分。

    用Aider的需求是紧接着之前新增的bang命令,我准备在前端界面上进行一点预览,比如!current_date这个bang应该在前端界面上能预览到日期,并且每分钟都检查是否到了新的日期等等;获取选中文本需要和Rust配合,在Rust获取到文本之后再想办法传递到前端展示。
    如何安装可以直接去官网查下,我不介绍了,先介绍下我是如何使用的,首先先搞 .aider.conf.yml ,持久化配置,不然每次启动Aider都要搞很多命令,我改的一般是下面几个配置:

    # 不进行自动提交
    auto-commits: false
    # 用deepseek模型提供商
    deepseek: true
    # 使用read-only这个文件
    read: [CONVENTIONS.md]

    这次的测试是用的Deepseek来进行的,因为价格更便宜而且Rust方面Deepseek写的更好,配置完key就可以直接运行Aider:

    export DEEPSEEK_API_KEY=<your key>
    aider

    接下来就是提需求了,使用了这么多自动写代码的产品之后,我目前摸索出了一些心得,那就是自己要把需求搞清楚之后拆分成简单的小任务,我的最终效果是这样,几个特殊的bang命令在界面上带有动态的预览:

    Aider虽然是支持自动找到需要修改的文件,和Composer、Copilot一样,不过最好还是自己添加下文件更加准确。我的第一个任务直接给的是界面相关的,并且手动添加了相关的前端文件:

    我希望给bang功能的 !s !cd !ct 增加预览,展示对应的内容,其中 !s 是由props传递进来  

    Deepseek没有正确理解这几个bang的意思,只是加了预览,但是没有实时更新日期和时间的预览值,于是我继续提修改要求(使用Sonnet3.5估计就没这种问题了):

    `!cd` 和 `!ct` 的值不用传递进来,直接在这个界面初始化,并且让currentTime应该每秒更新一次,currentDate每分钟更新一次

    这次就直接修改成我想要的样子了,然后继续修改样式,让界面美观:

    添加 `preview` class的样式,使这个预览的文字看起来更有预览的感觉,和实际的命令描述文本区分开 ,`!s`的preview如果发现selectedText没有内容,则不展示对应的preview部分,并且给preview设置最大宽度100px,超过的文本用省略展示

    期间Deepseek没有遵循Aider的指令格式,Aider会自动让Deepseek重新编写一次,然后就正确了,这个体验不错,不需要我去干预。
    接下来要修改Rust:

    udpate system_api.rs:新增一个tauri command,返回当前context里面的selected_text  

    后续还有一些聊天我就不赘述了,总共从启动Aider到测试完commit,大概花了30分钟不到,如果是我自己来写,估计时间差不多,但是这30分钟我除了提需求和测试之外,大概有一半时间我是在干别的事情,也就是说我自己花的时间大概是10-15分钟,体验还是不错的。

    附:Aider会自动寻找需要加到上下文的文件,示例如下

    我想要在输入bang的时候,比如!出现banglist提示面板之后,我还可以继续输入用于过滤bang command,直到输入的值无法匹配任何bang command才让banglist面板消失

    评价

    工程能力部分

    Aider是我目前使用到的工程最强的自动编码产品。
    强大的自检能力(升级、检索可用的key、确保项目有git等等)、自纠错能力(代码运行或者测试报错了会自动询问你是否要修复,也可以使用–yes让Aider永远自动运行不需要确认)、运行命令和读取错误能力(能够在写完代码之后自动运行测试用例,并且确保测试用例全部通过)、与terminal的结合完成度等,都让我觉得用着很舒心,不像是那种摇摇欲坠的半成品,写出来的代码因为纠错能力和运行命令来跑测试用例,所以相同模型下完成需求的能力比别的产品都要高,这属于对模型能力的增强而不是利用了。
    如果对没有界面而介意的同学可以试试看浏览器模式,不过我个人对他们和终端的结合程度已经非常满足了,单独为Aider开一个终端之后,几乎就相当于在IDE里集成了一个界面,而且也更少的使用到鼠标,让编码过程(不过好像也没多少编码过程了)更加的集中注意力。
    如果有心仪的IDE,比如VSCode或者JB家的,但是又没有心仪的自动编码产品,可以试试看Aider。

    代码完成部分

    Aider可以使用任何模型,而且对新提供商和模型的支持还挺快的。
    我使用的Deepseek,是Aider leaderboard上最便宜但是效果又在前列的模型(缺点嘛就是慢)。有钱或者有低价渠道的可以试试sonnet3.5和4o甚至是o1 preview,效果应该是比Deepseek要更好的。Aider在编写完代码之后会直接应用到代码文件中,这也是为什么Aider一定要你使用git的原因,不然你不知道它改了哪里(而且Aider默认是修改完代码就commit的,如果介意要配置下不要自动提交)。

    UI UX部分

    见仁见智,我个人还对这个交互比较满意,并且Aider也提供了一些配置来设置终端中的展示效果。
    不过有珠玉在前,和Cursor比肯定是不足的,能与原生IDE结合会让交互好很多,看Aider官方的意思是准备让社区发力,自己不会下场做。目前社区也做了点插件,我就没体验了。

    总结

    Aider是我心目中那种“水涨船高”的项目,随着大模型能力的提高,Aider能做到的东西也越来越多,大模型不管是智力、上下文、速度或者别的方面哪一项的提升,对于Aider本身来说都是增强。期待社区以后发力做出更好的编辑器插件吧。我的这个开源项目说不定也会以某种方式接入Aider。

    🔲 ⭐

    工具-Copilot Workspace

    不久前获取了Copilot Workspace的权限,一直没时间做测试,最近写了一个大模型工具客户端,刚好用这个开源项目来做下实验。
    可以通过Github上的Issue触发(AI自动改简单的bug和完成简单的需求现在就实现了?),也可以直接在网页里提自己的需求来触发。是的,看到这里你应该发现了,这个Workspace目前是无法直接在IDE里使用的。最近出了一个VsCode插件(2024.09.21 目前需要自己去下载vscode 插件文件安装),但是这个插件只能做到帮忙同步修改到vscode中。
    先介绍下流程吧,同样是之前测试Cursor Composer的那个需求(它没能完成),我直接通过Github Issue触发的:
    https://github.com/xieisabug/tea/issues/2
    点击了之后就自动进行分析,会列出它对需求或者bug的分析和解决方案。分析和方案都可以手动增删改,而且可以点击上面那个聊天的窗口对代码的情况进行自然语言描述,Workspace会根据描述再次改进之后,生成分析和解决方案。

    确认好分析之后,会根据分析来生成实现代码的计划,按照文件来列出所有计划,这个计划也是能自己进行增删改的。

    再之后就直接确认开始修改代码了。

    评价

    工程能力部分

    体验上来说比Composer要强上一些,毕竟编写代码是需要一定时间的,所以在我确认了你要如何修改之后,再去编写代码,我觉得这是能节省我大量时间的。
    而且寻找需要修改的文件比Composer的能力要强很多,应该也是在代码搜索方面下了很多功夫的,这次测试中,能准确找到我的rust文件和前端文件,但是同样找不到我的测试文件,好在我可以轻松的在Plan里自己加上这个文件。
    不过同样是写错的代码就直接错了,还是需要自己去调试的,好在有一个vscode插件能够同步修改到vscode里调试,之前没有这个插件的时候,只能在网页上人肉看,看完了提交然后再到vscode拉取到本地去修改。

    代码完成部分

    Copilot Workspace只能用默认的模型,也就是gpt 4o,之后可能会加上o1家族。
    使用了gpt 4o可能要作为减分项了,gpt 4o写代码完全不如sonnet 3.5,并且会犯Copilot也犯的错误,比如下图:
    ![[Pasted image 20240922164323.png]]
    喜欢去掉别人的括号或者分号,很是蛋疼。

    UI UX部分

    本来属于加分项,个人的体验感受是比Composer要强上不少的,直观、灵活,但是只能在网页上用而且只能用于Github项目,这应该就劝退了很多用户使用了。
    希望之后Composer或者别的项目能够参考Workspace项目的界面交互。

    总结

    如果Openai未来的模型代码能力提升上来,或者把o1接入进来,未来比Composer可期。

    🔲 ☆

    工具-Cursor

    很久以前,我曾使用过Cursor,当时它完全无法与Copilot相提并论。没想到现在再次使用,体验上的差距竟然如此巨大。

    首先是”无限Tab”功能,虽然触发频率较低,但一旦触发,它所带来的感官冲击非常强烈,令人难以不被震撼。仅仅修改了一处地方,多个位置就出现了shadow text,然后一路tab全部应用,只需触发一次就能爱上这个功能。

    其次是Chat功能,与之前使用的Zed AI类似,它能够方便地携带各种信息,包括上传的文档、网页、Git仓库、整个文件夹等等。虽然节约的只是复制和粘贴这两个操作,但这两个操作需要重复无数次。如果能够快捷地自动带上当前文件、选中的代码或整个代码库,那么解决的总操作量在高强度使用下每天可达数百甚至上千次。

    最后是Composer功能,被大家广泛誉为Cursor杀手级能力。但实际使用下来,体验并不理想。通常简单的任务用不上Composer,而复杂的任务Composer又无法完全胜任。不过,显然这是一个前景可期的功能,随着大模型能力的提高,这个功能只会越来越好用。等到下次像Sonnet3升级到Sonnet 3.5这样的更新再次出现时,Cursor必然会更加强大。当然,类似的功能并非只有Cursor拥有,Aider也提供了相似的功能,是否还有更多类似工具我就没有深入了解了。

    总而言之,作为VSCode上的一个”扩展”,Cursor完全有能力替代VSCode。不过Cursor的价格是Copilot的两倍,我目前不会选择订阅。它的体验并没有比Copilot好一倍。像自动补全、Chat、Apply以及Codebase的自动上下文等功能,Copilot都做得很好。仅凭多次Tab和一个尚不完善的Composer功能,不值得我多花一倍的钱。

    ❌