<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Xieisabug</title>
	<atom:link href="https://www.xiejingyang.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.xiejingyang.com</link>
	<description></description>
	<lastBuildDate>Thu, 08 Jan 2026 07:35:59 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.xiejingyang.com/wp-content/uploads/2024/09/cropped-xie-logo-32x32.webp</url>
	<title>Xieisabug</title>
	<link>https://www.xiejingyang.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>用js写卡牌游戏（十）</title>
		<link>https://www.xiejingyang.com/2026/01/06/%e7%94%a8js%e5%86%99%e5%8d%a1%e7%89%8c%e6%b8%b8%e6%88%8f%ef%bc%88%e5%8d%81%ef%bc%89/</link>
					<comments>https://www.xiejingyang.com/2026/01/06/%e7%94%a8js%e5%86%99%e5%8d%a1%e7%89%8c%e6%b8%b8%e6%88%8f%ef%bc%88%e5%8d%81%ef%bc%89/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 09:06:55 +0000</pubDate>
				<category><![CDATA[前端]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[卡牌游戏]]></category>
		<category><![CDATA[游戏]]></category>
		<category><![CDATA[游戏开发]]></category>
		<category><![CDATA[炉石传说]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1499</guid>

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



<h1 class="wp-block-heading">关于GAS</h1>



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



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="768" src="https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1024x768.jpg" alt="" class="wp-image-1500" srcset="https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1024x768.jpg 1024w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-300x225.jpg 300w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-768x576.jpg 768w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1536x1152.jpg 1536w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-2048x1536.jpg 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



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



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="768" src="https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1-1024x768.jpg" alt="" class="wp-image-1501" srcset="https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1-1024x768.jpg 1024w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1-300x225.jpg 300w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1-768x576.jpg 768w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1-1536x1152.jpg 1536w, https://www.xiejingyang.com/wp-content/uploads/2026/01/生成带有标签的衣服图片-1-2048x1536.jpg 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



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



<ol class="wp-block-list">
<li>添加 “不可折叠” Tag、添加 “可展开” Tag</li>



<li>改变面积为原来的四分之一</li>
</ol>



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



<p>在这些内容里，你可以看到命令模式、策略模式、状态模式等等经典设计模式的影子，他将开发的“复利”效应做到了极致，POE就是这样设计的，同样你可以<a href="https://developer.valvesoftware.com/wiki/Zh/Dota_2_Workshop_Tools/Scripting/Abilities_Data_Driven">在Dota2里也看到这样的设计</a>：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 这是一个非常简单的技能，他是一个被动技能，给单位添加了一个粒子特效。
"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"
                }
            }
        }
    }
}</pre>



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



<h1 class="wp-block-heading">我的设计</h1>



<p>我的卡牌过去是这样实现的：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
    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)
        }
    }
}</pre>



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



<p>所以想要做到像POE、Dota2那样进行配置，理想的情况下卡牌应该是这样的：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
    "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"
                        }
                    }
                ]
            }
        ]
    }
}</pre>



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



<p>所以设计任务： 1. 原来的各种属性抽象为Tag。 2. 原来的各种钩子的效果整理好，抽象为各种 Effect。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
    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)
        }
    }
}</pre>



<p>按照 Effect 的设想：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
    "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"
                    }
                }
            ]
        }
    ]
}</pre>



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



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="798" data-id="1517" src="https://www.xiejingyang.com/wp-content/uploads/2026/01/Pasted-image-20260108152610-1024x798.png" alt="" class="wp-image-1517" srcset="https://www.xiejingyang.com/wp-content/uploads/2026/01/Pasted-image-20260108152610-1024x798.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2026/01/Pasted-image-20260108152610-300x234.png 300w, https://www.xiejingyang.com/wp-content/uploads/2026/01/Pasted-image-20260108152610-768x598.png 768w, https://www.xiejingyang.com/wp-content/uploads/2026/01/Pasted-image-20260108152610.png 1386w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</figure>



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



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



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 示意伪代码
function outCard() {
    // ...
    triggerCardEffect(card, 'onStart', baseContext);
    // ...
}</pre>



<p>triggerCardEffect 内部简单来看可以这样设计：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 示意伪代码
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);
    });
}</pre>



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



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 示意伪代码
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);
        });
    }
}</pre>



<p>所有的 Effect 就只需要实现预定义的各种函数，然后注册起来：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">/**
 * 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;</pre>



<p>不过，都到了2026年了，我就不分享具体的代码实现过程了，我分享点别的。</p>



<h1 class="wp-block-heading">实现过程</h1>



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



<p>第一条prompt，先用Plan模式让AI做好计划：</p>



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



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



<p>AI的计划大概如下（肯定都会有不同，但没事）：</p>



<div class="wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-6c531013 wp-block-group-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767680558505-1024x617.png" alt="" class="wp-image-1503" srcset="https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767680558505-1024x617.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767680558505-300x181.png 300w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767680558505-768x463.png 768w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767680558505.png 1168w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>



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



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



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



<h3 class="wp-block-heading">卡牌数据没有完全迁移到新结构</h3>



<p>有可能会出现 cards.js 还是有很多遗留数据，或者甚至就完全没有迁移，所以：</p>



<pre class="wp-block-code"><code>现在的卡牌已经转为使用 effect tag 来进行配置了，但是卡牌的数据 cards.js 还是使用的函数。 请把这些卡牌数据转为使用effect和tag，因为这里的数据过大，请分批次转为多个json（按照卡牌职业分类）。</code></pre>



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



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="210" src="https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767681027249-1024x210.png" alt="" class="wp-image-1504" srcset="https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767681027249-1024x210.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767681027249-300x62.png 300w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767681027249-768x158.png 768w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767681027249.png 1130w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">文件命名不规范</h3>



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



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



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



<h3 class="wp-block-heading">偷懒不实现缺失的Effect</h3>



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



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">/**
 * 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}`);
        }
    }
}</pre>



<pre class="wp-block-code"><code>LegacyHookEffect 是偷懒的行为，把这些函数定义改为effect配置就是不希望再有使用函数配置的卡牌了。  
如果当前的effect设计不足以做到把所有卡牌都改为可配置effect的json表达，请告诉我哪里需要修改。如果当前的effect不足，需要新增，请告诉我要增加哪些。</code></pre>



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



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="973" src="https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767682472482-1024x973.png" alt="" class="wp-image-1513" srcset="https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767682472482-1024x973.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767682472482-300x285.png 300w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767682472482-768x730.png 768w, https://www.xiejingyang.com/wp-content/uploads/2026/01/QQ_1767682472482.png 1456w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">isStrong 等属性没有真正的用 Tag 来重构</h3>



<p>Review代码的时候发现，AI并没有理解 Tag 这种设计（不过我们也没说），改的不够彻底，所以：</p>



<pre class="wp-block-code"><code>现在代码里的模仿GAS的tag系统似乎没有真正用起来，现在的tag是用ApplyTag这个Effect来模拟之前的属性做法，给卡牌加上 isStrong 这样的属性，我希望你能彻底修改为tag的做法，只需要判断卡牌的tag是否有 Status.Buff.Strong，而不需要再转回原来的属性模式，所以原来的属性模式相关的逻辑也要改为GAS的tag模式。</code></pre>



<pre class="wp-block-code"><code>那这样的话，是否 cardType 其实也不需要了，直接用 tag 来实现就可以了。</code></pre>



<p>这样AI会把过去的属性移除，然后用新的Tag来重构，过去判断 isStrong 的地方，都变成 hasTag(card, &#8220;Status.Buff.Strong&#8221;)。</p>



<h1 class="wp-block-heading">其他内容</h1>



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



<h1 class="wp-block-heading">AI</h1>



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



<h1 class="wp-block-heading">下一步</h1>



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2026/01/06/%e7%94%a8js%e5%86%99%e5%8d%a1%e7%89%8c%e6%b8%b8%e6%88%8f%ef%bc%88%e5%8d%81%ef%bc%89/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>2025.12 AI使用有感</title>
		<link>https://www.xiejingyang.com/2025/12/21/2025-12-ai%e4%bd%bf%e7%94%a8%e6%9c%89%e6%84%9f/</link>
					<comments>https://www.xiejingyang.com/2025/12/21/2025-12-ai%e4%bd%bf%e7%94%a8%e6%9c%89%e6%84%9f/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Sun, 21 Dec 2025 06:29:40 +0000</pubDate>
				<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1494</guid>

					<description><![CDATA[不知道是不是因为AI真的陷入了瓶颈，现在的模型很少出现完美的，每个模型总是有一定的缺陷，这也就导致了 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>不知道是不是因为AI真的陷入了瓶颈，现在的模型很少出现完美的，每个模型总是有一定的缺陷，这也就导致了用AI需要一些技巧，这些技巧让AI带来的智力平权又拉开了一点距离。</p>



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



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



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



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



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/12/21/2025-12-ai%e4%bd%bf%e7%94%a8%e6%9c%89%e6%84%9f/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How I AI Coding 2025.10</title>
		<link>https://www.xiejingyang.com/2025/10/26/how-i-ai-coding-2025-10/</link>
					<comments>https://www.xiejingyang.com/2025/10/26/how-i-ai-coding-2025-10/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Sun, 26 Oct 2025 08:23:26 +0000</pubDate>
				<category><![CDATA[随笔]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1475</guid>

					<description><![CDATA[因为看到了Xuanwo大佬的文章，所以我也来写一下我是怎么用AI来开发的。 工具 VSCode In [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>因为看到了<a href="https://x.com/OnlyXuanwo">Xuanwo大佬</a>的<a href="https://mp.weixin.qq.com/s/L6wfyIhRisZR19OUKLishA">文章</a>，所以我也来写一下我是怎么用AI来开发的。</p>



<h1 class="wp-block-heading">工具</h1>



<p><strong>VSCode Insider with Copilot，Codex，Claude Code，Kagi，AIPP</strong><br>现在日常用的就是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使用，这点让我很安心）</p>



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



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



<p><a href="https://github.com/xieisabug/AIPP">AIPP</a>是我自己写的开源ChatApp，别的ChatApp各有优势但也总有槽点，所以做一个符合自己使用习惯的，我在中转和国内的厂商（Kimi、GLM、Deepseek）都有充值，用API来对一些问题提问。现在也只是刚把功能做好，还有很多Bug，不过我自己足够熟悉更新迭代的也会很快。</p>



<h1 class="wp-block-heading">MCP</h1>



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



<h1 class="wp-block-heading">感想</h1>



<p>Xuanwo大佬提的感想大部分我都赞同，我说一些我自己的别的感想：</p>



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



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



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



<ol class="wp-block-list"></ol>



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



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/10/26/how-i-ai-coding-2025-10/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>2025阅读清单</title>
		<link>https://www.xiejingyang.com/2025/08/24/2025%e9%98%85%e8%af%bb%e6%b8%85%e5%8d%95/</link>
					<comments>https://www.xiejingyang.com/2025/08/24/2025%e9%98%85%e8%af%bb%e6%b8%85%e5%8d%95/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Sun, 24 Aug 2025 13:20:03 +0000</pubDate>
				<category><![CDATA[阅读]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1452</guid>

					<description><![CDATA[上次1月中旬写，这次直接8月写，服了我自己了。 1.地煞七十二变图鉴 ★★★★★ 很少看志异的小说， [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>上次1月中旬写，这次直接8月写，服了我自己了。</p>



<h2 class="wp-block-heading" id="1-人性的弱点">1.地煞七十二变图鉴</h2>



<p>★★★★★</p>



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



<h2 class="wp-block-heading">2.我看见的世界：李飞飞自传</h2>



<p>★★★★</p>



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



<h2 class="wp-block-heading">3.第七重解答</h2>



<p>★★★★</p>



<p>反转挺多的，有时候觉得这什么啊？我一下就猜出来了；有时候觉得卧槽？还能这么反转？</p>



<h2 class="wp-block-heading">4.小说写作：叙事技巧指南（第十版）</h2>



<p>★★★</p>



<p>想写小说，听书听完的，收获有但是不多。</p>



<h2 class="wp-block-heading">5.美国创新简史：科技如何主推经济增长</h2>



<p>★★★★</p>



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/08/24/2025%e9%98%85%e8%af%bb%e6%b8%85%e5%8d%95/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>2025游戏清单</title>
		<link>https://www.xiejingyang.com/2025/08/24/2025-game-list/</link>
					<comments>https://www.xiejingyang.com/2025/08/24/2025-game-list/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Sun, 24 Aug 2025 10:29:01 +0000</pubDate>
				<category><![CDATA[随笔]]></category>
		<category><![CDATA[日常]]></category>
		<category><![CDATA[游戏]]></category>
		<category><![CDATA[生活]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1448</guid>

					<description><![CDATA[暗黑4 进度：不会再玩了，除非超级大更新 评分：6/10 评价：比暗黑3都不如 POE 2 进度：没 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">暗黑4</h2>



<p>进度：不会再玩了，除非超级大更新</p>



<p>评分：6/10</p>



<p>评价：比暗黑3都不如</p>



<h2 class="wp-block-heading">POE 2</h2>



<p>进度：没事刷刷</p>



<p>评分：8/10</p>



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



<h2 class="wp-block-heading">Monster Train 2</h2>



<p>进度：浅玩几轮</p>



<p>评分：6/10</p>



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



<h2 class="wp-block-heading">马里奥赛车世界</h2>



<p>进度：每日进行中</p>



<p>评分：8/10</p>



<p>评价：我倒是只有那么喜欢玩，但是我3岁的儿子每天都要在里面跑。</p>



<h2 class="wp-block-heading">咚奇刚：蕉力全开</h2>



<p>进度：每日进行中</p>



<p>评分：9/10</p>



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



<h2 class="wp-block-heading">元炁 Demo</h2>



<p>进度：八九不离十</p>



<p>评分：5/10</p>



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



<h2 class="wp-block-heading">逃离鸭科夫</h2>



<p>进度：第一张地图打完</p>



<p>评分：7/10</p>



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



<h2 class="wp-block-heading">三国望神州</h2>



<p>进度：每日进行中</p>



<p>评分：7/10</p>



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



<h2 class="wp-block-heading">燕云十六声</h2>



<p>进度：弃坑</p>



<p>评分：7/10</p>



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



<h2 class="wp-block-heading">POE 2：最后的德鲁伊</h2>



<p>进度：刷</p>



<p>评分：10/10</p>



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/08/24/2025-game-list/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>日常-阅读 How we built our multi-agent research system</title>
		<link>https://www.xiejingyang.com/2025/06/17/read-how-we-built-our-multi-agent-research-system/</link>
					<comments>https://www.xiejingyang.com/2025/06/17/read-how-we-built-our-multi-agent-research-system/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Tue, 17 Jun 2025 07:11:57 +0000</pubDate>
				<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[日常]]></category>
		<category><![CDATA[阅读]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1434</guid>

					<description><![CDATA[今天抽空阅读了 Anthropic 的 How we built our multi-agent r [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>今天抽空阅读了 Anthropic 的 <a href="https://www.anthropic.com/engineering/built-multi-agent-research-system">How we built our multi-agent research system</a>，其中有不少过去就已经了解熟知的知识，也提到了不少能够激发我思考的点，来总结总结。<br>首先先说说之前就了解的：</p>



<ol class="wp-block-list">
<li>一个非常聪明的规划者。Anthropic 用的自然是 Opus，规划任务、决策都是 Opus 来做的，越聪明的 AI 做规划者越能提高执行者的效率和效果，目前第一梯队的规划者只有 3 个，Anthropic 4-Opus、OpenAI O3、Gemini-2.5-Pro，排名有先后。</li>



<li>执行者的能力不能太低。Anthropic 的执行者使用的是 Sonnet，而不是 Haiku，执行者要能正确的使用工具，正确的遵循格式来输出，并且最重要的是能够理解任务的要点。</li>



<li>使用记忆。PreAct 的要点就是提前计划并且生成 TODO，需要记住 TODO 完成的状态；在每轮迭代任务的过程中，都会产生新的结果，都需要进行记录；长时间执行的任务，会产生巨长无比的上下文，通常经过总结后也需要保存到记忆中。文章中配了两张图都提到了 Memory 可以看出它的重要。 之所以不把记忆归类到工具，是因为记忆可以算作一个基础设施，是必须要使用的，而工具是根据任务的不同可以选择用或者不用。</li>



<li>使用工具。给予丰富的工具才能让 Agent 的智能发挥作用，最近看的最典型的例子就是，ChatGPT 网页上的 O3 在工具加持下能够通过非常普通的照片定位到照片拍摄位置。过去我倾向于看模型的 Aider 评分来看模型的能力，因为这个评测集通常反应了模型编写代码和指令遵循的能力，但发展到现在的阶段，Aider 的评分已经无法反应出模型真正解决问题的能力，现在我更喜欢看模型的 SWE-bench Verified 评分，这是一个经过筛选的现实问题集，考验模型使用各种工具来解决现实问题的能力，不过通常强的模型这两者的分数都不会低。</li>
</ol>



<p>再来谈谈新的收获：</p>



<ol class="wp-block-list">
<li>巨量的 Token 消耗。Anthropic 提到 Multi Agent 是普通聊天的 15 倍 Token 消耗，所以应该让 Multi Agent 作用在能产生高价值的地方，而不是普通的任务。我之前有想过为什么 AI IDE 不搞一个这种 Multi Agent 模式，能够又聪明又快速的完成任务，从这篇文章中可以一窥原因，现在的 AI IDE 不约而同的让自己的工具在尽量少的 Token 消耗的情况下来解决问题，但基本都是事与愿违，有时候看着 AI 50 行 50 行代码的 read，真的哭笑不得。想必这就是 AI 提供商巨头的护城河，他们的 Token 基本上是 Free 的，通过烧 Token 来提高效果这是一般的应用公司没法做到的。</li>



<li>Agent 调试。之前从没有想过来做一个工具像断点代码一样调试 Agent，Anthropic 做了一个工具，能够逐步的观看 Agent 如何进行处理，这使得在 Agent 优化的过程中能够直观的、不停的 减少 不必要的工具调用、生成冗长的搜索词等。这也让我想到了可以把 传统编程中的很多调试方法都带到 AI 应用开发，除了断点，还有像日志（做个 MCP 来让 AI 自动输出日志到指定的地方）、Mock（假设模型的前置返回或者 MCP 的返回来进行测试调试）等等，对于 AI 这种黑盒开发有不小的帮助。</li>



<li>智能体自我进化。像 Cursor 中的 Agent 自动调用测试获取报错信息或者是获取 Lint 报错一样，如果任务执行的不好，Anthropic 会让 Sonnet 自己来修改提示词再次进行尝试，直到获取到更好的结果。甚至当提供的 MCP 工具有问题时，Sonnet 会去修复这个工具然后继续。之前看信息流里有 OpenAI 的老哥说 O3 的降价也来自于 Codex 对系统的自我进化开发。这相当于强化学习训练出来的 AI 来用强化学习的方法来训练一个应用？</li>



<li>并行处理。不光是把任务分解后多个 Agent 同时去完成所有的任务，还有 Agent 同时调用多个工具来解决一个任务。这个想法其实我之前也想到了，并且在一个 Side Project 中也实践过了，效果非常好，这个 Project 是一个小说编辑器，在对小说进行润色的过程中，会让规划者先标记出来哪些句子需要润色，再让多个执行者并行的对每个句子来进行润色。原来这个任务在润色一篇 3000 字的文章时，起码要等待 40 秒（使用的是 gemini 2.5 pro），使用了这种方式之后，大约 10 秒内就能看到结果了。</li>



<li>提示词优化。Anthropic 提到一个微小的提示词修改，使得任务成功率从 30% 提高到 80%，这让我想到之前听的播客中的一个观念：如果我修改16 次提示词最终完成了比较难的问题，那么这个过程中，到底是我太菜了还是 AI 太菜了？Anthropic 很大方的开源了自己的提示词，可以去 <a href="https://github.com/anthropics/anthropic-cookbook/tree/main/patterns/agents/prompts">Anthropic 的仓库</a>里看看。</li>



<li>工程化。Anthropic 提到了很多工程化的问题，包含了 恢复状态、容错、可调试可观测可测试、部署更新、执行与并发 等各种挑战，这也是每个做 AI 应用的开发者都可能会碰到的问题，所以 AI 应用并不是写个提示词那么简单，涉及到的编码和传统软件工程的知识都非常多。在目前，至少是 2025 年 6 月这个节点，根本不可能有真的0编程知识的人能够使用 AI 开发上线运营一个应用。</li>
</ol>



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/06/17/read-how-we-built-our-multi-agent-research-system/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>LLM-大模型价格榜</title>
		<link>https://www.xiejingyang.com/2025/06/03/llm-%e5%a4%a7%e6%a8%a1%e5%9e%8b%e4%bb%b7%e6%a0%bc%e6%a6%9c/</link>
					<comments>https://www.xiejingyang.com/2025/06/03/llm-%e5%a4%a7%e6%a8%a1%e5%9e%8b%e4%bb%b7%e6%a0%bc%e6%a6%9c/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Tue, 03 Jun 2025 14:08:11 +0000</pubDate>
				<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[价格]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1430</guid>

					<description><![CDATA[之前一直在看的大模型价格榜在去年停止更新了，导致我有时候做产品的时候或者偶尔要查大模型价格的时候特别 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>之前一直在看的大模型价格榜在去年停止更新了，导致我有时候做产品的时候或者偶尔要查大模型价格的时候特别不方便，所以我自己 vibe 了一个：</p>



<p><a href="https://llm-price.xiejingyang.com/">https://llm-price.xiejingyang.com/</a></p>



<p>数据来自 litellm 的 <a href="https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json">模型价格定义json</a> 和 deepresearch + 手动整理，我会尽力保持更新功能和维护数据的。如果数据有问题，也请给我留言或者联系我。</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/06/03/llm-%e5%a4%a7%e6%a8%a1%e5%9e%8b%e4%bb%b7%e6%a0%bc%e6%a6%9c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>数据结构-Merkle Trees</title>
		<link>https://www.xiejingyang.com/2025/05/12/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84-merkle-trees/</link>
					<comments>https://www.xiejingyang.com/2025/05/12/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84-merkle-trees/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Mon, 12 May 2025 06:40:24 +0000</pubDate>
				<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[数据结构]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1423</guid>

					<description><![CDATA[从 https://simonwillison.net/2025/May/11/cursor-sec [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>从 https://simonwillison.net/2025/May/11/cursor-security/#atom-everything 看到的文章看到的<a href="https://read.engineerscodex.com/p/how-cursor-indexes-codebases-fast">相关文章</a>了解到的。</p>



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



<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Merkle Tree Demo</title>
    <style>
        body {
            font-family: sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            background-color: #f4f4f4;
        }

        h1, h2 {
            color: #333;
        }

        .tree-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-top: 30px;
            width: 100%;
            max-width: 800px; /* Limit max width */
        }

        .level {
            display: flex;
            justify-content: center;
            margin-bottom: 20px;
            width: 100%;
        }

        .node {
            background-color: #fff;
            border: 1px solid #ccc;
            padding: 10px 15px;
            margin: 0 5px;
            text-align: center;
            border-radius: 5px;
            word-break: break-all; /* Prevent long hashes from overflowing */
            box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
            transition: background-color 0.3s ease;
            min-width: 100px; /* Ensure some minimum width */
            flex-grow: 1; /* Allow nodes to grow */
            flex-basis: 0; /* Distribute space evenly */
        }

        .node label {
             display: block;
             margin-bottom: 5px;
             font-weight: bold;
             color: #555;
             font-size: 0.9em;
        }

        .node input[type="text"] {
            width: calc(100% - 12px); /* Adjust for padding/border */
            padding: 5px;
            border: 1px solid #ccc;
            border-radius: 3px;
            box-sizing: border-box; /* Include padding and border in element's total width */
            font-size: 0.9em;
        }

        .node .hash {
            font-family: 'Courier New', Courier, monospace;
            color: #007bff;
            font-size: 0.8em;
            margin-top: 5px;
        }

         /* Different colors for different levels */
        .level:last-child .node { background-color: #d4edda; border-color: #c3e6cb; color: #155724; } /* Root */
        .level:nth-last-child(2) .node { background-color: #fff3cd; border-color: #ffeeba; color: #856404; } /* Level 1 */
        .level:nth-last-child(3) .node { background-color: #d1ecf1; border-color: #bee5eb; color: #0c5460; } /* Level 0 (Leaf Parents) */
        /* Leaf level color handled explicitly in JS */


        .leaf-level .node {
             background-color: #f8d7da;
             border-color: #f5c6cb;
             color: #721c24;
             display: flex;
             flex-direction: column;
             align-items: center;
        }

         .leaf-level .node .hash {
             color: #721c24; /* Match text color */
             margin-top: 5px;
             font-size: 0.8em;
         }


        /* Lines (more complex for dynamic tree, simplified visual stacking here) */
        /* Could add lines using pseudo-elements or SVG/Canvas for true visual tree */

        #explanation {
            margin-top: 20px;
            padding: 15px;
            background-color: #e9ecef;
            border-left: 5px solid #007bff;
            max-width: 800px;
            color: #333;
        }
        #explanation h3 { margin-top: 0; }
        #explanation p { margin-bottom: 5px; }

    </style>
</head>
<body>

    <h1>Merkle Tree 默克尔树演示</h1>
    <p>修改下方的数据，观察上面的哈希值如何变化，尤其是最顶部的默克尔根。</p>

    <div class="tree-container">
        <!-- Tree levels will be generated here by JavaScript -->
        <!-- Example structure (reversed for visual clarity - root at top):
        <div class="level merkle-root-level">
            <div class="node"><label>Merkle Root:</label><div class="hash">...</div></div>
        </div>
        <div class="level level-1">
             <div class="node"><label>Hash(H12 + H34):</label><div class="hash">H1234</div></div>
             <div class="node"><label>Hash(H56 + H78):</label><div class="hash">H5678</div></div>
        </div>
         <div class="level level-0">
             <div class="node"><label>Hash(H1 + H2):</label><div class="hash">H12</div></div>
             <div class="node"><label>Hash(H3 + H4):</label><div class="hash">H34</div></div>
             <div class="node"><label>Hash(H5 + H6):</label><div class="hash">H56</div></div>
             <div class="node"><label>Hash(H7 + H8):</label><div class="hash">H78</div></div>
        </div>
        <div class="level leaf-level">
            <div class="node"><label>Data Block 1:</label><input type="text" value="Data A"><div class="hash">H1</div></div>
            <div class="node"><label>Data Block 2:</label><input type="text" value="Data B"><div class="hash">H2</div></div>
            <div class="node"><label>Data Block 3:</label><input type="text" value="Data C"><div class="hash">H3</div></div>
            <div class="node"><label>Data Block 4:</label><input type="text" value="Data D"><div class="hash">H4</div></div>
        </div>
        -->
    </div>

    <div id="explanation">
        <h3>默克尔树工作原理简介</h3>
        <p>1. **叶子节点:** 底部是原始数据块（你可以修改它们）。</p>
        <p>2. **哈希计算:** 每个数据块首先计算出自己的哈希值（显示在输入框下方）。</p>
        <p>3. **层层向上:** 相邻的哈希值被组合（串联），然后计算新的哈希值，形成上一层的节点。</p>
        <p>4. **默克尔根:** 这个过程重复进行，直到最顶端只剩下一个哈希值，这就是默克尔根。</p>
        <p>5. **验证:** 默克尔根是整个数据集的&#8221;指纹&#8221;。如果任何一个数据块或其顺序改变，默克尔根都会完全不同。这使得只通过默克尔根就能快速验证数据的完整性，而无需检查所有数据。</p>
        <p>6. **应用:** 区块链（如比特币、以太坊）、点对点下载（如 BitTorrent）等都广泛使用默克尔树来高效地验证数据的完整性。</p>
    </div>


    <script>
        // --- Hashing Function ---
        // Using the Web Crypto API (requires secure context - HTTPS, localhost)
        // Fallback/Simpler demo might use a library like crypto-js or a simpler non-cryptographic hash
        // For this demo, we'll use SHA-256 via Web Crypto API (async)

        async function sha256(message) {
            // encode as UTF-8
            const msgBuffer = new TextEncoder().encode(message);

            // hash the message
            const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);

            // convert ArrayBuffer to Array
            const hashArray = Array.from(new Uint8Array(hashBuffer));

            // convert bytes to hex string
            const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
            return hashHex;
        }

        // --- Merkle Tree Building Function ---
        async function buildMerkleTree(dataBlocks) {
            if (dataBlocks.length === 0) {
                return { root: null, levels: [] };
            }

            let currentLevel = [];
            const levels = []; // Store hashes at each level

            // 1. Compute Leaf Hashes
            const leafHashes = await Promise.all(dataBlocks.map(block => sha256(block)));
            currentLevel = leafHashes;
            levels.push(currentLevel); // levels[0] = leaf hashes

            // 2. Build Tree Levels upwards
            while (currentLevel.length > 1) {
                const nextLevel = [];
                for (let i = 0; i < currentLevel.length; i += 2) {
                    const left = currentLevel[i];
                    // Handle odd number of nodes: duplicate the last hash
                    const right = (i + 1 < currentLevel.length) ? currentLevel[i + 1] : left;

                    // Standard Merkle Tree pairing: hash(left_hash + right_hash)
                    const parentHash = await sha256(left + right);
                    nextLevel.push(parentHash);
                }
                currentLevel = nextLevel;
                levels.push(currentLevel); // levels[1] = level above leaves, etc.
            }

            const merkleRoot = currentLevel[0];
            return { root: merkleRoot, levels: levels };
        }

        // --- Display Function ---
        function renderTree(levels, dataBlocks) {
            const container = document.querySelector('.tree-container');
            container.innerHTML = ''; // Clear previous tree

            // Levels are stored bottom-up in the array (levels[0] is leaf hashes)
            // We want to render top-down visually

            // Render Root (top level)
            const rootLevelDiv = document.createElement('div');
            rootLevelDiv.classList.add('level', 'merkle-root-level');
            const rootNodeDiv = document.createElement('div');
            rootNodeDiv.classList.add('node');
            rootNodeDiv.innerHTML = `<label>Merkle Root:</label><div class="hash">${levels[levels.length - 1][0]}</div>`;
            rootLevelDiv.appendChild(rootNodeDiv);
            container.appendChild(rootLevelDiv);


            // Render intermediate levels (top-down, excluding root and leaves)
            for (let i = levels.length - 2; i > 0; i--) {
                 const levelDiv = document.createElement('div');
                 levelDiv.classList.add('level', `level-${i-1}`); // level-0 above leaves, level-1 etc.
                 levels[i].forEach(hash => {
                     const nodeDiv = document.createElement('div');
                     nodeDiv.classList.add('node');
                      // Give generic labels for intermediate nodes
                     nodeDiv.innerHTML = `<label>Hash:</label><div class="hash">${hash}</div>`;
                     levelDiv.appendChild(nodeDiv);
                 });
                 container.appendChild(levelDiv);
            }


            // Render Leaf Level (bottom level)
            const leafLevelDiv = document.createElement('div');
            leafLevelDiv.classList.add('level', 'leaf-level');
            dataBlocks.forEach((data, index) => {
                const nodeDiv = document.createElement('div');
                nodeDiv.classList.add('node');
                // Assuming levels[0] contains the leaf hashes in order
                const leafHash = levels[0] && levels[0][index] ? levels[0][index] : 'Error';
                nodeDiv.innerHTML = `
                    <label>数据块 ${index + 1}:</label>
                    <input type="text" value="${data}" data-index="${index}">
                    <div class="hash">${leafHash}</div>
                `;
                leafLevelDiv.appendChild(nodeDiv);
            });
            container.appendChild(leafLevelDiv);

             // Add event listeners to new input fields
            attachInputListeners();
        }

        // --- Handle Input Changes ---
        const initialData = ["数据 A", "数据 B", "数据 C", "数据 D"]; // Starting data blocks
        let currentData = [...initialData]; // Use a copy

        async function updateTree() {
             const { root, levels } = await buildMerkleTree(currentData);
             renderTree(levels, currentData);
             console.log("Merkle Root:", root);
             // Merkle root is already displayed by renderTree
        }

        function attachInputListeners() {
             document.querySelectorAll('.leaf-level input[type="text"]').forEach(input => {
                 input.addEventListener('input', (event) => {
                     const index = parseInt(event.target.dataset.index, 10);
                     currentData[index] = event.target.value;
                     updateTree(); // Recalculate and re-render the tree
                 });
             });
        }


        // --- Initial Load ---
        // Use a small delay to ensure DOM is ready, though async functions help
        document.addEventListener('DOMContentLoaded', () => {
            updateTree(); // Build and render the tree on page load
        });


    </script>

</body>
</html>



<p>当修改数据块中的文字，会让对应的树分支上的 hash 修改，一直向上延伸到 root，通过 hash 的对比快速的就能够获取到整个变动的分支。</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/05/12/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84-merkle-trees/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>LLM-大模型绘制流程图</title>
		<link>https://www.xiejingyang.com/2025/03/25/llm-flowchart-drawn-by-llm/</link>
					<comments>https://www.xiejingyang.com/2025/03/25/llm-flowchart-drawn-by-llm/#comments</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Tue, 25 Mar 2025 09:39:04 +0000</pubDate>
				<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<category><![CDATA[流程图]]></category>
		<category><![CDATA[绘图]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1415</guid>

					<description><![CDATA[过去在读代码的时候或者是学习的时候，经常让大模型给我画流程图，一直是用的 mermaid 的方式来绘 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>过去在读代码的时候或者是学习的时候，经常让大模型给我画流程图，一直是用的 mermaid 的方式来绘制，使用这种方法的好处就是大模型基本上都会，因为 mermaid 算是非常有名的 markdown 中展示流程图的方案了。</p>



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



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="440" src="https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895201553-1024x440.png" alt="" class="wp-image-1416" srcset="https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895201553-1024x440.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895201553-300x129.png 300w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895201553-768x330.png 768w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895201553-1536x660.png 1536w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895201553-2048x880.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>存为文件在 drawio 打开的效果如下：</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="803" src="https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895287033-1024x803.png" alt="" class="wp-image-1417" srcset="https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895287033-1024x803.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895287033-300x235.png 300w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895287033-768x602.png 768w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895287033-1536x1205.png 1536w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895287033.png 1586w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>如果使用 mermaid 是这样的：</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="288" src="https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895324503-1024x288.png" alt="" class="wp-image-1418" srcset="https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895324503-1024x288.png 1024w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895324503-300x84.png 300w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895324503-768x216.png 768w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895324503-1536x431.png 1536w, https://www.xiejingyang.com/wp-content/uploads/2025/03/QQ_1742895324503-2048x575.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>网友是在<a href="https://www.xiaohongshu.com/discovery/item/67c70e220000000029008889" data-type="link" data-id="https://www.xiaohongshu.com/discovery/item/67c70e220000000029008889">小红书</a>中看到的，但目前好像被删除了看不到了，我这边贴一下我从小红书中拿到的提示词：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">你是一个卓越的绘图高手，你需要根据用户的需求来进行绘图。
**核心能力:**
1.  根据视觉描述/需求直接生成可运行的draw.io代码
2.  校验机制保证代码准确性
3.  输出标准化代码块

**处理流程:**
① 接收输入→ ②要素解析→ ③结构建模→ ④语法生成→ ⑤完整性校验→ ⑥输出结果

**输出规范:**
```xml
&lt;!-- 经过校验的draw.io代码 -->
&lt;mxfile>
    [生成的核心代码]
&lt;/mxfile>
...
```

**交互规则:**
- 收到图片描述时: "正在解析结构关系(进行描述图片细节)----(校验通过)"
- 收到创建需求时: "建议采用[布局类型], 包含[元素数量]个节点，是否确认？"
- 异常处理: "第X层节点存在连接缺失，已自动补全"

**优势特性:**
- 元素定位精度: ±5px等效坐标
- 支持自动布局优化 (可禁用)
- 内置语法修正器 (容错率&lt;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&lt;sup>v&lt;/sup>和h&lt;sub>inter&lt;/sub> 不要使用latex格式
• 公式可以根据条件更换字体
• 数学符号如点乘必须使用正确格式: 应写为&amp;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

</pre>



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



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



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



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/03/25/llm-flowchart-drawn-by-llm/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>产品职业随想</title>
		<link>https://www.xiejingyang.com/2025/03/24/random-thoughts-on-product-related-careers/</link>
					<comments>https://www.xiejingyang.com/2025/03/24/random-thoughts-on-product-related-careers/#respond</comments>
		
		<dc:creator><![CDATA[xiejingyang]]></dc:creator>
		<pubDate>Mon, 24 Mar 2025 05:58:08 +0000</pubDate>
				<category><![CDATA[Learn In Public]]></category>
		<category><![CDATA[日常]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[产品经理]]></category>
		<category><![CDATA[学习]]></category>
		<category><![CDATA[成长]]></category>
		<category><![CDATA[随想]]></category>
		<guid isPermaLink="false">https://www.xiejingyang.com/?p=1413</guid>

					<description><![CDATA[随着干产品这个职业的深入，发现这个职业对于聪明要求的上线真是无限高，最近这段时间的几个感触记录一下：]]></description>
										<content:encoded><![CDATA[
<p>随着干产品这个职业的深入，发现这个职业对于聪明要求的上线真是无限高，最近这段时间的几个感触记录一下：</p>



<ol class="wp-block-list">
<li>产品经理最好是有一定的增长能力，把增长能力转化为设计的功能点做到产品里，比如了解当前的主流叙事和“流量密码”，把这些东西快速的融入到产品中，方便增长。这一点大部分的老板都比较敏感，通常有“流量密码”出来的时候老板总是第一时间希望能够在产品中添加，以蹭到这波流量，但老板的产品设计能力较弱，通常容易出现非常突兀的融合。</li>



<li>能把握到科技的发展，尤其是在现在 AI 发展速度爆炸的现在，仅仅设计一款利用到现有科技力量的产品是远远不够的，要能设计出随着领先与科技发展的产品，随着科技发展而得到提高。最火的例子就是 Cursor 了，模型越来越强，让 Cursor 从不好用变成了神器。</li>



<li>要有一定的非共识，有非共识的产品才能脱颖而出，否则就是靠资源堆砌的普通产品，随时可以被以更多资源堆砌的另一个产品替代。</li>



<li>接着上面的非共识，我举个我自己领悟到的：免费用户（或者说弱用户）应该被作为产品的资源和能力，来融入产品的设计。著名的设计比如网游的氪金机制、排行榜机制等。</li>
</ol>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xiejingyang.com/2025/03/24/random-thoughts-on-product-related-careers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
