前端如何理解 Agent 开发:从点击按钮到让 AI 帮你做事

如果你已经会写页面、调用接口和处理加载状态,就可以开始理解 Agent 开发。

我们先从一句话开始:Agent 应用让 AI 根据用户的目标选择下一步,再由你写的程序执行。

这句话里的“选择”和“执行”分别是谁负责,是理解 Agent 的关键。下面用一个博客助手,把这件事一步步拆开。

本文讲的是如何开发这样的应用。你不需要先训练一个模型,也不需要一开始就掌握一堆 AI 框架。


一、先看一个你已经会做的页面

假设你要给博客做一个文章管理页面,页面上有三个功能:

  • 点击“查看文章”,显示已经发布的文章。
  • 输入关键词,点击“搜索”,查找相关内容。
  • 编辑好文章,点击“保存草稿”,保存当前内容。

其中,“查看文章”的逻辑可能是这样:

async function getPosts() {
  const response = await fetch("/api/posts")

  if (!response.ok) {
    throw new Error("Failed to load posts")
  }

  return response.json()
}

用户点击按钮,事件处理函数调用 getPosts(),然后把返回结果显示到页面上。

用户点击按钮 → 程序调用接口 → 接口返回数据 → 页面显示结果

这里,什么时候查询、搜索什么、要不要保存,主要由用户操作和你写好的页面流程决定。

现在我们希望用户少点几个按钮,只说一句话:

看看我已经写过哪些文章,帮我推荐三个还没写过的 React 选题。

这就开始接近 Agent 的使用场景了:用户描述想达到的目标,应用需要安排中间的操作。

二、接入一个 AI 聊天框,就能完成吗?

我们先做最简单的一版:把用户的话发给模型,让它回答。

模型可能推荐:

可以写 React 入门、useState 用法和 useEffect 用法。

但问题来了:你的博客可能早就写过这三篇。

如果应用没有把文章列表提供给模型,它就没有可靠依据判断你写过什么。 即使模型给出了自信的回答,也不能说明它真的查询过你的博客。

你当然可以直接编写一个固定流程:

程序先查询文章 → 把文章列表和用户问题发给模型 → 模型推荐选题

如果需求一直这么简单,这样就够了。

接下来,我们给它多一点灵活性:当模型需要了解已有文章时,可以请求查询;如果标题信息不够,还可以请求读取某篇正文。这个时候,就需要介绍“工具”。

三、工具,就是你允许 AI 调用的业务能力

你已经有一个 getPosts() 函数,可以查询文章。

要把它开放给模型使用,需要告诉模型两件事:

  • 这个能力叫什么:getPosts
  • 什么时候使用:需要了解本站已经发布的文章时使用。

工具如果需要参数,还要说明参数的名称、类型和用途。例如搜索工具需要一个关键词。

给模型看的,是工具的说明和参数格式;真正执行查询的函数,仍然由你的程序负责。

模型不会因为听说了 getPosts 这个名字,就直接访问你的数据库。

它会通过模型服务的工具调用机制,返回一个类似这样的请求:

{
  "name": "getPosts",
  "arguments": {}
}

这是为了理解而简化的结构,不是某个 SDK 的完整响应。

你的程序收到之后,检查这个工具是否允许调用、参数是否有效,再执行对应的函数。不要执行任意生成的代码,也不要把未知工具名当成可以运行的命令。

用一段交互记录来看,会更直观:

用户:推荐三个我还没写过的 React 选题。

模型返回工具请求:
getPosts()

程序执行查询,把结果交回模型:
- React 入门
- useState 基础
- useEffect 基础

模型返回最终回答:
可以考虑状态提升、组件组合、表单状态管理。
下面分别说明它们适合解决的问题……

注意,中间“查询文章”这一步是程序真实执行的。页面上的一句“正在查询文章”,本身并不代表查询发生过。

这个过程就叫 Tool Calling,也就是工具调用

你可以先把它记成:

用户原来通过按钮调用的业务能力,现在也可以由 AI 提出调用请求。

四、为什么还需要“循环”?

刚才的例子只查了一次文章,就给出了回答。

但有时事情不会这么顺利。假设文章列表里有一篇叫《React 实战笔记》,光看标题,很难判断它是否已经讲过“表单状态管理”。

如果你提供了 readPost 工具,模型就可以继续请求读取正文:

第一轮:模型请求 getPosts
        程序返回文章列表

第二轮:模型请求 readPost,读取《React 实战笔记》
        程序返回正文,发现里面已经讲过表单状态管理

第三轮:模型根据正文调整选题
        返回三个建议和对应理由

上一轮拿到的结果,会影响下一轮选择的动作。 这就是 Agent 执行循环最值得理解的地方。

负责协调这个过程的,是你写的程序:

把用户目标和已有信息发给模型
                ↓
       模型返回了什么?
       ↙              ↘
   工具调用请求        最终回答
       ↓                 ↓
检查后执行工具       把回答交给用户
       ↓
把工具结果加入已有信息
       ↓
继续调用模型

这里不是让模型无限运行。程序要规定最大执行次数和每次调用的超时;信息不够时,也可以停下来请用户补充。

例如,用户没有说明想写哪个技术方向,应用可以询问:

你更想写 React 基础,还是项目实战?

所以你写的不只是一个请求函数,还包括“什么时候继续、什么时候等待、什么时候结束”。

五、前端、服务端和模型分别负责什么?

现在把这几个角色放到一起:

角色在博客助手里负责什么
用户提出目标,补充要求,审阅结果
前端页面接收输入,展示进度和结果,提供取消等操作
服务端程序调用模型,检查并执行工具,管理任务是否继续
模型根据收到的信息,提出工具调用或生成回答
业务接口真正查询文章、读取正文或保存草稿

可以把它们之间的关系画成这样:

前端页面 ←→ 服务端程序 ←→ 模型
                 ↕
              业务接口

在这个例子里,模型密钥和工具执行放在服务端。浏览器主要处理用户交互,不需要持有模型密钥。

对于前端开发者,很多工作还是熟悉的,只是页面需要表达更多状态:

你熟悉的工作在 Agent 页面里的变化
输入框收集“帮我完成什么”的目标
loading显示正在查询文章、读取正文等具体进度
接口错误提示告诉用户哪一步失败,能否重试
列表或卡片展示选题、推荐理由和参考文章
表单确认让用户检查准备保存的草稿
状态管理区分执行中、等待补充、完成、失败、已取消

进度最好来自程序实际发生的事件。例如查询接口确实返回了五篇文章,再显示“已找到 5 篇文章”。

“取消”也需要前后端配合:页面通知服务端停止任务,服务端再尝试中止正在进行的调用。仅仅隐藏 loading,不代表后台已经停止。

如果你只负责页面,可以和后端约定好任务接口及状态。如果你要独立完成整个应用,就需要再掌握服务端的模型调用和工具执行逻辑。

六、AI 能调用接口,是不是就可以让它随便操作?

这里可以直接套用你熟悉的后端鉴权思路:请求来自模型,也一样要经过检查。

例如,给助手增加“保存草稿”能力时:

  1. 服务端确认当前用户是否有保存权限。
  2. 检查标题、正文等参数是否符合要求。
  3. 页面按产品约定展示待保存内容,让用户确认。
  4. 确认后调用保存接口,成功了再显示“已保存”。

你不能因为模型说“用户已经同意”,就跳过程序里的确认记录;也不能因为模型生成了符合 TypeScript 类型的数据,就认为所有参数都合法。

还有一个容易忽略的问题:保存请求超时,不一定代表没有保存成功。重试时要能识别同一次保存操作,避免生成两份草稿。

初次练习时,可以只开放查询和读取工具。先跑通获取真实信息、生成答案的过程,再增加写入能力,会更容易理解和排错。

七、什么时候需要 Agent,什么时候固定流程就够了?

把同一个博客里的三个功能放在一起,就能看出区别:

需求可以怎么做原因
把一个中文标题翻译成英文一次模型调用输入和目标都很明确
查询文章,生成摘要,再翻译摘要固定工作流主要步骤可以提前写好
检查已有内容,遇到不明确的地方再读正文,最后推荐选题Agent后续操作取决于前面查到了什么

这也是一种常见的工程区分:工作流主要由预先写好的代码安排步骤,Agent 则让模型参与动态选择下一步。参考:Anthropic — Building effective agents

在实际产品里,两者可以一起使用。例如“选题推荐”让模型灵活判断,“保存草稿”继续走固定的校验和确认流程。

可以先问自己:

下一步操作能不能提前确定?还是必须看到前一步的结果,才能决定要查什么、做什么?

需要动态判断时,才值得进一步评估 Agent。普通代码也能根据结果分支;关键是这个判断是否适合交给模型,以及它是否比固定规则带来更好的效果。

八、先记住四个词,再做一个小练习

现在再看术语,就没有那么抽象了:

  • 模型:根据输入生成回答,也能提出工具调用请求的 AI 服务。
  • Prompt(提示词):你交给模型的任务说明,例如“推荐三个适合初学者、且尚未写过的选题”。
  • Tool(工具):程序允许模型请求使用的能力,例如查询文章。
  • Context(上下文):这次调用模型时,实际提供给它的信息,例如用户要求、文章列表和刚读取的正文。

这里的上下文很像你调用一个函数时传入的数据:页面上有某条信息,不等于模型就收到了它。要让模型参考文章列表,程序就需要把列表加入请求。

至于 RAG、MCP、长期记忆和多 Agent 协作,可以在需要时再学习。理解前面的工具调用和执行循环,就足够开始第一个小功能。

可以按这个顺序练习:

  1. 做一个输入框,把用户的问题发给模型,显示回答。
  2. 提供一个查询已有文章的工具,让模型能够请求使用它。
  3. 把工具查询结果交回模型,让它据此推荐选题。
  4. 在页面显示“正在查询”和“已完成”,并处理查询失败。
  5. 测试空文章列表、工具报错和推荐重复选题,检查结果是否符合预期。

这时,别只看回答是否流畅。打开任务记录,确认工具真的执行了,返回的数据真的被交给模型,推荐的选题也没有明显重复。

你会发现,前端开发经验可以一直用得上:接口定义决定有哪些能力,状态管理决定用户看到什么,异常处理决定失败后怎么办。Agent 开发在这些基础上,增加了一个由模型参与选择下一步的过程。