前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版

AI Agent 系统学习指南 Harness 工程、KV Cache 前缀失效、上下文压缩与评估的 JS 实战

首页2026-09-14 15:12:33Front-End
AI AgentLLMNode.js上下文工程

文章首发于: https://feinterview.poetries.top/blog/ai-agent-harness-engineering

某个客服 Agent 每天跑 10 万次对话,一直好好的。某天工程师为了让它知道当前时间,在系统提示词里塞了一行实时注入的时间戳。第二天监控告警,首 token 延迟从 0.5 秒涨到 3-5 秒,月度推理账单差不多翻了一倍。

代码没报错,模型也没换。

这篇是我这段时间的一份系统性整理,按「一个 Agent 从 Demo 走到生产要依次补上哪些东西」排的顺序,每一节都配了能跑的 JavaScript。这个领域的资料大多是 Python 视角的,这里的代码全部是我用 Node 重写过的。

先说这篇最想传达的那个判断:当各家模型能力越来越接近,Agent 的竞争力就从模型本身转移到了模型之外那一层工程实践上。

本文会依次回答这些问题:

  • Agent 这个词拆开之后,工程师真正能动的是哪几块?
  • 不用任何框架,最少多少行代码能跑起一个 Agent?
  • 上下文窗口里到底装了什么,各部分的成本和寿命有什么区别?
  • 一行时间戳为什么能让账单翻倍,怎么写才不炸缓存?
  • 工具返回的结果,为什么不能当成普通 user 消息塞回去?
  • Agent 老是数不清自己干过几次同样的事,怎么办?
  • ReAct 循环之外,生产级 Agent 还缺哪三件事?
  • 上下文快满了要压缩,压缩会不会把 KV Cache 全打掉?
  • 怎么让 Agent 跨会话记住用户,RAG 要做到什么程度?
  • Agent 老选错工具,该换个更强的模型还是改工具描述?
  • 怎么用数据证明你改的东西真的有效,而不是感觉上有效?
  • 什么时候才真的需要上多 Agent?
  • 线上出了问题,怎么从轨迹里把它捞回来?
  • 新踩到的经验,该进知识库、提示词、代码还是模型参数?
  • 选模型时除了准确率,还有哪几个维度会决定成败?
  • Agent 读回来的内容也能是攻击面,怎么防?
  • 任务要跑几小时、用户随时打断,架构该怎么改?

全文大概两万字,十八个小节,建议按顺序读,后面的每一节都依赖前面建立的概念。赶时间的话可以先看第一节和总结。

# 一、先把 Agent 这个词拆开

「Agent」现在被用得太宽,从一个套了提示词的聊天框,到能自己跑一周的编程系统,都叫 Agent。要讨论工程,得先有个能落到代码上的拆法。

我见过的各种拆法里,这组等式最实用:

Agent = Model + Harness

Harness = 上下文管理 + 工具接口 + 约束 + 验证 + 纠正

Agent ↔ Environment

Harness 直译是「马具」,套在马身上让人能驾驭它。放到这里,指的是 Agent 边界内、模型之外那一层运行与治理代码。

边界要划清楚,不然后面全是糊涂账。工具定义、调用适配器、沙箱的权限与重置机制,属于 Harness;沙箱里那些随行动变化的文件和进程、外部数据库、网页、用户、物理世界,属于 Environment。有一条容易搞混:部署位置不决定归属。哪怕仿真环境和 Agent 跑在同一个 Node 进程里,它依然是 Environment。

五个要素各管一段,我把它们摊平成一张表:

要素 它在解决什么 落到代码里是什么
上下文管理 让模型在每个决策点都有足够信息 系统提示词、状态栏、历史裁剪、压缩
工具接口 给模型观察和行动的手段 tool schema、调用适配器、结果序列化
约束 限定它能做什么 权限白名单、参数上限、审批开关
验证 判断这一步做得对不对 结构化字段校验、测试执行、linter
纠正 做错了怎么补救 静默重试、回退、熔断、转人工

前两项让 Agent「能做事」,后三项让它「不做错事」。

Harness 五要素闭环:上下文管理与工具接口让 Agent 能做事,约束、验证、纠正让它不做错事

这两类的重要性是不对称的,而且随着产品成熟度在迁移。早期框架基本都在卷前两项,给模型工具、给模型上下文。到了生产阶段,重心全在后三项。Claude Code 这类成熟产品的 Harness 里,绝大部分代码是约束、验证和纠正,工具本身反而只占一小部分。

有个数字很能说明问题。LangChain 在 Terminal Bench 2.0 上把自己的 Coding Agent 从 52.8% 提到 66.5%,排名从 30 名开外冲进前 5,改的不是模型,是 harness:让 Agent 自动检查执行结果、检测是否陷在重复循环里、调整思考策略。

# 从提示工程到 Graph 工程,工程师的手能伸多远

把视角拉远一点,这几年 AI 应用工程有一条很清晰的扩张弧线:

  • 提示工程,优化喂给模型的那段自然语言
  • 上下文工程,系统性管理模型能看到的所有信息,包括系统指令、工具定义、历史、外部知识
  • Harness 工程,进一步管「Agent 怎么组织模型运行、怎么跟环境交互」
  • Loop 工程,从单次运行扩展到跨轮次的持续运转,谁来发现下一件该做的事、何时才算真正完成
  • Graph 工程,2026 年开始被提起的说法,把 Agent 循环、确定性程序和人工审批组织成显式的执行图,节点承担能力,边规定路由,状态沿边传递并在关键边界持久化

这五层不是互相替代,是层层包含的。提示工程是上下文工程的子集,上下文工程是 Harness 工程的子集,一直往外套,单个 Agent 循环最后只是执行图里的一个节点。

我自己的感受是,每往外一层,工程师能影响的部分就多一块,而这块恰恰是模型厂商不会替你做的。这是这篇后面所有章节的立足点。

# 三条容易被跳过的原则

Anthropic 总结过三条,看着朴素,踩过坑之后回头看会觉得每条都在点上。

保持简单。 从最简单的方案开始,只在确实必要时加复杂度。直接调 API 优于套一层框架,清晰的代码优于聪明的抽象。理由很实际,每多一层抽象,以后调试时就多一个盲区。我见过不少团队一上来就上编排框架,结果 Agent 行为不对时,要先花半天搞清楚框架在中间替你改了哪些消息。

保持透明。 明确显示规划步骤、执行日志和决策轨迹。这不只是方便调试,更是让用户建立信任的前提。黑箱里出的错,外部观察者既定位不了也纠正不了。

按 Agent 的视角设计工具接口。 传统 API 是从程序员视角设计的,而 ACI(Agent-Computer Interface)强调的是让模型容易理解和正确使用。这条第十节展开。

先把整体骨架放这儿,后面所有代码都按这个结构组织:

┌──────────────────────── Agent ─────────────────────────┐
│  ┌────────────── Harness ──────────────┐               │
│  │  buildContext  ← 状态 + 轨迹 + 压缩  │               │
│  │        ↓                             │   观察        │
│  │     Model(推理 / 选工具)            │ ←──────────┐  │
│  │        ↓                             │            │  │
│  │  constrain → 权限与参数校验           │            │  │
│  │        ↓                             │   行动      │  │
│  │  工具接口 ─────────────────────────────────────────┼──┼→ Environment
│  │        ↓                             │            │  │
│  │  verify  → 看结构化字段,不看自由文本  │            │  │
│  │        ↓ 失败                         │            │  │
│  │  correct → 静默重试 / 回退 / 熔断     │ ───────────┘  │
│  └──────────────────────────────────────┘               │
└─────────────────────────────────────────────────────────┘
@前端进阶之旅: 代码已经复制到剪贴板

# 二、不用框架,最少多少行能跑起一个 Agent

概念讲完,先把东西跑起来。后面十几节都是在这个骨架上往里补,所以这一节的代码值得你真的敲一遍。

需要的只有 Node 18+ 和一个兼容 OpenAI 协议的 API Key。不装任何依赖,fetch 是内置的。

Step 1:建目录、配环境变量。

mkdir mini-agent && cd mini-agent && npm init -y && npm pkg set type=module
export LLM_BASE_URL="https://api.deepseek.com/v1"
export LLM_API_KEY="sk-..."
export LLM_MODEL="deepseek-chat"
@前端进阶之旅: 代码已经复制到剪贴板

Step 2:定义一个工具和它的 schema。描述里直接把触发时机和边界写清楚,这是第十节要展开的东西,先按对的写:

// tools.js
export const TOOL_SCHEMAS = [
  {
    type: 'function',
    function: {
      name: 'read_order',
      description: [
        '按订单号查询订单状态与金额。当用户提到具体订单号时使用。',
        '边界:只查单个订单,不支持按时间范围或用户 ID 批量查询。'
      ].join('\n'),
      parameters: {
        type: 'object',
        properties: { orderId: { type: 'string', description: '订单号,例如 A-1024' } },
        required: ['orderId']
      }
    }
  }
]

const ORDERS = { 'A-1024': { status: 'delivered', amount: 800 } }

export const REGISTRY = {
  async read_order({ orderId }) {
    const found = ORDERS[orderId]
    // 查不到就明说,别返回 null 让模型自己猜它是「没有」还是「出错了」
    return found ? { ok: true, orderId, ...found } : { ok: false, error: `订单 ${orderId} 不存在` }
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

Step 3:把循环拼起来。这一版还没有约束和验证,第七节补:

fe
  • 一、先把 Agent 这个词拆开
    • 从提示工程到 Graph 工程,工程师的手能伸多远
    • 三条容易被跳过的原则
  • 二、不用框架,最少多少行能跑起一个 Agent
  • 三、上下文窗口里到底装了什么
    • 按寿命给上下文分层
  • 四、一行时间戳为什么能让账单翻倍
    • 为什么缓存对前缀这么敏感
    • 落到代码上
    • 别猜,直接量
  • 五、工具结果为什么不能当成 user 消息塞回去
    • 思维链回传,各家策略是反的
  • 六、Agent 数不清自己干过几次,这件事该用代码解决
    • 上下文窗口是一台只有一半的检索引擎
    • 解法是状态栏
    • 三条经验,每条都有人踩过
  • 七、ReAct 循环之外,生产级 Agent 还缺哪三件事
    • 约束必须是白名单
    • 验证只看结构化字段,这是安全要求不是洁癖
    • 纠正的关键是不要暴露中间态
    • 三层的顺序不能换
  • 八、上下文快满了,压缩会不会把缓存全打掉
    • 先说清那个看似矛盾的地方
    • 压缩的第二个动机,比省 token 更重要
    • 生产级的分层压缩
    • 四条设计原则
  • 九、怎么让 Agent 跨会话记住用户
    • 读写分离的生命周期
    • RAG 要做到什么程度
  • 十、Agent 老选错工具,该换模型还是改描述
    • 描述的核心是「什么时候用」,不是「能做什么」
    • 静默输入转换,比功能缺失更隐蔽
    • 工具数量也要管
    • 一条实用的调试顺序
  • 十一、代码是通用 Agent 的元能力
    • 元能力体现在六个方向
    • 别忘了沙箱
  • 十二、怎么证明你改的东西真的有效
    • Pass@k 和 Pass^k,差别大到会得出相反结论
    • 最小可用的评估集
    • 分差多大才算真的变好
    • 别忘了过程指标
  • 十三、什么时候才真的需要上多 Agent
    • 步骤预算这件事反直觉
    • 四种典型的翻车方式
    • 一条务实的顺序
  • 十四、线上出问题怎么定位,轨迹该怎么存
    • 轨迹最有价值的去向是回流成评估集
    • 成本也要按 trace 归因
  • 十五、Agent 上线之后,怎么让它越跑越好
  • 十六、选模型时除了准确率还要看什么
  • 十七、提示注入和权限边界
    • 三条边界
    • 一句提醒
  • 十八、Agent 不只有对话这一个入口
    • 一个根本矛盾
    • 把一切建模成事件流
    • 让 Agent 在没人说话时也动起来
    • 长任务要能中断和恢复
  • 总结
  • 参考

Next.js 16 接入 Sentry 与飞书告警实战,sentry-hook-signature 验签、堆栈渲染与踩坑排查 →