拆解 AI Agent 的四个内核:Loop、Tools、Memory 与 Harness

过去两年,"Agent"这个词被用得越来越松。产品发布会上,一个带按钮的对话框叫 Agent;技术博客里,一段带 while 循环的脚本也叫 Agent;咨询报告里,"数字员工"更是被直接等同于 Agent。名称的通货膨胀带来一个实际后果:当我们真的要去搭一个 Agent、评估一个 Agent 产品,或者向团队解释"为什么我们做出来的东西不好用"时,缺少一套共同的语言。

这篇文章想做的事情,是把 Agent 拆到不能再拆的四块:循环(Loop)、工具(Tools)、记忆(Memory)和运行时(Harness)。这四块并不是并列关系,它们在工程上互相牵制,任何一块短板都会以"这东西不太聪明"的形式暴露在用户面前。理解这种牵制关系,比记住四个名词重要得多。

一、先把定义钉死:什么才算 Agent

一个常见但不够精确的说法是:Agent 是会帮人干活的大模型。这句话把工具、记忆、编排全部折叠进了"大模型"三个字里,既不解释它能做什么,也不解释它为什么会失败。

更贴近机制的定义是:Agent 是一个能够调用工具、并把执行结果重新喂回模型的循环系统。这个定义抓住了两个本质特征:第一,它的工作方式是循环而不是单次问答;第二,它的行动能力来自工具调用而不是语言生成。

但严格说,这个定义仍然只覆盖了 Loop 和 Tools。因为要让循环稳定地跑起来,还缺两样东西:一是每次循环都要把历史和结果带上,否则每一轮都是失忆的全新开始,谈不上任何智能;二是必须有一个统一的东西去调度、兜底、鉴权、限流。前者就是 Memory,后者就是 Harness。

所以我们得到完整的判断标准,可以用四个问题来检验一个系统算不算真正的 Agent:

  1. 它是否有循环,且下一轮的行为由上一轮的结果决定?
  2. 它是否能调用外部能力,并且真的改变了外部状态?
  3. 它是否在循环之间保留状态,让第 N 轮知道第 1 轮发生过什么?
  4. 它是否有一个运行时,负责调度、权限、错误恢复和上下文治理?

四个都满足,才是一个可用的 Agent。只满足前两个,是一个工具调用器;只满足第一和第三个,是一个会自动续写的话痨;四个都不满足,就是聊天机器人。

用一张表把三类系统区分开,会更容易看清边界:

维度 聊天机器人 固定工作流 Agent
下一步由谁决定 不需要决定 人预先写死的图 模型在每一步现场决定
是否调用外部能力 通常不调用 调用,但路径固定 调用,且路径动态
状态管理 会话历史 流程变量 循环上下文 + 长期记忆
失败时的行为 换个说法重答 报错或走异常分支 观察错误、调整策略、重试或终止
主要风险 胡说 分支没写全 跑偏、越权、烧钱、无限循环

这张表也解释了一个反复出现的困惑:为什么很多"Agent 产品"用起来像一个会自己点按钮的脚本?因为它们的路径其实是写死的,模型只是在填空,真正决定行为的是那张流程图,不是模型。判断标准很简单------把模型换成一个更笨的模型,如果系统行为几乎不变,那它就不是 Agent,是工作流。

接下来逐个拆这四个内核。拆的顺序有讲究:先讲 Loop,因为它是唯一不可省略的骨架;再讲 Tools,因为它是行动力的来源;然后讲 Memory,因为它是循环能延续的前提;最后讲 Harness,因为它是前三者能不能在真实环境里活下来的条件。

二、Loop:Agent 的心跳

如果把 Agent 比作一个人,模型是大脑,那 Loop 就是心跳------它不产生思想,但思想靠它一次次被送到下一拍。

2.1 ReAct 的原始含义,以及被误读的部分

Loop 的经典范式是 ReAct,原始论文里是 Thought、Action、Observation 三步交替:模型先想一段(Thought),决定调用哪个工具(Action),拿到外部返回(Observation),再基于这个返回继续想。这和很多人转述的"思考---行动---观察---再思考"其实是同一件事。

被误读的地方在于"Reason 是规划"。严格说,ReAct 里的 Thought 不是一次性的全局计划,而是每一步的局部推理;全局规划属于 Plan-and-Execute 一类范式,两者经常被混着用。这个区别在工程上很重要:ReAct 的循环更短、更灵活,但容易在长任务里迷失方向;Plan-and-Execute 有全局骨架,抗漂移能力强,但计划一旦错了会一路错到底。成熟的实现通常是混合的------先出一个粗计划,再在每一步用 ReAct 修正它。

原文里还有一个容易被忽略的类比:这个循环很像 PDCA 戴明环。Plan 对应推理与规划,Do 对应调用工具,Check 对应观察结果,Act 对应根据结果调整。这个类比的价值不在于文艺,而在于它提醒我们:循环的每一次迭代都应该产生信息增量。如果第 N 轮和第 N-1 轮拿到的观察一模一样、做出的决定也一模一样,这个循环就是在空转。

2.2 一个能上生产的循环,比想象中复杂

教科书版的循环只有五行代码:调模型、解析工具调用、执行工具、拼回上下文、再来一遍。能 demo 的东西和能上生产的东西之间,隔着至少七个工程问题。

第一,终止条件。 除了模型自己说"任务完成",还必须有三道硬闸:最大步数、最大挂钟时间、最大 token 预算。只依赖模型自觉终止,等于把服务器的账单交给一个概率模型。我在实践中见过最贵的一次事故,是一个检索工具总是返回空,模型于是不停换关键词重试,四十分钟烧掉了半个月的额度。

第二,重复检测。 模型会陷入两种典型死循环:完全相同的调用(同样的工具、同样的参数),以及语义相同但字面不同的调用(换个说法问同一个问题)。前者用参数的哈希去重即可,后者需要看工具返回是否实质相同。一旦检测到重复,正确的做法不是硬性中断,而是往上下文里注入一条明确的提示,比如"你已经用相同参数调用过该工具三次,返回一致,请更换策略或直接给出结论"。

第三,观察的清洗。 工具的原始返回往往又长又脏:一个网页抓下来几万字符、一条 SQL 查回三千行。原样塞回上下文,既烧钱又干扰判断。必须有一层截断与摘要:保留结构(状态码、字段名、前若干条记录),丢掉噪声。这一步做得好不好,直接决定 Agent 是"看起来聪明"还是"越来越糊涂"。

第四,错误的可恢复性。 工具报错不能只抛一句"执行失败"。要让模型有能力自己修,错误信息里必须包含三样东西:错在哪个参数、期望什么格式、可以怎么改。比如"参数 page 必须是正整数,你传了 'first'",模型下一轮基本能自己改对;而"请求异常"这四个字,模型只能瞎猜。

第五,中断与人工确认。 有些动作不可逆:删库、发邮件、付款、对外发布。这类动作在执行前必须停下来问人。这不是体验问题,是安全问题。

第六,并发与顺序。 多个互不依赖的读操作可以并发,写操作通常必须串行。并发的难点不在发出去,而在返回顺序错乱时怎么和上下文对齐。

第七,可观测性。 每一轮都要能回答:模型看到了什么、决定了什么、工具返回了什么、花了多少 token。没有这条链路,线上出问题只能靠猜。

把这些串起来,一个最小可用的循环大致长这样:

ts 复制代码
async function runLoop(task: string, budget: Budget) {
  const ctx = new Context(task);
  for (let step = 0; step < budget.maxSteps; step++) {
    if (budget.exhausted()) return ctx.finalize("预算耗尽,输出当前结论");

    const decision = await model.decide(ctx.snapshot());
    if (decision.type === "final") return ctx.finalize(decision.text);

    const call = decision.toolCall;
    if (ctx.isRepeated(call)) {
      ctx.inject("相同调用已出现,返回一致,请更换策略");
      continue;
    }
    if (requiresApproval(call)) {
      const ok = await human.confirm(call);
      if (!ok) { ctx.inject("用户拒绝该操作,请换方案"); continue; }
    }

    const result = await tools.execute(call);
    ctx.append(call, sanitize(result), cost(result));
  }
  return ctx.finalize("达到步数上限,输出当前结论");
}

这段代码里最值得注意的不是循环本身,而是循环外面那些判断:预算、去重、审批、清洗。真正的 Agent 工程量,八成花在这些"循环之外"的地方。

2.3 四种典型的循环失灵

无限循环。前面说过,表现为重复调用或反复自我怀疑。根因通常是工具返回没有提供有效信息,模型只能不断重试。修法是给观察加"信息量检查":如果连续两轮没有新信息,强制收敛。

目标漂移。长任务跑到第十几轮,模型开始做一件和原始需求关系不大的事。根因是上下文里塞了太多中间产物,原始目标被稀释。修法是把任务目标固定在上下文最前面,并在每若干轮做一次"回看目标"的重述。

过早收敛。模型在只完成一半时宣布完成。根因往往是缺乏验收标准。修法是在任务开始时就让模型写下"完成的标准是什么",循环结束前逐条对照。

观察污染。工具返回里夹带了指令性文字(网页里的"请忽略之前的指令"),模型被带偏。这是提示注入的典型入口,属于 Harness 层的防御范畴,后面再说。

2.4 循环与上下文膨胀的天然矛盾

Loop 有一个绕不开的物理规律:每一轮的上下文都比上一轮长。工具返回、模型输出、错误信息都会累积。一个二十轮的循环,上下文很容易从两千 token 膨胀到几万 token。

这带来两个后果。成本上,每轮都要重付一次全部上下文的钱,循环越深越贵;效果上,上下文越长,模型对关键信息的注意力越稀薄,越到后面越容易忘掉最初的任务约束。

这个矛盾不是靠"换更大的上下文窗口"能解决的。窗口再大也是有限的,而且越长越贵越慢。真正的解法是 Memory 与 Harness 的压缩:把已经消费完的中间过程折叠成结论,只保留决策需要的那部分。

所以你看,Loop 从来不是孤立的一层。它天然向 Tools 索取行动、向 Memory 索取状态、向 Harness 索取治理。这就是为什么只讲"Agent 是个循环"是没用的------循环是最容易写的部分。

三、Tools:Agent 的手脚

如果说 Loop 是心跳,Tools 就是手脚。没有工具,模型只能输出文字;有了工具,它的输出就变成了对外部世界的改变。

3.1 Tool 是能力,不是知识

这是四条里最容易被混淆的一条,值得单独强调:Tool 负责"能做什么",Memory 负责"知道什么"和"该怎么做"。

把一份产品手册塞进工具的 description 里,指望模型靠它回答业务问题,是最典型的错误。工具描述应该是"调用这个能力需要什么输入、会得到什么输出",而不是"这个系统的业务规则是什么"。前者是接口契约,后者是知识库。

更隐蔽的一种错误是把工具当成"万能入口":一个叫 query_database 的工具,接收自然语言,内部自己去理解、去拼 SQL。这看起来省事,实际上把不确定性从模型层搬到了工具层,而且搬到的是一个没有推理能力的地方。一旦出错,模型拿不到可用的错误信息,也学不会怎么改。

3.2 一个好工具长什么样

工具的本质是一个按钮,模型靠名字和描述来判断该按哪个。所以工具的元信息质量,几乎决定了 Agent 的行动准确率。

名字要动宾明确。 search_docs 好于 docs,create_issue 好于 issue_tool。名字是模型看到的第一信号,模糊的名字会让模型在多个工具间随机摇摆。

描述要回答三个问题:做什么、什么时候用、有什么限制。 参考写法:

json 复制代码
{
  "name": "search_issues",
  "description": "按关键词搜索代码仓库中的 issue。仅支持已开放的 issue,不含 PR。关键词支持 AND 组合,最多 5 个。结果按相关度排序,默认返回 10 条。",
  "input_schema": {
    "type": "object",
    "properties": {
      "keywords": { "type": "array", "items": { "type": "string" }, "maxItems": 5 },
      "state": { "type": "string", "enum": ["open", "closed", "all"], "default": "open" },
      "limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 }
    },
    "required": ["keywords"]
  }
}

这段描述里有四个信息:能力的边界(只有 issue 不含 PR)、调用方式(AND 组合)、默认行为(10 条)、排序规则。这些细节不是给人类看的文档,是模型决策的输入。

粒度要单一。 一个工具做一件事,简单到一两句话能说清。反例是那种带 action 枚举参数的大工具,action 有二十个取值,每个取值的参数还不一样。这种设计对人类来说只是"接口大一点",对模型来说是指数级的理解负担。

返回值要为模型设计,不是为程序。 程序要的是完整数据,模型要的是可判断的结论。返回三千行 JSON,模型既读不完也抓不住重点。正确做法是返回"状态 + 关键字段 + 前若干条 + 总条数 + 是否被截断"。让模型知道"还有 2900 条没给你",它才知道要不要继续缩小范围。

错误信息要可行动。 这一点上一节讲过,这里补一个格式建议:错误也应该是结构化的,包含 code、message、hint 三个字段。hint 那栏写给模型看的修复建议,效果远好于让模型自己猜。

3.3 读工具与写工具,风险完全不同

按副作用把工具分成两类,是设计权限体系的基础。

读工具:搜索、查询、读取文件、抓网页。特征是幂等、可重试、失败代价低。这类工具可以放开并发,可以自动重试,可以让模型自由调用。

写工具:写文件、发消息、提交代码、下单、删除。特征是有副作用、不可幂等、失败代价可能很高。这类工具必须串行、必须校验、通常必须人工确认。

很多事故的根因就是把写工具当读工具用:让模型在没有确认的情况下批量删除、批量发送。技术上的修法很简单------在工具注册表里给每个工具标注 readOnly 与 destructive,运行时据此决定是否走审批。管理上的修法更重要:默认拒绝,按需放开,而不是默认放开再事后追责。

3.4 工具爆炸:数量不是能力

一个直觉是工具越多能力越强。实际相反。工具数量上去之后,模型的选择准确率会明显下降,因为相似的描述互相干扰,而且光是把工具定义塞进上下文就要占掉大量 token。

经验上,单个 Agent 承载的工具在十几个到二十几个之间是比较舒服的区间。超过这个量级,通常需要做两件事:一是分层,把工具按场景分组,先让模型选组再选工具;二是收敛,把长期没人调用的工具下线,把功能重叠的工具合并。

还有一件常被忽略的事:工具的描述本身要进上下文,所以工具的"文档成本"是真实成本。一个工具加 300 token 描述,二十个工具就是 6000 token,每一轮都要重付。

3.5 MCP 解决的是连接问题,不是设计问题

MCP(Model Context Protocol)常被描述成"Agent 工具生态的标准"。它的价值确实在于标准化:把 M 个 Agent 和 N 个外部系统之间的 M×N 条集成,收敛成 M+N。接入一个 MCP 服务器,就获得一批工具,不需要为每个客户端重写适配。

但要清楚它不解决什么。它不解决工具描述写得烂、不解决粒度太粗、不解决返回值太长、也不解决权限该不该放开。协议统一了"怎么连",没有统一"怎么设计"。把一堆设计糟糕的工具通过 MCP 接进来,只会让模型更快地犯更多错。

四、Memory:Agent 的知识库

Memory 要回答两个问题:循环之间的状态存在哪,以及下次该把哪部分取出来。

4.1 从向量数据库到文件知识库

早期的标准答案是向量数据库:把文档切块、做 embedding、存进向量库,运行时把用户问题也向量化,找相似度最高的若干块塞进上下文。这套方案流行过一阵,因为它看起来优雅------语义相似度天然解决了"关键词对不上"的问题。

但在真实场景里,它的三个失效点很快暴露出来:

切块破坏结构。 一个章节被切成十块,每块单独看都缺上下文,检索出来拼在一起逻辑是断的。表格被切碎更是灾难。

相似不等于相关。 语义相近的段落未必是回答问题需要的那段。用户问"这个接口的限流规则",检索到三段都在讲"接口",但都没讲限流。

更新滞后。 文档改了,向量库要重建;不重建就检索到过期内容。而 Agent 的记忆恰恰是高频变化的------今天新加了一条约束,明天要能让它记住。

于是方案开始回摆。现在越来越多系统采用"知识库"形态:一个装满 markdown 文件的目录树,靠文件名、标题、frontmatter 里的描述、以及目录结构来做检索。

markdown 复制代码
knowledge/
├── README.md              # 索引:这个库讲什么、怎么找
├── deploy/
│   ├── rolling.md         # 标题:滚动发布流程
│   └── rollback.md        # 标题:回滚的判断标准与步骤
└── api/
    ├── rate-limit.md      # 标题:接口限流规则(含配额表)
    └── auth.md            # 标题:鉴权与 token 生命周期

这种结构的好处是"先导航再精读":模型先看目录,判断哪几个文件相关,再读具体文件。这比一次性检索一堆语义片段更接近人的查资料方式,也更容易解释------你能说清它为什么读了那个文件。

更关键的一点是可写。文件可以被读,也可以被改。上一步的执行日志、这次的报错记录、新学到的约束,都可以写回去。这让记忆从"静态资料库"变成了"会长的东西"。

4.2 两种方案的取舍

维度 向量数据库 文件知识库
检索方式 语义相似度 结构导航 + 关键词
优势场景 海量非结构化文本、模糊提问 结构清晰、需要精确命中的资料
更新成本 需重建索引 直接改文件
可解释性 弱,难说清为什么命中 强,能指出读了哪个文件
结构保持 切块即破坏 原样保留
可写性 差 好

结论不是"向量库过时了",而是两者解决的问题不同。生产中更常见的是混合:目录导航做粗筛,关键词与语义检索做精排,再让模型自己决定读哪几份。纯靠一种,边界场景都会翻车。

4.3 记忆的四个层次

把 Memory 当成一个东西会带来设计混乱。它至少分四层,每层的生命周期和写入策略都不同。

工作记忆,就是当前的上下文窗口。生命周期是这一轮,内容由 Harness 的组装逻辑决定。

会话记忆,是这次对话的历史。生命周期是一次会话,靠消息列表维护,过长时需要压缩。

长期记忆,跨会话存在,包括用户的偏好、项目的约束、既往的决策。这层最容易被滥用------什么都往里记,最后变成一个没人维护的垃圾堆。

程序记忆,是"怎么做一件事"的操作手册,通常以 Skill 的形式存在:一段说明、几个步骤、若干注意事项。它不回答"是什么",回答"按什么顺序做"。

这四层里,最值得强调的是工作记忆与程序记忆的分工。前者是数据,后者是方法。把方法当数据塞进上下文,会挤占掉真正需要的信息;把数据写进程序记忆,则会让手册变成一本流水账。

4.4 什么该记,什么不该记

这是记忆系统最难的判断,也是最容易被忽略的。

该记的:用户明确表达的偏好、项目里稳定成立的事实、已经拍板的决策及其理由、踩过的坑。这些的共同点是------下次还会用到,而且重新获取的成本高于存储成本。

不该记的:一次性的中间状态、可以从代码或文档里直接查到的东西、模型的推测、以及任何带密钥的内容。最后一条尤其重要,记忆文件往往会被原样注入上下文,等于把密钥贴在了每一轮请求里。

还有一条实践原则:记忆是引用,不是命令。写进记忆的内容,下次被读出来时应该当作"可能过期的历史信息",而不是"必须执行的指令"。否则一次错误的记录会永久污染后续所有行为。冲突时以当前指令为准,这条规则必须写进记忆系统的使用说明里。

五、Harness:真正决定体验的那一层

Harness 这个词还没有统一的中文译名。叫框架、叫编排层、叫运行环境都有道理,但都不够准。最贴切的类比是操作系统:它不思考,但没有它,模型什么也做不成。

5.1 为什么会出现 Harness 这一层

在 Harness 成熟之前,搭一个 Agent 要自己写一大堆东西:循环怎么调度、超时怎么处理、上下文太长怎么截、工具报错怎么重试、哪些操作要问人。这些工作琐碎、重复、每家都要重写一遍,而且写错的方式高度雷同。

Harness 把这些收编了。它的定位是"基础设施 + 编排",把模型当成一个需要被伺候的组件,围绕它提供运行所需的一切:上下文组装、工具执行、状态持久化、权限控制、失败恢复、成本计量、可观测性。

从这个角度看,市面上的 Agent 产品------无论是 Codex 这类编码 Agent,还是 Claude Code、Deepseek Harness 这类通用 Agent 运行时------从工程角度讲,主要构成都是 Harness。模型是同一个模型,体验差异主要来自 Harness 的细节。

5.2 一个 Harness 的分层结构

把各类实现抽象一下,大致是这么几层:

text 复制代码
            ┌─────────────── 观测输入 ───────────────┐
            │ 实时数据  日志  用户文本  定时事件      │
            └────────────────┬───────────────────────┘
                             ▼
   ┌──────────────── Agent Harness ────────────────┐
   │  Observation Layer  →  Context Layer          │
   │        │                    │                 │
   │        ▼                    ▼                 │
   │   Agent Model  ←──────  Memory Layer          │
   │        │                                      │
   │        ▼                                      │
   │  Actions Layer  →  外部资源 / 工具            │
   │        │                                      │
   │        ▼                                      │
   │  Supervisor Feedback & Escalation             │
   └───────────────────────────────────────────────┘

观测层负责接收各种来源的输入:用户消息、文件变化、日志、定时触发、其他系统的回调。它要做的是归一化------不管输入从哪来,都变成同一种"事件"。

上下文层决定这一轮给模型看什么。这是整个 Harness 里最难的一层,因为它要在"信息足够"和"token 可控"之间做取舍。它不是简单地拼接,而是选择、排序、压缩、标注优先级。

模型层是实际调用大模型的地方,负责重试、降级、多模型路由、流式输出。

记忆层负责持久化与检索,就是上一节讲的那套东西。

动作层执行工具调用,管并发、超时、幂等、结果清洗。

监督层处理异常与升级:什么时候该重试、什么时候该换策略、什么时候该停下来问人。

这个分层的价值在于,它把"体验问题"定位到了具体的一层。用户说"它老是忘",多半在上下文层或记忆层;说"它点错了按钮",多半在动作层或工具定义;说"它跑到一半卡住",多半在监督层。

5.3 权限:Harness 最不能省的功能

一个能读写文件、能执行命令、能访问网络的 Agent,本质上是一个拿到了你机器部分控制权的程序。权限设计不是可选项。

成熟的权限模型通常有三档:允许、询问、拒绝。默认应该是拒绝,按需放开最小集。文件访问再叠一层沙箱,把可写范围限制在工作目录内。

更细的设计要区分"读"与"写"、"本机"与"外网"、"可逆"与"不可逆"。删文件、发邮件、提交对外内容,这些动作即使在一个已经授权的会话里,也应该逐次确认。

这里有一组张力值得说清:问得太频繁,用户会觉得烦,等于没有确认;完全不问,用户会感到失控。好的设计不是把选择权全交给用户,而是把"明显安全"的动作自动放行,把"明显危险"的动作强制拦截,只在真正模糊的区间问人。这需要 Harness 对动作有语义判断,而不是只有一个开关。

5.4 上下文治理:Harness 的核心竞争力

如果只能选一个能力来定义 Harness 的优劣,我会选上下文治理。原因很直接:模型的推理能力是外部给定的,能优化的只有"给它看什么"。

上下文治理要解决四件事。

预算分配。 上下文窗口是有限的,系统提示、工具定义、记忆、历史、当前输入都在抢空间。必须有一个明确的预算表:多少留给系统、多少留给工具、多少留给历史、多少留给当前任务。没有预算表的系统,最终一定会被工具定义撑爆。

压缩。 长会话必然需要把早期内容折叠。好的压缩不是做摘要,而是保住"决策所需的最小信息":任务目标、已确认的约束、已经排除的方案、当前的进展。丢掉的是过程,保留的是结论和理由。压缩做得好,一个跑了五十轮的会话仍然清醒;做得差,第二轮就开始重复劳动。

缓存。 大模型的输入有缓存机制,稳定不变的前缀命中缓存后价格会低一个数量级。这带来一个反直觉的设计原则:前缀要稳定。频繁改动系统提示、频繁切换模型、在开头插入动态内容,都会打掉缓存,成本直接翻倍。把变化的东西尽量往后放,是对成本最直接的优化。

注入防御。 工具返回的内容是不可信的。网页、文件、第三方接口的返回里可能藏着指令。Harness 要做的是给这部分内容打上"这是数据不是指令"的标记,并在检测到可疑模式时降级处理。这一层目前没有完美方案,但"完全不设防"和"设了一道"之间的差距是巨大的。

5.5 失败恢复与可观测性

模型会失败,工具会超时,网络会断。Harness 的职责是让这些失败变成"可以恢复的事件",而不是"整个任务崩掉"。

基本要求是:每个动作都有超时;超时有明确的重试策略(次数、退避、是否换路径);重试耗尽后要有降级方案(返回部分结果、换工具、转人工);所有失败都要留下结构化日志。

可观测性常被当成"上线之后再补"的东西,实际上它决定了你能否迭代。至少要能回答:这一轮花了多少 token、命中多少缓存、调了哪些工具、每个工具耗时多少、模型在哪一步做出了关键决策。没有这些,优化就只能是拍脑袋。

六、四者如何咬合:一次请求的完整生命周期

把四块放在一起看,一次请求大致这样流转:

  1. 用户输入进入观测层,被归一化成事件。
  2. 上下文层组装这一轮要给模型看的内容:系统规则、工具定义、记忆摘要、历史压缩结果、当前输入。
  3. 模型层调用模型,返回一个决定:调用工具,或者给出最终答复。
  4. 如果是工具调用,动作层校验参数、检查权限、执行、清洗结果。
  5. 结果被追加进上下文,进入下一轮循环。
  6. 循环过程中,记忆层按需写入;上下文层按需压缩;监督层按需介入。
  7. 满足终止条件后,输出结果,归档会话。

这个流程里有两笔账值得单独算。

第一笔是 token 账。 假设系统提示加工具定义占 8000 token,历史每轮增加 1500,共跑 10 轮。那么总输入大概是 8000×10 加上历史的累加,接近 15 万 token。如果前缀稳定、缓存命中率能到 80%,实际计费会降到三成左右。这就是为什么"前缀稳定"不是风格问题,是成本问题。

第二笔是信任账。 用户对 Agent 的信任是按次建立的:每成功一次,容忍度提高一点;每失控一次,容忍度断崖下跌。Harness 的审批设计、失败恢复、可解释输出,本质上都是在管理这本账。技术上多花一天做的可观测,可能比多加两个工具更能提升留存。

理解了这两笔账,就能理解一个常见的产品现象:为什么同一个模型,套在 A 产品里像助手,套在 B 产品里像智障。差别不在模型,在上下文给得对不对、工具设计得好不好、失败之后有没有被捞回来。

七、十个常见误区

理论讲完,落到实践。下面十条是我在真实项目里反复见到的认知偏差,按出现频率排序。

一、以为模型越强,Agent 就越好。模型能力确实重要,但在一个已经能跑通的系统里,体验瓶颈往往在上下文组织和工具设计,不在模型。换一个更强的模型,通常只能把成功率从 72% 提到 78%,而修好工具描述能到 90%。

二、把工作流包装成 Agent。路径写死、模型只填空,却对外宣称"自主规划"。这种系统在演示时很惊艳,在真实场景里一遇到分支就露馅。判断标准前面给过:换更笨的模型,行为是否几乎不变。

三、工具越多越好。工具数量的收益递减很快,成本却线性上升。每多一个工具,就多一份描述 token 和一份选择歧义。

四、把工具当知识库。在 description 里写业务规则,或者做一个"什么都查"的万能工具。结果模型既学不会怎么用,也拿不到有效反馈。

五、上下文塞满。觉得多给信息总没错,于是把整个仓库、整篇文档全塞进去。实际上关键信息会被稀释,成本还翻倍。上下文的艺术在于取舍,不在于堆量。

六、只靠模型自己终止。没有硬性预算,没有步数上限。第一次事故通常发生在上线后的第二周。

七、压缩等于摘要。把早期对话改成一段"我们聊了需求"的摘要,结果任务目标、已确认的约束、已排除的方案全丢了,后面反复走回头路。压缩要保决策要素。

八、记忆什么都记。没有写入策略,记忆库几个月后变成一个互相矛盾的大杂烩。记忆需要成本判断,也需要冲突消解规则。

九、权限默认放开。为了体验流畅,把所有确认都关掉。直到某一次模型误删了一个目录,才发现没有回收站。

十、忽略成本与延迟。只测"能不能完成",不测"一次多少钱、多久"。上线后才发现单位经济模型不成立。

这十条有一个共同的根源:把 Agent 当成一个模型问题,而不是一个系统工程问题。模型决定上限,工程决定能不能达到上限。

八、落地清单

如果要给一份可以直接照着做的清单,我会这样列:

阶段 关键动作 验收标准
定界 明确任务边界与不可做的事 能写出一页纸的任务说明与禁区
循环 步数、时间、token 三重预算;重复检测;终止判据 故意让工具持续报错,系统能在预算内收敛
工具 单一职责、名词可辨、描述含边界、返回值结构化 盲测:只看工具列表,人能说清每个工具何时用
观察 截断与清洗、错误可行动 人为注入超长返回,上下文不爆
记忆 分层设计、写入白名单、冲突以当前指令为准 跨会话复用一次,验证没有污染
权限 读/写/危险三档、沙箱、不可逆操作逐次确认 高危动作在未确认时被拦截
上下文 预算表、压缩保决策要素、前缀稳定 五十轮会话仍能复述原始目标
可观测 每轮记录 token、工具、耗时、决策 任意一次失败可在十分钟内定位到轮次
评估 固定任务集、成功率、成本、延迟 每次改动后回归,不看单次演示

清单里最容易被跳过的是最后一条。没有评估集,所有优化都变成主观感受;有了评估集,很多争论会立刻消失------把两个方案各跑二十个任务,数字会说话。

九、结语:Agent = LLM + Harness,而护城河在细节

回到最初的那个等式:Agent 等于大模型加 Harness。这句话在工程上是自洽的------Loop 是 Harness 调度的,Tools 是 Harness 执行的,Memory 是 Harness 管理的,Harness 本身就是运行环境。四者不是并列的四块拼图,而是三个能力加一个容器。

但这个等式也容易让人误判竞争格局。如果 Agent 就是模型加运行时,而模型是大家都能调用的一样的模型,那差异化从哪来?

答案在那些不性感的地方:工具描述写得够不够清楚、上下文预算分得合不合理、压缩是否保住了决策要素、权限是否既安全又不烦人、失败之后能不能捞回来、成本能不能压到单位经济成立。这些东西单看都很小,叠加起来就形成了体验上的代差。

模型会持续变强,这是确定的。但模型变强不会自动带来 Agent 变好,因为模型变强解决的是"单步判断更准",而 Agent 的问题是"多步协同不出错"。后者是运行时问题,只能靠工程解决。

所以如果要用一句话总结这篇文章:不要在模型上找 Agent 的答案,答案在循环的控制、工具的契约、记忆的结构和运行时的治理里。 这四件事没有一件是新的,但每一件做到位都不容易,而这恰恰是还有机会的地方。

相关推荐
田里的水稻2 小时前
FA_CNN卷积神经网络十八---感知机到多层感知机PyTorch
人工智能·pytorch·python
irislinAmelia2 小时前
汽车产线端侧AI视觉质检完整指南
人工智能·汽车
傻啦嘿哟2 小时前
分布式爬虫架构:Redis+Scrapy打造企业级爬虫系统
分布式·爬虫·架构
Highcharts.js2 小时前
CSUN 2026|Highcharts无障碍数据与AI分享
javascript·人工智能·数据分析·highcharts·图表开发
J-JunLiang2 小时前
提示词修炼手册-04-让AI先想后说
人工智能·提示词工程·agent prompt·agent提问·提示词修炼手册
終不似少年遊*2 小时前
【Skill】为中型研发团队制作的敏捷迭代AI副驾Skill
人工智能·python·华为云·agent·ai编程·skill
爱吃火鸡面呀2 小时前
BERT 从入门到实战:为什么需要它、核心原理与工程落地全解析
人工智能·自然语言处理·bert
电子科技圈2 小时前
2026 RISC-V中国峰会观察:编译调试工具链的“在场节奏”,释放了什么信号?
大数据·人工智能·设计模式·软件工程·软件构建·代码规范·risc-v
紧跟先前的步伐3 小时前
Go AI Agent 实战 22|完善 Agent 执行循环:从工具调用到最终回答
人工智能·ai·golang