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

智能体频繁出错,先检查后端接口设计

dev.to · AI#Agent#接口设计#后端
Editor brief · 编辑速览

文章以智能体调用 NestJS 订单后端为例,指出多次往返、冗余响应和模糊错误会增加模型误判与错误写入的风险。面向前端页面设计的 REST 接口,直接暴露为智能体工具可能导致数据过量获取和调用顺序错误。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

Agent 连到业务后端后,频繁失败不一定是模型不够聪明,也可能是接口一直在让它猜:完成一件事要连续调用 5 次,响应塞满无关字段,失败时只返回一句模糊提示。

作者在一个 NestJS 项目里遇到了这个问题。他的做法是在现有服务上加一层薄工具接口,把输入、输出、错误和执行边界收紧。这篇文章值得读的地方,是把 Agent 的可靠性问题落回了程序员能控制、能测试的接口契约。

为什么前端用着正常的接口,交给 Agent 就容易出错

作者的 Agent 需要创建订单、查询库存和退款。接入后经常失败,他将原因归结为后端接口围绕前端页面设计,没有照顾机器调用的需要。

页面接口通常假定调用方了解业务流程。它可以返回整屏需要的数据,可以按滚动列表分页,也可以把一些判断留给用户。人看到库存提示、订单状态和操作按钮,会结合界面补齐上下文;错误不够明确时,还能换个入口继续操作。

Agent 能依赖的,主要是工具描述和返回内容。接口没有交代的信息,就容易变成模型需要猜测的部分。一旦猜测进入写操作,后果可能是错误订单或错误退款。

作者反对两个极端:直接把面向页面的 REST 接口全部暴露成工具,以及提供一个什么都能做的巨型接口。前者让 Agent 背负页面接口的调用顺序和冗余数据,后者把过多决策空间交给模型,也让测试与追踪变得困难。

这里要抓住的是接口用途。REST 并不天然不适合 Agent,专门包一层工具也不会自动可靠。关键在于:调用方是否知道工具能做什么、需要什么,以及执行后究竟发生了什么。

薄工具层应该承担什么职责

作者保留原有业务服务,只在上面加一层翻译:接收明确的参数,调用服务,再把结果整理成小而稳定的结构。

下面这段代码展示了订单工具层的边界,业务操作仍然交给 OrdersService:

// tools/order.tools.ts
import { OrdersService } from "./orders.service";

export interface OrderItem {
  productId: string;
  quantity: number;
}

export class OrderTools {
  constructor(private readonly orders: OrdersService) {}

  @Tool({ name: "create_order", description: "Create an order for a customer" })
  async createOrder(
    @Param("customerId") customerId: string,
    @Param("items") items: OrderItem[],
  ) {
    const order = await this.orders.create({ customerId, items });
    return {
      orderId: order.id,
      status: order.status,
      total: order.total,
    };
  }

  @Tool({ name: "check_stock", description: "Check stock for one product" })
  async checkStock(@Param("productId") productId: string) {
    const stock = await this.orders.checkStock(productId);
    return { productId, inStock: stock.quantity > 0, quantity: stock.quantity };
  }

  @Tool({ name: "issue_refund", description: "Issue a refund for a paid order" })
  async issueRefund(
    @Param("orderId") orderId: string,
    @Param("reason") reason: string,
  ) {
    const refund = await this.orders.refund(orderId, reason);
    return { orderId, refundId: refund.id, status: refund.status };
  }
}

重点看 this.orders.create({ customerId, items }) 这一行:工具把业务执行委托给服务,随后才挑选返回字段。Tool 和 Param 装饰器来自所用的 Agent 框架,并非 NestJS 自带,原文也明确说这是简化示例。

这种拆法有三个实际作用。

首先,规则集中在服务里。订单是否合法、什么状态允许退款,都由 OrdersService 判断。否则同一项业务会出现两套规则,普通接口一套,Agent 工具另一套,后续很难同步维护。

其次,返回值围绕下一步决策设计。创建订单只返回 orderId、status、total,不用把整个订单及其关联对象交给模型。如果以后确实需要新字段,再明确加入契约。

最后,Agent 只接触限定的工具。作者不让它直接写查询、访问数据库或调用管理后台接口,以免绕过已有业务规则。

工具层负责表达能力边界,服务层负责执行业务规则。

不过,TypeScript 类型不等于运行时校验。示例没有展示如何拦住缺失字段、空数组或非法数量,接入时仍需补齐这一环,不能看到 OrderItem[] 就认为输入已经安全。

错误、日志和测试,为什么也是工具接口的一部分

对于 Agent,错误返回会直接影响下一步行动。

一句「出错了」无法区分应该停止、重试还是补充参数。作者建议统一返回简短错误码和可读消息,错误类别保持少量,例如 not found、out of stock、already refunded、invalid input。

库存不足时,Agent 可以向用户说明原因;已经退款时,它应当停止重复尝试。原文没有给出具体错误对象结构,这些名称也不应被当成某个框架规定的标准枚举。

堆栈、数据库报错和内部服务名称则留在服务端日志。它们未必有助于模型决策,还可能被原样转述给用户。

日志需要记录工具名称、输入、输出和成功与否。用户反馈退错订单时,开发者至少能查到调用了哪个工具、传入哪个订单 ID、提供了什么退款理由。日志能还原调用事实,但是否足以定位全部原因,仍取决于记录是否完整。

写操作还要经过认证、权限检查和服务端校验。作者对退款这类敏感操作提出更严格的流程:模型提出操作,用户明确确认,然后工具执行。示例代码并未实现这个确认机制。

测试也不能只覆盖 OrdersService。工具测试要检查真实调用可能出现的输入,包括缺失字段、空 items、不存在的商品 ID,并断言输出结构。只验证方法没有抛异常,抓不到字段改名后 Agent 读到 undefined 这种问题。

返回结构是 Agent 下一步决策的契约,也应该成为测试对象。

我的判断

我认同作者把接口设计放到可靠性讨论的中心。对已经有 Node 或 NestJS 服务的团队,这条路线很务实:复用业务规则,用少量适配代码把能力暴露清楚,比为 Agent 重写一套后端更容易维护。

但文章没有提供失败率、调用次数变化、延迟或模型对照实验。作者说工具层只占底层服务代码的一小部分,并且让 Agent 变得可靠,这是项目经验,不能据此推导出可量化的收益。

「一个工具只做一件事」也需要按业务动作理解。如果创建订单原本就必须完成多项内部校验,工具可以表达完整的创建动作,由服务协调执行。把每个底层步骤都拆给模型,反而可能重现开头连续调用 5 次才能完成任务的问题。

另外,清晰错误只能帮助模型少犯错,不能替代服务端保障。返回 already refunded 的前提,是服务能正确识别重复操作。用户确认也不能替代权限检查,更不能只靠模型声称已经获得确认。

如果现有 API 已经具备明确输入、精简响应、稳定错误和完整权限控制,直接做工具映射未必有问题。是否另建一层,应看契约差异有多大。作者对两种错误路线的批评有启发,但措辞比文中证据更绝对。

能拿来做什么

  • 给现有 Node 或 NestJS 项目接 Agent 时,先挑一个完整业务动作整理工具契约,明确参数、成功返回和失败类别,再复用现有服务执行。
  • 检查直接从页面接口映射出来的工具,删除没有明确用途的返回字段,并把必须遵循的调用条件写清楚,减少模型猜测。
  • 为订单、退款等工具增加输入边界和输出结构测试,优先覆盖缺失字段、空列表、无效 ID 与字段变更,而不只测试正常调用。
  • 在开放写操作前,落实服务端认证、权限、校验与调用日志;涉及退款时,把明确确认做成可验证的执行条件。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
写入全部报成功,记录却少了近千条
下一篇
Agent权限策略为何必须禁止自身修改

资讯速览

dev.to · AI · 2026-10-29 13:48

AI 评分 8.0 / 10

相关标签

#Agent#接口设计#后端

继续阅读

  • Gemini 4 Carbon 首批面向安全防守者
  • 写入全部报成功,记录却少了近千条
  • Agent权限策略为何必须禁止自身修改
  • 文档问答如何识别无答案并主动拒答
  • 让AI回答的每项主张都有证据可查