☰
AI Agent 开发实战:从最小循环到工程化落地
2026/10/5 5:09:08 网站建设 项目流程

1. 从最小循环说起:AI Agent 到底在“循环”什么

很多人第一次接触 AI Agent,脑子里浮现的是科幻电影里那种能自己思考、自己行动的智能体。但真到了动手搭建的时候,你会发现最核心的东西其实特别朴素——就是一个循环。这个循环在业界通常叫Agent Loop,翻译过来就是“智能体循环”。它做的事情可以用一句话概括:让模型反复地“想一下、做一下、看一下结果”,直到任务完成或者达到退出条件。

我刚开始接触这块的时候,也觉得这玩意儿能有多复杂?不就是调个 API 吗?但真正踩过坑之后才明白,一个能跑通的循环和一个能扛住真实场景的循环,中间隔着的不是几行代码,而是一整套工程化的思考。这篇文章我会从最基础的循环结构讲起,一步步拆到 Function Calling、Prompt 设计、Workflow 编排,最后聊到怎么让这套东西变得可靠。适合刚入门 AI Agent 开发的同学,也适合已经写过 demo 但总觉得“不太稳”的从业者。

先说说为什么是“循环”。传统的 LLM 调用是单次的:你给一个 Prompt,模型返回一段文本,结束。但 Agent 要解决的是多步骤任务,比如“帮我查一下明天北京的天气,然后根据天气推荐穿什么衣服”。这个任务拆开来看,第一步是查天气,第二步是根据天气结果做推荐。模型没法在一次调用里既查天气又做推荐,因为它没有实时数据。所以你需要让它先输出一个“查天气”的动作,你执行完把结果喂回去,它再基于结果输出推荐。这个“输出动作 → 执行 → 喂回结果 → 再输出”的过程,就是循环。

这个循环的最小结构大概长这样:

while not done: response = llm.chat(messages) if response.has_tool_call: result = execute_tool(response.tool_call) messages.append(result) else: done = True

看起来很简单对吧?但这里面每一个环节都有讲究。messages怎么维护?工具调用的结果用什么格式塞回去?什么时候判断done?模型如果一直不返回最终答案怎么办?这些问题在后面都会展开讲。

提示:如果你之前只写过单次 Prompt 调用,建议先手动实现一遍这个最小循环,不要急着上框架。框架帮你封装了很多东西,但如果你不理解底层在干什么,出了问题根本没法排查。

2. Function Calling:让模型从“说”变成“做”

2.1 Function Calling 的本质是什么

Function Calling 这个词听起来很技术,但它的本质特别简单:你告诉模型有哪些函数可以用,模型决定什么时候调用哪个函数,并且帮你把参数填好。注意,模型本身不执行函数,它只是输出一个结构化的调用请求,真正执行的是你的代码。

举个例子,你定义了一个函数叫get_weather,参数是city。当用户问“北京今天天气怎么样”,模型不会直接回答,而是输出一个 JSON 类似:

{ "function": "get_weather", "arguments": {"city": "北京"} }

你的代码拿到这个 JSON,去调真实的天气 API,把结果再塞回对话里,模型才能基于结果生成最终回答。

为什么要有这个东西?因为模型的训练数据是静态的,它不知道今天的天气、不知道你数据库里有什么、不知道当前股价。Function Calling 就是给它开了一扇窗,让它能“伸手”去拿外部世界的信息。

2.2 工具定义的几个关键细节

定义工具的时候,有几个地方特别容易出问题。第一个是描述。很多人写工具描述就写一句“获取天气”,这太模糊了。模型需要知道:这个工具什么时候用?参数是什么意思?有没有格式要求?我一般会写得比较详细,比如:

{ "name": "get_weather", "description": "查询指定城市当前的天气状况,包括温度、湿度、风力。适用于用户询问天气相关问题时调用。", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,使用中文,例如:北京、上海、广州" } }, "required": ["city"] } }

描述写得越清楚,模型调用得越准确。我实测下来,描述从一句话扩展到三四句话,工具调用的准确率能提升不少。

第二个是参数类型。尽量用简单的类型,string、number、boolean 这些。复杂的嵌套对象模型容易填错。如果确实需要复杂参数,考虑拆成多个简单工具。

第三个是工具数量。不要一次性给模型几十个工具,它会懵。我一般控制在 5 到 10 个以内,超过的话就做分组或者用路由的方式先选类别再选具体工具。

2.3 工具调用结果怎么塞回去

工具执行完之后,结果要以特定格式追加到对话历史里。不同模型的格式略有差异,但大体上是一条tool角色的消息,带上tool_call_id对应之前的调用请求。这一步如果格式不对,模型会忽略结果或者报错。

我踩过的一个坑是:工具返回的结果太长。比如你调了一个搜索工具,返回了五千字的网页内容,直接塞回去会占用大量 token,而且模型可能抓不住重点。后来我的做法是在工具层面就做截断和摘要,只返回最相关的部分。

注意:工具执行失败的时候,不要把异常直接抛给模型。应该返回一个结构化的错误信息,比如{"error": "城市名称无法识别"},让模型知道发生了什么,它可能会换个参数重试或者告诉用户。

3. Prompt 设计:Agent 的“操作系统”

3.1 System Prompt 决定了 Agent 的行为边界

如果说 Agent Loop 是骨架,Function Calling 是手脚,那 System Prompt 就是大脑的操作系统。它决定了 Agent 的身份、行为规范、输出格式、边界条件。我见过很多 Agent 跑不稳,最后排查下来都是 System Prompt 没写好。

一个好的 System Prompt 应该包含这几个部分:

  • 角色定义:你是谁,你擅长什么
  • 任务说明:你要帮用户完成什么类型的事情
  • 工具使用规范:什么时候该调工具,什么时候直接回答
  • 输出格式要求:回答的结构、语气、长度
  • 边界和禁忌:什么不能做,遇到不确定的情况怎么办

我一般会写一个模板,然后根据具体场景调整。比如一个客服 Agent 的 System Prompt 可能是这样:

你是一个电商平台的客服助手,负责回答用户关于订单、退换货、物流的问题。 你可以使用以下工具: - query_order:根据订单号查询订单状态 - query_logistics:根据订单号查询物流信息 - create_return:创建退货申请 规则: 1. 用户询问订单相关问题时,先调用 query_order 确认订单状态 2. 如果用户情绪激动,先安抚再处理问题 3. 不确定的信息不要编造,告诉用户你会转人工处理 4. 回答保持简洁,不超过三句话

这个 Prompt 里每一条规则都是有原因的。比如“先调用 query_order”是因为不确认订单状态就回答容易出错;“不超过三句话”是因为客服场景用户不想看长篇大论。

3.2 Prompt 里的常见坑

第一个坑是指令冲突。比如你既说“回答要详细”又说“保持简洁”,模型就不知道该听哪个。每一条指令都要检查有没有和别的指令矛盾。

第二个坑是过度约束。有些人怕模型乱来,写了几十条规则,结果模型变得特别死板,稍微超出预期的情况就不会处理了。规则要抓大放小,核心行为约束住就行。

第三个坑是缺少示例。对于输出格式要求高的场景,光描述不够,最好给一两个输入输出的例子。这叫 Few-shot Prompting,能显著提升格式稳定性。

还有一个热词里提到的 “invalid prompt” 问题,通常是因为 Prompt 里包含了某些被判定为不合规的内容。这种情况一般发生在用户输入被直接拼接到 Prompt 里的场景。解决办法是在拼接之前做一层过滤和转义,不要把原始用户输入直接塞进 System Prompt。

3.3 Prompt Token 的优化

Prompt Token 是成本的大头。System Prompt 越长,每次调用的成本越高。优化思路有几个:

  • 把不常用的规则移到工具描述里,按需加载
  • 用更紧凑的表达,去掉冗余的客套话
  • 对于多轮对话,定期做历史摘要,不要把全部历史都带上
  • 工具返回结果做截断

我做过一个对比,把一个 2000 token 的 System Prompt 优化到 800 token,效果基本没降,但成本降了一半多。

4. Workflow 编排:从单 Agent 到多步骤流水线

4.1 什么时候需要 Workflow

单 Agent 循环能解决很多问题,但有些场景它搞不定。比如一个任务需要严格按照步骤来:先查数据,再分析,再生成报告,最后审核。这种有明确阶段划分的任务,用 Workflow 编排会更稳。

Workflow 的思路是把大任务拆成多个节点,每个节点是一个独立的处理单元,节点之间通过定义好的数据格式传递信息。这样做的好处是每个节点可以单独优化、单独测试,出了问题也容易定位。

举个实际例子,我做过一个“竞品分析报告生成”的 Agent,拆成了这几个节点:

  1. 信息收集节点:调用搜索工具,收集竞品的基本信息
  2. 信息整理节点:把收集到的信息结构化,提取关键维度
  3. 分析节点:对比各竞品的优劣势
  4. 报告生成节点:按照模板生成最终报告
  5. 审核节点:检查报告是否有事实错误或遗漏

每个节点用独立的 Prompt,独立的工具集。这样比一个大循环塞所有逻辑要可靠得多。

4.2 Workflow 编排的几种模式

常见的编排模式有串行、并行、条件分支、循环这几种。

串行最简单,A 做完做 B,B 做完做 C。适合有严格先后顺序的任务。

并行是多个节点同时执行,最后汇总。比如同时查三个数据源,然后合并结果。并行能省时间,但要注意结果合并的逻辑。

条件分支是根据上一步的结果决定下一步走哪条路。比如审核不通过就回到生成节点重做。

循环是某个节点重复执行直到满足条件。比如反复搜索直到找到足够的信息。

实际项目里往往是几种模式的组合。我建议刚开始不要搞太复杂,先用串行把流程跑通,再逐步加入并行和分支。

4.3 节点之间的数据传递

节点之间传什么、怎么传,是 Workflow 设计里最容易出问题的地方。我的经验是:每个节点的输出格式要严格定义,最好用 JSON Schema 约束。不要传自然语言,因为自然语言有歧义,下游节点解析起来容易出错。

比如信息收集节点的输出应该是:

{ "competitors": [ {"name": "产品A", "features": ["功能1", "功能2"], "price": "99元"}, {"name": "产品B", "features": ["功能3"], "price": "129元"} ] }

而不是“我找到了两个竞品,产品A有功能1和功能2,价格99元……”这种。

提示:节点之间的数据格式一旦定下来,就不要轻易改。改一次,上下游都要跟着改,很容易漏掉某个地方导致 bug。

5. 从能跑到可靠:工程化落地的关键点

5.1 错误处理和重试

Agent 跑起来之后,你会遇到各种各样的错误:模型返回格式不对、工具调用超时、参数填错、循环次数超限。这些都要有处理机制。

我的做法是分三层:

  • 工具层:每个工具内部做超时控制和异常捕获,返回结构化错误
  • 循环层:设置最大循环次数,超过就强制退出并返回当前结果
  • 节点层:Workflow 的每个节点可以配置重试策略,失败几次后走降级逻辑

重试不是万能的。有些错误重试有用,比如网络超时;有些错误重试没用,比如参数格式错误。要区分对待。

5.2 可观测性

Agent 跑在生产环境,你必须知道它每一步在干什么。我一般会记录这些信息:

  • 每次模型调用的输入 Prompt 和输出
  • 每次工具调用的参数和返回结果
  • 每个节点的开始时间、结束时间、耗时
  • 整个任务的 token 消耗

这些数据一方面用于排查问题,另一方面用于优化成本和效果。比如你发现某个节点的 token 消耗特别高,就可以针对性优化。

5.3 并发和性能

热词里有人问“AI Agent 怎么扛并发”,这确实是个实际问题。Agent 的每次循环都要调模型,延迟本来就高,并发上来之后更容易堵。

几个优化方向:

  • 异步调用:模型调用和工具调用都用异步,不要阻塞
  • 缓存:对于相同的输入,缓存模型输出或工具结果
  • 限流:控制同时运行的 Agent 数量,避免把下游服务打挂
  • 超时控制:每个环节都要设超时,不能让一个卡住的请求拖垮整个系统

我实测下来,用异步 + 缓存的方式,同样的硬件资源能支撑的并发量能提升好几倍。

5.4 测试和评估

Agent 的测试比传统软件难,因为输出不是确定的。我的做法是建立一套评估集:准备一批典型的输入,定义期望的输出特征,每次改动后跑一遍看通过率。

评估集不用很大,几十条就够,但要覆盖主要场景和边界情况。通过率下降就说明改动有问题,需要排查。

6. 常见问题速查

问题可能原因排查方向
模型不调用工具工具描述不清、Prompt 没说明何时用检查工具描述和 System Prompt
工具参数填错参数描述模糊、类型复杂简化参数、补充示例
循环不退出退出条件没定义好加最大循环次数限制
输出格式不稳定Prompt 缺少格式约束加 Few-shot 示例
响应太慢串行调用太多、没缓存改异步、加缓存
Token 消耗过高Prompt 太长、历史没压缩优化 Prompt、做历史摘要

7. 我踩过的几个坑

第一个坑是把用户输入直接拼到 System Prompt 里。有次用户输入了一段很奇怪的内容,导致模型行为完全跑偏。后来我改成用户输入永远放在 user 角色消息里,System Prompt 保持干净。

第二个坑是工具返回结果没做大小限制。有个搜索工具返回了几万字的网页内容,直接把上下文撑爆了,模型后面的回答全是乱的。后来我在工具层面加了截断,只返回前 2000 字。

第三个坑是没有设最大循环次数。有次模型陷入了一个死循环,反复调用同一个工具,跑了上百次才被我发现。后来我加了硬性限制,超过 10 次循环就强制退出。

第四个坑是Prompt 里的指令互相矛盾。我写了“回答要详细”又写了“控制在三句话以内”,模型有时候详细有时候简短,很不稳定。后来我把所有指令过了一遍,确保没有冲突。

这些坑说起来都很简单,但没踩过就是想不到。希望看到这里的你能少走点弯路。

8. 后续可以怎么扩展

这套最小循环 + Function Calling + Workflow 的架构,跑通之后可以往几个方向扩展。

一个是多 Agent 协作。让不同的 Agent 负责不同的角色,比如一个负责规划、一个负责执行、一个负责审核,通过消息传递协作。这个模式适合复杂任务,但调试起来也更麻烦。

另一个是记忆系统。给 Agent 加上长期记忆,让它能记住之前的交互,在后续对话中复用。这个需要配合向量数据库来做。

还有一个是自适应 Workflow。不是固定流程,而是让模型根据任务情况动态决定走哪些节点。这个灵活度更高,但可控性会下降,需要权衡。

我自己目前主要在用单 Agent + 固定 Workflow 的组合,稳定性和可控性都比较好。等这套跑顺了,再考虑往更复杂的方向走。毕竟 Agent 这东西,能稳定跑起来比看起来酷要重要得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询