学习精选 · AI 工具
AI 学习经验

用 TypeScript 从零搭一个 AI Agent Harness:校验、隔离、预算与可观测性

freeCodeCamp2026-10-20约 4 分钟读完AI 整理查看原文

多数 Agent 教程只演示工具调用,却回避了工具失败、参数校验、无限循环和上下文爆掉这些真问题。这篇教程用 TypeScript 和 Node.js 24 从最简循环起步,逐层加上参数校验、工作区隔离、执行预算、上下文裁剪和事件观测,并用脚本化的假模型把失败路径也测出来。

今天就能做

  • 先写一个 scriptedModel 假模型,把 Agent 主循环和失败路径的测试跑通,再接真实模型。
  • 在工具执行前加一层 JSON Schema 校验,并把工具参数类型定为 unknown 而非 any。
  • 给 Agent 设 maxSteps 和 AbortSignal,轮数与工具调用次数分开计数,避免无限跑。

核心架构:模型只提议,harness 才执行

  • 最重要的设计决定是把「提议」和「执行」分开:模型返回的只是一条带工具名和参数的结构化请求,真正调用实现、把结果回填给模型的是 harness。
  • Model 接口刻意不绑定任何厂商,OpenAI、Anthropic 的适配器只需在自家 API 和这套类型之间做转换,harness 本身不用改。
  • 工具参数的类型定为 unknown 而不是 any,因为模型生成的数据属于不可信输入,必须在执行前校验。
  • 主循环顺序固定:把对话和工具定义发给模型、追加模型回复、若有工具请求就执行并追加结果、直到拿到最终答案或触达步数上限。

工具失败不等于任务终止

  • 工具抛错时,harness 不直接结束,而是追加一条带原 callId 的 tool 消息并标记 isError,让模型下一轮自己决定怎么补救,比如换个路径或换条命令。
  • 请求了不存在的工具名同样走这条路:回一条 Unknown tool 错误消息,而不是崩掉整个运行。
  • 注册表用 Map 建立工具名到实现的映射,并在启动时检查重名,避免同名工具互相覆盖。
  • maxSteps 默认 10,且必须是正的安全整数,否则直接抛 RangeError;模型可以一直请求干活,但迭代次数由 harness 说了算。

用假模型把测试变确定性

  • 测试里不调真实 API,而是写一个 scriptedModel,按数组顺序返回预设响应:先一条工具请求,再一条最终答案。
  • 脚本耗尽即抛错,这样多出来的意外模型轮次不会静默通过,测试能真正卡住循环次数。
  • 最小用例覆盖「执行工具并返回最终答案」这条主路径,用 Node.js 内置 test runner 和 assert/strict 跑,依赖极少。
  • 项目按 Git tag 分节推进,每节对应一个里程碑,可以 checkout 到 01-model-loop 这样的快照跟着做,而不是直接看最终代码。

后续要补的几层防护

  • 参数校验:给每个工具定义显式的 JSON Schema 契约,执行前先验证,并区分「参数不合法」和「执行失败」两类错误,处理方式不同。
  • 工作区隔离:把文件操作限制在指定目录内,命令由模型从白名单里选,而不是让它自由拼命令。
  • 执行预算:轮数和工具调用次数分开计数,并把取消信号和截止时间一路透传下去。
  • 上下文管理:对工具输出和面向模型的历史做长度上限,且不能把一次工具调用和它的结果拆散。
  • 可观测性:在执行边界发事件,模型用量只统计真实拿到的数据,不凭空估算。

原文:How to Build an AI Agent Harness from Scratch in TypeScript

来源:freeCodeCamp · 2026-10-20

查看原文

本文由 AI 阅读原文后整理,未经人工逐字核对,内容以原文为准。

登录后可以点赞、查看和发表评论