☰
Agent工程实现:从Demo到生产的七要素与七个决策点
2026/10/31 4:14:22 网站建设 项目流程

Agent 这个词在 2025 年的技术热点里已经快被讲烂了,但我在社区里看到最多的问题其实是另一个层面的:demo 都会跑,一上生产就翻车。同样一个 ReAct 循环,在本地 notebook 里能老老实实调工具,到了线上面对真实流量和脏数据就开始死循环、乱调用、上下文爆炸。这就是“会拼 prompt”和“懂工程实现”之间的差距。这篇内容我打算一次性把 Agent 的工程实现讲透,围绕标题里两条主线展开:先拆 Agent 的七要素,说明每个 Agent 系统里必须在场的能力模块;再拆工程落地时的七个决策点,告诉你从选模型、选框架到扛并发、做评估,每一步到底在选什么、为什么这么选。内容会比较长,但每一节都是可以直接抄进项目里的判断依据。适合正在做 Agent 开发、想从实验性代码走向生产环境的工程师,也适合刚入门但不想只看 API 教程的同学。

1. 先理清七要素:一个 Agent 系统里必须有哪几块积木

1.1 为什么是七要素,而不是“模型+提示词”

很多人对 Agent 的理解停留在“大模型 + 工具调用”,这个理解不能算错,但太粗糙。一个能在真实业务里稳定工作的 Agent,需要同时具备七个能力模块,缺少任何一个,系统都会在特定的环节暴露出短板。

我把这七个要素定义为:模型(Model)、规划(Planning)、记忆(Memory)、工具(Tools)、行动(Action)、感知(Perception)、反馈闭环(Reflection)。它们之间的关系不是简单的并列,而是一个持续运转的循环:感知外部输入,交给模型做规划,从记忆里取出相关上下文,决定调用哪些工具,执行具体动作,最后把执行结果反馈给系统进行反思和修正。

这七个要素对应到工程上,每一个都有自己的实现难点。模型要选型和调参,规划要设计循环和状态机,记忆要做分层和检索,工具要定义协议和鉴权,行动要处理副作用和幂等,感知要做结构化输入解析,反馈闭环要做评估和自省机制。说 Agent 是“系统工程”而不是“一个模型”,就是因为这些模块全都需要工程化处理。

1.2 要素一:模型——Agent 的决策引擎,但不是全部

模型是 Agent 的推理核心,负责理解任务、生成计划、决定调用哪个工具、解读工具返回结果。但我要强调一点:模型是上限,而不是全部。很多人把 Agent 效果不好全部归因于模型不够强,这其实是偷懒的想法。工程上的上下文管理、工具编排、循环控制,往往比换一个更大参数的模型带来更明显的效果提升。

在选模型的时候,核心要看三个能力维度。

  • 工具调用能力:模型是否支持 function calling,还是只能靠 prompt 硬生成 JSON 格式的调用参数。原生支持 function calling 的模型在参数结构化上明显更稳。
  • 长上下文能力:Agent 在运行过程中会把历史对话、工具返回、中间推理过程都塞进上下文。超过模型的有效注意力长度后,Agent 会“忘事”,这不是 prompt 能解决的。
  • 推理与指令遵循能力:复杂任务分解、多步推理、遵循复杂约束,不同模型之间的差距非常大。

举个例子,如果你做的是一个需要频繁调用数据库查询的工具型 Agent,用工具调用能力弱的模型,每一轮都会出现参数格式错误,整体体验会非常崩溃。

1.3 要素二到五:规划、记忆、工具、行动的协同逻辑

规划是 Agent 把一个大目标拆成可执行步骤的能力。工程上最常见的规划形式是 ReAct 循环:模型先思考下一步做什么(Thought),然后决定调用什么工具(Action),拿到观察结果后继续思考,直到任务完成。复杂一点的系统会用 Plan-and-Execute 模式,模型先生成一份完整计划,然后逐条执行。

记忆是 Agent 区别于普通对话系统的关键。短期记忆对应当前任务上下文,通常是放在 prompt 里的对话历史和中间状态;长期记忆则要外置到 Redis、向量数据库、PostgreSQL 等存储中,按需检索相关片段放回上下文。工程上最常见的坑是“所有东西都往上下文里塞”,导致 token 成本暴涨、模型注意力被稀释。

工具是 Agent 连接外部世界的接口。一个工具本质上就是一个函数,模型通过结构化参数调用它。工具的粒度设计很重要:太粗则复用性差,太细则模型容易选错。比如“发送邮件”和“获取邮件列表”应该分开定义,而不是做成一个“操作邮件系统”的大工具。

行动是工具调用的实际执行层,包含网络请求、数据库写入、文件操作等。工程上最容易忽略的是行动的副作用控制:一次工具调用如果是写操作,重试时会不会造成重复执行?这需要接口设计成幂等,或者在调用层加去重机制。

1.4 要素六到七:感知与反馈闭环,常常被忽略的两个环节

感知是 Agent 获取外部信息的方式。在聊天机器人里,感知就是解析用户消息;在自动化 Agent 里,感知可能来自 Webhook、消息队列、定时任务或者页面事件。工程上要格外注意输入的结构化:用户的自然语言输入需要先经过意图识别和关键信息抽取,再进行规划,而不是把原始文本一股脑丢给模型。

反馈闭环是 Agent 自我修正的机制。最简单的闭环是在每轮工具调用后检查返回结果是否符合预期,如果报错则调整参数重试。高级一点的闭环会引入反思节点:模型在完成一部分任务后,主动对照目标评估已有产出,发现问题就自我纠正。这个机制在实际项目里非常有效,但要注意控制反思频率,否则 token 成本和延迟都会飙升。

七要素讲完了,接下来是工程实现的核心部分。从要素到决策点的转换,本质上是把“Agent 需要什么能力”转变成“我要怎么设计这个系统”。下面七个决策点,我按实际项目里会遇到的先后顺序来拆。

2. 决定 Agent 骨架的关键:模型选型、框架与记忆设计

2.1 决策点一:模型选型与推理参数配置

第一个决策点在项目启动时就躲不掉:用哪个模型,以及它的推理参数怎么配。

模型选型可以按任务类型粗分三档。第一档是复杂推理与多步规划型任务,比如数据分析、代码生成、复杂业务编排,选推理能力最强的旗舰模型,不要省这个钱。第二档是工具调用密集型任务,模型需要频繁输出结构化调用参数,这时候要重点看 function calling 的稳定性和输出格式的规范程度。第三档是轻量型任务,比如简单的意图分类、关键词抽取,完全可以用小模型,成本低、延迟低,效果还够用。

推理参数里最重要的是 temperature。工具调用和结构化输出场景,我建议调到 0.1 到 0.3 之间;创意生成类场景可以放宽到 0.7 到 0.9。很多人喜欢默认用 0.7,结果工具调用参数经常出现随机错误,这不是模型问题,是参数没调对。

还有一个容易忽略的参数是 max_tokens。Agent 在一次推理中要输出思考过程、调用参数、中间结果,如果你把 max_tokens 设得太小,模型的输出会被强行截断,整个循环直接崩溃。建议根据任务的复杂程度,至少留出 1024 到 2048 的余量。另外注意,如果用了 reasoning 模型,思考过程会占用大量输出 token,要在成本预估里算进去。

2.2 决策点二:框架选型与语言栈选择

选框架是第二个决策点,也是团队内部争论最多的问题。选框架的核心标准不是“哪个火”,而是“状态管理和循环控制适不适合你的场景”。

  • 不用框架,手写循环:适合简单场景,一个 while 循环加一个工具调用函数就够了。优点是灵活、依赖少、问题好排查,缺点是状态管理、记忆、工具编排全部要自己造轮子,项目复杂起来维护成本很高。
  • LangChain:老牌生态,组件齐全,适合快速搭原型。但很多人诟病它的抽象层太厚,出了问题不好排查,生产环境需要谨慎评估。
  • LangGraph:专为有状态、有循环的 Agent 场景设计,核心概念是图,节点和边可以精确控制流程。我现在的项目基本都用 LangGraph,因为 Agent 本质上就是一个有状态的状态机,用图来建模非常自然。
  • Spring AI:Java 生态的选择,适合技术栈以 Java 为主、需要与 Spring 体系深度整合的团队,尤其是企业级应用。
  • 扣子(Coze)这类平台:适合不想从零写代码、想快速搭建 Bot 的场景。优点是可视化编排、上手快,缺点是灵活性和私有化部署能力受限,在需要深度定制或数据合规的场景里不太够用。

还有一个热词值得单独说:基于 Rust 的 AI Agent。Rust 的优势在于性能和高并发下资源占用可控,适合做 Agent 运行时内核、网关或者嵌入到对延迟敏感的服务里。但 Rust 生态在 Agent 层面还比较早期,团队如果主要用 Rust,可以关注,但不要轻易把核心业务全部押上去。

2.3 决策点三:记忆分层设计

第三个决策点是记忆怎么设计。我见过很多项目,记忆就是“把聊天记录全存 Redis,每次全拿出来拼进 prompt”,这种做法在对话轮次少的时候没问题,一旦上下文超过模型窗口,效果会迅速恶化。

记忆分层是工程上最常用的解法。

  • 第一层:短期工作区。存放当前任务的上下文,包括用户输入、模型思考、工具返回。这层在每次状态更新时重写,控制在模型窗口安全范围内。
  • 第二层:长期记忆库。存放跨会话的结构化记忆,比如用户偏好、已完成任务的摘要、关键实体信息。通常用向量数据库存储,按语义相似度检索。
  • 第三层:摘要记忆。当短期上下文即将超出窗口时,用模型把前面的关键信息压缩成摘要,替换掉原始长文本。这是控制 token 成本最重要的手段。

在实际项目中,我会建议把“记忆操作”也做成显式的工具调用,而不是让系统隐式处理。比如模型判断“这个信息值得记住”,就调用 save_memory 工具写入长期记忆库;判断“需要回忆相关历史”,就调用 search_memory 工具检索。让模型自己管理记忆生命周期,比写死规则更灵活。

3. 从规划到执行:工具编排、规划模式与多智能体架构

3.1 决策点四:工具定义与调用编排

工具是 Agent 能力的边界,工具定义的优劣直接影响 Agent 的成功率。第四个决策点要解决的是:工具怎么描述、怎么注册、怎么被模型正确选中。

工程上,工具定义通常是一份 JSON Schema,包含工具名称、描述、参数列表。描述信息远比参数重要,因为模型是靠描述来理解工具适用场景的。我见过太多工具描述写“对数据进行操作”,模型根本不知道什么时候该选它。好的描述应该写清楚“在什么条件下使用、输入什么、输出什么、有什么副作用”。

工具数量也要控制。一个 Agent 暴露超过 20 个工具时,模型选错的概率会明显上升。这时候应该做分组或者路由:先让模型选一个工具组,再在组内选具体工具。这相当于两级路由,能显著降低决策难度。

工具调用的工程细节也不能忽视。鉴权是必须的:Agent 的每个工具调用都应该经过权限校验,不能因为模型“觉得该调用”就放行。写操作要做幂等设计,比如在参数里带 request_id,服务端根据 request_id 去重。工具返回值要有固定结构,至少包含 success 标识、数据、错误信息三段,这样模型才能可靠地判断调用成功还是失败。

3.2 决策点五:规划模式与状态流转

第五个决策点是规划模式,也就是 Agent 内部的工作流怎么组织。这一层直接决定 Agent 的行为边界和稳定性。

最基础的 ReAct 循环流程是:模型思考 -> 调用工具 -> 观察结果 -> 再思考,直到得出最终答案。实现上就是一个循环,用一个状态变量记录当前步数,到最大步数就强制终止。这个模式的优点是实现简单、适应性强,缺点是每轮都要调模型,延迟和成本偏高,且容易陷入重复尝试的循环。

更可控的 Plan-and-Execute 模式是:先让模型把任务拆成若干步骤,生成一份计划,然后按顺序逐步执行,每步完成后再判断要不要调整计划。适合目标清晰、步骤可预期的场景,比如数据报表生成、批量信息处理。缺点是对动态变化的场景适应性差,计划容易过时。

在工程实现上,我强烈建议把 Agent 的流程建模成状态图,而不要写成自由的 while 循环。状态图可以精确控制每个节点之间的流转条件,设置超时、循环上限、异常分支。LangGraph 的核心价值就在这里:节点是执行单元,边是流转逻辑,整个 Agent 的行为是可视化、可控的。这对生产环境的排查和维护非常关键。

3.3 决策点六:多智能体协作还是单体循环

第六个决策点是架构层面的争论:要不要上多智能体。我的建议非常直接:能单智能体解决的,不要上多智能体。多智能体带来的通信开销、状态同步、故障扩散,会让项目复杂度成倍上升。

什么场景适合多智能体?我归纳为三类。

  • 角色分工明确的任务。比如一个研究类 Agent,拆成“检索员”和“分析师”,检索员负责收集资料,分析师负责综合判断。不同角色用不同 prompt 和工具集,职责边界清晰。
  • 需要隔离工具权限的场景。比如一个智能体只能读数据,另一个才能写数据,通过多智能体隔离权限比在单智能体里做工具鉴权更简单。
  • 子任务可以并行执行的场景。多个独立任务同时进行,用多个 Agent 并行处理能显著缩短耗时。

工程上有几种常见的多智能体模式。Supervisor 模式:一个主管 Agent 负责任务分配,多个子 Agent 各司其职;Pipeline 模式:Agent 按流水线顺序处理,前一个输出是后一个输入;Hierarchical 模式:多级上下级关系;GroupChat 模式:多个 Agent 自由发言协作。最稳的是 Supervisor 模式,控制力最强,最不稳的是完全自由的 GroupChat,生产环境慎用。

4. 上生产必须搞定的事:并发扛压与可观测性

4.1 决策点七之一:Agent 怎么扛并发

“AI Agent 怎么扛并发”这个热词我在社区里看到很多次,说明这是大家公认的痛点。Agent 和普通 API 最大的区别是:一个请求不是一次模型调用,而是一串循环调用,单次任务可能消耗几十秒甚至几分钟。如果用同步方式处理,线程很快被打满,服务直接雪崩。

扛并发的第一原则:把 Agent 执行从 Web 请求链路中剥离出来。Web 层接收请求后,把任务写入队列立即返回,后台 Worker 从队列里取任务执行,执行结果通过回调、WebSocket 或轮询返回给前端。这个模式下,Web 层是无状态的,并发能力取决于消息队列,Agent 执行层则可以通过增加 Worker 数量水平扩展。

第二原则:模型调用层必须做限流和重试。大模型 API 有速率限制,突发流量会导致 429 错误。常见做法是令牌桶限流,控制每秒请求数;重试必须用指数退避加抖动,不然并发失败会形成重试风暴。

第三原则:状态持久化。Agent 的中间状态(当前步骤、已生成的输出、工具调用记录)如果只存在内存里,Worker 一旦重启任务就丢了。生产环境应该把 Agent 状态写进 Redis 或 PostgreSQL,这样 Worker 可以随时接管未完成任务,也方便排查问题。

还要注意冷启动延迟。Agent 任务本身耗时长,首 token 延迟反而不那么重要。真正影响体验的是排队延迟,所以队列消费速度要监控起来,及时扩容 Worker。

4.2 决策点八:可观测性与效果评估

Agent 的调试难度远超普通应用,因为它每个任务都是一个多步决策过程。第七个决策点是:怎么让 Agent 的行为可以被观察、被衡量。

可观测性至少要有三层。第一层是链路追踪,每一个 Agent 任务从开始到结束,每一步调用模型、调用工具、状态流转都要有 trace,方便定位是哪一步出了问题。可以用 LangSmith、Langfuse 这类专用工具,也可以用 OpenTelemetry 自己接。

第二层是指标监控。最重要的是任务成功率、平均完成时长、Token 消耗量、工具调用失败率、单任务成本。这些指标要按天聚合,观察趋势,效果退化往往不是突然发生的,而是指标缓慢爬坡。

第三层是评估体系。没有评估就没有迭代方向。建议给 Agent 准备一个评测集,包含典型任务和边界情况,每次修改 prompt 或工具定义后跑一遍评测集,对比通过率。这个流程和传统软件的回归测试非常像,是 Agent 工程化必不可少的环节。评测可以用模型当裁判(LLM-as-a-judge)来自动打分,也可以人工抽检,两种结合最稳。

5. 实战复盘:一个内容发布助手的完整工程实现

5.1 场景与需求拆解

理论讲再多,不如看一个具体案例。我以一个内容运营场景为例:团队需要 Agent 根据选题要求生成内容草稿,从素材库检索相关资料,按品牌模板排版,最后进入人工审核队列。这里我特意把“发布”环节设计成人工确认,而不是让 Agent 直接自动发布,因为自动发布到公共平台是高危操作,内容合规、平台风控都是现实约束,人工确认是工程上最稳妥的兜底方案。

这个场景覆盖了大部分 Agent 工程要点:感知输入(选题需求)、规划(生成内容方案)、工具(检索素材、排版模板)、状态管理(草稿状态流转)、并发(多人同时提交需求)、可观测性(追踪生成链路)。

5.2 技术选型与目录结构

技术栈选型如下:FastAPI 做 Web 层和 API 入口;LangGraph 做 Agent 编排;LangChain 做模型调用和工具封装;PostgreSQL 存任务状态,Redis 做任务队列和缓存;内容输出存对象存储。

目录结构保持简单清晰,核心模块按职责拆开,避免把逻辑全堆在 main.py 里。

agent_service/ ├── api/ │ └── main.py # FastAPI 入口 ├── agent/ │ ├── graph.py # LangGraph 状态图定义 │ ├── nodes.py # 各节点实现 │ ├── tools.py # 工具定义 │ └── prompt.py # Prompt 模板 ├── worker/ │ └── consumer.py # 队列消费 Worker ├── storage/ │ ├── task_repo.py # 任务状态存储 │ └── memory.py # 记忆管理

5.3 核心代码骨架

用 FastAPI 接收请求,立即写入任务队列。这一步非常关键,Web 层绝对不能同步等待 Agent 跑完,否则一个请求就占住一个 Worker 线程几十秒。

from fastapi import FastAPI from redis import Redis app = FastAPI() redis = Redis(host="redis", port=6379, decode_responses=True) @app.post("/api/tasks") def create_task(req: dict): task_id = generate_task_id(req) # 任务状态初始化为 pending redis.hset(f"task:{task_id}", mapping={ "status": "pending", "input": req.get("brief"), "step": "0", }) # 写入队列,让后台 Worker 消费 redis.lpush("agent_task_queue", task_id) return {"task_id": task_id, "status": "pending"}

LangGraph 部分定义一个简单的四节点状态图:planning 节点生成内容大纲,retrieval 节点检索素材,drafting 节点生成草稿,formatting 节点按模板排版。关键是要设置最大步数,防止 Agent 反复循环。

from langgraph.graph import StateGraph, END from typing import TypedDict, Optional class TaskState(TypedDict): brief: str plan: list materials: list draft: Optional[str] formatted: Optional[str] step_count: int def planning_node(state: TaskState): # 调用模型拆分内容方案 return {"plan": generate_plan(state["brief"])} def retrieval_node(state: TaskState): # 调用素材检索工具 return {"materials": search_materials(state["brief"])} def drafting_node(state: TaskState): # 根据方案和素材生成草稿 return {"draft": generate_draft(state["brief"], state["plan"], state["materials"])} def formatting_node(state: TaskState): # 调用排版工具,输出最终内容 return {"formatted": apply_template(state["draft"])} graph = StateGraph(TaskState) graph.add_node("planning", planning_node) graph.add_node("retrieval", retrieval_node) graph.add_node("drafting", drafting_node) graph.add_node("formatting", formatting_node) graph.set_entry_point("planning") graph.add_edge("planning", "retrieval") graph.add_edge("retrieval", "drafting") graph.add_edge("drafting", "formatting") graph.add_edge("formatting", END)

5.4 并发与幂等设计

这个系统里的并发压力在 Web 层和模型调用层。Web 层通过 Redis 队列削峰,Worker 按消费能力处理任务,天然限流。模型调用层必须做速率限制,防止多 Worker 同时打爆模型 API。

幂等设计也要考虑进去。在实际项目中,模型调用可能失败后重试,如果任务状态没有做幂等处理,同一个任务会被重复提交。解决方法是任务 ID 生成时带上请求内容的哈希值,Worker 消费前先检查任务状态,已经处理过的直接跳过。这一步很实际,不做的话,线上会跑出很多重复任务。

6. 常见问题与排障实录

6.1 Agent 进入死循环怎么处理

死循环是 Agent 最经典的问题:模型反复调用同一个工具,或者反复给出一模一样的错误计划。我在项目里至少遇到三次,第一次是模型拿到工具报错后不换思路,而是重试同样的参数。解法分两层:第一层是硬性保护,在循环里加最大步数限制,到步数强制终止并返回超时错误;第二层是软性引导,在 prompt 里明确写“如果上一步失败,必须改变策略而不是重试”,同时在工具返回里加上错误提示让模型意识到要换方案。两步都做,死循环率会大幅下降。

6.2 工具参数幻觉与返回异常

模型在调用工具时生成错误参数,是工具型 Agent 最常见的失败模式。比如说调用搜索工具时把查询词写成空字符串,或者把日期参数格式写错。做校验是必须的:工具函数在入口处严格校验参数类型和必填项,不合法就直接返回错误,不要把脏数据传进下游。更好的一层是加 few-shot 示例,在工具描述里直接给出正确和错误的参数示例。实际经验是,给模型看一两个正例,参数错误率能降一半以上。

6.3 上下文膨胀与记忆污染

Agent 跑久之后,上下文里塞满了历史调用记录和低价值信息,模型开始“遗忘”最初的任务目标。我见过最夸张的一个案例,Agent 跑 20 多轮后居然把用户的原始需求忘了,开始自由发挥。解法就是前面提到的记忆分层:定期把中间推理和工具返回压缩成摘要,把关键信息写入长期记忆,及时清理上下文里的噪声。不要指望模型自己区分哪些信息重要,这要靠工程手段控制。

6.4 压测不达标与冷启动延迟

还有一个常见问题是并发压测时表现和预期差距很大,原因往往不在模型,而在任务排队和 Worker 数量不匹配。排查思路是先看 Redis 队列积压情况:如果队列持续增长,说明消费能力不足,需要扩容 Worker;如果队列正常但响应慢,就要看模型 API 的延迟和限流情况。冷启动延迟方面,可以在业务低峰期预热模型连接池和常用工具缓存,能省掉一部分首轮延迟。

说点我在实际项目里的体会:做 Agent 工程,最难的不是写出能跑的代码,而是让 Agent 在一千次运行里都不出大错。模型本身有随机性,工程手段就是给这种随机性加上护栏。宁可多用两步状态检查和权限控制,也不要让模型自由发挥。这个思路在多次上线踩坑之后,我越来越认为是做 Agent 的底线。如果你正在做类似的系统,先把七要素对齐,再把七个决策点逐一确认,跑通后再谈优化,这条路会走得稳很多。

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

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

立即咨询