<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Hyacehila</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://hyacehila.github.io/</id>
  <link href="https://hyacehila.github.io/" rel="alternate"/>
  <link href="https://hyacehila.github.io/feed.xml" rel="self"/>
  <rights>All rights reserved 2026, Hyacehila</rights>
  <subtitle>Essays of a Boring Person</subtitle>
  <title>Hyacehila's Blog</title>
  <updated>2026-07-01T15:56:19.868Z</updated>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Essays" scheme="https://hyacehila.github.io/categories/essays/"/>
    <category term="Game Design" scheme="https://hyacehila.github.io/tags/Game-Design/"/>
    <category term="Classification" scheme="https://hyacehila.github.io/tags/Classification/"/>
    <category term="Game Genres" scheme="https://hyacehila.github.io/tags/Game-Genres/"/>
    <content>
      <![CDATA[<p>我最开始了解游戏类型时，脑子里其实是一张很朴素的表：ACT、RPG、AVG、SIM、SLG。像给文件夹命名。动作放动作里，角色扮演放 RPG 里，策略放策略里，看起来很省事。这也是我玩了这么多年形成的经验，但很快就卡住了。</p><p>《塞尔达传说：旷野之息》算动作冒险，当然没问题。可它又是开放世界、探索、解谜，甚至还有一点沙盒系统的味道。《原神》可以说是开放世界 ARPG，也可以说是角色养成和抽卡服务型游戏。《王者荣耀》是 MOBA，但移动端输入、短局节奏、社交关系也很重要。《明日方舟》更麻烦：塔防、策略、角色收集、关卡解谜、长期运营，少说一个都像漏了一块。</p><p>游戏类型不是那种能一次放准的文件夹。它更像我们聊天时用的速记。说“Roguelike”，别人会想到随机、死亡、重复尝试；说“MOBA”，别人会想到英雄、兵线、团队配合；说“休闲”，别人会先假设它容易上手、压力不大、适合短时间打开。</p><p>这些词不一定严谨，但很有用。问题是，如果只把它们当标签贴上去，又很容易偷懒。一个“RPG”到底是在说角色成长，还是在说剧情选择？一个“开放世界”是在说地图大，还是在说玩家真的能自由组织目标？一个“抽卡养成”是在说玩法，还是在说长期运营和商业结构？</p><p>所以这篇文章想做的事很简单：把这些类型名拆开看一遍。哪些是传统大类，哪些是融合类型，哪些其实是在描述平台、情绪、社交方式或商业模式。它不算词典，更像一份学习笔记。以后再说一款游戏是什么类型时，至少能知道自己到底在强调哪一层。</p><h2 id="游戏类型为什么很难分干净"><a href="#游戏类型为什么很难分干净" class="headerlink" title="游戏类型为什么很难分干净"></a>游戏类型为什么很难分干净</h2><p>传统分类当然有价值。动作游戏下面可以分射击、格斗、平台动作；RPG 下面可以分 JRPG、CRPG、ARPG、MMORPG；策略下面可以分 RTS、SLG、4X、塔防。它清楚，适合入门，也方便记忆。</p><p>问题是现代游戏经常不是从一根树枝长出来的。</p><p>机制会互相借。FPS 的第一人称视角和移动操作可以用来射击，也可以用来解谜，于是有《Portal》。RPG 的角色成长可以服务回合制战斗，也可以服务即时动作，于是有 ARPG。策略游戏的地图控制和资源争夺可以和单英雄操作结合，于是有 MOBA。</p><p>平台也会改变类型。键盘鼠标适合复杂快捷键和信息密度，所以 PC 上长期适合策略、模拟、管理和硬核射击。手柄适合角色移动、动作战斗和竞速。触屏适合点击、拖拽、短循环和碎片时间。体感、VR、方向盘、飞行摇杆、节奏控制器又会把一些体验推到新的方向。</p><p>玩家技能也不是单一的。动作游戏看反应和时机，策略游戏看规划和资源，解谜游戏看规则理解，模拟游戏看系统理解，RPG 看角色构筑和长期成长。很多游戏会故意把这些技能叠在一起。</p><p>还有一件事常被忽略：类型会从玩家社区里长出来。Roguelike 来自《Rogue》，Soulslike 来自《黑暗之魂》系列，Metroidvania 来自《银河战士》和《恶魔城》的传统。MOBA 和 RTS 自定义地图关系很深，Battle Royale 的现代形态也和 Mod、军事模拟、生存玩法有关。类型不是只从设计文档里发明出来的，它也会被玩家先玩出来，再被市场和社区命名。</p><p>因此，与其问“一款游戏到底属于哪个类型”，不如先问“我为什么要给它分类”。给玩家推荐时，标签要贴近体验；做设计分析时，要拆到机制和玩家技能；看历史演化时，要看标志性作品和社区；做市场定位时，还要看平台、商业模式和受众预期。</p><h2 id="用-MDA-先拆一拆"><a href="#用-MDA-先拆一拆" class="headerlink" title="用 MDA 先拆一拆"></a>用 MDA 先拆一拆</h2><p>MDA 把游戏拆成三层：Mechanics、Dynamics、Aesthetics。简单说，Mechanics 是规则和系统，Dynamics 是玩家和系统互动后发生的过程，Aesthetics 是玩家最后感受到的东西。因为很多类型名其实都混着这三层。</p><table><thead><tr><th>类型</th><th>Mechanics：系统里有什么</th><th>Dynamics：玩家会怎么玩</th><th>Aesthetics：玩家感受到什么</th></tr></thead><tbody><tr><td>体育</td><td>现实运动规则、计分、身体或体感输入</td><td>练习、对抗、比赛节奏、复现真实赛事</td><td>竞争、身体代入、临场感</td></tr><tr><td>模拟</td><td>变量、资源、生产链、物理或经济规则</td><td>调参、观察反馈、优化流程</td><td>管理复杂系统的满足感</td></tr><tr><td>动作</td><td>移动、攻击、判定、闪避、冷却</td><td>反应、连招、走位、风险控制</td><td>紧张、爽快、掌控感</td></tr><tr><td>冒险</td><td>场景、物品、对话、剧情节点</td><td>探索、推理、选择路径、推进故事</td><td>好奇、悬疑、故事投入</td></tr><tr><td>RPG</td><td>属性、等级、装备、技能、选择</td><td>构筑角色、推进故事、承担后果</td><td>成长、扮演、身份感</td></tr><tr><td>策略</td><td>单位、资源、地图、科技、信息差</td><td>规划、取舍、克制、调度</td><td>智胜对手、掌控局势</td></tr><tr><td>Roguelike</td><td>程序生成、随机物品、死亡惩罚</td><td>试错、记忆、临场构筑</td><td>惊喜、挫败、再来一局</td></tr><tr><td>解谜</td><td>机关、空间关系、物理规则、线索</td><td>试验、推理、顿悟、路线规划</td><td>想明白后的快感</td></tr><tr><td>休闲</td><td>简单输入、短循环、低惩罚、轻量社交</td><td>随手进入、重复推进、碎片时间游玩</td><td>放松、陪伴、低负担</td></tr></tbody></table><p>拿《星露谷物语》来说，Mechanics 是种植、采集、生产、社交、时间和体力；Dynamics 是玩家每天安排路线，决定先浇水、下矿、钓鱼，还是去送礼；Aesthetics 则是很典型的放松、积累和陪伴。它当然可以叫模拟经营，也可以叫农场生活模拟，甚至在某些玩法下接近休闲游戏。不同标签只是抓住了不同层。</p><p>《Portal》也一样。Mechanics 看起来像 FPS：第一人称视角、移动、瞄准、发射。Dynamics 却不是战斗，而是利用传送门理解空间关系。Aesthetics 也不是杀敌爽感，而是解开问题后的顿悟。只说它是 FPS 会误导，只说它是解谜又会漏掉它借来的操作框架。</p><p>所以后面讲类型时，我会尽量按 MDA 的顺序去看：这个类型常见的机制是什么，玩家会形成什么玩法过程，最后给人的感觉是什么。</p><h2 id="基础大类：先看玩家主要在做什么"><a href="#基础大类：先看玩家主要在做什么" class="headerlink" title="基础大类：先看玩家主要在做什么"></a>基础大类：先看玩家主要在做什么</h2><h3 id="体育与竞速"><a href="#体育与竞速" class="headerlink" title="体育与竞速"></a>体育与竞速</h3><p>体育游戏把现实运动的规则、计分和身体技巧变成可操作的数字系统。FIFA、NBA 2K、Madden NFL 依赖真实联赛、球员名单和粉丝文化；《Wii Sports》则把挥拍、投球、挥拳这类身体动作变成家庭娱乐。</p><p>竞速经常从体育里独立出来。街机竞速看爽快、漂移、道具和刺激，比如《马力欧卡丁车》；拟真竞速看车辆调校、赛道记忆、刹车点和驾驶技术，比如《Gran Turismo》《Forza Motorsport》。竞速游戏最为特殊的产物应该是《Forza Horizon》，弱化体育竞技，给玩家开放世界进行观景和体验，整体的游玩体验反而变得休闲了。同样是赛车，面向的玩家可以完全不同。</p><p>这里的边界不难抓：玩家是不是在一套比赛规则里竞争？输入是不是在模拟身体或载具技巧？如果是，它就接近体育或竞速。</p><h3 id="模拟"><a href="#模拟" class="headerlink" title="模拟"></a>模拟</h3><p>模拟游戏不是完整复制现实，而是把现实系统里的关键关系压缩成可玩的模型。好的模拟游戏不一定最真实，但一定要让玩家理解和操控一个系统。</p><p>《SimCity》《城市：天际线》把交通、人口、税收和公共服务变成可调变量；《过山车之星》《双点医院》把经营、动线和顾客满意度变成管理问题；《动物森友会》《星露谷物语》则把生活节奏、收集、装饰和社交做得更温和。</p><p>另一端是硬核模拟。《微软飞行模拟》《Kerbal Space Program》保留更多飞行或轨道力学约束。难点不是把现实一股脑搬进去，而是让复杂系统变得可学。太真实可能像工作手册，太抽象又会失去模拟的味道。</p><p>国内玩家熟悉的养成、经营、生活类游戏也常常在模拟附近。《中国式家长》《火山的女儿》模拟成长路径和资源分配；不少餐厅、农场、城市经营手游则把生产链、等待时间和订单系统做成移动端循环。</p><h3 id="动作"><a href="#动作" class="headerlink" title="动作"></a>动作</h3><p>动作游戏的核心是即时操作。移动、躲避、攻击、跳跃、瞄准、格挡、连招，玩家要在持续变化的局势里做出反应。</p><p>平台动作是很经典的形态。《超级马力欧》看跳跃、落点和关卡节奏；《Celeste》把跳跃和冲刺做成精密挑战；《宇宙机器人》更强调空间互动和关卡奇观。格斗游戏如《街头霸王》《拳皇》《铁拳》，把动作压缩到短时间对抗、输入精度、距离和心理博弈里。</p><p>射击是动作游戏的大分支。FPS 强调第一人称视角下的瞄准、走位和视野控制，比如《Doom》《Counter-Strike》《Apex Legends》；TPS 能看到角色身体，更适合掩体、翻滚、近战和角色动作，比如《战争机器》《绝地求生》《喷射战士》。但射击框架不一定服务击杀，《Portal》就是拿 FPS 操作来做空间解谜。</p><p>动作游戏常被误解成暴力游戏，其实暴力不是本质。它真正关心的是实时输入和即时反馈。玩家慢半拍，体验就会变。</p><h3 id="冒险"><a href="#冒险" class="headerlink" title="冒险"></a>冒险</h3><p>冒险游戏的核心不是有冒险故事，而是玩家通过观察场景、理解情境、使用物品、对话或选择来推进未知。</p><p>传统 point-and-click adventure 如《猴岛的秘密》《Grim Fandango》，让玩家找线索、组合物品、和角色对话。现代冒险游戏的边界更宽。《Life is Strange》《Firewatch》偏叙事探索和角色关系；《底特律：变人》《行尸走肉》偏互动电影和分支选择；日式 ADV、视觉小说和推理文字冒险则把文本、角色和选择推到前台，比如《逆转裁判》《弹丸论破》。</p><p>动作冒险是更主流的融合形态。《塞尔达传说》《古墓丽影》《神秘海域》都让探索、空间理解、谜题和即时动作结合。争论它到底是动作还是冒险意义不大。更重要的是看玩家注意力怎么分配：既要操作，也要读空间和故事。</p><p>冒险游戏的问题也很明显。固定谜题和线性故事第一次很强，第二次可能就少了新鲜感。分支、隐藏线索、多个解法和环境叙事，都是在补这个短板。</p><h3 id="RPG"><a href="#RPG" class="headerlink" title="RPG"></a>RPG</h3><p>RPG 的核心不是有等级，而是玩家扮演一个或多个角色，通过属性、装备、技能、队伍、选择和故事推进来形成成长。它最吸引人的地方大概是三个问题：我是谁？我怎么成长？我的选择会不会改变世界？</p><p>JRPG 通常强调固定角色、明确剧情线、队伍成长和强叙事。《最终幻想》《勇者斗恶龙》《女神异闻录》都是典型例子。回合制很常见，但不是绝对标准。更重要的是玩家进入一段“别人已经写好，但我可以参与体验”的英雄故事。</p><p>CRPG 或经典欧美 RPG 更强调规则系统、角色构筑、队伍配置和选择后果。《博德之门 3》《辐射 1&#x2F;2》《异域镇魂曲》都带有桌游传统。玩家不是只看主角故事，而是通过角色创建、对话选择、任务路径和阵营关系写自己的故事。Bethesda 风格的开放世界 RPG，比如《上古卷轴 5》《辐射 4》，又把自由探索和玩家自我叙事放到更大空间里。</p><p>ARPG 把 RPG 的成长、装备和构筑放进即时动作战斗。《暗黑破坏神》《怪物猎人》《艾尔登法环》《原神》都可以从不同角度理解为 ARPG。MMORPG 则把 RPG 放进长期在线社会中，《魔兽世界》《最终幻想 XIV》《梦幻西游》强调职业、组队、公会、交易、副本和版本运营。</p><p>SRPG 或战术 RPG 把角色成长和战棋策略结合。《火焰纹章》《皇家骑士团》《梦幻模拟战》让角色成长、站位、地形、资源和永久死亡交织在一起。一个单位不只是棋子，也是角色。</p><h3 id="策略"><a href="#策略" class="headerlink" title="策略"></a>策略</h3><p>策略游戏的核心是用脑子赢。它要求玩家理解规则、资源、地形、单位、时机、信息和长期计划。传统棋类可以看作它的精神源头：胜负不靠反应，而靠判断。</p><p>回合制策略给玩家更多思考时间。《文明》系列代表 4X：探索、扩张、开发、征服。玩家要在科技、外交、军事、城市和资源之间做长期选择。《幽浮》《火焰纹章》则更强调战术层面的站位、命中率、掩体、技能和角色风险。</p><p>RTS 把策略和时间压力放在一起。《星际争霸》《帝国时代》《Warcraft III》要求玩家同时处理资源采集、科技树、造兵、侦查、扩张、微操和多线战斗。它不是“动作加策略”，而是把宏观规划和微观执行压缩到实时节奏里。</p><p>大战略和战争模拟又是另一条路。《Hearts of Iron》看国家工业、补给、战线和政治；《Total War》常把回合制大地图管理和实时战场指挥结合起来。轻量策略也存在，比如《Worms》把地形破坏、投射物轨迹和回合决策做得很直观。</p><p>国内语境里的 SLG 有时比较混乱。它可能指传统策略战棋，也可能指移动端长期运营的战争&#x2F;联盟游戏。后者经常同时包含建造、养成、联盟外交、PVP、时间加速和付费资源。只写一个 SLG，往往说不清楚。</p><h3 id="解谜"><a href="#解谜" class="headerlink" title="解谜"></a>解谜</h3><p>解谜游戏让玩家理解规则，再用这个理解解决被设计出来的问题。好谜题不只是难，而是让玩家有一刻突然意识到：原来系统是这样运作的。</p><p>《俄罗斯方块》把空间填充、速度压力和长期风险压缩到极致。《Lemmings》让玩家在实时环境中给小人分配技能，处理路径、牺牲和整体目标。《Portal》借用 FPS 操作框架，把视角、空间、传送门和物理关系变成谜题。《Angry Birds》则把触屏、抛物线和物理破坏做成休闲解谜。</p><p>解谜经常和冒险、恐怖、平台动作、物理模拟融合。《纪念碑谷》依赖视觉错觉和空间结构；《Baba Is You》把规则本身变成可移动对象；《密室逃脱》和推理游戏更依赖线索组织。</p><p>解谜的坑是一题一解。如果设计者只接受一个答案，却没有给足反馈，玩家就不是在理解系统，而是在猜作者脑子里想什么。早期 point-and-click adventure 里的 pixel hunt 就是这个问题：玩家不是没想明白，只是不知道该点哪个像素。</p><h3 id="休闲"><a href="#休闲" class="headerlink" title="休闲"></a>休闲</h3><p>休闲游戏不是低质量游戏。它说的是一种设计目标：降低学习成本、失败压力和单次投入，让玩家能在轻松、碎片或社交场景里进入。</p><p>三消、点击、合成、轻经营、放置、轻量解谜都经常属于休闲语境。《Candy Crush》《Best Fiends》《Township》强调短关卡、直觉输入、即时反馈和长期轻目标。Clicker 或放置游戏把操作压到很低，乐趣来自数字增长、解锁节奏和“系统自己也在推进”。</p><p>休闲也可以是一种玩法状态。《Minecraft》可以被硬核玩家玩成红石工程，也可以被休闲玩家玩成建造、种田和陪伴。《星露谷物语》可以被效率玩家算日程，也可以被当作下班后的放松循环。</p><p>移动端休闲还经常和商业设计绑在一起。等待时间、体力、加速道具、生产槽位、每日任务和活动日历都会改变节奏。如果设计过度依赖等待和付费，玩家有空想玩时，游戏反而不让他玩。这就很别扭。</p><h2 id="融合类型和现代标签"><a href="#融合类型和现代标签" class="headerlink" title="融合类型和现代标签"></a>融合类型和现代标签</h2><h3 id="音乐、恐怖、沙盒和开放世界"><a href="#音乐、恐怖、沙盒和开放世界" class="headerlink" title="音乐、恐怖、沙盒和开放世界"></a>音乐、恐怖、沙盒和开放世界</h3><p>这几个不太像基础大类，更像现代游戏里常用的体验标签。它们经常跨在动作、冒险、模拟、策略这些大类上面。</p><p>音乐游戏的核心是节奏、听觉、输入时机和反馈。《节奏天国》《太鼓达人》《DJMAX》《Muse Dash》《Phigros》都要求玩家把音乐结构转成身体输入。它可以是街机、主机、移动端，也可以使用专用控制器。它常被单列，是因为输入和审美绑得太紧。</p><p>恐怖更像情绪标签，不是单一机制。《生化危机》早期偏生存恐怖，强调资源稀缺和空间压迫；《寂静岭》偏心理恐怖；《逃生》强调无力逃跑和追逐；中式恐怖游戏可能更依赖民俗、禁忌和叙事悬疑。恐怖可以和冒险、动作、解谜、步行模拟、射击结合，所以还要继续问：它到底靠什么让玩家害怕？</p><p>沙盒强调开放性、创造和玩家自我表达。《Minecraft》《泰拉瑞亚》《Roblox》都说明，沙盒不只是地图大，而是玩家能不能改变、组合、建造、破坏或自定义世界。开放世界强调空间开放，沙盒强调系统可操作。两者经常重合，但不是一回事。</p><p>开放世界本身更像空间结构标签。它说的是玩家能在一个连续的大空间里自由移动、选择目标和安排路线。《GTA》《塞尔达传说：旷野之息》《艾尔登法环》《原神》《Forza Horizon》都可以从这个角度理解。开放世界不保证沙盒，也不保证自由叙事；有些开放世界只是把任务摊在大地图上，有些则真的让探索、遭遇和系统互动成为主要乐趣。</p><h3 id="ARPG、A-AVG、SRPG"><a href="#ARPG、A-AVG、SRPG" class="headerlink" title="ARPG、A-AVG、SRPG"></a>ARPG、A-AVG、SRPG</h3><p>最常见的融合类型，来自基础大类之间的交叉。</p><p>ARPG 是动作和 RPG 的结合。《暗黑破坏神》偏装备、词缀和刷宝循环；《怪物猎人》偏动作理解、武器熟练度和材料成长；《原神》偏角色队伍、元素反应、开放世界探索和服务型更新；《艾尔登法环》偏动作、构筑、地图探索和高惩罚挑战。</p><p>A-AVG 或动作冒险把即时动作和冒险探索结合。《塞尔达传说》《古墓丽影》《神秘海域》《小小噩梦》都在这个附近。它们不是纯动作，因为玩家还要读空间、找路径、理解场景；也不是纯冒险，因为操作和时机很重要。</p><p>SRPG 把策略和 RPG 结合。《火焰纹章》《三角战略》《梦幻模拟战》让角色成长、职业、装备和剧情选择进入战棋局势。玩家一边赢这一局，一边培养这一队人。</p><p>这类融合其实可以用一句话拆：先找主轴，再找支撑轴。主轴回答玩家大部分时间在做什么，支撑轴回答什么系统让它更深。</p><h3 id="MOBA"><a href="#MOBA" class="headerlink" title="MOBA"></a>MOBA</h3><p>MOBA 是很好的类型演化案例。它继承 RTS 的地图、兵线、资源、视野、团队战略和单位技能，但把玩家操作焦点从一整支军队收缩到一个英雄。小兵沿路线推进，玩家通过英雄成长、技能释放、装备选择、地图资源和团队配合影响战局。</p><p>《DotA》与 RTS 自定义地图文化关系很深，后来《英雄联盟》《Dota 2》《王者荣耀》等作品把这种玩法产品化、竞技化和平台化。MOBA 很难塞进传统树状分类，因为它同时有动作性、策略性、RPG 成长、团队沟通和强竞技压力。</p><p>《王者荣耀》还说明平台会改写类型。移动端减少键鼠操作复杂度，用虚拟摇杆、自动寻路、快捷施法和更短对局适配碎片场景。它不是简单把 PC MOBA 缩小，而是重新组织输入和节奏。</p><h3 id="Battle-Royale"><a href="#Battle-Royale" class="headerlink" title="Battle Royale"></a>Battle Royale</h3><p>Battle Royale 通常包含大地图、多玩家出生、随机物资、高死亡惩罚、不断缩小的安全区，以及最后存活者获胜。它可以和射击结合成《PUBG》《Apex Legends》《堡垒之夜》，也可以和派对、动作、近战或其他玩法结合。</p><p>这个类型最关键的设计不是“很多人互相打”，而是缩圈。开放大地图在人数减少后容易失去节奏，玩家可能一直躲着。安全区收缩把空间不断压小，迫使遭遇继续发生，也让一局游戏从搜集、转移、埋伏逐渐进入终局对抗。</p><p>《PUBG》偏写实军事射击和生存压力，《Apex Legends》加入英雄技能和高速移动，《堡垒之夜》加入建造、活动和社交平台属性。它们共享 Battle Royale 结构，但玩家技能和审美不同。</p><h3 id="Roguelike-Roguelite"><a href="#Roguelike-Roguelite" class="headerlink" title="Roguelike &#x2F; Roguelite"></a>Roguelike &#x2F; Roguelite</h3><p>Roguelike 来自 1980 年的《Rogue》。传统 Roguelike 的关键词包括程序生成、永久死亡、回合制、网格移动、资源识别、地牢探索和高难度。玩家一次次死亡，不只是刷数值，而是在学习怪物、物品、风险和世界规则。</p><p>现代语境里，Roguelite 更常见。它保留随机关卡、构筑变化和死亡循环，但不一定坚持传统 Roguelike 的所有规则，也常常加入局外成长。《Hades》是动作 Roguelite，《杀戮尖塔》是卡牌构筑 Roguelite，《FTL》是太空船管理与随机事件，《以撒的结合》是双摇杆动作和随机道具，《暖雪》则把国风动作、流派构筑和反复挑战结合。</p><p>Roguelike 的核心不是“随机地图”，而是不确定性、高惩罚、短到中等循环，以及玩家通过失败理解系统。只有随机奖励或随机副本，不一定就该叫 Roguelike。</p><h3 id="Soulslike"><a href="#Soulslike" class="headerlink" title="Soulslike"></a>Soulslike</h3><p>Soulslike 来自《恶魔之魂》《黑暗之魂》以及后来 FromSoftware 的一系列作品。它通常包含高惩罚死亡、精确动作、体力管理、篝火或检查点、敌人配置学习、碎片化叙事和互相勾连的关卡结构。</p><p>但 Soulslike 不等于“很难的 ARPG”。如果只是敌人数值高、玩家容易死，却没有可学习的敌人动作、风险回报、关卡路线和死亡后的重新理解，那只是难。《艾尔登法环》加入开放世界后，边界又被扩大：玩家可以绕路、探索、成长，再回来挑战。</p><p>国内玩家有时会把“受苦”当成标签。这个说法很形象，但还不够。Soulslike 真正成立的地方，是死亡、学习、掌控和世界神秘感同时存在。</p><h3 id="Metroidvania"><a href="#Metroidvania" class="headerlink" title="Metroidvania"></a>Metroidvania</h3><p>Metroidvania 来自《银河战士》和《恶魔城》的传统。它的核心是一个连续、互相连接的世界，玩家通过获得新能力解锁旧区域的新路径。它不像线性平台关卡一关一关推进，也不像开放世界一开始到处可去，而是用能力、地图、门和路线组织探索。</p><p>《空洞骑士》《奥日》《赤痕：夜之仪式》都能从这个传统理解。它的乐趣是“回头看见旧世界变了”。不是地图变了，而是玩家的能力和理解变了。一个之前跳不过的平台、打不开的门、看不懂的路线，在获得二段跳、冲刺、钩爪或变形能力后突然连起来。</p><h3 id="Survival、Crafting-与-Sandbox"><a href="#Survival、Crafting-与-Sandbox" class="headerlink" title="Survival、Crafting 与 Sandbox"></a>Survival、Crafting 与 Sandbox</h3><p>生存游戏强调资源匮乏、环境威胁、身体状态、建造和长期风险。《Don’t Starve》《方舟：生存进化》《森林》《饥荒》都要求玩家处理饥饿、温度、怪物、材料和基地。生存不只是血量低，而是世界会持续消耗玩家。</p><p>Crafting 和建造常与生存绑定，也可以走向沙盒表达。《Minecraft》既能是生存，也能是创造；《泰拉瑞亚》既能是探索和建造，也能是动作冒险和装备成长。关键要看玩家的主要压力来自哪里：活下去，还是表达自己。</p><h3 id="Tower-Defense、4X-和卡牌构筑"><a href="#Tower-Defense、4X-和卡牌构筑" class="headerlink" title="Tower Defense、4X 和卡牌构筑"></a>Tower Defense、4X 和卡牌构筑</h3><p>塔防是策略的清晰分支。敌人沿路线推进，玩家通过资源、塔、单位、阻挡、技能和地形来防守。《植物大战僵尸》《明日方舟》《Kingdom Rush》都是不同形式的塔防。《明日方舟》有意思的地方在于，它把塔防、角色养成、关卡解谜、抽卡和长期运营放到同一个框架里。</p><p>4X 是探索、扩张、开发、征服。《文明》《群星》《无尽空间》让玩家在很长时间尺度里经营国家、文明或星际帝国。它和 RTS 都是策略，但节奏完全不同：RTS 关心实时操作和局部战斗，4X 更关心宏观方向、科技、外交、资源和长期计划。</p><p>卡牌构筑把策略压缩进牌组、概率、资源和回合选择。《炉石传说》《游戏王：大师决斗》《昆特牌》偏对战卡牌；《杀戮尖塔》《月圆之夜》偏 Roguelite 构筑；《影之诗》《阴阳师：百闻牌》又带有角色、IP 和运营内容。卡牌游戏的有趣之处在于，玩家不只选择当前动作，也在设计未来会抽到什么。</p><h3 id="派对、社交推理、放置与抽卡养成"><a href="#派对、社交推理、放置与抽卡养成" class="headerlink" title="派对、社交推理、放置与抽卡养成"></a>派对、社交推理、放置与抽卡养成</h3><p>有些现代标签已经不只描述机制，而是在描述社交场景或运营结构。</p><p>派对游戏强调多人同屏、低门槛、短局和可笑场。《马力欧派对》《胡闹厨房》《糖豆人》都适合朋友聚会或直播观看。社交推理如《Among Us》《鹅鸭杀》《狼人杀》，核心不是操作，而是隐藏身份、语言说服、信息不对称和群体心理。</p><p>放置游戏强调低操作、长期增长和离线收益。《Cookie Clicker》《旅行青蛙》以及大量放置 RPG，都让玩家以很低投入获得持续反馈。它们经常和数值成长、收集、自动战斗和养成结合。</p><p>抽卡养成不是纯玩法类型，但今天很重要。它描述的是角色获取、资源规划、长期更新和商业模式。《原神》《崩坏：星穹铁道》《阴阳师》《明日方舟》都有不同程度的抽卡养成结构。分析这类游戏时，如果只说 ARPG、回合制 RPG 或塔防，会漏掉玩家很大一部分体验：角色池、版本节奏、保底、资源分配、队伍搭配和内容运营。</p><p>这也是现代游戏分类越来越像标签系统的原因。一个标签不够，就叠多个。</p><h2 id="类型通常怎样长出来"><a href="#类型通常怎样长出来" class="headerlink" title="类型通常怎样长出来"></a>类型通常怎样长出来</h2><p>把这些类型放在一起看，会发现几条常见路径。</p><p>有些类型被技术和设备推出来。街机摇杆、手柄、键鼠、触屏、体感、VR、方向盘都会改变可行体验。没有合适输入，很多玩法很难成立；有了新输入，旧玩法也会换一副面孔。</p><p>有些类型从社区和 Mod 里长出来。MOBA、Battle Royale、许多生存玩法和 UGC 平台都说明，玩家会在已有游戏里创造新规则。开发者要做的，有时不是凭空发明玩法，而是识别玩家已经玩出来的东西，把它整理、平衡、产品化。</p><p>有些类型由标志性作品命名。Roguelike、Soulslike、Metroidvania 都不是先有完整理论再有游戏，而是先有强烈体验，后来玩家需要一个词来描述“像它的那类东西”。</p><p>商业模式也会改变类型。MMORPG、移动休闲、抽卡养成、赛季制竞技、Battle Pass 不只是收费方式，它们会影响内容节奏、玩家目标和系统设计。</p><p>最后是玩家技能迁移。FPS 玩家会把瞄准和走位带到战术射击；RPG 玩家会把构筑意识带到刷宝和抽卡；策略玩家会把资源规划带到塔防、卡牌和 4X。类型会融合，玩家自己也在迁移。</p><h2 id="分析一款游戏时，我会这样问"><a href="#分析一款游戏时，我会这样问" class="headerlink" title="分析一款游戏时，我会这样问"></a>分析一款游戏时，我会这样问</h2><p>以后看一款游戏，或许应该按照下面的思路去理解其玩法。</p><ol><li><p>玩家大部分时间在做什么？战斗、探索、经营、建造、解谜、收集、社交、阅读，哪个占比最高？</p></li><li><p>失败主要来自哪里？是反应慢、策略错、资源不够、构筑不好、线索没理解，还是社交判断失败？</p></li><li><p>核心循环是什么？一局、一关、一天、一次副本、一次抽卡、一轮赛季，玩家怎样开始、获得反馈、成长、再回来？</p></li><li><p>玩家成长在哪里？是角色数值成长、玩家技术成长、知识成长、收藏成长、社交关系成长，还是审美表达成长？</p></li><li><p>平台和输入改变了什么？键鼠、手柄、触屏、体感、VR 是否决定了它的节奏和复杂度？</p></li><li><p>主标签和副标签分别是什么？主标签描述核心体验，副标签描述支撑系统。比如“开放世界 ARPG + 抽卡养成 + 服务型内容”，就比只说“RPG”清楚。</p></li><li><p>这个标签对谁有用？给玩家推荐、给设计拆解、给市场定位、给学术研究，需要的标签可能不一样。</p></li></ol><p>用这个方法回看开头的例子，《原神》不需要在 ARPG 和开放世界之间二选一。它的主体验可以是开放世界动作 RPG，支撑系统包括角色收集、元素反应、队伍构筑、探索解谜和服务型更新。《明日方舟》也不只是塔防，它是塔防关卡、策略解谜、角色养成、抽卡收集和长期运营的组合。《王者荣耀》也不只是移动版 Dota，它是为触屏、短局、社交传播和移动竞技重新组织过的 MOBA。</p><p>所以游戏分类最后不是给游戏贴一个永远不变的名牌。它更像一套描述体验的语言。树状分类帮我们抓历史和边界，标签分类帮我们面对现代游戏的混合现实，多维框架则提醒我们：类型名背后还有机制、技能、平台和玩家感受。</p><p>一款游戏可以同时属于很多类型。这不是分类失败，而是电子游戏本来就长这样。真正重要的是，当我们说出一个类型名时，知道自己在强调什么，也知道它没说完什么。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>PLOS ONE, <a class="link"   href="https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0299819" >The tangled ways to classify games<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Robin Hunicke, Marc LeBlanc, Robert Zubek, <a class="link"   href="https://users.cs.northwestern.edu/~hunicke/MDA.pdf" >MDA: A Formal Approach to Game Design and Game Research<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Steamworks Documentation, <a class="link"   href="https://partner.steamgames.com/doc/store/tags" >Tags and Genres<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Game Developer, <a class="link"   href="https://www.gamedeveloper.com/design/postmortem-i-defense-of-the-ancients-i-" >Postmortem: Defense of the Ancients<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>RogueBasin, <a class="link"   href="https://www.roguebasin.com/index.php/Berlin_Interpretation" >Berlin Interpretation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>ESPN, <a class="link"   href="https://www.espn.com/gaming/story/_/id/29364632/how-made-how-brendan-greene-pubg-revolutionized-gaming" >How Brendan Greene’s PUBG revolutionized gaming<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/26/game-classification/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/26/game-classification/"/>
    <published>2026-06-26T00:10:00.000Z</published>
    <summary>A study note on video game genre classification, covering genre trees, gameplay tags, player skills, platform constraints, and hybrid genres.</summary>
    <title>Video Game Genre Classification: From Genre Trees to Gameplay Tags</title>
    <updated>2026-07-01T15:56:19.868Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Essays" scheme="https://hyacehila.github.io/categories/essays/"/>
    <category term="Methodology" scheme="https://hyacehila.github.io/tags/Methodology/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Design" scheme="https://hyacehila.github.io/tags/Design/"/>
    <content>
      <![CDATA[<p>刚看完罗子雄的<a class="link"   href="https://www.youtube.com/watch?v=ocReynMrkms" >《如何成为一名优秀的设计师》<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。这个 talk 不长，它也没有给人一种听完就掌握设计秘诀的错觉，反而把话说得很老实：多看，多做，多想。先模仿，再借鉴，最后慢慢长出自己的判断。</p><p>我不是严格意义上的设计师（事实上我的审美能力目前一塌糊涂）。可看完以后，脑子里冒出来的反而是 AI Agent。做 Agent 当然不是做平面，也不是做交互稿，但两件事都很依赖一种手感：知道什么是好，知道哪里不对，知道自己为什么这么改。工具和框架变得很快，一个人怎么从不会到会、从会一点到真的有判断，绕来绕去还是这些笨办法。</p><h2 id="先让自己有参照"><a href="#先让自己有参照" class="headerlink" title="先让自己有参照"></a>先让自己有参照</h2><p>设计里的“看”，当然不是随手刷几张好看的图。它更像是在训练眼睛与大脑。看得足够多，才知道什么是平庸，什么是精确，什么东西乍一看简单，其实背后藏了很多取舍。审美不是凭空长出来的，它需要被大量好作品校准。</p><p>做 Agent 时，我觉得也有类似的“系统审美”。需要看真实产品、开源框架、论文 demo、失败案例、工具协议，也要看用户到底怎么工作。看多了以后，会慢慢发现一个 Agent 好不好，不在于它堆了多少 planner、memory、reflection。很多时候，好的 Agent 很朴素：边界清楚，接口稳定，失败时知道停在哪里。</p><p>所以初级阶段的模仿很重要。设计师要临摹优秀作品，Agent Builder 也应该读别人的系统，复现别人的流程，拆 prompt，拆工具接口。模仿不是丢人的事。真正危险的是看得太少，却太早把某个新名词当成答案，然后逐渐在不断增多的概念中迷失自我。</p><h2 id="真实问题会教育人"><a href="#真实问题会教育人" class="headerlink" title="真实问题会教育人"></a>真实问题会教育人</h2><p>但只看是不够的。罗子雄讲设计时强调要“做”真实的东西，这点放到 Agent 上更明显。教程&#x2F;论文&#x2F;Blogs 会把问题切得很干净：输入是什么，工具是什么，评价指标是什么。真实世界不会这么配合。</p><p>一旦开始做真实问题，摩擦马上就来了。工具会超时，网页会改版，权限会失败，用户会说半句话，任务会在中途变形，模型还会一本正经地犯错。上下文太长会污染判断，太短又会漏掉关键信息。自动执行太激进会越界，处处确认又会让用户觉得它没用。</p><p>这些东西只有动手时才会撞上。撞过以后，再回头看别人的设计，很多细节会突然变得合理：为什么工具 schema 写得这么保守？为什么计划要暴露给用户？为什么有些步骤必须保留人工确认？以前觉得啰嗦的地方，可能都是被真实问题打过以后留下来的。</p><p>所以学习 Agent 不能只停在读框架文档和看前沿文章。真正让人成长的，是把一个不那么干净的问题做成能反复使用的工作流。它可以很小，也可以不完美，但只要碰过真实约束，就比一个漂亮但无摩擦的 demo 更有训练价值。</p><h2 id="别急着复制形式"><a href="#别急着复制形式" class="headerlink" title="别急着复制形式"></a>别急着复制形式</h2><p>第三步是“想”。看和做如果没有思考，很容易变成素材堆积和体力劳动。设计里要问：为什么这里要留白？为什么按钮放在这里？为什么这个颜色在这个场景下成立？</p><p>Agent 也是一样。不能只问“这个流程怎么搭”，还要问“为什么要这样搭”。为什么这里需要 planner，而不是直接执行？为什么这里要引入 memory，而不是重新检索？为什么这个任务适合 autonomous loop，另一个任务却更适合 human-in-the-loop？</p><p>我自己也会犯这个毛病。看完一个 paper 或框架，第一反应是把关键词装进自己的系统里：multi-agent、reflection、RAG、memory，仿佛都加上就更完整。可很多时候，问题可能就是把接口做整齐，把反馈写清楚。问为什么，是把经验变成判断力的过程。我们知道要这样做，也要知道为什么这样做，这样当遇到一个新的问题的时候，才会发现其实它 nothing new。</p><h2 id="借鉴，不是复刻"><a href="#借鉴，不是复刻" class="headerlink" title="借鉴，不是复刻"></a>借鉴，不是复刻</h2><p>从 0 到 1 的时候，模仿是必要的。没有足够多的模仿，人很难建立基本手感。但从 1 到 100，重点就变成了组合、借鉴和改造。那句常被归到毕加索名下、也被乔布斯引用过的 Good Artists Copy, Great Artists Steal，大概说的也是这个意思。真正的吸收不是照搬，而是理解它为什么成立，然后把它放进自己的问题里去变形。</p><p>设计不是割裂的，Agent 也不是。一个好 Agent 可能从操作系统里借权限边界，从产品设计里借反馈节奏，从数据库里借状态管理，从组织协作里借任务分解，从新的模型技术变革中吸收新的 Agent 架构设想。看的东西越杂，越可能在某个真实问题里产生新的组合。</p><p>但无论看得多广，最后还是要回到做。做虚拟项目，做比赛项目，做自己真的想解决的问题，做那些外人看起来不够宏大、但你愿意反复打磨的小工具。很多时候，能把一个东西从可以跑改到好用，已经是在跨过一条很重要的线。</p><p>设计里的 Good is not enough，放到 Agent 里也成立。一个 Agent 能跑通，不代表它值得被依赖；一个 demo 令人惊艳，不代表它能进入真实工作流。优秀不是会用最新工具，而是逐渐形成自己的判断：知道什么值得看，什么必须亲手做，什么地方应该停下来问一句为什么。</p><p>看、做、想听起来都不新鲜。也许正因为它们不新鲜，才更可靠。技术行业总喜欢把新东西讲成范式革命，然后几个月就革一次，可人的成长没有那么多捷径。无论是设计师，还是 Agent Builder，最后都要回到一件很普通的事：在真实世界里持续观察、行动、理解，把下一次做得比这一次再好一点。</p>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/25/from-designer-to-agent-builder/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/25/from-designer-to-agent-builder/"/>
    <published>2026-06-24T18:00:00.000Z</published>
    <summary>Designer training also works for AI Agent builders: see more real systems, solve real problems, and keep asking why.</summary>
    <title>From Designer to Agent Builder: See, Make, Think</title>
    <updated>2026-07-01T15:56:19.868Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Foundation Models" scheme="https://hyacehila.github.io/categories/foundation-models/"/>
    <category term="Multimodality" scheme="https://hyacehila.github.io/tags/Multimodality/"/>
    <category term="VLM" scheme="https://hyacehila.github.io/tags/VLM/"/>
    <category term="Interaction Model" scheme="https://hyacehila.github.io/tags/Interaction-Model/"/>
    <content>
      <![CDATA[<p>最近看到 <a class="link"   href="https://joyai-vl-video-future-academy-jd.github.io/JoyAI-VL-Interaction/" >JoyAI-VL-Interaction<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，一开始只觉得它挺好玩：能看视频流，能判断什么时候说话，还能把复杂问题委派给后台模型或 agent。但再想一层，它其实碰到了一个更基础的问题：Chat 真的是生成式模型天然的交互形态吗？</p><h2 id="Chat-不是模型的天生形态"><a href="#Chat-不是模型的天生形态" class="headerlink" title="Chat 不是模型的天生形态"></a>Chat 不是模型的天生形态</h2><p>我们现在太习惯 Chat 了。用户说一句，模型回一句；用户再问，模型再答。对于一个长程的 Agent Runtime，Agent则会在收到命令后默默的执行，然后汇报结果。久而久之，语言模型等价于 Chatbot 。一轮输入，一轮输出，再用一枚 EOS token 结束回答，好像这就是模型本身的形状。</p><p>但这更像产品层和训练数据层形成的协议，而不是模型结构本身所决定的。自回归生成模型做的事情很朴素：给定前面的 token，预测下一个 token。EOS token 只是序列里的特殊符号，用来告诉解码器“这段可以停了”。如果场景不要求模型停在这里，而是让它持续接收音频、视频、文本和动作 token，这也是很自然的。</p><p>一轮轮 Chat 是把连续世界切成片段的界面设计。它很好用，但不是唯一合理的形态。真实交互里，人会听、看、打断、补充、沉默，也会一边观察一边决定下一句话该不该说。</p><p>从这个角度看，Interaction Model 并不是凭空出现的新物种。它更像是把生成式模型从 Chat 产品的约束放开，重新放回连续事件流里：输入不再只有一段用户消息，输出也不再只有一段助手回答，而是持续的感知、判断和行动。</p><h2 id="Interaction-Model-到底新在哪里"><a href="#Interaction-Model-到底新在哪里" class="headerlink" title="Interaction Model 到底新在哪里"></a>Interaction Model 到底新在哪里</h2><p><a class="link"   href="https://thinkingmachines.ai/blog/interaction-models/" >Thinking Machines Lab 的 Interaction Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 文章讲的就是这个问题。他们认为，今天很多 AI 系统的协作瓶颈不在于模型完全不会做事，而在于交互界面太窄。用户必须先把意图整理成完整输入；模型生成时又经常卡在自己的输出里，新的语音、画面、打断和反馈进不来。我们可以通过两轮 Tool Calling 之前的时间去 Steer 插入自己的想法，但这只是补丁。</p><p>TML 的说法是，interaction models 应该原生处理交互，而不是依赖外部脚手架补丁。模型要能同时处理音频、视频和文本，在实时协作中持续接收信息、回应和行动。他们提到的 multi-stream、micro-turn 设计，就是把大回合切成更小的时间片，让模型不必等完整一句话或完整一段回答结束，才重新感知世界。依旧多轮，但几百毫秒的轮次对人类就意味着连续，远大于普朗克时间。</p><p>这里有意思的不是低延迟本身，而是协作结构变了。用户可以打断，模型可以边听边想，画面变化可以触发模型改变计划，后台 agent 可以和前台交互模型分工。interaction model 在架构上没有什么惊天动力的变化，而在训练目标、数据组织、输入输出协议和系统形态。</p><h2 id="回到生成式模型更早的样子"><a href="#回到生成式模型更早的样子" class="headerlink" title="回到生成式模型更早的样子"></a>回到生成式模型更早的样子</h2><p>我更愿意把这个方向理解成生成式模型的回归，而不是对生成式模型的反叛。早期语言模型学习的是序列中的延续关系。后来 instruction tuning、RLHF、聊天模板和 tool call 协议，把模型变成了非常好用的对话助手。副作用是，我们把模型能力和聊天界面绑得太紧了。</p><p>一旦进入多模态实时场景，Chat 的边界就会露出来。摄像头画面不是固定 prompt，语音不是已经结束的文字，用户动作也不一定会以清晰命令出现。此时 EOS 反而不是关键，关键是模型能不能学会一组新的 action token 或行为标签：继续听、保持静默、发出提醒、调用工具、委派后台模型。</p><p>这样看，Interaction Model 仍然可以是生成式的。只是它生成的不一定都是自然语言，也可能是时机、动作、控制信号，或者给后台系统的任务描述。这也是一种 VLA，而实时交互的 VLA 正是目前研究具身智能的核心技术。</p><h2 id="JoyAI-VL-Interaction-做了什么"><a href="#JoyAI-VL-Interaction-做了什么" class="headerlink" title="JoyAI-VL-Interaction 做了什么"></a>JoyAI-VL-Interaction 做了什么</h2><p>JoyAI-VL-Interaction 是一个不错的例子，也正是看到了他我才接触到 Interaction Model 并考虑写了这篇 Blog，它也一定程度上影响了我对 Agent 的想法。它是一个 8B 规模、视觉优先的交互模型。模型每秒都要在三个动作之间做判断：保持静默、直接回应，或者进行委派。这里的静默不是失败输出，而是一种被训练出来的行为。</p><p>这和普通视频理解模型不太一样。传统 VLM 更关心“视频里有什么”“请总结这段视频”。JoyAI-VL-Interaction 更像在回答另一个问题：“现在是否值得打断人类？”如果值得，是立刻提醒一句，还是把复杂问题交给后台的复杂长程任务模型。</p><p>它的行为来自超过 400 万条时间对齐交互样本，并通过强化学习进一步优化。这个数据形态很关键，因为交互问题天然带时间。一个提醒说得对，但晚了五秒，交互上可能已经失败。系统上，JoyAI-VL-Interaction 也不只是丢出一个模型权重。它开放了模型、训练配方、时间对齐数据和可部署系统，服务侧包括推理、WebUI、ASR、TTS、后台 agent，并兼容 vLLM 生态。</p><p>官方还在 58 个真实事件驱动视觉交互场景中做了人工成对比较，评估响应质量和响应时机。这比单纯问答准确率更贴近任务本身，因为交互模型的失败经常是“没有在该出现的时候出现”。总体来看，这是一个还算有趣且有价值的新尝试。</p><h2 id="为什么这个方向值得看"><a href="#为什么这个方向值得看" class="headerlink" title="为什么这个方向值得看"></a>为什么这个方向值得看</h2><p>我不想把 JoyAI-VL-Interaction 说成已经解决了实时助理。8B 模型在知识、复杂推理、长尾请求和个性化上肯定还有限制。TML 的 interaction model 也还处在研究预览阶段，长会话上下文、部署成本、安全边界和后台 agent 协作，都还要继续探索。</p><p>但这个方向很值得看。它不是发明了一个和生成式模型完全不同的新结构，而是把我们从 Chat 的惯性里拽出来。模型不一定只能等用户发话；生成也不一定只生成自然语言；EOS 也不必成为交互的边界。我们以前总是在研究 VLA、自动驾驶与机器人的时候讨论实时性，但人与 Agent 之间的交互，未尝不需要这种实时性，现有的 Chat 对齐和 Agent 设计也不一定就是正确的答案。</p><p>如果说过去几年基础模型最重要的界面是 Chat，那么下一阶段可能会出现更多 Online 的界面：摄像头里的生活助理、直播流里的实时评论员、机器人身上的观察者、桌面环境里的协作者到所有设计人机交互的地方。它们需要的不是更快地回答我看到了什么，而是判断现在该不该做点什么。</p><p>这也是 JoyAI-VL-Interaction 以及所有 Interaction Model 有趣的地方。它不只是一个会看视频的模型，而是一个把交互时机放进模型行为里的尝试。这个看似很新的概念又回到一个很朴素的问题：如果生成式模型本来就可以沿着连续序列往前走，那为什么一定要把它关在一问一答的 Chat 框里？</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a class="link"   href="https://joyai-vl-video-future-academy-jd.github.io/JoyAI-VL-Interaction/" >JoyAI-VL-Interaction 项目页<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/jd-opensource/JoyAI-VL-Interaction" >JoyAI-VL-Interaction GitHub 仓库<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2606.14777" >JoyAI-VL-Interaction 技术报告<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://huggingface.co/jdopensource/JoyAI-VL-Interaction-Preview" >JoyAI-VL-Interaction 模型权重<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://huggingface.co/datasets/jdopensource/JoyAI-VL-Interaction" >JoyAI-VL-Interaction 数据集<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://thinkingmachines.ai/blog/interaction-models/" >Thinking Machines: Interaction Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/23/joyai-vl-interaction/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/23/joyai-vl-interaction/"/>
    <published>2026-06-23T04:00:00.000Z</published>
    <summary>Chat is one way we package generative models, not the natural shape of the model itself. Interaction models return models to continuous tokens, perception, and action, with JoyAI-VL-Interaction as a concrete vision-language example.</summary>
    <title>JoyAI-VL-Interaction: From Chat Back to Continuous Interaction</title>
    <updated>2026-07-01T15:56:19.868Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="UI Design" scheme="https://hyacehila.github.io/tags/UI-Design/"/>
    <category term="Frontend" scheme="https://hyacehila.github.io/tags/Frontend/"/>
    <content>
      <![CDATA[<p>Vibe 写前端最容易翻车的起点，是一句帮我做一个好看的 dashboard。</p><p>这句话太空。模型会自己补行业、用户、信息密度、配色和布局，最后端出一张互联网平均脸。用 Claude Code 或其他 Coding Agent 写过几次前端的人，应该都见过那种熟悉的味道：蓝紫色渐变、发光边框、暖色纸质感、圆角卡片一层套一层。不能说完全不好看，但很难说它属于这个产品。</p><p>这篇文章不做模型排行榜，也不从 Figma、设计系统、UI&#x2F;UX 流程讲起。这里默认读者是技术出身的 Vibe Coder：能一定程度理解 AI 写出来的代码，能改组件、接数据、跑项目（哪怕靠 AI），但没有系统学过视觉设计。</p><p>因此本文不关注那些给设计师使用的 no-code 产品，而是侧重于帮助一个原本的前端&#x2F;客户端&#x2F;算法出身的技术人员去完成一些简单的前端或者全栈设计。哪些工具能帮 coding agent 生成可用、可看、还能继续改的界面？哪些工具真的能改善视觉方向、组件质量和生成美学？哪些工具虽然很火，但更适合放到附录里，仅供参考但不展开。</p><p>成熟工具和一句 prompt 的差别，通常在上下文：真实组件、设计系统、视觉参考、风格约束、可运行预览和反馈循环。让模型少猜一点，页面就会少一点 AI 平均值。</p><h2 id="生成可用的界面"><a href="#生成可用的界面" class="headerlink" title="生成可用的界面"></a>生成可用的界面</h2><p>对技术型用户来说，最有价值的第一步经常是先拿到一版能放进工程里的 UI。后端、部署和数据库可以后面再接；页面长什么样、组件怎么组织、视觉方向是否站得住，反而要尽早看见。后端是对错分明的，但 UI 和审美息息相关。</p><p><a class="link"   href="https://v0.dev/" >v0<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是一个不错的开始。它是较早把 AI 生成 UI 做出声量的产品，更像一个高质量 UI 起草器：快速给出 React、Tailwind、shadcn&#x2F;ui 生态里的页面和组件代码。按钮、表单、卡片、空状态、布局这些基础件的下限很高，技术用户也容易把结果接回自己的项目。</p><p>v0 的问题是默认气质太强。用多了会出现大家都长得像 v0的熟悉感。它适合生成某个页面、组件或交互片段，再由开发者继续改信息结构、视觉节奏和品牌细节；不适合把完整产品判断、信息架构和审美方向都交给它。v0 也一直在变，但 Vercel 作为一个有历史积累的 Web 应用平台，他们很难走向 All in AI 而抛弃前端开发者与设计师对前端系统的介入。</p><p><a class="link"   href="https://claude.com/product/design" >Claude Design<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 更像是 coding 前的视觉工作台。它不负责把整个前端工程搭好，而是先把一个模糊的页面想法变成可看的原型、页面方向或设计 artifact。对技术出身的 Vibe Coder 来说，这一步很有用：你不必在代码里猜高级一点到底是什么，可以先看到一个界面，再判断信息密度、布局节奏和视觉气质对不对。然后根据自己的感觉进行下一步 Vibe Designing。</p><p>它的工作逻辑不是让模型凭空画 UI，而是尽量先吃上下文。官方资料里提到，Claude Design 可以从代码库、设计文件、上传素材里提取 design system，包括组件、颜色、字体和已有模式，再用这些东西生成新的设计。换成开发者语言，就是先把项目里的视觉约束喂给模型，减少它现场发明按钮、卡片和配色的机会。</p><p>所以 Claude Design 最适合做三类事：探索首页或 dashboard 的视觉方向，做一个能点击&#x2F;能评审的交互原型，或者把一个产品想法整理成演示（HTML Slides）和交接材料（文档材料或网页完成的动画）。它可以和 Claude Code 衔接，例如同步 design system，或者把更清楚的设计方向交给 coding agent 实现。但它不是生产级前端本身。真正落地时，还是要回到工程项目里处理组件抽象、状态、数据、响应式和浏览器验收。Claude Design 也带有一层内部校验：它会把生成结果和导入的 design system 对照，在你看到之前做一轮修正，他的任务是进行迭代的美学和设计优化，而不是代码本身。</p><p><a class="link"   href="https://github.com/nexu-io/open-design" >Open Design<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是更接近 Claude Design 替代品的开源项目。README 直接写自己是 open-source Claude Design alternative，local-first、native desktop app，并把 skills、<code>DESIGN.md</code> design systems、plugins、sandboxed iframe preview、HTML&#x2F;PDF&#x2F;PPTX&#x2F;MP4 导出、多 agent&#x2F;CLI 接入放到一个本地工作台里。我们输入 brief 并选择大致希望的设计模式，通过内部辅助材料的拼接，然后调度 Coding Agent 去生成所需的前端系统。虽然支持多种导出格式，但 HTML 依旧是这个系统的核心。</p><p>这类工具的价值，是把 Claude Design 机制做成一套本地工作台。想找 Claude Design 开源替代，又希望把 agent 和设计系统放在本地流程里，Open Design 值得试。风险也很直接：项目变化快，最好先拿一个小页面或原型试，当然对于一个 Vibe Designer 来说，手里其实也没有什么已经上线的生产项目，往往是一些个人玩具或 Startup 尝试，能够低成本获得一套不错的前端这是个很好的选择，不至于被 Claude Design 彻底套牢。</p><p><a class="link"   href="https://github.com/alchaincyf/huashu-design" >Huashu Design<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则在前面的基础上都向后退了一步。它不是 Open Design 那种桌面&#x2F;网页设计工作台，也不是生产 Web App 框架。更准确的说法是：它把 Claude Design 的一些思路 Skill 化了，包括设计上下文、品牌资产协议、反 AI slop、设计变体、评审和导出。从而方便我们在不同的 Coding Agent 产品里利用这些能力。OpenDesign 明确吸收了 Huashu Design，两者整体在解决问题形态类似但产品风格不同。</p><p>Huashu Design 的 README 和 <code>SKILL.md</code> 把定位写得很清楚：用 HTML 做高保真原型、交互 demo、幻灯片、动画、设计变体、设计方向顾问和专家评审。仓库里有 Playwright、pptxgenjs、sharp、pdf-lib，脚本覆盖 PDF&#x2F;PPTX&#x2F;MP4&#x2F;GIF 导出，references 里有品牌资产协议、反 AI slop、设计风格、critique guide、动画和验证流程。它还专门对比了 Claude Design 与 huashu-design：前者是浏览器里的图形产品，后者是 agent 里的 Skill，交付物也从画布&#x2F;Figma 导出转向 HTML、MP4、GIF、可编辑 PPTX 和 PDF。所以它更像 Claude Design 思路的开源 Skill 化旁路。用它做生产前端并不合适，但拿它来探索视觉方向、生成 PPT、动画、信息图、原型和设计评审材料，很有参考价值。</p><p><a class="link"   href="https://github.com/abi/screenshot-to-code" >screenshot-to-code<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 解决的是另一个实际问题：说不清想要什么，但能指着图说「像这个」。README 支持 screenshots、mockups、Figma designs、screen recordings 到 HTML&#x2F;Tailwind、React&#x2F;Tailwind、Vue&#x2F;Tailwind 等代码；源码里有 React&#x2F;Vite 前端、FastAPI 后端、prompt pipeline 和 Playwright screenshot preview。</p><p>它的价值是把视觉参考变成硬约束。真实参考页面、竞品截图、手绘草图，都比「高级一点」「现代一点」这种 prompt 更可靠。短板也明显：越接近还原截图，越可能得到难维护的布局。生成后还要整理组件、状态和响应式。当然前面的产品也都支持了类似的功能，screenshot-to-code 目前更像是一个历史遗物。</p><h2 id="给-coding-agent-加审美约束"><a href="#给-coding-agent-加审美约束" class="headerlink" title="给 coding agent 加审美约束"></a>给 coding agent 加审美约束</h2><p>AI 做出来的页面经常不是大结构全错，而是细节的局部疏漏。按钮状态、表单间距、弹窗层级、hover、focus、loading、empty、error，单独看都小，叠起来就是质感。审美约束不只是风格好看，也包括别让模型每次都从空白 CSS 开始编。</p><p><a class="link"   href="https://ui.shadcn.com/" >shadcn&#x2F;ui<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 现在几乎绕不开。它的 README 说得很清楚：Open Source、Open Code，用它来 build your own component library。它不是黑盒 npm 组件库，而是通过 registry&#x2F;CLI 把组件源码放进你的项目。button、dialog 等组件基于 Radix、Tailwind、class-variance-authority，状态、focus ring、disabled、ARIA、dark mode 都有现成处理。shadcn&#x2F;ui 能把 AI 从现场发明基础控件拉回来。短板是同质化。如果什么都用默认 shadcn，页面稳定的像以前见过的东西。更好的用法是把它当底座，再在排版、信息密度、颜色和少量关键组件上做差异。</p><p>另一半问题是审美判断 Skill 。它们不会替代设计师，但能把很多本来靠经验的约束写进 agent 的工作方式里。</p><p><a class="link"   href="https://github.com/anthropics/skills/tree/main/skills/frontend-design" >frontend-design<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是 Anthropic skills 仓库里的前端设计 Skill。它的 <code>SKILL.md</code> 要求先把 subject、audience、single job、palette、type、layout、signature 想清楚，再写代码；还会提醒模型避开暖色奶油背景、黑底荧光点、报纸式排版这些默认套路。它不提供组件，重点是把不要太模板写进 agent 的工作方式。landing page、产品页、品牌页，或者任何从零开始的页面，都可以先让它介入，只要我们需要一些风格参考。</p><p><a class="link"   href="https://github.com/ConardLi/garden-skills/tree/main/skills/web-design-engineer" >web-design-engineer<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 更像一位 HTML-first 的设计工程师。<code>SKILL.md</code> 里有事实验证、设计上下文、风格 recipe、设计系统声明、v0 草稿、浏览器验证、五维评审和反套路清单。它比 frontend-design 更重，也更像完整工作流。页面、dashboard、原型、slide deck、可视化都适合；小改按钮时用它会显得过度。</p><p>Huashu Design 也可以放在这一类里理解。它一方面能生成 HTML 视觉 artifact，另一方面也提供了品牌资产协议、反 AI slop、设计评审和风格探索规则。对技术用户来说，它的价值还在于把怎样避免一眼 AI 味写成了 agent 能执行的清单。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>上面这些工具名字很多，但问题并不复杂：它们都在减少 AI 的自由发挥。</p><p>v0 让 AI 从成熟组件和前端代码出发；Claude Design、Open Design、Huashu Design 让视觉方向先变成可观察的 artifact；screenshot-to-code 把真实参考图变成约束；shadcn&#x2F;ui 提供基础组件底座；frontend-design 和 web-design-engineer 把审美判断前置。</p><p>生成闭环也很重要。成熟工具通常不会让 AI 写完代码就结束，而是提供预览、截图、点击、控制台、网络请求和响应式检查的入口。浏览器里的反馈非常关键，但本文不展开这类工具。这里只需要记住一点：能看见、能点击、能截图、能报错，才有机会把页面从像代码生成的改成真实可用的。</p><p>如果目标是生成一个能放进工程里继续改的页面或组件草稿，优先看 v0。它的下限高，适合技术用户快速拿到 React&#x2F;Tailwind&#x2F;shadcn 生态里的可改代码。</p><p>如果问题是不知道界面该长什么样，不要急着进完整应用生成器。Claude Design、Open Design、Huashu Design、screenshot-to-code 更适合先找视觉方向。Open Design 更像完整开源工作台，Huashu Design 更像 Claude Design 思路的 Skill 化旁路，screenshot-to-code 适合有明确截图参考时使用。</p><p>如果界面已经能跑，但总有廉价感，先检查基础组件和状态。shadcn&#x2F;ui 可以做底座；frontend-design 和 web-design-engineer 把设计判断前置。</p><p>真正要避免一眼 AI 味，不要把希望押在一句更长的 prompt 上。真实参考、明确场景、稳定组件、风格约束、可运行预览和浏览器反馈，这些东西比形容词管用。本文提到的这些工具，就是在帮助一个不了解设计的人，能够完成这些工作</p><h2 id="附录：不作为本文主线的工具"><a href="#附录：不作为本文主线的工具" class="headerlink" title="附录：不作为本文主线的工具"></a>附录：不作为本文主线的工具</h2><p>下面这些工具不是没价值，只是和本文的主问题有一点距离。它们更适合快速生成完整项目、验证 MVP、已有设计稿转代码、线框、营销站或 no-code 网站。</p><ul><li><a class="link"   href="https://lovable.dev/" >Lovable<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合把产品想法快速变成 full-stack MVP。它把自然语言生成、真实代码、发布、项目知识、设计系统、Supabase、支付和域名等能力打包在一起。需求复杂后，数据模型、权限和代码维护仍然要认真审查。</li><li><a class="link"   href="https://replit.com/ai" >Replit Agent<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合不想配置本地环境、希望在在线 IDE 里边生成边运行的人。它很适合想法验证和可部署小应用，但视觉质感通常还需要后续组件和设计约束补上。</li><li><a class="link"   href="https://bolt.new/" >Bolt.new<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合在浏览器里完成生成、运行、编辑。它的优势是反馈快，短板是默认仍然走 prompt-to-app 叙事，不一定适合做精细视觉方向探索。</li><li><a class="link"   href="https://github.com/stackblitz-labs/bolt.diy" >bolt.diy<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：Bolt 路线的开源版本，核心是 Remix&#x2F;Vite、WebContainer、xterm、AI SDK，以及部署、仓库、Supabase 等 API。适合想研究或自托管这类 app builder 的技术用户。</li><li><a class="link"   href="https://github.com/dyad-sh/dyad" >Dyad<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：本地开源 app builder，源码里能看到 Electron&#x2F;Vite、AI SDK、Monaco、xterm、SQLite&#x2F;Drizzle、Supabase&#x2F;Neon&#x2F;Vercel SDK、Playwright、preview sync、screenshot client 和 component selector。适合重视本地控制、隐私、BYOK、可迁移性的开发者。</li><li>Base44、Emergent、Firebase Studio、Create、Anything：都属于值得观察的 prompt-to-app &#x2F; no-code 应用生成方向。它们可以作为原型工具或产品验证工具，但不在本文正文展开。</li><li><a class="link"   href="https://www.figma.com/make/" >Figma Make<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合已经在 Figma 生态里做 prompt-to-prototype 和协作的人。</li><li><a class="link"   href="https://stitch.withgoogle.com/" >Google Stitch<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合从 prompt 或图片探索 UI 方向，再导出到设计&#x2F;代码链路。</li><li><a class="link"   href="https://help.figma.com/hc/en-us/articles/32132100833559-Guide-to-the-Figma-MCP-server" >Figma MCP Server<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合把真实 Figma 文件、变量、组件和布局信息交给 coding agent。</li><li><a class="link"   href="https://www.builder.io/m/design-to-code" >Builder.io Visual Copilot<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合把已有 Figma 设计稿转成前端代码，再由工程侧整理。</li><li><a class="link"   href="https://www.locofy.ai/" >Locofy<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合设计稿到 React&#x2F;Next&#x2F;HTML 的快速工程起步。</li><li><a class="link"   href="https://www.animaapp.com/" >Anima<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合设计师和前端之间的 design-to-code 协作，但输出仍需工程审查。</li><li><a class="link"   href="https://www.framer.com/ai/" >Framer AI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合个人站、作品集、营销页，不是复杂应用前端主路线。</li><li><a class="link"   href="https://webflow.com/ai" >Webflow AI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合品牌站、CMS、营销网站和 no-code 发布。</li><li><a class="link"   href="https://www.relume.io/" >Relume<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合先生成 sitemap 和 wireframe，帮非设计师理清信息架构。</li><li><a class="link"   href="https://uizard.io/" >Uizard<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合产品经理、创业者从草图或 prompt 快速得到 wireframe&#x2F;mockup。</li><li><a class="link"   href="https://www.visily.ai/" >Visily<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：适合非设计背景团队做早期 UI 草图和讨论材料。</li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/22/ai-frontend-design-tools/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/22/ai-frontend-design-tools/"/>
    <published>2026-06-21T23:00:00.000Z</published>
    <summary>A practical survey for technical vibe coders choosing AI frontend tools: UI generators, visual workbenches, component systems, skills, MCPs, and feedback loops that reduce generic AI-looking UI.</summary>
    <title>AI Frontend Tools: Choosing the Right Stack to Avoid Generic AI UI</title>
    <updated>2026-07-01T15:56:19.868Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Systems" scheme="https://hyacehila.github.io/categories/agent-systems/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Game AI" scheme="https://hyacehila.github.io/tags/Game-AI/"/>
    <category term="Decision Making" scheme="https://hyacehila.github.io/tags/Decision-Making/"/>
    <content>
      <![CDATA[<p>最近聊 NPC 智能时，很多人的第一反应已经变成了 LLM 对话、角色扮演、长期记忆、会自己接任务的数字伙伴。这符合最近的流行趋势，我想大部分研究游戏 NPC 的人目前应该都在做这个。但如果把视角稍微往前挪一点，游戏行业很早就已经在做一种非常经典的 Agent 系统：一个 NPC 观察世界，维护自己的内部状态，选择下一步行动，再通过移动、攻击、交易、对话、逃跑或协作去改变世界。LLM 才出来几年，但游戏 AI 至少已经十几年了。</p><p>只是这套传统游戏 AI 通常不叫 Agent。它可能叫敌人 AI、战斗 AI、队友 AI、怪物行为、Boss 逻辑、NPC Brain，或者干脆叫行为树。但从系统结构上看，它非常符合 Agent 的基本定义：它被放在一个环境里，有可观察的信息，有目标或偏好，有可执行动作，也会因为环境反馈而改变下一步行为。</p><p>这篇文章不讨论“让 NPC 接入大模型聊天”这一类新问题，而是从生成式模型出现之前的游戏 AI 讲起。我们会把 NPC 看成一种传统 Agent，看看它是怎样被拆成感知、状态、决策、行为和动作的；再用小白能读懂的方式解释脚本、有限状态机、行为树、效用 AI、GOAP 和 HTN。最后再回到今天的 LLM Agent，看看新旧两种 Agent 到底像在哪里，又不一样在哪里。回顾历史，才能更好的去理解现在应该做什么。</p><h2 id="先把-NPC-想成一个循环"><a href="#先把-NPC-想成一个循环" class="headerlink" title="先把 NPC 想成一个循环"></a>先把 NPC 想成一个循环</h2><p>游戏里的 NPC 不是一段静止的设定文案，也不是一张会播放动画的皮肤。它存在于游戏循环里。游戏引擎不断推进时间，场景里的玩家、怪物、道具、声音、子弹、任务状态都在变化。NPC 的智能不是一次性算出来的，而是在每一帧或每隔几帧反复更新。</p><p>一个最朴素的 NPC Agent 循环大概是这样：</p><pre class="mermaid">flowchart LR  A["感知<br/>看到玩家、听到声音、读取任务状态"] --> B["世界状态 / 黑板<br/>敌人位置、血量、警戒值、目标"]  B --> C["决策<br/>选择巡逻、追击、攻击、撤退、求援"]  C --> D["行为<br/>执行一段可持续的动作流程"]  D --> E["动作<br/>移动、瞄准、播放动画、发射技能"]  E --> F["环境反馈<br/>玩家逃走、受到伤害、目标死亡"]  F --> A</pre><p>这张图里有几个关键词。</p><p>第一是感知。NPC 不应该知道整个宇宙的一切。一个守卫可能只能看到视野锥里的玩家，听到附近的脚步声，记住刚才被攻击的方向。即使程序员在内存里能拿到全部对象，设计上也会故意限制 NPC 的信息来源。信息来源决定了他能做到什么，而 NPC 能做到什么和玩家体验息息相关。</p><p>第二是状态。NPC 需要把感知到的信息整理成自己能用的形式。玩家在不在视野里，最后一次看到玩家的位置在哪里，当前血量是否危险，队友是否正在求援，任务目标是否已经完成，这些信息会被写入一个局部状态。有些项目会把它叫黑板，意思是很多模块都可以在上面读写临时信息。</p><p>第三是决策。决策层回答现在该做什么。如果玩家很近就攻击，如果玩家消失就搜索，如果血量太低就撤退，如果队友需要支援就过去。这听起来像几条 if-else，但真实项目一复杂，决策就会变成一个专门的问题。</p><p>第四是行为。行为不是一个瞬间按钮，而是一段持续过程。追击需要寻路、转向、避障、保持距离；攻击需要瞄准、等待前摇、播放动画、结算伤害、进入冷却。决策层只说“我要攻击”，行为层负责把这个意图变成一串可以执行的步骤。</p><p>第五是动作。动作是最贴近引擎的一层，涉及动画、物理、寻路、技能、声音、特效、网络同步。动作是一切的基础，一个决策看起来很聪明，但如果动画接不上、寻路卡住、技能前摇不合理，玩家看到的仍然是一个很笨的 NPC。</p><p>所以，传统游戏 NPC AI 的核心是把一个持续行动的实体放进可控的闭环里。它必须能跑得动，能被调试，能被策划修改，能在不同机器上表现稳定，还要在玩家看来合理。</p><h2 id="决策技术的谱系"><a href="#决策技术的谱系" class="headerlink" title="决策技术的谱系"></a>决策技术的谱系</h2><p>不同游戏对 NPC 的要求差异很大。一个 2D 平台跳跃游戏里的巡逻怪，可能只需要左右移动和碰到玩家后攻击。一个潜行游戏里的守卫，需要巡逻、听声、搜查、呼叫支援、丢失目标后回到岗位。一个开放世界 RPG 的同伴，需要跟随玩家、参与战斗、治疗队友、避免挡路、响应剧情。一个策略游戏里的 AI，还要考虑资源、科技、兵种、地图控制和长期计划。</p><p>因此游戏 AI 没有一种万能技术。更常见的是技术谱系：越往左越直接、越可控；越往右越抽象、越能表达复杂目标，但实现和调试成本也更高。</p><pre class="mermaid">flowchart TB  A["脚本 / 规则<br/>直接写死条件和动作"] --> B["FSM<br/>把行为拆成有限状态"]  B --> C["Behavior Tree<br/>把决策组织成层级任务"]  C --> D["Utility AI<br/>为候选动作打分"]  D --> E["GOAP<br/>根据目标自动规划动作序列"]  E --> F["HTN<br/>把高层任务分解成低层步骤"]  G["RL / ANN / GA / SA / MCTS<br/>学习、搜索、优化、模拟"] -. "常作为补充能力" .-> C  G -. "也可辅助" .-> D  G -. "也可辅助" .-> E</pre><p>接下来我们按这条线看。每种方法都先讲它解决什么问题，再用一个虚构游戏场景说明它怎么工作。</p><h2 id="感知和黑板：决策之前先有世界"><a href="#感知和黑板：决策之前先有世界" class="headerlink" title="感知和黑板：决策之前先有世界"></a>感知和黑板：决策之前先有世界</h2><p>在讲具体决策算法之前，还有一层经常被忽略：NPC 到底怎样知道世界。很多新手会把 AI NPC 理解成写一个聪明的选择函数，但真实游戏里，选择函数吃到什么信息，往往比选择函数本身更重要。</p><p>先看感知。感知不是简单地读取玩家坐标。一个更像人的守卫需要视野、听觉、触觉和事件通知。视野会考虑距离、角度、遮挡、光照和玩家姿态；听觉会考虑声音强度、传播距离、材质和环境噪声；事件通知可能来自队友呼救、警报器、任务脚本或玩家刚刚触发的机关。设计者会刻意让这些信息不完整，因为不完整才会产生悬念。玩家躲在箱子后面时，守卫不该直接知道玩家位置，而是只知道刚才那边有声音或最后一次看见玩家在拐角处。</p><p>再看记忆。NPC 通常不应该每一帧都把感知结果清空。它需要记住最后一次看到玩家的位置，记住刚才听到的声音来源，记住某个门已经被打开，记住自己刚刚被哪个敌人攻击。这个记忆可以很短，只持续几秒；也可以更长，比如模拟经营游戏里的居民记住某个角色和自己的关系。记忆让 NPC 不至于像失忆机器，也让玩家能理解它为什么继续搜索、为什么怀疑某个区域、为什么追着一个方向跑。</p><p>黑板就是把这些信息集中放置的一种常见方式。行为树节点、Utility 评分、GOAP 动作、寻路模块都可以读取黑板。比如黑板上可能有：</p><ul><li><code>enemy_visible</code>: 当前是否看见敌人。</li><li><code>last_enemy_position</code>: 最后一次看见敌人的位置。</li><li><code>health_ratio</code>: 当前血量比例。</li><li><code>cover_position</code>: 推荐掩体位置。</li><li><code>current_goal</code>: 当前高层目标。</li><li><code>suspicion_level</code>: 警戒或怀疑程度。</li></ul><p>黑板的好处是解耦。感知系统负责写入我看到了什么，决策系统负责读取现在我相信什么，动作系统负责执行我要去哪里。但黑板也可能变成垃圾堆。如果任何模块都随便写变量，变量命名不清、生命周期不明、谁覆盖谁说不清，问题就会非常难查。因此成熟项目通常会给黑板变量定义类型、默认值、过期时间、写入权限和调试显示，不能让每一个开发者都随便的去写黑板。</p><p>还有一个关键点：NPC 的世界状态不等于真实世界状态。真实世界里玩家可能躲在门后，但 NPC 的黑板里只记录玩家最后出现在门口。这种差异正是游戏 AI 的表现空间。优秀的 NPC 不是知道真相，而是根据有限信息做出合理反应。潜行游戏、恐怖游戏、战术射击都很依赖这一点。玩家会观察 NPC 的信息边界，并利用这些边界制定策略。</p><p>所以，传统 Agent 的智能不只在决策层。感知给它输入，黑板给它记忆，决策算法只是基于这些信息做选择。一个很普通的 FSM，如果配上合理的视野、听觉、记忆和搜索行为，也会显得可信；一个很复杂的规划器，如果拿到的是作弊式全局信息，反而会破坏体验。无论是开发传统的决策系统还是开发基于 LLM 的 NPC，控制信息的感知与记忆都是我们要考虑的问题，只是角度可能不同。</p><h2 id="脚本：最直觉的-NPC-智能"><a href="#脚本：最直觉的-NPC-智能" class="headerlink" title="脚本：最直觉的 NPC 智能"></a>脚本：最直觉的 NPC 智能</h2><p>最早、也最容易理解的 游戏 AI 是脚本。脚本的意思很简单：在特定条件下执行特定动作。玩家进入房间，敌人刷出来；玩家靠近商人，商人转身说话；Boss 血量低于一半，进入第二阶段；玩家拿到钥匙，门口守卫改口放行。</p><p>脚本的优点是清楚、便宜、稳定。它很适合做剧情事件、一次性演出、教学关卡、机关触发和简单怪物逻辑。策划想要一个确定效果，脚本往往最直接。</p><p>问题是脚本一多，行为之间的关系会变得难以维护。比如一个守卫既要巡逻，又要看见玩家后追击，还要听到声音后调查，还要血量低时逃跑，还要在队长死亡后士气崩溃。如果所有逻辑都写成 if-else，就很快变成一团互相覆盖的条件。</p><p>一个简单脚本可能长这样：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">每次更新守卫（随游戏时间流逝决策）:</span><br><span class="line">  如果守卫死亡:</span><br><span class="line">    播放死亡动画</span><br><span class="line">    停止更新</span><br><span class="line"></span><br><span class="line">  如果看见玩家:</span><br><span class="line">    朝玩家移动</span><br><span class="line">    如果距离足够近:</span><br><span class="line">      攻击玩家</span><br><span class="line">  否则如果听到可疑声音:</span><br><span class="line">    移动到声音来源</span><br><span class="line">  否则:</span><br><span class="line">    沿巡逻路线移动</span><br></pre></td></tr></table></figure></div><p>这种写法适合入门，但它把“当前正在做什么”藏在条件顺序里。假设守卫正在调查声音，下一帧突然又看见玩家，脚本会马上切到追击，这也许合理。可如果守卫正在播放一个无法中断的开门动画呢？如果它刚刚丢失玩家，应该搜索几秒，而不是立刻回巡逻呢？脚本本身没有给这些状态持续性一个清晰位置，不同的状态理应带来不同的决策逻辑，而脚本只能把这一切放到 if-else 里，这处理不了复杂的逻辑，而只能处理一个确定性的效果。</p><p>于是有限状态机出现了。</p><h2 id="FSM：把-NPC-拆成几个明确状态"><a href="#FSM：把-NPC-拆成几个明确状态" class="headerlink" title="FSM：把 NPC 拆成几个明确状态"></a>FSM：把 NPC 拆成几个明确状态</h2><p>FSM 是 Finite State Machine，有限状态机。它的核心思想是：一个 NPC 在任意时刻只处于有限个状态之一，每个状态负责一类行为，状态之间通过条件切换。</p><p>还是守卫例子。我们可以给它五个状态：</p><ul><li><code>Patrol</code>：巡逻。</li><li><code>Investigate</code>：调查。</li><li><code>Chase</code>：追击玩家。</li><li><code>Attack</code>：攻击玩家。</li><li><code>Flee</code>：逃跑或求援。</li></ul><p>这样一来，NPC 当前到底在做什么就清楚了。每个状态有自己的进入逻辑、更新逻辑和退出逻辑并配合行为与动作。比如进入 <code>Attack</code> 时播放拔刀动画，更新时检查攻击距离和冷却，退出时停止攻击特效。</p><p>伪代码可以写成这样：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">状态 Patrol:</span><br><span class="line">  沿路线移动</span><br><span class="line">  如果听到声音: 切换到 Investigate</span><br><span class="line">  如果看见玩家: 切换到 Chase</span><br><span class="line">  如果血量过低: 切换到 Flee</span><br><span class="line"></span><br><span class="line">状态 Chase:</span><br><span class="line">  向玩家最后位置移动</span><br><span class="line">  如果进入攻击距离: 切换到 Attack</span><br><span class="line">  如果丢失玩家超过 5 秒: 切换到 Investigate</span><br><span class="line">  如果血量过低: 切换到 Flee</span><br><span class="line"></span><br><span class="line">状态 Attack:</span><br><span class="line">  面向玩家并攻击</span><br><span class="line">  如果玩家离开攻击距离: 切换到 Chase</span><br><span class="line">  如果血量过低: 切换到 Flee</span><br></pre></td></tr></table></figure></div><p>FSM 的好处在于简单、明确、成本低。它很适合处理小规模行为：状态数量有限，转换条件清楚，后续增量需求也不多。比如简单小兵、机关、载具、页面流程，或者不太复杂的对话和交付逻辑，都可以用 FSM 做。它可解释、可调试，也容易画成状态图；运行时通常只需要检查当前状态和少量转换条件，性能开销也比较低。</p><p>它的典型问题是状态爆炸。假设我们又加了“中毒”“被冰冻”“受到嘲讽”“携带旗帜”“保护 VIP”“夜间警戒增强”等条件，原来的几个状态就会被迫和这些条件组合。你可能开始写 <code>ChaseWhilePoisoned</code>、<code>AttackWhileProtectingVIP</code>、<code>FleeWithFlag</code>。状态越来越多，切换规则越来越乱，最后谁也不敢改。也就是说，FSM 和脚本一样，适合边界清楚的小问题；一旦问题本身持续变复杂，状态数量和状态转换会急剧增加，维护成本会很快超过它一开始带来的简洁性。</p><p>另一个问题是层级表达不足。比如战斗本身可以包含追击、攻击、躲避、换弹、找掩体；非战斗  又可以包含巡逻、闲聊、看风景、修理设备。普通 FSM 很难自然表达这种嵌套结构，只能把层级关系压平成更多状态和更多转换。虽然可以继续发展成分层 FSM，但很多游戏项目会选择另一种更适合层级组织的形式：行为树。</p><h2 id="Behavior-Tree：把决策组织成一棵任务树"><a href="#Behavior-Tree：把决策组织成一棵任务树" class="headerlink" title="Behavior Tree：把决策组织成一棵任务树"></a>Behavior Tree：把决策组织成一棵任务树</h2><p>Behavior Tree，行为树，常被用在游戏 AI 里。它把 NPC 的行为拆成很多小节点，再用树结构组合起来。每个节点运行后返回三种状态之一：</p><ul><li><code>Success</code>：成功。</li><li><code>Failure</code>：失败。</li><li><code>Running</code>：还在执行。</li></ul><p>行为树里常见两类组合节点。<code>Selector</code> 像“从左到右找一个能做的方案”，只要某个子节点成功或正在运行，它就停止尝试后面的节点。<code>Sequence</code> 像“按顺序完成一组步骤”，只要某个子节点失败，整个序列就失败。</p><p>一个守卫行为树可以这样理解：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">根节点 Selector:</span><br><span class="line">  Sequence: 处理危险</span><br><span class="line">    条件: 血量过低?</span><br><span class="line">    动作: 寻找掩体</span><br><span class="line">    动作: 呼叫支援</span><br><span class="line"></span><br><span class="line">  Sequence: 战斗</span><br><span class="line">    条件: 看见玩家?</span><br><span class="line">    动作: 移动到攻击距离</span><br><span class="line">    动作: 攻击玩家</span><br><span class="line"></span><br><span class="line">  Sequence: 调查</span><br><span class="line">    条件: 听到声音?</span><br><span class="line">    动作: 移动到声音来源</span><br><span class="line">    动作: 搜索附近区域</span><br><span class="line"></span><br><span class="line">  动作: 巡逻</span><br></pre></td></tr></table></figure></div><p>这棵树的意思是：先看是否处于危险，如果危险就优先处理；否则如果能战斗就战斗；否则如果有可疑声音就调查；都没有就巡逻。它比一大坨 if-else 更清楚，因为每个行为被拆成节点，组合关系也显式写在树上。</p><p>行为树特别适合游戏开发有几个原因。</p><p>第一，它能表达优先级。把紧急行为放在树的左边，普通行为放在右边，就可以形成一种自然的抢占逻辑。血量低时逃跑比巡逻优先，玩家进入攻击范围比闲聊优先。</p><p>第二，它适合复用。<code>移动到目标</code>、<code>检查距离</code>、<code>播放动画</code>、<code>等待冷却</code> 都可以做成节点，在不同敌人之间复用。</p><p>第三，它适合工具化。行为树可以做成可视化编辑器，让策划和程序一起调整。策划不一定要写代码，也能看懂“这个敌人先判断血量，再判断视野，再决定攻击或巡逻”。</p><p>第四，它天然支持持续行为。一个动作节点可以返回 <code>Running</code>，表示这个行为还没有完成。比如移动到目标点需要多帧才能完成，行为树下一帧继续 tick 这个节点即可。</p><p>行为树也不是银弹。树越大，阅读成本越高。优先级如果都靠节点顺序表达，后期可能出现为什么这个行为老是抢走控制权的问题。很多复杂行为还需要共享黑板变量，而黑板写得太随意，又会变成另一种隐形耦合。</p><p>行为树最适合的问题是把复杂行为拆成层级任务。但它不擅长回答另一个问题：如果有很多可选动作，每个动作都不是绝对对错，只是有不同程度的好坏，该怎么选？</p><p>这就是 Utility AI 关心的问题。</p><h2 id="Utility-AI：不问能不能做，而问值不值得做"><a href="#Utility-AI：不问能不能做，而问值不值得做" class="headerlink" title="Utility AI：不问能不能做，而问值不值得做"></a>Utility AI：不问能不能做，而问值不值得做</h2><p>Utility AI 可以翻译成效用 AI。它的想法很像人类做选择：不是简单判断能不能做，而是给每个候选行为打分，选择当前最有价值的行为。如果你是传统统计&#x2F; ML 出身的，可以参考类似 SHAP 的效用来理解。</p><p>例如一个队友 NPC 可能有这些选择：</p><ul><li>攻击最近敌人。</li><li>治疗玩家。</li><li>治疗自己。</li><li>躲到掩体后。</li><li>捡起附近弹药。</li><li>复活倒地队友。</li></ul><p>这些行为通常都能做，但重要程度会随场景变化。玩家血量只剩 10%，治疗玩家分数很高；NPC 自己快死了，躲掩体或自救分数很高；敌人残血且离得很近，攻击分数可能更高；弹药快没了，捡弹药分数升高。</p><p>一个很小的 Utility AI 可以这样写：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">候选行为:</span><br><span class="line">  治疗玩家:</span><br><span class="line">    分数 = 玩家受伤程度 * 距离可达性 * 治疗技能可用</span><br><span class="line"></span><br><span class="line">  攻击敌人:</span><br><span class="line">    分数 = 敌人威胁度 * 命中概率 * 武器弹药充足度</span><br><span class="line"></span><br><span class="line">  躲避:</span><br><span class="line">    分数 = 自己受伤程度 * 附近掩体质量</span><br><span class="line"></span><br><span class="line">每次决策:</span><br><span class="line">  计算所有候选行为分数</span><br><span class="line">  选择最高分行为</span><br><span class="line">  如果最高分比当前行为高出足够多:</span><br><span class="line">    切换行为</span><br></pre></td></tr></table></figure></div><p>这里有一个细节很重要：通常不会只要分数稍微高一点就立刻切换。否则 NPC 会在“攻击”和“治疗”之间疯狂摇摆。工程上常用滞后、冷却、最短执行时间、切换成本等机制，让行为更稳定。</p><p>Utility AI 的优点是适合多因素权衡。它不像 FSM 那样要求你提前画出所有状态，也不像行为树那样把优先级固定在树结构里。它可以把血量、距离、敌人威胁、资源、任务目标、队友状态都转成分数，然后比较。</p><p>它的难点也在这里：分数怎么设计？一个行为的分数曲线太陡，NPC 会过早执行；太平，NPC 又像没反应。多个分数相乘还是相加？某些条件是否应该直接归零？一个看似合理的公式，在真实关卡里可能表现很怪。</p><p>所以 Utility AI 很依赖调试工具。设计者需要看到当前每个行为的分数，以及每个因素贡献了多少。否则玩家说“队友为什么不救我”，策划和程序只能猜。</p><p>Utility AI 很适合做即时选择，但有时 NPC 需要的不只是“下一步做什么”，而是“为了达成目标，接下来一串动作应该怎么安排”。比如想攻击玩家，但没有弹药；想开门，但没有钥匙；想制造药水，但缺材料。此时就进入规划问题。</p><h2 id="GOAP：让-NPC-为目标生成行动计划"><a href="#GOAP：让-NPC-为目标生成行动计划" class="headerlink" title="GOAP：让 NPC 为目标生成行动计划"></a>GOAP：让 NPC 为目标生成行动计划</h2><p>GOAP 是 Goal-Oriented Action Planning，目标导向行动规划。它不是让你写一条固定流程，而是让你把世界拆成一组事实，把 NPC 能做的事情拆成一组动作，再交给规划器去拼出一条行动路线。</p><p>如果你要在项目里使用 GOAP，通常要做三件事。</p><p>第一，定义世界状态。规划器不能直接理解连续、混乱的游戏世界，所以你要把它翻译成离散事实。比如 <code>有钥匙 = true</code>、<code>仓库门打开 = false</code>、<code>知道玩家位置 = true</code>、<code>玩家被抓住 = false</code>。这些事实可以来自感知系统、任务系统、背包系统、关卡脚本，也可以来自黑板。</p><p>第二，定义目标。目标也是一组希望达成的事实。比如守卫的目标不是一句自然语言抓住玩家，而是 <code>玩家被抓住 = true</code>。治疗型队友的目标可能是 <code>玩家安全 = true</code>，商人的目标可能是 <code>完成交易 = true</code>，居民的目标可能是 <code>自己吃饱 = true</code>。</p><p>第三，定义动作。每个动作至少要有三个部分：前置条件、执行效果、成本。前置条件说明什么时候这个动作可用；执行效果说明动作成功后世界状态会怎样变化；成本说明这个动作有多贵、多慢或多危险。</p><p>举一个虚构潜行游戏里的守卫。当前状态是：守卫没有钥匙，仓库门锁着，但它怀疑玩家躲在仓库。我们可以定义这些动作：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">动作 拿钥匙:</span><br><span class="line">  前置: 知道钥匙位置 = true</span><br><span class="line">  效果: 有钥匙 = true</span><br><span class="line">  成本: 1</span><br><span class="line"></span><br><span class="line">动作 走到仓库门口:</span><br><span class="line">  前置: 知道仓库位置 = true</span><br><span class="line">  效果: 在仓库门口 = true</span><br><span class="line">  成本: 2</span><br><span class="line"></span><br><span class="line">动作 开仓库门:</span><br><span class="line">  前置: 有钥匙 = true, 在仓库门口 = true</span><br><span class="line">  效果: 仓库门打开 = true</span><br><span class="line">  成本: 1</span><br><span class="line"></span><br><span class="line">动作 进入仓库:</span><br><span class="line">  前置: 仓库门打开 = true</span><br><span class="line">  效果: 在仓库内 = true</span><br><span class="line">  成本: 1</span><br><span class="line"></span><br><span class="line">动作 抓住玩家:</span><br><span class="line">  前置: 在仓库内 = true, 看见玩家 = true</span><br><span class="line">  效果: 玩家被抓住 = true</span><br><span class="line">  成本: 1</span><br></pre></td></tr></table></figure></div><p>开发者做到这里，并没有手写“先拿钥匙，再走到仓库门口，再开门，再进仓库”。你只是告诉系统：世界有哪些事实，目标是什么，动作会怎样改变事实。</p><p>背后的 GOAP 系统会做什么？它会从当前世界状态出发，尝试把动作一个个接起来，看看哪条动作序列能让目标事实成立。这个过程本质上是搜索：当前状态是一个节点，执行某个动作会得到一个新状态，规划器不断扩展这些状态，直到找到满足目标的路径。实现上可以用 A*、Dijkstra 或其他搜索策略；游戏里也经常加很多限制，比如最多搜索多少步、多久重新规划一次、哪些 NPC 才允许做复杂规划。</p><p>用刚才的例子，规划器可能得到这样一条计划：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">目标: 玩家被抓住 = true</span><br><span class="line"></span><br><span class="line">当前状态:</span><br><span class="line">  有钥匙 = false</span><br><span class="line">  知道钥匙位置 = true</span><br><span class="line">  知道仓库位置 = true</span><br><span class="line">  仓库门打开 = false</span><br><span class="line"></span><br><span class="line">规划结果:</span><br><span class="line">  拿钥匙</span><br><span class="line">  走到仓库门口</span><br><span class="line">  开仓库门</span><br><span class="line">  进入仓库</span><br><span class="line">  抓住玩家</span><br></pre></td></tr></table></figure></div><p>然后执行系统会逐个执行计划里的动作。这里要注意：规划和执行不是一回事。规划器只是在抽象状态里推演，真正执行还要调用寻路、动画、交互、战斗、物理和任务系统。比如走到仓库门口在计划里只是一个动作，执行时却可能要走导航网格、避开障碍、处理被玩家打断、播放开门动画。</p><p>执行过程中世界也可能变化。玩家可能逃走，钥匙可能被别人拿走，门可能已经被炸开。如果某个动作的前置条件不再满足，或者动作执行失败，NPC 不能继续照着旧计划演下去。常见做法是中止当前计划，把新的世界状态写回黑板，然后重新规划。这样 NPC 看起来才像是真的在根据局势调整，而不是在执行一张过期清单。</p><p>所以 GOAP 的魅力在于涌现感。设计者没有为每一种情况写死流程，而是提供动作积木和状态规则，系统自己组合出路线。如果没有钥匙就去拿钥匙，如果门已经开了就跳过开门，如果敌人太强就先找武器。NPC 看起来像是在想办法。</p><p>它的代价也很清楚。世界状态必须被离散化，动作定义要可靠，搜索空间要受控，执行失败要能回滚和重规划。GOAP 往往适合需要目标感的 NPC：战术敌人、潜行守卫、小队成员、模拟世界中的居民。它能让角色看起来更主动，但前提是你愿意认真建模状态、动作和调试工具。</p><h2 id="HTN：把复杂任务分解成可执行步骤"><a href="#HTN：把复杂任务分解成可执行步骤" class="headerlink" title="HTN：把复杂任务分解成可执行步骤"></a>HTN：把复杂任务分解成可执行步骤</h2><p>HTN 是 Hierarchical Task Network，层级任务网络。它也属于规划，但思路和 GOAP 不太一样。GOAP 更像“我知道目标状态，请帮我搜索一串动作”；HTN 更像“我知道要完成一个高层任务，请按规则把它拆成更小的任务，直到拆成可以直接执行的动作”。</p><p>如果你要使用 HTN，最重要的工作不是定义大量前置条件和效果，而是定义任务如何分解。</p><p>HTN 里通常有两类任务。第一类是复合任务，比如“帮助玩家通过据点”“开店营业”“组织一次进攻”“完成日常巡逻”。复合任务不能直接执行，它必须继续被拆开。第二类是原子任务，比如“移动到掩体”“播放开门动画”“射击三秒”“治疗玩家”。原子任务已经足够具体，可以交给引擎里的动作系统执行。</p><p>开发者还要为复合任务定义方法。方法可以理解成“在某种条件下，这个任务应该怎样拆”。同一个复合任务可以有多个方法，运行时根据当前世界状态选择其中一个。</p><p>比如一个同伴 NPC 的高层任务是“帮助玩家通过据点”。它可以有两种拆法：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">复合任务 帮助玩家通过据点:</span><br><span class="line">  方法 A: 潜行通过</span><br><span class="line">    条件: 玩家未被发现</span><br><span class="line">    子任务:</span><br><span class="line">      标记敌人</span><br><span class="line">      关闭探照灯</span><br><span class="line">      跟随玩家潜入</span><br><span class="line"></span><br><span class="line">  方法 B: 正面交火</span><br><span class="line">    条件: 玩家已被发现</span><br><span class="line">    子任务:</span><br><span class="line">      找掩体</span><br><span class="line">      压制敌人</span><br><span class="line">      治疗玩家</span><br><span class="line">      跟随玩家推进</span><br></pre></td></tr></table></figure></div><p>其中“压制敌人”本身还不是一个引擎动作，它还可以继续拆：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">复合任务 压制敌人:</span><br><span class="line">  方法 默认压制:</span><br><span class="line">    条件: 有可见敌人</span><br><span class="line">    子任务:</span><br><span class="line">      选择高威胁目标</span><br><span class="line">      移动到可射击位置</span><br><span class="line">      瞄准目标</span><br><span class="line">      连续射击三秒</span><br><span class="line">      评估是否换位</span><br></pre></td></tr></table></figure></div><p>背后的 HTN 系统会做什么？它会从一个高层任务开始，检查当前有哪些方法可用，选择一个方法，把任务替换成它的子任务；如果子任务里还有复合任务，就继续分解；直到整棵任务树都被拆成一串原子任务。最后系统得到的不是一个抽象目标，而是一张可执行清单。</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">输入任务:</span><br><span class="line">  帮助玩家通过据点</span><br><span class="line"></span><br><span class="line">当前状态:</span><br><span class="line">  玩家已被发现 = true</span><br><span class="line">  有可见敌人 = true</span><br><span class="line"></span><br><span class="line">HTN 分解过程:</span><br><span class="line">  帮助玩家通过据点</span><br><span class="line">  -&gt; 找掩体 -&gt; 压制敌人 -&gt; 治疗玩家 -&gt; 跟随玩家推进</span><br><span class="line">  -&gt; 找掩体 -&gt; 选择高威胁目标 -&gt; 移动到可射击位置 -&gt; 瞄准目标 -&gt; 连续射击三秒 -&gt; 评估是否换位 -&gt; 治疗玩家 -&gt; 跟随玩家推进</span><br></pre></td></tr></table></figure></div><p>如果某个方法的条件不满足，HTN 规划器会尝试同一个任务的其他方法。比如玩家没有被发现，就选潜行通过；玩家已经被发现，就选正面交火。如果所有方法都不可用，这个任务就分解失败，上层任务可以换另一种方案，或者执行系统可以中止并重新选择高层任务。</p><p>HTN 和行为树有一点像，因为它们都擅长表达层级。但二者关注点不同。行为树通常在运行时反复 tick，一边判断一边执行；HTN 更像先生成一个任务计划，再把计划交给执行器。也就是说，行为树偏“实时控制结构”，HTN 偏“任务分解和计划生成”。当然实际项目里也可以混用：外层行为树决定当前大模式，进入某个模式后用 HTN 生成一段任务计划。</p><p>HTN 的优点是非常贴近设计者的思路。很多游戏行为本来就是任务分解：做饭、巡逻、交易、打扫房间、组织进攻、救援队友。设计者可以把高层流程写得清楚，同时让系统根据条件选择不同拆法。它也更容易接入叙事和任务系统，因为剧情任务、日程系统、阵营行动本来就有层级结构。</p><p>它的代价是前期建模更重。你要定义复合任务、原子任务、方法、条件、子任务顺序，还要处理失败回退。HTN 写得太死，会变成更复杂的脚本；写得太抽象，又难以预测运行结果。它适合中大型行为系统，不一定适合一个只会左右巡逻的小怪。</p><p>可以用一句话区分 GOAP 和 HTN：GOAP 让系统在动作空间里搜索“怎样把世界变成目标状态”；HTN 让系统按照你写好的任务分解规则，把“我要做的大事”拆成一串小事。前者更强调状态和动作效果，后者更强调任务结构和设计者提供的分解知识。</p><h2 id="学习和搜索方法放在哪里"><a href="#学习和搜索方法放在哪里" class="headerlink" title="学习和搜索方法放在哪里"></a>学习和搜索方法放在哪里</h2><p>讲到游戏 AI，很多人会自然想到强化学习、神经网络、遗传算法、模拟退火、蒙特卡洛树搜索。这些当然也是 AI，但它们在传统 NPC 里的位置经常被误解。它们不总是直接控制运行时 NPC，更常见的是作为某个环节的辅助能力。</p><p>强化学习适合让智能体通过试错学习策略。它在棋类、对战模拟、自动测试、平衡性探索、机器人控制等场景很有价值。但商业游戏里的 NPC 不一定适合直接用一个黑箱策略来控制。原因很实际：训练成本高，行为难解释，调试困难，线上表现可能不可控。玩家不只希望 NPC 足够强，还希望它公平、有性格、会犯合理的错。</p><p>神经网络可以用于感知、预测、动画控制、策略近似、难度调节等。比如预测玩家下一步移动方向，判断一个位置是否容易被发现，或者把复杂评分函数压缩成一个模型。但如果神经网络直接决定 NPC 的所有行为，设计者就很难精确控制体验。当然我们也可以说现在的 LLM 就是一个神经网络，当然这样分意义不大。</p><p>遗传算法和模拟退火更像优化工具。它们可以帮助搜索参数组合，例如敌人刷新频率、技能冷却、队伍阵型、赛车路线、关卡布局评分。它们通常不是这个怪物每一帧怎么行动的答案，而是帮助开发者找到更好的配置。</p><p>蒙特卡洛树搜索常见于棋类、卡牌、策略和局部战术模拟。它通过大量模拟评估候选行动，适合规则明确、可快速推演的环境。问题是实时动作游戏通常状态空间巨大，而且每次模拟成本高，所以 MCTS 往往用于局部决策、离线分析或某些特定玩法。</p><p>这几类方法和前面的 FSM、行为树、Utility、GOAP、HTN 并不冲突。更常见的架构是混合式的：顶层仍然用行为树或 HTN 控制可解释流程，局部用 Utility 评分，某些参数由学习方法生成，某些候选路线由搜索算法评估。游戏 AI 的目标不是炫技，而是服务体验。</p><h2 id="为什么传统-NPC-更强调可控"><a href="#为什么传统-NPC-更强调可控" class="headerlink" title="为什么传统 NPC 更强调可控"></a>为什么传统 NPC 更强调可控</h2><p>如果只从论文或 Demo 看，越自动、越聪明、越会涌现，好像就越先进。但游戏开发有一组非常现实的约束。</p><p>第一是实时性。NPC 决策不能卡住游戏。一个开放世界里可能同时有几十个、几百个实体在更新。每个 NPC 都做复杂规划，帧率马上会掉。工程上常见做法是降低更新频率、分层计算、远处 NPC 简化模拟、把昂贵决策摊到多帧执行。</p><p>第二是可调试性。玩家说这个敌人不合理，开发者必须能回放现场，看到它当时看见了什么、黑板里有什么、行为树走到哪个节点、Utility 分数是多少、GOAP 计划为什么失败。没有可观察性，AI 就会变成无法维护的神秘盒子。</p><p>第三是可设计性。游戏 NPC 不是越聪明越好，而是越符合设计目标越好。恐怖游戏里的怪物可能需要压迫感，但不能每次都最优；新手村敌人需要让玩家学会系统，而不是把玩家打崩；队友 NPC 要有帮助，但不能抢走玩家的英雄时刻。AI 的聪明要被体验目标约束。</p><p>第四是确定性。很多游戏需要回放、同步、录像、联机一致性。NPC 行为如果充满不可控随机性，会给调试和网络同步带来麻烦。即使使用随机，也往往要使用可复现的随机种子和明确的概率表。</p><p>第五是生产协作。NPC 行为不是程序一个人写完就结束。策划要调参数，美术要接动画，关卡设计要摆放巡逻路线，音频要接提示音，QA 要复现问题。行为树编辑器、黑板查看器、调试线框、日志、热更新配置，这些工具本身就是游戏 AI 的一部分。</p><p>所以传统游戏 AI 的核心价值不是让 NPC 成为真正的人，而是让它在有限规则下表现得像一个可信的行动者。这个可信很关键。玩家不要求每个敌人都有自由意志，但要求它在游戏规则里讲得通。</p><h2 id="一个完整-NPC-可能怎样组合这些技术"><a href="#一个完整-NPC-可能怎样组合这些技术" class="headerlink" title="一个完整 NPC 可能怎样组合这些技术"></a>一个完整 NPC 可能怎样组合这些技术</h2><p>为了把前面的概念串起来，想象一个虚构动作 RPG 里的队友 NPC。它的职责是跟随玩家、参与战斗、治疗、提醒危险，并在剧情点执行一些特殊动作。</p><p>最外层可以用行为树组织优先级：</p><ul><li>如果剧情强制控制，执行剧情行为。</li><li>如果自己濒死，优先躲避和自救。</li><li>如果玩家倒地，尝试救援。</li><li>如果正在战斗，进入战斗子树。</li><li>如果没有战斗，跟随玩家或待机。</li></ul><p>战斗子树内部可以用 Utility AI 做选择：</p><ul><li>治疗玩家的分数取决于玩家血量、距离、治疗冷却和当前危险程度。</li><li>攻击敌人的分数取决于敌人威胁、命中概率、距离和弹药。</li><li>躲避的分数取决于自身血量、敌人火力和掩体质量。</li></ul><p>遇到复杂目标时，可以用 GOAP 或 HTN：</p><ul><li>玩家被困在门后，NPC 需要找到控制台、解除锁定、回到玩家附近。</li><li>小队准备突入房间，NPC 需要先扔烟雾弹、找掩体、压制敌人，再跟随玩家推进。</li></ul><p>底层动作则交给寻路、动画、技能系统、碰撞和音频系统。AI 决策说“移动到掩体”，动作层要找到具体路径、处理卡住、播放翻滚或蹲伏动画。决策说“治疗玩家”，技能系统要检查距离、朝向、冷却、资源、施法前摇和网络同步。</p><p>这就是为什么游戏 AI 往往是一个系统工程，而不是某个单独算法。FSM、行为树、Utility、GOAP、HTN 都只是决策层的工具。真正的 NPC Agent 还需要感知、记忆、动作、调试、内容工具和性能预算。</p><h2 id="当-LLM-介入游戏-NPC：哪些没变，哪些变了"><a href="#当-LLM-介入游戏-NPC：哪些没变，哪些变了" class="headerlink" title="当 LLM 介入游戏 NPC：哪些没变，哪些变了"></a>当 LLM 介入游戏 NPC：哪些没变，哪些变了</h2><p>生成式 AI 让我们重新想象 NPC：它们可以说更自然的话，记住玩家经历，解释自己的动机，甚至根据玩家的表达临时组织一段回应。但把 LLM 接进游戏，并不等于传统 NPC 架构就可以被整体替换。一个会说话的角色，仍然要在游戏世界里行动；只要它要行动，就绕不开感知、状态、决策、动作和反馈这条闭环。</p><p>没有变的是底层工程关系。LLM 可以参与理解玩家说了什么，也可以生成一段符合角色性格的台词，但它不能直接让角色穿过墙、跳过动画、无视技能冷却，也不能凭空发放任务奖励。NPC 最终能不能移动，要看寻路和物理；能不能攻击，要看技能系统和战斗规则；能不能完成任务，要看任务系统；能不能说某句话，也要看世界观、内容安全和本地化规则。</p><p>所以，LLM 更合理的位置通常不是替代行为树的大脑，而是接在语义层或高层意图层。它可以帮助 NPC 理解玩家自然语言，生成更有角色感的回应，解释当前任务目标，整理长期互动记忆，或者提出几个高层候选计划。真正要落到游戏运行时，仍然需要传统系统把这些语义结果翻译成受约束的动作：走到哪里、看向谁、触发哪个动画、调用哪个技能、更新哪个任务状态。语言模型可以参与思考，但动作接口必须被游戏规则包住。</p><p>真正变化的是 NPC 和玩家之间的语义接口。传统 NPC 往往只能响应固定选项：点击对话、接任务、交物品、触发战斗。接入 LLM 后，玩家可能直接说“我迷路了，带我去安全的地方”“你为什么不相信那个商人”“我现在不想打架，有没有别的办法”。模型可以把这些开放表达转成更结构化的意图，比如求助、问路、质疑剧情、请求替代路线，再交给任务系统、导航系统或决策系统判断能不能做。</p><p>但 LLM 也带来了新风险。它可能产生幻觉，承诺不存在的奖励，编出世界观里没有的设定，误解玩家意图，或者在多人游戏里给某个玩家不公平的信息。它还有延迟和成本问题，不适合每一帧都参与实时决策。越靠近玩家体验，越需要边界：哪些内容可以生成，哪些必须从任务数据库读取，哪些动作需要规则系统确认，哪些回答必须被安全过滤，哪些记忆可以长期保存。</p><p>因此，比较稳妥的理解是：传统游戏 AI 负责让 NPC 在规则世界里可信地行动，LLM 负责让 NPC 更好地理解和表达。二者不是简单的新旧替换关系，而是上下层协作关系。传统系统提供边界、状态、动作和验证，LLM 提供语言、解释、意图归纳和候选方案。</p><h2 id="小白应该怎样理解：传统游戏-AI-是-LLM-NPC-的地基"><a href="#小白应该怎样理解：传统游戏-AI-是-LLM-NPC-的地基" class="headerlink" title="小白应该怎样理解：传统游戏 AI 是 LLM NPC 的地基"></a>小白应该怎样理解：传统游戏 AI 是 LLM NPC 的地基</h2><p>如果第一次接触游戏 AI，可以先不要纠结哪种算法更高级。更好的入门方式是问五个问题。</p><p>第一，NPC 需要知道什么？这对应感知和世界状态。它能不能看见玩家，能不能听到声音，是否知道队友位置，是否记得刚才发生过什么。</p><p>第二，NPC 能做什么？这对应动作空间。它能移动、攻击、躲避、说话、交易、开门、求援，还是只能左右巡逻。</p><p>第三，NPC 为什么选择这个动作？这对应决策。简单行为用脚本或 FSM 就够了；层级行为用行为树；多因素权衡用 Utility；目标驱动流程用 GOAP 或 HTN。</p><p>第四，玩家怎样感知它？这对应表现层。动画、音效、转身速度、攻击前摇、台词、提示 UI，都会影响玩家对 AI 的判断。有时 NPC 决策是合理的，但表现太突然，玩家仍然觉得它作弊。</p><p>第五，如果接入 LLM，它负责哪一层？这是今天讨论 LLM NPC 时最容易混淆的问题。LLM 可以理解玩家说什么，可以生成一句更自然的回答，可以把模糊请求整理成高层意图，也可以帮助角色解释自己的行为。但它不应该单独决定角色能不能发奖励、能不能发现玩家、能不能使用技能、能不能改变剧情状态。这些仍然应该由游戏规则、任务系统、战斗系统和传统 AI 结构来确认。</p><p>举个例子，玩家对队友 NPC 说：“帮我找一条安全路线。”LLM 可以把这句话理解成“玩家想避开战斗并到达目标点”，也可以生成一句符合角色设定的回应，比如“我看看有没有能绕开巡逻队的路”。但真正的安全路线不是模型凭空编出来的。路线可不可达，要问导航系统；哪些区域危险，要看敌人感知、巡逻路线和黑板状态；是否应该绕路，要让 Utility 或 GOAP 评估代价；NPC 最后怎么移动，还要交给寻路、动画和避障系统。</p><p>用这个框架看，很多游戏 AI 现象都会变得容易理解。敌人“突然知道你在哪”，可能是感知边界没设计好；队友“不救你”，可能是 Utility 分数或行为优先级有问题；怪物“原地发呆”，可能是行为树某个节点一直 Running；Boss “转阶段很生硬”，可能是 FSM 切换缺少过渡；模拟居民“每天行为太机械”，可能需要 HTN 或更丰富的日程状态。如果接入 LLM 后 NPC 开始乱说任务奖励、编造不存在的地点，问题也未必是“模型不够聪明”，而是语义生成没有被任务数据库和规则系统约束住。</p><p>脚本让行为可控，FSM 让状态清楚，行为树让层级任务可组织，Utility 让多因素选择更灵活，GOAP 让 NPC 能围绕目标生成计划，HTN 让复杂任务可以逐层分解。学习和搜索方法则像工具箱里的增强模块，帮助训练、优化、模拟或解决局部决策问题。这些传统技术不是 LLM NPC 到来后就过时的旧零件，而是让角色真正能在游戏里行动的地基。</p><p>所以，LLM 可以让 NPC 更会说、更会解释、更能连接玩家意图，但可信的游戏 Agent 仍然依赖感知边界、状态管理、动作约束、调试工具和设计目标。真正难的不是让角色说出一段漂亮台词，而是让它在游戏规则里持续、稳定、可控地行动。只要它能观察环境、维护状态、选择行动、接收反馈，它就已经站在 Agent 的范畴里。至于这个 Agent 的语义层是否接入语言模型，反而是建立在传统游戏 AI 地基之上的下一层选择。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>Ian Millington, <em>Artificial Intelligence for Games</em>. <a class="link"   href="https://www.taylorfrancis.com/books/mono/10.1201/9781315375229/artificial-intelligence-games" >Taylor &amp; Francis 页面<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Steve Rabin 主编，<em>Game AI Pro</em> 系列。官网提供章节索引与公开下载说明：<a class="link"   href="https://www.gameaipro.com/" >Game AI Pro<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Alex J. Champandard, Philip Dunstan, <em>The Behavior Tree Starter Kit</em>. <a class="link"   href="https://www.gameaipro.com/GameAIPro/GameAIPro_Chapter06_The_Behavior_Tree_Starter_Kit.pdf" >Game AI Pro Chapter 6<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Kevin Dill, Dave Mark, <em>An Introduction to Utility Theory</em>. <a class="link"   href="https://www.gameaipro.com/GameAIPro/GameAIPro_Chapter09_An_Introduction_to_Utility_Theory.pdf" >Game AI Pro Chapter 9<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Jeff Orkin, <em>Three States and a Plan: The AI of F.E.A.R.</em> <a class="link"   href="https://www.gamedevs.org/uploads/three-states-plan-ai-of-fear.pdf" >GDC 资料 PDF<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/20/game-npc-agents-before-llm/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/20/game-npc-agents-before-llm/"/>
    <published>2026-06-19T20:00:00.000Z</published>
    <summary>Before LLM agents became popular, game NPCs had already formed a practical agent architecture around perception, state, decision making, and action.</summary>
    <title>How Game NPCs Became Agents Before Generative AI</title>
    <updated>2026-07-01T15:56:19.868Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="ComfyUI" scheme="https://hyacehila.github.io/tags/ComfyUI/"/>
    <category term="AI Video" scheme="https://hyacehila.github.io/tags/AI-Video/"/>
    <category term="Workflow" scheme="https://hyacehila.github.io/tags/Workflow/"/>
    <content>
      <![CDATA[<p>过去两年，图片生成里最常见的动作，大概就是抽卡。</p><p>原因倒也朴素：生成模型本来就带有试错味道。换一个 seed，换一点提示词，换一个 LoRA，换一张参考图，甚至什么都不换，结果就可能从普通变成可用。Stable Diffusion、SDXL、Flux 这些模型让很多人习惯了「批量出图、挑一张、再局部重绘、再放大」的流程。ComfyUI 能在这个阶段变得重要，也和这件事有关。它把生成过程拆成节点和连线，把原本一次次点按钮的事情，变成了可以保存、修改和复用的工作流。</p><p>现在，视频生成也开始进入这个阶段。</p><p>只是视频麻烦得多。图片抽卡失败，最多是这一张不行；视频失败，可能是角色第一秒还对，第三秒脸就漂了。也可能是上一段和下一段接不上，镜头运动不错但产品变形了。当前不少视频模型仍然以短片段、单镜头、文生视频或图生视频为基本单位。比如 Stable Video Diffusion 发布时提供的是 14 帧和 25 帧的图生视频模型，更强的闭源模型如Seedance 2.0 和 HappyHorse 也只最多支持 15 秒的生成能力。而人们所需要的绝对不止 15 秒。</p><p>这篇不是 ComfyUI 教程。我也不是 ComfyUI 的专业用户。更准确地说，我想借这篇文章从 workflow 的角度重新理解它：ComfyUI 现在到底是什么？为什么把它叫成本地生图软件已经有点别扭？当视频生成逐渐变成常用能力时，它需不需要像 LibTV 这类产品一样，补上一些面向长视频的编排能力？</p><p>我的判断先放在这里：ComfyUI 已经从生图 UI 变成了开放的生成式 workflow&#x2F;runtime；视频生成正在把问题推向更高一层。它未来值得补一些镜头、分段、批量抽卡、核验和长任务管理能力。但它不必变成 LibTV。ComfyUI 最有意思的地方，还是开放、可控、本地化、模型生态和节点可组合。</p><h2 id="ComfyUI-现在是什么"><a href="#ComfyUI-现在是什么" class="headerlink" title="ComfyUI 现在是什么"></a>ComfyUI 现在是什么</h2><p>如果只从界面看，ComfyUI 很容易被理解成一个把 Stable Diffusion 画成流程图的工具。这个说法曾经不算错。</p><p><a class="link"   href="https://docs.comfy.org/" >官方文档<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>现在把 ComfyUI 描述为 node-based interface and inference engine for generative AI。它处理的基本对象是 workflow：一组由 nodes 和 links 连接起来的计算图。节点可以加载模型、编码提示词、采样、解码、保存结果，也可以做 ControlNet、IP-Adapter、LoRA、放大、视频合成、音频处理、3D 或 agent 相关任务。也就是说，ComfyUI 关心的是这次生成由哪些步骤组成，不只盯着最后那张图。</p><p>传统 WebUI 更像参数面板。用户填 prompt、选模型、调步数、点生成。ComfyUI 则把这些步骤摊开，让模型、参数、输入、输出都成为显式节点。一个 KSampler 节点连接了 prompt embedding、latent、模型、采样器和 seed；一个 VAE Decode 节点把 latent 还原成图像；一个 Save Image 节点负责落盘。看起来复杂，但它让用户能看见生成过程。</p><p>如果是第一次理解 ComfyUI，我会先抓几个概念，不急着去背节点名。</p><p>先看 node graph。节点图的用处不在炫技，它只是把生成过程摆到明面上。图像生成里，一张图背后有模型加载、文本编码、latent 初始化、采样、解码、后处理等步骤。视频生成里，这条链更长：可能还要处理参考图、首尾帧、运动模块、补帧、放大、拼接。节点图把这些步骤拆开，用户就可以替换其中一段，而不用整套流程从头来。</p><p>再看 workflow。workflow 是一套可以保存和复现的生成配置。除了 prompt，它还记录节点结构、模型选择、参数连接和处理顺序。很多时候真正影响结果的，是模型、参考图、ControlNet 强度、LoRA 权重、denoise、采样器和后处理一起形成的状态。</p><p>下面是一套基础的节点组合与他们的一般编排顺序：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Load Checkpoint：请模型上场</span><br><span class="line">CLIP Text Encode：翻译提示词</span><br><span class="line">Empty Latent Image：准备空画布</span><br><span class="line">KSampler：真正生成</span><br><span class="line">VAE Decode：把 latent 变成图片</span><br><span class="line">Save Image：保存结果</span><br><span class="line">Load Image：导入参考图</span><br><span class="line">VAE Encode：把图片压回 latent</span><br><span class="line">Load LoRA：加载风格/角色补丁</span><br><span class="line">ControlNet：控制结构</span><br><span class="line">Upscale：放大增强</span><br><span class="line">Video Combine：把帧合成视频</span><br></pre></td></tr></table></figure></div><p>本地模型生态也很重要。ComfyUI 的能力来自本地开源模型和社区开源节点。这些信息可以通过 Load Checkpoint、Load LoRA、VAE、ControlNet 等节点进入工作流。随着社区扩展，Flux、Wan、AnimateDiff、Stable Video Diffusion、HunyuanVideo 等图像和视频路线都能以某种形式接进来。这是它和纯云端 WebUI 生成产品不一样的地方。用户可以在自己的机器上，利用整个社区提供的信息，将自己的生成任务组织成一个工作流。</p><p>最后是可编程。<a class="link"   href="https://docs.comfy.org/development/comfyui-server/api-examples" >ComfyUI Server API<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 支持把 workflow 作为任务提交，通过队列、history 和 WebSocket 监听执行状态。外部脚本或 agent 可以修改 seed、prompt、参考图和参数，批量跑结果，再取回输出。到这里，ComfyUI 已经不只是一个交互界面，也可以被当作生成后端来调度。</p><p>现在的 ComfyUI 理解为三个东西叠在一起：可视化生成图谱、本地&#x2F;远程推理运行时、可被程序调用的 workflow 系统。它最早因生图而流行，但现在讨论它，只看图片已经不够了。</p><p>在本章结束之前还需要聊一下关于生图 Pipeline 的补充问题，前面的角度基本还是在本地模型拆解的角度展开的，现在大家更多的依赖外部 API 使用Partner Nodes 进行图片生成，那实现一个基础的生图 Pipeline 需要先用快速模式区分风格进行抽卡，在4-10张多样性图片中挑选以后，开始使用更高质量的模式进行多轮次的迭代微调以获得更好的生成效果。系统需要自动化的评估（一般是通过外部的 LLM Rubric 作为评估来源），减少人工的提示撰写工作，让系统自我优化，只在必要的时候使用人。</p><h2 id="ComfyUI-正在往哪里走"><a href="#ComfyUI-正在往哪里走" class="headerlink" title="ComfyUI 正在往哪里走"></a>ComfyUI 正在往哪里走</h2><p>如果只看社区里那些复杂节点图，ComfyUI 似乎永远属于技术用户。但官方近年的动作，明显在把它往外推。节点图的控制力还在，复杂 workflow 也开始被包装给普通用户、agent 和云端系统调用。</p><p>一条线是 API 化。官方文档里有 local API examples 和 workflow API format：用户可以把工作流导出成 API 格式，通过 <code>/prompt</code> 提交到队列，通过 <code>/queue</code> 查看队列，通过 <code>/history</code> 取结果，通过 WebSocket 监听执行状态。这意味着 ComfyUI 很适合放进更大的系统里。一个外部脚本可以读取 100 个 prompt，给每个 prompt 分配 20 个 seed，批量提交任务，再把输出图送去 CLIP、OCR 或 VLM 打分。</p><p>另一条线是 Partner Nodes。<a class="link"   href="https://docs.comfy.org/tutorials/partner-nodes/overview" >Partner Nodes<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 可以把外部 API 服务、闭源模型或第三方托管模型接进 ComfyUI workflow。这个方向很现实，因为生产流程很少只靠一个模型。本地模型可能负责低成本抽卡，闭源模型负责高质量图生视频，VLM 负责审核，OCR 负责检查文字，人脸模型负责一致性。ComfyUI 要成为 workflow&#x2F;runtime，就需要让这些能力待在同一张图里。</p><p>还有 App Mode、Agent 和 Cloud。官方博客 <a class="link"   href="https://blog.comfy.org/p/from-workflow-to-app-introducing" >From Workflow to App<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 提到，App Mode 可以把复杂工作流包装成更像应用的界面；<a class="link"   href="https://docs.comfy.org/agent-tools" >Agent Tools<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 让 agent 调用 ComfyUI 生成 image、video、audio、3D；<a class="link"   href="https://blog.comfy.org/p/comfy-cloud-is-now-in-public-beta" >Comfy Cloud<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则指向云端运行 workflow、部署为 API、并行运行多个 workflow、团队协作等场景。</p><p>这些东西放在一起看，ComfyUI 已经不像一个单点工具了。它更像一套生成式媒体工作流平台：底层是开放节点图，中间有 API、队列、云端和模型连接，上层再把 workflow 包装成 app 或 agent tool。</p><p>也正因为这样，长视频编排才会变成一个绕不开的问题。如果 ComfyUI 只是一次运行一个图的工具，长视频当然离它很远。但如果它已经是 workflow&#x2F;runtime，那么分段、继承、筛选、重试和拼接迟早会来到它面前。</p><h2 id="视频不是一次生成能解决的"><a href="#视频不是一次生成能解决的" class="headerlink" title="视频不是一次生成能解决的"></a>视频不是一次生成能解决的</h2><p>长视频的问题，不在于把 prompt 写长，也不在于把视频模型的 duration 参数拉满。</p><p>在目前的模型条件下，很多视频生产更像一个多阶段流水线。先生成角色或产品参考图，完成整体的脚本和镜头初步设计。再利用生图模型抽关键帧，把关键帧变成短视频，拼接检查一致性。如果某一段坏了，还要回到对应镜头重新抽卡，不用把整条视频全部推倒重来。</p><p>图片生成常常只需要回答这一张够不够好。视频生成要多想很多：角色有没有漂，场景有没有换，上一段尾帧和下一段首帧能不能接上。镜头结构、画面运动、文字和产品细节都可能出问题。还有成本。视频重抽一次，比图片肉疼得多。</p><p>同时受限于生成模型的能力限制与成本约束，长视频（大于15s）生成的基本动作是分段。分段之后，真正麻烦的问题出现了：段与段之间如何共享信息？</p><p>如果第一段确认了角色形象，第二段应该继承这个角色参考。如果第一段的尾帧很好，第二段可以用它作为首帧或参考图。如果第三个镜头是产品特写，它应该继承产品图、品牌色、材质和构图要求。如果某个镜头的候选有 20 个，系统应该能记录哪个被选中，为什么被选中，下一阶段使用的是哪一版。</p><p>这时，workflow 本身还不够。一个 ComfyUI workflow 可以很好地描述怎么生成一个镜头，但很难天然描述这部视频有 24 个镜头，每个镜头有 10 个候选，前 6 个镜头共享同一个角色参考，第 7 个镜头使用第 6 个镜头的尾帧，10 个镜头之间共享某种环境，但人物可能需要进行着装上的改变。问题已经越过单个节点图，到了项目级、镜头级、任务级编排。</p><p>生成长视频从的问题目前已经从生成问题变为了系统问题。模型能力当然重要，但素材结构、执行顺序、筛选机制和失败重试同样重要。没有这些外部结构，模型再强，也很容易停留在生成了一个不错的短片段，难以去生成一个可以交付的产品（如短剧）。</p><h2 id="为什么拿-LibTV-做参照"><a href="#为什么拿-LibTV-做参照" class="headerlink" title="为什么拿 LibTV 做参照"></a>为什么拿 LibTV 做参照</h2><p>我把 LibTV 拿出来，不是为了说它替代 ComfyUI，也不是给它写评测。它在这里更像一个参照物：当产品直接面向视频创作时，它会自然长出哪些上层结构？</p><p>LibTV 更像一个 AI 视频创作工作台。它绕开采样器、VAE、denoise 这些底层参数，把界面放在剧本、角色、参考图、视频片段、会话和结果下载上。官方 <a class="link"   href="https://github.com/libtv-labs/libtv-skills" >libtv-skills<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 仓库里提供的脚本能力包括创建会话、发送创作指令、查询会话进展、上传文件、下载结果等；<a class="link"   href="https://www.liblib.tv/zh/cli" >LibTV CLI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 页面也强调可以在 Claude Code 、Codex 等 agent 工具中调用 LibTV 完成图片、视频和角色生成。</p><p>这和 ComfyUI 的抽象层级不同。ComfyUI 的节点更像推理算子：加载哪个模型，使用哪个条件，如何采样，如何解码，如何把结果传给下一个节点。LibTV 的对象更像创作资产：这个项目里有哪些角色，哪个镜头要生成什么，参考图是什么，当前会话进展到哪里，结果如何下载，素材如何继续被使用。他们的不同源于生成模型的阶段，前者来自开源生图模型的巅峰期，后者则是利用闭源生成模型进行长视频生成的工具。</p><p>LibTV 给 ComfyUI 的启发，不是把节点全部藏起来，这会丢掉他原本的优势。恰恰相反，ComfyUI 不应该丢掉节点图。真正值得借鉴的是：视频生产需要比单个 workflow 更高的组织单位。图片时代，一个 workflow 生成一批图已经很有用；视频时代，用户需要围绕 scene、shot、asset、candidate、version 来工作。</p><h2 id="ComfyUI-应该补什么"><a href="#ComfyUI-应该补什么" class="headerlink" title="ComfyUI 应该补什么"></a>ComfyUI 应该补什么</h2><p>如果从这个角度看，我不会先给 ComfyUI 补一个一键出片按钮。更该补的是一层中层编排能力。它夹在底层生成模型和上层 App&#x2F;Agent 之间，管住视频生产里的分段、继承、筛选和长任务。</p><p>我会先补 Shot&#x2F;Scene 层。ComfyUI 可以继续保留 workflow 作为底层执行图，但在 workflow 之上增加镜头和场景概念。一个视频项目可以包含多个 scene，每个 scene 包含多个 shot，每个 shot 有时长、描述、参考图、首帧、尾帧、使用的 workflow、候选结果和当前状态。用户管理的就会是一条视频结构，而不是一堆散落的输出文件。</p><p>然后是批量抽卡层。一个镜头不应该只生成一次，而应该能生成 N 个候选。系统需要知道这些候选来自同一个 shot，参数差异是什么，成本是多少，哪些被淘汰，哪一个进入下一阶段。这个能力不一定复杂，但能少掉很多手动复制 workflow、改 seed、找文件的烦躁。</p><p>核验层也需要补。核验不必一开始就全自动，也不必假装 VLM 能判断一切。更现实的做法是把人工评分和模型评分放在一起。比如 VLM 检查是否符合镜头描述，CLIP 检查图文相关性，OCR 检查画面文字，人脸相似度检查角色一致性，NSFW 模型做安全过滤，最后仍然可以由人打勾或打叉。它的目的不是替代审美，而是把筛选结果结构化，让结果能回到下一轮生成。</p><p>资产继承层可能更基础。长视频不能每次从零开始，已经确认的东西要能带下去。角色参考、产品参考、场景参考、风格参考、上一镜头尾帧，都应该可以作为资产在不同 workflow 之间传递。这里的资产不只是文件路径，还应该包含用途：这是角色脸部参考，这是服装参考，这是场景深度图，这是上一段可续写尾帧。</p><p>长任务管理也绕不开。视频生成会失败，会排队，会中断，会需要重试。ComfyUI 已经有队列和 history，但长视频需要镜头级、项目级的任务视角。用户想知道的不是某个节点是否执行过，而是「第 12 个镜头还有 3 个候选没跑完」「第 5 个镜头通过了核验但还没放大」「第 8 个镜头失败两次，应该换模型」。</p><p>最后可以有一个轻量 timeline。ComfyUI 不需要变成 Premiere，也不需要做完整剪辑软件。但如果它要支持视频生产，至少可以提供一个按镜头排列、预览、替换候选、导出粗剪的轻量时间线。用户应该能从结构上看到整条视频，而不是在文件夹里挨个打开 mp4。</p><p>这些能力加起来，并不是把 ComfyUI 改造成 LibTV。它们更像是给现有节点图补一点视频时代需要的生产语义。解决生成哪些、按什么顺序、如何继承、如何筛选、如何继续。</p><h2 id="不必变成-LibTV"><a href="#不必变成-LibTV" class="headerlink" title="不必变成 LibTV"></a>不必变成 LibTV</h2><p>我觉得更合理的方向，也许是三层结构。</p><p>底层仍然是 node graph。专业用户在这里控制模型、参数、参考图、采样、放大和后处理。</p><p>中层是 orchestration。它负责镜头、场景、批量候选、核验、资产继承、长任务和版本。或许他可以是一个视频生成的专门层，生图和视频生成需要作为两个独立人物拆分开，保留一个资源层用于将他们形成中介，这里仅仅是随便聊聊想法，具体怎么做谁知道呢？</p><p>上层是 App Mode、Agent 或 Studio UI。普通用户不需要看到所有节点，只需要上传素材、填写需求、选择候选、确认结果。复杂 workflow 可以被封装成应用，也可以被 agent 调用。</p><p>未来真正有用的系统，可能会同时吸收两边的经验：底层像 ComfyUI 一样开放可控，上层像 LibTV 一样围绕视频项目组织。ComfyUI 不再是一个本地生图软件，视频生成的兴起会逼这类 runtime 面对更麻烦的问题：如何把一次次短片段生成，组织成一个可以被创作、被筛选、被继承、被重试、被交付的长视频生产流程。</p><p>也许未来的视频模型会强到一次生成完整短片。但在那之前，工作流编排仍然绕不开。哪怕最终的生成模型已经强大到可以生成几分钟甚至几个小时的短片，但真正的有价值的长视频生产，还需要一层能理解镜头和项目的结构。而不是提出一句 prompt ，剩下的全部交给模型去猜。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a class="link"   href="https://docs.comfy.org/" >ComfyUI 官方文档<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.comfy.org/development/core-concepts/workflow" >ComfyUI Workflow 核心概念<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.comfy.org/development/comfyui-server/api-examples" >ComfyUI Server API 示例<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.comfy.org/tutorials/partner-nodes/overview" >ComfyUI Partner Nodes 概览<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://blog.comfy.org/p/from-workflow-to-app-introducing" >From Workflow to App: Introducing App Mode, App Builder, and ComfyHub<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://blog.comfyui.ca/comfyui/update/2024/06/18/Next-Chapter.html" >The next chapter for ComfyUI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://blog.comfy.org/p/comfy-cloud-is-now-in-public-beta" >Comfy Cloud is now in public beta<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.comfy.org/agent-tools" >ComfyUI Agent Tools<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://stability.ai/news-updates/stable-video-diffusion-open-ai-video-model" >Stable Video Diffusion 发布介绍<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/Wan-Video/Wan2.1" >Wan2.1 GitHub 仓库<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://www.liblib.tv/zh/cli" >LibTV CLI 页面<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/libtv-labs/libtv-skills" >libtv-skills GitHub 仓库<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/18/comfyui-video-workflow-orchestration/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/18/comfyui-video-workflow-orchestration/"/>
    <published>2026-06-17T23:00:00.000Z</published>
    <summary>ComfyUI has outgrown the label of an image-generation UI. It is closer to an open generative workflow/runtime, and video generation now exposes what that runtime still needs: segments, inherited assets, candidate sampling, evaluation, and long-running orchestration.</summary>
    <title>From ComfyUI to LibTV: What Workflow Orchestration Needs in the Video Generation Era</title>
    <updated>2026-07-01T15:56:19.867Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Agent Skills" scheme="https://hyacehila.github.io/tags/Agent-Skills/"/>
    <category term="HTML" scheme="https://hyacehila.github.io/tags/HTML/"/>
    <content>
      <![CDATA[<p>前几天我写过一篇<a href="/blog/2026/06/08/fact-layer-interface-layer-markdown-html/">《事实层与界面层：Markdown 与 HTML 不是替代关系》</a>，里面顺手提了一句：HTML 拿来做 PPT 也挺好用。</p><p>这里稍微展开一下。相关项目现在确实很实用：学习成本低，出片快，效果也不差。更重要的是，它不像很多 AI 小工具那样只热闹一阵。只要浏览器还适合展示，只要 Agent 还擅长写前端，它就有继续存在的理由。</p><p>HTML PPT 当然不是新东西。Reveal.js、Slidev、Marp 已经用了很多年，浏览器早就可以当演示播放器。变化发生在 Agent 这一层：Claude Code、Codex、Cursor 这类工具已经能稳定写前端，而 Agent Skills 把风格、叙事顺序和领域习惯写成可复用的说明书、模板、脚本和约束。于是「做一份能看、能讲、符合场景的 slides」开始变成一种可以打包和分享的能力。</p><p>这篇就看几个相关 Skill 分别在解决生成过程中的哪一环。</p><h2 id="通用-Skill：来点艺术风格"><a href="#通用-Skill：来点艺术风格" class="headerlink" title="通用 Skill：来点艺术风格"></a>通用 Skill：来点艺术风格</h2><p>通用 HTML PPT Skill 解决的问题是：用户说不清自己想要什么风格，只知道别像 AI 模板。没有约束时，结果很容易滑向紫蓝渐变、圆角卡片、空洞图标和一堆熟悉但没有性格的布局。每个用 AI 生成过前端界面的人能理解这是什么。</p><p><code>frontend-slides</code>（21,714 stars）算是目前最受欢迎的相关 Skill。它的切入点很聪明。它没有继续堆 CSS，而是把风格选择改成了视觉预览。Agent 会先生成三种真实封面，用户看图来选，不用先在脑子里描述「设计流派」。大多数人说不出自己要哪种风格，但一眼能看出哪张不对味。</p><p>它用多风格模板和用户描述做匹配，再让用户在几个方案里挑。这个流程很省心。项目内置 12 种风格，包括浅色、暗色和四个特殊风格，也支持 beautiful-html-templates 提供的 34 个模板。对多数普通需求来说，<code>frontend-slides</code> 已经够用了。</p><p><code>guizang-ppt-skill</code>（17,311 stars）更依赖用户主动选择风格。它有两套互不混用的视觉系统：一套是「电子杂志 × 电子墨水」，偏复古和风格化；另一套是瑞士国际主义，强调无衬线与现代简洁。</p><p>两种风格加起来只有 9 套配色，布局也被限制得比较紧。这种强约束不妨碍创作，反而很适合 Agent。模型越自由，越容易发明不存在的结构；deck 越长，风格漂移越明显。<code>guizang-ppt-skill</code> 用一部分局部自由换整体稳定性，长稿尤其受益。</p><p><code>html-ppt-skill</code>（6,039 stars）更像一个完整的 HTML PPT 作者系统。它有 36 个主题、15 个完整 deck 模板、31 种单页布局、27 种 CSS 动画和 20 种 Canvas 特效。功能很全，特点没有前两个鲜明。</p><p>它的 Presenter Mode 挺有意思。按 <code>S</code> 可以打开独立演讲者窗口，里面有当前页、下一页、逐字稿和计时器。对于演讲者比较实用。</p><h2 id="专用-Skill：让内容按领域逻辑展开"><a href="#专用-Skill：让内容按领域逻辑展开" class="headerlink" title="专用 Skill：让内容按领域逻辑展开"></a>专用 Skill：让内容按领域逻辑展开</h2><p>通用 Skill 解决的是“看起来像一份好的 PPT”。专用 Skill 处理另一个问题：在某个领域里，什么才算讲清楚。</p><p>教育、科普和正式汇报场景里，<code>visual-cognition-slides</code>（70 stars）和 <code>ppt-director</code> 很适合放在一起看。它们都先处理同一个问题：这一页为什么成立，观众应该从哪里理解它。当然他们目前做的工具仍旧很有限，是否应该取代讲者对内容的把控将思考也外包给 AI 值得商榷，与此同时他们本身也不怎么好用，能力很是有限。</p><p><code>visual-cognition-slides</code> 更偏教学设计。它会先问受众是谁、最后只能记住一件事是什么，再按知识类型选择解释方式：概念性知识用类比动画，程序性知识用步骤动画，关系性知识用连接图，数据性知识用比例和趋势。它的硬规则也很明确：一张 slide 一个认知单元，文字只是标签，图形才是主体。对教育内容来说，这比换一套漂亮主题管用。</p><p><code>ppt-director</code> 则更像正式汇报里的总导演。它关心受众&#x2F;评审校准、页面结构导演稿、设计语言对表、HTML 预览和 PPTX 审查门禁；尤其是把不绑定风格的 <code>页面描述_优化版</code>，和带画布、坐标、字体字号、组件映射的 <code>生成就绪导演稿</code> 分开。前者解决“这页如何被理解”，后者解决“这页如何被生成”。这说明专用 Skill 的价值不只在领域知识，也在把生成前的判断过程固化下来。</p><p>商业汇报里，<code>KingDee-PPT-Skill</code>（54 stars）把企业品牌规范和商业模型绑在一起。他的内容分析阶段可以作为参考：识别金字塔&#x2F;MECE、PDCA、SWOT、黄金圈、5W1H、SCQA、IPD 五看等结构，再映射到对应版式。它也采用 HTML-first 工作流，先做可演示的 HTML deck，再按需要导出 PPTX。</p><p>这种 Skill 不需要适合所有公司。它就是为某一类汇报习惯服务的：管理层看到 SWOT、PDCA、IPD，知道该从哪里读、该问什么问题。反过来讲，说服这些细分领域的人接受 HTML 而不是 PPTX，可能比继续打磨 Skill 本身更难。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>把这些项目放在一起看，通用 Skill 和专用 Skill 的分工很清楚。</p><p>通用 Skill 更像设计总监。它关心主题、字体、动效、舞台、演讲者模式和视觉节奏。它要解决的是空白页恐惧：我有材料，但不知道怎么把它做成一份像样的 PPT。</p><p>专用 Skill 更像领域协作者。它关心受众是否理解、教学内容有没有降低理解成本、商业逻辑是否落进熟悉框架。它主要处理信息组织问题，美观只是入口。</p><p>AI 做 PPT，最直观的好处是省时间。把大纲丢进去，几分钟后拿到一份能看的 slides。但 HTML PPT 和 Agent Skills 放在一起，重点不止是快。领域框架可以封装成 Skill，模型开始在受约束的流程里帮人组织表达。</p><p>主题当然重要，但主题不会单独存在。不同领域有不同的习惯和范式。以前这些东西要靠人自己学、自己记住，下次做 PPT 的时候再想起来。</p><p>如果 Skill 同时封装领域理解和专业风格，AI 生成 HTML PPT 就不只是自动排版。人给出材料和意图，Skill 带来领域规范与风格要求，Agent 再把它编译成一份可以观看、演讲、继续修改的界面。说白了，模板只是外壳，真正有价值的是里面那套可复用的判断。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a class="link"   href="https://github.com/zarazhangrui/frontend-slides" >frontend-slides<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/op7418/guizang-ppt-skill" >guizang-ppt-skill<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/lewislulu/html-ppt-skill" >html-ppt-skill<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/edu-ai-builders/visual-cognition-slides" >visual-cognition-slides<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/Hermess/ppt-director" >ppt-director<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/WayneZhon/KingDee-PPT-Skill" >KingDee-PPT-Skill<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a href="/blog/2026/06/08/fact-layer-interface-layer-markdown-html/">《事实层与界面层：Markdown 与 HTML 不是替代关系》</a></li><li><a href="/blog/2026/03/10/from-mcp-to-agent-skills/">《从 MCP 到 Agent Skills：为什么 Agent 又需要一种新的上下文工程协议？》</a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/15/ai-html-ppt-agent-skills/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/15/ai-html-ppt-agent-skills/"/>
    <published>2026-06-14T20:00:00.000Z</published>
    <summary>AI-generated HTML PPTs become interesting when Skills encode design rules, narrative sequencing, and domain judgment. General Skills handle visual quality and stage behavior; specialized Skills encode how different domains organize a talk.</summary>
    <title>AI-Generated HTML PPT Skills</title>
    <updated>2026-07-01T15:56:19.867Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Systems" scheme="https://hyacehila.github.io/categories/agent-systems/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Context Engineering" scheme="https://hyacehila.github.io/tags/Context-Engineering/"/>
    <content>
      <![CDATA[<h2 id="引言：从地图到手册"><a href="#引言：从地图到手册" class="headerlink" title="引言：从地图到手册"></a>引言：从地图到手册</h2><p>在<a href="/blog/2026/03/21/agent-memory-panorama/">《从记忆形成到记忆治理：Agent Memory 的全景图》</a>里，我把 Agent Memory 拆成了三层结构：L1 全上下文（知识直接在当前窗口里，靠长上下文与 KV-cache 支撑）、L2 外部记忆（向量库、文件系统、知识图谱里的外接非参数记忆）、L3 参数记忆（编码进权重的隐式知识）。</p><p>那篇文章的主角是 L2，也就是长期记忆如何形成、组织、更新和失效。L1 这部分，我当时只留下了一个简单的解释：<strong>当前推理现场里，信息到底怎么选择、压缩、隔离和调度。</strong></p><p>这篇文章接着讲这个入口。Memory 全景图更像一张地图，回答的是”长期记忆都在研究什么”；本文换成一个更工程化的问题：在真实的 Agent runtime 里，注意力预算有限，信息怎么读进来、怎么留住、又怎么从当前窗口里离开？</p><h2 id="正文开始之前"><a href="#正文开始之前" class="headerlink" title="正文开始之前"></a>正文开始之前</h2><p>正文会从存储结构讲到运行时手法。正式展开前，先交代三件事：本文在整个系列里处在哪一层，上下文工程在这里具体指什么，以及为什么上下文应该被当成一种需要调度的有限资源。</p><h3 id="三篇的分工：地图、手册、拆解"><a href="#三篇的分工：地图、手册、拆解" class="headerlink" title="三篇的分工：地图、手册、拆解"></a>三篇的分工：地图、手册、拆解</h3><p>这篇文章和前后两篇是一组，但分工不同。《Agent Memory 全景图》偏研究视角，讨论长期记忆怎么形成、组织、更新、失效和评估。本文偏工程落地，讨论在一个 runtime 里，有限注意力预算下信息怎么进出当前窗口；《Agent Runtime Teardown》偏产品和框架拆解，讨论市面上常见的 Agent Runtime 和独立记忆系统怎么装配这些方案。</p><p>所以本文会停在工程实现，把常见手法讲清楚，但不逐个产品横评。读到某个机制时，如果你想知道某个具体系统怎么实现，代码的每一行是怎么写的，答案在 teardown 篇里。</p><p>按 CoALA 的语言（见<a href="/blog/2026/03/03/cognitive-architecture-to-agent-framework/">《从智能体的认知结构到智能体框架》</a>），本文讨论的基本都是 Working Memory 的工程化管理：什么该进场，什么该留在场上，什么该退场，什么要在需要时重新召回，以及这些动作背后的附带约束和工程手法。只要底层还是 attention 机制和有限窗口，这几个动作就绕不开。</p><h3 id="严格区分-LLM-Memory-与-Agent-Memory"><a href="#严格区分-LLM-Memory-与-Agent-Memory" class="headerlink" title="严格区分 LLM Memory 与 Agent Memory"></a>严格区分 LLM Memory 与 Agent Memory</h3><p>讨论运行时调度前，先拆开一个常见混淆：KV-Cache、RoPE、Attention 变种、长上下文架构，这些 LLM Memory 解决的是模型如何拥有更长更有效的上下文窗口；Agent Memory 解决的是智能体如何跨任务积累、检索、更新和遗忘知识。前者是推理基础设施，后者是系统设计。解决这两类问题的思路完全不同，相关研究也大相径庭。</p><p>L1 的物理基底是 LLM Memory：窗口能放多少、prompt cache 命中率多高、decode 多贵，都由模型架构和推理基础设施决定。为什么 output token 比 input 贵、prefill 与 decode 的不对称、KV-Cache 如何吃掉显存和调度槽位，以及怎么把上下文组织得 KV-Cache 友好，我在<a href="/blog/2026/04/26/output-token-pricing-kv-cache-agent-cost/">《为什么 Output Token 更贵：从 KV Cache 到 Agent 成本工程》</a>里已经单独聊过。</p><p>L2 是 Agent 的附属结构，但它要通过 L1 才能发挥作用：任何外部记忆，最后都必须进入推理上下文窗口，才能影响下一步行动。于是讨论 Agent Memory 时，就不能绕开 L1 的基础设施约束。简单说，LLM Memory 决定工作台有多大、多贵；Agent Context Engineering 决定外部信息什么时候进来、什么时候离开，以及工作台上到底该放什么。</p><h3 id="上下文是有限资源：Context-Rot-与注意力预算"><a href="#上下文是有限资源：Context-Rot-与注意力预算" class="headerlink" title="上下文是有限资源：Context Rot 与注意力预算"></a>上下文是有限资源：Context Rot 与注意力预算</h3><p>Context Engineering 的动机很直接：上下文是有限资源，而且退化通常来得比直觉更早。许多研究都指出了直觉与现实之间的差距。</p><p>更大的窗口不等于更好地利用。早在 <a class="link"   href="https://arxiv.org/abs/2307.03172" >Lost in the Middle<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里就有一个被反复验证的现象：模型对长上下文不同位置的信息利用并不均匀，开头和结尾的信息更容易被用上，中间的信息经常被忽略，即便是长上下文模型也一样。</p><p>Chroma 的 <a class="link"   href="https://www.trychroma.com/research/context-rot" >Context Rot<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 报告测了 18 个模型，结论相当一致：性能会随输入长度增长而退化，而且退化不均匀，常常出现在很意外的位置。大海捞针（NIAH）测试不一定能准确反映 LLM 的长上下文能力，性能退化可能比我们想象得更早。</p><p>更反直觉的是，他们发现结构连贯的 haystack 反而不如打乱顺序的 haystack。也就是说，让上下文读起来更顺，有时会损害检索性能。这里没有一个简单的”装满就崩”阈值，注意力召回本来就是很难预测的问题。</p><p>Anthropic 在 <a class="link"   href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" >Effective context engineering for AI agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里把这件事拆成两个拮抗的概念：模型受益于充足信息，也会受 Transformer 结构限制出现上下文腐烂。</p><p>无论是 compaction、notes 还是 subagent，本质上都在找一组更小、更高信号的 token，让目标达成概率最大化。</p><p>这就是后面所有方案的前提。上下文会腐化，注意力有预算，所以”信息放在哪””怎么取出来””怎么写进去””什么时候隔离”都不是锦上添花，而是处理复杂任务的必需。后面会分别讨论记忆结构、检索与写入，以及一些工程手法。</p><h2 id="Object-Path：先确定记忆对象和记忆载体"><a href="#Object-Path：先确定记忆对象和记忆载体" class="headerlink" title="Object Path：先确定记忆对象和记忆载体"></a>Object Path：先确定记忆对象和记忆载体</h2><p>先看存储。但别一上来就问用哪个数据库，先问一个更底层的问题：Agent 在运行时读写的到底是什么对象。Memory 全景图已经解释过为什么不同记忆适合不同载体：关系密集的语义知识适合图，操作性经验和规范适合文件，事实记录适合关系数据库。本文不再重复这套选型理由，而是讨论工程上该怎么实现，以及这些载体如何一起服务于当前窗口的调度。</p><p>如果直接从向量库、图数据库、文件系统开始聊，很容易把问题说成工具选型。Context Engineering 真正关心的是另一件事：信息如何以可治理的形态留在窗口外，又如何在需要时以最小高信号集合回到窗口里。所以这一节先定义 memory object，再讨论它如何投影到向量索引、全文索引、图、文件和关系数据库。</p><h3 id="Memory-Object-与-Metadata-联系起各种数据结构"><a href="#Memory-Object-与-Metadata-联系起各种数据结构" class="headerlink" title="Memory Object 与 Metadata 联系起各种数据结构"></a>Memory Object 与 Metadata 联系起各种数据结构</h3><p>无论最终落在向量库、数据库、图还是文件系统，运行时读写的基本单位都不应该是一整块未经治理的文本，而应该是带元数据的 memory object。一个 memory object 至少需要这些字段：</p><ul><li><code>type</code>：persona、conversation、experience、knowledge、rule 等。</li><li><code>scope</code>：用户级、会话级、项目级、全局级。</li><li><code>content</code>：被保留的事实、规则、经验或摘要。</li><li><code>source</code>：来自哪次对话、哪次工具调用、哪份外部材料。</li><li><code>timestamp</code>：写入时间和最后更新时间。</li><li><code>confidence</code>：这条记忆有多确定。</li><li><code>status</code>：active、stale、conflicted、deleted 等。</li><li><code>links</code>：它与哪些记忆重复、冲突、继承或 supersede。</li></ul><p>Memory 全景图列过写入侧要回答的六个问题：写什么、写到哪、怎么写、如何更新、何时失效、何时写。这张字段表承载的，就是这些决定。</p><p><code>status</code> 和 <code>links</code> 表达版本与冲突语义，<code>timestamp</code> 和 <code>confidence</code> 表达时效与不确定性。没有这些元数据，后面的版本更新、冲突消解、删除与回滚都很难做。</p><p>这些字段还会进入下一章的 metadata 过滤，也会被 promotion 用来保留 provenance。读写两条路径在这里接上了。</p><p>确定了 memory object 之后，再看存储载体会清楚很多。关系数据库、向量索引、全文索引、图和文件系统不一定是彼此替代的选项，更像同一份记忆的不同投影。关系数据库提供业务事实源负责保存对象本身、权限、状态和版本；全文索引负责精确词和编号；向量索引负责跨表述召回；图负责关系和路径；文件系统负责可读、可编辑和可恢复。</p><p>不要让向量库成为唯一事实源。向量库能回答什么和这个 query 相似，但它不天然知道这条记忆是否过期、是否被新版本取代、是否属于当前用户、是否可以被引用到答案里。存储结构要先保住治理语义，再把不同检索能力做成投影。后面无论用 SQLite、LanceDB、Postgres、图数据库还是文件系统，核心都是这个边界。</p><p>特别地，像 LLM Wiki 这样的系统也研究知识结构，也会思考如何更好地存储和召回，但这里不展开。它们更像知识沉淀系统或独立技术实验，可以单独写文章分析。本文只关心更基础的工程问题：一个 runtime 如何把外部记忆存成可治理对象，又如何在当前窗口里选择性使用它们。</p><h3 id="向量嵌入语义检索"><a href="#向量嵌入语义检索" class="headerlink" title="向量嵌入语义检索"></a>向量嵌入语义检索</h3><p>向量索引是 memory object 的一种重要投影，也是传统 RAG 的入口。但别把它想成一个把文本丢进去就会让 AI 变聪明的”语义搜索盒子”。真正落地时，效果往往不取决于数据库名字，而取决于几件更朴素的事：文档怎么切，向量怎么生成，索引怎么建，原文和元数据有没有留住，以后换模型、换库时会不会把自己锁死。</p><p>先讲这些底层选择，再看三档工程方案。</p><h4 id="向量嵌入检索的注意事项"><a href="#向量嵌入检索的注意事项" class="headerlink" title="向量嵌入检索的注意事项"></a>向量嵌入检索的注意事项</h4><p>向量嵌入检索解决的是一类很具体的问题：把 query 和文档片段映射到同一个向量空间里，再用距离或相似度找出语义相近的候选。自然语言改写、模糊需求、跨表述召回，是它擅长的地方。错误码、函数名、合同条款编号、人名、项目代号这类精确匹配，单靠 dense embedding 经常会漏掉。后面会讲混合检索，这里先只看向量库本身怎么建。</p><p>Chunking 最容易被低估。固定长度切分省事，但容易把标题、表格、代码块和段落关系切断；按结构切分更稳，比如按 Markdown 标题、段落、函数、章节、页面或表格单元切。</p><p>chunk 太大，向量会变成一团平均语义，真正有用的句子被稀释；chunk 太小，又会丢上下文，召回后还得靠相邻片段或 parent document 回填。比较稳的做法是让小 chunk 负责命中，再用标题路径、页码、章节、父文档 ID 把上下文补回来。chunk 不该是一段裸文本，它应该是带出处的检索单元。</p><p>Embedding 模型也不能随手挑。通用模型可以覆盖很多文档，但代码、医学、法律、内部制度这类文本有自己的术语密度。维度越高不等于效果越好，它会直接影响存储、内存、索引构建和检索延迟。</p><p>更麻烦的是版本治理。embedding 模型一换，旧向量和新向量通常不能混在一起比较。至少要记录 <code>embedding_model</code>、<code>embedding_dim</code>、<code>distance_metric</code> 和索引版本，否则后面排查召回问题会很痛苦。</p><p>索引层也是取舍。小数据量可以 exact KNN，也就是把所有向量算一遍距离，简单、可解释，规模上来后就慢了。ANN 用近似换速度。HNSW 通常召回好、查询快，但吃内存，构建和参数也更敏感；IVF 先把向量分桶，再在相关桶里找，内存和速度更可控，但需要训练或聚类，召回更依赖参数。这里没有神奇按钮。你调的是延迟、内存、构建成本和召回率之间的平衡。</p><p>Metadata 和 provenance 也要在写入时留住。向量库只返回相似，不天然知道这段话属于哪个租户、哪个项目、哪个版本、哪一页、是否已经删除、用户是否有权限看。写入时没有把这些信息结构化，检索时就只能靠补丁。至少要保留 <code>doc_id</code>、<code>chunk_id</code>、标题路径、source URI、页码或行号、更新时间、权限标签、删除状态和 parser 版本。RAG 的答案要能追溯，不然召回再准也很难进入可靠系统。</p><p>评估也要早做。别只看 demo 问题。准备一组真实 query，覆盖语义改写、精确术语、跨文档、无答案、旧版本、新版本、表格和代码块。看 Recall@k、MRR、引用是否支持答案，也看删除和权限是否生效。向量检索的很多问题其实和模型无关，而是文档解析错、chunk 切坏、metadata 缺失，或者评估样本太干净。</p><h4 id="三档检索底座一：Local-first：SQLite-FTS5-sqlite-vec-sqlite-vss-vec1"><a href="#三档检索底座一：Local-first：SQLite-FTS5-sqlite-vec-sqlite-vss-vec1" class="headerlink" title="三档检索底座一：Local-first：SQLite + FTS5 + sqlite-vec &#x2F; sqlite-vss &#x2F; vec1"></a>三档检索底座一：Local-first：SQLite + FTS5 + sqlite-vec &#x2F; sqlite-vss &#x2F; vec1</h4><p>如果目标是本地 Agent、个人知识库、离线工具，或者小团队先跑通传统 RAG，SQLite 是一个很实用的起点。它不靠性能天花板取胜，胜在把事情做小：文档表、chunk 表、元数据、索引状态、删除状态、任务记录都可以放在一个本地数据库里，随应用一起分发。</p><p>SQLite FTS5 是官方全文检索扩展，带 <code>bm25()</code> 排序函数。它正好补 dense embedding 的短板：精确词、编号、异常码、产品名、制度条款。</p><p>向量侧有三个方向，成熟度不一样。<code>sqlite-vec</code> 是第三方 SQLite 向量扩展，纯 C、依赖少，适合本地嵌入；但它仍是 pre-v1，要接受接口变化，项目文档也把它称作 <code>sqlite-vss</code> 的 successor。<code>sqlite-vss</code> 是更早基于 Faiss 的路线，作者已经把主要精力转向 <code>sqlite-vec</code>，新项目不太适合启用它。</p><p><code>vec1</code> 是 SQLite 官方新的向量扩展，文档已经列出 ANN、L2 和 cosine 距离接口，也提醒测试和优化还不充分。方向值得关注，但首版采用前要验证语言绑定、发布节奏、平台打包和索引能力。</p><p>这一路线最好用在小边界里：每个用户一个库，或者每个小项目一个库。查询时可以并行跑 FTS5 和向量检索，再在业务层做简单融合和 rerank。边界也很窄。SQLite 不适合作为高并发、多租户、集中审计的检索服务；向量扩展还在演进；权限和索引一致性都要自己治理。它最舒服的位置，是 local-first 的基础设施，不是企业搜索平台。</p><p>升级信号也很清楚：多人共享、集中权限、后台索引队列、查询审计、跨项目统计，或者本地文件分发已经管不住版本。到了这一步，就该往服务化走。</p><h4 id="三档检索底座二：轻服务化：LanceDB"><a href="#三档检索底座二：轻服务化：LanceDB" class="headerlink" title="三档检索底座二：轻服务化：LanceDB"></a>三档检索底座二：轻服务化：LanceDB</h4><p>LanceDB 可以放在 SQLite 和重型搜索基础设施之间。它仍然能本地跑，也方便轻量部署，但向量检索、全文检索、hybrid search、rerank 的路径更直接。官方文档里的 hybrid search，就是把 vector search 和 full-text search 的候选合并，再通过 reranking 算法排序。比起自己从零拼 FTS、向量索引和融合逻辑，这条路省不少力气。</p><p>我更愿意把它理解成先把检索层服务化一点。原始文档、chunk 元数据、权限和任务状态仍然可以放在 Postgres 或业务数据库里，LanceDB 专心做检索索引。这样边界比较清楚：业务事实源归业务库，检索能力交给检索组件，答案生成层只拿统一格式的候选。</p><p>但它不会替你处理权限、审计和图谱。多租户隔离、ACL 过滤、删除传播、索引重建状态，最好仍由外层服务控制。如果团队已经决定要做内部知识库服务，而不是单机工具，LanceDB 是一个不错的过渡层：比纯 SQLite 更像服务，又比一上来引入大规模向量数据库轻。</p><p>继续往上走的信号，是数据量、并发、租户隔离、SLA、备份恢复、搜索运营开始成为日常工作。到那时，检索层就不再只是一个库了，才有必要考虑更专门的向量数据库或搜索平台。</p><h4 id="三档检索底座三：Postgres-centered-service：Postgres-pgvector-FTS-ParadeDB"><a href="#三档检索底座三：Postgres-centered-service：Postgres-pgvector-FTS-ParadeDB" class="headerlink" title="三档检索底座三：Postgres-centered service：Postgres + pgvector + FTS &#x2F; ParadeDB"></a>三档检索底座三：Postgres-centered service：Postgres + pgvector + FTS &#x2F; ParadeDB</h4><p>到了内部服务阶段，我会优先认真看 Postgres。原因很朴素：很多团队本来就用它管理用户、权限、文档元数据、任务、审计、版本和删除状态。把传统 RAG 的一部分能力放进同一个数据库生态，通常比额外引入几套服务更稳。</p><p><code>pgvector</code> 把向量相似度检索带进 Postgres，支持 exact search，也支持 HNSW、IVFFlat 这类 approximate search 索引。Postgres 自带全文检索，可以用 <code>tsvector</code>、<code>tsquery</code>、ranking 函数处理关键词召回。这样一来，文档事实源、权限过滤、事务一致性、向量检索、全文检索都能留在一套数据库和 SQL 边界里。对内部知识库来说，这比多画一个组件更有用。</p><p>但 Postgres 也不是完整搜索引擎。Postgres FTS 的体验和 Elasticsearch &#x2F; OpenSearch 那类搜索平台不是一回事；dense + lexical 的融合通常还要自己写 SQL 或业务编排；数据量特别大时，专用向量库的扩展边界会更高。</p><p>如果希望在 Postgres 内得到更接近搜索引擎的 BM25、faceted search、hybrid search 体验，可以关注 ParadeDB 的 <code>pg_search</code> 路线。它的吸引力在于不急着把系统拆成好几套服务，同时补上 Postgres 原生搜索的一些短板。</p><p>这一层适合小团队到中等规模的内部服务，尤其适合已经有 Postgres 运维经验、又很在意权限和审计的场景。再往后，Qdrant、Milvus、OpenSearch、Elasticsearch、Neo4j 这些选择当然存在，但那基本进入专门搜索基础设施或图基础设施的领域，需要更明确的规模压力和运维投入。对本文讨论的适度工程化 RAG 来说，先把这三层吃透，已经够用了。</p><p>这三档讲的是怎么把传统 RAG 的存储和索引底座建出来。它们不是三套互斥方案，而是工程边界随规模变化的三个阶段：本地时把事情做小，轻服务化时把检索层拆出来，内部服务阶段把权限、审计和事务一致性放回稳定的业务数据库生态。底座建好之后，真正决定当前窗口质量的，是怎么取准，比如稀疏加稠密混合、metadata 过滤、query rewrite 和 rerank，放到下一章讲。</p><h3 id="图存储：先验证图检索收益，再选择图数据库"><a href="#图存储：先验证图检索收益，再选择图数据库" class="headerlink" title="图存储：先验证图检索收益，再选择图数据库"></a>图存储：先验证图检索收益，再选择图数据库</h3><p>图的难点不在查询，而在怎么把非结构化文本变成图，以及图怎么随新信息增量更新。实体关系抽取要回答谁、和谁、什么关系、何时，通常还要靠一轮 LLM 调用。这一步质量决定图能不能用；抽取错了，再漂亮的多跳遍历也只是在错误的边上推理。</p><p>运行时遍历要控制跳数和扇出。多跳关联是图的长处，但不加限制地遍历，很快就会把成百上千个节点拉进候选集，最后违背”最小高信号集合”。</p><p>增量更新也麻烦：要做实体消解，判断”老王”和”王经理”是不是同一个节点；还要处理边的时效，判断旧关系是否已经失效。</p><h4 id="阶段一：用-LightRAG-先验证图检索收益"><a href="#阶段一：用-LightRAG-先验证图检索收益" class="headerlink" title="阶段一：用 LightRAG 先验证图检索收益"></a>阶段一：用 LightRAG 先验证图检索收益</h4><p>所以图存储应该从”关系型问题是否真的需要图检索”开始。早期可以只在 SQLite 或 Postgres 里保留简单的 <code>entity</code>、<code>relation</code>、<code>mention</code>、<code>chunk_link</code> 表，把它们当作可审计的关系投影。也可以更临时一点，用 JSON、NetworkX、内存图、LlamaIndex 的默认存储，或者 LightRAG 的轻量存储先跑实验。这样做不优雅，但足够验证很多问题：实体是否稳定、关系是否可抽取、用户是否真的会问多跳问题、图召回是否比 BM25 + dense + rerank 更好。</p><p>LightRAG 适合做第一轮收益验证。它把实体、关系和 chunk 检索包装成比较直接的 GraphRAG 通道，并提供 <code>local</code>、<code>global</code>、<code>hybrid</code>、<code>naive</code>、<code>mix</code> 这类查询模式。</p><p>这里最有用的是它能让你很快比较”只走传统 chunk 向量检索”和”把图结构也纳入召回”之间的差异。比如 <code>naive</code> 可以近似传统 RAG baseline，<code>mix</code> 则会把 local、global 和 naive 结果合并，更适合观察图检索是否真的给当前语料带来额外信号。</p><p>它本身也是一个很有趣的独立项目。如果只需要尽快跑一个能用的 RAG MVP，或者希望做一些 RAG 研究，它是很好的选择。</p><p>这个阶段不该以”已经接入图数据库”为验收，而应该输出一组可复现的判断：哪些 query 真的需要图，哪些实体和关系抽得稳定，哪些多跳路径可以解释答案，哪些错误来自抽取而不是检索。验收也要朴素：在关系型、多跳、跨文档问题上，GraphRAG 是否比 BM25 + dense + rerank 有稳定提升；如果只在少数 demo 问题上好看，就让它继续留在实验里。</p><p>从 Context Engineering 的角度看，轻量图检索实验的价值，是让系统学会一件事：什么时候应该把关系路径提升进 Working Memory，什么时候只需要原文 chunk。只有这个选择做对，图才是在节省注意力预算，而不是把更多结构化噪声搬进窗口。</p><h4 id="阶段二：Neo4j-作为真正的图基础设施"><a href="#阶段二：Neo4j-作为真正的图基础设施" class="headerlink" title="阶段二：Neo4j 作为真正的图基础设施"></a>阶段二：Neo4j 作为真正的图基础设施</h4><p>如果图检索被证明有稳定收益，下一步也不一定立刻上 Neo4j。只有当图谱开始成为核心资产，或者它会被多个功能复用时，Neo4j 这类图数据库才真正有意义。这里的核心变化是：图不再只是 RAG 的一个召回通道，而是系统里可查询、可维护、可解释、可运营的一类基础数据。</p><p>Neo4j 的价值在成熟度。它有完整的 property graph 建模、Cypher 查询语言、可视化工具、图算法生态和相对成熟的运维路径。对组织、人、项目、客户、合同、系统、风险、流程这些长期存在的实体来说，Neo4j 能把关系从抽出来辅助检索提升为可以被产品和业务系统共同使用的结构化资产。</p><p>它也在向 GraphRAG 靠近。Neo4j 支持向量索引，可以把 embedding 放在节点属性上做向量相似度查询；Neo4j GraphRAG Python 则提供面向 Neo4j 的 retriever、Text2Cypher、hybrid 检索和 LLM 组合方式。也就是说，Neo4j 不只是一个图遍历后端，它可以同时承载一部分向量召回、图召回和 Cypher 查询，把 GraphRAG 从实验工具推进到更稳定的服务边界里。</p><p>但它确实重。引入 Neo4j 意味着要认真设计 schema、约束、索引、权限、备份、迁移、增量同步和删除传播，会带来很高的运维成本。Neo4j 的合理位置是”图谱已经被证明是长期资产，所以需要真正的图基础设施”。在那之前，LightRAG 更像低成本探针；Neo4j 则是验证通过后的承载层。FalkorDB、Memgraph 也可以作为 Neo4j 之外的轻量图服务候选，不过这里就不再展开了。</p><h3 id="文件系统：目录布局与导航"><a href="#文件系统：目录布局与导航" class="headerlink" title="文件系统：目录布局与导航"></a>文件系统：目录布局与导航</h3><p>文件系统是被低估的记忆载体，但它的价值不只是便宜存文本。对 Agent 来说，文件系统更像一种 Agent-native 的记忆协议层：Agent 天生会 <code>read</code> &#x2F; <code>write</code>，会跑 <code>glob</code> 和 <code>grep</code>，会顺着路径、目录、文件名和 Markdown 标题导航。</p><p>路径本身可以成为索引，Markdown 本身可以成为人和 Agent 都能读写的记忆格式。工程重点也就不只是把内容存进去，而是让 Agent 高效导航，不必把全部内容一次性拉进上下文。</p><p>这也是为什么很多真实工具都在往仓库里的 Markdown 上收敛，把它当作一种上下文协议。Claude Code 用 <code>CLAUDE.md</code> 承载项目上下文，也支持 auto memory；Codex 用 <code>AGENTS.md</code> 做分层指令；Gemini CLI 使用 <code>GEMINI.md</code>。</p><p>GitHub Copilot 支持 <code>.github/copilot-instructions.md</code> 和路径级 instructions；Cursor Rules 则把规则放进 <code>.cursor/rules/*.mdc</code>。</p><p>这些文件名不同，但抽象很接近：把稳定规则、项目约定、目录知识和工作偏好放在 Agent 启动或按需检索时能找到的位置。Claude 的 memory tool 更进一步，直接把跨会话记忆做成一个可读写的文件目录，让 Agent 在需要时读回，而不是预先把所有记忆塞满窗口。</p><p>文件型记忆最好分层，不要把所有 Markdown 都混成一锅。</p><ul><li>稳定指令层：比如 <code>CLAUDE.md</code>、<code>AGENTS.md</code>、<code>GEMINI.md</code>、<code>.github/copilot-instructions.md</code>、<code>.cursor/rules/*.mdc</code>，适合放项目约定、架构边界、测试命令、代码风格和长期有效的操作规则。</li><li>演化笔记层：比如 <code>NOTES.md</code>、auto memory、<code>/memories/*</code>，适合放 Agent 从纠错、用户偏好、项目事实和反复出现的问题里沉淀出的跨会话知识。</li><li>运行态工作层：比如 <code>todo.md</code>、scratchpad、handoff artifact、evidence 或 log 摘要，适合放当前任务目标、阶段状态、失败痕迹和可恢复引用。</li></ul><p>这三层的生命周期不同。稳定指令应该由人类明确维护，不能被一次任务里的临时结论随手改写；演化笔记可以由 Agent 辅助更新，但需要 provenance、时间戳和冲突处理；运行态工作文件则更接近 Working Memory 的外溢，任务结束后可以归档、压缩或丢弃。分层的意义，是防止临时 scratchpad 升级成长期事实，也防止 Agent 自动写入的记忆污染团队共享规范。</p><p>文件系统还有一个向量库很难替代的优势：它天然可治理。文件可以 diff，可以 code review，可以回滚，可以被权限隔离，也可以被人类直接编辑。对规则、经验、操作手册、项目约定这类需要共同维护的记忆来说，这种可见性很重要。黑盒索引也许更擅长相似度召回，但它不擅长解释”这条规则为什么存在、谁改过、什么时候生效、能不能删”。文件系统至少把这些问题放回了一个成熟的工程工作流里。</p><p>但文件系统记忆也不是把所有 Markdown 自动加载进上下文。好的文件系统记忆不是更长的 prompt，而是更清楚的导航：入口文件要短，目录结构要清楚，命名要可预测，正文要能被 <code>grep</code> 命中，长文档要保留目录、标题路径和引用链接。</p><p>会话开始只加载稳定入口，需要细节时再按路径展开；不需要时只保留文件名、行号、URL 或摘要。这种 just-in-time 的读法，和向量检索、图遍历一样，都是把 L2 记忆投影进 L1 工作台的一种方式。</p><p>它的特殊优势在于，人类和 Agent 可以共同维护同一套文本结构，维护成本远比数据库低。它的缺陷也明显：基本只适合本地的 Single Agent 治理。</p><h2 id="Read-Path：从外部记忆到-Working-Memory"><a href="#Read-Path：从外部记忆到-Working-Memory" class="headerlink" title="Read Path：从外部记忆到 Working Memory"></a>Read Path：从外部记忆到 Working Memory</h2><p>有了存储结构，下一步就是把外部信息接回当前推理现场。前一章讲的是外部记忆怎么存成可治理对象，又怎么投影到关系库、全文索引、向量索引、图和文件系统里。Read Path 关心的是另一侧：任务发生时，runtime 怎么从这些投影里挑出少量证据，让它们带着来源、权限和版本信息进入 Working Memory，去指导真实决策。相比于 Memory 全景图的简单介绍，这里我们需要将整个工程问题讲清楚，</p><h3 id="检索是-Pipeline，不是一次-Search-调用"><a href="#检索是-Pipeline，不是一次-Search-调用" class="headerlink" title="检索是 Pipeline，不是一次 Search 调用"></a>检索是 Pipeline，不是一次 Search 调用</h3><p>从 Context Engineering 的角度看，检索不是一次 Search API 调用，它对应的是 Rewrite &#x2F; Select &#x2F; Compress 的整个流程。外部记忆里也许有很多相关内容，但当前窗口只需要少数高信号片段。</p><p>一条稍微完整一点的 read path，大概长这样：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">query / task state / scope / ACL / time</span><br><span class="line">  -&gt; query plan</span><br><span class="line">  -&gt; retrievers</span><br><span class="line">  -&gt; hard filter / fusion / dedup / rerank</span><br><span class="line">  -&gt; compression / evidence pack</span><br><span class="line">  -&gt; Working Memory</span><br></pre></td></tr></table></figure></div><p>这里每一步都接着前文的存储结构。<code>scope</code>、<code>ACL</code>、<code>status</code>、<code>timestamp</code>、<code>links</code> 决定候选能不能被看见；全文索引、向量索引、图和文件系统决定候选能不能被找到；provenance 决定候选能不能进入答案；版本和冲突信息决定它进入 Working Memory 时要不要被标记或者在进入之前就被筛选。</p><p>RAG 最早被提出时，重点是把参数记忆和可更新的非参数记忆结合起来。但真正的检索增强不止是”向量库 + 生成模型”，还需要一条可以拆分、替换、评估和治理的 pipeline。</p><p>这也解释了为什么 Read Path 后面会接 Write Path。Promotion 只是把外部证据临时投影进 Working Memory，服务眼前任务；Persistence 才是把当前任务产生的新事实、新规则、新经验写回长期记忆。读和写在 metadata 与 working memory 上接壤。</p><h3 id="检索方式：Read-Path-的最小动作单元"><a href="#检索方式：Read-Path-的最小动作单元" class="headerlink" title="检索方式：Read Path 的最小动作单元"></a>检索方式：Read Path 的最小动作单元</h3><p>讨论混合检索前，先把最小动作单元讲清楚。很多系统看起来复杂，底层通常就是几种能力的组合：按路径找、按字符串找、按词项找、按向量找、按结构找、按关系找。数据库和索引系统只是这些能力的载体，不是能力本身。</p><h4 id="文件路径、目录导航与-grep-glob"><a href="#文件路径、目录导航与-grep-glob" class="headerlink" title="文件路径、目录导航与 grep&#x2F;glob"></a>文件路径、目录导航与 grep&#x2F;glob</h4><p>最朴素的检索其实是导航。已知文件名、目录、扩展名、模块路径、配置名、错误信息、函数名时，路径检索、glob、regex、grep 往往比向量检索更可靠。</p><p>它的工作方式很直接：先根据路径、文件类型或 ignore 规则缩小搜索空间，再用字符串或正则表达式匹配内容。<code>ripgrep</code> 这类工具的价值不在语义，而在确定性和速度。递归搜索目录、支持正则、默认尊重 <code>.gitignore</code>，这些特性很适合在大代码库或文件树里快速定位候选。</p><p>这类检索的缺点也明显：它需要字面线索。用户问”登录失败的处理逻辑在哪里”，但代码里实际叫 <code>AuthChallenge</code>，grep 可能找不到。可一旦 query 里有错误码、配置键、接口名、日志片段、文档标题，确定性搜索通常应该先于语义搜索。</p><p>尤其是 Coding Agent ，一套优雅的 Embedding 方案不一定有价值，根据一点初始信息进行反复多轮 glob&#x2F;grep 往往就能定位错误。这就是 Claude Code 一直以来的做法，搭配上专用针对性的训练，能解决非常复杂的代码任务。</p><h4 id="倒排索引、关键词匹配与-BM25"><a href="#倒排索引、关键词匹配与-BM25" class="headerlink" title="倒排索引、关键词匹配与 BM25"></a>倒排索引、关键词匹配与 BM25</h4><p>grep 是逐文件扫描。全文检索系统则会提前建倒排索引：把 token 映射到出现过它的文档或 chunk。查询时不必重新扫所有文本，而是直接从词项表里找到候选，再按相关性排序。</p><p>BM25 是这条路线上最常见的排序方法，也是传统搜索引擎使用多年的技术。它大致综合三类信号：query 词在文档里出现得多不多，词本身在整个语料里常不常见，文档长度会不会让长文天然占便宜。术语、编号、异常码、人名、接口名、制度条款、产品代号，这些查询 BM25 往往被 dense embedding 更好用。</p><p>所以 SQLite FTS5 (SQLite Extension - Full-Text Search)、Postgres 全文检索、OpenSearch、Elasticsearch 这类系统仍然重要。即使系统已经有向量库，也不该把关键词检索当成旧时代技术。对 Agent 来说，BM25 是低成本、高可解释、容易和权限过滤结合的候选生成器。</p><h4 id="n-gram-与-sparse-n-gram"><a href="#n-gram-与-sparse-n-gram" class="headerlink" title="n-gram 与 sparse n-gram"></a>n-gram 与 sparse n-gram</h4><p>n-gram 检索介于 grep 和全文检索之间。它不理解语义，也不一定按自然语言分词，而是把文本拆成连续的字符片段。trigram 就是长度为 3 的字符片段。这样做的好处是，它适合子串匹配、模糊拼写、相似字符串和正则候选剪枝。至于 sparse n-gram 就是抛弃一些不怎么有区分度的片段，增强检索效率。</p><p>Postgres 的 <code>pg_trgm</code> 就是典型例子：它用 trigram 相似度支持文本相似匹配，也可以通过 GiST 或 GIN 索引加速查询。对产品名拼写不稳定、文件名搜索、短字符串匹配、日志片段定位这类问题，trigram 往往比完整分词更合适。</p><p>Cursor 的 fast regex search 也可以放在这个家族里理解。它为 Agent 工具加速大仓库 regex 搜索：先用 sparse n-gram 之类的索引方法筛掉大量不可能匹配的文件，再对候选做精确正则匹配。它不替代 grep，只是让精确工具在大规模代码库里仍然能被 Agent 高频调用。并和 Cursor 引以为傲的代码向量语义数据库协同工作。</p><h4 id="向量语义检索"><a href="#向量语义检索" class="headerlink" title="向量语义检索"></a>向量语义检索</h4><p>向量语义检索解决的是跨表述召回。它通常用 encoder 把 query 和 document chunk 分别编码到同一个向量空间里，再用 cosine、dot product 或 L2 distance 找最近邻。用户说”客户退款流程”，文档写”售后退费 SOP”，只要 embedding 空间学到了相近语义，就可能被召回。</p><p>Dense Passage Retrieval 是这条路线的经典节点。它把开放域问答里的问题和 passage 分别编码成 dense vector，再用向量相似度召回候选。工程上，规模小可以 exact KNN，所有向量算一遍相似度；规模上来就要 ANN（近似最邻近），用近似换速度。</p><p>HNSW、IVF、PQ 分别是三种最为核心的解决这个问题的算法。HNSW (Hierarchical Navigable Small World) 基于多层图结构的近似最近邻（ANN）搜索。有着极高的查询速度和极高的召回率，也伴随极高的内存消耗用来存储图结构。IVF (Inverted File Index) 则是经典的分桶然后组内暴力索引的方法。PQ (Product Quantization) 则是唯一的有损压缩方法，通过降低维数减少开销，但精度损失严重，一般和 IVF 联合使用。Faiss (Facebook AI Similarity Search) 则是开源的，用于组织这些算法的有效高层工具。</p><p>随着 RAG 架构的普及，开发者倾向于“少引入新组件”，因此传统关系型数据库纷纷通过插件拥抱向量能力。这非常适合那些需要在单一数据库中同时保证 ACID 事务与向量检索的场景。pgvector (PostgreSQL Extension) 以及 sqlite-vec (SQLite Extension) 就是其中的经典扩展。至于需要更大规模的服务，Elasticsearch &#x2F; OpenSearch &#x2F; Redis 这种原生就提供混合检索的框架是值得选择的，他们的侧重点略有不同。</p><p>向量检索的误区是把”语义相近”当成”答案正确”。它擅长自然语言改写、模糊问题、跨语言或跨表达召回，但对错误码、函数名、合同编号、短 query、罕见实体并不天然可靠。它返回的是相似候选，不是经过验证的证据。因此向量检索最好被看作候选生成器，而不是最终答案选择器。</p><h4 id="LSP-与代码索引"><a href="#LSP-与代码索引" class="headerlink" title="LSP 与代码索引"></a>LSP 与代码索引</h4><p>代码不是普通文本。函数、类、接口、引用、定义、类型、调用关系、模块边界，本来就是结构化信息。如果只把代码切成 chunk 再做 embedding，就会丢掉很多编译器和语言服务器已经知道的东西。</p><p>LSP 的价值在这里很明显。Language Server Protocol 把补全、跳转定义、查找引用、文档符号、workspace symbols、诊断等语言能力标准化，让编辑器和工具可以复用语言服务器。对 Agent 来说，LSP 检索回答的是这个符号在哪里定义、哪里被引用、当前文件有哪些结构化实体，不是哪段文本看起来更相似。</p><p>如果有 LSP、AST 这样的符号关系可以利用，那为什么不呢？</p><h4 id="图检索与关系路径"><a href="#图检索与关系路径" class="headerlink" title="图检索与关系路径"></a>图检索与关系路径</h4><p>图检索处理的是实体和关系。它关心的不是某个 chunk 是否相似，而是实体之间如何连接：人属于哪个团队，系统依赖哪个服务，合同对应哪个客户，故障影响哪些组件，某个概念在哪些文档里以不同名字出现。</p><p>GraphRAG 不是图数据库。图数据库只是承载层，真正的检索单元包括实体邻域、关系路径、多跳遍历、社区摘要、Text-to-Cypher、模板查询等。LightRAG 是相对轻量且适合研究的技术选型。当然我们也可以选择自己研究图数据库的算法，然后自己考虑编排（Llamaindex 是非常常用的工具）。不过图检索不一定有价值且大概率很昂贵，建议把图和 BM25、dense、reranker 放在同一评估集上比较。只有关系型、多跳、跨文档问题有稳定收益时，再把图谱升级成基础设施。</p><h3 id="从单路检索到混合检索与-Agentic-RAG"><a href="#从单路检索到混合检索与-Agentic-RAG" class="headerlink" title="从单路检索到混合检索与 Agentic RAG"></a>从单路检索到混合检索与 Agentic RAG</h3><p>理解了这些最小单元，再看工程系统会清楚很多。所谓混合检索，就是让不同检索器各做自己擅长的事，然后在统一候选层合并。随着各种加速算法的成熟，把所有策略全跑一遍也没那么贵，难点在于如何聚合，给 Agent 带来信息而不是噪声。</p><p>混合检索里最容易被低估的是 hard filter。权限、租户、项目、时间、删除状态、版本状态，这些不该交给 reranker 猜，而应该在召回前后作为硬约束生效，我们有 metadata 就应该去利用。企业知识库里，泄露无权限文档比少召回一个 chunk 严重得多。</p><p>候选合并之后，通常还要 dedup、fusion 和 rerank。Dedup 处理同一个 chunk 被多条路径召回、同一段文本在不同版本里重复出现的问题。Fusion 处理不同检索器分数不可比的问题。RRF 很适合这个阶段，因为它按排名融合，不要求 BM25 分数、向量相似度、图路径分数处在同一尺度上。各个数据库 hybrid search 文档，处理的基本就是这类稀疏、稠密和排序融合问题。虽然数据来源变得越来越多，现有的融合方式往往不那么够用，结合项目的需求本身设计合适的融合方案变得很重要。</p><p>Rerank 是另一层。第一阶段召回的目标是别漏，所以可以宽一点；第二阶段 rerank 的目标是排准，可以慢一点。以前的 reranker 往往还是一个神经网络模型，通常比 bi-encoder 更准，但成本更高。而现在，直接让一个 LLM 充当 Reranker 也是常见的情况，毕竟 token 在越来越便宜，还训练干嘛。</p><p>再往前走，就是 Agentic RAG。传统 RAG 是一次 retrieve-then-generate；Agentic RAG 则把检索变成多轮动作：计划、检索、阅读、发现缺口、改写查询、再检索、对照证据、生成答案。它用更多 test-time compute 换召回覆盖、多跳能力和自我校验。换句话说，这也是一种检索侧的 test-time scaling。</p><p>Agentic RAG 是一个蛮有意思的话题，检索从一个确定性行为变成了多轮次的 Agent Action。ReAct 在思想上毫无疑问是他的开篇之作，Thinking 和 Acting 交织，反馈指引下一轮行动。IRCoT 和 Search-o1 将同样的思想扩展到了检索领域。FLARE 用即将生成的内容预测自己缺什么，再主动触发检索。Self-RAG 也是类似的思路，但将“检索与反思自己的检索结果”放到了训练阶段学习，而不是依赖外部启发式方法。 检索在 Agentic RAG 中从一个前置步骤变成了一段自我往复的循环。从 Feedback 信息的角度来看，这绝对是正确的选择。</p><p>工程上要小心两个问题。第一，Agentic RAG 不是免费收益，它会增加延迟、成本和不确定性。第二，多轮检索不等于把更多内容塞进窗口。每一轮都应该产出更好的候选、更窄的 scope 或更明确的缺口；做不到这一点，只是在扩大噪声。</p><h3 id="Agentic-RAG-之后：让结构重新进入检索"><a href="#Agentic-RAG-之后：让结构重新进入检索" class="headerlink" title="Agentic RAG 之后：让结构重新进入检索"></a>Agentic RAG 之后：让结构重新进入检索</h3><p>Agentic RAG 解决的是“什么时候检索、检索什么、检索后如何继续行动”，但它没有自动解决另一个老问题：文档并不是一堆无序 chunk。如果底层仍是扁平文本块，Agent 只是用更高成本反复搜索，仍可能漏掉长文档里集中、连续、有层级分布的证据。很多答案并不是随机散落在全文，而是沿着标题层级、段落顺序和局部叙事组织起来。人读文档通常先看目录、标题和小节位置，再进入某个区域连续阅读；RAG 如果只反复猜关键词、命中零散片段，就很容易错过同一节里没有被 query 明确说出的要求。</p><p>RAPTOR 是较早把这种结构显式做进检索的一条路线。它先把原始文本切成叶子节点，再递归 embedding、聚类、摘要，构造一棵从局部片段到高层摘要的树；查询时可以在树上逐层走，也可以把全树节点摊平后在不同抽象层级中一起检索。这样做的好处是，系统不只拿到最相似的短 chunk，也能召回主题性、跨段落的上层节点，适合需要全局理解和多步综合的问题。不过 RAPTOR 的树是后处理生成的结构，不是文档原生结构；聚类和摘要会重写信息，可能压缩掉细节，甚至引入轻微幻觉。换句话说，它利用了结构，但结构来自模型对文档的再组织。</p><p>DeepRead 更接近把文档原本的结构还给 Agent。它把标题和段落都视为一等实体：标题构成全局导航骨架，带有子标题集合、直属段落数和 token 数，只有这层轻量骨架进入系统提示；段落则作为基本检索和阅读单元，避免答案被滑动窗口切碎。运行时只有两个工具：<code>Retrieve</code> 接收查询字符串，在段落级语义检索后返回段落坐标，并按上下文窗口适当外扩，给 Agent 一个带位置的预览；<code>ReadSection</code> 则按 doc_id、section_id 和段落范围返回连续原文。这样，Agent 可以先定位，再沿着确定区域顺序阅读，而不是在长文档里不断重新搜索关键词。</p><p>这两篇工作放在一起，其实说明 Agentic RAG 之后还有一条很重要的路线：不只是让模型多检索几轮，而是把检索对象从扁平文本块恢复成有位置、有层级、有阅读顺序的文档。RAPTOR 证明了多层抽象结构可以提升长文档 QA，但也提示我们，重写式树结构会带来信息破坏风险；DeepRead 则更保守地利用原生标题和段落顺序，把结构变成 Agent 的导航接口。<strong>比 RAG 更好，往往也会比 RAG 更贵，这是 Agentic Search 带来的直接结果</strong>；但当搜索开始结合意图理解、结构导航和连续阅读，它也会在一定程度上改变搜索本身。</p><h3 id="工程增强：让检索更像-Runtime-决策"><a href="#工程增强：让检索更像-Runtime-决策" class="headerlink" title="工程增强：让检索更像 Runtime 决策"></a>工程增强：让检索更像 Runtime 决策</h3><p>有了基本检索器和混合检索层，真正影响系统质量的，往往是一些工程增强。它们不一定像论文里的主贡献，但在生产系统里很要命。</p><p>第一是信息需求判断。Agent 要先判断当前问题属于哪类：精确定位、语义探索、结构化查询、关系多跳、时效版本、代码符号、无答案判断。不同信息需求应该走不同路线。问”错误码 E1027 是什么”时，BM25 和 grep 比向量更该先出场；问”有没有类似的客户退款政策”时，dense 更有价值；问”这个函数改了会影响谁”时，LSP 与 AST 更重要。</p><p>这就是 router 的价值。它把”该用什么检索器”变成 runtime 决策。LlamaIndex Router Retriever 这类工具提供了一个具体实现：让 LLM 根据 query 选择一个或多个 retriever。更成熟的系统也可以不用 LLM router，而用规则、分类器、查询日志和失败样本训练出路由策略。</p><p>第二是 query rewrite。用户输入通常不是好的检索语句。用户说的是任务，索引里存的是文档片段、代码符号、规则条目、实体关系和历史记录。中间有天然语义落差。很多时候 query rewrite 不是一改一，而是一改多：把一个问题拆成多个检索子问题，扩展不同说法，抽取关键实体，生成结构化 filter，再分别送进不同 retriever。关于 query rewrite 的研究不多（有趣的更是没有），RAG-Fusion&#x2F;HyDE&#x2F;Self-Retrieval 可以作为参考。</p><p>第三是 index-side recall enhancement。前文讲 chunking 时说过，chunk 太小会丢上下文，chunk 太大又会稀释语义。很多增强其实都是在修这个问题。Anthropic 的 Contextual Retrieval 是一个很好的工程例子：在写入索引前，为每个 chunk 生成一段 chunk-specific context，再把这段上下文和原 chunk 一起用于 embedding 和 BM25。Jina 的 Late Chunking 则反过来，先在长文本上产生 contextualized token embeddings，再池化出 chunk embedding，让 chunk embedding 保留更长上下文的信息。Parent document retrieval、sentence window retrieval 也是同一个思路：小粒度负责命中，大粒度负责回填。命中时用小 chunk 保持召回敏感，进入 Working Memory 前再带回父段落、相邻句子、标题路径或页码。</p><p>第四是 promotion。检索结果不应该原样进入上下文，而应该被整理成 evidence pack。一个好的 evidence pack 至少包括：和当前目标直接相关的摘录，必要的父级上下文，source URI、标题路径、页码或行号，版本和时间，置信度，冲突或过期标记，权限和可引用状态。promotion 同时提供本轮次的信息和 Agentic RAG 的未来决策。从而方便他的行动。</p><h3 id="标准候选对象与-LlamaIndex-的价值"><a href="#标准候选对象与-LlamaIndex-的价值" class="headerlink" title="标准候选对象与 LlamaIndex 的价值"></a>标准候选对象与 LlamaIndex 的价值</h3><p>多路检索要想可治理，最好别让业务层直接依赖某个数据库或框架的返回值。BM25、dense、graph、LSP、文件导航，都应该被规整成一种候选对象。可以叫它 <code>RetrievalResult</code>：</p><div class="code-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;query_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;q_20260611_001&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;retriever&quot;</span><span class="punctuation">:</span> <span class="string">&quot;grep|bm25|dense|lsp|graph|file&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;doc_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;doc_123&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;chunk_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;chunk_456&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;source_uri&quot;</span><span class="punctuation">:</span> <span class="string">&quot;file://policy/leave_policy.pdf#page=3&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;title_path&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;人事制度&quot;</span><span class="punctuation">,</span> <span class="string">&quot;休假政策&quot;</span><span class="punctuation">,</span> <span class="string">&quot;年假&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;text&quot;</span><span class="punctuation">:</span> <span class="string">&quot;召回文本...&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;snippet&quot;</span><span class="punctuation">:</span> <span class="string">&quot;高亮片段...&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;score&quot;</span><span class="punctuation">:</span> <span class="number">0.83</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;rank&quot;</span><span class="punctuation">:</span> <span class="number">4</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;metadata&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;tenant_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;tenant_a&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;acl_tags&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;hr&quot;</span><span class="punctuation">,</span> <span class="string">&quot;cn-office&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;active&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;version&quot;</span><span class="punctuation">:</span> <span class="string">&quot;v3&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;provenance&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;indexed_at&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2026-06-11T10:00:00+08:00&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;source_updated_at&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2026-06-10T18:00:00+08:00&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;parser&quot;</span><span class="punctuation">:</span> <span class="string">&quot;docling|ragflow|custom&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><p>这个对象的意义不是 JSON 格式本身，而是边界。检索器负责找候选，编排层负责过滤、融合、去重、重排和压缩，生成层只接收已经带来源和治理信息的证据。以后把 Chroma 换成 LanceDB，把 LanceDB 换成 Qdrant，把 LightRAG 换成 Neo4j GraphRAG，或者把 grep 换成更快的 sparse n-gram search，引入中间层来降低整个系统的耦合是面向未来所必须的。</p><p>LlamaIndex 的价值也可以放在这里理解。它不一定是最终生产系统的唯一框架，但它把很多检索编排抽象产品化了：retriever、router、query fusion、node postprocessor、response synthesizer、property graph retriever。读它的设计，能帮助我们把 RAG 从”调用一个向量库”提升到”组织一组可替换的 read path 组件”。当然，框架仅仅是编排系统的工具，不要让它取代我们对系统的理解以及我们对系统的要求。</p><h2 id="Write-Path：从运行时事件到可重建知识资产"><a href="#Write-Path：从运行时事件到可重建知识资产" class="headerlink" title="Write Path：从运行时事件到可重建知识资产"></a>Write Path：从运行时事件到可重建知识资产</h2><p>如果检索回答”什么该被带进来”，写路径回答的就是”当前发生的事和新增补的信息怎样变成以后可信的记忆”。后者往往更难，因为写错的记忆会在未来持续污染检索结果。</p><p>工程里的 Write 不应该被理解成一次 <code>add_memory</code> 调用，也不应该被理解成把文本 append 到向量库里。更准确的说法是：先决定谁是事实源，哪些只是 projection；再把事实源的一次变化提交成可审计状态；最后让向量索引、BM25、图、文件摘要这些投影异步更新或重建。投影是用于提升 read path 的召回和组织能力，但不应该单独承担真实记忆的职责。</p><p>换句话说，Write Path 的核心不是”把新信息存下来”，而是判断一条新信息如何改变系统对世界的当前解释：它是新增事实、旧事实的新版本、条件化偏好、冲突证据、短期事件，还是根本不该进入长期记忆。</p><h3 id="写入什么：Promotion-与-Persistence-不是对等概念"><a href="#写入什么：Promotion-与-Persistence-不是对等概念" class="headerlink" title="写入什么：Promotion 与 Persistence 不是对等概念"></a>写入什么：Promotion 与 Persistence 不是对等概念</h3><p>进入 Working Memory 的内容，不一定值得写入长期记忆。Promotion 是把外部信息临时带进当前窗口，服务眼前任务；persistence 是把运行时产生的新事实、新规则或新经验写回长期记忆。前者可以相对激进一点，错了最多污染当前轮；后者必须保守，因为写错会污染未来很多次检索。</p><p>这个区分能避免一个常见误区：只要某条内容帮当前任务答对了，就把它沉淀成长期记忆。很多信息只是局部、临时、上下文相关，应该随着任务结束退场。真正适合 persistence 的，是稳定偏好、明确事实、可迁移经验、被反复激活的规则，或者用户主动纠正后形成的新约束。Persistence 的目标不是多记一点，而是让未来的 Read Path 只读到可解释、可回滚、可失效的信息。</p><h3 id="何时写入：运行时记忆写入与知识库写入"><a href="#何时写入：运行时记忆写入与知识库写入" class="headerlink" title="何时写入：运行时记忆写入与知识库写入"></a>何时写入：运行时记忆写入与知识库写入</h3><p>讨论 Write Path 时，最容易混在一起的其实是两类完全不同的写入。</p><p>一类是运行时 Agent memory 写入：用户在对话里纠正系统，工具调用暴露出一个可迁移经验，某个项目约定被反复触发，或者用户明确给出偏好和身份事实。它的触发点是事件，重点是判断这条信息是否稳定、是否跨任务有用、是否应该更新 persona、rule、experience 或 episodic summary。</p><p>另一类是知识库 &#x2F; RAG 写入：连接器拉到新文档，Wiki 页面改了，代码仓库有新 commit，业务数据库导出了一批记录，制度文件换了版本。它的触发点是 source change，重点不是让 LLM 自动记住，而是把外部事实源重新解析、规范化、切 chunk、计算 hash、更新 metadata，再刷新各种检索投影。</p><table><thead><tr><th>维度</th><th>运行时 Agent memory</th><th>知识库 &#x2F; RAG 写入</th></tr></thead><tbody><tr><td>输入来源</td><td>对话、工具调用、用户纠错、环境反馈</td><td>文档、Wiki、代码、工单、业务库、网页抓取</td></tr><tr><td>触发方式</td><td>事件触发：偏好出现、错误被纠正、经验可迁移、规则反复激活</td><td>来源变化：文件更新、connector 同步、定时刷新、CDC、人工发布</td></tr><tr><td>事实源</td><td>memory object、用户 profile、规则文件、审计日志</td><td>document store、对象存储、业务库快照、Git&#x2F;Wiki 历史</td></tr><tr><td>写入对象</td><td>persona、rule、experience、semantic fact、episodic summary</td><td>document、chunk、metadata、source hash、index manifest</td></tr><tr><td>更新策略</td><td>保守写入，必要时请求确认或标记低置信度</td><td>默认可重建；增量更新是规模和新鲜度压力下的优化</td></tr></tbody></table><p>这两类写入都叫 Write，但风险形态不同。运行时写入的危险，是把临时语境、幻觉、用户玩笑或一次性失败固化成长期偏见。知识库写入的危险，则是旧 chunk、旧向量、旧图边和旧摘要残留在投影里，让系统以为自己读到了最新事实。如果我们是在构建一个用户侧的 Agent，那么最常见的是运行时来记住偏好，而如果我们在构建服务，那么往往知识库的稳定与正确就是核心。</p><h3 id="Write-Pipeline：同一个抽象，两条实现路径"><a href="#Write-Pipeline：同一个抽象，两条实现路径" class="headerlink" title="Write Pipeline：同一个抽象，两条实现路径"></a>Write Pipeline：同一个抽象，两条实现路径</h3><p>一个可治理的写路径可以共用同一套抽象，但实现上最好拆成两条路径：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">runtime memory:</span><br><span class="line">  event</span><br><span class="line">    -&gt; memory proposal</span><br><span class="line">    -&gt; gate</span><br><span class="line">    -&gt; normalize</span><br><span class="line">    -&gt; align</span><br><span class="line">    -&gt; commit</span><br><span class="line">    -&gt; project</span><br><span class="line">    -&gt; verify</span><br><span class="line"></span><br><span class="line">KB / RAG ingestion:</span><br><span class="line">  source change</span><br><span class="line">    -&gt; parse / chunk / hash</span><br><span class="line">    -&gt; staging index</span><br><span class="line">    -&gt; evaluate</span><br><span class="line">    -&gt; publish manifest</span><br><span class="line">    -&gt; retire old index</span><br></pre></td></tr></table></figure></div><p>运行时记忆要先生成 <code>memory proposal</code>。proposal 是写入候选，不是已经落库的记忆。它至少要带上候选内容、来源、scope、type、confidence、TTL 或有效期、privacy &#x2F; ACL、idempotency key，以及触发它的事件。这样系统才能区分用户明确说了一个稳定偏好，和模型从一次对话里猜到一个偏好。</p><p><code>gate</code> 决定要不要写。这里要检查稳定性、复用价值、权限边界和来源可靠性。用户主动纠正、外部事实源变更、工具失败复盘，通常比模型自己总结出来的偏好更值得写。很多系统把写入拖到会话结束统一总结，但这会把许多细粒度证据混在一起。更稳的做法是按事件生成 proposal，再由 gate 决定是否提交、降级为 episodic summary，或者只留在当前任务日志里。</p><p><code>normalize</code> 把候选转成稳定 schema：时间、实体、项目、用户、source URI、版本、权限、证据片段都要结构化。对知识库来说，这一步还包括解析文档、保留标题路径和页码、生成 chunk、计算 source hash、记录 parser version 和 embedding model version。</p><p><code>commit</code> 才是真正的写入。它应该写 audit log，而不是只写向量库。commit 需要留下 <code>active</code>、<code>stale</code>、<code>conflicted</code>、<code>deleted</code> 等状态，记录 <code>supersedes</code> &#x2F; <code>superseded_by</code>，必要时保留 <code>valid_at</code>、<code>invalid_at</code>、<code>observed_at</code>、<code>source_updated_at</code>、<code>committed_at</code> 和 <code>index_version</code>。写入更像一次小型状态提交，不是给全局变量赋值。</p><p><code>project</code> 负责刷新投影。语义知识重新生成 embedding，术语和编号进入全文索引，实体关系更新图边，文件型记忆更新目录或摘要，Wiki 页面重新入库。投影可以异步，但必须能追踪；否则 read path 会召回旧向量、旧关键词或已经失效的关系。</p><p><code>verify</code> 则是写入后的回归检查。新文档是否能被召回，旧版本是否被降级，删除是否传播到所有检索通道，权限过滤是否仍然生效，引用是否还能追到原始 source。即便是用户侧 runtime，也不应该只把核查责任丢给用户；至少要提供写入 diff、来源链接、撤销入口和 memory review，让自动写入保持可见。</p><p>知识库写入更像数据发布流程，而不是单条记忆提交。LlamaIndex 的 document management pipeline 用 <code>doc_id</code> 和 hash 判断文档是否变化，避免重复写入，并把 update &#x2F; delete 做成文档级操作。工程上也常用 staging index、离线评估、index manifest 和蓝绿切换来发布新索引。这样做不花哨，但它把”这次知识库到底发布了什么”变成可验证状态。</p><h3 id="写入最难的是对齐旧世界"><a href="#写入最难的是对齐旧世界" class="headerlink" title="写入最难的是对齐旧世界"></a>写入最难的是对齐旧世界</h3><p><code>align</code> 是 Write Path 里最容易被低估的一步。新知识不自然是对旧知识的覆盖，”用户喜欢拿铁”和”用户最近开始戒咖啡”不是一个简单的二选一问题。系统需要知道两条记忆的时间关系、适用条件和冲突状态。把记忆当成”当前最优快照”去 overwrite，时间维度上的信息就被抹掉了。</p><p>这里至少有三类问题。</p><p>第一类是时间变化。旧事实未必是错的，它可能只是过了有效期。用户过去在上海工作，后来搬到杭州，这不是要把”上海”从历史里删掉，而是要标记它在什么时间段成立。Zep &#x2F; Graphiti 这类 temporal graph 把 fact validity 和 provenance 放到中心位置，就是为了让系统能回答”现在什么是真的””当时什么是真的”，而不是只保留最后一次写入的结果。</p><p>第二类是事实矛盾。新旧事实如果不能同时成立，就应该进入 <code>conflicted</code>、<code>superseded</code> 或待确认状态，而不是强行合并。MemConflict 这类评测把 memory conflict 单独拿出来测，原因也在这里：长期记忆系统真正难的不是记住更多，而是在新证据到来时不把矛盾写成一致。</p><p>第三类是条件适用。偏好、规则和经验很少是全局真理。”这个项目用 pnpm”、”这位用户喜欢简短回答”、”这个客户不接受周五发布”都可能有 scope、时间和场景限制。没有条件字段，运行时记忆就会从帮助变成偏见。</p><p>所以 <code>align</code> 不只是 duplicate 检查和相似记忆合并。它要做实体消解、冲突检测、supersede 判断、条件收窄、时间对齐和遗忘传播。Mem0 这类记忆层产品把 add &#x2F; update &#x2F; search 做成显式 API，本质上是在产品化这段 pipeline；LangMem 把 memory operation 表达成”输入 conversation 和当前 memory state，再生成更新后的 memory state”，也说明写入不是单点插入，而是对已有状态的重写和整合。</p><p>由于我们需要 <code>align</code> ，那么如果 action space 只有 append 和 overwrite，系统很快会把历史事实、当前事实、冲突事实和临时结论混在一起。更稳的做法，是把写入动作显式化。</p><ul><li><code>ADD</code>：新增一条没有直接冲突的记忆。</li><li><code>UPDATE</code>：在同一个事实或 profile 内更新字段。</li><li><code>SUPERSEDE</code>：新记忆取代旧记忆，但保留旧记忆的历史身份。</li><li><code>CONFLICT</code>：新旧信息互相矛盾，先标记冲突而不是合并。</li><li><code>ARCHIVE</code>：旧记忆不再默认召回，但仍可审计和恢复。</li><li><code>DELETE</code>：因错误、隐私、权限或用户请求彻底删除。</li><li><code>NOOP</code>：信息太临时、太不确定或已有等价记忆，不写入。</li><li><code>ASK_USER</code>：影响长期行为但证据不足时，请用户确认。</li></ul><p>这组动作的意义，不是把 schema 变复杂，而是让系统承认写入有多种结局。长期记忆系统最危险的状态，是所有新信息都被包装成”更新成功”。</p><p>时间字段也应该服务于这个动作空间。<code>valid_at</code> &#x2F; <code>invalid_at</code> 表达事实在世界中何时成立或失效；<code>observed_at</code> &#x2F; <code>source_updated_at</code> 表达来源何时说过或更新过这件事；<code>committed_at</code> 表达系统何时把它写入记忆。前两者是世界时间，后者是系统时间。把它们混在一起，系统就很难解释为什么一条旧记忆仍然被召回，或者为什么新信息没有立刻覆盖旧信息。</p><h3 id="索引是-Projection：工程上为什么经常重建知识库"><a href="#索引是-Projection：工程上为什么经常重建知识库" class="headerlink" title="索引是 Projection：工程上为什么经常重建知识库"></a>索引是 Projection：工程上为什么经常重建知识库</h3><p>这也是为什么真实工程里，知识库经常不是一直聪明地增量生长（当然研究增量生长的项目也是非常多，这绝对是一个值得思考的能力，尤其是对于用户侧 runtime 的较大知识库），而是反复重建、分区重建或蓝绿切换。听起来笨，但它更可验证。</p><p>增量更新真正难的不是插入一条新 chunk，而是处理一整串连锁问题：旧 chunk 是否已经 stale，删除是否传到向量索引、FTS 和图，旧 chunk 能不能和新 chunk 共存，embedding 模型换了以后旧向量还能不能比较，实体抽取模型改变后旧图边是否还可信。只要这些问题没有被显式建模，增量就会把知识库变成一层层历史残留。</p><p>所以小规模、本地、个人知识库、小团队 PoC，默认全量重建或按目录 &#x2F; 文档集合分区重建往往更合理。重建时重新解析、重新 chunk、重新 embedding、重新跑 BM25 &#x2F; graph extraction，然后用新的 index manifest 替换旧版本。旧索引先不删，验证通过再切流量；出问题就回滚。这比在旧索引上不断打补丁更容易定位问题。</p><p>增量更新适合另一类条件：数据规模大到全量重建太贵；freshness 要求高到不能等下一轮批处理；来源系统能提供可靠变更流；系统已经有 doc_id、source hash、delete tombstone、index version 和 projection lag 监控。Graphiti 则选择实时增量图谱，适合对话和事件流里持续变化的 temporal facts。增量有价值，但不是所有系统一开始都该追的目标。</p><p>图谱尤其应该谨慎。图检索收益还没被验证时，自动增量图谱很容易变成错误关系的放大器。实体消解、关系抽取、边的时间有效性、旧关系失效，全都比普通 chunk upsert 更难。很多时候，先把图作为可重建 projection，用固定语料离线生成和评估，比让运行时持续改图更稳。</p><h3 id="写入评估：不要只测召回"><a href="#写入评估：不要只测召回" class="headerlink" title="写入评估：不要只测召回"></a>写入评估：不要只测召回</h3><p>最后，Write Path 的评估不能只看未来能不能召回。Memory 全景图里那套 L1-L6 框架，在这里可以落成更工程化的指标。</p><p>写入正确性看 <code>write precision</code>：写进去的候选到底有多少是真正稳定、有用、来源可靠的记忆。更新正确性看 duplicate rate、conflict detection、supersede accuracy：新旧事实有没有对齐，有没有重复堆积，有没有把冲突强行合并。投影质量看 projection lag、stale recall rate、delete consistency：提交以后多久能被读到，旧版本是否还在召回，删除是否传到所有索引。</p><p>治理能力还要看 rollback success、audit completeness、citation correctness 和 permission correctness。HaluMem 这类评测已经开始把 memory hallucination 拆到 extraction、updating、QA 这些操作层；LongMemEval 把长期多 session 里的知识更新、时间推理和 abstention 拉进评测；MemoryAgentBench 进一步强调 accurate retrieval、test-time learning、long-range understanding 和 selective forgetting；MemConflict 则把冲突记忆单独拿出来测。方向是对的：不要只问系统记不记得，而要问它写得准不准、改得对不对、删得干不干净、不确定时敢不敢停。</p><h2 id="缓解上下文不足的工程手法"><a href="#缓解上下文不足的工程手法" class="headerlink" title="缓解上下文不足的工程手法"></a>缓解上下文不足的工程手法</h2><p>前面几章解决的是信息怎么进出存储。Context Engineering 更难的部分，在单次任务执行过程中出现：任务跑了几十轮，上下文逼近窗口上限，工作台开始变脏，这时该怎么办？</p><p>这一节只讨论运行时手法。先和<a href="/blog/2026/03/20/building-agent-deterministic-constraints/">《给 LLM 戴上确定性枷锁的外围工程》</a>划清边界：那篇文章也讲 subagent、checkpoint、fork、worktree，但角度是限制即可靠性，把它们看成收窄失败半径的原语。</p><p>这里换一个角度，只看它们怎么帮助管理上下文：哪些信息留下，哪些换出，哪些隔离到别处。</p><h3 id="压缩派：Compaction-与-Context-Reset"><a href="#压缩派：Compaction-与-Context-Reset" class="headerlink" title="压缩派：Compaction 与 Context Reset"></a>压缩派：Compaction 与 Context Reset</h3><p>最直接的办法是压缩（compaction）：把接近窗口上限的对话摘要掉，用摘要重启一个新窗口。</p><p>Anthropic 给的实践要点是：<strong>保留架构决策、未解决的 bug、关键实现细节，丢掉冗余工具输出</strong>；先最大化 recall（别漏掉相关内容），再优化 precision（去掉多余内容）。</p><p>Claude Code 的自动 compact 在上下文超过 95% 时触发，先清理较早的工具输出，必要时再摘要对话，并保留最近访问的 5 个文件。其中最轻量的一种形式是 tool-result clearing：接近 token 上限时，自动清掉上下文里陈旧的工具调用和结果。</p><p>Anthropic 在 <a class="link"   href="https://claude.com/blog/context-management" >context management 的发布<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里给了一组数字：在一个 100 轮 web 搜索测试里，单是 context editing 就削减了 84% 的 token 消耗，带来 29% 的性能提升；配合 memory 工具一起用则达到 39%。</p><p>压缩的风险也明显：过度压缩会丢掉当时看不出重要、后来才显出关键的细节。context reset 是另一种处理方式。compaction 是原地压缩，同一个 agent 带着摘要继续跑，连续性更好；reset 则给下一个 agent 一个干净上下文，只通过一份结构化 handoff artifact 交接必要状态。reset 要付出 handoff 成本，但能切断前面几十轮噪音的影响。选哪一个，取决于你更想保留连续性，还是更需要一个干净起点。Claude 在 Runtime 默认使用 Compact，但对于 Dynimic Workflow 使用了后者，你的选择和你的任务本身息息相关。</p><p>错误也不一定需要立刻清理，虽然注意力的失效并非线性，但开发共识依旧认为我们应该在 Context 窗口稀缺后再考虑压缩或重置。把失败动作和对应 stack trace 留在上下文里，因为模型看到失败会隐式更新自己的信念，从而避免重复同样的错误。从某种意义上讲，错误恢复能力是判断 agentic 行为的清晰指标之一。</p><h3 id="外部化派：把记忆挪到窗口外面"><a href="#外部化派：把记忆挪到窗口外面" class="headerlink" title="外部化派：把记忆挪到窗口外面"></a>外部化派：把记忆挪到窗口外面</h3><p>另一条路是不在窗口里硬扛，把信息外部化到文件系统。Manus 在 <a class="link"   href="https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus" >Context Engineering for AI Agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里把文件系统称作”终极上下文”：容量大、天然持久，Agent 也能直接操作。</p><p>压缩最好是可恢复的。可以丢掉网页正文，但留下 URL；可以省略文档内容，但保留路径。这样需要时还能重新拉回来，避免 compaction 带来的不可逆损失。Anthropic 的结构化笔记（写 <code>NOTES.md</code>、维护 <code>to-do.md</code>）和 Claude 的 file-based memory 工具（如 Claude.md*2，rules，skills）也是这个思路：把记忆放到窗口外，需要时再读回来，并且跨会话存活。</p><p>长循环任务还有一个独立问题：目标漂移。Manus 观察到一个典型任务平均要 ~50 次工具调用。跑到后半程，最初目标会开始掉出注意力。这就是 Lost-in-the-Middle 在 agentic 场景里的表现。此时外部化一个<code>todo.md</code>，每完成一步就重写一次，把当前目标不断推到上下文最末端，也就是模型注意力最强的位置。这也是外部化的思想之一。</p><h3 id="隔离派：Subagent-与-Checkpoint-Fork"><a href="#隔离派：Subagent-与-Checkpoint-Fork" class="headerlink" title="隔离派：Subagent 与 Checkpoint &#x2F; Fork"></a>隔离派：Subagent 与 Checkpoint &#x2F; Fork</h3><p>最后一类是隔离。与其在一个上下文里硬塞，不如把任务切开。</p><p>Subagent 的工程价值不只是提速，更重要的是上下文隔离。子 agent 可以为了探索烧掉数万 token，但只向主 agent 返回一份 1000-2000 token 的压缩摘要（Anthropic 的数字）。主 agent 因此保持干净，详细搜索和探索过程被挡在外面。</p><p>Claude Code 的 <a class="link"   href="https://code.claude.com/docs/en/sub-agents" >subagent<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 给每个子 agent 独立的上下文窗口、定制 system prompt、受限工具集和独立权限。一个只读 reviewer subagent 如果没有 Edit 工具，不许改文件就不只是提示词，而是动作空间限制。</p><p>和隔离配套的是状态管理原语。Claude Code 的 <a class="link"   href="https://code.claude.com/docs/en/checkpointing" >checkpointing<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 在每次用户 prompt 时自动快照文件状态、跨会话持久、30 天后清理，支持五种 rewind（恢复代码 &#x2F; 恢复对话 &#x2F; 两者都恢复 &#x2F; 从某点摘要 &#x2F; 摘要到某点）。</p><p>会话本身是本地 JSONL（见 <a class="link"   href="https://code.claude.com/docs/en/how-claude-code-works" >how Claude Code works<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>）。<code>--continue</code> &#x2F; <code>--resume</code> 在同一会话后面追加消息，<code>--fork-session</code> &#x2F; <code>/branch</code> 则把历史复制成一个新会话、原会话不动。</p><p>从上下文管理角度看，这些原语提供的是换出和分叉能力：把一段上下文存到窗口外，需要时再换回来，或者从一个干净分支重新开始。</p><p>边界再说一次：subagent 隔离、tool-call 隔离、session 隔离作为可靠性原语的系统展开，在确定性枷锁那篇里讲过。这里只取它们的上下文管理视角，也就是把 subagent 当作 <code>Isolate</code> 原语。至于到底选 MAS、Single Agent 还是 Dynamic Workflow，已经进入 Agent 架构选型本身，我放到<a href="/blog/2026/03/03/cognitive-architecture-to-agent-framework/#mas-or-single-agent-and-dynamic-workflow">认知结构那篇的 “MAS or Single Agent and Dynamic Workflow” 一节</a>里讨论。</p><h2 id="结语：Write-Select-Compress-Isolate"><a href="#结语：Write-Select-Compress-Isolate" class="headerlink" title="结语：Write &#x2F; Select &#x2F; Compress &#x2F; Isolate"></a>结语：Write &#x2F; Select &#x2F; Compress &#x2F; Isolate</h2><p>这些手法看起来分散，但 LangChain 在 <a class="link"   href="https://www.langchain.com/blog/context-engineering-for-agents" >Context Engineering for Agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里给了一个好用的分类框架，把它们收成四类动作：</p><ul><li>Write（写出去）：把信息存到窗口外，比如 scratchpad、外部化笔记、跨会话记忆。</li><li>Select（选进来）：把相关信息拉进窗口，比如检索、<code>CLAUDE.md</code> 这类规则文件、记忆召回。</li><li>Compress（压缩）：只留执行任务所需的 token，比如 compaction、摘要、trimming。</li><li>Isolate（隔离）：把上下文切分到不同 agent 或环境，比如 subagent、沙箱。</li></ul><p>对照前文，压缩派是 Compress，外部化派是 Write，检索那章是 Select，隔离派是 Isolate。</p><p><strong>Context Engineering 不是某个单点技巧，需要组合编排这些动作。</strong></p><p>Drew Breunig 还总结过四种常见上下文失败模式：poisoning（幻觉进入上下文并被反复引用）、distraction（上下文多到压过模型自身能力）、confusion（无关内容干扰回答）、clash（上下文里有互相矛盾的部分）。这些坑，基本都能对应到 write、select、compress、isolate 的某个动作没做好。</p><p>“怎么评估一个 Context 系统做得好不好”，我在 Memory 全景图里给过一套 L1-L6 框架：写入正确性、更新正确性、调用及时性、行为一致性、经验迁移可控性、不确定性处理。这里不重复。至于真实 runtime 怎么把存储、检索、写入、隔离这些动作装配起来，留给 teardown 篇逐个介绍。</p><p>Context Engineering 的重点不是把窗口做长，也不是堆一个向量库。更实用的标准是：<strong>系统能不能说明哪些信息进入了当前上下文，哪些被压缩或换出，哪些被隔离在子 agent 里，哪些被写入长期记忆，以及这些决定为什么发生</strong>。窗口会继续有限，注意力也仍然是预算。只要这个前提不变，把上下文当成有限资源来调度，就是 Agent 工程的一项基础能力。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>Anthropic, <a class="link"   href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" >Effective context engineering for AI agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic &#x2F; Claude, <a class="link"   href="https://claude.com/blog/context-management" >Managing context on the Claude Developer Platform<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic Docs, <a class="link"   href="https://code.claude.com/docs/en/memory" >Claude Code Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool" >Memory tool<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Manus, <a class="link"   href="https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus" >Context Engineering for AI Agents: Lessons from Building Manus<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Chroma, <a class="link"   href="https://www.trychroma.com/research/context-rot" >Context Rot: How Increasing Input Tokens Impacts LLM Performance<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>LangChain, <a class="link"   href="https://www.langchain.com/blog/context-engineering-for-agents" >Context Engineering for Agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>LangChain Docs, <a class="link"   href="https://docs.langchain.com/oss/python/concepts/memory" >Memory overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://docs.langchain.com/oss/python/langchain/long-term-memory" >Long-term memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>LangMem, <a class="link"   href="https://langchain-ai.github.io/langmem/concepts/conceptual_guide/" >Conceptual Guide<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>OpenAI Help Center, <a class="link"   href="https://help.openai.com/articles/8590148-memory-faq" >Memory FAQ<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>OpenAI Codex, <a class="link"   href="https://developers.openai.com/codex/guides/agents-md" >Custom instructions with AGENTS.md<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>GitHub Docs, <a class="link"   href="https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions" >Custom instructions for GitHub Copilot<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Gemini CLI, <a class="link"   href="https://google-gemini.github.io/gemini-cli/docs/cli/gemini-md.html" >Provide context with GEMINI.md files<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://google-gemini.github.io/gemini-cli/docs/tools/memory.html" >Memory Tool<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Cursor Docs, <a class="link"   href="https://cursor.com/docs/rules" >Rules<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；Cursor, <a class="link"   href="https://cursor.com/blog/semsearch" >SemSearch<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://cursor.com/blog/fast-regex-search" >Fast Regex Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2307.03172" >Lost in the Middle: How Language Models Use Long Contexts<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2005.11401" >Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2312.10997" >Retrieval-Augmented Generation for Large Language Models: A Survey<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>ripgrep, <a class="link"   href="https://github.com/BurntSushi/ripgrep" >ripgrep<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Stephen Robertson and Hugo Zaragoza, <a class="link"   href="https://www.staff.city.ac.uk/~sbrp622/papers/foundations_bm25_review.pdf" >The Probabilistic Relevance Framework: BM25 and Beyond<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>SQLite, <a class="link"   href="https://sqlite.org/fts5.html" >FTS5<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://sqlite.org/vec1.html" >vec1<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Alex Garcia, <a class="link"   href="https://github.com/asg017/sqlite-vec" >sqlite-vec<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://github.com/asg017/sqlite-vss" >sqlite-vss<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>PostgreSQL Docs, <a class="link"   href="https://www.postgresql.org/docs/current/textsearch.html" >Full Text Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://www.postgresql.org/docs/current/pgtrgm.html" >pg_trgm<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Microsoft, <a class="link"   href="https://microsoft.github.io/language-server-protocol/" >Language Server Protocol<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Tree-sitter, <a class="link"   href="https://tree-sitter.github.io/tree-sitter/" >Tree-sitter<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2004.04906" >Dense Passage Retrieval for Open-Domain Question Answering<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/1702.08734" >Billion-scale similarity search with GPUs<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>pgvector, <a class="link"   href="https://github.com/pgvector/pgvector" >pgvector<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>LanceDB, <a class="link"   href="https://docs.lancedb.com/search/hybrid-search/" >Hybrid Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；Qdrant, <a class="link"   href="https://qdrant.tech/documentation/search/hybrid-queries/" >Hybrid Queries<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；Weaviate, <a class="link"   href="https://docs.weaviate.io/weaviate/search/hybrid" >Hybrid Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；Elasticsearch, <a class="link"   href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion" >Reciprocal rank fusion<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://cormack.uwaterloo.ca/cormacksigir09-rrf.pdf" >Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/1901.04085" >Passage Re-ranking with BERT<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2003.06713" >Document Ranking with a Pretrained Sequence-to-Sequence Model<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；BAAI, <a class="link"   href="https://bge-model.com/tutorial/5_Reranking/5.1.html" >BGE Reranker<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>ParadeDB, <a class="link"   href="https://github.com/paradedb/paradedb" >ParadeDB &#x2F; pg_search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2210.03629" >ReAct: Synergizing Reasoning and Acting in Language Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2212.10509" >Interleaving Retrieval with Chain-of-Thought Reasoning for Knowledge-Intensive Multi-Step Questions<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2305.06983" >Forward-Looking Active REtrieval augmented generation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2310.11511" >Self-RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2401.15884" >Corrective Retrieval Augmented Generation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2402.03367" >RAG-Fusion<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2212.10496" >Precise Zero-Shot Dense Retrieval without Relevance Labels<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2305.14283" >Query Rewriting for Retrieval-Augmented Large Language Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic, <a class="link"   href="https://www.anthropic.com/news/contextual-retrieval" >Introducing Contextual Retrieval<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；Jina AI, <a class="link"   href="https://arxiv.org/abs/2409.04701" >Late Chunking<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；LangChain, <a class="link"   href="https://python.langchain.com/docs/how_to/parent_document_retriever/" >Parent Document Retriever<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；LlamaIndex, <a class="link"   href="https://developers.llamaindex.ai/python/examples/node_postprocessor/metadatareplacementdemo/" >Sentence Window Retrieval<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2602.05014" >DeepRead: Document Structure-Aware Reasoning to Enhance Agentic Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2401.18059" >RAPTOR: Recursive Abstractive Processing for Tree-Organized Retrieval<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2404.16130" >From Local to Global: A Graph RAG Approach to Query-Focused Summarization<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>LightRAG, <a class="link"   href="https://github.com/HKUDS/LightRAG" >LightRAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2109.10086" >SPLADE v2<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2004.12832" >ColBERT<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>LlamaIndex, <a class="link"   href="https://developers.llamaindex.ai/python/framework/integrations/retrievers/router_retriever/" >Router Retriever<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://developers.llamaindex.ai/python/framework/integrations/retrievers/reciprocal_rerank_fusion/" >Reciprocal Rerank Fusion<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://docs.llamaindex.ai/en/stable/module_guides/indexing/lpg_index_guide/" >PropertyGraphIndex<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://docs.llamaindex.ai/en/stable/module_guides/querying/response_synthesizers/" >Response Synthesizers<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://docs.llamaindex.ai/en/stable/module_guides/querying/node_postprocessors/" >Node Postprocessors<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://developers.llamaindex.ai/python/examples/ingestion/document_management_pipeline/" >Document Management Pipeline<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Microsoft GraphRAG, <a class="link"   href="https://microsoft.github.io/graphrag/cli/" >CLI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://microsoft.github.io/graphrag/index/overview/" >Indexing Overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Mem0, <a class="link"   href="https://docs.mem0.ai/overview" >Docs<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://docs.mem0.ai/platform/quickstart" >Quickstart<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://github.com/mem0ai/mem0" >GitHub<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Zep &#x2F; Graphiti, <a class="link"   href="https://help.getzep.com/graphiti/getting-started/overview" >Graphiti docs<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://github.com/getzep/graphiti" >GitHub<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://arxiv.org/abs/2501.13956" >Zep: A Temporal Knowledge Graph Architecture for Agent Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Letta, <a class="link"   href="https://docs.letta.com/guides/agents/memory" >Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://docs.letta.com/guides/core-concepts/memory/context-hierarchy" >Context hierarchy<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Andrej Karpathy, <a class="link"   href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f" >LLM Wiki<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2511.03506" >HaluMem<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2410.10813" >LongMemEval<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://openreview.net/forum?id=DT7JyQC3MR" >MemoryAgentBench<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2605.20926" >MemConflict<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2502.12110" >A-MEM: Agentic Memory for LLM Agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://arxiv.org/abs/2305.10250" >MemoryBank: Enhancing Large Language Models with Long-Term Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Neo4j, <a class="link"   href="https://neo4j.com/docs/cypher-manual/current/indexes/semantic-indexes/vector-indexes/" >Vector Indexes<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；<a class="link"   href="https://neo4j.com/docs/neo4j-graphrag-python/current/" >Neo4j GraphRAG Python<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic Docs, <a class="link"   href="https://code.claude.com/docs/en/sub-agents" >Subagents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://code.claude.com/docs/en/checkpointing" >Checkpointing<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://code.claude.com/docs/en/how-claude-code-works" >How Claude Code works<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a href="/blog/2026/03/21/agent-memory-panorama/">《从记忆形成到记忆治理：Agent Memory 的全景图》</a></li><li><a href="/blog/2026/03/03/cognitive-architecture-to-agent-framework/">《从智能体的认知结构到智能体框架》</a></li><li><a href="/blog/2026/03/20/building-agent-deterministic-constraints/">《给 LLM 戴上确定性枷锁的外围工程：从 Claude Code 看 Agent Harness》</a></li><li><a href="/blog/2026/04/26/output-token-pricing-kv-cache-agent-cost/">《为什么 Output Token 更贵：从 KV Cache 到 Agent 成本工程》</a></li><li><a href="/blog/2026/06/07/agent-runtime-teardown/">《拆开 Agent Runtime：记忆、上下文与隔离在真实系统里如何被装配》</a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/11/agent-context-engineering/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/11/agent-context-engineering/"/>
    <published>2026-06-10T20:00:00.000Z</published>
    <summary>Treating context as a finite resource: from context rot and attention budgets to storage structures, retrieval pipelines, time-aligned writes, version governance, and runtime techniques such as compaction, reset, subagents, and checkpointing.</summary>
    <title>Context Is All You Need: Context Engineering for Agents</title>
    <updated>2026-07-01T15:56:19.867Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="Data Curation" scheme="https://hyacehila.github.io/tags/Data-Curation/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Retrieval" scheme="https://hyacehila.github.io/tags/Retrieval/"/>
    <content>
      <![CDATA[<p>把 Tavily、Exa、Firecrawl、Crawl4AI、Jina Reader、Nimble、GPT Researcher、Open Deep Research 这些名字排成一列，很容易写成工具百科。每个工具一小节，讲功能、价格、适用场景。读完能认一堆名词，但还是不知道自己到底该接哪一层。</p><p>我更想换个问法：AI Agent 到底怎样从互联网里拿到可用信息？</p><p>对人来说，互联网通常是浏览器、搜索框、网页和链接。对 Agent 来说，它是一条很长的信息管线：先发现可能相关的来源，再打开页面，抽取正文，去掉导航和广告，把动态页面或 PDF 转成模型能读的文本，然后筛掉重复、过时和互相冲突的片段，最后带着引用进入上下文。中间任何一段坏掉，模型后面说得再顺也只是顺着坏材料往下编。</p><p>所以这篇文章不按厂商逐个介绍，而是沿着这条管线往下看。搜索、网页抓取和结构化清洗不是同一个问题。但他们都和 Agent 从互联网获取信息息息相关。</p><p>整体介绍：</p><table><thead><tr><th>阶段</th><th>代表工具</th><th>主要卡点</th><th>相对上一阶段的变化</th><th>仍然留下的问题</th></tr></thead><tbody><tr><td>模型内置联网</td><td>OpenAI Web Search、Claude Web Search、Gemini Grounding、xAI Web Search &#x2F; X Search</td><td>让模型在生成过程中直接查实时信息并给出来源</td><td>接入最快，开发者不必自己搭搜索和阅读链路</td><td>搜索过程、来源选择、中间证据和重试策略不够透明</td></tr><tr><td>托管式 Web Retrieval</td><td>Tavily、Exa，以及传统搜索&#x2F;SERP API</td><td>把搜索和初步读取打包成可调用 API</td><td>开发者可以控制 query、域名、时间、结果数量和输出形态</td><td>已经拿到材料，不代表解析、清洗和证据组织都可靠</td></tr><tr><td>网页解析、抓取与结构化清洗</td><td>Firecrawl、Crawl4AI、Jina Reader、Trafilatura</td><td>把 URL、站点和文档转成可进入上下文或知识库的数据</td><td>从返回链接变成可读取、可遍历、可抽取的材料</td><td>动态页面、表格、元数据、去重和版本治理仍要处理</td></tr><tr><td>Deep Research 变成长程工作流</td><td>Open Deep Research、GPT Researcher、STORM、Perplexica</td><td>把搜索、阅读、综合和引用组织成多步研究循环</td><td>工具调用不再是一次搜索，而是 query planning、multi-hop search、交叉验证</td><td>评估困难，引用正确不代表结论可靠，报告容易看起来很像真的</td></tr><tr><td>商业抓取平台化</td><td>Nimble、Bright Data、Oxylabs</td><td>把高风控、地区化、动态页面、SERP、电商和社媒采集交给专门平台</td><td>从“能解析页面”进入“能稳定拿到目标场景的数据”</td><td>仍要决定采什么、如何入库、如何进入 RAG、Agent 或分析系统</td></tr></tbody></table><h2 id="第一阶段：模型内置联网，最快也最黑箱"><a href="#第一阶段：模型内置联网，最快也最黑箱" class="headerlink" title="第一阶段：模型内置联网，最快也最黑箱"></a>第一阶段：模型内置联网，最快也最黑箱</h2><p>最省事的做法，是直接用模型厂商提供的联网工具。OpenAI 的 <a class="link"   href="https://developers.openai.com/api/docs/guides/tools-web-search" >Web Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、Anthropic 的 <a class="link"   href="https://platform.claude.com/docs/en/docs/agents-and-tools/tool-use/web-search-tool" >Claude web search tool<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、Gemini 的 <a class="link"   href="https://ai.google.dev/gemini-api/docs/google-search" >Grounding with Google Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、xAI 工具文档里的 <a class="link"   href="https://docs.x.ai/developers/tools/web-search" >Web Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://docs.x.ai/developers/tools/x-search" >X Search<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，都属于这一层。</p><p>这条路线省事。你不用自己决定搜索引擎，不用写爬虫，不用处理页面清洗，也不用设计引用格式。模型需要新信息时自己搜，拿到结果，再把答案和引用一起返回。对很多通用问答、简单资料查询、新闻背景补充来说，这已经够用。</p><p>麻烦也在这里：搜索过程对于我们变成了一个黑盒。</p><p>开发者能看到最终答案和部分引用，却不一定能完整看到它为什么搜这个 query、为什么选择这些来源、为什么放弃另一些来源、有没有漏掉重要页面。联网能力此时从一次工具调用变成模型内部的策略。OpenAI 的 Response API 进一步放大了这一点，用户请求的 API 不再是一个模型而是一套服务，而用户无权了解服务内部的细节。</p><p>这对开发者是双刃剑。</p><p>如果你只是想问这个产品今天发布了吗，黑箱一点没关系。可如果你在做金融、法律、医疗、企业舆情、竞争情报，或者任何需要回放证据链的系统，黑箱就会变得难受。你需要知道系统搜过什么、没搜什么、每条引用来自哪里、同一结论有没有第二来源支撑。模型内置联网可以给你答案，但不一定可信。</p><p>所以第一阶段解决的是模型能不能接触新信息。它没有解决开发者能不能管理这次信息获取。</p><h2 id="第二阶段：托管式-Web-Retrieval，把搜索和初步读取打包"><a href="#第二阶段：托管式-Web-Retrieval，把搜索和初步读取打包" class="headerlink" title="第二阶段：托管式 Web Retrieval，把搜索和初步读取打包"></a>第二阶段：托管式 Web Retrieval，把搜索和初步读取打包</h2><p>第二阶段不是简单地把搜索从模型内部拆出来，也不是退回传统搜索结果页。更准确地说，它把“搜索 + 初步内容获取”打包成一个托管 API。</p><p>Tavily 和 Exa 很接近。它们都在试图把搜索结果变成模型能继续消费的材料：接收或生成 query，找到相关网页，返回答案、摘要、正文、引用或 highlights。真正的差异在封装程度和控制权。</p><p><a class="link"   href="https://docs.tavily.com/" >Tavily<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 更像一站式 Agent web layer。它把 search、extract、crawl、map 和 cited research 放在同一个产品语境里，适合快速给 Agent 接上外部网页信息。你可以把它理解成少搭几段管线：先拿到可读结果，再让模型继续推理。</p><p><a class="link"   href="https://exa.ai/docs/reference/search" >Exa<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 更像可控的语义检索和内容获取接口。它的 Search API 可以在搜索时同时取 contents，文档和 changelog 也强调 Markdown content、新鲜度控制（用 <code>maxAgeHours</code> 决定是否要更新页面）、domain filtering、highlights 等能力。它给开发者留下更多旋钮：来源范围、内容格式、新鲜度、是否要正文。</p><p>Brave Search API、SerpApi、Serper 这类搜索结果接口也能作为来源发现层补充，但本文不展开 SERP 生态。大部分 Agent 开发用不到这些，利用更加成熟的服务就够了。</p><p>到了这一层，开发者拿到的不再只是一组 URL 或 snippet。托管检索 API 已经帮你做了一部分读取和整理，并保留了一些可以控制的自由度。</p><p>但它仍然不能替代专门的解析层。只要你要自建知识库、做可复现评估、处理大量 URL，或者要求正文、表格、元数据保真，读取和清洗就会重新变成独立工程层。</p><h2 id="第三阶段：网页解析、抓取与结构化清洗合到一起"><a href="#第三阶段：网页解析、抓取与结构化清洗合到一起" class="headerlink" title="第三阶段：网页解析、抓取与结构化清洗合到一起"></a>第三阶段：网页解析、抓取与结构化清洗合到一起</h2><p>到这一层，问题从检索 API 返回了什么，变成任意 URL、文档站和文件怎样稳定进入模型上下文。</p><p>托管检索 API 越好，越容易让人误以为网页解析已经不是问题。实际不是。网页对人是可读页面，对模型却常常是一堆噪声：导航栏、推荐栏、cookie 弹窗、广告、CSS class、hydration 数据、评论区、隐藏节点、脚本、重复页脚。单页读取、站点抓取、结构化抽取看起来是三个功能，放到 RAG 和 Agent 里，其实是一条连续链。</p><p>Firecrawl 正好站在这条链的中间。<a class="link"   href="https://docs.firecrawl.dev/features/scrape" >Scrape<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 负责把单个 URL 转成 Markdown、HTML、JSON、截图等格式，也可以处理 PDF 等非网页内容；<a class="link"   href="https://docs.firecrawl.dev/features/crawl" >Crawl<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 负责递归遍历站点，并处理 sitemap、JavaScript 渲染、路径过滤和深度限制；Map 用来发现站点结构；<a class="link"   href="https://docs.firecrawl.dev/features/extract" >Extract<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则把一个或多个 URL、甚至整个 domain 的内容按 prompt 或 schema 抽成结构化字段。这样看，Firecrawl 不是单纯 reader，也不是单纯 crawler，而是在帮开发者少维护一截抓取和清洗栈。</p><p>这也是它适合 Agent 和 RAG 的地方：你想少碰代理、渲染、PDF、站点遍历这些脏活，又想拿到相对干净的输入材料。Firecrawl 可以承担这层基础工作。后面怎么去重、怎么切 chunk、怎么判断来源可信、怎么把结果写入知识库，还是你的系统设计。</p><p>其他工具可以作为补充。<a class="link"   href="https://jina.ai/reader/" >Jina Reader<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 适合临时 URL 阅读，简单、快，但不承担站点级治理。<a class="link"   href="https://trafilatura.readthedocs.io/en/latest/" >Trafilatura<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是自建 Python 文本抽取管线时很实用的正文抽取工具，是在生成式 AI 出现之前的和好的工程化手段。<a class="link"   href="https://github.com/unclecode/crawl4ai" >Crawl4AI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则适合想把抓取能力留在本地的团队：自己控制并发、缓存、页面选择和部署，也自己承担失败恢复和维护成本。</p><p>读取不是搜索的附属品。搜索只告诉你哪里可能有答案。解析和抓取决定这些材料能不能干净地进入上下文。很多 RAG 系统看起来是检索坏了，其实是读取阶段就已经坏了：正文没抽出来，表格丢了，旧版本文档和新版本文档混在一起，目录页被当成内容页，PDF 被切成一堆没有上下文的碎片。</p><p>这些问题不像模型能力那么耀眼，但它们决定 RAG 和 research agent 的地基稳不稳。</p><h2 id="第四阶段：Deep-Research-把检索变成长程工作流"><a href="#第四阶段：Deep-Research-把检索变成长程工作流" class="headerlink" title="第四阶段：Deep Research 把检索变成长程工作流"></a>第四阶段：Deep Research 把检索变成长程工作流</h2><p>再往上走，检索不再是单次搜索，而是一段研究过程。</p><p>OpenAI 文档把 deep research 描述成更长时间的 agent-driven investigation。开源世界里，<a class="link"   href="https://github.com/langchain-ai/open_deep_research" >Open Deep Research<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://github.com/assafelovic/gpt-researcher" >GPT Researcher<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://github.com/stanford-oval/storm" >STORM<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>、<a class="link"   href="https://github.com/ItzCrazyKns/Perplexica" >Perplexica<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>（现已更名 Vane）都在做相近的事：给定一个问题，系统自动拆 query，搜索多个来源，阅读网页，整理证据，生成报告，并尽量带上引用。</p><p>这类系统处理的东西把搜索放进了一个循环：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">问题</span><br><span class="line">  -&gt; 拆成子问题</span><br><span class="line">  -&gt; 生成搜索 query</span><br><span class="line">  -&gt; 找来源</span><br><span class="line">  -&gt; 读取和抽取页面</span><br><span class="line">  -&gt; 判断证据是否足够</span><br><span class="line">  -&gt; 继续搜索或修正方向</span><br><span class="line">  -&gt; 综合报告</span><br><span class="line">  -&gt; 引用和反查</span><br></pre></td></tr></table></figure></div><p>这一层会暴露一个新问题：引用不等于可信。</p><p>一个 research agent 可以给每段话配链接，但链接可能只支持其中一半。它也可能引用了正确网页，却误读了网页；或者找到很多来源，但来源都互相抄。更麻烦的是，长报告天然容易显得可靠。段落完整，引用齐全，语气冷静，人就会放松警惕。</p><p>所以 benchmark 开始跟上来。OpenAI 的 <a class="link"   href="https://openai.com/index/browsecomp/" >BrowseComp<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 用 1,266 个难找但可验证的短答案问题测浏览器 Agent 的持久搜索能力；<a class="link"   href="https://arxiv.org/abs/2311.12983" >GAIA<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 测一般 AI assistants 在工具使用、网页、推理等混合任务上的表现；<a class="link"   href="https://agentresearchlab.com/benchmarks/deepresearch-bench/index.html" >DeepResearch Bench<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://arxiv.org/abs/2505.19253" >DeepResearchGym<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则更直接地看 deep research systems 的报告、证据和可复现性。</p><p>这些评测有自己的局限。短答案不等于真实研究，LLM-as-judge 也不是最终裁判。但它们至少提醒我们：新的难点真正难的是持续找、反复查、知道自己还缺什么，并把证据和结论对齐。</p><h2 id="第五阶段：商业抓取平台化"><a href="#第五阶段：商业抓取平台化" class="headerlink" title="第五阶段：商业抓取平台化"></a>第五阶段：商业抓取平台化</h2><p>普通网页解析解决的是给我一个 URL，我能不能读干净。再往后，难题会变成在高风控、高规模、强地区差异的网站上，系统能不能持续拿到可用数据。这时问题不只是 HTML 清洗，而是代理网络、浏览器渲染、反封锁、目标站适配、批量任务和交付方式。</p><p>这就是 Nimble、Bright Data、Oxylabs 这类商业抓取平台出现的位置。它们不是让模型更会总结，而是把网页数据采集里最容易拖垮系统的部分平台化：代理和地区化访问、JavaScript 渲染、SERP 采集、电商页面解析、社媒、地图和本地搜索数据、批量任务调度，以及结构化结果输出。</p><p><a class="link"   href="https://www.nimbleway.com/" >Nimble<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 更像面向实时网页数据的托管采集层。它提供 Web、SERP、E-commerce、Maps 等 API，把代理、地区化访问、浏览器渲染、反封锁和数据交付封装起来。对 Agent 或 RAG 系统来说，Nimble 解决的是稳定拿到某类页面背后的结构化事实。</p><p><a class="link"   href="https://brightdata.com/" >Bright Data<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 的重心更偏完整的数据采集基础设施：代理网络、Web Scraper API、SERP API、预置 scraper、数据集和结构化输出。它适合价格监控、电商目录、搜索结果、公开网页数据集这类任务，把反机器人、验证码处理、目标站适配和 JSON&#x2F;CSV 交付尽量放到平台侧。<a class="link"   href="https://oxylabs.io/" >Oxylabs<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 也在类似位置，但更强调企业级代理网络和大规模公共网页数据采集。</p><p>这三类平台共同帮我们做的，不是理解网页，而是让网页数据持续可得。代理、解封、渲染、解析、批量采集、目标站适配和交付方式交给成熟平台之后，应用侧更该关心的是：到底要什么数据，多久更新一次，进入 RAG、Agent 或分析系统之前要保留哪些字段和证据。</p><h2 id="两条真正的主线：看见什么，控制什么"><a href="#两条真正的主线：看见什么，控制什么" class="headerlink" title="两条真正的主线：看见什么，控制什么"></a>两条真正的主线：看见什么，控制什么</h2><p>把这些工具读完后，可以把问题收成两条线。</p><p>第一条是 Agent 看见什么。</p><p>模型内置联网让它看见最终搜索结果和引用。托管检索 API 让它看见候选来源和初步整理后的材料。解析和抓取层让它看见正文、站点结构和结构化字段。Deep Research 系统让它看见一串中间证据。商业抓取平台则让它更稳定地看见 SERP、电商、社媒、地图和地区化页面里的目标数据。</p><p>信息不是从网页进入模型这么简单。它在每一层都会被重写：SERP snippet、Markdown、chunk、JSON schema、summary、citation、report。每重写一次，就多一次丢失和误解的机会。</p><p>第二条是开发者能控制什么。</p><p>模型内置联网控制最少，但省事。托管检索 API 让你控制 query、来源和一部分内容获取。解析工具让你控制页面读取和清洗。抓取框架让你控制站点遍历。结构化抽取让你控制字段。Deep Research 框架让你控制研究循环。商业抓取平台让你把代理、地区、目标站适配和数据交付变成更稳定的外部能力。</p><p>这也是选型时最该问的问题：你愿意把哪一层交给模型，哪一层必须握在自己手里？</p><h2 id="工具选型应该回到你卡在哪一层"><a href="#工具选型应该回到你卡在哪一层" class="headerlink" title="工具选型应该回到你卡在哪一层"></a>工具选型应该回到你卡在哪一层</h2><p>如果你缺的是最新信息，但任务很轻，先用模型内置联网。OpenAI、Claude、Gemini、Grok 这类能力够快，也省事。</p><p>如果你想快速拿到可消费网页材料，看 Tavily 和 Exa。Tavily 更像一站式 Agent web layer，Exa 更适合可控的语义检索和 contents 获取。传统搜索&#x2F;SERP API 可以作为补充，但不要把它们误认为已经解决了网页读取和证据组织。</p><p>如果你搜到了材料但读不干净，看 Firecrawl、Jina Reader、Trafilatura。不要急着换模型。先确认网页有没有被正确解析、清洗和分解。</p><p>如果你缺的是站点级抓取、RAG 语料建设和结构化清洗，看 Firecrawl 的 Crawl、Map、Extract，或者看 Crawl4AI 这种自托管路线。这里的问题已经是数据工程，搜索只是入口。</p><p>如果你缺的是长程研究能力，看 Open Deep Research、GPT Researcher、STORM、Perplexica，同时要配套评估。没有评估的 Deep Research，很容易变成漂亮报告生成器。</p><p>如果你缺的是高风控站点、SERP、电商、社媒、价格监控或地区化访问，看 Nimble、Bright Data、Oxylabs。这里的重点不是让模型更聪明，而是让系统稳定拿到目标数据。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>互联网进入 Agent，不是一根网线接到模型上。</p><p>它更像一条不断拆分的工程链路：搜索负责发现来源，读取负责拿到正文，清洗负责降低噪声，结构化负责变成字段，研究循环负责补证据，商业抓取平台负责让高风控和地区化网页数据稳定可得。</p><p>模型越强，这条链路需要做的更清楚。因为模型会把坏材料说得很像真的。以前搜索结果坏了，人还能自己点开看一眼；现在 Agent 会替人读、替人总结、替人写报告。它读错的同时，错误也被包装好了。</p><p>好的 Agent 信息获取系统，不会把所有网页都塞给模型。我们需要更好的生成效果，也需要让它更值得被人类相信。</p>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/10/ai-agent-retrieval-tools/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/10/ai-agent-retrieval-tools/"/>
    <published>2026-06-09T20:00:00.000Z</published>
    <summary>A systems view of how web information enters agent context, from built-in web search and search APIs to scraping, structured extraction, deep research workflows, and commercial web data platforms.</summary>
    <title>How AI Agents Get Information from the Web: Search, Crawling, and Structured Extraction</title>
    <updated>2026-07-01T15:56:19.867Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Systems" scheme="https://hyacehila.github.io/categories/agent-systems/"/>
    <category term="Methodology" scheme="https://hyacehila.github.io/tags/Methodology/"/>
    <category term="Tool Use" scheme="https://hyacehila.github.io/tags/Tool-Use/"/>
    <category term="Software Engineering" scheme="https://hyacehila.github.io/tags/Software-Engineering/"/>
    <content>
      <![CDATA[<p>最近有个说法挺容易让人心动：AI 以后不该再输出 Markdown ，而应该直接给 HTML。</p><p>这话不是纯粹为了造梗。Claude Code 团队的 Thariq Shihipar 写了《Using Claude Code: The unreasonable effectiveness of HTML》，Simon Willison 又转述了一次，然后 Karpathy 又来吹了吹。那篇文章的例子很实在：代码审查、调研报告、图表、交互式编辑器、PR 说明，都可以做成一个能在浏览器里打开的 <code>.html</code> 文件。和一长串 Markdown 比，它确实更像一个可以上手用的工作台。</p><p>看起来挺让人心动的，应该有不少人都遇到过手机打不开<code>.md</code>的问题。</p><p>很多时候，我们不是缺内容，而是缺一个让人愿意读下去的界面。AI 可以吐出两千行分析、二十个风险点、十几个文件之间的调用关系，但人眼面对一整屏等宽字体时，很容易直接进入略读模式。换成有导航、有层级、有展开折叠、有图示的 HTML，情况会好很多。不是因为 HTML 更高级，而是因为人理解复杂系统时，确实需要一些空间和停顿。而HTML就是为了这种交互而设计的。</p><p>但HTML 应该取代 Markdown？</p><p>对我来说，HTML 适合作为一层交互界面。它让我更愿意读，也更容易看懂复杂系统。可它不适合慢慢积攒在仓库里成事实源。事实源要能被 diff 检查，要能被 grep 找到，要能在几个月后回答一句很具体的问题：这次到底改了什么。</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin:28px 0 34px;">  <div style="border:1px solid #e5e7eb;border-radius:14px;padding:20px 18px;background:#fafafa;">    <strong style="display:block;font-size:1.08em;margin-bottom:8px;">Markdown · 事实层</strong>    <p style="margin:0;color:#555;font-size:0.95em;line-height:1.6;">留下可 diff、可 grep、可追溯的记录。计划、结论、任务状态和审查意见，最后都要回到这里。</p>  </div>  <div style="border:1px solid #e5e7eb;border-radius:14px;padding:20px 18px;background:#fafafa;">    <strong style="display:block;font-size:1.08em;margin-bottom:8px;">HTML · 界面层</strong>    <p style="margin:0;color:#555;font-size:0.95em;line-height:1.6;">把复杂关系摊开给人看。它可以生成、刷新、丢弃，也可以把人的选择写回事实层。</p>  </div></div><h2 id="HTML-赢在阅读和理解"><a href="#HTML-赢在阅读和理解" class="headerlink" title="HTML 赢在阅读和理解"></a>HTML 赢在阅读和理解</h2><p>复杂系统里最难读的往往不是结论，而是关系：哪个模块依赖哪个模块，状态在哪里流动，改动会碰到哪些边界，风险藏在哪条调用链后面。Markdown 可以描述这些东西，但描述到一定复杂度就开始吃力。HTML 可以把它们变成图、表、分栏、时间线、可折叠区域，甚至是一个可以拖动和过滤的小工具。</p><p>这不是装饰。关系本来就带有空间感。你把它总结成段落，读者要在脑子里重新建模；你把它展开成一个界面，读者可以先扫结构，再钻细节。Claude 那篇文章里列出来的示例集，真正有说服力的地方也在这里：很多输出不是「排版更漂亮的 Markdown」，而是把原本很难扫读的材料改成了一个可以操作的视图。</p><p>review 也是一样。一个模型给出上千行 markdown 方案，谁能一口气 review 这么多内容呢？ 人的注意力是自然会涣散掉的。HTML 可以让人先看到摘要，再按模块展开；先看风险，再点进证据；先看文件列表，再看每个文件的修改意图。阅读不再只剩一路往下滚，人也比较可能真的读完。</p><p>临时协作时，HTML 也顺手。一个自包含文件发出去，对方点开就能看。里面可以有勾选框、过滤器、复制按钮，也可以把某段内容整理成 prompt。对很多一次性分析、会议材料、PR 辅助审查来说，这比 Markdown 省事。</p><p>所以我并不反对 HTML。相反，AI 工具应该更擅长生成这种界面。需要的时候，把一份长报告变成一个浏览器里的工作区，把一个调用链变成图，把一堆任务变成可以筛选的列表。而且拿他来做 PPT 也挺好用的，简单快捷，开箱即用。</p><p>我的分歧只在下一步：这些界面不能自动变成事实本身。</p><h2 id="问题出在把交互界面当事实源"><a href="#问题出在把交互界面当事实源" class="headerlink" title="问题出在把交互界面当事实源"></a>问题出在把交互界面当事实源</h2><p>HTML 一旦开始承担事实源，麻烦会来得很快。</p><p>先说 diff。需求里一句话从「必须支持离线」改成「优先支持离线」，在 Markdown 里通常就是一行差异。放进 HTML，可能混着标签、样式、布局、脚本和生成器的细微变化。review 的人打开 diff，看到的不是意图，而是一堆噪音。版本历史本来应该回答「谁在什么时候改了什么」，结果变成了「这次生成出来的界面和上次有多少不同」。</p><p>搜索和长期维护也会变麻烦。Markdown 的优势不是语法多强，而是它简单。你可以用 <code>rg</code> 找一段话，用 Git 看历史，用任何编辑器打开，用脚本做简单处理。HTML 当然也能搜索，但当真正的信息被包在结构和样式里面，文本的可操作性就会下降。今天觉得只是多几个 <code>&lt;div&gt;</code>，半年后可能就是一堆没人想碰的历史文件。</p><p>token 成本更像慢性病。单个 HTML 文件多出的标签和样式也许不算什么，但事实源不是一次性读物。spec、计划、审查记录、任务清单会被模型反复读、反复归档、反复带回上下文。每一次读 HTML，都在为界面付费。大上下文窗口会让这个问题看起来没那么急，但它不会让冗余消失。</p><h2 id="Markdown-的价值不在朴素，而在可审计"><a href="#Markdown-的价值不在朴素，而在可审计" class="headerlink" title="Markdown 的价值不在朴素，而在可审计"></a>Markdown 的价值不在朴素，而在可审计</h2><p>Markdown 的价值不是它看起来朴素，而是它把账留得清楚。内容就在文本里，没有额外结构，所有的层级工具都是信息的一部分；变化可以被人和工具低成本检查；你不需要先打开某个运行环境，才能知道文件到底写了什么。</p><p>John Gruber 当年对 Markdown 的定位其实很清楚：HTML 是 publishing format，Markdown 是 writing format。Markdown 不是要替代 HTML，而是让写作、阅读和编辑文本本身更容易。这个区分放到 AI 工作流里依然成立，只是 writing 不再只是写博客，也包括写 spec、写计划、写任务状态、写审查结论。</p><p>这些东西不应该只活在一个漂亮视图里。</p><p>如果一个 Agent 生成了 PR review dashboard，我希望它帮我看懂改动。没问题。可如果我勾掉了一个风险、改了一个判断、重新排序了任务，这些结果最后要回到 Markdown，或者回到另一个同样可审计的事实系统里。HTML 可以是操作台，但操作完要落账。不能让改动只留在 HTML 的交互层里。</p><h2 id="不是替代，是分层"><a href="#不是替代，是分层" class="headerlink" title="不是替代，是分层"></a>不是替代，是分层</h2><p>我理解 HTML-first 的吸引力。对很多人来说，AI 生成的内容终于可以不再是一份难读的报告，而是一个能打开、能点、能分享的小应用。这确实是进步。不同人的工作流也不一样，如果一个团队只需要短期交付、视觉审查和一次性汇报，HTML 作为主要产物完全合理。</p><p>但我的日常（或者说大部分系统开发者的日常）不是这样。我的问题不是「模型能不能生成漂亮输出」，而是「这些输出能不能被长期检查」。我需要知道一个判断什么时候变了，为什么变了，谁接受了它，后来有没有被推翻。HTML 能帮我理解这些东西，却不应该替我保存这些东西。</p><p>我会把边界划在这里。</p><p>需求、约束、计划、review 结论、任务状态、决策记录，这些需要长期存在、需要被版本控制、需要被模型和人反复检查的内容，应该留在 Markdown 里，或者留在同等可审计的结构化存储里。</p><p>阅读视图、关系图、PR 审查辅助、研究材料浏览器、临时 dashboard、交互式摘要，这些是给人看的界面。它们的目的不是留下最终记录，而是让人更快看懂、更愿意参与、更容易给出反馈。做成 HTML 很合适。</p><p>这条规矩也解释了为什么这篇文章本身可以在 Markdown 里嵌一段 HTML 卡片。卡片是界面层，负责让那组关系更容易看；整篇文章仍然是 Markdown，负责留下可以 diff 的文本。两者不是互相排斥，只是各自待在该待的位置。</p><p>最后回到那句话：</p><blockquote><p>Markdown 负责事实，HTML 负责理解。源文件不变，视图可丢，结论回流。</p></blockquote><p>Skill 没有取代 MCP，CLI 不会取代 GUI，HTML 也不会取代 Markdown， AI Agent 改变很多东西，但炒作的强度比现实的变化更猛。</p><p>p.s. 为什么 Anthropic 的团队总是喜欢给我们搞一堆更烧 token 的方案，HTML 意味着我们需要为每一个 <code>&lt;&gt;</code> 付钱，多智能体和 Dynamic Workflow 也是 token 消耗大户，吹这玩意是为了赚我钱？</p><p>p.s. 从 <code>.md </code> 到 <code>.html</code> 背后还有一个更宏伟的概念，等到脑机接口成熟以后，我们应该直接输出表征流（视频流），交互速度直接拉满，<code>.html</code> 也只是临时中间体。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a class="link"   href="https://claude.com/blog/using-claude-code-the-unreasonable-effectiveness-of-html" >Using Claude Code: The Unreasonable Effectiveness of HTML（Thariq Shihipar，claude.com）<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://simonwillison.net/2026/May/8/unreasonable-effectiveness-of-html/" >Simon Willison 转述：Using Claude Code: The Unreasonable Effectiveness of HTML<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://thariqs.github.io/html-effectiveness/" >The unreasonable effectiveness of HTML 示例集<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://daringfireball.net/projects/markdown/syntax" >Daring Fireball：Markdown Syntax Documentation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a href="/blog/2026/05/27/cli-vs-gui-agent-era/">《我们又回到了 CLI：Agent 时代 CLI 与 GUI 的选型》</a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/08/fact-layer-interface-layer-markdown-html/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/08/fact-layer-interface-layer-markdown-html/"/>
    <published>2026-06-08T04:00:00.000Z</published>
    <summary>HTML is tempting. It can turn long AI-generated documents into something readable, clickable, and shareable. But I do not want HTML to quietly become the source of truth. Markdown should keep the diffable, searchable, auditable record; HTML should make complex systems easier to read.</summary>
    <title>The Fact Layer and the Interface Layer: Markdown and HTML Aren't Rivals</title>
    <updated>2026-07-01T15:56:19.867Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Systems" scheme="https://hyacehila.github.io/categories/agent-systems/"/>
    <category term="Context Engineering" scheme="https://hyacehila.github.io/tags/Context-Engineering/"/>
    <category term="Agent Memory" scheme="https://hyacehila.github.io/tags/Agent-Memory/"/>
    <category term="Agent Runtime" scheme="https://hyacehila.github.io/tags/Agent-Runtime/"/>
    <content>
      <![CDATA[<blockquote><p><strong>写作状态：本文为占位草稿。</strong> 现在只保留文章定位和标题坑位，不展开产品索引，不做长内容盘点。</p></blockquote><h1 id="Agent-Memory-与-Runtime-技术盘点：外挂记忆、运行时研究与框架内建能力"><a href="#Agent-Memory-与-Runtime-技术盘点：外挂记忆、运行时研究与框架内建能力" class="headerlink" title="Agent Memory 与 Runtime 技术盘点：外挂记忆、运行时研究与框架内建能力"></a>Agent Memory 与 Runtime 技术盘点：外挂记忆、运行时研究与框架内建能力</h1><p>这篇文章不再沿用 L1&#x2F;L2&#x2F;L3 的测绘写法，也不做产品排行榜。后续真正要回答的是：一个系统到底怎么记、怎么取、怎么改、怎么忘。在这里我们用真实运行的系统的例子，来解释一个完整的 Agent Runtime、一个 Memory Framework 以及 Agent 开发工具，都是怎么来帮助用户管理上下文与长期记忆的。这将是对前面讨论 Research 和 Context Engineering 的实例化研究。</p><h2 id="外挂-Memory-产品与研究（占位）"><a href="#外挂-Memory-产品与研究（占位）" class="headerlink" title="外挂 Memory 产品与研究（占位）"></a>外挂 Memory 产品与研究（占位）</h2><h3 id="Mem0-OpenMemory"><a href="#Mem0-OpenMemory" class="headerlink" title="Mem0 &#x2F; OpenMemory"></a>Mem0 &#x2F; OpenMemory</h3><h3 id="Zep-Graphiti"><a href="#Zep-Graphiti" class="headerlink" title="Zep &#x2F; Graphiti"></a>Zep &#x2F; Graphiti</h3><h3 id="Letta-MemGPT"><a href="#Letta-MemGPT" class="headerlink" title="Letta &#x2F; MemGPT"></a>Letta &#x2F; MemGPT</h3><h3 id="TencentDB-Agent-Memory"><a href="#TencentDB-Agent-Memory" class="headerlink" title="TencentDB Agent Memory"></a>TencentDB Agent Memory</h3><h3 id="Cognee"><a href="#Cognee" class="headerlink" title="Cognee"></a>Cognee</h3><h3 id="Supermemory"><a href="#Supermemory" class="headerlink" title="Supermemory"></a>Supermemory</h3><h3 id="MemOS"><a href="#MemOS" class="headerlink" title="MemOS"></a>MemOS</h3><h3 id="Generative-Agents"><a href="#Generative-Agents" class="headerlink" title="Generative Agents"></a>Generative Agents</h3><h3 id="Reflexion"><a href="#Reflexion" class="headerlink" title="Reflexion"></a>Reflexion</h3><h3 id="MemoryBank"><a href="#MemoryBank" class="headerlink" title="MemoryBank"></a>MemoryBank</h3><h3 id="A-MEM"><a href="#A-MEM" class="headerlink" title="A-MEM"></a>A-MEM</h3><h3 id="LongMemEval"><a href="#LongMemEval" class="headerlink" title="LongMemEval"></a>LongMemEval</h3><h3 id="HaluMem"><a href="#HaluMem" class="headerlink" title="HaluMem"></a>HaluMem</h3><h3 id="MemoryAgentBench"><a href="#MemoryAgentBench" class="headerlink" title="MemoryAgentBench"></a>MemoryAgentBench</h3><h3 id="MemConflict"><a href="#MemConflict" class="headerlink" title="MemConflict"></a>MemConflict</h3><h3 id="LongMemEval-V2"><a href="#LongMemEval-V2" class="headerlink" title="LongMemEval-V2"></a>LongMemEval-V2</h3><h2 id="Agent-Runtime-研究与产品（占位）"><a href="#Agent-Runtime-研究与产品（占位）" class="headerlink" title="Agent Runtime 研究与产品（占位）"></a>Agent Runtime 研究与产品（占位）</h2><h3 id="AIOS"><a href="#AIOS" class="headerlink" title="AIOS"></a>AIOS</h3><h3 id="SWE-agent"><a href="#SWE-agent" class="headerlink" title="SWE-agent"></a>SWE-agent</h3><h3 id="OpenHands"><a href="#OpenHands" class="headerlink" title="OpenHands"></a>OpenHands</h3><h3 id="Agent-S"><a href="#Agent-S" class="headerlink" title="Agent S"></a>Agent S</h3><h3 id="OSWorld-BrowserGym"><a href="#OSWorld-BrowserGym" class="headerlink" title="OSWorld &#x2F; BrowserGym"></a>OSWorld &#x2F; BrowserGym</h3><h3 id="Magentic-One-Magentic-UI"><a href="#Magentic-One-Magentic-UI" class="headerlink" title="Magentic-One &#x2F; Magentic-UI"></a>Magentic-One &#x2F; Magentic-UI</h3><h3 id="Claude-Code"><a href="#Claude-Code" class="headerlink" title="Claude Code"></a>Claude Code</h3><h3 id="Codex-CLI"><a href="#Codex-CLI" class="headerlink" title="Codex CLI"></a>Codex CLI</h3><h3 id="OpenClaw"><a href="#OpenClaw" class="headerlink" title="OpenClaw"></a>OpenClaw</h3><h3 id="Hermes-Agent"><a href="#Hermes-Agent" class="headerlink" title="Hermes Agent"></a>Hermes Agent</h3><h3 id="Pi-dev"><a href="#Pi-dev" class="headerlink" title="Pi.dev"></a>Pi.dev</h3><h2 id="Agent-框架提供的记忆能力（占位）"><a href="#Agent-框架提供的记忆能力（占位）" class="headerlink" title="Agent 框架提供的记忆能力（占位）"></a>Agent 框架提供的记忆能力（占位）</h2><p>这一节讨论的是 Agent Framework 自己提供的记忆能力，而不是专门的 Memory Layer，也不是模型厂商在产品里做好的个人记忆。换句话说，这里关心的是：当开发者选了一个框架之后，它到底帮你处理了多少记忆问题，又把多少复杂度留给了开发者。</p><p>我会按五个维度拆它。<strong>短期与裁剪</strong>看的是会话历史如何进入上下文窗口，框架是否提供截断、摘要、compaction 或 history reducer。<strong>长期记忆</strong>看的是历史信息能不能跨会话沉淀成可复用事实，还是只提供一个外接 provider 的接口。<strong>用户记忆</strong>看的是有没有 user、session、app、agent 这类作用域隔离，避免不同人、不同任务、不同产品入口的记忆串味。<strong>工作记忆</strong>看的是框架是否支持任务白板、TODO、中间决策、结构化运行状态，而不是只把所有东西塞进聊天记录。<strong>RAG</strong>则看它如何处理外部知识召回，以及它到底把 RAG 当作知识库，把 Memory 当作用户经验，还是干脆把两者混成同一个 context injection 问题。</p><p>这五个维度不是为了给每个框架打分，而是为了把它们的记忆哲学暴露出来。它们都能叫 memory，但开发时承担的工程复杂度完全不同。同样，这样的解读可以方便你根据你的需求和框架的契合程度，去选择适合的 Framework。</p><h3 id="LangGraph-LangMem"><a href="#LangGraph-LangMem" class="headerlink" title="LangGraph &#x2F; LangMem"></a>LangGraph &#x2F; LangMem</h3><p><strong>短期与裁剪</strong>：LangGraph 的短期记忆不是普通 chat buffer，而是 thread-level graph state。<code>checkpointer</code> 保存同一个 thread 里的 messages、tool result、中间状态、human-in-the-loop 暂停点，让 graph 可以恢复、重试、time travel。裁剪也不只是删旧消息，而是在状态进入模型前决定保留哪些消息、移除哪些消息、摘要哪些历史、哪些节点状态继续参与推理。state 是状态机的状态字典，可以用 messages 存储短期对话记忆，但具体策略由开发者决定。LangMem 在上层补了 summarization &#x2F; compaction 这类封装，减少开发者直接手写消息整理逻辑。</p><p><strong>长期记忆</strong>：长期记忆落在 <code>store</code>。它跨 thread 存在，保存的是 JSON documents，每条 memory 有 namespace 和 key。你可以按 namespace 保存用户事实、偏好、任务经验或应用级知识，但 namespace、schema、权限、遗忘和合并规则都要自己设计。LangMem 补上的正是“怎么写记忆”和“怎么召回记忆”：agent 可以在 hot path 里用 memory tools 主动保存和搜索记忆，也可以用 background memory manager 在后台抽取、去重、合并、更新长期记忆，同时维护记忆一致性。这一层已经非常接近真实 Agent 产品需要的 memory layer。</p><p><strong>用户记忆</strong>：LangGraph 不替你定义 <code>UserMemory</code> schema。用户记忆通常也是长期 <code>store</code> 的一种命名空间设计，例如按 user_id、app_id、tenant_id、project_id 组合 namespace，再用 key 区分 profile、preference、episodic memory 或任务经验。框架给你跨 thread 存储和召回底座，不替你决定用户画像应该长什么样。</p><p><strong>工作记忆</strong>：这是 LangGraph 最强的一块，也是我们在短期与裁剪里已经提到的内容。graph state 天然适合保存任务计划、中间决策、审批状态、节点输出、工具结果和失败恢复信息。它把工作记忆看成可持久化的内存执行状态，而不是模型上下文里一段临时文本。这对长任务、多步骤流程、人类审批和恢复运行非常关键。</p><p><strong>RAG &#x2F; Store</strong>：LangGraph 的 <code>store</code> 既可以放长期记忆，也可以接向量检索和外部知识。RAG 在这里不是一个孤立插件，而是 graph 里的节点、状态和工具调用：检索结果可以进入 state，后续节点继续加工。LangGraph &#x2F; LangMem 是这批里最像 Memory 基础设施的一组，强在可编排，难在需要开发者自己设计制度。</p><h3 id="Mastra-Agno-AgentScope-CrewAI"><a href="#Mastra-Agno-AgentScope-CrewAI" class="headerlink" title="Mastra &#x2F; Agno &#x2F; AgentScope &#x2F; CrewAI"></a>Mastra &#x2F; Agno &#x2F; AgentScope &#x2F; CrewAI</h3><p>这四个框架可以合并来看，但不是因为它们不重要，而是因为它们和 LangGraph 处理的是同一组问题，只是抽象层级不同。LangGraph 把 <code>state</code>、<code>checkpoint</code>、<code>store</code> 暴露成底层基础设施，让开发者自己定义 memory runtime 的制度；Mastra、Agno、AgentScope、CrewAI 更像把一部分制度直接内置进框架，让开发者更快拿到可用形态。区别不是有没有 Memory，而是 Memory 的治理权到底在框架手里，还是在应用开发者手里。</p><p><strong>短期与裁剪</strong>：和 LangGraph 的 graph state 不同，这四者更像把短期上下文做成框架内置能力。Mastra 走的是 TypeScript agent runtime 路线，message history 绑定 thread &#x2F; resource，memory processors 会在模型调用前过滤、裁剪、重排或摘要上下文，避免开发者自己写一堆消息清理逻辑。Agno 也把 session history 和 session summaries 拆开，前者负责“刚才聊了什么”，后者负责长会话变短，比较适合产品里的连续对话。AgentScope 的记忆模块保存 <code>Msg</code>，并用 mark 给消息打标签，ReActAgent 还提供 memory compression，应对 token 超限。CrewAI 的短期上下文则嵌在 Agent、Task、Crew、Flow 的执行过程里，开发者更多是在配置协作结构，不直接维护一份 state dict。</p><p><strong>长期记忆</strong>：LangGraph 的长期记忆是通用 <code>store</code>，所以它像数据库；这四者更像产品化 memory layer。Mastra 的特色最明显：<code>semantic recall</code> 用向量召回历史消息，<code>observational memory</code> 则用后台 Observer &#x2F; Reflector 把长对话整理成更密的 observation log，目标是少塞 raw history，又保留长期经验。Agno 的 <code>Memory</code> &#x2F; <code>MemoryManager</code> 更直接，负责 long-term user memories 的创建、检索、更新、删除，还可以让 agent 通过 memory tools 自己管理记忆。AgentScope 有 long-term memory 接口，也接了 Mem0LongTermMemory 这类实现，另有 ReMe 这种更偏研究和生态的记忆项目。CrewAI 最近的方向是统一 <code>Memory</code> class，用 LLM 在写入时推断 scope、category、importance，召回时混合语义相似度、recency 和 importance，而是试图把它们收进一个统一 API。</p><p><strong>用户记忆</strong>：这里最值得对比的是 Agno 和 Mastra。Agno 明确区分 user memory 是跨会话学到的用户事实、偏好和背景，这个边界非常产品化。Mastra 则把 使用可持久的 Markdown 状态块，可以按 resource scope 跨同一用户的多个 thread 保存，也可以按 thread scope 限定在单次任务里，适合写用户画像、长期目标、偏好和当前任务摘要。CrewAI 的 unified memory 可以靠 scope tree 和 LLM 分析组织用户或项目记忆，但这种自动组织很方便，也意味着你要认真检查它的边界是否符合产品权限要求。AgentScope 也能保存偏好与事实，不过它更偏通用 agent runtime：消息 mark、session state、long-term memory 都是积木，用户画像 schema 仍要应用层定义。</p><p><strong>工作记忆</strong>：LangGraph 的工作记忆就是 graph state，所以它很适合把计划、审批、节点输出、失败恢复都当成可持久化执行状态。Mastra 和 Agno 更偏成品工作台”：Mastra 的 working memory 可以充当 agent scratchpad，workflow state 又能保存流程步骤和中间产物；Agno 用 session state、Team、Workflow、AgentOS runtime 承载任务运行状态和多 agent 协作状态。AgentScope 的工作记忆更像运行时状态管理，agent 的 system prompt、memory、context、tool、session 都被纳入 state &#x2F; session 管理，适合实验多 agent、工具调用和可恢复运行。CrewAI 则最偏协作建模：工作记忆藏在 Agent &#x2F; Task &#x2F; Crew &#x2F; Flow 之间，像项目分工与流程推进的状态，而不是一块显式白板。</p><p><strong>RAG &#x2F; Store</strong>：LangGraph 把 RAG 看成 graph 里的节点、状态和工具调用，所以检索链路可以被完整编排。Mastra 的 RAG 色彩主要体现在 vector store 对 semantic recall 的支撑上：历史消息被嵌入、检索、带上下文窗口召回。Agno 把 Knowledge 单独拆出来，这一点很清楚：Memory 处理用户和会话经验，Knowledge 处理外部知识库。AgentScope 有 RAG、toolkit 和 long-term memory 的组合，使用类似 Langgraph 的工具箱。CrewAI 也有 knowledge、storage 和外部工具连接，但它的特色是统一 Memory 可以单独用，也可以挂到 Agent、Crew、Flow 上。总体趋势一致，但进入路径根据被主干设计影响。</p><p>所以这四者不能简单说弱于 LangGraph（从自由度说确实，但如果真想要自由度你就不需要框架了）。Mastra 的价值在于 TypeScript 生态里少见地把 message history、semantic recall、working memory、observational memory、memory processors 串成了一套相对完整的 agent memory runtime。Agno 的价值在于边界清楚，session history、summary、user memory、knowledge 各归各位，很适合产品型 agent。AgentScope 的价值在于工程化与研究生态，适合做多 agent、状态管理、RAG、长记忆的组合并直接作为服务提供。CrewAI 的价值在于协作范式和统一 Memory API，适合围绕角色、任务、团队和流程快速组织 agent。LangGraph &#x2F; LangMem 更像让你自己搭 memory runtime 的地基，强在可编排、可替换、可治理；这四者更像已经替你规定好一部分管线形状，强在上手快、产品感更强，更适合做一个上线的服务。</p><h3 id="AutoGen-Microsoft-Agent-Framework-Semantic-Kernel"><a href="#AutoGen-Microsoft-Agent-Framework-Semantic-Kernel" class="headerlink" title="AutoGen&#x2F;Microsoft Agent Framework&#x2F;Semantic Kernel"></a>AutoGen&#x2F;Microsoft Agent Framework&#x2F;Semantic Kernel</h3><p>微软 Agent 家族路线有点乱：AutoGen、Semantic Kernel、Microsoft Agent Framework 三个名字都能讲 Agent，但它们其实代表了三代不同抽象。AutoGen 更像研究型多智能体框架，Semantic Kernel 更像企业集成和 RAG 框架，MAF 则是微软试图收束后的统一运行时。微软确实是一家没有品味的公司，喜欢自己和自己竞争。</p><h4 id="AutoGen"><a href="#AutoGen" class="headerlink" title="AutoGen"></a>AutoGen</h4><p><strong>短期与裁剪</strong>：短期记忆落在 <code>model_context</code>。<code>BufferedChatCompletionContext</code> 保留最近 N 条消息；<code>TokenLimitedChatCompletionContext</code> 按 token 预算控制上下文，超预算时会从中间删除消息；<code>HeadAndTailChatCompletionContext</code> 保留最早的 head 和最近的 tail，并用 skipped message 标记中间被跳过的历史。这些策略解决的是上下文窗口预算，并且没有什么压缩，就是截断。</p><p><strong>长期记忆</strong>：长期记忆通过 <code>Memory</code> protocol 外挂。基本链路是：把事实、文本或其他内容包装成 <code>MemoryContent</code> 写入 memory store；推理前由 memory 根据当前上下文或查询执行 <code>query</code>；再通过 <code>update_context</code> 把召回结果写回模型上下文。需要增加长期记忆则使用 <code>add</code>。 AutoGen 只规定这组接口，不规定后端的具体工作流。</p><p><strong>用户记忆</strong>：AutoGen 没有 <code>UserMemory</code> 作用域。用户偏好、身份事实、跨会话信息可以用 <code>ListMemory</code> 保存，也可以放进 Mem0、Redis、Chroma 或自定义后端；<code>ListMemory</code> 更像示例级实现：按时间顺序保存内容，<code>update_context</code> 时把记忆追加进上下文。当我们在真实开发的过程中，需要使用类似长期记忆的方法处理 <code>UserMemory</code> 的问题。</p><p><strong>工作记忆</strong>：<code>TextCanvasMemory</code> 是比较典型的工作记忆。它保存持续变化的文档或画布，类似于 <code>todo.md</code>，让 agent 编辑长文本、草稿或计划时，将中间状态外置，不是自动抽取用户事实。他的工作方式和经典的 <code>todo.md</code> 基本一样。</p><p><strong>RAG</strong>：综上，Autogen 根本不提供自己的 RAG 设计，仅仅是又一套接口，你可以自由的选择和编排自己喜欢的 RAG 系统。Chroma、Redis、Mem0 等只是不同 memory implementation。它们可以用 embedding、关键词、metadata 或外部服务做召回，但在 AutoGen 看来都走同一个模式：memory 自己决定如何查询、排序、过滤，再通过 <code>update_context</code> 把结果注入上下文。</p><p>这就是 Autogen，从现在的眼光来看已经完全落伍而不值得使用的框架，我们能看到他在 Memory 的编排上基本同样一事无成。</p><h4 id="Semantic-Kernel"><a href="#Semantic-Kernel" class="headerlink" title="Semantic Kernel"></a>Semantic Kernel</h4><p><strong>短期与裁剪</strong>：Semantic Kernel 的短期记忆落在 <code>ChatHistory</code> 和 <code>AgentThread</code>。<code>ChatHistory</code> 是模型实际看到的消息流，<code>AgentThread</code> 是会话状态抽象（服务端 thread id ）。SK 有 <code>ChatHistoryReducer</code> 这条线，可以做消息数截断与旧消息摘要。这套能力主要在 chat history 层工作，需要开发者决定什么时候 reduce、保留哪些 system&#x2F;tool&#x2F;function-call 结构，只提供了适当的工具封装。</p><p><strong>长期记忆</strong>：长期记忆主要通过 <code>Mem0Provider</code> 补齐（也有其他方案，我们在 RAG 那里会聊到）。它从 thread 消息中抽取 memories，后续 invocation 前再按当前请求召回。这里的长期记忆不是原始聊天归档，而是被抽取后的可复用事实。SK 通过 provider 把外部记忆能力挂到 agent 调用链上。但起码没有只提供抽象，不提供解决方案。</p><p><strong>用户记忆</strong>：Semantic Kernel 还是使用类似 <code>Mem0Provider</code>  的方案，但是将记忆进行了类别拆分。<code>UserId</code> 可以表示跨 thread 的用户偏好和长期事实，<code>ThreadId</code> 可以把记忆限定在单个任务里。它把“这个人长期如此”和“这个任务暂时如此”分开了。它比 AutoGen 清楚的一点是，SK 至少把 user&#x2F;thread 这两个作用域暴露了出来，记忆系统本身仍旧依赖外部 Provider。</p><p><strong>工作记忆</strong>：<code>WhiteboardProvider</code> 也是类似 <code>todo.md</code> 的产物，提供了相当完善的封装和开箱即用的体验。它从对话中抽取 requirements、proposals、decisions、actions，保存任务推进过程中真正要稳定保留的结构化状态。即使 chat history 被截断，agent 仍然知道已经确认了什么、下一步该做什么。</p><p><strong>RAG</strong>：RAG 是 SK 成熟的地方。Vector Store 是外部知识库，<code>TextSearchProvider</code> 负责检索并注入 agent 上下文。它不是像 AutoGen 那样只给一个 memory interface，而是围绕企业知识库、向量存储和搜索 provider 做了比较完整的连接器设计。这也是 SK 我认为为数不多的完整系统化设计。</p><p>这就是 Semantic Kernel：它不是一个统一的 Memory runtime，而是把 thread、history、Mem0、Whiteboard、Vector Store 这些能力拼成一组 provider。它比 AutoGen 更接近可用的企业 RAG 和任务白板，但整体上仍然是能力组合，而不是统一记忆系统。</p><h4 id="Microsoft-Agent-Framework"><a href="#Microsoft-Agent-Framework" class="headerlink" title="Microsoft Agent Framework"></a>Microsoft Agent Framework</h4><p><strong>短期与裁剪</strong>：Microsoft Agent Framework 的短期记忆落在 <code>AgentSession</code> 和 <code>ChatHistoryProvider</code>。<code>AgentSession</code> 保存会话状态，用于对话复用和恢复。<code>ChatHistoryProvider</code> 管历史持久化与上下文管理：负责上下文的装配以及长上下文时，由 reducer 和 compaction 压缩成可继续推理的上下文预算。开发者只需要简单配置即可。</p><p><strong>长期记忆</strong>：长期记忆统一放到 <code>AIContextProvider</code> 后面。provider 可以在调用前搜索相关上下文，也可以在调用后从新消息中抽取记忆。这里的相关机制完全类似于 SK，我们可以建立适当的 scope，然后让 <code>AIContextProvider</code> 根据对应 scope 召回，这就是我们在其他 blog 里提到的关于 metadata 的重要性。<code>AIContextProvider</code> 本身也不和固定后端绑定。</p><p><strong>用户记忆</strong>：用户记忆通过分 scope 的 <code>AIContextProvider</code> 实现。app、agent、user、session 都可以成为边界，避免不同用户和任务串味。虽然没有将用户记忆系统单列，但是 MAF 基本已经找到了一个成熟的抽象，能够提供相对稳定的记忆层，只是仍旧需要不少开发者的工作量，后台的 provider 需要为了前端的简洁，实现不少复杂的记忆存储与召回逻辑。</p><p><strong>工作记忆</strong>：MAF 没有像 SK WhiteboardProvider 那样开箱即用的结构化工作记忆。它提供的是 session state、context provider、workflow checkpoint 这些底层积木。你可以用它们实现项目白板、任务计划、中间决策和 TODO，但抽取 schema、更新策略、冲突处理、何时注入上下文，都要开发者自己设计。相当不友好，工作记忆太常用了，重复开发会消耗不少时间。</p><p><strong>RAG</strong>：<code>TextSearchProvider</code>负责外部知识召回。它们既可以自动注入上下文，也可以作为工具由 agent 按需调用。完全继承了 SK 提供的成熟外挂知识库方案。</p><p>这就是 Microsoft Agent Framework：它试图把 AutoGen 的多智能体遗产和 SK 的企业 RAG 遗产收束到一套 session、history、context provider、RAG、compaction 的运行时里。整体而言确实更加成熟了。</p><h3 id="Dify-Coze-n8n"><a href="#Dify-Coze-n8n" class="headerlink" title="Dify &#x2F; Coze &#x2F; n8n"></a>Dify &#x2F; Coze &#x2F; n8n</h3><h4 id="Dify"><a href="#Dify" class="headerlink" title="Dify"></a>Dify</h4><p><strong>短期与裁剪</strong>：Dify 的短期记忆主要落在 Agent 节点和 LLM 节点的会话上下文里。Agent 节点的 Memory 参数本质上是 <code>TokenBufferMemory</code>，开发者可以控制保留多少历史消息，窗口越大，模型看到的上下文越完整，token 成本也越高。LLM 节点也可以启用 Memory，把之前的 user-assistant 消息作为上下文拼回 prompt。这里解决的是低代码应用里的多轮连续性，不是一个完整的 Agent runtime 记忆系统。Dify 会自动处理系统的避免爆上下文，当然还是经典的裁剪+压缩思路。</p><p><strong>长期记忆</strong>：Dify 默认没有真正的跨会话长期记忆。LLM 节点的 Memory 是 node-specific，而且不在不同 conversation 之间持久。想要长期保存用户事实、历史偏好或任务经验，需要开发者自己接外部数据库、知识库、插件、API 节点或变量更新逻辑。Dify 提供的是应用编排平台，不是一个帮你自动抽取、合并、遗忘和治理长期记忆的框架。</p><p><strong>用户记忆</strong>：Dify 里比较接近用户记忆的是 Conversation Variables。它可以在同一个 chat session 的多轮对话中持续保存状态，比如用户选择、表单字段、任务阶段、临时偏好。但这个作用域仍然是会话级的，不是天然跨会话的 <code>UserMemory</code>。如果你要做“这个用户长期喜欢什么”“这个客户以前买过什么”，就需要把变量和外部存储打通，你需要用长期记忆那一套自己去搞。</p><p><strong>工作记忆</strong>：Dify 的工作记忆更像 workflow 变量和节点状态。变量赋值节点、条件分支、知识检索结果、工具返回值可以共同构成一次任务的中间状态，但它不是 SK Whiteboard 那种结构化白板，也不是 Mastra working memory 那种用户画像表。这就是 Workflow 的程序记忆，schema、更新策略和冲突处理都散落在 workflow 设计里。</p><p><strong>RAG</strong>：RAG 是 Dify 最成熟的方向之一。它把知识库、检索、重排、LLM 节点和应用发布放进同一个平台，对企业问答、客服助手、表单处理和内容生成非常友好。在 Dify 里，RAG 更多是外部知识进入上下文，Memory 更多是会话连续性和变量状态，两者可以在工作流里组合，却没有统一成一个长期记忆模型。</p><p>这就是 Dify：它适合交付，不适合研究长期记忆机制。它把 Agent 应用里最常见的知识库、工具、变量、发布和运营后台做好了，但 memory 的核心问题，尤其是跨会话用户事实抽取、冲突合并、过期、删除和治理，仍然要靠开发者自己补。</p><h4 id="Coze"><a href="#Coze" class="headerlink" title="Coze"></a>Coze</h4><p><strong>短期与裁剪</strong>：Coze 的短期记忆主要体现在 Bot 对话、变量、工作流节点和平台托管的上下文里。作为产品化 Agent 工厂，它更关心的是用户在聊天入口里是否能连续互动，而不是让开发者直接控制每条消息如何进入模型上下文。上下文裁剪、历史拼接和节点状态被平台藏起来了，专注产品设计而无需关心这些细节。当然其后台大概率还是裁剪+压缩的那一套，维护单一会话内记忆，这是最经济有效的方案。</p><p><strong>长期记忆</strong>：Coze 的长期记忆不是纯黑盒，但它暴露的是产品化配置，而不是完整 memory runtime。开发者可以在智能体编排页面开启长期记忆；开启后，系统会自动从对话中抽取用户画像、用户记忆点和用户手动编辑的信息，并写入平台系统数据库。开发者还可以配置是否“支持在 Prompt 中调用长期记忆”：开启后，用户可以在普通对话中通过提问召回记忆；关闭后，长期记忆只能通过工作流里的长期记忆节点召回。新版记忆库还支持绑定多个低代码智能体和工作流，并用用户 UID 与渠道 ID 组合作为隔离标识。这就是他暴露的长期记忆能力，但其后台具体如何工作不得而知。</p><p><strong>用户记忆</strong>：Coze 的用户记忆边界比 Dify 清楚。新版长期记忆会按用户 UID 与渠道 ID 隔离，同一记忆库下不同用户、不同渠道的数据不会混在一起。记忆内容也有内置分类：用户画像、用户记忆点、用户编写的信息；其中用户编写的信息优先级更高，和自动抽取内容冲突时会优先采纳。开发者和调试者可以在 Memory &gt; 长期记忆 页面查看、编辑、删除或清空自己的长期记忆，用户也可以通过自然语言要求系统修改或记录记忆。长期记忆节点可以被用于召回长期记忆。考虑到我们在 Dify 里将数据库和变量放到了用户记忆范畴，那么 Coze 也有类似的能力。</p><p><strong>工作记忆</strong>：Coze 的工作记忆主要藏在工作流、变量、数据库、知识库和插件编排里。它可以承载任务状态、表单信息、中间结果和流程节点输出。工作流编排就是这样，没什么额外可以说的。</p><p><strong>RAG</strong>：Coze 也有知识库和插件体系，RAG 在这里服务于 Bot 能不能回答业务知识、调用外部能力、完成产品入口任务。它和长期记忆的关系更偏产品分工：知识库保存公共知识，长期记忆保存用户个性化信息。这个产品分工很清楚，但它没有把知识库、长期记忆、变量、数据库统一抽象成一个可编程 memory runtime。你只能通过可视化节点去使用他们。</p><p>这就是 Coze：它不是 code-first Agent framework，而是产品化 Agent 工厂。它的长期记忆比 Dify 更像真正面向用户的个性化记忆，但工程透明度和平台绑定也更强。你可以很快做出记得用户的 Bot，却不一定能细致控制这套记忆系统如何写入、合并、审计和迁移。</p><h4 id="n8n"><a href="#n8n" class="headerlink" title="n8n"></a>n8n</h4><p><strong>短期与裁剪</strong>：n8n 的短期记忆主要通过 AI cluster 里的 memory 子节点实现，最典型的是 Simple Memory。它保存当前 session 中可配置长度的聊天历史，让 AI Agent 或 chain 能够知道用户前几轮说了什么。这个能力解决的是对话连续性，是一个可视化 workflow 里的 chat history buffer。依旧是裁剪+压缩，三个工作流平台都这样。</p><p><strong>长期记忆</strong>：n8n 不内建完整的长期记忆治理系统，但它很擅长把外部记忆服务接进流程。除了 Simple Memory 之外，n8n 还可以使用 Redis Chat Memory、Postgres Chat Memory、Zep 等 memory service；如果需要更复杂的消息加载、插入、删除和压缩，还可以用 Chat Memory Manager。n8n 把记忆当成一个可以接入 workflow 的外部节点”。</p><p><strong>用户记忆</strong>：n8n 的用户记忆边界依赖 session key、外部存储和 workflow 设计。你可以用不同 session id 区分不同用户，也可以把用户信息写进数据库、CRM、表格或向量库，再在后续流程里召回。但这不是 Dify&#x2F;Coze 那种面向终端产品的用户画像记忆，更不是框架级的 <code>UserMemory</code> 作用域。用户隔离、权限、生命周期和删除策略，都要由 workflow 设计者自己负责。</p><p><strong>工作记忆</strong>：n8n 真正强的是工作流执行状态。触发器、节点输入输出、条件分支、循环、错误处理、外部 SaaS 连接器共同构成了它的工作记忆。它能很自然地保存“这次自动化流程走到了哪一步、哪个系统返回了什么、下一步该调用哪个服务”。工作流编排就是这样，没什么额外可以说的。</p><p><strong>RAG</strong>：n8n 可以通过向量库节点、检索节点、工具节点和 AI Agent 节点拼出 RAG 流程。这里的 RAG 仍然是 workflow 拼装结果：你把数据进入向量库、检索、重排、生成这些步骤连起来，它就能跑。它不是统一 memory runtime，也不会替你决定外部知识、聊天历史和用户记忆之间的优先级。</p><p>这就是 n8n：它擅长把 AI 嵌进自动化流程，而不是把流程演化成完整 Agent runtime。它的 memory 能力很实用，但本质上是节点化的会话记忆和外部存储连接。对于流程自动化 + 一点智能的任务，它非常顺手；对于复杂长期记忆、用户画像治理和多 Agent 工作记忆隔离，它仍然要靠开发者自己搭。</p><h3 id="LlamaIndex"><a href="#LlamaIndex" class="headerlink" title="LlamaIndex"></a>LlamaIndex</h3><p>LlamaIndex 也是相对特殊的存在。它本来就不是典型的 agent dev framework，而是 RAG &#x2F; Context Engineering 框架：把文档、数据库、API、网页、向量库这些外部数据整理成模型可用的上下文。它当然也有 agent、workflow、tool calling，但这些能力大多是围绕如何把正确的知识送进模型长出来的，如果我们不需要 Agentic RAG，那恐怕 LlamaIndex 甚至都没有必要开发这些 Agent 组件。</p><p>所以 LlamaIndex 的 Memory 更像 RAG 能力的延伸。它用短期队列保存最近对话，超出 token 预算后可以把旧消息 flush 给 <code>MemoryBlock</code>；<code>StaticMemoryBlock</code> 放固定背景，<code>FactExtractionMemoryBlock</code> 抽取事实，<code>VectorMemoryBlock</code> 把历史写进向量召回链路。这个设计很自然，因为在 LlamaIndex 眼里，对话历史、用户事实、文档片段都可以被处理成 context。</p><p>它的特性也在这里：适合做知识密集型 agent、企业问答、文档分析、带检索的聊天系统。它不擅长的是替你定义用户记忆、项目记忆、工作白板和权限边界。你可以用 metadata、session id、vector store、fact block 搭出这些东西，但治理规则仍然要自己定。</p><p>这就是 LlamaIndex：RAG &#x2F; Context Framework 长出的 Memory。它最强的是把知识、历史和抽取事实组织成可召回上下文，而不是提供一套完整 Agent Runtime 的记忆制度，他甚至无法让你自由的去搭建一个 Agent。</p><h3 id="OpenAI-Agents-SDK-Claude-Agent-SDK"><a href="#OpenAI-Agents-SDK-Claude-Agent-SDK" class="headerlink" title="OpenAI Agents SDK &#x2F; Claude Agent SDK"></a>OpenAI Agents SDK &#x2F; Claude Agent SDK</h3><p>OpenAI Agents SDK 和 Claude Agent SDK 不太适合继续套前面的五类 Memory 表格。它们更像把成熟 agent runtime 暴露给开发者：核心是 run loop、tool execution、handoff 或 subagent、session、sandbox &#x2F; workspace，而不是从零设计一套 agent memory layer。和 AutoGen、SK、LlamaIndex 不同，它们不是先给你框架抽象，再让你拼出 agent；它们是先有一个能工作的 agent，再让开发者围绕运行时加工具、状态和边界。</p><p>OpenAI 这边的中心是 <code>Runner</code>。模型决定是否 tool call、是否 handoff、是否给出 final output；SDK 执行工具、把结果送回模型、继续循环，并处理 <code>max_turns</code>、guardrails、tracing、human-in-the-loop 这些工程问题。Claude Agent SDK 的气质更像 Claude Code as a library：把 Claude Code 已经有的工具、agent loop、上下文管理、文件操作和命令执行包装成 SDK。它们都不是在教开发者造 agent，而是在把成熟 agent runtime 变成可编排的产品。</p><p>所以这里的短期记忆不是 Memory 模块，而是 transcript &#x2F; session。OpenAI 可以用 <code>Session</code>、<code>conversation_id</code>、<code>previous_response_id</code>、<code>to_input_list()</code> 继续对话；Claude 侧有 session continuation、resume、fork。它们解决的是短期记忆的延续。上下文控制也更像运行时钩子。OpenAI 有 <code>session_input_callback</code>、<code>call_model_input_filter</code>、handoff input filter，用来决定历史怎么和新输入合并，哪些内容在模型调用前被裁掉或改写。Claude 侧更多依赖 Claude Code runtime 的 context management 和 session 管理。它们给的是控制点，不是记忆治理策略；哪些状态写进上下文，哪些只留在本地对象或外部系统，仍然要开发者判断。</p><p>工作记忆被转移到了工作区与文件系统。普通 OpenAI Agents SDK 没有内置项目白板，状态可以放在 local context、tools、run state、外部数据库里。Sandbox Agents 拥有独立的沙箱文件系统：workspace、files、shell、snapshot 都能保存任务现场。Claude Code Agent SDK 天然围绕文件系统、命令和代码编辑工作，任务状态通常留在 repo、临时文件、命令结果和 session transcript 里。我们在就是在调度一个云端的 Claude Code，那么他的工作记忆其实就是 Claude Code 的。</p><p>长期记忆也更像 workspace 经验沉淀，而不是传统数据库式 <code>UserMemory</code>。OpenAI Sandbox 的 <code>Memory()</code> 会把 prior runs 的 lessons 整理成 <code>MEMORY.md</code>、<code>memory_summary.md</code> 和 rollout summaries，后续 run 再按需读取。Claude Code 侧的 <code>CLAUDE.md</code>、project &#x2F; user memory、auto memory 也是类似逻辑：启动时把持久上下文加载进来，让 agent 少走弯路。外部知识同理，OpenAI 的 file search &#x2F; web search、Claude 的读文件 &#x2F; 搜索项目，本质上都是让信息进入 agent runtime 的工具能力。至于 RAG 之类的知识库则需要用户自己配置，毕竟 Runtime 自己面向本地任务，本身就和企业级项目所用的知识库无关。</p><p>这就是 OpenAI Agents SDK 和 Claude Agent SDK：短期交给 session &#x2F; transcript，工作状态交给 tools &#x2F; workspace &#x2F; filesystem，长期经验交给 workspace memory、<code>CLAUDE.md</code>、auto memory。它们更像成熟 Agent 的可编程外壳，不是 Memory-first 的 Agent Framework。如果要严格的用户记忆、项目记忆、权限隔离、冲突合并和遗忘策略，仍然要在 SDK 之外自己设计。</p><h3 id="Pydantic-AI-PocketFlow"><a href="#Pydantic-AI-PocketFlow" class="headerlink" title="Pydantic AI &#x2F; PocketFlow"></a>Pydantic AI &#x2F; PocketFlow</h3><p>Pydantic AI 没有必要按上面五类展开，因为它本来就不提供完整的记忆管理层。它真正提供的是 typed agent 编程体验：message history 可以通过 <code>all_messages()</code>、<code>new_messages()</code> 和 <code>message_history</code> 在多次运行之间传递，history processors 可以在模型调用前做裁剪、过滤或摘要；除此之外，长期记忆、用户记忆、RAG、工作白板、冲突合并、权限隔离都要开发者自己接数据库、向量库、检索器或外部 memory service。换句话说，Pydantic AI 只把消息历史作为结构化数据这件事做得很漂亮，并不替你决定什么该被记住、怎么写入、怎么召回、怎么删除。</p><p>PocketFlow 也一样，因为它是极简流程编排底座，不是 Agent memory framework。它的核心是 Node、Flow、Action 和 <code>shared store</code>，所谓记忆最多就是节点之间共享的一次运行状态：中间结果、工具返回、分支输出、trace、最终产物都可以放进去。但 <code>shared store</code> 不是长期记忆，也不是用户画像，更不是语义检索层。要做跨会话保存、用户隔离、RAG、记忆抽取、过期删除或冲突处理，开发者必须自己把 <code>shared store</code> 接到外部数据库、文件、向量库或业务系统里。PocketFlow 的优点是透明轻量，缺点也正是它几乎不替你做记忆治理。但记忆有时候也不一定是你需要的。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><h3 id="LangGraph-LangMem-1"><a href="#LangGraph-LangMem-1" class="headerlink" title="LangGraph &#x2F; LangMem"></a>LangGraph &#x2F; LangMem</h3><ul><li><a class="link"   href="https://docs.langchain.com/oss/python/langgraph/persistence" >LangGraph Persistence<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.langchain.com/oss/python/langgraph/add-memory" >LangGraph Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.langchain.com/oss/python/concepts/memory" >LangChain Memory Concepts<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://langchain-ai.github.io/langmem/" >LangMem Documentation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://langchain-ai.github.io/langmem/guides/memory_tools/" >LangMem Memory Tools<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><h3 id="Mastra-Agno-AgentScope-CrewAI-1"><a href="#Mastra-Agno-AgentScope-CrewAI-1" class="headerlink" title="Mastra &#x2F; Agno &#x2F; AgentScope &#x2F; CrewAI"></a>Mastra &#x2F; Agno &#x2F; AgentScope &#x2F; CrewAI</h3><ul><li><a class="link"   href="https://mastra.ai/docs/memory/overview" >Mastra Memory overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://mastra.ai/docs/memory/working-memory" >Mastra Working Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://mastra.ai/docs/memory/semantic-recall" >Mastra Semantic Recall<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://mastra.ai/docs/memory/observational-memory" >Mastra Observational Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://mastra.ai/docs/memory/memory-processors" >Mastra Memory Processors<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://mastra.ai/docs/workflows/overview" >Mastra Workflows<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.agno.com/memory/overview" >Agno Memory Overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.agno.com/reference/memory/memory" >Agno Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.agno.com/concepts/memory/user-memory" >Agno User Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.agno.com/concepts/memory/session-summaries" >Agno Session Summaries<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.agno.com/reference/knowledge/knowledge" >Agno Knowledge<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.agno.com/agentos/introduction" >Agno AgentOS<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/agentscope-ai/agentscope" >AgentScope GitHub<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://doc.agentscope.io/" >AgentScope Documentation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://doc.agentscope.io/tutorial/task_long_term_memory.html" >AgentScope Long-Term Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://doc.agentscope.io/tutorial/task_state.html" >AgentScope State&#x2F;Session Management<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/agentscope-ai/ReMe" >AgentScope ReMe<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.crewai.com/en/concepts/memory" >CrewAI Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.crewai.com/en/concepts/knowledge" >CrewAI Knowledge<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.crewai.com/en/concepts/flows" >CrewAI Flows<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><h3 id="AutoGen-Semantic-Kernel-Microsoft-Agent-Framework"><a href="#AutoGen-Semantic-Kernel-Microsoft-Agent-Framework" class="headerlink" title="AutoGen &#x2F; Semantic Kernel &#x2F; Microsoft Agent Framework"></a>AutoGen &#x2F; Semantic Kernel &#x2F; Microsoft Agent Framework</h3><ul><li><a class="link"   href="https://github.com/microsoft/autogen" >AutoGen README<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://microsoft.github.io/autogen/stable/user-guide/agentchat-user-guide/memory.html" >AutoGen Memory and RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://microsoft.github.io/autogen/stable/user-guide/core-user-guide/components/model-context.html" >AutoGen Model Context<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/agent-framework/overview/" >Microsoft Agent Framework overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/agent-framework/agents/conversations/" >Microsoft Agent Framework conversations<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/agent-framework/agents/conversations/context-providers" >Microsoft Agent Framework context providers<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/agent-framework/agents/conversations/compaction" >Microsoft Agent Framework context compaction<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-memory" >Semantic Kernel Agent Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-rag" >Semantic Kernel Agent RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/vector-store-connectors/" >Semantic Kernel Vector Store connectors<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><h3 id="Dify-Coze-n8n-1"><a href="#Dify-Coze-n8n-1" class="headerlink" title="Dify &#x2F; Coze &#x2F; n8n"></a>Dify &#x2F; Coze &#x2F; n8n</h3><ul><li><a class="link"   href="https://docs.dify.ai/en/use-dify/nodes/agent" >Dify Agent node<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.dify.ai/en/use-dify/nodes/llm" >Dify LLM node<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.dify.ai/en/use-dify/nodes/variable-assigner" >Dify Variable Assigner<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://www.coze.cn/open/docs/guides/long_memory" >Coze 长期记忆<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.n8n.io/advanced-ai/examples/understand-memory/" >n8n What’s memory in AI?<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.memorybufferwindow/" >n8n Simple Memory node<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/" >n8n AI Agent node<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://docs.n8n.io/advanced-ai/rag-in-n8n/" >n8n RAG in n8n<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><h3 id="LlamaIndex-1"><a href="#LlamaIndex-1" class="headerlink" title="LlamaIndex"></a>LlamaIndex</h3><ul><li><a class="link"   href="https://developers.llamaindex.ai/python/framework/understanding/rag/" >LlamaIndex RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://developers.llamaindex.ai/python/framework/module_guides/deploying/agents/memory/" >LlamaIndex Agent Memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><h3 id="OpenAI-Agents-SDK-Claude-Agent-SDK-1"><a href="#OpenAI-Agents-SDK-Claude-Agent-SDK-1" class="headerlink" title="OpenAI Agents SDK &#x2F; Claude Agent SDK"></a>OpenAI Agents SDK &#x2F; Claude Agent SDK</h3><ul><li><a class="link"   href="https://openai.github.io/openai-agents-python/" >OpenAI Agents SDK overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://openai.github.io/openai-agents-python/running_agents/" >OpenAI Agents SDK Running agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://openai.github.io/openai-agents-python/sessions/" >OpenAI Agents SDK Sessions<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://openai.github.io/openai-agents-python/sandbox/memory/" >OpenAI Agents SDK Sandbox memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://code.claude.com/docs/en/agent-sdk/overview" >Claude Agent SDK overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://code.claude.com/docs/en/agent-sdk/sessions" >Claude Agent SDK sessions<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://code.claude.com/docs/en/memory" >Claude Code memory<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><h3 id="Pydantic-AI-PocketFlow-1"><a href="#Pydantic-AI-PocketFlow-1" class="headerlink" title="Pydantic AI &#x2F; PocketFlow"></a>Pydantic AI &#x2F; PocketFlow</h3><ul><li><a class="link"   href="https://pydantic.dev/docs/ai/core-concepts/message-history/" >Pydantic AI Message History<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://the-pocket.github.io/PocketFlow/" >PocketFlow Documentation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/07/agent-runtime-teardown/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/07/agent-runtime-teardown/"/>
    <published>2026-06-07T01:00:00.000Z</published>
    <summary>A placeholder structure for future technical teardowns of external memory systems, agent runtimes, and framework-provided memory capabilities.</summary>
    <title>Agent Memory and Runtime Atlas: External Memory, Runtime Systems, and Framework Memory</title>
    <updated>2026-07-01T15:56:19.867Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Systems" scheme="https://hyacehila.github.io/categories/agent-systems/"/>
    <category term="Methodology" scheme="https://hyacehila.github.io/tags/Methodology/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Evaluation" scheme="https://hyacehila.github.io/tags/Evaluation/"/>
    <content>
      <![CDATA[<p>Shunyu Yao 在 <a class="link"   href="https://ysymyth.github.io/The-Second-Half/" >The Second Half<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里有个判断我一直记得：AI 的下半场会从解决问题转向定义问题，evaluation 与 RL 的 generalization 会比训练算法更重要。放到 Agent 上，我们可以再往前推一步：定义问题，给系统搭一个能不断返回信号的环境，Agent 就能在不进行参数训练的同时解决新的问题。</p><p>模型已经很会说、会写、会联想，也能在很多问题上快速给出候选方案。可是一旦没有反馈，这些候选很容易停在“看起来合理的解释”。把问题放进一个能验证、能比较、能回滚的系统里，生成才会慢慢变成搜索。</p><p>这篇文章原本从 AI for Science 切入，因为科学场景对验证特别敏感，反馈回路也更容易看清。但它不该只停在科学发现。宇宙弦积分论文里是科学任务的 <code>tree search + verifier</code>，Trae Agent 里是编码任务的 <code>ensemble search + pruning + selector</code>。两个例子看起来很远，其实都在追问同一个麻烦：LLM 把候选空间撑大以后，系统怎么管住这些候选。</p><p>人的角色没有消失，只是换了位置：定义问题，设计验证器，控制搜索空间，剪掉坏分支。最后还得有人判断，结果到底有没有意义。</p><h2 id="宇宙弦论文值得看的地方"><a href="#宇宙弦论文值得看的地方" class="headerlink" title="宇宙弦论文值得看的地方"></a>宇宙弦论文值得看的地方</h2><p><a class="link"   href="https://arxiv.org/abs/2603.04735" >Solving an Open Problem in Theoretical Physics using AI-Assisted Discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 表面上在讲宇宙弦引力辐射功率谱里的一个球面积分。我更关注的是它的方法部分：作者把一个理论物理问题组织成了一个可搜索、可验证、可反馈的 Agent 系统。</p><p>他们先搭了一个 neuro-symbolic system，再把模型放进这个系统里工作。Gemini 负责生成数学假设、展开路径和 Python 验证代码；Tree Search 负责组织候选解法空间；高精度数值计算负责检查候选公式；执行错误、数值误差和不稳定现象再被回注到模型上下文里。整个过程大约探索了 600 个候选节点，超过八成的分支因为代数错误、数值发散或灾难性抵消被剪掉。</p><p>这个过程大概是这样的：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">LLM 生成候选推导</span><br><span class="line">→ Tree Search 展开解法空间</span><br><span class="line">→ Python verifier 执行和打分</span><br><span class="line">→ traceback / error / instability 回注</span><br><span class="line">→ 剪枝、修正、换路线</span><br><span class="line">→ 继续搜索</span><br></pre></td></tr></table></figure></div><p>这和普通聊天式使用模型的差别很大。普通聊天里，模型输出一个答案，人读一读，觉得对或不对。这里不是这样。系统把模型输出放在候选节点的位置：它要能被运行、被比较、被反驳，然后再交给 verifier。</p><p>negative prompting 也很有意思。系统找到一条有效路线之后，作者会明确禁止模型继续用它，引导它寻找别的方法。最后模型给出了六类解析方法：单项式展开、Gaussian lifting、Legendre 谱方法、Volterra 递推、Gegenbauer 展开等。我更想拿走的不是某个提示词模板，而是搜索治理：别让模型太早收敛到一条路，也别让它一直在同一类表示里打转。</p><h2 id="编码任务里的同一条回路"><a href="#编码任务里的同一条回路" class="headerlink" title="编码任务里的同一条回路"></a>编码任务里的同一条回路</h2><p><a class="link"   href="https://arxiv.org/abs/2507.23370" >Trae Agent<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 把类似的问题搬到了软件工程里。它讨论的是 repository-level issue resolution：给定一个代码库和一个自然语言描述的 issue，系统通过 test-time scaling 生成一组 candidate patches，再从里面挑一个最终补丁。这个任务在形式上很像科学发现里的候选公式搜索，只是候选对象从公式和推导路径换成了 patch，验证器从数值积分换成了测试、执行环境和代码理解。</p><p>我会把 Trae 的结构记成三步。第二步里的两个闸门是平级的，这点容易写错：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Patch Generation：多样化生成候选 patch</span><br><span class="line">→ Patch Pruning：deduplication 与 regression testing 平级剪枝</span><br><span class="line">→ Patch Selection：repo-level understanding + majority voting</span><br></pre></td></tr></table></figure></div><p>多样化采样放在最前面。Trae 的起点不是赌一个 Agent 一次写对，而是用 coder agent 并行生成多个 patch。多样性来自高温采样、多次独立运行，也来自多个模型的 round-robin mixture。这个设计背后的判断很朴素：同一个 issue 反复跑，整体通过率可能差不多，但每次解决的是不同子集。候选空间里确实有互补信息，问题是怎么把它捞出来。</p><p>但候选不是越多越好。ensemble size 增大时，oracle 上界会上升，也就是说只要能选中正确 patch，理论潜力更高；adversary 下界也会下降，因为候选里混入更多错误、冗余和干扰项。候选越多，单轮 prompt selector 看到的信息越长，context dilution 越严重，选择本身反而会变难。</p><p>光多生成几个答案没用。多样化生成后面要接候选治理。</p><p>接下来是 patch pruning。它是一个独立治理层，不是最终选择。Trae 里面的 pruning 由两个平级策略组成：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">patch deduplication：移除 redundant candidates</span><br><span class="line">regression testing：移除 faulty / low-quality candidates</span><br></pre></td></tr></table></figure></div><p>deduplication 解决的是冗余。多个 patch 可能表面不同，实际修改等价；如果全丢给 selector，只会浪费上下文窗口，还会让投票和比较被重复方案污染。Trae 的做法不是让 LLM 随口判断这两个补丁差不多，而是先用 <code>unidiff</code> 把候选转成结构化对象，然后考虑将在结构化对象的层面比较，比直接在自然语言表面比较稳得多。</p><p>regression testing 解决的是不可行或低质量候选。Trae 会从原代码库中运行测试，保留原本就能通过的 tests，再由 tester agent 选择更像 true regression tests 的子集。随后每个 candidate patch 都要在这些 regression tests 上单独跑；失败的 patch 被剪掉，能通过的才进入 selection。这里的可验证反馈是搜索中途的过滤器。</p><p>还有一个很小心的设计：如果所有候选都没通过 regression tests，Trae 不会把候选集清空，而是保留全集进入后续选择。自动选出来的 regression tests 可能不准，误杀正确 patch 的代价太高。剪枝不是粗暴相信 verifier，它也要给自己留后路。</p><p>patch selection 也不是普通的 LLM-as-judge。Trae 的 selector agent 会模拟真实程序理解过程：读相关代码片段，看 issue 描述里提到的文件、patch 修改的文件和依赖相关代码；同时生成和执行测试，收集 execution traces，用静态理解和动态验证拼出 repository-level understanding。最后再用多数投票压一压单次 selector 的不稳定。</p><p>复杂任务里，剪枝和最终选择是两轮不同的引入 Feedback 的过程。Pruning 先把候选空间压小，让我们能够深入搜索；selector 再做更贵、更细的判断，去给出最终的答案。</p><h2 id="Feedback-在这里起什么作用"><a href="#Feedback-在这里起什么作用" class="headerlink" title="Feedback 在这里起什么作用"></a>Feedback 在这里起什么作用</h2><p>宇宙弦论文和 Trae Agent 合在一起看，feedback 不是最后才出现的一张成绩单。它散在任务过程里。模型擅长生成候选，发现发生在候选被环境反复筛选之后。</p><p>生成时有执行反馈。宇宙弦案例里，模型写出的 Python 验证代码会暴露 traceback、数值发散、灾难性抵消；Trae 的 coder agent 也会探索代码库、复现 bug、生成 patch、重跑 reproduction tests。这类反馈直接帮助模型修正当前路线。</p><p>什么样的反馈才撑得起这个筛选？我理解下来，至少要快，也要局部。如果每改一版都要等几个月湿实验，Agent 很难高频迭代；如果反馈只是一句“错了”，下一轮生成也很难真正变好。宇宙弦的 tree search 会剪掉代数错误、数值不稳定和误差太大的分支；Trae 的 patch pruning 会通过结构化去重剪掉 redundant candidates，通过 regression testing 剪掉 faulty candidates。搜索系统需要知道哪个候选更好、哪条分支值得继续。没有一个可比较的 score，Tree Search、evolutionary search、ranking tournament 都会失去抓手。</p><p>到了选择阶段，feedback 又变成证据。科学场景里，这可能是数值基准、形式验证、实验结果、文献证据和专家复核；编码场景里，则是静态代码理解、依赖关系、测试执行结果和 execution traces。它们能帮助 selector 判断哪个候选更值得留下。</p><h2 id="可控搜索让单轮能力变成持续改进"><a href="#可控搜索让单轮能力变成持续改进" class="headerlink" title="可控搜索让单轮能力变成持续改进"></a>可控搜索让单轮能力变成持续改进</h2><p>再看宽一点，宇宙弦论文、Trae Agent 和过去几年几个 AI for Science 系统，其实都在用相近的骨架。</p><p><a class="link"   href="https://www.nature.com/articles/s41586-023-06924-6" >FunSearch<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 把数学问题改写成程序搜索问题：LLM 生成候选程序，evaluator 自动执行和打分，高分程序进入数据库，再被拿来提示下一轮生成。Google DeepMind 的官方介绍里也强调，FunSearch 不是单靠 LLM 灵感，而是把 LLM 的创造性和 automated evaluator 配在一起，用 evaluator 过滤幻觉和错误想法。</p><p><a class="link"   href="https://deepmind.google/blog/alphaevolve-a-gemini-powered-coding-agent-for-designing-advanced-algorithms/" >AlphaEvolve<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 也是类似结构，只是规模更工程化。它是一个 evolutionary coding agent，由 Gemini 生成和修改算法，由自动评估器验证答案，再用演化框架保留有希望的程序。它能处理算法发现和优化问题，但用户得先定义 evaluation function。</p><p><a class="link"   href="https://www.nature.com/articles/s41586-026-10644-y" >Co-Scientist<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 把这套机制放进生命科学假设生成里。它把一次性假设生成拆成多 Agent 系统：Generation agent 产生假设，Reflection agent 扮演虚拟 peer reviewer，Ranking agent 组织 idea tournament，Evolution agent 重组和改写高分假设，Proximity agent 控制多样性，Meta-review agent 综合反馈。这里的 feedback 不再只是数值误差，也包括文献证据、假设新颖性、可测试性、虚拟辩论和排序。</p><p><a class="link"   href="https://arxiv.org/abs/2408.06292" >The AI Scientist<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 更靠近端到端自动化，试图覆盖 idea、code、experiment、paper writing 和 automated review 的全流程。它让人看到自动研究流程可以长成什么样，也把另一个问题推到台前：当系统开始自动写论文，automated reviewer 的可信度会变成瓶颈。如果 evaluator 不够可靠，自动科学很容易产出形式上像论文、但验证不足的东西。</p><p><a class="link"   href="https://www.nature.com/articles/s41586-026-10652-y" >Robin<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则把多 Agent 系统接到实验生物学流程里：文献检索、假设生成、实验建议、数据分析、再生成更新后的假设。它把反馈从纯计算推到了 lab-in-the-loop。代价也很直接：实验反馈更贵，每一次实验机会都得省着用。</p><p>领域不同，骨架却很像：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">候选生成</span><br><span class="line">→ 搜索或排序</span><br><span class="line">→ 外部工具执行</span><br><span class="line">→ 验证/剪枝/集成</span><br><span class="line">→ 反馈进入下一轮</span><br></pre></td></tr></table></figure></div><p>模型提出可能性，系统让这些可能性接受选择压力。这个分工一旦成立，Agent 就不只是一次性给建议，而是在一个受控环境里持续推进候选。</p><p>这里有个容易被跳过的前提。Tree Search 本来就不适合直接处理无限开放的自然语言问题。它在棋类、程序搜索、组合优化里好用，是因为动作空间相对有限，状态可以被表示，下一步动作能被枚举，候选结果也能被某种反馈比较。自然语言问题正缺这些东西。一个问题可以沿着无数方向展开，每个节点都能继续写成一大段话，节点之间很难比较，失败也常常没有明确位置。</p><p>LLM 带来的变化更微妙。它不会让自然语言空间真的变小，但它很擅长临时造出一组可操作的候选结构。一个问题可以被拆成子问题，模糊想法可以被写成假设列表，推理路线可以被整理成几个分支，实验设计可以落到步骤，数学推导可以变成可执行代码，软件修改可以变成 patch，回答质量也可以被拆成几个评价维度。原本连续、松散、不可枚举的语言空间，到了这里，至少在局部有了可以展开、可以选择、可以回退的形状。搜索也就有了下手的地方。</p><h2 id="Feedback-driven-Agent-的通用结构"><a href="#Feedback-driven-Agent-的通用结构" class="headerlink" title="Feedback-driven Agent 的通用结构"></a>Feedback-driven Agent 的通用结构</h2><p>如果从这些系统里抽一层可迁移的结构，我现在会写成这样：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Problem Interface</span><br><span class="line">→ Candidate Generator</span><br><span class="line">→ Diversity / Sampling Controller</span><br><span class="line">→ Pruning Gates</span><br><span class="line">→ Domain Runtime / Tools</span><br><span class="line">→ Verifier / Evaluator</span><br><span class="line">→ Selector / Aggregator</span><br><span class="line">→ Feedback Memory</span><br><span class="line">→ Human Owner</span><br></pre></td></tr></table></figure></div><p>先是 <code>Problem Interface</code>。科学问题不能只停留在一句自然语言里，它要被写成输入、输出、约束、资源预算和成功标准。编码任务也一样，issue 描述、代码库状态、测试环境、允许修改范围和验收标准都要清楚。FunSearch 需要问题描述、seed program 和 evaluator；AlphaEvolve 需要初始程序和评价函数；宇宙弦论文把物理问题压成 <code>I(N, α)</code> 的可计算积分；Trae 则把软件 issue resolution 写成从候选 patch 集合里选出一个能通过 golden tests 且满足 issue 要求的 patch。</p><p>然后才轮到 <code>Candidate Generator</code>。这是 LLM 最擅长的位置：提出公式、程序、实验方案、证明路线、机制假设，也可以生成多个 patch、测试和重构路径。别把它当最终裁判就行。它更像一个高通量候选源。</p><p><code>Diversity / Sampling Controller</code> 管覆盖面。宇宙弦论文里的 negative prompting 会阻止模型重复已有路线；Trae 用高温采样、独立运行和多模型 mixture 扩大 patch 多样性；Co-Scientist 里还有 Proximity agent 控制假设之间的距离。没有多样性，搜索很容易变成同一答案的反复改写。</p><p><code>Pruning Gates</code> 把候选空间压回可选择范围。Trae 在这里给了一个很清楚的样子：deduplication 和 regression testing 都属于 pruning，但它们是平级闸门。一个处理冗余，一个处理不可行或低分。换到别的领域，dedup 可以是分子结构等价、证明路线等价、检索证据重复；testing 可以是仿真失败、约束违反、统计不显著、引用不支持结论。</p><p><code>Domain Runtime / Tools</code> 是 Agent 接触外部世界的接口。数学里是数值积分、符号计算、定理库；生物里是文献数据库、序列分析、实验数据处理；材料里是 DFT、结构稳定性预测、合成可行性检查；软件里是测试集、benchmark、profiling、类型系统和真实代码执行环境。</p><p><code>Verifier / Evaluator</code> 把候选从叙述拉回外部约束。它最好独立于模型自评。数值误差、反例、实验读数、仿真结果、统计显著性、类型检查、单元测试、Lean&#x2F;Coq 证明、专家复核，都可以成为反馈。但 verifier 也不是神谕。Trae 对 regression testing 的保守策略提醒我们：只要 verifier 有误杀风险，系统就要保留回退路径。而每个学科和问题的 <code>Verifier</code> 都不一样。</p><p><code>Selector / Aggregator</code> 留到最后。它要独立于 pruning，不能把剪枝结果直接当最终答案。简单任务可以 generate-and-rerank，复杂任务则需要更贵的 selector。Trae 的 selector agent 要建立 repository-level understanding，还要通过多数投票降低单次判断不稳定性；Co-Scientist 用 ranking tournament 和 meta-review 做类似的聚合。</p><p><code>Feedback Memory</code> 用来记住失败。哪些路线不稳定，哪些表示有用，哪些假设被反例杀死，哪些 patch 类型经常破坏兼容性，哪些测试容易误判，这些都该进系统记忆。否则很多失败会在不同轮次里反复出现。</p><p><code>Human Owner</code> 这一层不能拿掉。人类要判断问题值不值得做，验证器是不是量到了真正的目标，结果是不是只是在钻 benchmark 的空子。最后也要有人把系统发现转成共同体或工程团队能审查、能复现、能交付的东西。</p><h2 id="哪些问题适合这种方法"><a href="#哪些问题适合这种方法" class="headerlink" title="哪些问题适合这种方法"></a>哪些问题适合这种方法</h2><p>这类系统更适合“难求解、易验证”的问题，不适合覆盖所有科学或工程问题。FunSearch 的 Nature 论文里也强调，很多数学和计算机科学问题虽然难以求解，但候选解的质量容易评估。宇宙弦积分也是如此：解析式难找，但给定 <code>N</code> 和 <code>α</code> 后，可以用高精度数值积分做基准。编码任务也类似：真实 issue 的修复很难一次写对，但 patch 能不能编译、测试是否通过、是否破坏既有行为，至少有一部分可以验证。</p><p>把范围放宽一点，适合 Agent 的问题往往长得有点像。它能拆成中间步骤，每一步都可检查，避免拖到最后才发现整件事错了；它有清楚的候选表示，无论那是程序、公式、分子、材料结构、实验方案、因果图、证明草稿、参数化模型，还是一个 patch；它在早期筛选阶段最好有便宜的局部反馈，不必每个候选都押上一次昂贵实验或人工 review。还要有明确的失败信号，比如发散、反例、测试失败、物理约束违反、实验无效、统计不显著、patch parse failure。这些信号都比“看起来不太好”有用得多。</p><p>还有一点容易被忽略：它得允许搜索。候选空间足够大，模型的联想才有价值；空间也不能完全无边界，否则搜索就会变成随机尝试。Trae 的经验尤其提醒我，候选空间扩大以后，选择难度会同步上升。搜索系统不能只看生成上界，也要算选择成本。</p><p>反过来，如果一个问题没有可靠 verifier、反馈极慢、成功标准模糊，只能靠长篇解释自圆其说，就不宜过早把它称为自动发现或自动解决。在这种场景里，AI 仍然可以做文献整理、假设启发、代码草稿和写作辅助，只是还不能被当作一个闭环搜索系统。</p><h2 id="不要把所有-AI-系统都混成-Agent"><a href="#不要把所有-AI-系统都混成-Agent" class="headerlink" title="不要把所有 AI 系统都混成 Agent"></a>不要把所有 AI 系统都混成 Agent</h2><p>现在 AI for Science 和 coding agent 的研究都很多，但它们不都属于同一种东西。</p><p><a class="link"   href="https://www.nature.com/articles/s41586-024-07487-w" >AlphaFold 3<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://www.nature.com/articles/s41586-023-06735-9" >GNoME<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 都是真正有用的科学 AI 系统。前者预测生物分子复合物结构，后者用图网络扩展材料发现空间。它们说明 AI 可以大幅压缩候选空间，改变科学工作流。但严格说，它们更像强大的预测模型或发现工具，不是本文讨论的那种“生成候选、执行搜索、吸收反馈、迭代行动”的 Agent 系统。</p><p>软件工程里也一样。一个模型能生成代码，不等于它已经是稳定的 coding agent。更接近 Agentic Coding 的系统，通常要包含代码库探索、工具调用、测试执行、错误恢复、轨迹记录和最终选择。Trae 的价值不只在 Pass@1 数字，而在于它把 repository-level issue resolution 组织成 generation、pruning、selection 三个相互独立又能衔接的阶段。</p><p>与其问用了 AI 没有，不如问：它有没有把问题变成一个反馈足够丰富的环境。候选有没有被多样化生成？有没有结构化表示？有没有可验证剪枝？有没有独立 selector？有没有人能审查和接管？如果没有这条反馈回路，它可能仍然有用，但还不是这里讨论的 feedback-driven agentic search。</p><h2 id="可以带走的方法论"><a href="#可以带走的方法论" class="headerlink" title="可以带走的方法论"></a>可以带走的方法论</h2><p>要把这套东西搬到一个新领域，不管是新学科还是一个新的 Agent 产品，我觉得第一步不该急着选模型。先把几个问题问清楚。</p><p>候选到底是什么？公式、程序、机制假设、实验方案、分子结构、材料配方、一次浏览器操作、一段检索结果，还是一个 patch？候选对象越清楚，后面的去重、验证和选择才越有抓手。</p><p>不要只让模型生成一个答案。可以用高温采样、多次独立运行、多模型 mixture、negative prompting、proximity control 或其他策略，让候选空间里真的有不同路线。</p><p>剪枝可以有多个闸门，彼此不一定是从属关系，但 feedback 都要可靠。Trae 里的 deduplication 和 regression testing 就是平级策略：一个移除 redundant candidates，一个移除 faulty candidates。科学任务里也可以同时有数值误差、物理约束、仿真结果、统计检验、文献证据等多个剪枝面。</p><p>剪枝之后仍然需要 selector。这个 selector 可以是 ranking tournament、majority voting、repo-level selector agent、专家复核，或者多种方式组合。别让“通过某个局部 verifier”直接等同于“最终正确”。</p><p>还要控制 ensemble size。候选越多，上界可能越高，但上下文、执行、去重、测试和选择成本都会上升。test-time scaling 不是无脑堆采样，而是采样、剪枝、选择一起扩展。</p><p><strong>绕了一圈，我还是会回到最开始那句话。Agent 能不能持续变强，很大程度上取决于我们能不能把问题工程化成一个可搜索、可验证、可剪枝、可选择的反馈环境。科学发现和编码任务就是很好的例子。</strong></p><p>在这样的环境里，LLM 不应该被放在最终裁判的位置。它可以是高通量的候选生成器，可以是跨学科的联想器，也可以是不知疲倦的代码和推导助手。系统要可靠，得靠 verifier；要推进，得靠 search；要规模化，得靠 pruning；要落地，还得靠 selector 和 human owner。模型越强，这套外部结构越重要，因为生成越快，验证和选择的瓶颈就越早露出来。</p><p>所以下半场我更惦记的，不是AI 会不会想出新东西。我更担心另一头：我们能不能给它一个足够好的反馈世界，让那些新东西被筛选和反驳，最后沉淀成可信的知识和可交付的软件，而不只是又一批漂亮但不可验证的文本。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>Shunyu Yao, <a class="link"   href="https://ysymyth.github.io/The-Second-Half/" >The Second Half<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>.</li><li>Pengfei Gao, Zhao Tian, Xiangxin Meng et al., <a class="link"   href="https://arxiv.org/abs/2507.23370" >Trae Agent: An LLM-based Agent for Software Engineering with Test-time Scaling<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, arXiv:2507.23370, 2025.</li><li>Michael P. Brenner, Vincent Cohen-Addad, David P. Woodruff, <a class="link"   href="https://arxiv.org/abs/2603.04735" >Solving an Open Problem in Theoretical Physics using AI-Assisted Discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, arXiv:2603.04735, 2026.</li><li>David P. Woodruff et al., <a class="link"   href="https://arxiv.org/abs/2602.03837" >Accelerating Scientific Research with Gemini: Case Studies and Common Techniques<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, arXiv:2602.03837, 2026.</li><li>Bernardino Romera-Paredes et al., <a class="link"   href="https://www.nature.com/articles/s41586-023-06924-6" >Mathematical discoveries from program search with large language models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, Nature, 2023.</li><li>Google DeepMind, <a class="link"   href="https://deepmind.google/blog/funsearch-making-new-discoveries-in-mathematical-sciences-using-large-language-models/" >FunSearch: Making new discoveries in mathematical sciences using Large Language Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 2023.</li><li>Google DeepMind, <a class="link"   href="https://deepmind.google/blog/alphaevolve-a-gemini-powered-coding-agent-for-designing-advanced-algorithms/" >AlphaEvolve: A Gemini-powered coding agent for designing advanced algorithms<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 2025.</li><li>Alexander Novikov et al., <a class="link"   href="https://arxiv.org/abs/2506.13131" >AlphaEvolve: A coding agent for scientific and algorithmic discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, arXiv:2506.13131, 2025.</li><li>Vivek Natarajan et al., <a class="link"   href="https://www.nature.com/articles/s41586-026-10644-y" >Accelerating scientific discovery with Co-Scientist<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, Nature, 2026.</li><li>Google DeepMind, <a class="link"   href="https://deepmind.google/blog/co-scientist-a-multi-agent-ai-partner-to-accelerate-research/" >Co-Scientist: A multi-agent AI partner to accelerate research<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 2026.</li><li>Chris Lu et al., <a class="link"   href="https://arxiv.org/abs/2408.06292" >The AI Scientist: Towards Fully Automated Open-Ended Scientific Discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, arXiv:2408.06292, 2024.</li><li>Sakana AI, <a class="link"   href="https://sakana.ai/ai-scientist/" >The AI Scientist: Towards Fully Automated Open-Ended Scientific Discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 2024.</li><li>Ali Essam Ghareeb et al., <a class="link"   href="https://arxiv.org/abs/2505.13400" >Robin: A multi-agent system for automating scientific discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, arXiv:2505.13400, 2025.</li><li>FutureHouse, <a class="link"   href="https://www.futurehouse.org/research-announcements/demonstrating-end-to-end-scientific-discovery-with-robin-a-multi-agent-system" >Demonstrating end-to-end scientific discovery with Robin<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 2025.</li><li>Peter Jansen et al., <a class="link"   href="https://arxiv.org/abs/2406.06769" >DISCOVERYWORLD: A Virtual Environment for Developing and Evaluating Automated Scientific Discovery Agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, NeurIPS Datasets and Benchmarks, 2024.</li><li>Allen Institute for AI, <a class="link"   href="https://allenai.github.io/discoveryworld/" >DiscoveryWorld project page<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>.</li><li>Google DeepMind and Isomorphic Labs, <a class="link"   href="https://www.nature.com/articles/s41586-024-07487-w" >Accurate structure prediction of biomolecular interactions with AlphaFold 3<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, Nature, 2024.</li><li>Google DeepMind, <a class="link"   href="https://www.nature.com/articles/s41586-023-06735-9" >Scaling deep learning for materials discovery<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, Nature, 2023.</li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/06/feedback-driven-agentic-scientific-discovery/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/06/feedback-driven-agentic-scientific-discovery/"/>
    <published>2026-06-06T04:00:00.000Z</published>
    <summary>The cosmic string case and Trae Agent come from different domains, but both ask the same design question: after an LLM generates candidates, how does the system search, verify, prune, and choose?</summary>
    <title>Feedback Loops for Agentic Search</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Essays" scheme="https://hyacehila.github.io/categories/essays/"/>
    <category term="Methodology" scheme="https://hyacehila.github.io/tags/Methodology/"/>
    <category term="Society" scheme="https://hyacehila.github.io/tags/Society/"/>
    <content>
      <![CDATA[<blockquote><p>本文译自 Addy Osmani 的<a class="link"   href="https://x.com/addyosmani/status/2056078124346228860" >《Don’t Outsource the Learning》<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，并在不改变原意的前提下做了适当的语言润色与本地化。原作者：<a class="link"   href="https://x.com/addyosmani" >Addy Osmani<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。文中第一人称「我」均指原作者。</p></blockquote><h1 id="Don’t-Outsource-the-Learning"><a href="#Don’t-Outsource-the-Learning" class="headerlink" title="Don’t Outsource the Learning"></a>Don’t Outsource the Learning</h1><p>现在有件事变得太容易了：让 AI 把代码写完，自己却把学习这一步省掉。Bug 是修好了，可你的心智模型纹丝没动——时间一长，甚至还会退步。我们其实是在悄悄地用未来的能力，换今天的速度，而工具并不会拦着我们。要不要停下来，只能由你自己决定。</p><p>我们大多数人都滑进了同一个套路：把一段需求或一条报错粘进去，模型递回来一个修复方案，症状消失，你直接发版（ship）。在这个循环的某个环节，问题与解法之间那场乱糟糟的较量，已经彻底不再发生了。</p><p>我以前写过「认知投降」（cognitive surrender）——就是 AI 的判断不知不觉顶替掉你自己判断的那一刻。今天要说的，是它的单人版本：场上只有你和模型。模型比你快，于是你索性不再跟它比拼「谁更理解」。可就在这成千上万次的小互动里，那些没有 AI 在旁边时你本来能独立做出来的东西，正一周一周地被减弱。而这些时刻，发生在当下的那一天，没有哪一次看起来像是个问题。</p><p>我并不反对 AI。这些工具我天天都在用，过去一年靠它们交付的成果，比之前好几年加起来还多。但我们使用它们的默认方式，只为一件事做了优化：把任务关掉。</p><p>而这件事，跟「让自己一直敏锐到足以在整段职业生涯里持续驾驭它们」，根本是两个目标。</p><h2 id="这些研究正在指向同一个结论"><a href="#这些研究正在指向同一个结论" class="headerlink" title="这些研究正在指向同一个结论"></a>这些研究正在指向同一个结论</h2><p>过去一年里的几项研究，落点出奇地一致。</p><p><strong>Anthropic</strong> 在 2026 年初做了一个随机对照试验：让工程师去学一个全新的 Python 库，一半有 AI 协助，一半没有。两组完成任务的速度不相上下。但在随后的理解测验里，AI 组败下阵来——50% 对手动组的 67%，而且越是调试题，差距拉得越大。更耐人寻味的是 AI 组<strong>内部</strong>的分化：用 AI 去追问「概念」的工程师得分超过 65%，直接复制粘贴生成代码的则不到 40%。可见决定结果的不是工具本身，而是你用它的姿势。</p><p><strong>MIT</strong> 的《Your Brain on ChatGPT》研究，把写文章的人分成三组：用 LLM 的、用搜索引擎的、纯靠脑子的。EEG 数据显示，外部辅助每多叠一层，大脑的连接强度就弱一分，其中 LLM 组的耦合最弱。文章写完后，83% 的 LLM 组用户连自己刚写的东西里的一句话都复述不出来。研究者给这个现象起了个名字——「认知负债」（cognitive debt）：今天省下的脑力，明天要用批判性思维来还。</p><p><strong>CHI 2026</strong> 的一项研究又补上了相关的一笔：当人们在任务一开始就用上 LLM，LLM 会替整个问题定好框架。即便后面的活儿全是人自己干的，这种最初的「锚定」也会让最终决策明显变差。换句话说，操作的<strong>先后顺序</strong>，比 AI 用了多少更要紧。</p><p>方法各不相同，结论却殊途同归：<strong>在缺乏主动学习意图的情况下使用 AI，会悄悄蚀掉那项你正靠它吃饭的技能。</strong></p><h2 id="工具的默认设置是为了「交付」，不是为了「教会你」"><a href="#工具的默认设置是为了「交付」，不是为了「教会你」" class="headerlink" title="工具的默认设置是为了「交付」，不是为了「教会你」"></a>工具的默认设置是为了「交付」，不是为了「教会你」</h2><p>打开一个编码 agent，一切照默认走，那么所有设计都只朝一个指标看齐：把任务做完。模型写代码，你点接受，循环往复。在任何一个节点上，工具都不会停下来问你一句「你觉得问题出在哪？」或者「要不先自己写头五行试试？」</p><p>这就是当下的产品与交互的设计方向。产品团队被奖励的，是合并的变更数和更短的周期，而不是「把你磨成一个更敏锐的工程师」。我们都想少敲几下键盘，于是工具把摩擦一点点润滑了。麻烦在于，<strong>学习恰恰就藏在那些摩擦里</strong>。</p><p>也有几家公司想给这种循环踩一脚刹车。Anthropic 为 Claude 上线了「学习模式」（Learning Mode）：用苏格拉底式的反问，并在往下走之前先让你写一段代码。OpenAI 和 Google 也推出了类似的功能。但说实话，几乎没人在真正的生产工作里用它们。我们悄悄把它们归进了「学生才用」的那一类——这是个误判。同一个能帮大二学生学会 React 的功能，照样能帮一位资深工程师学会 Rust，前提只是你愿意重新当一回新手。</p><h2 id="「既然-AI-能做，我为什么还要懂？」"><a href="#「既然-AI-能做，我为什么还要懂？」" class="headerlink" title="「既然 AI 能做，我为什么还要懂？」"></a>「既然 AI 能做，我为什么还要懂？」</h2><p>这问题问得在理。对某些活儿来说，答案确实是——也许你真不用懂。如果是样板代码、胶水代码，或者一个你这辈子都不会再看第二眼的一次性 CI 脚本，那就放心交出去，把这点语法背进脑子的机会成本太高了。</p><p>但换成真正要长期维护的软件，<strong>纯委托会在几个特定的地方崩掉</strong>：</p><ul><li><strong>东西出故障的时候。</strong> AI 写的代码，崩起来和人写的没两样。「这是 agent 写的」帮不了你调试，团队里总得有人真正吃透这套架构。</li><li><strong>它一本正经地犯错的时候。</strong> LLM 仍然会胡说八道。面对一个看着合理、实则错误的答案，唯一的防线就是你懂得够多、一眼能识破。skills 之类的「创可贴」只能顶一阵子。</li><li><strong>地基变动的时候。</strong> 代码是临时的，系统是长久的。框架升级、或者安全评审揪出一个结构性问题时，你没法靠「再 prompt 一遍」蒙混过去，得有真正理解这套系统、能把它迁移过去的人。</li><li><strong>你偏离中位数的时候。</strong> 对那些在 GitHub 上被解决过上百万遍的问题，AI 游刃有余；可你离中位数越远，它就越力不从心。那些困难的、没文档的问题——也正是撑得起一份资深薪水的问题——依旧要靠深刻的理解。</li><li><strong>市场重新定价的时候。</strong> 那些只会借 AI 交付、离了 AI 就不行的工程师，正踏进一个早已开始重估「专业能力值多少钱」的市场。拿 AI 来跳过学习，等于拿未来的竞争力，去换一个稍微轻松点的周二下午。</li></ul><h2 id="解药藏在你怎么提问里"><a href="#解药藏在你怎么提问里" class="headerlink" title="解药藏在你怎么提问里"></a>解药藏在你怎么提问里</h2><p>好消息是：制造认知负债的那些工具，同样能把人磨得更锋利。区别只在于，你向它们提出什么样的要求。</p><ul><li><strong>先立假设，再开口问。</strong> 在请求修复方案之前，先用两三句话写下你认为问题出在哪，然后拿模型的回答去<strong>检验</strong>你的判断，而不是<strong>替换</strong>掉它。</li><li><strong>先要解释，再要代码。</strong> 在陌生领域，第一句不妨这么问：「讲讲这是怎么工作的、还有哪些替代方案、各自的取舍是什么。」等概念吃透了，再去要代码。</li><li><strong>吃不准的时候，把学习模式打开。</strong> 是会慢一些，但慢正是它的意义。</li><li><strong>把 AI 的输出当成初级同事提的 PR。</strong> 去读它、挑它的毛病、跟它较真。你会因为「测试过了」就直接合并吗？不会的话，这里也别合。</li><li><strong>隔三差五，亲手把东西重推一遍。</strong> 挑一段模型替你写的代码，试着从零再造一次。这是一次校准，能让你看清自己究竟悄悄丢了多少。</li><li><strong>让模型把它刚做的事讲给你听。</strong> 它写出一个漂亮的函数后，问问它用到了哪些概念、想看懂这个设计该去读些什么。多这么一问，你从这次会话里带走的东西就完全不一样了。</li></ul><p>这些都谈不上什么大动作，不过是在你已经在用的工具里，调整几个小小的姿势而已。</p><h2 id="两个指标，而不是一个"><a href="#两个指标，而不是一个" class="headerlink" title="两个指标，而不是一个"></a>两个指标，而不是一个</h2><p>我现在习惯在每次编码收工时问自己一句：<strong>今天我学到东西了，还是只是关掉了几个 issue？</strong></p><p>有时候诚实的答案就是「我只是关了几个 issue」——这也没什么。但要是接连好几个月答案都如此，那认知负债就在你看不见的后台默默累积。</p><p>「交付」和「学到手」是两条不同的线。你的老板和客户永远只会问第一条，第二条只能靠你自己盯着。</p><blockquote><p>我宁可只交付出本可以交付的 80%，却把该学会的东西学满 100%，也不要反过来。把时间拉到很多年，这两种取法会养出截然不同的工程师。</p></blockquote><p>你不必在「用 AI」和「学习」之间二选一，但你确实得主动挑一套两者兼顾的工作流——因为默认设置不会替你挑。工具一直都准备好了，就等你。</p><p>你正打算随手扔出去的下一件无聊小事，就是个不错的起点。</p>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/03/dont-outsource-the-learning/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/03/dont-outsource-the-learning/"/>
    <published>2026-06-02T18:00:00.000Z</published>
    <summary>A Chinese translation and commentary of Addy Osmani's essay: the default AI coding loop is optimized for closing tasks, not for keeping you sharp.</summary>
    <title>Don't Outsource the Learning</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Essays" scheme="https://hyacehila.github.io/categories/essays/"/>
    <category term="Society" scheme="https://hyacehila.github.io/tags/Society/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="AI Safety" scheme="https://hyacehila.github.io/tags/AI-Safety/"/>
    <content>
      <![CDATA[<p>Agent 这个词已经快被用烂了。</p><p>浏览器里能点按钮的是 Agent，IDE 里能改代码的是 Agent，客服后台里能分单的是 Agent，手机里能替你打开 App 的也是 Agent。再往远处说，就变成完全自主智能体、AGI、ASI。故事听起来很顺：模型继续变强，工具越接越多，某一天它自然从聊天窗口里站起来，接管人类手里的大部分工作。</p><p>我不太相信这个叙事。至少不相信它会以这种方式发生。</p><p>Agent 的变化当然重要。Chatbot 主要在回答，Agent 开始行动。它看环境、调工具、读写状态、连续执行任务。从这一刻起，我们讨论的就不只是智能，还有行动权、授权边界和后果由谁承担。</p><p>一个只会说错话的模型，最坏情况通常是一段错误文本。一个能操作浏览器、手机、文件系统、邮箱、CRM、支付页面和公司后台的 Agent，说错话只是风险里最轻的一层。它可能点错按钮，发错邮件，删错文件，把不该上传的内容交给第三方服务，或者在你还没真正理解时替你做了一个不可逆动作。</p><p><strong>通用 AI 已经足够强，但还不够可信。它已经能做很多事，麻烦的是，我们还不知道哪些事真的可以放心交给它。</strong> 我在 OpenClaw 的那篇文章里聊过这个问题，但那包含了个人的一些经历和无关的技术细节，现在让我们抛开过多的技术细节来继续讨论这个问题</p><h2 id="从手机和浏览器开始的不安"><a href="#从手机和浏览器开始的不安" class="headerlink" title="从手机和浏览器开始的不安"></a>从手机和浏览器开始的不安</h2><p>豆包手机风波是一个很好的切口。那篇 <a class="link"   href="https://www.gm7.org/archives/23470" >《从豆包手机风波看通用 AI Agent 的困局与出路》<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里讲得很好：通用 Agent 不只是技术问题，还会撞上安全、法律、平台生态和用户授权。手机不是一个普通界面。通讯录、相册、私聊、验证码、支付、定位、App 登录态都在里面。让 AI 进入手机，就不是让它“帮我总结一下网页”那么简单。</p><p>AI 浏览器也是同一类问题。浏览器里有登录态，有 Cookie，有公司后台，有邮箱，有各种 SaaS 系统。传统浏览器扩展已经足够麻烦，Agentic Browser 又多了一层“它会替你行动”。Gartner 那些关于 AI 浏览器的安全提醒，语气可能偏保守，但担心本身并不奇怪：网页内容可以被攻击者控制，Agent 又会把网页内容当成任务上下文。间接提示注入不是什么遥远的实验室问题，它天然适合发生在浏览器里。</p><p>Agent 真正危险的地方，不是会出错，而是会带着权限出错。</p><p>普通软件的权限通常比较清楚：这个按钮会提交表单，那个 API 会写数据库。Agent 的权限更像一团动态东西。它读到什么、理解成什么、接下来调用哪个工具，很多时候不是预先写死的。你当然可以加审批、加沙箱、加策略，但只要目标是通用和自主，系统就会不断向边界外伸手。</p><p>我能理解用户为什么兴奋。第一次看到 AI 自己打开网页、填表、查资料、整理结果，确实会有一种“它终于能做事了”的感觉。可问题也从这里开始：如果它能替我做事，我到底愿意把多少东西交给它？</p><h2 id="几种不同的未来想象"><a href="#几种不同的未来想象" class="headerlink" title="几种不同的未来想象"></a>几种不同的未来想象</h2><p>现在关于 Agent 的未来，市场上并没有一个统一版本。大家嘴上都在说 agent，心里想的东西可能很不一样。</p><p>企业软件公司喜欢把 Agent 讲成数字员工。Microsoft 2026 Work Trend Index 里的“Frontier Firm”就是这个方向：人和 Agent 混在一起工作，Agent 承担更多执行，人类负责意图、判断和质量。这套叙事很顺，也最容易被企业接受。它没有直接说人会消失，而是说组织会重新分工。</p><p>创业叙事往往更激进。autonomous workforce、多 Agent 公司、无人值守业务流程，这些词都很诱人。一个能 24 小时工作的数字员工，不抱怨、不请假、不需要办公室。如果成本足够低，企业没有理由不试。问题是，这个想象经常把“能跑 demo”直接跳到“能扛责任”。</p><p>安全团队看见的是另一种东西：一个高权限软件主体。OpenAI 在 <a class="link"   href="https://openai.com/index/practices-for-governing-agentic-ai-systems/" >Practices for Governing Agentic AI Systems<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里讨论各方责任和安全实践，Anthropic 在 <a class="link"   href="https://www.anthropic.com/research/trustworthy-agents" >trustworthy agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 相关研究里反复谈人类控制、透明度、隐私、安全和身份归属。它们没有否定 Agent，只是把问题拉回了责任：当 AI 能行动时，谁来负责？</p><p>AI Safety 那边更担心长期目标。Yoshua Bengio 近年一直提醒，人类真正该小心的不是会回答问题的 AI，而是有自主目标、能长期行动、能获取资源的 superintelligent agent。他提出 Scientist AI 这类更审慎的路径，本质上是在说：别急着把最强的智能做成最强的行动者。</p><p>我更关注后两种。Agent 会来，而且会很深地进入工作流。但完全自主智能体不会那么快成为主流。模型会继续变聪明，可聪明和可信之间隔着一整套工程、制度和责任问题。</p><h2 id="为什么长期完全自治很难"><a href="#为什么长期完全自治很难" class="headerlink" title="为什么长期完全自治很难"></a>为什么长期完全自治很难</h2><p>今天的模型已经能完成很多以前想不到的任务。METR 的 <a class="link"   href="https://metr.org/time-horizons/" >Task-Completion Time Horizons of Frontier AI Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 用 time horizon 来衡量模型能完成多长的人类专家任务，这比普通 benchmark 更接近 Agent 讨论。它把问题从“模型会不会做题”推进到“模型能不能连续做事”。</p><p>但这个指标不能读得太远。METR 自己也提醒，time horizon 不是模型能连续自治多久。它衡量的是特定任务、特定环境、特定可靠性下，AI agent 能完成相当于人类专家多长时间的任务。真实世界里的长期任务要脏得多。</p><p>真实任务经常没有干净目标。用户一开始也说不清自己要什么，中途又会改主意。上下文散在聊天记录、文档、会议、邮件、公司习惯和人的偏好里。反馈也慢。今天做的决策，可能两周后才知道有没有坑。更麻烦的是，很多错误并不会立刻报错。它们会变成错误承诺、错误库存、错误审批、错误沟通，然后在系统里慢慢发酵。</p><p>长期自治还会遇到治理问题。一个 Agent 如果只是帮我总结网页，出错了我最多骂它两句。可如果它要持续经营一个广告账户、管理一个供应链、处理客户投诉、修改生产系统配置，事情就变了。它需要预算边界、权限边界、异常上报、审计记录、回滚机制，还需要有人对结果负责。</p><p>这里最麻烦的不是“它会不会犯错”。人也会犯错。麻烦的是，Agent 犯错的方式不太像人。它可能在看起来很合理的文本里埋下一个错误假设，也可能被网页里的恶意指令带偏，还可能因为工具权限太大，把一个小误解放大成真实损失。模型越像一个能干的人，用户越容易忘记它其实没有人的常识、责任感和处境理解。</p><p>我不太认同“模型再强一点，完全自治自然就到了”。长期自治不是把模型运行更久，而是让系统在更久的时间里仍然能被治理。它需要稳定目标、可靠反馈、可控权限、可解释过程和责任闭环。少一块都不舒服。</p><h2 id="User-in-the-loop-不是临时补丁"><a href="#User-in-the-loop-不是临时补丁" class="headerlink" title="User in the loop 不是临时补丁"></a>User in the loop 不是临时补丁</h2><p>很多人说 Human in the loop 时，脑子里想的是一个很笨的画面：AI 每做一步都问人，用户不停点确认。这当然很烦，也很低效。如果 HITL 只是这样，它确实会被淘汰。</p><p>我说的 User in the loop，不是让人当橡皮图章。更接近的画面是：人还握着方向盘、刹车和责任，只是不用亲手拧每一颗螺丝。</p><p>人提出目标，Agent 给出计划。人不一定检查每一步，但应该能看见它准备碰哪些资源、可能产生什么后果。低风险动作可以自动执行，高风险动作要批准。执行过程中，人可以暂停、修改目标、接管任务。结束以后，系统要留下足够清楚的记录，方便回看它做了什么、为什么这么做、错在哪里。</p><p>Anthropic 在 <a class="link"   href="https://www.anthropic.com/research/measuring-agent-autonomy" >Measuring AI agent autonomy in practice<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 里有一个我觉得很重要的判断：有效监督不是把人塞进审批链，而是让人能真正监控和介入。经验用户有时会减少逐步批准，但这不等于完全放手。他们更像是在看仪表盘，在风险变大时接管。</p><p>OpenAI 的 <a class="link"   href="https://openai.com/index/harness-engineering/" >Harness engineering<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 说得更直白：Humans steer. Agents execute. 这句话比很多“数字员工”宣传都准确。人类不一定亲手做每个步骤，但仍然要设计环境、定义目标、建立反馈，并判断结果。</p><p>短期内我更看好分级自治。有些任务只需要观察和建议，比如整理会议纪要、找异常数据、生成候选方案。有些任务可以让 Agent 先执行，再由人验收，比如改一小段代码、草拟邮件、准备报告。有些任务可以自动执行，但要有预算和回滚，比如内部数据同步、低风险客服分流。再往上，涉及钱、法律责任、用户隐私、生产系统和公共安全的动作，就不该轻易交给无人值守的 Agent。</p><p>这不是保守。是现实。</p><h2 id="我们应该做什么"><a href="#我们应该做什么" class="headerlink" title="我们应该做什么"></a>我们应该做什么</h2><p>如果要认真建设 Agent，我觉得方向反而很清楚。</p><p>先做边界清楚的小工作流。不要一开始就做“帮我经营整家公司”的万能 Agent。让它负责一个具体环节：收集信息、生成草稿、检查差异、跑测试、分拣工单、监控指标。任务越具体，反馈越清楚，Agent 越容易变好。</p><p>权限要小。能只读就别给写权限，能在沙箱里跑就别直接碰生产环境，能用临时凭证就别给长期 token。过去软件权限错了，是某个功能越权；Agent 权限错了，可能是一个会推理、会组合工具、会绕路的系统越权。</p><p>观测要早做。日志、轨迹、工具调用、输入输出、人工修改、失败原因，这些东西一开始看起来麻烦，但没有它们，Agent 产品最后会变成玄学。你不知道它为什么成功，也不知道它为什么失败。更糟的是，你以为它在变好，其实只是 demo 更顺了。</p><p>评测也要贴近场景。通用 benchmark 只能说明底模能力，不能说明你的 Agent 在真实业务里可靠。客服 Agent 要看误分率和升级率，代码 Agent 要看测试、diff 和 review，浏览器 Agent 要看任务完成率、误点击、敏感数据暴露和恢复能力。不同任务要有不同的验收口径。</p><p>最后，人类角色要重新设计。不要把人当成阻碍自动化的旧零件。人应该在目标、边界、异常和责任上出现，而不是被迫盯着每个低价值步骤。好的 Agent 系统会把人从重复执行里拉出来，但不会把判断和责任一起拿走。</p><h2 id="我们不要做什么"><a href="#我们不要做什么" class="headerlink" title="我们不要做什么"></a>我们不要做什么</h2><p>我最不喜欢的一种做法，是把“完全自治率”当成先进程度。好像人介入越少，系统就越高级。这在低风险、强反馈的任务里可能成立，但一旦任务进入真实组织，未必如此。</p><p>很多 Agent 项目最后失败，不一定是模型太笨，常见问题反而更朴素：目标太大、权限太重、价值不清、成本失控。Gartner 预测到 2027 年底会有超过 40% 的 agentic AI 项目被取消，理由包括成本上升、业务价值不清和风险控制不足。这个数字不一定精确，但方向我相信。很多公司现在买的不是 Agent，是焦虑。</p><p>也不要把 demo 当生产。一个 Agent 能在录屏里订机票、改网页、跑代码，不代表它能在一万个真实用户那里稳定工作。生产系统最怕的不是一次失败，而是失败不可见、不可复现、不可追责。</p><p>更不要把 prompt 当治理。Prompt 可以约束行为，但它不是权限系统，不是审计系统，不是法律责任，也不是安全边界。让模型在 system prompt 里写“不要泄露隐私”，和真的限制它访问隐私数据，是两件事。</p><p>我也不建议急着把最强模型直接接到最高权限工具上。强模型更会做事，也更会把错误做成完整方案。它越像一个可靠员工，越需要真实的员工管理方式：职责、权限、考核、审计、离职交接，甚至事故复盘。</p><h2 id="AGI-ASI-讨论不能绕过可信"><a href="#AGI-ASI-讨论不能绕过可信" class="headerlink" title="AGI&#x2F;ASI 讨论不能绕过可信"></a>AGI&#x2F;ASI 讨论不能绕过可信</h2><p>说到这里，就会回到 AGI&#x2F;ASI。</p><p>很多关于 AGI 的讨论喜欢从能力外推：模型数学更强（在写到这一段时，GPT解决了 Erdos 平面距离猜想）、代码更强、工具使用更强、长任务更强，所以 AGI 越来越近。我不否认能力在推进，也不否认某些跳变可能发生。只是我越来越觉得，AGI 讨论如果只看能力，会漏掉最麻烦的部分。</p><p>一个系统足够通用，不等于它足够可信。一个系统足够聪明，也不等于它适合被授权长期行动。</p><p>OpenAI 的 <a class="link"   href="https://openai.com/index/introducing-superalignment/" >Superalignment<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 项目当年提出过一个很直白的问题：如果系统比人类更聪明，人类如何监督它？这个问题放到今天的 Agent 上，已经有了一个小号版本：如果 Agent 能比普通用户更懂浏览器、更懂代码、更懂金融产品、更懂公司流程，用户如何判断它的建议和行动是对的？</p><p>现在的答案还不够好。我们有评测，有安全策略，有人工审核，有红队测试，有模型监控，有权限系统。但这些东西加起来，还不是“我可以放心让一个通用智能体长期自主行动”的答案。</p><p>这也是我认为 AGI&#x2F;ASI 仍然比较遥远的原因。模型会继续变强，但“强”距离“可以长期委托”还有很远。真正进入社会结构的智能，必须被制度化。它要能被授权，也能被撤权；能执行，也能解释；能学习，也能被审计；能带来收益，也能在出错时被停止。</p><h2 id="结尾：未来是重新分工"><a href="#结尾：未来是重新分工" class="headerlink" title="结尾：未来是重新分工"></a>结尾：未来是重新分工</h2><p>我不觉得 Agent 的未来是彻底取代人类工作者。至少短期不是。</p><p>更可能发生的是，工作被重新切开。边界清楚、反馈明确、重复性高、数字化程度高的部分，会越来越多交给 Agent。人会继续留在目标定义、质量判断、跨人协调、伦理和责任这些位置上。很多岗位会变，某些岗位会消失，也会有新的岗位长出来。这个过程不会温柔，但它也不是一句“AI 取代一切”能概括的。</p><p>Agent 真正有价值的地方，是让人把一部分执行委托出去。可委托不是放弃控制。委托的前提是我知道你能做什么、不能做什么、做错了怎么办，以及我什么时候可以叫停。</p><p>我对 Agent 未来的判断很简单：我们会继续走向更强的自治，但主流形态会先是可治理的自治。人类不会一直亲手执行每一步，也不会很快从系统里消失。</p><p>未来的 AI 未必像一个完全独立的同事。它更可能像一层到处存在的行动能力，被嵌进浏览器、IDE、手机、公司后台、数据系统和个人工作流里。它会改变工作，也会改变人对自己能力边界的想象。</p><p>但在它足够可信之前，最好的问题仍然不是“能不能让它自己干完”，而是“我们应该怎样把一部分世界交给它”。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a class="link"   href="https://www.gm7.org/archives/23470" >从豆包手机风波看通用 AI Agent 的困局与出路<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic, <a class="link"   href="https://www.anthropic.com/research/trustworthy-agents" >Trustworthy agents in practice<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic, <a class="link"   href="https://www.anthropic.com/research/measuring-agent-autonomy" >Measuring AI agent autonomy in practice<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Anthropic, <a class="link"   href="https://www.anthropic.com/news/our-framework-for-developing-safe-and-trustworthy-agents" >Our framework for developing safe and trustworthy agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>OpenAI, <a class="link"   href="https://openai.com/index/practices-for-governing-agentic-ai-systems/" >Practices for Governing Agentic AI Systems<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>OpenAI, <a class="link"   href="https://openai.com/index/introducing-superalignment/" >Introducing Superalignment<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>OpenAI, <a class="link"   href="https://openai.com/index/harness-engineering/" >Harness engineering: leveraging Codex in an agent-first world<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>METR, <a class="link"   href="https://metr.org/time-horizons/" >Task-Completion Time Horizons of Frontier AI Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Gartner, <a class="link"   href="https://www.gartner.com/en/newsroom/press-releases/2025-06-25-gartner-predicts-over-40-percent-of-agentic-ai-projects-will-be-canceled-by-end-of-2027" >Gartner Predicts Over 40% of Agentic AI Projects Will Be Canceled by End of 2027<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Gartner, <a class="link"   href="https://www.gartner.com/en/newsroom/press-releases/2026-05-26-gartner-says-applying-uniform-governance-across-ai-agents-will-lead-to-enterprise-ai-agent-failure" >Gartner Says Applying Uniform Governance Across AI Agents Will Lead to Enterprise AI Agent Failure<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Microsoft, <a class="link"   href="https://www.microsoft.com/en-us/worklab/work-trend-index/agents-human-agency-and-the-opportunity-for-every-organization" >2026 Work Trend Index: Agents, Human Agency, and the Opportunity for Every Organization<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>NIST, <a class="link"   href="https://www.nist.gov/news-events/news/2026/02/announcing-ai-agent-standards-initiative-interoperable-and-secure" >Announcing the AI Agent Standards Initiative for Interoperable and Secure AI Agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>OWASP, <a class="link"   href="https://aivss.owasp.org/aiuc-aivss-crosswalk" >AIVSS Crosswalk<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Yoshua Bengio, <a class="link"   href="https://yoshuabengio.org/en/publication/superintelligent-agents-pose-catastrophic-risks-can-scientist-ai-offer-safer-path" >Superintelligent Agents Pose Catastrophic Risks: Can Scientist AI Offer a Safer Path?<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/06/01/ai-agent-future-governed-delegation/</id>
    <link href="https://hyacehila.github.io/blog/2026/06/01/ai-agent-future-governed-delegation/"/>
    <published>2026-06-01T05:00:00.000Z</published>
    <summary>The future of AI agents will not begin with full autonomy replacing humans, but with governed delegation: humans set goals and boundaries while AI takes on more execution.</summary>
    <title>The Future of AI Agents Is Governed Delegation, Not Full Autonomy</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="Dimensionality Reduction" scheme="https://hyacehila.github.io/tags/Dimensionality-Reduction/"/>
    <category term="Data Curation" scheme="https://hyacehila.github.io/tags/Data-Curation/"/>
    <category term="Retrieval" scheme="https://hyacehila.github.io/tags/Retrieval/"/>
    <content>
      <![CDATA[<p>RAG 系统出错时，我们很容易先把锅甩给生成模型：模型是不是不够强，提示词是不是写得不够好，是不是还缺一个更复杂的 agent loop。这个反应很自然，因为最后说错话的是模型。但在很多真实问题里，答案在更早的地方就坏了。模型拿到的上下文本来就不对，后面再怎么生成，也只是在错误材料上做语言组织。</p><p>早期的 <a class="link"   href="https://arxiv.org/abs/2005.11401" >RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://arxiv.org/abs/2004.04906" >DPR<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 研究已经把这个分工讲得很清楚：生成质量依赖检索阶段提供的外部证据。到了工程实践里，这句话会落到一堆更具体的麻烦上。检索失败往往不是一个单点故障，而是一组空间问题：查询没有靠近正确文档，正确文档被切得太碎，语义相近但业务上不同的内容挤在一起，长尾知识变成孤岛，某些来源的数据污染了整个邻域，或者 embedding 模型把表面相似误当成了任务相似。</p><p>我关注 <a class="link"   href="https://github.com/apple/embedding-atlas" >Embedding Atlas<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，也是因为它处理的正是这个问题。它不是又一个“把向量降到二维然后画散点图”的小工具。它把 embedding、metadata、搜索、过滤、近邻和聚类放进同一个交互界面里，让人可以真的翻一批文本、图片或其他对象在表示空间里的组织方式。它的论文 <a class="link"   href="https://arxiv.org/abs/2505.06386" >Embedding Atlas: Low-Friction, Interactive Embedding Visualization<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 强调“低摩擦”和“交互式分析”。这对 RAG 开发者很重要：我们需要的通常不是一张漂亮截图，而是一个能反复追问的诊断入口。</p><p>对 RAG 来说，我真正想问的问题很朴素：</p><p><strong>这套向量空间到底把什么东西放近了，又把什么东西放远了？</strong></p><h2 id="RAG-的检索问题，是空间组织问题"><a href="#RAG-的检索问题，是空间组织问题" class="headerlink" title="RAG 的检索问题，是空间组织问题"></a>RAG 的检索问题，是空间组织问题</h2><p>最朴素的 RAG 流程可以写成：</p><pre class="mermaid">flowchart LR    DOC["原始文档"] --> CHUNK["切分为 chunk"]    CHUNK --> EMB["计算 embedding"]    EMB --> INDEX["向量索引"]    Q["用户问题"] --> QEMB["问题 embedding"]    QEMB --> RET["近邻检索"]    INDEX --> RET    RET --> CTX["上下文拼装"]    CTX --> LLM["生成答案"]</pre><p>从工程上看，这里面有很多步骤：解析、清洗、切分、向量化、索引、召回、重排、拼上下文、生成。但只看 embedding 这一层，动作反而很简单：把文档块和查询都变成高维空间里的点，然后用距离或相似度决定谁应该进入上下文。</p><p>设文档块向量为</p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>d</mi><mi>i</mi></msub><mo>∈</mo><msup><mi mathvariant="double-struck">R</mi><mi>m</mi></msup></mrow><annotation encoding="application/x-tex">d_i \in \mathbb{R}^m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7144em;"></span><span class="mord"><span class="mord mathbb">R</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span></span></span></span></span><p>查询向量为</p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>q</mi><mo>∈</mo><msup><mi mathvariant="double-struck">R</mi><mi>m</mi></msup></mrow><annotation encoding="application/x-tex">q \in \mathbb{R}^m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7144em;"></span><span class="mord"><span class="mord mathbb">R</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span></span></span></span></span><p>如果做了 <code>L2</code> 归一化，那么余弦相似度可以直接写成点积：</p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>s</mi><mo stretchy="false">(</mo><mi>q</mi><mo separator="true">,</mo><msub><mi>d</mi><mi>i</mi></msub><mo stretchy="false">)</mo><mo>=</mo><msup><mi>q</mi><mi mathvariant="normal">⊤</mi></msup><msub><mi>d</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">s(q,d_i)=q^\top d_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">s</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.0935em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">⊤</span></span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span><p>向量检索做的事，就是找到相似度最高的前 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi></mrow><annotation encoding="application/x-tex">k</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> 个文档块：</p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mrow><mi mathvariant="normal">TopK</mi><mo>⁡</mo></mrow><msub><mi>d</mi><mi>i</mi></msub></msub><mtext> </mtext><mi>s</mi><mo stretchy="false">(</mo><mi>q</mi><mo separator="true">,</mo><msub><mi>d</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\operatorname{TopK}_{d_i} \ s(q,d_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0942em;vertical-align:-0.3442em;"></span><span class="mop"><span class="mop"><span class="mord mathrm">TopK</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3281em;"><span style="top:-2.357em;margin-left:0em;margin-right:0.0714em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3442em;"><span></span></span></span></span></span></span><span class="mspace"> </span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">s</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span><p>公式很干净，真实语料却从来不干净。文档里有重复段落、模板文本、版本差异、广告噪音、短句标题、长表格、代码片段、跨语言内容、过时内容和权限边界。查询也不总是长得像文档。它可能是口语化问题、错误术语、隐含需求，甚至只是一个不完整的任务指令。</p><p>RAG 的难点不在于“接一个向量数据库就能检索”。真正难的是：<strong>embedding 空间是否真的把任务所需的语义关系组织出来了。</strong></p><p>检索基础设施也不该停在“把 Query 丢给向量库，再返回 Top-K”。开发者需要知道哪些内容被召回、哪些内容被漏掉、噪声来自切块还是数据源、错误样本是否成簇，以及业务边界有没有进入向量空间。只有这些问题能被看见，召回过程才算得上可诊断、可干预。</p><p>可视化的作用，就是给这个问题一个观察窗口。</p><h2 id="Embedding-Atlas-更适合拿来做诊断"><a href="#Embedding-Atlas-更适合拿来做诊断" class="headerlink" title="Embedding Atlas 更适合拿来做诊断"></a>Embedding Atlas 更适合拿来做诊断</h2><p><a class="link"   href="https://apple.github.io/embedding-atlas/" >Embedding Atlas<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是 Apple 开源的 embedding 可视化工具。它可以作为命令行工具使用，也可以嵌入 Notebook 或 Streamlit；当前 PyPI 版本为 <code>0.20.0</code>，要求 Python <code>&gt;=3.11</code>。</p><p>最小启动方式很直接：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pip install embedding-atlas</span><br><span class="line">embedding-atlas path_to_dataset.parquet</span><br></pre></td></tr></table></figure></div><p>如果你已经提前算好了高维 embedding，可以指定向量列：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">embedding-atlas path_to_dataset.parquet --vector embedding_vectors</span><br></pre></td></tr></table></figure></div><p>如果你已经提前算好了二维投影，也可以直接指定坐标列：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">embedding-atlas path_to_dataset.parquet --x projection_x --y projection_y</span><br></pre></td></tr></table></figure></div><p>它也支持从 Hugging Face dataset 读取数据，还可以提供预计算 nearest neighbors。后者对 RAG 诊断尤其有用，因为我们不只想看点在二维图上的位置，也想知道每个点在原始向量空间里真正的邻居是谁。</p><p>这就是 Embedding Atlas 和普通静态散点图的差异。静态图最多告诉你“这批点大概分成几团”；交互界面还能让你继续往下问：</p><ul><li>这一团里具体是什么文本？</li><li>换成按来源、标签、时间、chunk 长度、召回结果着色后，结构还成立吗？</li><li>某个错误样本的最近邻到底是谁？</li><li>搜索一个关键词后，命中的点是分散的，还是集中在某个区域？</li><li>某类 metadata 是否正在污染一个邻域？</li><li>query 和它应该命中的 document 是否真的处在同一个局部空间里？</li></ul><p>这些问题靠一张图回答不了。它们需要把 embedding 空间、原始文本和 metadata 绑在一起看。</p><h2 id="相关研究与工具脉络"><a href="#相关研究与工具脉络" class="headerlink" title="相关研究与工具脉络"></a>相关研究与工具脉络</h2><p>把 embedding 投影成一张可浏览地图，并不是 Embedding Atlas 才有的想法。<a class="link"   href="https://projector.tensorflow.org/" >TensorFlow Embedding Projector<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 很早就把 PCA、t-SNE、UMAP 和 metadata 过滤做成了交互式界面；<a class="link"   href="https://home.nomic.ai/blog/posts/data-mapping" >Nomic Atlas 的 data mapping 系列<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 也一直在讲，非结构化数据地图不只是装饰，它本身就是探索和治理数据的界面。</p><p>Embedding Atlas 的增量，更像是把这条路线拉回开发者日常。它不只关心投影算法，也关心大规模点云、密度聚类、自动标签，以及能不能低成本接进现有数据工作流。换句话说，它把 embedding 可视化从“偶尔做一张分析图”，推向了“随手打开一批向量看一看”。</p><p>RAG 方向也有类似的工具脉络。<a class="link"   href="https://arize.com/docs/phoenix/retrieval/overview-retrieval" >Arize Phoenix<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 把 retrieval troubleshooting、trace、eval 和 UMAP 视图连在一起，用来分析坏响应聚类、无近邻查询和检索相关性。<a class="link"   href="https://github.com/Renumics/renumics-rag" >Renumics RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 及其文章 <a class="link"   href="https://medium.com/data-science/visualize-your-rag-data-evaluate-your-retrieval-augmented-generation-system-with-ragas-fc2486308557" >Visualize your RAG Data<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，则把问题、文档片段和 RAGAS 分数放进同一个 UMAP 视图里。再往 RAG 系统内部看，<a class="link"   href="https://arxiv.org/abs/2411.01751" >RAGViz<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 关注 token 与 document 层面的注意力可视化，<a class="link"   href="https://arxiv.org/abs/2601.12991" >RAGExplorer<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则把不同 RAG 配置放在一起做对比诊断。</p><p>所以，“可视化 RAG”不是一件事，至少可以拆成三层。第一层是 embedding 空间可视化，看 query、document、metadata 和错误样本的分布；第二层是检索链路可观测性，看 trace、检索结果和上下文相关性；第三层是生成过程可视化，看模型在生成时到底注意了哪些文档。本文主要讨论第一层，但它最好不要和后两层割裂开。</p><h2 id="从向量到图：可视化背后的几层结构"><a href="#从向量到图：可视化背后的几层结构" class="headerlink" title="从向量到图：可视化背后的几层结构"></a>从向量到图：可视化背后的几层结构</h2><p>Embedding 可视化通常会经历四层转换：高维向量、近邻图、二维投影和可解释标签。</p><p>第一层是高维向量。embedding 模型把文本、图片或其他对象映射成向量。这里的距离不是普通空间里的物理距离，而是模型学到的表示关系。它可能捕捉主题、实体、语气、格式、语言、来源，也可能把一些对业务没那么重要的表面特征放大。</p><p>第二层是近邻图。对每个点找到 top-k 近邻，就能得到一张图：</p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>G</mi><mo>=</mo><mo stretchy="false">(</mo><mi>V</mi><mo separator="true">,</mo><mi>E</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">G=(V,E)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal">G</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.2222em;">V</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mclose">)</span></span></span></span></span><p>其中每个样本是节点，足够相近的样本之间连边。RAG 的很多现象其实更适合放在这张图上理解：重复内容会形成密集团，孤立知识会变成边缘点，跨主题污染会表现为不该出现的桥接边，语义混淆会表现为两个业务类别在近邻图里纠缠。</p><p>第三层是二维投影。UMAP、t-SNE、PCA 等方法把高维点压到二维，方便人眼观察。Embedding Atlas 文档中提到可以基于已有向量计算 UMAP，也可以直接读取预计算的二维坐标。<a class="link"   href="https://arxiv.org/abs/1802.03426" >UMAP<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 的直觉是尽量保留局部邻域结构，让高维空间里相近的点在二维图里仍然相近。它适合观察局部团块、桥接区域和离群点。</p><p>第四层是标签与 metadata。没有 metadata 的 embedding 图很容易变成“看起来挺有结构”的幻觉。只有把来源、类别、时间、文档类型、chunk 长度、召回次数、人工标注、错误类型这些字段叠上去，空间结构才开始变成诊断线索。</p><p>我更倾向于把 RAG 的观察流程画成这样：</p><pre class="mermaid">flowchart LR    A["文档与查询样本"] --> B["chunk 与清洗"]    B --> C["embedding 向量"]    C --> D["近邻图 / UMAP 投影"]    D --> E["Embedding Atlas 交互分析"]    M["metadata<br/>来源 · 类型 · 时间 · 标签 · 错误样本"] --> E    E --> F["RAG 诊断<br/>召回 · 覆盖 · 混淆 · 数据质量"]</pre><p>在这里，可视化不是最后拿来展示的图，而是夹在数据构建和系统评估之间的诊断层。</p><h2 id="第一种诊断：query-和正确文档有没有靠近"><a href="#第一种诊断：query-和正确文档有没有靠近" class="headerlink" title="第一种诊断：query 和正确文档有没有靠近"></a>第一种诊断：query 和正确文档有没有靠近</h2><p>最直接的 RAG 诊断，是把评测集里的 query 也放进同一个 embedding 空间。</p><p>如果一个问题有人工标注的正确文档，或者有点击、采纳、引用等弱监督信号，就可以把 query 和 positive document 同时可视化。理想情况下，query 应该靠近它的 positive document，至少应该进入同一个局部邻域。</p><p>一旦它们没有靠近，就值得停下来读原文。</p><p>有时问题出在 query-document mismatch。用户说的是任务语言，文档写的是说明书语言。比如用户问“为什么这里一直超时”，文档写的是“默认请求等待时间为 30 秒”。两者语义相关，但字面表达不近。这时可能需要 query rewriting、HyDE、领域微调 embedding，或者在索引里加入 FAQ 式标题。</p><p>有时问题出在 chunk。正确答案跨越多个段落，但切分后每个 chunk 都只保留了局部信息，导致单个 chunk 和 query 都不够近。这时问题不在向量库，而在 chunk 策略。可视化时你会看到同一文档的多个 chunk 分散在不同区域，或者 query 落在几个相关 chunk 的中间，却没有任何一个 chunk 足够接近。</p><p>还有一些时候，是 embedding 模型本身没有对齐任务。通用 embedding 可能更擅长主题相似，而你的 RAG 任务需要区分因果、步骤、API 约束、错误码、权限边界或版本差异。图上看起来“主题差不多”的内容挤在一起，但真正应该召回的操作性文档并不突出。</p><p>这种诊断会把抽象的 recall failure 变成一个能观察的问题：query 是落错团了，落在团边界，还是正确团内部本身就很混乱？</p><h2 id="第二种诊断：错误召回是否成簇"><a href="#第二种诊断：错误召回是否成簇" class="headerlink" title="第二种诊断：错误召回是否成簇"></a>第二种诊断：错误召回是否成簇</h2><p>单个错误案例通常不够说明问题。一个 query 没召回正确文档，可能只是偶然；但如果许多错误召回聚成一团，就说明系统在稳定地犯同一种错。</p><p>比如一个企业内部知识库里，同时有“报销流程”“合同审批”“采购申请”“付款申请”。这些文档都会出现申请、审批、金额、发票、负责人等词。通用 embedding 很容易把它们放到同一个大团里。RAG 一旦遇到“怎么申请付款”这类问题，就可能召回报销流程或采购审批。</p><p>如果只看线上日志，这些错误会散落在不同 query 下，很难形成直觉。放到 embedding 图里，它们会呈现为一个混杂区域：不同业务类型的 chunk 互相穿插，错误召回边大量跨越业务标签。</p><p>这时可以考虑几种改法：</p><ul><li>在 chunk 前增加业务域标题，让向量包含更明确的上下文；</li><li>把检索拆成两段：先做 domain routing，再在域内向量检索；</li><li>引入 metadata filter，例如部门、文档类型、产品线、版本；</li><li>对容易混淆的类别构造 hard negatives，微调 embedding 或 reranker；</li><li>用 reranker 补充向量检索无法区分的细粒度约束。</li></ul><p>但这里不要太急着“看到混在一起就改模型”。有些混合只是主题相近，并不一定错；有些混合才说明业务边界被破坏。可视化只提供线索，最后还是要回到评测样本和业务语义里确认。</p><h2 id="第三种诊断：长尾知识是否变成孤岛"><a href="#第三种诊断：长尾知识是否变成孤岛" class="headerlink" title="第三种诊断：长尾知识是否变成孤岛"></a>第三种诊断：长尾知识是否变成孤岛</h2><p>RAG 的一个常见目标，是让模型能利用长尾知识：冷门功能、旧版本说明、少见错误码、低频客户问题、内部流程细节。麻烦在于，长尾知识在 embedding 空间里经常表现为孤岛。</p><p>孤岛不一定是坏事。某些内容本来就特殊，应该远离主团。但如果一个孤岛里的内容经常被问到，却很少被召回，那就说明系统对它的可达性不好。</p><p>在 Embedding Atlas 里，可以把点按访问频率、召回频率、人工问题覆盖情况或线上失败率着色。这样会看到几种不同形态：</p><ul><li>高频访问区域：应该被重点维护，错误会带来高影响；</li><li>低频但高价值孤岛：需要评测集专门覆盖，不能被平均指标淹没；</li><li>完全无人访问的孤岛：可能是冷知识，也可能是过时、重复或噪音；</li><li>位于主团边缘的桥接点：常常是跨主题文档，既可能提供连接，也可能制造误召回。</li></ul><p>这会改变我们理解 RAG 评估的方式。平均 recall@k 只能告诉你总体召回率，空间视角会提醒你：错误不是均匀分布的。系统可能在主流问题上表现很好，却系统性忽略边缘区域。</p><h2 id="第四种诊断：chunk-是过碎、过粗，还是带错上下文"><a href="#第四种诊断：chunk-是过碎、过粗，还是带错上下文" class="headerlink" title="第四种诊断：chunk 是过碎、过粗，还是带错上下文"></a>第四种诊断：chunk 是过碎、过粗，还是带错上下文</h2><p>RAG 里最容易被低估的是 chunk。切分策略不只是文本预处理，它直接决定 embedding 空间里的基本单位。</p><p>chunk 过碎时，很多点会变成语义残片。它们可能只有半个步骤、一句定义、一个表格行或一个代码片段。这样的点在空间里很容易被表面词吸走，靠近一些并不真正回答问题的内容。</p><p>chunk 过粗时，另一个问题会出现：一个点内部同时包含多个主题。它可能在二维图上处在几个团之间，成为“桥”。这种桥有时能帮助跨主题召回，但也可能把不相关邻域连起来，造成误召回。</p><p>还有一种更隐蔽的情况：chunk 本身不算短，但缺少标题、路径、产品名、版本号等上下文。比如“点击设置后选择高级选项”这句话本身没有说明属于哪个产品、哪个页面、哪个版本。embedding 只看 chunk 内容时，很可能把不同产品的相似步骤混在一起。</p><p>分析 chunk 时不应该只看长度分布，还应该在可视化里叠加几个字段：</p><ul><li><code>chunk_length</code>：过短点是否集中在噪音区域；</li><li><code>document_id</code>：同一文档的 chunk 是否被过度打散；</li><li><code>section_title</code>：标题是否帮助 chunk 聚回正确主题；</li><li><code>source</code>：某些来源是否形成异常团块；</li><li><code>version</code>：新旧版本是否被混在同一邻域。</li></ul><p>如果同一篇文档的 chunk 在空间里完全散开，不一定是错，因为文档可能本来就多主题。但如果某些重要文档的答案段落被打散到无法被 query 命中，就应该重新考虑切分、标题注入或父子 chunk 检索。</p><h2 id="第五种诊断：数据质量问题会在空间里显形"><a href="#第五种诊断：数据质量问题会在空间里显形" class="headerlink" title="第五种诊断：数据质量问题会在空间里显形"></a>第五种诊断：数据质量问题会在空间里显形</h2><p>Embedding 空间也能暴露数据清洗问题。</p><p>重复文本会形成极密集的小团。模板化页面会因为共享页眉、页脚、导航文案而靠近。机器翻译或 OCR 噪音可能形成奇怪的边缘区域。过时文档可能和新文档高度相似，却在 metadata 上属于不同版本。爬虫抓到的错误页、登录页、目录页也可能形成明显团块。</p><p>这些问题对 RAG 的影响很现实。重复内容会浪费 top-k 名额；模板文本会污染相似度；旧版本文档会和新版本竞争召回；目录页会因为关键词覆盖广而被误召回；错误页一旦进入上下文，模型就可能顺着它生成错误答案。</p><p>如果把数据来源、爬取时间、文档类型和版本叠加到 embedding 图上，很多清洗问题会比在表格里更早暴露。你可能会发现：</p><ul><li>某个来源形成一个巨大但内容低价值的团；</li><li>不同版本的同一文档几乎重叠；</li><li>空白页、错误页和导航页聚成一小团；</li><li>某些高召回 chunk 其实只是模板文本；</li><li>大量短 chunk 被标题或固定话术主导。</li></ul><p>这时 Embedding Atlas 更像数据体检工具，而不只是 RAG 调参工具。它能帮你决定哪些内容该去重、降权、过滤、重切或补充 metadata。</p><h2 id="可视化如何进入一个严肃的-RAG-评估流程"><a href="#可视化如何进入一个严肃的-RAG-评估流程" class="headerlink" title="可视化如何进入一个严肃的 RAG 评估流程"></a>可视化如何进入一个严肃的 RAG 评估流程</h2><p>可视化最大的风险，是让人过度相信图像。二维投影很有说服力，但它不是高维空间本身。UMAP 和 t-SNE 都会为了保留某些结构而牺牲另一些结构。图上两个团离得远，不一定代表它们在原始向量空间也远；图上看起来分开，也不代表检索时不会互相命中。</p><p>所以 embedding 可视化不应该替代指标，而应该和指标形成循环。<a class="link"   href="https://arxiv.org/abs/2104.08663" >BEIR<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://arxiv.org/abs/2210.07316" >MTEB<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 提醒我们，检索和 embedding 需要跨任务评估；<a class="link"   href="https://arxiv.org/abs/2309.15217" >RAGAS<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 进一步把 RAG 拆成 context、faithfulness、answer quality 等维度；<a class="link"   href="https://arxiv.org/abs/2405.07437" >RAG 评估综述<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和中文基准 <a class="link"   href="https://arxiv.org/abs/2401.17043" >CRUD-RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 则说明，retriever、context length、knowledge base construction 和 LLM 本身都会影响结果。</p><pre class="mermaid">flowchart LR    A["离线评测集"] --> B["检索指标<br/>recall@k · MRR · nDCG"]    B --> C["错误样本集合"]    C --> D["Embedding Atlas 可视化"]    D --> E["形成诊断假设"]    E --> F["修改数据 / chunk / embedding / reranker"]    F --> B    G["人工抽检与线上反馈"] --> C</pre><p>在这个循环里，指标回答“有没有变好”，可视化回答“为什么可能变好或变坏”。这两个问题都不能省。</p><p>一个实用流程可以是：</p><ol><li>准备一批 query、positive document、negative document 和线上错误样本；</li><li>把 query 与 document chunk 放入同一个数据表；</li><li>加入字段：<code>type</code>、<code>source</code>、<code>doc_id</code>、<code>section</code>、<code>chunk_length</code>、<code>label</code>、<code>retrieval_result</code>、<code>error_type</code>；</li><li>计算 embedding，并保留向量列；</li><li>用 Embedding Atlas 打开数据，按不同 metadata 着色和过滤；</li><li>对错误区域抽样阅读原文，形成具体假设；</li><li>修改 chunk、metadata filter、reranker 或 embedding 策略；</li><li>回到离线指标和人工评测验证。</li></ol><p>这里最重要的是第 6 步。可视化只能让你找到“值得读的地方”，不能替你判断原因。真正的诊断还是要回到原文、任务和用户意图。</p><h2 id="嵌入可视化带来的理解变化"><a href="#嵌入可视化带来的理解变化" class="headerlink" title="嵌入可视化带来的理解变化"></a>嵌入可视化带来的理解变化</h2><p>我觉得 embedding 可视化最有趣的地方，是它会改变我们对 RAG 的直觉。</p><p>第一，它让“知识库”从文件集合变成了几何对象。过去我们说知识库质量，常常想到文档完整不完整、格式干不干净、有没有更新。可视化之后，你会开始问：这些知识在空间里是否有好的覆盖？哪些区域过密，哪些区域空洞？哪些边界模糊，哪些孤岛没人能到达？</p><p>第二，它让“召回错误”从个案变成结构。一个错误 query 可能只是偶然，一片错误区域则说明系统有稳定偏差。RAG 优化不应该只追逐个别 bad case，而应该找到错误的空间模式。</p><p>第三，它让“embedding 模型好不好”变得更具体。不是抽象地说某个模型分数更高，而是看它有没有把你的任务边界表达出来。对客服 RAG，产品线边界可能很重要；对论文 RAG，方法、任务和数据集之间的关系可能更重要；对代码 RAG，API 名称、调用约束和版本差异可能比主题相似更重要。</p><p>第四，它提醒我们 RAG 不只是检索算法，也是数据设计。很多检索问题最后不是换 ANN 索引解决的，而是通过数据清洗、chunk 重构、标题注入、metadata filter、分层路由和 hard negative 训练解决的。</p><p>所以我会关注 Embedding Atlas 这样的工具。它把 embedding 从一个藏在向量数据库里的中间产物，变成了可以被观察、讨论和改造的工程对象。</p><h2 id="但不要把图当成答案"><a href="#但不要把图当成答案" class="headerlink" title="但不要把图当成答案"></a>但不要把图当成答案</h2><p>最后还是要把边界讲清楚：不要把图当成答案。</p><p>二维投影不是原始高维空间。可视化里的团块不自动等于真实类别，离群点不自动等于坏数据，混在一起也不自动等于错误。UMAP 的参数、采样方式、归一化、向量模型、metadata 选择，都会影响你看到的图。</p><p>可视化更适合做三件事：</p><ul><li>发现异常区域；</li><li>形成诊断假设；</li><li>选择人工抽检样本。</li></ul><p>它不适合单独做最终结论。最终仍要看 recall@k、MRR、nDCG、answer correctness、context precision、faithfulness、人工偏好、线上点击、用户反馈和业务成本。中文实践文章里也有类似提醒：比如 <a class="link"   href="https://jimmysong.io/book/ai-handbook/rag/observability/" >RAG 可观测性<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 会把检索指标、语义质量、日志和 trace 放在一起讨论，而不是只看二维图。</p><p>Embedding Atlas 提供的是一种可观察性。它不会自动让 RAG 变好，也不会替你决定该换模型、换 chunk，还是加 reranker。但它会让 RAG 的一部分失败从黑盒里浮出来：哪些是模型问题，哪些是 chunk 问题，哪些是数据问题，哪些是业务边界没有进入向量空间。</p><p>当我们说“更好的 RAG”时，不应该只想到更大的生成模型、更强的 reranker 或更复杂的 agent。很多时候，更好的 RAG 来自几件更朴素的事：知道自己的语料长什么样，查询落在哪里，错误如何成簇，长尾知识有没有被覆盖。</p><p>Embedding 可视化的意义就在这里。它不替系统做决定，但它让我们终于能观察向量空间本身。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><strong>项目与官方文档</strong></p><ul><li><a class="link"   href="https://github.com/apple/embedding-atlas" >apple&#x2F;embedding-atlas<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://apple.github.io/embedding-atlas/" >Embedding Atlas Documentation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://pypi.org/project/embedding-atlas/" >Embedding Atlas PyPI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://projector.tensorflow.org/" >TensorFlow Embedding Projector<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://home.nomic.ai/blog/posts/data-mapping" >Nomic Atlas Data Mapping<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><p><strong>论文与基准</strong></p><ul><li><a class="link"   href="https://arxiv.org/abs/2505.06386" >Embedding Atlas: Low-Friction, Interactive Embedding Visualization<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/1802.03426" >UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2005.11401" >Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2004.04906" >Dense Passage Retrieval for Open-Domain Question Answering<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2104.08663" >BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2210.07316" >MTEB: Massive Text Embedding Benchmark<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2309.15217" >Ragas: Automated Evaluation of Retrieval Augmented Generation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2405.07437" >Evaluation of Retrieval-Augmented Generation: A Survey<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2401.17043" >CRUD-RAG: A Comprehensive Chinese Benchmark for Retrieval-Augmented Generation of Large Language Models<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2411.01751" >RAGViz: Diagnose and Visualize Retrieval-Augmented Generation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://arxiv.org/abs/2601.12991" >RAGExplorer: A Visual Analytics System for the Comparative Diagnosis of RAG Systems<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><p><strong>工具实践</strong></p><ul><li><a class="link"   href="https://arize.com/docs/phoenix/retrieval/overview-retrieval" >Arize Phoenix Retrieval Overview<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://github.com/Renumics/renumics-rag" >Renumics RAG<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://medium.com/data-science/visualize-your-rag-data-evaluate-your-retrieval-augmented-generation-system-with-ragas-fc2486308557" >Visualize your RAG Data: Evaluate your Retrieval-Augmented Generation System with Ragas<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul><p><strong>中文实践与译介</strong></p><ul><li><a class="link"   href="https://blog.csdn.net/deephub/article/details/136094642" >使用 UMAP 降维可视化 RAG 嵌入<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://llamaindex.org.cn/blog/evaluating-the-ideal-chunk-size-for-a-rag-system-using-llamaindex-6207e5d3fec5" >RAG 分块大小指南：找到最佳设置<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://jimmysong.io/book/ai-handbook/rag/observability/" >RAG 的可观测性：如何监控检索增强生成系统<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/05/29/embedding-atlas-rag-embedding-visualization/</id>
    <link href="https://hyacehila.github.io/blog/2026/05/29/embedding-atlas-rag-embedding-visualization/"/>
    <published>2026-05-29T04:00:00.000Z</published>
    <summary>Embedding visualization is not just a pretty UMAP plot; it is a diagnostic layer for RAG retrieval, coverage, chunking, confusion, and data quality.</summary>
    <title>Embedding Atlas: Visualizing Embedding Spaces for Better RAG</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Systems" scheme="https://hyacehila.github.io/categories/agent-systems/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Tool Use" scheme="https://hyacehila.github.io/tags/Tool-Use/"/>
    <category term="Software Engineering" scheme="https://hyacehila.github.io/tags/Software-Engineering/"/>
    <content>
      <![CDATA[<p>CLI 在 Agent 时代重新成了一种受关注的交互方式。</p><p>这有点反直觉。过去十几年，开发工具的大方向一直是把复杂命令藏进界面里：Vim、Emacs 之后有 VS Code、JetBrains，<code>git</code> 命令之外也有 diff 面板、分支图和冲突解决器。我们花了很长时间，把写代码从黑框里搬进编辑器，还顺手补上了插件、调试器和重构工具。</p><p>可 Agentic Coding 起来之后，第一批跑得起来、也足够好用的工具，又大多从终端长出来。Claude Code、Codex、Aider、OpenCode、Hermes、Openclaw 这些编码或通用 Agent，最早的使用方式几乎都是一行命令。</p><p>我不觉得这是倒退。现阶段把 Coding Agent 放在 CLI 里很合理，后面会展开。但另一个问题也绕不开：CLI 是眼下顺手，还是未来也应该一直这样？</p><p>所以先从一套我觉得够用的终端工具链说起。它能解释为什么 CLI 现在舒服；后半段再谈我更关心的问题：当人的工作从写代码变成 review 和编排，承载它的到底应该是 CLI 还是 GUI。</p><p>我现在常用的是下面这套组合，各自负责的事很清楚。</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin:28px 0 34px;">  <div style="border:1px solid #e5e7eb;border-radius:14px;padding:18px 16px;background:#fafafa;min-height:190px;display:flex;flex-direction:column;align-items:center;text-align:center;">    <div style="height:56px;display:flex;align-items:center;justify-content:center;margin-bottom:10px;font-size:34px;line-height:1;">🌿</div>    <strong style="display:block;min-height:30px;font-size:1.08em;line-height:1.3;">git worktree</strong>    <p style="margin:10px 0 0;color:#555;font-size:0.95em;line-height:1.55;">让每个 Agent / 分支 / 实验拥有独立目录。</p>  </div>  <div style="border:1px solid #e5e7eb;border-radius:14px;padding:18px 16px;background:#fafafa;min-height:190px;display:flex;flex-direction:column;align-items:center;text-align:center;">    <div style="height:56px;display:flex;align-items:center;justify-content:center;margin-bottom:10px;"><img                       lazyload                     src="/images/loading.svg"                     data-src="https://raw.githubusercontent.com/ghostty-org/website/main/public/ghostty-logo.svg"                      alt="Ghostty official logo" style="width:42px;height:42px;object-fit:contain;"                ></div>    <strong style="display:block;min-height:30px;font-size:1.08em;line-height:1.3;">Ghostty</strong>    <p style="margin:10px 0 0;color:#555;font-size:0.95em;line-height:1.55;">负责字体、主题、响应速度和长期终端观感。</p>  </div>  <div style="border:1px solid #e5e7eb;border-radius:14px;padding:18px 16px;background:#fafafa;min-height:190px;display:flex;flex-direction:column;align-items:center;text-align:center;">    <div style="height:56px;display:flex;align-items:center;justify-content:center;margin-bottom:10px;"><img                       lazyload                     src="/images/loading.svg"                     data-src="https://zellij.dev/img/logo.png"                      alt="Zellij official logo" style="width:42px;height:42px;object-fit:contain;"                ></div>    <strong style="display:block;min-height:30px;font-size:1.08em;line-height:1.3;">Zellij</strong>    <p style="margin:10px 0 0;color:#555;font-size:0.95em;line-height:1.55;">把 Agent、测试、服务和日志整理成 workspace。</p>  </div>  <div style="border:1px solid #e5e7eb;border-radius:14px;padding:18px 16px;background:#fafafa;min-height:190px;display:flex;flex-direction:column;align-items:center;text-align:center;">    <div style="height:56px;display:flex;align-items:center;justify-content:center;margin-bottom:10px;"><img                       lazyload                     src="/images/loading.svg"                     data-src="https://neovim.io/logos/neovim-mark.svg"                      alt="Neovim official logo" style="width:42px;height:42px;object-fit:contain;"                ></div>    <strong style="display:block;min-height:30px;font-size:1.08em;line-height:1.3;">Neovim</strong>    <p style="margin:10px 0 0;color:#555;font-size:0.95em;line-height:1.55;">在终端 session 里完成快速编辑和小范围修补。</p>  </div></div><h2 id="一套以终端为中心的-Agentic-Coding-工具链"><a href="#一套以终端为中心的-Agentic-Coding-工具链" class="headerlink" title="一套以终端为中心的 Agentic Coding 工具链"></a>一套以终端为中心的 Agentic Coding 工具链</h2><p>先说工具。如果你已经把 Claude Code、Codex CLI 或 Aider 放进日常，终端体验会突然变得重要：一个 Agent 在跑任务，一个窗口在看测试，一个窗口在启动本地服务，另一个还在对比日志、查 Git 状态、临时改配置，可能还有窗口连着服务器，跑一个时间很长的训练。下面这套组合解决的不是酷炫，而是把「并行任务、终端会话、临时编辑、分支隔离」管住。</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Git worktree   负责代码上下文隔离</span><br><span class="line">Ghostty        负责现代终端窗口体验</span><br><span class="line">Zellij         负责终端 workspace / pane / tab 管理</span><br><span class="line">Neovim         负责终端内快速编辑文件</span><br></pre></td></tr></table></figure></div><p><strong><code>git worktree</code></strong> 是 Git 自带的能力，我觉得在 Agentic Coding 里尤其有用。我们经常会同时在不同分支上调度 AI 工作，再把结果合回来。同一个仓库可以在不同目录下 checkout 不同分支，共享同一份对象数据库，但工作区彼此独立。一个 Agent 在 <code>feature/search</code> 上实现搜索，另一个 Agent 在 <code>fix/login-test</code> 上修测试，主目录仍然保持干净。不用反复 <code>git switch</code>，也不用 clone 多份仓库。Claude Code、Codex、OpenCode 现在基本都内置了 worktree 支持。</p><p><strong>Ghostty</strong> 负责最外层的窗口观感。Agentic Coding 往往意味着长时间盯着流式输出、日志和 diff，字体渲染、滚动、主题、快捷键都会直接影响疲劳感。你当然可以继续用 iTerm2、WezTerm、Windows Terminal 或 Kitty，Mac 自带终端也够用。但如果正好在重整一套以终端为中心的环境，这一层值得考虑。谁不想看得舒服一点呢。</p><p><strong>Zellij</strong> 是个现代化的终端复用器：把窗口切成多个 pane、组织 tab、保存 layout、恢复 session，默认 UI 比传统 <code>tmux</code> 直观。Agent 输出不和测试日志混在一起，本地服务长期挂在一个 pane 里，session 可以恢复，不必每次重新摆窗口。给每个 worktree 一个独立 session 是个顺手的习惯：</p><p><strong>Neovim</strong> 解决「Agent 写了 90%，你只想立刻改一行」的场景。当 Agent 在一个 pane 里跑、测试在另一个 pane 里输出，你不必切回图形编辑器，终端内就能完成快速修补和 review。它更像一把随身小刀，不负责整场开发。</p><p>这套组合不神秘。它只是把 Agent 已经待在终端这件事整理得没那么乱。问题还在后面：这会不会就是最终形态？</p><h2 id="为什么-Agent-时代我们又回到了终端"><a href="#为什么-Agent-时代我们又回到了终端" class="headerlink" title="为什么 Agent 时代我们又回到了终端"></a>为什么 Agent 时代我们又回到了终端</h2><p>要回答 CLI 是不是未来，得先想清楚我们为什么会回到 CLI。</p><p>我的判断是：<strong>CLI 是当下的最优解，但主要因为它短期最省事，而不是因为它本质上更适合人。</strong></p><p>传统开发里，编辑器是为人写代码设计的。光标、补全、边栏文件树、单文件聚焦的编辑视角，都是围绕「一个人逐行敲代码、逐处改 bug」来优化的。这套设计在过去很成功。但 Agentic Coding 改变了人的工作内容：你不再是主要的代码生产者，更像是在调度几个半自动队友。一个 Agent 在实现功能，一个 Agent 在修测试，你自己随时 review diff、补充说明、打断错误方向，同时本地服务、数据库和日志还在旁边跑。</p><p>当人的工作从写变成看与编排，编辑器就有点不合身了。边栏插件挤在一个为单人编码设计的界面里，diff 是给「我刚改的那几行」准备的，不是给「五个 Agent 各自改了一摊」准备的。所以退回终端并不奇怪：CLI 轻、可脚本化，Agent 可以直接寄宿，不需要先迁就一套旧工作方式留下来的 GUI。</p><p>它更像过渡期的应急方案：现有 GUI 不趁手，而终端正好够用、够快、够灵活。但现有 GUI 不趁手，不等于 GUI 这条路走不通。</p><h2 id="CLI-杀死-GUI？"><a href="#CLI-杀死-GUI？" class="headerlink" title="CLI 杀死 GUI？"></a>CLI 杀死 GUI？</h2><p>这几个判断混在一起后，就容易出现 2026 年那波很会传播的口号。从 X 到 YouTube 到小红书，一种时髦口径同时冒出来，最有代表性的是<a class="link"   href="https://cn.ai.cc/blogs/the-app-is-dead-agentic-cli-killed-gui-2026/" >一篇同名檄文<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：</p><blockquote><p>The App Is Dead. Agentic CLI Killed the GUI in 2026.</p></blockquote><p>常见的叙述内容基本有以下几点：</p><ul><li>IDE 边栏插件已死；</li><li>桌面 App 是上一个时代的产物；</li><li>真正的 AI 工程师都在终端里完成所有事情；</li><li>CLI &#x3D; 极客 &#x2F; 高效 &#x2F; 未来，GUI &#x3D; 小白 &#x2F; 低效 &#x2F; 过去。</li></ul><p>这种说法好转发，因为它把工具选择变成身份标签：用 CLI 的是先锋，用 GUI 的是落伍。但看投入方向，事情没那么简单。AI 大厂并没有只押 CLI，它们同样在做桌面端、浏览器插件和 Computer Use。</p><p><strong>Codex</strong> 一边保留 CLI，一边把桌面端和浏览器接入做得更重。它的 <a class="link"   href="https://developers.openai.com/codex/app/chrome-extension" >Chrome 扩展<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>能直接跑在你自己的浏览器 profile 里，复用你已经登录好的会话。访问 Salesforce、Gmail 或内网工具时，只需在 prompt 里用 <code>@Chrome</code> 把任务交给它，登录、cookie、token、二次验证那堆麻烦都省掉了；本地 localhost 的预览与验证则交给内置浏览器，两边互不打扰。Codex App 也在往 ChatGPT 入口里靠。</p><p><strong>Claude Code</strong> 从 2025 年 5 月的 CLI-first，演变成了一个全家桶：CLI、多桌面 App（Mac&#x2F;Windows）、Web 应用和 IDE 扩展。像 fast mode 这类能力，在桌面 App 里点一下就能切换。它没有放弃 CLI，但也显然没把宝全押在 CLI 上。CLI 里的斜杠命令当然还会增加，可一旦切到桌面应用，这些命令就不再是用户必须记住的东西。</p><p>所以我更愿意看投入方向，而不是口号。博主可以喊 CLI 万岁，厂商会把钱投到用户会长期停留的地方。</p><p>再看复杂工作流。最需要 GUI 的，是编排型工作流：一个父需求挂多个子模块，多人各切一片；iOS &#x2F; Android &#x2F; Server &#x2F; Web 多端并发；每端再挂一个或多个 Agent，外加 bug 列表、知识沉淀、子代理调度。这种工作流如果纯 CLI，你每开一个模块、一个端、一个 Agent 都得开一个终端窗口。三个模块乘五个端就是一屏铺满终端，有管理工具也会让人头晕；GUI 至少可以把它们折叠成项目、任务、状态面板和筛选器。</p><p>我不是说终端不能做。只是当业界开始盘点<a class="link"   href="https://www.augmentcode.com/tools/best-ai-coding-agent-desktop-apps" >「2026 最好的 AI 编码 Agent 桌面应用」<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>时，迁移理由和这里很接近：多 Agent 编排需要专门的基础设施，任务时长从「分钟」拉长到「小时」甚至更久，Agent 管理和代码编辑最好各用一套界面。IDE 边栏则很容易把 Agent 困在单一上下文和同步、编辑器内的交互里。这些都不是一个终端窗口适合独自扛下来的。</p><p>GUI 的用处也不是把按钮画漂亮，而是让人看见复杂度，又不被复杂度淹没：多窗口隔离让每个需求互不串线，状态面板让进度、测试状态、子代理输出、bug 列表一屏可见，流式输出推一段显示一段，可以边读边追问，而不是滚屏看完早就忘了上下文。工具越常用，易用性就越要命。CLI 能撑住早期用户，但很难成为所有人的主入口。</p><h2 id="那么，定制-GUI-能不能吞下整套-CLI-工具链？"><a href="#那么，定制-GUI-能不能吞下整套-CLI-工具链？" class="headerlink" title="那么，定制 GUI 能不能吞下整套 CLI 工具链？"></a>那么，定制 GUI 能不能吞下整套 CLI 工具链？</h2><p>回到开头那套终端工具链。</p><p>worktree + Ghostty + Zellij + Neovim，其实是在用四件分散的 CLI 工具，拼出「上下文隔离 + 终端观感 + workspace 管理 + 快速编辑」四种能力。但这四件事，一个为 Agent 定制的 GUI 也可以一并吞下：</p><ul><li>切 worktree？不用敲命令，点两下就切，甚至自动为每个 Agent 建好独立工作区；</li><li>看 diff？直接开一个 diff 面板，而不是依赖零散的 CLI 文本返回；</li><li>多终端？像编辑器那样开多个终端面板，状态各自独立；</li><li>观感？交给设计师定制，大概率比手动美化过的 Ghostty 更耐看、更一致。</li></ul><p>Zellij、Ghostty、Neovim 解决的体验问题，一个像样的 GUI 几乎都能覆盖，而且通常会更顺。</p><p>问题就剩一个：CLI 除了能复用现成命令行工具，还剩多少优势？</p><p>在人和工具交互这件事上，我不觉得还有多少。CLI 现在的优势，很大程度上是生态优势：存量工具都在命令行里，Agent 直接复用很省事。这当然重要。只是这个优势属于工具复用，不属于交互体验。</p><h2 id="可能的分工：CLI-回归工具复用层，GUI-回归人机交互"><a href="#可能的分工：CLI-回归工具复用层，GUI-回归人机交互" class="headerlink" title="可能的分工：CLI 回归工具复用层，GUI 回归人机交互"></a>可能的分工：CLI 回归工具复用层，GUI 回归人机交互</h2><p>把工具复用和人机交互拆开看，CLI 的位置其实在之前讨论 Skills 的时候就出现过。</p><p>我在<a href="/blog/2026/03/10/from-mcp-to-agent-skills/">《从 MCP 到 Agent Skills：为什么 Agent 又需要一种新的上下文工程协议？》</a>里聊过，Skills 是一种很轻的能力封装：一个目录、一份说明、几段脚本和若干参考资料，让模型按需读取。Skills 基本上就是在使用 CLI 来执行这些命令，而非 MCP，从而换取一个灵活编排，他很有存在的价值。</p><p>因此，CLI 最后会更像工具复用层，而不是人的主界面。它会继续和 MCP 竞争「能力怎么交给模型」这个位置，作为 Agent 调用、脚本拼装、能力封装的底座存在。在这一层，CLI 的可组合性是长期优势，没有谁能轻易替代。</p><p>人机交互这一层，则更可能回到 GUI。GUI 本来就是为人看状态、对比差异、点选切换而生的。现在人还要并行监控多个 Agent，这些诉求更适合图形界面。CLI 目前占着人机交互的位置，更多是先顶上来：编辑器还没为「人 review、人编排」这套新工作方式重新设计，而 CLI 恰好够用。一旦专门为 Agent 编排设计的 GUI 成熟起来，人这一侧的交互没有理由一直停在终端。</p><p>两者不是谁杀死谁，而是各归各位。</p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>我们确实又回到了 CLI，但回到终端不等于终点就是终端。</p><p>CLI 是 Agent 时代当下的最优解，这没问题。编辑器为旧的工作方式而设计，在人转向 review 和编排之后有点不合身；CLI 轻、可脚本化，Agent 可以直接寄宿，短期内自然会被拿来当承载层。前面那套 worktree + Ghostty + Zellij + Neovim 的组合，正是这个阶段里很务实的选择，今天用它不亏。</p><p>但厂商的真实投入、编排型工作流的体验上限，还有 Skills 暴露出来的那条线索，都在提醒我：CLI 的长期价值在工具组合与复用，不在人的主交互入口；人机交互这一层，还是会回到为人设计的 GUI。当一个定制 GUI 能点两下切 worktree、开 diff 面板、并排多个终端，并且做得比手动拼起来的 CLI 工具链更好看、更顺手时，CLI 未必还是未来的答案。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a class="link"   href="https://git-scm.com/docs/git-worktree" >Git 官方文档：git-worktree<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://ghostty.org/" >Ghostty 官方网站<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://zellij.dev/" >Zellij 官方网站<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://neovim.io/" >Neovim 官方网站<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://developers.openai.com/codex/app/chrome-extension" >OpenAI Codex 文档：Chrome 扩展<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://www.augmentcode.com/tools/best-ai-coding-agent-desktop-apps" >Augment Code：9 Best AI Coding Agent Desktop Apps in 2026<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a class="link"   href="https://cn.ai.cc/blogs/the-app-is-dead-agentic-cli-killed-gui-2026/" >The App Is Dead: Agentic CLI Killed the GUI in 2026<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li><a href="/blog/2026/03/10/from-mcp-to-agent-skills/">《从 MCP 到 Agent Skills：为什么 Agent 又需要一种新的上下文工程协议？》</a></li><li><a href="/blog/2026/04/07/spec-is-not-the-new-paradigm/">《Spec 不是新范式：Vibe Coding、SDD 与 AI 时代的软件工程转向》</a></li><li><a href="/blog/2026/04/10/how-to-choose-the-right-model-for-developers/">《Claude Code or Codex：编码模型差异如何变成产品体验的不同》</a></li><li><a href="/blog/2026/05/22/agent-browser-tools-comparison/">《让 Agent 操作浏览器：从自动化脚本到浏览器基础设施的演进》</a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/05/27/cli-vs-gui-agent-era/</id>
    <link href="https://hyacehila.github.io/blog/2026/05/27/cli-vs-gui-agent-era/"/>
    <published>2026-05-27T06:00:00.000Z</published>
    <summary>Agentic coding has pushed many developers back to the terminal. The CLI is convenient today because it is light, scriptable, and easy for agents to drive. That does not mean the GUI is dead. This post starts from a terminal-centered workflow and argues that CLI belongs in the tool-composition layer, while review and orchestration will move back to GUI.</summary>
    <title>Back to the CLI: Choosing Between CLI and GUI in the Agent Era</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="MCP" scheme="https://hyacehila.github.io/tags/MCP/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Browser Automation" scheme="https://hyacehila.github.io/tags/Browser-Automation/"/>
    <content>
      <![CDATA[<p>如果把 Codex Chrome extension、Claude in Chrome、Playwright、Chrome DevTools MCP、Browser-Use、Vercel agent-browser、Stagehand、Skyvern、Lightpanda、Browserbase、Steel.dev、MultiOn 这些工具排成一列，很容易写成工具百科：每个工具一小节，讲功能、场景和限制。这样能帮人认名词，但解释不了一个更有意思的问题：这些工具为什么会这样演进？</p><p>让我们按照用户解除的顺序来展开：先看官方宿主如何把真实浏览器、登录态、权限确认和安全边界打包成开箱即用的能力，再让浏览器能被稳定控制，让网页状态能被模型读懂，然后让行动可以缓存、验证和编排，最后把浏览器本身变成可承载的运行时资源。</p><h2 id="浏览器为什么会成为-Agent-基础设施"><a href="#浏览器为什么会成为-Agent-基础设施" class="headerlink" title="浏览器为什么会成为 Agent 基础设施"></a>浏览器为什么会成为 Agent 基础设施</h2><p>很多真实任务没有干净 API。查数据、填表单、登录后台、下载发票、复现前端 bug、检查网络请求、跑性能分析，最后都会回到浏览器里。对人来说，浏览器是视觉界面；对 Agent 来说，浏览器是一堆复杂状态：DOM、无障碍树、截图、网络请求、console 日志、cookie、localStorage、iframe、弹窗、验证码、加载时序和权限边界。</p><p>传统浏览器自动化关心的是程序怎么控制浏览器。Agent 浏览器工具要处理的问题更宽：模型看见什么，怎么决定动作，怎么判断动作是否成功，失败以后怎么恢复，成功经验能不能复用。</p><p>先用一张表把脉络压住：</p><table><thead><tr><th>阶段</th><th>代表工具</th><th>解决的核心瓶颈</th><th>相对上一阶段的变化</th><th>仍然留下的问题</th></tr></thead><tbody><tr><td>官方宿主浏览器桥</td><td>Codex Chrome extension、Claude in Chrome</td><td>登录态复用、权限确认、敏感动作确认、prompt injection 风险和真实浏览器操作</td><td>从“给 Agent 一把浏览器工具”，变成宿主产品直接接入用户已登录的 Chrome，并把安全边界放到产品层</td><td>仍然依赖 UI；结构化 API 和官方 connector 更安全；测试、调试、低 token 表示、工作流和生产化仍需要后续工具</td></tr><tr><td>从人写脚本到 Agent 调用浏览器</td><td>Playwright、Playwright MCP、Chrome DevTools MCP</td><td>把用户操作自动化和 DevTools 调试封装成 Agent 工具</td><td>从开发者写脚本，变成 Agent 能扮演“终端用户”或“前端工程师”</td><td>上下文污染严重，传统自动化与 DevTools 输出仍面向人类测试&#x2F;调试，不是原生面向 Agent 的上下文边界</td></tr><tr><td>从完整网页到 Agent 可读表示</td><td>Vercel agent-browser、Browser-Use</td><td>控制 Agent 能看到什么，而不只是让它能操作浏览器</td><td>对页面状态做语义压缩、引用化和任务相关过滤</td><td>自主探索成本高，执行确定性不足</td></tr><tr><td>从开放探索到工业落地</td><td>Stagehand、Skyvern</td><td>把自主浏览器操作推向可编排、可复用的流程</td><td>Stagehand 走开发者混合接管与缓存自愈，Skyvern 走业务视觉工作流与目标检查</td><td>长流程仍然依赖浏览器会话、代理、回放和生产运维</td></tr><tr><td>从单次操作到生产级运行时</td><td>Lightpanda、Browserbase、Steel.dev、MultiOn</td><td>承载并发、会话、隔离、代理、反爬、成本和 API 化</td><td>浏览器从本地工具变成云端基础设施和可复用运行时</td><td>Chrome 兼容性、权限安全、登录态和风控仍是长期挑战</td></tr></tbody></table><p>重点不在于给工具排座次，而是看它们在改哪一层接口：从宿主官方边界，到页面点击和运行时诊断；从 DOM 解析，到模型可读表示；从自由探索，到缓存和工作流；从单机浏览器，到云端 session 和轻量 runtime。</p><h2 id="第零阶段：官方浏览器桥，先把浏览器交给宿主"><a href="#第零阶段：官方浏览器桥，先把浏览器交给宿主" class="headerlink" title="第零阶段：官方浏览器桥，先把浏览器交给宿主"></a>第零阶段：官方浏览器桥，先把浏览器交给宿主</h2><p>在讨论 Playwright、MCP、agent-browser 或 Browser-Use 之前，今天已经有一类更靠前的选择：由 Agent 宿主自己提供的浏览器桥。它们不是又一层 CDP 封装，也不是让开发者自己维护一套浏览器 session，而是让 Codex 或 Claude 直接接入用户正在使用、已经登录的 Chrome。</p><p><a class="link"   href="https://developers.openai.com/codex/app/chrome-extension" >Codex Chrome extension<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 走的是这个方向。它通过 Codex 插件和 Chrome 扩展连接真实 Chrome profile，让 Codex 可以使用用户已经登录的浏览器状态去操作 Gmail、Salesforce、公司内网或其他需要登录的网页。更重要的是，它把很多过去需要工程师自己补的边界放进了产品层：访问新网站前的域名授权、allowlist 和 blocklist、浏览历史这类高风险能力的显式授权，以及把网页内容当成不可信上下文处理的安全模型。</p><p><a class="link"   href="https://code.claude.com/docs/en/chrome" >Claude in Chrome<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 也类似（他更早一些）。Claude Code 可以通过 <code>claude --chrome</code> 启动，或在会话中使用 <code>/chrome</code> 连接 Chrome 扩展。它复用用户的浏览器登录态，在可见 Chrome 窗口里执行点击、输入、导航和读取页面状态；遇到登录页或 CAPTCHA 这类需要人类介入的场景，会暂停让用户处理。Anthropic 也单独讨论了 <a class="link"   href="https://support.claude.com/en/articles/12902428-using-claude-in-chrome-safely" >Claude in Chrome 的安全使用<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，重点就是 prompt injection、站点权限、敏感动作确认和高风险任务边界。</p><p>所以，如果问题只是“我希望 Agent 打开浏览器，利用我的登录态，替我完成一个网页任务”，这两个官方工具几乎应该是第一优先级。它们把登录态、授权、可见操作、人工接管和安全确认做成了宿主产品的一部分。相比自己拿 Playwright 连 profile、临时跑 CDP、或者把一个通用 browser agent 接进真实账号，它们更像一条被产品化过的道路。</p><p>但这并不意味着浏览器应该变成所有任务的第一选择。浏览器本质上仍然是结构化 API 和官方 connector 适配不完整时的临时中介。只要目标系统有稳定 API、MCP、app connector 或官方集成，优先走这些结构化接口通常更安全、更稳定、更可审计。</p><p>官方浏览器桥解决的是“能不能开箱即用地让 Agent 在我的真实浏览器里干活”。后面的工具解决的是更细的问题：如果要写回归测试，需要 Playwright；如果要诊断前端运行时，需要 Chrome DevTools MCP；如果要压缩网页上下文，需要 agent-browser 或 Browser-Use；如果要把流程做成可复用业务自动化，需要 Stagehand 或 Skyvern；如果要大规模承载 session，就会走向 Browserbase、Steel.dev 或 Lightpanda。</p><h2 id="第一阶段：从人写脚本到-Agent-调用浏览器"><a href="#第一阶段：从人写脚本到-Agent-调用浏览器" class="headerlink" title="第一阶段：从人写脚本到 Agent 调用浏览器"></a>第一阶段：从人写脚本到 Agent 调用浏览器</h2><p>如果把官方宿主浏览器桥看成第零阶段，那么第一阶段的代表是 Playwright、Playwright MCP 和 Chrome DevTools MCP。它们不是典型的自主 Agent 框架，但它们是浏览器 Agent 细分控制和调试工具链的起点。理解它们之间的关系，不能只看谁能点按钮，要先看底层那条线：CDP。</p><p><a class="link"   href="https://chromedevtools.github.io/devtools-protocol/index.html" >Chrome DevTools Protocol<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是 Chrome、Chromium 和其他 Blink-based 浏览器的调试与自动化协议。它把浏览器内部能力拆成 DOM、CSS、Network、Runtime、Debugger、Performance、Tracing、Input、Page 等 domain。Chrome DevTools 自己就在用这套协议，许多浏览器自动化和调试工具也和它有直接或间接关系。</p><p><a class="link"   href="https://playwright.dev/docs/intro" >Playwright<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是现代 Web 自动化的确定性基线。它支持 Chromium、WebKit 和 Firefox，可以打开页面、定位元素、点击、输入、等待网络请求、截图、录制 trace，也能和测试断言、CI、报告系统配合。在 Chromium&#x2F;Chrome 场景里，Playwright 和 CDP 生态血脉相连，也支持通过 CDP 连接已有 Chrome；但它给开发者的不是原始 CDP，而是更高层的 locator、action、auto-wait、trace 和 test API。</p><p>这就是 Playwright 的价值：把底层浏览器协议变成稳定的测试和自动化抽象。只要页面设计相对固定，用 Playwright 做 E2E 测试，就能像真实用户一样穿过整个系统流程，不必每次手写 DOM、Network 或 Runtime 级别的协议调用。</p><p>很多时候，我们确实不需要 Agent 自主理解网页。登录测试、结账流程回归、表单校验、前端改动后的 E2E 检查，成功标准都很明确。用模型自由探索，反而多了一层不确定性。</p><p>Agent 时代的新变化，是这些确定性能力开始通过 MCP 暴露出来。不过 Playwright MCP 和 Chrome DevTools MCP 虽然都站在浏览器自动化&#x2F;调试这条谱系上，却让模型扮演了两个角色。</p><h3 id="同源不同角色：终端用户-vs-前端工程师"><a href="#同源不同角色：终端用户-vs-前端工程师" class="headerlink" title="同源不同角色：终端用户 vs 前端工程师"></a>同源不同角色：终端用户 vs 前端工程师</h3><p><a class="link"   href="https://playwright.dev/mcp/introduction" >Playwright MCP<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>把 Playwright 的自动化能力包装成 MCP Server，让 LLM 可以通过结构化 accessibility snapshot 和元素 ref 操作网页。它把模型当成“终端用户”：页面上有什么按钮、输入框、复选框，下一步该点哪里、填什么、等什么。官方文档也强调，它基于 accessibility snapshot 工作，不需要视觉模型；典型工具包括导航、点击、输入、表单、tab、dialog、storage、network、tracing 等。</p><p>这一步不是让 Playwright 变成完整自主 Agent，而是让浏览器控制能力进入 Agent loop：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">用户目标</span><br><span class="line">  -&gt; 模型判断需要浏览器</span><br><span class="line">  -&gt; 调用 Playwright MCP</span><br><span class="line">  -&gt; 获取页面状态和元素引用</span><br><span class="line">  -&gt; 执行点击、输入、截图、等待等动作</span><br><span class="line">  -&gt; 把结果返回模型继续推理</span><br></pre></td></tr></table></figure></div><p>Chrome DevTools MCP 则把模型当成“前端工程师”。它当然也有 input automation 和 navigation tools，可以点击、输入、导航、截图；但这不是它最有价值的地方。它强在把 DevTools 视角交给 coding agent。</p><p>Google 在 <a class="link"   href="https://developer.chrome.com/blog/chrome-devtools-mcp?hl=en" >Chrome DevTools MCP 发布文章<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>里说得很直接：coding agent 看不到自己写出来的前端代码在浏览器里实际发生了什么。它可以改文件，可以运行命令，但如果没有浏览器反馈，就不知道页面是否白屏、资源是否 404、CORS 是否失败、按钮为什么点不动、LCP 为什么很高。</p><p>根据 <a class="link"   href="https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/tool-reference.md" >Chrome DevTools MCP tool reference<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，它暴露的不只是点击和填表，还包括 console、network、performance trace、Lighthouse、heap snapshot、DOM&#x2F;CSS、页面导航、截图和输入自动化。换句话说，它让 Agent 不只会操作浏览器，还会读 DevTools。</p><h3 id="上下文差异：交互树-vs-运行时证据"><a href="#上下文差异：交互树-vs-运行时证据" class="headerlink" title="上下文差异：交互树 vs 运行时证据"></a>上下文差异：交互树 vs 运行时证据</h3><p>Playwright MCP 给模型的上下文更像页面的可操作语义结构。它会把页面转成 accessibility snapshot，并给交互元素分配 ref。模型看到的是标题、按钮、文本框、复选框和它们的引用，因此更适合做逻辑层面的页面操作：登录、填表、点击下一步、抓取肉眼可见的数据。</p><p>Chrome DevTools MCP 给模型的上下文更像浏览器运行时证据。它适合拿 console 报错、network request、DOM&#x2F;CSS 细节、performance trace、Lighthouse 结果、heap snapshot 来排查原因。它回答的不是下一步点哪里，而是为什么页面现在是这个状态。</p><p>所以，如果希望 AI 自动登录系统、填报表单、抓取页面上可见数据，Playwright MCP 更自然；如果希望 AI 排查 React 内存泄漏、分析页面加载性能、定位 API 请求失败或 CORS 问题，Chrome DevTools MCP 更自然。</p><p>这组工具的问题也在这里。它们让浏览器终于能被 Agent 调用，却仍然把浏览器以“测试工程师”和“前端工程师”的信息形态送进上下文。Playwright MCP 已经用 accessibility snapshot、ref 和无视觉模式做了压缩，但它仍然继承了 E2E 自动化工具的视角。Chrome DevTools MCP 的信息量更大，很多日志、请求、样式、trace 片段只对特定问题有意义；如果没有筛选，模型很容易被低价值细节牵走。</p><p>第一阶段解决了 Agent 能不能使用浏览器工具的问题，没有解决浏览器应该以什么形态进入 Agent 上下文的问题。第二阶段就是从这里开始的。</p><h2 id="第二阶段：从完整网页到-Agent-可读表示"><a href="#第二阶段：从完整网页到-Agent-可读表示" class="headerlink" title="第二阶段：从完整网页到 Agent 可读表示"></a>第二阶段：从完整网页到 Agent 可读表示</h2><p>第二阶段不是为了再封装一层 CDP，也不是给浏览器多加一个操作接口，而是把浏览器状态重新整理成 Agent 可消费的任务上下文。</p><p>Playwright 提供了很强的浏览器控制基座，但如果直接把 Playwright 式浏览器状态交给 AI，会遇到几个问题。</p><p>第一是上下文灾难。真实 Web 应用的 DOM 里有大量布局容器、样式类名、框架状态、hydration 数据、埋点节点和不可见元素；trace、日志、截图、网络信息也会迅速膨胀。人类调试时可以筛选，模型上下文不行。</p><p>第二是状态节奏不同。传统 Playwright 脚本更像一次性运行一段流程，而 Agent 需要看一步、想一步、走一步。它需要浏览器 session 常驻，需要每一步都能读取当前状态，再决定下一步。</p><p>第三是定位脆弱。CSS selector 和 XPath 适合开发者写确定性脚本，但不适合模型在失败后自我修复。一旦 DOM 层级、class name 或组件结构变了，模型很容易陷入一种尴尬状态：知道自己要点哪里，但不知道该怎么定位。</p><p>于是问题变成：如何把 Playwright 能控制的浏览器，变成 Agent 能理解和连续操作的环境？Vercel Labs <code>agent-browser</code> 和 Browser-Use 给出了两条不同路线：一条做文本降维，一条做 Agent 闭环。</p><h3 id="Vercel-agent-browser：文本降维与-CLI-哲学"><a href="#Vercel-agent-browser：文本降维与-CLI-哲学" class="headerlink" title="Vercel agent-browser：文本降维与 CLI 哲学"></a>Vercel agent-browser：文本降维与 CLI 哲学</h3><p>Vercel Labs 的 <a class="link"   href="https://github.com/vercel-labs/agent-browser" >agent-browser<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 代表了轻量化方向。它是面向 AI agents 的浏览器自动化 CLI，通过 Chrome&#x2F;Chromium 的 CDP 工作，核心形态是本地 CLI 加常驻 daemon。常见流程是先用 <code>agent-browser snapshot</code> 拿到带 ref 的 accessibility tree，再用 <code>agent-browser click @e2</code>、<code>fill @e3</code> 这类短命令完成动作。</p><p>这套设计首先考虑的是 <code>context budget</code>。模型不需要读完整 DOM，也不需要看截图，只要看到页面上有哪些标题、链接、按钮、输入框，以及这些元素对应的 ref。对终端里的 coding agent 来说，页面状态被压缩成短文本，动作也被压缩成短引用。</p><p>一个典型快照大概是这样：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- heading &quot;Example Domain&quot; [ref=e1]</span><br><span class="line">- link &quot;More information...&quot; [ref=e2]</span><br></pre></td></tr></table></figure></div><p>模型不需要生成复杂 selector，只要输出：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">agent-browser click @e2</span><br></pre></td></tr></table></figure></div><p>这种 ref-based 操作改变了 Agent 和网页之间的接口。过去模型可能要生成 selector：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">click(&quot;button.submit.primary:nth-child(2)&quot;)</span><br></pre></td></tr></table></figure></div><p>现在它只需要选择一个语义节点：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">click @e2</span><br></pre></td></tr></table></figure></div><p>这一步看似很小，但对 token 成本和动作稳定性影响很大。Agent 不再需要在一堆 CSS 类名里猜测哪个 selector 最合适，而是基于无障碍语义和引用 ID 操作页面。</p><p>CLI 形态也很关键。<code>agent-browser</code> 更像一个可以被 Claude Code、Cursor、Codex 这类工具调用的终端能力，而不是完整的 autonomous browser agent。浏览器在 daemon 里保持会话状态，AI 可以像敲 shell 命令一样逐步探索网页；如果 AI 卡住，人类也可以直接在同一个终端里接管命令，帮它点过某一步，再让它继续。</p><p>这条路线可以概括为“降维”：把浏览器从复杂 DOM、trace 和 DevTools 面板，降成一组很短的文本快照和动作命令。它适合 coding agent 做轻量页面检查、资料查阅、功能验证和局部交互。边界也清楚：<code>agent-browser</code> 解决低 token 控制和终端可接管，不负责完整任务规划。它让模型更便宜地操作网页，但它自己不是 Web Agent 大脑。</p><h3 id="Browser-Use：把浏览器组织成-Agent-环境"><a href="#Browser-Use：把浏览器组织成-Agent-环境" class="headerlink" title="Browser-Use：把浏览器组织成 Agent 环境"></a>Browser-Use：把浏览器组织成 Agent 环境</h3><p>Browser-Use 走的是另一条路线。<a class="link"   href="https://github.com/browser-use/browser-use" >browser-use<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 的定位是让网站可以被 AI agents 使用。它关心的不只是页面快照，而是把浏览器包装成模型可以循环观察、推理、行动、检查结果的环境。模型面对的不是一段固定脚本，而是一个目标和不断变化的网页状态。</p><p>这类框架把浏览器变成 Agent environment：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">观察页面</span><br><span class="line">  -&gt; 推理和规划下一步</span><br><span class="line">  -&gt; 执行动作</span><br><span class="line">  -&gt; 读取页面结果</span><br><span class="line">  -&gt; 判断任务是否完成或是否需要重试</span><br></pre></td></tr></table></figure></div><p>这和 <code>agent-browser</code> 的区别很大。<code>agent-browser</code> 是一把锋利的命令行工具，模型需要自己决定如何把多步任务组织起来；Browser-Use 更像浏览器任务框架，把观察空间、动作空间、状态摘要和任务循环放到一起。它可以结合 DOM&#x2F;HTML 状态、可交互元素，必要时使用截图或视觉信息，帮助模型围绕自然语言目标持续推进。</p><p>相对 Playwright，Browser-Use 的进步不是换一种点击方式，而是改变任务形态。Playwright 执行的是开发者提前写好的流程；Browser-Use 面对的是“帮我完成这个网页任务”这种开放目标。模型不再只是调用固定脚本，而是在页面状态中循环决策。</p><p>它也可以融合视觉理解，让 VLM 辅助理解页面结构，而不是完全依赖 DOM。更准确地说，Browser-Use 的核心是浏览器状态和动作循环；页面结构、交互元素、截图、视觉能力，都只是为这个循环服务。</p><p>代价也很直接：上下文和模型调用成本更高，执行路径更不确定，长任务更容易漂移。越开放，越需要验证、缓存、自愈和业务流程约束。</p><h3 id="两条路线的对比"><a href="#两条路线的对比" class="headerlink" title="两条路线的对比"></a>两条路线的对比</h3><table><thead><tr><th>维度</th><th>Playwright</th><th>Vercel agent-browser</th><th>Browser-Use</th></tr></thead><tbody><tr><td>核心哲学</td><td>人类开发者写确定性自动化</td><td>把网页降维成低 token CLI 工具</td><td>把浏览器组织成 Agent 任务环境</td></tr><tr><td>页面表示</td><td>DOM、locator、trace、截图、事件</td><td>Accessibility snapshot、<code>@eN</code> ref、短文本</td><td>页面结构、交互元素、状态摘要，可结合截图&#x2F;视觉</td></tr><tr><td>定位方式</td><td>CSS selector、locator、XPath</td><td>语义节点引用，如 <code>@e2</code></td><td>Agent 根据观察结果选择动作</td></tr><tr><td>Token 成本</td><td>直接给模型很高</td><td>极低，优先压缩上下文</td><td>中到高，取决于任务循环和视觉使用</td></tr><tr><td>自主性</td><td>低，依赖开发者脚本</td><td>中，提供可组合命令</td><td>高，内置多步任务循环</td></tr><tr><td>人类接管</td><td>改代码或调试脚本</td><td>直接在终端敲 CLI 命令</td><td>相对更像接管一个运行中的 Agent loop</td></tr><tr><td>典型场景</td><td>CI&#x2F;E2E、稳定流程</td><td>coding agent 的轻量网页操作</td><td>开放网页任务、多步骤自主执行</td></tr><tr><td>遗留问题</td><td>上下文和定位不适合模型</td><td>不负责完整规划和业务验证</td><td>成本、漂移和可靠性压力更大</td></tr></tbody></table><p>第二阶段其实不是一个方向，而是两条分叉。agent-browser 的进步在于降维，把浏览器压缩成文本大模型容易使用的终端工具。Browser-Use 的进步在于组织闭环，把浏览器包装成可以观察、推理、行动和检查的 Agent 环境。</p><p>二者都回答了第一阶段留下的上下文问题，也都留下了新的问题。<code>agent-browser</code> 解决上下文经济，却不负责完整任务规划；Browser-Use 提供自主循环，却带来成本、漂移和验证压力。第三阶段的 Stagehand &#x2F; Skyvern，就是在把自主性重新收进缓存、验证、视觉确认和业务流程约束里。</p><h2 id="第三阶段：从开放探索到工业落地"><a href="#第三阶段：从开放探索到工业落地" class="headerlink" title="第三阶段：从开放探索到工业落地"></a>第三阶段：从开放探索到工业落地</h2><p>第二阶段解决了 Agent 怎么看网页、怎么循环决策的问题，但还没有解决工业落地。</p><p><code>agent-browser</code> 解决了低 token 操作和终端可接管，但它不负责完整任务规划。Browser-Use 提供了自主循环，也带来了成本、漂移和稳定性压力。第三阶段从“能自主”转向“能落地”：怎么把 AI 放进可控流程，怎么减少重复推理，怎么让非开发者也能配置复杂网页任务。</p><p>Stagehand 和 Skyvern 是两条不同路线。Stagehand 面向开发者，把 Playwright 和 AI 混合成一个更容易生产化的 SDK；Skyvern 面向业务自动化，把视觉优先的浏览器代理包装成工作流平台。</p><h3 id="Stagehand：开发者路线，混合接管与执行缓存"><a href="#Stagehand：开发者路线，混合接管与执行缓存" class="headerlink" title="Stagehand：开发者路线，混合接管与执行缓存"></a>Stagehand：开发者路线，混合接管与执行缓存</h3><p><a class="link"   href="https://www.browserbase.com/stagehand/" >Browserbase 对 Stagehand 的介绍<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>把它称为面向 browser agents 的开源 SDK，核心原语包括 <code>act</code>、<code>observe</code>、<code>extract</code> 和 <code>agent</code>。这几个原语背后的思想很清楚：不要在 Playwright 和 Agent 之间二选一，而是把确定性脚本和 AI 推理混合起来。</p><p>Stagehand 更像 AI 增强型 Playwright，而不是一个黑盒 autonomous agent。开发者仍然写代码、定义流程、处理输入输出和业务校验；AI 只在页面不稳定、语义定位困难、数据提取复杂时介入。</p><p>一个典型 Stagehand 风格的流程是：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">用代码控制主流程</span><br><span class="line">  -&gt; 用 observe 找当前页面可行动作</span><br><span class="line">  -&gt; 用 act 执行自然语言动作</span><br><span class="line">  -&gt; 用 extract 按 schema 提取结构化数据</span><br><span class="line">  -&gt; 必要时交给 agent 处理更长流程</span><br><span class="line">  -&gt; 成功路径尽量缓存和复用</span><br></pre></td></tr></table></figure></div><p>这就是混合接管。打开网页、填固定账号、进入某个后台路径，这些确定性步骤继续用代码。点击一个经常改文案的按钮、从复杂页面里提取结构化字段、判断当前页面有哪些可行动作，这些不稳定环节交给 <code>act</code>、<code>observe</code> 和 <code>extract</code>。</p><p>Stagehand 的另一个关键点是缓存。完全自主 Agent 往往每一步都要重新问模型，这在重复流程里很浪费。Stagehand 的缓存思路是：第一次让模型解析动作或 agent step，成功后把可复用的动作结果保存下来；后续遇到相似页面结构时，优先使用缓存，减少或跳过 LLM 调用。缓存失效或页面变化时，再唤起模型重新定位和修复。</p><p>这个设计很实际：AI 不再每一步都推理，而是只在不确定或缓存失效时介入。它更适合专业开发者、已有业务流水线、稳定但会小幅变化的网页任务。Stagehand 不是要取代 Playwright，而是让 Playwright 在真实网页变化面前更有弹性。</p><h3 id="Skyvern：业务路线，视觉优先工作流平台"><a href="#Skyvern：业务路线，视觉优先工作流平台" class="headerlink" title="Skyvern：业务路线，视觉优先工作流平台"></a>Skyvern：业务路线，视觉优先工作流平台</h3><p>Skyvern 处理的是另一类问题：复杂业务门户和非开发者自动化。</p><p>这类网站经常有动态表单、弹窗、iframe、分页、文件上传下载、非语义化按钮和奇怪布局。只靠 selector 或无障碍树经常不够，因为关键控件在视觉上很明显，在 DOM 里却可能只是一个没有 role 的嵌套 <code>div</code>。</p><p><a class="link"   href="https://www.skyvern.com/docs/developers/getting-started/introduction" >Skyvern 文档<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>明确说，它使用 LLM 和 computer vision 自动化 browser-based workflows。官方描述的执行循环是：截图、提取 DOM、LLM 推理、执行动作、检查目标、重复。把它理解成 vision-first 更准确：视觉和截图是核心感知入口，DOM 是辅助信息，最终目标是不把脆弱的 XPath 或 selector 当作唯一真相。</p><p>这条路线更接近 AI RPA 或 workflow automation platform。Skyvern 可以通过 dashboard、API 或工作流触发；workflow block 可以表达登录、导航、下载、提取、循环、代码等步骤。对业务用户来说，它不像 Stagehand 那样要求你在代码里精细编排 <code>act</code> 和 <code>extract</code>，而是更适合用自然语言目标和可视化流程去配置“登录后台 -&gt; 查找未付款发票 -&gt; 下载 PDF -&gt; 发邮件”这类任务。</p><p>Skyvern 把浏览器自动化从“开发者写脚本”推向“业务流程编排”。它对复杂门户、非语义化页面和动态 UI 更友好，也更接近非开发者能理解的自动化工具形态。</p><p>代价也明显。视觉和多模态推理更慢、更贵；工作流越长，越需要明确的目标检查、人工介入点、权限管理和异常处理。遇到登录、2FA、验证码、支付或敏感数据时，不能简单相信“视觉模型会解决一切”，仍然需要工作流设计和权限治理。</p><h3 id="第三阶段的坐标"><a href="#第三阶段的坐标" class="headerlink" title="第三阶段的坐标"></a>第三阶段的坐标</h3><table><thead><tr><th>维度</th><th>Playwright</th><th>Browser-Use</th><th>Stagehand</th><th>Skyvern</th></tr></thead><tbody><tr><td>技术定位</td><td>确定性自动化 API</td><td>开放式 browser agent loop</td><td>AI 增强型 Playwright SDK</td><td>视觉优先 workflow automation platform</td></tr><tr><td>人类介入点</td><td>编写完整脚本</td><td>初始目标和运行中监督</td><td>代码与 AI 混合编排</td><td>Dashboard &#x2F; workflow blocks &#x2F; 自然语言目标</td></tr><tr><td>执行速度</td><td>快</td><td>慢到中等，依赖模型循环</td><td>快，缓存命中时接近确定性执行</td><td>较慢，依赖视觉和多步检查</td></tr><tr><td>Token 成本</td><td>低，但不适合直接给模型</td><td>中到高</td><td>低到中，重复流程可通过缓存降低</td><td>高，视觉和长流程成本更重</td></tr><tr><td>抗改版能力</td><td>低，依赖 selector&#x2F;locator</td><td>中到高，取决于观察和动作设计</td><td>高，靠 AI 定位、自愈和缓存验证</td><td>高，靠视觉优先和目标检查</td></tr><tr><td>目标用户</td><td>测试&#x2F;自动化工程师</td><td>Agent 开发者</td><td>专业开发者和生产流水线</td><td>业务自动化用户、运营团队、RPA 场景</td></tr><tr><td>遗留问题</td><td>脆弱、上下文不适合模型</td><td>成本、漂移、验证不足</td><td>仍需代码和浏览器运行时</td><td>成本高、速度慢、权限和异常治理复杂</td></tr></tbody></table><p>这一阶段把浏览器 Agent 从“能探索”推向“能完成业务流程”。Stagehand 解决开发者侧的可控、缓存和低成本；Skyvern 解决业务侧的视觉工作流和非开发者可用性。</p><p>不过第三阶段仍然默认有一个浏览器可以被稳定运行。只要走向生产，这个假设就会变重：浏览器 session 怎么管理？并发怎么扩？登录态怎么隔离？代理和验证码怎么办？失败轨迹怎么回放？这就是第四阶段的问题。</p><h2 id="第四阶段：从单次操作到生产级浏览器运行时"><a href="#第四阶段：从单次操作到生产级浏览器运行时" class="headerlink" title="第四阶段：从单次操作到生产级浏览器运行时"></a>第四阶段：从单次操作到生产级浏览器运行时</h2><p>当浏览器 Agent 从 demo 变成服务，问题就从“能不能操作网页”变成“能不能稳定承载浏览器 session、并发、代理、登录态、回放、隔离和成本”。浏览器不再只是工具，而是运行时资源。</p><ul><li><a class="link"   href="https://lightpanda.io/docs/" >Lightpanda<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：解决浏览器 runtime 太重的问题，面向更轻量、更高并发的 AI-native&#x2F;headless browser。</li><li><a class="link"   href="https://docs.browserbase.com/use-cases/agents" >Browserbase<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：解决托管浏览器 session、调试、回放、Agent Identity，以及 Stagehand 生态承载问题。</li><li><a class="link"   href="https://steel.dev/" >Steel.dev<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：解决浏览器 fleet、代理、反爬、captcha、云端 session 等执行基础设施问题。</li><li><a class="link"   href="https://docs.multion.ai/" >MultiOn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>：把浏览器操作进一步 API 化，让开发者提交自然语言 Web action，而不是管理每一次点击。</li></ul><p>这一阶段只说明一个事实：浏览器 Agent 最终会从工具调用进入基础设施层。具体产品选型不是本文重点，重要的是看见生产化承载本身会成为独立问题。</p><h2 id="两条真正的技术主线"><a href="#两条真正的技术主线" class="headerlink" title="两条真正的技术主线"></a>两条真正的技术主线</h2><p>把这些工具按阶段读完后，可以再抽象成两个问题。第一个问题是：Agent 看见什么？第二个问题是：Agent 怎么行动？浏览器 Agent 的演进，本质上是在改这两层接口。</p><p>不过在感知层和行动层之前，官方浏览器桥先补上了一层产品边界：谁的浏览器、谁的登录态、谁来授权、谁来确认敏感动作，以及网页内容在什么安全模型里被读取。Codex Chrome extension 和 Claude in Chrome 的价值首先在这里，而不只是多提供一组 click 和 fill。</p><p>感知层回答的是：浏览器状态以什么形态进入模型上下文。</p><p>最早的自动化主要依赖 DOM、locator 和 DevTools telemetry。CDP 把浏览器内部状态暴露出来，Playwright 把它们包装成测试与自动化抽象，Chrome DevTools 把它们包装成调试视角。这里的信息很强：DOM、CSS、console、network、trace、performance、heap snapshot 都能看到。但它们首先是给人类工程师和测试框架用的，不是给模型上下文设计的，所以强观测能力和上下文污染是同时出现的。</p><p>Playwright MCP 开始做第一层压缩：它用 accessibility snapshot 和 ref 把页面变成可交互语义树。模型看到的不再是完整 HTML，而是按钮、输入框、标题、链接和引用 ID。这适合模型像终端用户一样推理：“我要点哪个按钮”“我要填哪个输入框”。</p><p><code>agent-browser</code> 把这个方向推得更极端。它把页面快照压缩成极短文本，把元素变成 <code>@eN</code> 引用，优先服务 token economy。对本地 coding agent 来说，这等于把浏览器变成了一个低噪声、低成本的文本界面。</p><p>Browser-Use 的感知不只是单次快照，而是任务循环里的状态摘要。它需要在每一步告诉模型：当前页面是什么、有哪些可交互元素、上一步做完后发生了什么，必要时还可以结合截图或视觉信息。它的重点不是最小 token，而是支撑连续决策。</p><p>Stagehand 的感知服务于代码流程里的不确定节点。<code>observe</code> 回答“当前有哪些可行动作”，<code>extract</code> 回答“我能从这里拿到什么结构化数据”。它不是把整个网页交给 Agent，而是在确定性代码骨架里，把局部不确定性转成模型可以处理的结构。</p><p>Skyvern 的感知更偏 vision-first。它用截图和视觉信息理解复杂业务页面，同时用 DOM 辅助和目标检查降低误判。对非语义化页面、动态表单、视觉上明显但 DOM 结构混乱的控件，这种感知方式比纯 selector 更接近人类。</p><p>可以写成：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">host-native browser bridge / signed-in state / permission gates</span><br><span class="line">  -&gt; CDP / DOM / DevTools telemetry</span><br><span class="line">  -&gt; Accessibility Tree / ref</span><br><span class="line">  -&gt; compressed text snapshot / @eN refs</span><br><span class="line">  -&gt; task-oriented browser state</span><br><span class="line">  -&gt; 视觉 + DOM</span><br><span class="line">  -&gt; engine-native browser state</span><br></pre></td></tr></table></figure></div><p>第二层是行动层。行动层回答的是：模型如何把意图变成浏览器里的动作。</p><p>官方浏览器桥把行动先放回宿主产品里：动作发生在用户可见的真实浏览器中，登录、验证码、敏感提交和站点授权都能回到人类确认。它不追求最底层的可编程性，而是追求普通任务的开箱可用和权限治理。</p><p>Playwright 的行动是脚本化的：selector、locator、click、fill、hover、auto-wait。它很稳定，但前提是开发者已经知道流程和页面结构。</p><p>Playwright MCP 和 Chrome DevTools MCP 把这些能力变成工具调用。Playwright MCP 偏用户动作：导航、点击、输入、等待、截图。Chrome DevTools MCP 偏工程诊断：读取 console、network、DOM&#x2F;CSS、performance，再配合必要的输入自动化复现问题。它们都把浏览器能力接入了模型，但仍然没有完全解决动作上下文如何收敛的问题。</p><p><code>agent-browser</code> 把动作压缩成 CLI&#x2F;ref 命令。模型不需要生成复杂 selector，只需要 <code>click @e2</code> 或 <code>fill @e3</code>。这种行动接口适合本地 coding agent，也方便人类在终端里直接接管。</p><p>Browser-Use 把动作放进 agent loop。模型不是只调用一次 click，而是持续观察、规划、执行、检查，直到任务完成或需要重试。这让浏览器操作从单步工具调用变成了多步任务执行。</p><p>Stagehand 把行动重新收回开发者控制。确定性代码负责主流程，AI 负责不稳定动作；成功动作或 agent step 可以缓存，缓存失效时再让模型修复。这让行动既有 AI 的弹性，又尽量接近脚本的成本和速度。</p><p>Skyvern 把行动编排成工作流。它不要求用户像开发者一样管理每个 selector，而是通过 workflow blocks、自然语言目标和视觉检查来组织任务，更接近业务 RPA。</p><p>Browserbase、Steel.dev 和 MultiOn 则把行动推向云端执行层。Browserbase&#x2F;Steel.dev 关心 session、代理、回放、并发和隔离；MultiOn 进一步把动作封装成 Web action API，让开发者提交任务，而不是管理每一次点击。</p><p>可以写成：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">host-native browser action / human confirmation</span><br><span class="line">  -&gt; script / selector</span><br><span class="line">  -&gt; MCP tools</span><br><span class="line">  -&gt; ref / action primitives</span><br><span class="line">  -&gt; agent loop</span><br><span class="line">  -&gt; hybrid cached actions / workflow blocks</span><br><span class="line">  -&gt; cloud execution / Web action API</span><br></pre></td></tr></table></figure></div><p>感知层决定模型是否看得清，行动层决定系统是否做得稳。官方浏览器桥则把这两层放进宿主产品的登录态、权限和安全边界里。工具演进不是从 A 替代 B，而是在这些层上不断改接口。</p><h2 id="工具选型应该回到你卡在哪一层"><a href="#工具选型应该回到你卡在哪一层" class="headerlink" title="工具选型应该回到你卡在哪一层"></a>工具选型应该回到你卡在哪一层</h2><p>所以选型不应该从“哪个工具最火”开始，而应该从“我的瓶颈在哪一层”开始。</p><p>如果目标系统已经有结构化 API、官方 app connector、MCP server 或稳定集成，先看这些接口。它们通常比浏览器更安全、更稳定、更可审计，也不容易被网页 UI 改版和 prompt injection 牵着走。</p><p>如果你的目标只是让 Agent 在已经登录的网页里替你完成任务，先看 Codex Chrome extension 和 Claude in Chrome。它们不是最细的浏览器自动化原语，但作为开箱即用的真实浏览器操作能力，登录态复用、权限确认、人工接管和安全边界都更完整。</p><p>如果你缺的是更细的稳定控制，再看 Playwright 和 Playwright MCP。已知流程、E2E 测试、CI 回归，不需要强行交给自主 Agent。进一步说，如果目标是让模型像普通用户一样完成流程，Playwright MCP 更自然。</p><p>如果你缺的是调试反馈，看 Chrome DevTools MCP。它最适合 coding agent 在真实 Chrome 里读取 console、network、DOM&#x2F;CSS、performance 和 Lighthouse，再回到代码里修问题。如果目标是让模型像前端工程师一样诊断页面，Chrome DevTools MCP 更自然。</p><p>如果你缺的是 Agent 可读页面表示，或者你已经发现 Playwright&#x2F;DevTools 输出正在污染上下文，看 Vercel agent-browser 和 Browser-Use。前者偏轻量、低 token、本地终端工作流；后者偏完整浏览器任务环境和自主探索。这个问题不要停留在 Playwright MCP 或 Chrome DevTools MCP 上继续堆更多 DevTools、trace 或 DOM 输出，而要转向更明确的上下文压缩和任务相关过滤。</p><p>如果你缺的是行动缓存和流程编排，看 Stagehand 和 Skyvern。前者适合专业开发者把 Playwright 与 AI 推理混合，并通过缓存降低重复流程成本；后者适合复杂业务门户和视觉优先的工作流自动化，更接近 AI RPA。</p><p>如果你缺的是生产化承载，看 Lightpanda、Browserbase、Steel.dev、MultiOn。Lightpanda 解决 runtime 成本，Browserbase 和 Steel.dev 解决云端浏览器基础设施，MultiOn 解决更高层的 Web action API 化。</p><p>这样看，工具选型就不再是一排工具里挑一个，而是先定位你处在浏览器 Agent 工具链的哪个阶段：</p><div class="code-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">有结构化 API / 官方 connector -&gt; API / connector</span><br><span class="line">只想让 Agent 操作已登录浏览器 -&gt; Codex Chrome extension / Claude in Chrome</span><br><span class="line">控制不了浏览器        -&gt; Playwright / Playwright MCP</span><br><span class="line">看不到真实运行时      -&gt; Chrome DevTools MCP</span><br><span class="line">上下文被浏览器噪声污染 -&gt; agent-browser / Browser-Use</span><br><span class="line">行动需要被缓存/编排   -&gt; Stagehand（开发者混合接管）/ Skyvern（业务视觉工作流）</span><br><span class="line">生产运行扛不住        -&gt; Lightpanda / Browserbase / Steel.dev / MultiOn</span><br></pre></td></tr></table></figure></div><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>浏览器过去是给人看的应用，现在正在变成 Agent 使用互联网的环境接口。</p><p>官方浏览器桥让 browser agent 从工程实验变成可直接使用的产品能力。Codex Chrome extension 和 Claude in Chrome 解决的是“让 Agent 在我的真实浏览器里干活”这件事：复用登录态、放进权限确认、保留人工接管，并把 prompt injection 和敏感动作纳入宿主产品的安全边界。</p><p>在这条线之后，Playwright 解决确定性控制，Chrome DevTools MCP 解决真实运行时反馈，但它们也会把大量浏览器信息带进 Agent 上下文。agent-browser 和 Browser-Use 解决模型可读的网页状态，Stagehand 解决开发者侧的混合接管和执行缓存，Skyvern 解决业务侧的视觉工作流，Lightpanda、Browserbase、Steel.dev、MultiOn 解决生产运行时和平台化。</p><p>所以这不是“AI 替代自动化脚本”的故事。更准确地说，浏览器被拆成了几层接口：宿主官方安全边界、可控制的环境、可读的状态、可验证的动作、可承载的运行时。</p><p>这些接口一旦稳定下来，Agent 操作浏览器就不再是一段脆弱的自动化脚本，而会成为 AI 系统访问真实 Web 世界的一条基础通道。</p>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/05/22/agent-browser-tools-comparison/</id>
    <link href="https://hyacehila.github.io/blog/2026/05/22/agent-browser-tools-comparison/"/>
    <published>2026-05-22T01:00:00.000Z</published>
    <summary>A discussion of how browser-agent tools evolved from official host-native browser bridges to automation scripts and browser infrastructure, covering Codex Chrome extension, Claude in Chrome, Playwright, Chrome DevTools MCP, Browser-Use, Stagehand, Skyvern, Lightpanda, and cloud browser platforms.</summary>
    <title>Letting Agents Use Browsers: From Automation Scripts to Browser Infrastructure</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Agent Infrastructure" scheme="https://hyacehila.github.io/categories/agent-infrastructure/"/>
    <category term="MCP" scheme="https://hyacehila.github.io/tags/MCP/"/>
    <category term="Agents" scheme="https://hyacehila.github.io/tags/Agents/"/>
    <category term="Tool Use" scheme="https://hyacehila.github.io/tags/Tool-Use/"/>
    <content>
      <![CDATA[<p>这篇文章就是一个收藏夹，放一些我喜欢的、可以外接给 Agent &#x2F; Coding CLI 的资源。</p><p>它们不一定很大，也不一定值得单独写一篇文章。可能是一套 Skills，一个 MCP Server，一个插件，或者某段脚本、某份提示词结构、某个看起来有点奇怪、但确实能省事的小办法。共同点是：都能挂到 Agent 或 Coding CLI 上，让它多一点能力。</p><p>这篇来源分两块：一块是<strong>大厂 &#x2F; 平台方基础服务 Skill</strong>，多半是官方或平台团队维护的 CLI、产品文档和工程最佳实践；另一块是<strong>独立开发者捣鼓出来的东西</strong>，更像试验田，有编辑流程、创作工作流，也有一些小而顺手的工具。每条还是会标类型（Skill &#x2F; MCP Server &#x2F; 插件 &#x2F; 工具），以后攒多了也不至于翻半天。</p><p>先留在这里。后面遇到新的，再慢慢补。</p><h2 id="大厂-平台方基础服务-Skill"><a href="#大厂-平台方基础服务-Skill" class="headerlink" title="大厂 &#x2F; 平台方基础服务 Skill"></a>大厂 &#x2F; 平台方基础服务 Skill</h2><h3 id="vercel-labs-skills"><a href="#vercel-labs-skills" class="headerlink" title="vercel-labs&#x2F;skills"></a><a class="link"   href="https://github.com/vercel-labs/skills" >vercel-labs&#x2F;skills<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill 分发工具 &#x2F; CLI</strong></p><p><code>vercel-labs/skills</code> 不是某个具体 skill，而是装 skill 的工具。入口是 <code>npx skills</code>，可以从 GitHub 仓库、本地目录或其他 git source 拉取 skills，再放到不同 Agent 能识别的位置。它不教 Agent 怎么写页面、做视频、跑实验，只管一件事：这些能力怎么装、怎么分享、怎么迁移。</p><p>它也要和 <a class="link"   href="https://github.com/vercel-labs/agent-skills" >vercel-labs&#x2F;agent-skills<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 区分开。<code>vercel-labs/skills</code> 是 CLI &#x2F; 分发工具，像基础设施；<code>vercel-labs/agent-skills</code> 才是 Vercel 官方维护的内容型 skills 集合。前者管怎么装，后者管装什么。这两个仓库放在一起看，能看出 Vercel 不只想写几份好用的 <code>SKILL.md</code>，也想把分发这件事做顺。Vercel 官方也写了一些关于他们在 Skills 方面研究的 blogs，他们的观点是值得参考的。</p><h3 id="ClawHub"><a href="#ClawHub" class="headerlink" title="ClawHub"></a><a class="link"   href="https://github.com/openclaw/clawhub" >ClawHub<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill &#x2F; Plugin 注册表 &#x2F; 分发目录</strong></p><p>ClawHub 是 OpenClaw 生态里的公共 skill registry。它把围绕 <code>SKILL.md</code> 和配套文件的发布、版本、搜索、安装、评论、收藏和审查收进同一套目录里。具体任务怎么做，仍然交给各个 skill 自己；ClawHub 关心的是这些 skills 和 plugins 怎么被发现、更新和治理。</p><p>把它和 <code>vercel-labs/skills</code> 放在一起看会更清楚。<code>vercel-labs/skills</code> 偏安装和迁移：从 GitHub、本地目录或 git source 把 skill 放到合适的位置。ClawHub 偏 OpenClaw 自己的 registry 和 package catalog：既有技能目录，也开始覆盖 code plugins、bundle plugins 这类更重的扩展单元。对于 OpenClaw 来说，它承担的是公共市场和索引层的角色。</p><p>用这类注册表时，别只看名字就装。安装前先 inspect：来源、版本、changelog、metadata、扫描状态和 moderation 状态都值得扫一眼。Skill 的门槛低是好事，但它会把脚本、环境变量、外部服务和本地权限一起带进 Agent 工作流里。越顺手，越要先看清楚。</p><h3 id="Remotion-Agent-Skills"><a href="#Remotion-Agent-Skills" class="headerlink" title="Remotion Agent Skills"></a><a class="link"   href="https://www.remotion.dev/docs/ai/skills" >Remotion Agent Skills<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill</strong></p><p>Remotion Agent Skills 是 Remotion 给 Agent 准备的视频工程说明书。它让 Agent 按 Remotion 的方式写 React composition、frame-based 动画、音频、字幕、素材和转场，最后渲染成 MP4。这里的时间不是一页一页推进，而是一帧一帧算；产物也不是网页舞台，而是可以交付、复用、自动导出的视频文件。</p><p>它把视频生成拉回了工程层。很多 AI 视频工具适合输出气氛和镜头感（自动匹配图片素材），但技术内容、数据动画、字幕节奏、批量模板和 CI 渲染，还是需要更确定的结构。Remotion 让 Agent 不再是想象一段视频，而是用 React 和时间轴把视频做出来。真要把技术视频做成稳定栏目，或者在 CI 里批量 render，它更像生产引擎。在视频生成模型成本降低之前，我们还是需要依赖一下这些确定性的工具。</p><h2 id="独立开发者捣鼓出来的东西"><a href="#独立开发者捣鼓出来的东西" class="headerlink" title="独立开发者捣鼓出来的东西"></a>独立开发者捣鼓出来的东西</h2><h3 id="General-Research-Review-Agent-And-Skills"><a href="#General-Research-Review-Agent-And-Skills" class="headerlink" title="General Research Review Agent And Skills"></a><a class="link"   href="https://github.com/Hyacehila/General-Research-Review-Agent-And-Skills" >General Research Review Agent And Skills<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill</strong></p><p>这是我自己做的一套 research review skill suite，主要用来辅助综述写作。它不是那种“帮我写一篇综述”的单条 prompt，而是把 scoping review 拆成几个可以接力的步骤：找文献、去重、筛选候选池、抽取论文证据、整理大纲、综合成文，最后检查引用和语言。</p><p>我最喜欢的是它把综述从一段聊天，变成了一套有中间产物的流程。以前做这类工作，经常是 Zotero、Google Scholar、手动表格、零散 PDF、临时 prompt 混在一起，最后再让 LLM 帮忙润色。这样当然也能做，但回头查的时候会很痛苦：哪些文章被排除了，为什么排除，某个结论到底靠哪几篇文章支撑，引用有没有贴错，都不太好追。</p><p>这套 skills 处理的就是这些地方。candidate pool、selection ledger、evidence notes、outline、citation map，还有最后的 PDF&#x2F;HTML&#x2F;Markdown 报告，都会留下来。它不是为了把文章写得更漂亮，而是让综述里最容易散掉的部分有迹可查：检索从哪里来，筛选怎么做，证据写在哪，正文引用支撑了什么。相比临时 prompt 或单纯的文献管理工具，它更适合有范围、有审计要求的综述型研究；如果只是随手总结几篇论文，就没必要上这么重的流程。</p><h3 id="Humanizer-Humanizer-zh"><a href="#Humanizer-Humanizer-zh" class="headerlink" title="Humanizer &#x2F; Humanizer-zh"></a><a class="link"   href="https://github.com/blader/humanizer" >Humanizer<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> &#x2F; <a class="link"   href="https://github.com/op7418/Humanizer-zh" >Humanizer-zh<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill</strong></p><p>Humanizer 和 Humanizer-zh 是一组写作清理 skills，用来改掉文本里的 AI 味道。它们不是语法纠错工具，盯的是更烦人的东西：过度总结、宣传腔、三段式排比、破折号滥用、空泛的“关键作用”，还有那种一看就像聊天机器人回答的客套话。</p><p>我喜欢它们，是因为这比“帮我润色一下”具体得多。普通润色经常会把文字改得更顺、更满，但也更像 AI；Humanizer 反过来，会删掉那些太工整、太会总结、太像模板的地方。英文内容可以用 Humanizer，中文内容就用 Humanizer-zh。</p><p>Humanizer-zh 对中文博客尤其有用。中文模型很容易写出“首先、其次、此外、综上所述”，也很容易把一句普通判断抬成“重要意义”“深刻影响”“复杂格局”。我很多时候不是想让文章更华丽，只是想让它听起来像真的有人写过、删过、犹豫过。写完技术文章、项目介绍、评论和随笔后，都可以拿它过一遍。</p><h3 id="Beautiful-Article"><a href="#Beautiful-Article" class="headerlink" title="Beautiful Article"></a><a class="link"   href="https://github.com/ConardLi/garden-skills/blob/main/skills/beautiful-article/SKILL.md" >Beautiful Article<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill</strong></p><p>Beautiful Article 是一套把现成材料做成网页长文的 skill。网页、PDF、Word、Markdown、截图，甚至一大段粘贴材料，都可以先交给它处理。它会把这些东西整理成干净的源文，再做成一个可以离线打开、可以直接分享的单文件 HTML。它解决的不是生成一个网页，而是让 Agent 真的像编辑一样，先读材料，再重排结构，再把文章变得更好读，并给我们一个更加优雅的交互方式。</p><p>漂亮不是堆样式，对于一篇文章而言，更好读需要内容和视觉结构的配合。它会先抽取材料，再写编辑计划，然后停下来让用户确认文章类型、主题、版式、配图和封面。真正开写时，也不是一口气完成，而是先做首屏和第一节，让你看方向对不对。这个节奏很适合长材料：风格可以提前校准，信息也不容易在生成过程中悄悄丢掉。source、plan、review 这些中间文件还会留下来，回头检查时不会只剩一个成品 HTML。</p><p>它适合处理那些内容其实不错，但读起来太痛苦的材料，比如报告、教程、访谈、复盘、方案分析、解释文和很长的文章，也可以用于个人自己的分享。最后的成品可以有表格、代码块、图解、封面、目录，也可以加一点交互式小块，但它始终是在做文章，不是在做后台、表单、dashboard 或产品原型。如果手里有一份东西已经够扎实，只是太长、太散、太难读，我会很愿意把它交给 Beautiful Article 收拾一遍。</p><h3 id="Web-Video-Presentation"><a href="#Web-Video-Presentation" class="headerlink" title="Web Video Presentation"></a><a class="link"   href="https://github.com/ConardLi/garden-skills/tree/main/skills/web-video-presentation" >Web Video Presentation<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill</strong></p><p>Web Video Presentation 走的是内容导演路线。它先把文章或口播稿拆成 script、outline 和章节 step，再做成一个 16:9、可点击推进、适合录屏的网页舞台。它不负责把 React 代码渲染成 MP4，它关心的是怎么把一篇文章组织成值得录下来的讲解。</p><p>它不是一上来就写动画，而是要求先保留原文，产出口播稿和 outline，在稿子、章节、主题、素材、开发模式上停下来对齐。它的 <code>narrations.ts</code> 把 step 数和口播文本绑成唯一真相源，每一步独占整屏，画面细节还要回到 article 里抽。这个思路对技术博客特别有用：技术内容最怕被压成几句漂亮废话，它逼着 Agent 把论证链、数字、案例和节奏都留下来。</p><p>所以做单条技术分享时，它会比直接上 Remotion 顺手：先把博客拆成口播、章节和视觉节拍，再用浏览器录屏，得到一个足够清楚的视频。如果以后需要更稳定的字幕、音频和批量导出，再把这些中间产物迁到 Remotion 里做最终渲染也不迟。Web Video Presentation 给了很好的内容层和协作节奏，尤其适合把文章变成可讲、可录、还能保留细节的网页演示。也无需承担视频生成的高昂成本和抽卡风险。</p><h3 id="yinyo-image2-prompt-GPT-Image-2-Skill"><a href="#yinyo-image2-prompt-GPT-Image-2-Skill" class="headerlink" title="yinyo-image2-prompt &#x2F; GPT Image 2 Skill"></a><a class="link"   href="https://github.com/xiaoshiyilangzhao1996-droid/yinyo-image2-prompt" >yinyo-image2-prompt<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> &#x2F; <a class="link"   href="https://github.com/ConardLi/garden-skills/blob/main/skills/gpt-image-2/SKILL.md" >GPT Image 2 Skill<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h3><p><strong>类型：Skill</strong></p><p>这两个 skills 都围绕同一个问题：怎么让 Agent 更稳定地使用 GPT Image 2 生图和改图，而不是每次临时堆一段提示词。新一代图像模型对“8K、ultra detailed、masterpiece”这类旧咒语已经不太吃了，真正影响结果的反而是主体顺序、场景结构、文字约束、镜头语言、编辑时哪些要变和哪些不能变。它们处理的就是这层翻译工作：把人的模糊想法，变成模型更容易执行的视觉指令。</p><p>yinyo-image2-prompt 小而专。它把 GPT Image 2 的常见任务拆成 35 个子模板，用 5-Phase 流程引导用户先判断场景、再补足关键参数，背后还整理了 33 组盲评和几组 PK 赛的经验。它会提醒你什么时候不要套模板：App UI、Logo、编辑工作流这种结构强的任务，模板很有帮助；Pixar 3D、概念插画这类更靠叙事和画面感的任务，过度工程化反而会把模型的自由度压坏。这个判断比单纯多塞几个 prompt 更有用。</p><p>ConardLi 的 GPT Image 2 Skill 则更像一条生图生产线。它不只负责写 prompt，还把运行环境分成三种模式：本地有 API key 时可以直接调用脚本出图并落盘；宿主 Agent 自带图像工具时，就把渲染好的 prompt 委托给宿主；如果什么图像工具都没有，它也能退化成纯 prompt 顾问。它还带有 <code>check-mode.js</code>、<code>generate.js</code>、<code>edit.js</code> 这些脚本，模板库按 UI、产品、信息图、学术图、技术图、编辑工作流等目录展开，prompt 和图片也会分别归档，适合真正接进 Agent 的工作流里反复使用。</p><p>yinyo-image2-prompt 更适合用来学习和优化 GPT Image 2 的提示词判断：该问什么、该省什么、什么场景别过度写。GPT Image 2 Skill 更适合作为工程入口：让 Agent 先判断模式，再选模板、渲染 prompt、保存产物，必要时直接出图。前者像脑子，后者像手脚；真正想把生图变成稳定工作流时，两个放在一起看会更完整。</p><p>生图得玩，感觉拿来搞钱还是很有前景的。</p>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/05/17/agent-resource-collection/</id>
    <link href="https://hyacehila.github.io/blog/2026/05/17/agent-resource-collection/"/>
    <published>2026-05-17T05:00:00.000Z</published>
    <summary>A rolling collection of resources you can plug into agents and coding CLIs: Skills, MCP servers, plugins, and small tools that are handy enough to keep.</summary>
    <title>An Agent Resource Collection: Skills, MCP Servers, Plugins, and Handy Tools</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Essays" scheme="https://hyacehila.github.io/categories/essays/"/>
    <category term="Society" scheme="https://hyacehila.github.io/tags/Society/"/>
    <category term="Software Engineering" scheme="https://hyacehila.github.io/tags/Software-Engineering/"/>
    <category term="Product" scheme="https://hyacehila.github.io/tags/Product/"/>
    <content>
      <![CDATA[<p>在上一篇关于生成式 AI 的文章里，我写过一个判断：AI 不会简单终结工作，它更可能先重排劳动，再放大需求。把视角缩小到程序员身上，这个变化会更具体：代码、文案、资料研究、设计草稿和 demo 的成本都在下降，但成本下降不会自然让人少做事，反而会释放出更多精力，也让过去被时间和能力挡住的想法开始变得可行动。</p><p>传统意义上的 Software Engineer 正在向 Builder 靠近。过去的软件工程被组织分工定义：产品定需求，设计定交互，工程师负责实现，测试负责质量，运营和销售负责触达用户。工程师多数时候是在解决别人已经定义好的问题。</p><p>AI 改变的正是这条边界。它把原本分散在流程里的部分能力打包给个人，让个人可以更高效地完成过去需要团队协作的一部分执行工作，生产力因此被放大。个人未必能取代团队，但已经能低成本跑通一条小产品链路。<strong>Builder 不是会用 AI 写更多代码的人，而是能把问题、产品、用户、分发和反馈连起来的人。</strong></p><h2 id="代码变便宜后，工程师的价值前移"><a href="#代码变便宜后，工程师的价值前移" class="headerlink" title="代码变便宜后，工程师的价值前移"></a>代码变便宜后，工程师的价值前移</h2><p>Anthropic Economic Index 观察到，AI 的使用主要集中在软件开发、技术写作等认知任务上；现阶段，它更多是在增强具体工作，而不是替代整个职业。Google DORA 2025 也显示，AI 已经接近成为开发工具的默认配置，但收益并不是自动发生的：协作、反馈机制和质量标准越清楚，AI 越能放大效率；流程越混乱，AI 也越容易放大混乱。</p><p>Microsoft 2026 Work Trend Index 把未来组织描述为一种新的分工：AI 和 agent 承担越来越多执行，人类负责意图、判断、质量标准和工作设计。如果把这个组织层面的趋势放到个人身上，结论很直接：代码便宜之后，判断前移。你不只是更快实现需求，而是要更早决定什么值得实现、谁会使用、如何验证，以及如何把东西送到真实用户面前。</p><p>一个能跑的 demo 不是产品。AI 让 demo 更便宜，也让人在错误方向上快速堆出更多产出。过去做错方向至少很累，现在一个周末就能做出漂亮但没人要的东西，这反而要求工程师更早接触用户和市场。</p><h2 id="OPC：一个人的最小公司系统"><a href="#OPC：一个人的最小公司系统" class="headerlink" title="OPC：一个人的最小公司系统"></a>OPC：一个人的最小公司系统</h2><p>OPC 不是一个严格的法律概念，而是一种新的最小公司形态：一个人负责问题判断、产品定义、用户关系和收入闭环，把原本需要团队完成的执行环节尽可能交给 AI 和外部服务。它和自由职业不同。自由职业主要出售个人时间，OPC 更接近经营一个可重复交付的资产：软件、插件、模板、内容产品、自动化服务，或者某个垂直场景里的工作流。</p><p>“一人独角兽”的说法很吸引人，因为它把这个趋势讲到了极端：如果 AI 可以写代码、做设计、生成内容、处理客服、分析数据，一个极强的个人是否可以用工具链替代一家公司？但这个叙事容易误导人。AI 还没有强到让一个人无成本复制完整组织，更现实的起点，不该是追求“一人独角兽”，而是先做出一个人也能持续经营的公司，或者一个高杠杆的小产品。</p><p>真正变化的不是公司里只剩一个人，而是公司职能被拆成了更小、更便宜、更容易租用的模块。过去必须靠固定员工、层级管理和大量沟通完成的开发、设计、客服、部署、支付、分发、数据分析等工作，现在可以部分被 AI、自动化、SaaS、云服务、外包和平台市场承接。创业不再需要第一天就搭出一套完整公司体系，可以先找到用户和问题，再按需接入能力。</p><p>一个 OPC 至少要跑通四个闭环：第一是问题闭环，知道服务谁、解决什么高频或高收益问题；第二是交付闭环，用软件、模板、自动化或内容产品重复交付；第三是收入闭环，有明确价格、付款方式和续费或复购理由；第四是反馈闭环，能持续看到使用、留存、退款、客服和转化数据。缺少其中任何一环，它都更像项目、作品或自由职业，而不是公司系统。</p><p>普通工程师更容易切入的 OPC 形态，通常不是宏大的平台，而是足够窄的微型 SaaS、浏览器插件、开发者工具、行业模板、自动化脚本、内容加工具包，或者把内部反复使用的工作流外部化。它们共同的起点不是“我能做一个多大的系统”，而是“我是否知道一个具体人群每周反复遇到什么麻烦，并且能用可重复交付的方式替他们省事”。</p><p>适合 OPC 的业务通常有共同特征：低支持成本、高自动化、清晰获客入口、可重复交付、低合规压力和健康毛利。AI 让个人可以更晚扩张组织，更早验证商业假设，但它不会替你消除现金流、维护、信任和获客这些基本问题。不过组织能力变轻，不代表需求自动成立。一个人的公司系统，首先仍要回答产品问题。</p><p>反过来说，并非所有业务都适合一开始按 OPC 来做。高客制化交付、重销售、强合规、重客服、长实施周期，或者依赖大规模网络效应的业务，都不该被简单想象成“一个人加 AI”就能跑起来。OPC 更适合从窄问题、轻交付、明确入口和可计量收益开始。</p><h2 id="产品思维：先找真实痛点，再写更多代码"><a href="#产品思维：先找真实痛点，再写更多代码" class="headerlink" title="产品思维：先找真实痛点，再写更多代码"></a>产品思维：先找真实痛点，再写更多代码</h2><p>对传统程序员来说，最难的转变可能不在工具，而在问题选择。工程师很容易从技术出发：这个框架很新，这个模型很强，这个架构很漂亮，所以我要做个东西出来。但用户不为技术本身付费。用户付费，是为了更快、更确定、成本更低、收入更高，或者少受一点痛苦。</p><p>Marc Andreessen 那篇著名的 “The only thing that matters” 讲 product-market fit，本质上是在提醒创业者：市场比团队和产品更残酷。需求强烈的市场，会把不完美的产品往前拉；没有真实需求的市场，不会因为你的技术优雅而突然出现。放到 AI 时代，这个提醒更有价值，因为做出 demo 太容易了，做出一个没人要的 demo 也太容易了。</p><p>所以 Builder 的首要问题不该是“我能用 AI 做什么”，而该是“谁的哪个痛点，强到让他愿意付钱、花时间，或者承担迁移成本”。先别开 repo。用一页纸写清：用户是谁，使用者、付费者和决策者是否是同一个人，现在怎么解决，痛点发生得有多频繁，是否愿意付费，你能在哪里找到 10 个这样的人。写不清，就不要急着做。</p><p>a16z 曾提出 product-user fit 应该先于 product-market fit。这个说法对个人 Builder 尤其重要：不要急着证明自己面对的是一个巨大市场，先找到几个具体的人。能约到访谈、反复听到同一个问题、有人愿意试用甚至预付，才算有起点。先服务一个具体用户群，比先幻想一个宏大平台更可靠。</p><p>MVP 也应该放在这个语境里理解。MVP 不是低配版产品，而是用最低成本验证关键假设的方式。它至少要回答五个问题：用户现在用什么笨办法解决？痛点是否强到愿意付费或迁移？第一批用户从哪里来？AI 降低了哪部分交付成本？什么信号说明继续，什么信号说明停止？给 MVP 设定时间盒和停止标准：低触达产品可以用两周验证试用、反馈或付费信号；B2B 或垂直行业可以用四到六周验证访谈、试点意向和决策链条。</p><h2 id="分发应该从选题阶段开始"><a href="#分发应该从选题阶段开始" class="headerlink" title="分发应该从选题阶段开始"></a>分发应该从选题阶段开始</h2><p>技术人还有一个常见误区：先把产品做出来，之后再想怎么推广。工程师往往低估 distribution 的重要性。一个产品如果没有有效分发方式，再好的技术也可能只是在本地运行得很完美。</p><p>对个人 Builder 来说，分发不等于投广告，也不只是营销部门的事情。分发可以来自内容、开源、插件市场、SEO、社群、应用商店、B2B outbound，也可以来自你熟悉的垂直工作场景里的直接触达。关键不在形式，而在第一批用户从哪里来。</p><p>更进一步说，分发应该进入选题阶段。一个想法刚出现时，就应该问：谁会看到它？谁会信任它？谁会愿意试用？谁会付费？用户现在聚集在哪里？有没有一个可以重复使用的渠道？如果这些问题完全没有答案，那产品不是“还没开始推广”，而是商业模型一开始就缺了一半。</p><p>不同产品也需要不同的渠道适配：SEO 型产品要对应可搜索的问题，开源或开发者工具要有可展示的 repo 和集成场景，插件产品要适配 marketplace，B2B outbound 则要有明确 ICP 和触发事件。分发不是产品之后的包装，而是产品设计的一部分。</p><p><strong>没有入口，小产品很容易停在本地项目阶段。AI 让做产品的成本下降，但没有让注意力和信任变便宜。</strong></p><h2 id="从能力栈到验证系统"><a href="#从能力栈到验证系统" class="headerlink" title="从能力栈到验证系统"></a>从能力栈到验证系统</h2><p>转向 Builder 并不意味着工程能力不重要。恰恰相反，工程基本功仍然是底盘：系统理解、测试、部署、安全、数据、可观测性、成本控制和长期维护，决定 demo 能不能变成服务。AI 可以帮你更快写出代码，但不会替你保证正确性，也不会自动处理用户数据、支付失败、权限泄露、服务中断和长期演进。</p><p>变化在于，工程能力不再只服务于把需求实现出来，而要进入一个更早的反馈回路：先找用户，再判断需求，再用最小实现验证，最后根据反馈决定继续、收缩或停止。工程师要补的不是更多 coding workflow，而是三件事：会找人聊，会判断真假需求，会把产品放进一个稳定的获客入口。</p><p>AI 在这里的作用，也不只是帮你写代码。更实用的做法是把它放进固定流程：访谈摘要、竞品表、落地页草稿、发布文案、客服问题整理、每周指标复盘。不要临时问 AI，要让它成为工作系统的一部分。这样 AI 才不是一次性的灵感工具，而是帮你持续压低验证成本的执行层。</p><p>所以工程师转 Builder，不是先学一整套商业知识，而是先改工作顺序。不要从技术栈开始，而是从具体用户开始；不要先做完整系统，而是先验证一个付费场景；不要把上线当终点，而是把上线当获取反馈的入口。</p><p>这也是 OPC 和 Builder 最后落到同一个地方的原因。OPC 不是一个人把所有事情都做完，而是一个人设计出最小组织系统：用 AI 放大执行，用工程守住质量，用分发接触用户，用 MVP 找到答案。代码仍然重要，但它应该服务于判断，而不是替代判断。</p><p>代码变便宜后，问题不再只是“我能不能做出来”，而是“这个问题是否值得解决，谁愿意为它付出代价，我能不能用最短路径验证它”。从 Engineer 到 Builder，不是从技术转向商业话术，而是把工程能力放回真实世界，用更短的反馈回路解决一个真实存在的问题。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>Anthropic, <a class="link"   href="https://www.anthropic.com/news/the-anthropic-economic-index?pubDate=20250519" >The Anthropic Economic Index<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Google, <a class="link"   href="https://blog.google/innovation-and-ai/technology/developers-tools/dora-report-2025/" >How are developers using AI? Inside our 2025 DORA report<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Microsoft, <a class="link"   href="https://www.microsoft.com/en-us/worklab/work-trend-index/agents-human-agency-and-the-opportunity-for-every-organization" >2026 Work Trend Index Annual Report<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Fortune, <a class="link"   href="https://fortune.com/2024/02/04/sam-altman-one-person-unicorn-silicon-valley-founder-myth/" >Could AI create a one-person unicorn?<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Marc Andreessen, <a class="link"   href="https://pmarchive.com/guide_to_startups_part4.html" >The only thing that matters<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>a16z, <a class="link"   href="https://a16z.com/product-user-fit-comes-before-product-market-fit/" >Product-User Fit Comes Before Product-Market Fit<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Blake Masters &#x2F; Peter Thiel, <a class="link"   href="https://github.com/startup-engineering/000-how-to-build-the-future/blob/main/09-if-you-build-it.md" >CS183 notes: If You Build It, Will They Come?<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li><li>Lean Enterprise Institute, <a class="link"   href="https://www.lean.org/lexicon-terms/lean-startup/" >Lean Startup<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/05/11/from-engineer-to-builder-opc-product-thinking/</id>
    <link href="https://hyacehila.github.io/blog/2026/05/11/from-engineer-to-builder-opc-product-thinking/"/>
    <published>2026-05-10T22:00:00.000Z</published>
    <summary>Generative AI expands not only productivity, but also the boundary of individual action and experimentation. As code gets cheaper, engineers need product thinking, distribution, and validation.</summary>
    <title>From Engineer to Builder: One-Person Companies and Product Thinking in the AI Era</title>
    <updated>2026-07-01T15:56:19.866Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hyacehila</name>
    </author>
    <category term="Fiction" scheme="https://hyacehila.github.io/categories/fiction/"/>
    <category term="Sci-Fi" scheme="https://hyacehila.github.io/tags/Sci-Fi/"/>
    <category term="Fiction" scheme="https://hyacehila.github.io/tags/Fiction/"/>
    <content>
      <![CDATA[<h2 id="无字之证"><a href="#无字之证" class="headerlink" title="无字之证"></a>无字之证</h2><p>雨夜，乾陵。</p><p>第一张纸烘到半干时，梁成看见了自己的死期。</p><p>那不是墨。纸背先浮出一横，接着是一点，灰色的字像从纸里渗出来。军吏以为是诏令，书吏只看了一眼便跪倒在泥里，债主伸手去抢。轮到梁成看时，纸上只剩一篇墓志。</p><p>亡匠梁成，京兆人。少习镌刻，手拙心迟。后唐某年九月，奉命修乾陵碑，三日后卒于陵下。无妻。有女，名宁，转籍不详。</p><p>最后四个字像刀，钉在他眼里。火光一晃，字又变了。军吏看见的是讨伐逆臣的文告，书吏看见的是一份新朝改元的册命，债主看见的则是债券，白纸黑字，写明阿宁已经归他家使唤。每个人都说别人看错了。每个人都说自己看见的才是真的。</p><p>纸很快烧焦。字卷进黑边里，没了。</p><p>三日前，州城匠行。</p><p>那时他还叫梁成，至少匠行的籍册上这样写。债券上那个梁字却像粱，女儿阿宁唤他时只叫阿耶。他给人修碑，也给人磨去不该留的字。乱世里的石匠活得比书吏粗贱些，却比兵卒长久些。死人总会有，活人总要让死人说几句体面话。会刻字的人饿不死，只是也富不了。</p><p>那年关中雨多。谷子没熟透，兵已经先来过一遍。州城里的节帅要给自己寻一个正统来历，便想到了乾陵。他不敢动陵，也不敢真说自己和李唐有什么血脉，只叫人去拓一张无字碑。</p><p>差事传到匠行，没人肯接。</p><p>拓无字碑，听着像疯话。若是拓不出字，交不了差；若是拓出了字，更不好说。最后行首把活派给梁成，因为他欠着钱，恰好能叫他出命。</p><p>债不是他一个人欠下的。前一年他给一座县令墓补志，原石泡过水，字根都酥了。他按旧拓补了三行，第二天墓主人的侄子带兵来，说那三行里少了一个官衔，辱了祖宗。匠行赔了钱，钱记在他名下。阿宁的户帖也押了进去。再拖两个月，债主就能把她从良人名籍里摘出去，送到谁家作使女。</p><p>行首把节帅的文书摊在他面前，说：“乾陵的碑大，费纸费墨。你若回来，债可销一半。若拓得好，孩子的籍也许能还。”</p><p>梁成问：“无字碑，要怎样才算拓得好？”</p><p>行首看着门外的雨，说：“上头觉得它该有字。”</p><p>雨夜，乾陵。</p><p>抵达乾陵的一行人不多。两个军吏，一个书吏，三个挑纸墨的杂役，还有梁成。债主也跟着。他不是官差，却拿着阿宁的户帖，说怕梁成跑。</p><p>梁山远看像一只伏在雨里的兽。陵道两旁的石人石马缺胳膊少耳朵，脸被风磨得发钝。白日里还好，一到傍晚，荒草间全是水声。军吏说那是雨从石缝里淌下来，另一个说不是，陵里有河。</p><p>梁成没有接话。他见过太多墓，知道墓旁最不缺声音。</p><p>梁成那夜面对的，当然不是今日游客看见的那块题刻斑驳的碑。宋、金以后的诗句和姓名还没有来，汉字之外的题刻也还在后世。在他眼前，它近乎空白。</p><p>这块碑比他想的更高，雨水顺着碑面往下走，像有人一直从顶上泼水。碑身在暗处发青，近看能见到浅浅的纹理，却没有正经碑文的行格，更不见上面想看到的碑文。</p><p>梁成摸了摸石面，指腹被细砂刮了一下。</p><p>书吏撑着油伞，催他动手。</p><p>梁成先按规矩做干拓。净纸贴上去，用软刷从中间向四面赶气，再拿扑子蘸墨，轻轻拍。纸揭下来，只有石纹，像一张冻住的水面。书吏皱眉。军吏骂了声废纸。债主抱着阿宁的户帖，笑得很轻。</p><p>第二张纸刚贴上去，雨忽然大了。风把伞掀翻，纸半湿半干地吸在碑上，怎么揭都揭不动。梁成怕纸烂，拿衣袖去护。那一瞬间，他觉得掌心下面不是石头，是一块正在慢慢呼吸的皮。</p><p>他不敢说。</p><p>等雨势稍停，纸终于揭下来。纸面仍是空的。军吏失了耐性，叫杂役在残墙边生火，把湿纸烘干，明日再试。</p><p>火烧起来时，第一笔字从纸背浮了出来。梁成后来才明白，那不是碑文显形，是裂缝开了。</p><h2 id="裂缝"><a href="#裂缝" class="headerlink" title="裂缝"></a>裂缝</h2><p>那夜无人睡稳。军吏守着碑，书吏在帐中默写自己看见的册命，写到一半又全撕了。他说年号不对，官署也不对，可读的时候偏偏像多年以前就已奉行过。债主抱着户帖不撒手，半夜醒来两次，喊阿宁已经画押。</p><p>梁成坐在帐外，手里搓着一小团湿纸浆。指甲里全是石粉。</p><p>天快亮时，他又做了一次。</p><p>干纸无字。湿透了也无字。只有纸半干，贴在碑面与空气之间，还没决定自己是纸还是碑皮时，字才出来。字不会停太久。热一催，便浮；风一吹，便散。若人赶在散去之前读完，它就会在那人心里补上自己缺的部分。</p><p>梁成试着不读，只看笔画。他发现那些字并不真正刻在石上。碑面太平了，没有字根，没有刀路。文字像从石头背后伸出来，借纸活一小会儿。它等的不是墨，是眼睛。</p><p>午后，雨停了片刻。他绕到碑座后面查看，发现一道旧裂。裂缝被前人补过，补料里掺着细碎的碑砂，手艺极高，不细看几乎认不出。可雨水泡久了，补缝处又松开一线。梁成用竹签挑出一点旧灰，里面夹着一片薄得像鱼鳞的石片。</p><p>石片上有字。</p><p>不是碑文。也不像题记。只有几句禁语，刻得很浅：</p><p>不得补字。</p><p>不得拓全。</p><p>不得命文。</p><p>最后一句磨损得厉害，只剩半截：</p><p>留名者，补……</p><p>梁成看了很久，背上慢慢出了汗。</p><p>书吏也找了过来。他眼尖，看见梁成掌心里的石片，立刻伸手来抢。梁成躲了一下，书吏只看清“不得拓全”四个字，脸就白了。</p><p>“这是禁碑。”书吏低声说。</p><p>“什么禁碑？”</p><p>书吏摇头。他说自己家里以前藏过一册旧书，讲武后晚年有一道密诏，未入实录，也未入国史。那诏书不是给一代人的，是给所有后来人的。谁得了它，谁就能说明天下原本该怎样走。</p><p>梁成说：“你信？”</p><p>书吏嘴唇发抖：“我方才不信。可我昨夜看见的册命，里面有我的名字。它说我本该做中书舍人，不该在这里给武夫磨墨。”</p><p>一个人若看见自己本该拥有的命，很难再觉得眼前这条命是真的。</p><p>傍晚，节帅的快马到了。军令很短：三日内拓成全本，护送回州城。若碑上无字，便拓出无字之证；若碑上有字，一个笔画也不许少。</p><p>梁成知道，这才是最坏的情形。</p><p>一张完整拓本会进军府。书吏会誊抄，军吏会传阅，节帅会命人改成檄文。檄文会贴到城门上，读给不识字的兵听，再由兵带去下一个州县。若那文字真能叫人相信另一条历史，军府就是最好的水渠。</p><p>字会顺着命令流出去。</p><h2 id="译码"><a href="#译码" class="headerlink" title="译码"></a>译码</h2><p>第二夜，梁成偷偷把债主绑了。</p><p>这事做得不体面。他趁债主睡熟，用拓碑的麻绳勒住手脚，又用湿纸塞了嘴。债主醒来时眼睛瞪得像鱼，喉咙里呜呜响。梁成从他怀里摸出阿宁的户帖，揣进自己衣内。纸还带着人的热，像一块小小的肉。</p><p>他没有跑。陵道外都是军吏，跑不出去。况且裂缝还在。</p><p>他需要弄明白那碑到底要什么。</p><p>梁成把旧裂旁的泥水一点点刮净，又取来三张纸。第一张只拓裂缝，第二张拓半碑，第三张试着拓全。第三张刚铺上，风就停了。山间的虫声也停了。整个乾陵像被一只看不见的手按住。</p><p>他听见有人在碑里写字。</p><p>不是刻。是写。笔锋落在纸上，有轻微的沙沙声。梁成抬头，雨水打进眼睛。碑面还是什么都没有，可他眼前忽然多了一座宫城。</p><p>宫城已经烧毁过。梁木是黑的，瓦上长着草，殿门却全开着，金钉新得刺眼。他知道那是大明宫，虽然他从没见过完整的大明宫。他站在含元殿前，衣裳湿透，手里仍捏着拓纸。每一扇门后都挂着一篇碑文。</p><p>第一篇说，武周不曾断绝，李唐只是借来的外衣。</p><p>第二篇说，天下若早听女主之治，藩镇不会割据，百姓不会被一遍遍征发。</p><p>第三篇说，神龙之后所有史官都在说谎，所有庙号、谥号、实录都该重排。</p><p>还有更多。每一篇都严整、漂亮，像最好的史官用最冷的手写成。梁成只读了几行，便觉得胸中一松。他几乎相信自己这辈子的穷困也有了解释。不是他手艺不好，不是他命贱，是这世道从一开始就走错了。只要把那篇正确的碑文拓出去，天下便能回到该回的地方。</p><p>这念头太舒服了。</p><p>舒服得可怕。</p><p>他猛地咬破舌尖。血腥味把宫城撞碎。眼前又是雨夜，又是青碑。第三张纸贴在碑上，已经显出密密麻麻的行列。军吏不知何时站在他身后，眼神直勾勾的。</p><p>“拓下来。”军吏说。</p><p>梁成把纸撕了。</p><p>军吏一拳打在他脸上。他倒进泥里，耳边嗡嗡响。书吏扑上去抢碎纸，抓到几片，读了一眼，忽然哭起来。他一边哭一边笑，说原来如此，原来先帝未死，原来天下还有正朔。</p><p>军吏抽刀砍他。</p><p>这一刀没有砍中。书吏像早知道刀从哪里来，向旁边偏了一寸，刀锋削掉他一绺头发。他回身去夺刀，动作利落得不像一个握笔的人。梁成这才明白，纸上的字不只是叫人相信。它会把相信之后的那个人也补出来。</p><p>军吏若信了讨伐诏令，便成了奉诏杀人的兵。书吏若信了册命，便开始像那个未曾存在的中书舍人一样说话、走路、避刀。债主若读完债券，阿宁就会在他的世界里已经画押。</p><p>每个人得到一篇最容易相信的墓志。</p><p>那些字不像在记死人，倒像在替活人预备一条可以走错的路。</p><p>梁成捂着肿起的半边脸，爬到碑座前。他想起石片上那句“留名者，补……”。</p><p>补什么，石片没有说完。</p><p>不得补字，不得拓全，不得命文。可碑座后的旧裂正张着口，像一句没有收住的断语。</p><p>他摸到怀里的户帖。</p><p>雨水快把墨泡花了，阿宁的名字还在。那个“宁”字被水晕开一点，末笔拖得很长，像一条细路。梁成忽然想起她初学写字的时候，常把宁字少写一横。他笑她，她便赌气似的把补上的那一横画得很长，说这样谁都不会漏看。</p><p>原来名字被看见，也会被抓住。</p><p>户帖能抓住阿宁，债券能抓住债户，匠籍能抓住梁成。碑里的文字也一样。它不缺道理，不缺诏令，不缺正史，它只缺一个肯被写上去、又肯被抹掉的人。</p><p>梁成低头看着那张户帖。女儿的名字还在。</p><p>那一刻他竟有点庆幸。庆幸自己只是个匠人，名不贵，命也不贵。拿来补这一道裂，也值了。</p><h2 id="真相"><a href="#真相" class="headerlink" title="真相"></a>真相</h2><p>第三日天亮前，碑里又有了声音。</p><p>这一次不是写字声。梁成听见女人咳嗽，咳得很轻，也很老。那声音隔着许多石头和年月传来，不像鬼，更像一个人醒着太久，终于厌了。</p><p>他没有看见武后本人。只看见一只手，把写好的碑文一页页放进火里。</p><p>那些碑文没有立刻烧掉。火舔到纸边，字反而更亮。每一篇都能自圆其说，每一篇都有证据，每一篇都能替一个不得安宁的时代找出罪人。梁成不识多少史，却看得懂其中的诱惑。人最怕的不是不知道自己为何受苦。人最怕的是有人递来一篇文章，把所有苦都解释得清清楚楚，还顺手给出一把刀。</p><p>武后晚年遇到的，或许就是这种东西。</p><p>它不是毒。毒入血，尚能验尸。它也不是妖书。妖书要靠人信鬼神，它却不需要。它只改人解释世事的方式。读懂某些句式以后，人会把眼前的一切都接到另一条线索上。旧友成了逆党，旧主成了篡贼，自己的犹豫成了天命之前最后一点软弱。</p><p>这样的文字若刻在碑上，就不会死。</p><p>碑文最适合活得久。一个皇帝死后留下的碑文，尤其不容轻慢。后世可以反驳它，却必须先读它；可以摹拓它，却会把它带到更远的地方。只要有一代人把那篇文字读全，它便能借那一代人的制度和怨气重新长出来。</p><p>梁成在幻象里看见许多次失败。</p><p>有一回，中宗命人补刻碑文，刻工读到半篇，丢下刀，夜里开了宫门。</p><p>有一回，史官把碑文抄入实录，二十年后，天下州县同时改用一个并不存在的年号。</p><p>还有一回，一个乱世军镇得了拓本，借武周正统起兵。起初只是一州一县的改旗，后来所有人都开始修改祖先，修改墓志，修改自己出生时该属于哪一个朝代。那条路走到尽头，活人不再按记忆相认，只按文本归类。父子可以因一篇墓志互为仇敌，夫妻可以因一行年号从未相识。</p><p>这些事都没有发生。</p><p>没有发生，不等于没有逼近过。</p><p>武后最后没有把自己的功业刻上去。她把最想说的话、最有资格说的话、最能说服人的话，全压进了无字之中。她交出去的是评价权。后人可以骂她，可以替她辩，可以编故事，可以在碑上题诗，也可以说她心机深重，死后仍要众人猜。都行。猜测是散的，争论是乱的，乱就安全。</p><p>不能有一篇唯一正确的碑文。</p><p>梁成醒来时，雨停了。</p><p>碑面那道裂缝变宽了一点，像一只刚睁开的眼。军吏死了一个，另一个被书吏按在泥里，嘴里念着陌生的官名。债主不知怎么挣开了绳，正趴在碎纸旁，用舌头舔纸上的灰。他一边舔一边含糊地说，契成了，契成了。</p><p>梁成走过去，把他推开。</p><p>债主抬头看他，忽然愣住：“你是谁？”</p><p>梁成没有答。</p><p>他捡起地上的石锤，把自己随身带的匠籍木牌砸碎。木牌上刻着他的名、籍贯、师承和保人。每砸一下，他胸口就空一点。接着是债券。他把债券从债主怀里抢出来，撕碎，混进石粉。</p><p>最后是私印。</p><p>那枚小印是他师父给的，石料不好，边角有缺。梁成平日舍不得用，怕越盖越损。此刻他把印放在碑座上，一锤下去，印文碎成红灰。</p><p>梁成。</p><p>两个字从碎石里冒了一下，又没了。</p><p>他把匠籍、债券、私印、拓纸浆、自己的血和雨水揉在一起，搓成一条细灰。灰很轻，却越揉越冷。他用竹片挑着，一点点填进裂缝。</p><p>碑在吸它。</p><p>不是石缝吃灰的那种吸法。更像一处旧伤终于等到了第一个愿意被按进去的名字。梁成的手指贴在碑上，听见身后有人喊他的名字。第一声很清楚，第二声少了姓，第三声只剩一个含混的音。</p><p>他没有回头。</p><p>裂缝快合拢时，碑面浮出一行小字。</p><p>亡匠梁成，京兆人。少习镌刻，手拙心迟。后唐某年九月，奉命修乾陵碑，三日后卒于陵下。</p><p>他看着那行字，等后面出现“有女，名宁，转籍不详”。</p><p>没有。</p><p>后面什么也没有。</p><p>梁成笑了一下。嘴里都是血，笑得不好看。他抬手，把最后一点灰抹上去。碑面冷得像冬天的井水。那行墓志从末尾开始退，先没了卒年，再没了籍贯，然后是他的名。</p><p>到天亮时，碑上仍然没有正式碑文。</p><h2 id="余波"><a href="#余波" class="headerlink" title="余波"></a>余波</h2><p>节帅的人在午后赶到。他们看见一地碎纸、一个疯了的书吏、两个互相指认为逆党的军吏，还有一个说不清自己为什么在陵下的债主。</p><p>债主手里拿着一张户帖。上面写着阿宁的名字，良籍无误，父栏却是空的。债主说这帖原本押在他处，可又说不出押的是谁。匠行的账册后来也翻过，某一页缺了半行，前后债目都在，唯独债主追索的那笔没了债户。</p><p>有人问：“修碑的匠人呢？”</p><p>没人答得上来。</p><p>他们在碑座旁找到一只石锤。锤柄磨得很旧，像被人用过许多年。可匠行无人认领。行首看了半晌，只说这手艺眼熟，再问眼熟在哪里，他又摇头。</p><p>节帅最终只得到一张空白拓本。纸很大，墨色匀，石纹清楚，确实是乾陵无字碑。没有诏令，没有册命，没有天命可借。他发了火，砍了书吏，又把债主关了几日。可州城很快有别的仗要打，这件事便丢在后头。</p><p>那张拓本后来不知所终。</p><p>阿宁拿回了自己的户帖。她在匠行门口等了三天，第四天被一个卖纸的寡妇收留。很多年后，她也学会了补纸。有人送来破损的契券、族谱、墓志，她总能把缺处补得很平。只是她有个怪癖，从不替人补名字。</p><p>别人问为什么，她说名字不能乱补。</p><p>再后来，乾陵无字碑上开始有了后人的题刻。起初是一两处，后来越来越多。游人留下诗，官员留下名，异族使者留下旁人读不懂的文字。有人嫌它们坏了古碑，有人把它们当成史料。无论怎样，它们都在碑面上，像一层又一层杂声。</p><p>杂声有时比寂静安全。</p><p>真正危险的文字怕的不是被遮住，而是被完整地读出来。零碎题刻、游人感慨、错讹的摹本、争执不休的解释，都能把那篇正式碑文压回深处。后世越争，碑越稳。人们围着它说武后，说功罪，说无字的用意。每一种说法都离真相很近，又都不够完整。这样正好。</p><p>乾陵仍在那里。</p><p>今天的人站在碑前，会看见满碑题刻，然后听讲解说它叫无字碑。多数人会觉得矛盾，拍照，笑一笑，转身去看下一处石像。少数人会停得久一点，盯着那些后刻的字，想象原本该有怎样一篇大字刻在中间。</p><p>想象可以。</p><p>不要读见。</p><p>在碑座靠下的地方，有一道并不起眼的旧裂。修补痕迹和石色几乎融在一起，只有雨后近看，才会觉得那道纹路弯得古怪。它不像普通裂缝，更像一个很古的“水”字。笔画不正，像小孩少写了一横，又倔强地补长了。</p><p>没有人知道它是谁补的。</p><p>这也很好。</p><p>无字碑最稳的时候，本来就不该有谁的名字。</p>]]>
    </content>
    <id>https://hyacehila.github.io/blog/2026/05/10/epitaph-protocol-01-wordless-stele/</id>
    <link href="https://hyacehila.github.io/blog/2026/05/10/epitaph-protocol-01-wordless-stele/"/>
    <published>2026-05-10T04:00:00.000Z</published>
    <summary>On a rainy night, the Wordless Stele at Qianling reveals to each reader the official history they already believe; an indebted stonemason must seal an old crack with his own name.</summary>
    <title>Epitaph Protocol 01: Wordless Stele</title>
    <updated>2026-07-01T15:56:19.865Z</updated>
  </entry>
</feed>
