做 Agent 做了差不多两年,从最初的"套个 Prompt 调 API"到现在自己搭了一套偏生产的框架,中间踩过的坑和绕过的弯比预期多不少。最近不少朋友在选型,或者在 demo 跑通后不知道怎么继续往下走,问的问题都很相似:Agent 到底该有什么、不该有什么?模型已经很强了,为什么工程上还是一团乱麻?所以我想从一个工程实现者的角度,把 Agent 系统拆成两部分来讲:第一部分是构成 Agent 的七要素,第二部分是实现时绕不开的七个决策点。掌握这两块,基本就能回答"Agent 是怎么做出来的"以及"我的 Agent 为什么需要做成这样"。
这七年里我自己的体会是,Agent 并不神秘,它本质上就是一套"模型+状态+工具+策略"的组合。难点不在模型选择,而在于你得在七个关键节点上做出取舍,每一步取舍都会影响最终系统的稳定性、成本和用户体验。下文会尽量把每个要素和决策点讲透,并附上我实际项目中的做法,希望能帮你少走点弯路。
1. 先从根上想清楚:Agent 到底是一个新东西,还是换了个说法的老系统
很多团队把 Agent 想成"一个超级聪明的大模型,能听懂人话然后直接干活"。这个描述不完全错,但它在工程上是没法落地的。真正落地的时候,你会发现 Agent 是一个由若干组件组成的执行系统,LLM 只是其中那个负责"思考"的部件。你还需要给这个部件提供信息、提供工具、提供反馈,还要管它什么时候停下。
1.1 如果你还分不清 Workflow 和 Agent,就先别急着画架构
现在业界关于 Agent 跟 Workflow 的区别吵得很厉害。我的简化理解是这样的:Workflow 是预先定义好的固定路径,每一步做什么、调用什么工具、如果出错走哪条分支,都是写死的;而 Agent 则是把路径选择权交给模型,让模型根据输入动态决定下一步调用什么动作。说白了,Workflow 是"考勤打卡",Agent 是"自由职业者"。
但在工程里,这两者不是对立的,往往是一个 Agent 系统内部既包含固定 Workflow,又包含动态决策。比如用户请求进来先做意图识别,这是 Workflow;识别完以后决定调哪个 API、要不要追问上下文,这是 Agent 的能力。把"认为所有逻辑都应该动态化"和"认为动态化就是玄学"两种观点融合起来,才能做出既能跑得稳定又能应对不确定性的系统。
1.2 从"会聊天"到"会干活",真正变化的是控制流
普通聊天机器人只有"理解-生成"两个步骤,Agent 多了一个关键循环:理解 – 规划 – 执行 – 观察 – 再规划。也就是常说的 ReAct 循环。
这个循环里最重要的不是模型厉害,而是"观察"这一步。很多 Agent 应用做得很笨,是因为模型输出一个工具调用结果后,系统没有认真观察返回值就直接进下一步。观察这一步承担的是"把外部世界的信息变成模型可读的反馈",没有它,Agent 就缺少了闭环,容易在错误的假设上一路狂奔。
我见过很多失败的 Agent 项目,本质都是把"循环"建错了。要么循环得太狠,模型反复调用同一个失败工具却停不下来;要么循环得太浅,调完一个工具就把结果甩给用户,不去判断结果是否满足需求。这个度怎么控制,我放到后面的推理循环决策点里细讲。
1.3 为什么要专门提出"七要素"
所谓七要素,是我跟团队复盘了多个 Agent 项目之后总结出来的一套"零件清单"。它不是学术定义,更像一个工程 checklist。当你准备开发或者评估一个 Agent 方案时,拿这七个名字去对照,就能快速发现系统里缺了哪块。
它们分别是:模型底座、指令与角色、推理模块、工具集、记忆系统、上下文管理、行动与反馈。这七个要素缺了任何一个,都会有明显的问题:没有记忆,Agent 是金鱼;没有推理模块,Agent 是简单的命令解释器;没有行动反馈,Agent 只是一个更贵的聊天机器人。很多人把 Agent 做挂了,恰恰是因为只盯着"模型+工具"两个要素,其他五个全在裸奔。
2. 七要素拆开看:每个零件在系统里到底是干什么的
既然确定了 Agent 是一套组合系统,接下来就要把每一个要素讲透。注意我这里没有用"模块"来称呼,因为它们不一定是独立模块,有的要素可能是模型行为的一部分,有的要素需要你专门写代码来实现。理解这一点,对后续决策非常重要。
2.1 模型底座:不是越强越好,而是越合适越好
模型底座是整个 Agent 的"脑",负责理解输入、生成推理步骤、输出指令。常见的可选范围包括通用大模型、代码专用模型、轻量级模型等。
我和团队在做 Agent 时,总结过一个简单粗暴的选型标准:如果 Agent 的重心是"会使用复杂工具",那么模型本身的工具调用能力(Function Calling)必须强,至少不能频繁出现参数幻觉;如果 Agent 的重心是"长文本分析",那模型上下文长度和遵循指令的能力比工具调用更关键;如果 Agent 运行在边缘端,那模型参数量就得小到能塞进设备内存。
很多人一上来就上最强的模型,结果延迟高、成本高,精度提升比例却非常有限。更好的做法是分层:场景复杂度低的对话走小模型,需要深度推理和大量工具组合的任务走大模型。成本优化这件事,从 Agent 选型的第一天就要开始想。
2.2 指令与角色:这道工序是规则的第一道闸门
指令与角色不是给模型写一段"你是一个乐于助人的 Agent"就完了。指令承担的作用是约束模型的输出格式、决策边界和语气偏向。它决定了 Agent"像谁"和"能做什么、不能做什么"。
工程上,我会把指令拆成两层。静态层是固定的 system prompt,里面写好全局规则、输出格式、敏感话题处理策略。动态层则由代码根据当前会话状态、用户画像、上下文片段实时生成。你不应该在代码里把所有情况都写死在 system prompt 里,那样 prompt 会膨胀到几千字,模型反而失去焦点。动态拼装的能力往往被忽视,但它才是 Agent 工程化的重要一步。
2.3 推理与规划:让模型"想几步"的机制设计
推理与规划是 Agent 区别于普通聊天机器人的核心。它可以是简单的"先调用搜索,搜索不到再调用知识库查询",也可以是复杂的任务分解,把"帮我订机票"拆成查航班、选座位、支付、发送确认单等子任务。
工程实现推理这一要素有几种不同的方案:一是直接依赖模型本身的 zero-shot 规划能力,Prompt 里写一句"请一步步规划";二是引入 CoT(思维链)示例,让模型按照给出的样板去推理;三是用结构化规划,比如让模型输出一个 JSON 计划数组,再由代码去逐项执行。
这三种方案的稳健性依次递增,但灵活度依次递减。最让我难受的项目经历,是团队迷信模型的"自主规划"能力,让模型完全自由输出规划步骤,结果模型生成了一个只有它自己懂的步骤列表。后来我们改成"模型先输出意图和可选动作,代码再决定执行顺序",整个系统一下就稳定了。
2.4 工具集:Agent 与外部世界交互的双手
工具集就是你提供给模型的一组函数。每个工具至少要有名称、描述、输入参数 JSON Schema 和实际执行函数。很多人有一个误解,认为工具越多越好。其实工具越多,模型选错工具的几率越大。工程上需要的是让模型"看得懂每个工具是干什么的"。
我通常给工具描述加一行"使用场景提示",例如"当用户需要查询实时天气时使用,注意城市名需要标准化后传入",这样工具调用的准确率会有明显提升。另外工具之间的边界要尽可能清晰,尽量避免两个工具的职责重叠,否则模型会把简单问题分流到复杂的工具上。
2.5 记忆系统:短期上下文与长期档案要分开管理
记忆系统解决的是 Agent 的"连续性"问题。短期记忆就是当前会话的上下文窗口,长期记忆则是以某种形式存储的用户历史偏好、历史任务记录、知识条目等。在工程实现里我倾向于把记忆分三个层次:
- 会话级记忆:存在于单次会话中,通常存对话摘要或轮次状态。
- 用户级记忆:跨会话,存储用户偏好、已验证身份、常用地址等。
- 业务级记忆:与用户无关,但属于领域知识的一部分,比如产品说明书、政策文档片段。
工程实现长期记忆最常用的方案是向量数据库 + 语义检索,把一段长期记忆切成片段,用 embedding 存储,然后在需要时检索 top-k 拼进上下文。这里最常踩的坑是"把原始内容全部塞进向量库"而不考虑隐私和时效,导致我记得的"用户信息"里混入了过期的、甚至错误的信息。记忆系统必须支持读取、写入、校验和删除,不然越积累越混乱。
2.6 上下文管理:token 是资源,不是垃圾场
上下文管理是被低估得最厉害的一环。LLM 的上下文窗口是有限的,即使现在很多模型支持几十万 token,也不代表你该把所有内容都堆进去。Token 就是成本,Token 就是延迟,Token 更是注意力分散的根源。
做上下文管理,需要考虑四件事:
- 内容选择:把检索回来的记忆、工具输出、历史对话按要求截断、摘要、重排。
- 优先级:系统指令优先级最高,其次是当前任务说明,再是近期对话,最后才是长尾记忆。
- 遗忘机制:旧对话需要自动归档,不能让一条三个月前的聊天记录占用上下文。
- 长度估算:不是数文字个数,而是按 tokenizer 估算 token 数量,达到阈值就触发裁剪。
我最常推荐的做法是"摘要 + 原始窗口两级管理"。每轮对话结束以后,把这一轮的关键信息压成一个摘要存好后序备用,但当前窗口仍保留最近几轮原始内容。这样既保证模型能感知最近细节,又不会让上下文无限膨胀。
2.7 行动与反馈:Agent 和环境的闭环
行动与反馈是 Agent 执行动作、观察结果、判断是否完成的机制。一个简单的动作是调用工具,一个复杂的动作是"等待用户授权"。行动不一定总是立刻执行,还可能涉及异步工单、人工审批、长时间运行任务。
反馈回路在真实系统中很关键。比如你调用支付工具,工具返回一个"支付成功"的状态,Agent 需要据此判断任务是否结束。但如果工具返回"超时,未知状态",Agent 应该怎么处理?是要重试,还是转人工?这就是行动与反馈在实际工程里最考验人的地方。一定要把工具返回的信息归类为:成功、失败、未知三态,并对"未知"单独制定策略。
3. 七个决策点:从能跑通的 Demo 到能上生产的 Agent
讲完"有哪些零件",接下来就要回答"怎么装起来"的问题。我在实践中总结了七个决策点,这七个点凡是有一个考虑不周,都会在线上给你颜色看。它们没有绝对正确的答案,但每一个决策你都得有依据、有预案。
3.1 决策点一:什么逻辑交给模型,什么逻辑交给代码
第一个决策点最底层,它会直接影响项目的进度和稳定性。很多人倾向于"能用模型就用模型",这是错的。模型擅长的是语义理解、文本生成、复杂条件下的模糊决策;而模型不擅长的是精确计算、强约束校验、重复百次不变的规则。
我从一个真实场景说起。当时做的是一个文案创作 Agent,用户提交产品信息,Agent 自动出一版营销文案。最开始我们把"判断文案是否包含违禁词"也交给模型去做,结果模型偶尔会漏掉,上线后出现了一丝风险。后来把违禁词校验改成代码层的敏感词库扫描,模型只负责"写得好不好",不负责"合规性"。这个小改动让系统稳定性提升了一个数量级。
所以,在做 Agent 时,你先画一条线:凡是结果可以确定性验证的,尽量走代码;凡是结果必须靠语义理解的,才交给模型。不要在模型身上赌它永远不会出错,模型只负责从"可选动作集合"里做选择,至于"这个动作是否合法"应该是规则前置判断。
3.2 决策点二:记忆存到哪里、存多久、怎么召回
记忆这个决策点很容易在项目初期被忽略,因为 demo 阶段不需要记忆,跑几轮对话看不出什么问题。但一旦用户量上来,你必然要面对"不同的用户继续上一次任务"这类需求。
我的建议分两步。第一步,先把短期记忆策略定下来,至少你的 Agent 要能记住当前会话里的关键状态(比如已经完成哪些步骤、有哪些待确认字段)。第二步,再考虑长期记忆。长期记忆在初版不需要做得特别重,用一个 KV 表存 user_id -> user_preference_json 就够用了;只有当记忆条目需要语义检索时,才引入向量库。
还要想好记忆的生命周期。像支付信息这种敏感数据,不仅不能进长期记忆,甚至短期记忆里也应当做脱敏。我在项目里一般会给记忆数据加上过期时间,比如对话摘要保留 7 天,用户偏好保留 30 天,领域知识永久但支持版本更新。这听上去不性感,但生产环境最需要的就是这种"无聊的确定性"。
3.3 决策点三:工具集到底开放到什么程度
工具集问题的本质是 Agent 的能力边界。一个 Agent 可以拥有一百个工具,也可以只拥有三个。决定这个"度"的因素不是你能调多少 API,而是你能否保证每个工具描述清晰、输出可控、调用成本可接受。
我在实践里总结了一个"工具准入标准":
- 工具必须有明确的成功/失败返回结构,不能返回裸字符串。
- 工具的副作用要可控。比如"发送邮件"和"获取邮件列表"都是工具,但前者有副作用,必须配合用户确认动作,后者可以直接执行。
- 工具的调用频率必须统计。如果某个工具一周都没有被调用过,说明它的入口太深或者描述不清楚,应重新设计。
- 工具要遵循最小权限原则。Agent 不应该持有它用不到的管理接口权限。
我在一个内部客服 Agent 项目里,一开始把全部 60 多个内部系统 API 都暴露给模型,结果模型经常调错。后来我们重新梳理成 12 个"聚合工具",比如"查询订单"这一个工具内部去聚合订单状态、物流信息、售后入口,模型只需要选择"查询订单"就可以了。工具调用准确率从 74% 提升到 96% 左右,代价只是每个工具的实现里多加了一些内部逻辑。
3.4 决策点四:Agent 自主循环到哪里停
推理循环是 Agent 的灵魂,也是导致线上事故最多的点。你需要明确设置最大迭代步数,否则一个 Agent 可能在一个问题上循环调工具直到超时。我们项目里默认最大步数是 5,复杂任务可以放宽到 8,超过阈值后直接降级为"无法完成任务,请转人工"。
除了步数限制,还要给推理循环加"条件终止器"。条件终止器可以是一个函数,它检查当前状态是否已经满足用户目标。比如目标是"查询订单状态",终止条件是"工具返回了 order_status 字段";如果工具返回的是"用户未登录"这类非目标状态,Agent 应转为提问,而不是再调一次查询接口。
这里有个工程细节:不要在每轮推理后把"完整历史对话"都塞回去。应该维护一个"状态快照",比如当前目标、已完成步骤、未解决障碍、最新观察结果。模型基于快照做下一步决策,比读几千字的聊天记录更高效,也更不容易跑偏。
3.5 决策点五:并发场景下怎么扛住流量
热搜词里很多人问"AI Agent 怎么扛并发",这确实是最现实的工程问题。大多数 Agent 的瓶颈不在 LLM 本身,而在 Agent 内部的编排和工具调用。一个简单的链式调用往往涉及多个外部 API,接口响应慢一点、超时重试多一点,整体吞吐就上不去了。
要做高并发的 Agent,我建议从三个方面下手:
一是用异步而非同步。不要让一个 HTTP 长连接把整个 Agent 执行过程全占住。把耗时工具调用变成异步任务,用队列通信,Agent 执行器与 HTTP 服务解耦。我们最初的实现是 FastAPI 同步处理,压测到 20 并发就有大量请求排队;后来改成将任务提交给内部队列,由 worker 池执行,把 LLM 调用和工具调用都用 asyncio 协程并行等待,单实例能扛的并发直接翻了 5 倍。
二是给 LLM 调用加缓存和限流。对同一问题的相似请求,可以在一段时间内直接返回缓存结果。每次调用前估算当前模型 provider 的速率限制,超阈值时排队而不是并发轰炸。扣子、LangChain 这类框架都有各自的限流策略,但我们自己实现时会更细,区分"用户级限流"和"全局限流"。
三是"瘦 Agent"架构。把重计算放到单独的服务里执行,Agent 编排层只负责调度。比如一个"文档分析 Agent",真正耗时的 embedding 和解析工作抽出去做成独立服务,Agent 编排层拿到结果再排版。这样编排层能更轻松扛并发,因为它的逻辑变薄了。
3.6 决策点六:失败降级与安全边界怎么设
Agent 的失败形式比普通接口多得多。除了网络错误、超时,还有模型输出 JSON 解析失败、工具参数校验不过、模型幻觉式地调了一个不存在的工具、上下文超长等等。每一类失败都要有预案。
我的默认策略是"三级降级":
- 一级降级:模型输出异常时,自动重试一次,并给模型附加上一次错误的详细信息。
- 二级降级:放弃模型决策,走兜底规则。比如用户的问题无法被工具覆盖,则返回统一的"我不能回答这类问题"话术。
- 三级降级:转人工,把当前上下文摘要和已尝试的动作发给人话务系统。
安全边界也是 Agent 生产化的重中之重。我强烈建议 Agent 在执行任何"有副作用"的工具前,都通过一个审批机制。最简单的审批是"用户二次确认",复杂一些的是"风险分级 + 自动审批"。资金支付、对外发布、删除数据这三类动作,绝不能让 Agent 一口气执行完。即便用户明确说"帮我支付",也最好在支付前展示订单详情并要求确认一次,因为 Agent 可能理解错了订单 id。
3.7 决策点七:可观测性和评测体系,不会让你失望
Agent 最难调试的一点是"路径的不确定性"。传统的日志只能看到接口入参和出参,但 Agent 中间经历了什么推理过程、为什么选择这个工具、哪一步导致偏离预期,都需要可观测性工具去还原。
我在项目里会为 Agent 专门设计一份"轨迹日志",记录以下内容:
- 每一轮推理的 input tokens / output tokens。
- 模型输出的原始内容(已经过脱敏)。
- 工具名称、入参、耗时、返回值摘要。
- 本轮决策依据的当前状态快照。
- 最终退出原因(正常结束 / 步数超限 / 触发安全策略)。
有了轨迹日志,才好做评测。Agent 评测不是只看最终答案对不对,还要看"路径是否合理"。我用多维度的指标来打分:任务成功率、工具调用正确率、平均步数、超时率、用户干预率。每周固定跑一批回归用例,看新改动有没有让关键指标恶化。不要相信"模型变聪明了所以不需要评测"这种话,模型一升级,Agent 的行为就可能变。
4. 案例:用 FastAPI + LangGraph 实现一个轻量客服 Agent
理论讲得再多,不如看一个具体案例。这里我分享一个我在公司内部搭过的客服 Agent 简化版,用来演示七要素和七个决策点是怎么落到代码里的。技术栈是 FastAPI + LangGraph,因为 LangGraph 的图结构很适合管理推理循环。
4.1 系统结构与状态定义
先定状态。LangGraph 会让每个节点共享一个状态字典,我们把它定义成:
from typing import TypedDict, Annotated from operator import add class AgentState(TypedDict): messages: Annotated[list, add] # 对话历史 user_id: str task: str plan: list current_step: int tools_result: dict finish: bool这个状态字典就是整个 Agent 的"白板",七要素中的记忆、上下文、行动反馈都会在这个白板上留下痕迹。节点的顺序由 LangGraph 的边来控制,模型和工具引擎各占一个节点。
4.2 三个核心节点:规划、执行、反思
LangGraph 里可以画三个节点,对应 Agent 循环。我先定义只负责调用大模型并输出结构化决策:
from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, END llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) def planner_node(state: AgentState) -> dict: # 构造精简的决策 prompt,只让模型输出下一步动作 system = """你是一个客服助手。根据当前任务、工具列表和已观察到的结果,输出下一步决策。 输出必须是JSON:{"action": "工具名或reply", "args": {...}, "reason": "简短理由"}""" user_content = f"任务:{state['task']}\n当前步骤:{state['current_step']}\n工具结果:{state['tools_result']}\n对话历史摘要:{state['messages'][-3:]}" resp = llm.invoke([{"role": "system", "content": system}, {"role": "user", "content": user_content}]) # 解析 JSON,失败则走兜底回复 import json try: decision = json.loads(resp.content) except json.JSONDecodeError: decision = {"action": "reply", "args": {"message": "抱歉,我没有理解,请重新描述。"}} return {"messages": [("assistant", resp.content)], "plan": [decision]}第二步是执行节点,根据决策调用工具:
def tool_executor(state: AgentState) -> dict: decision = state["plan"][-1] action = decision["action"] if action == "reply": return {"messages": [("assistant", decision["args"]["message"])], "finish": True} if action in tool_registry: try: result = tool_registry[action](**decision["args"]) status = "success" except Exception as e: result = str(e) status = "error" return {"tools_result": {action: {"status": status, "result": result}}, "current_step": state["current_step"] + 1} # 工具不存在,状态设成 error return {"tools_result": {action: {"status": "error", "result": "unknown tool"}}, "current_step": state["current_step"] + 1}第三步是反思节点,让模型根据工具结果判断任务是继续还是结束:
def reflect_node(state: AgentState) -> dict: last_tool = list(state["tools_result"].keys())[-1] last_result = state["tools_result"][last_tool] if last_result["status"] == "success" and state["current_step"] >= len(state.get("plan", [])): return {"finish": True} return {}然后把节点和边关系组合起来,加上最大步数限制:
graph = StateGraph(AgentState) graph.add_node("planner", planner_node) graph.add_node("executor", tool_executor) graph.add_node("reflect", reflect_node) graph.set_entry_point("planner") graph.add_edge("planner", "executor") graph.add_edge("executor", "reflect") graph.add_conditional_edges("reflect", lambda state: "finish" if state["finish"] else "planner", {"finish": END, "planner": "planner"}) app = graph.compile()你可以看到,整个推理循环被显式地用状态机管理,而不是让模型在一个巨长的 prompt 里自由发挥。这就是决策点四"循环刹车"的实际落地。
4.3 并发与部署:FastAPI 作为接入层
FastAPI 层只负责接收 HTTP 请求、构建设备初始状态、然后调用上面编译好的 graph。组件并行方面,如果工具调用是 IO 密集的,我会把它们全部定义成 async 函数,并在 executor 节点里用 asyncio.gather 并发执行,减少总耗时。LangGraph 在较新版本里支持 async 节点,所以执行层能进一步提高并发能力。
部署时我们需要给工作设定超时。FastAPI 请求的 timeout 跟 Agent 的执行 timeout 要分开,一般一个 Agent 任务最长运行 30 秒,超过就返回"任务正在处理中"并异步上报结果。这个异步化设计能让接口不被长任务拖死,也是"扛并发"的关键。
4.4 评测阶段我们做了哪些回归
上线之前,我们准备了 200 条人工标注测试语料,每条语料包含:用户提问、期望最终答案、期望调用工具、允许的步数范围。评测脚本自动跑一遍 Agent 并对比期望结果,统计工具调用正确率。每次更换模型、调整 prompt 或增删工具,都先跑这个测试集。这个习惯养成了以后,Agent 行为漂移的次数大幅减少,算是长期主义的回报。
5. 常见误区与踩坑后的个人心得
写到这里,我想把实战里最容易翻车的几个误区集中分享一下,很多都是我们线上真实出现过的,希望能给后来者一些提示。
5.1 误区:把 Agent 当成纯模型能力,忽视工程约束
有些团队测试时觉得"哇,模型自动调工具!好智能!"于是把所有逻辑都丢给模型。但一到生产,用户会输入各种奇怪的表达,模型会突然改变输出格式,工具 API 会升级导致参数变化,这种情况下没有工程约束的 Agent 就是灾难。
我的经验是:Agent 本质是一个"带 AI 大脑的确定性系统"。大脑负责理解与决策,但系统骨架、状态流转、失败兜底都必须由代码掌控。我们可以把大脑替换成不同模型,而骨架应该保持稳定。这才是 Agent 能落地的关键。
5.2 误区:上下文越长越好,记忆全存下来
我们曾经在一个数据分析 Agent 里把用户的全部历史查询都塞进上下文,结果 token 爆了,延迟从 2 秒变成 12 秒,而且模型生成的结论因为被太多噪声干扰,反而更不准确。后来我们改成"只保留当前任务相关摘要 + 最近三条查询",效果显著提升。
这里顺便提一下"AI Agent token是什么意思"这个问题:token 是模型处理文本的基本单位,一个 token 大约相当于一个英文单词的四分之三、一个中文汉字的一到两个。你给模型发多少 token、模型回答多少 token,都直接影响成本和速度。所以省 token 不是抠门,而是对系统健康负责。
5.3 误区:Agent 不需要人审、不需要安全机制
我见过最吓人的一次是某个 Agent 在没有二次确认的情况下,连续调用了三次"发送短信"工具,给用户发了一堆重复短信。模型不觉得自己做错了,因为它只是按指令执行。如果你不给 Agent 加副作用操作确认机制,它迟早会在某个巧合下做出让你头疼的事。
现在我做所有的 Agent 系统都会默认加一套安全规则引擎,把"发短信、发邮件、支付、删除、修改权限"这类操作标记为高风险。高风险工具执行前必须经过用户确认,或至少通过内部审核接口。安全机制的优先级永远高于智能。
最后分享一个实战里的小经验
在所有 Agent 项目中,对我帮助最大的一个动作是:强制保存完整的"决策轨迹"。不管模型最终答没答对,只要轨迹完整,问题就能被快速定位。项目初期大家都急着调 prompt、换模型,但不少人忽略了:真正决定 Agent 稳定性上限的,往往就是那些不起眼的状态管理和失败兜底逻辑。如果你现在正要开始做一个 Agent,我建议先拿出一张纸,把这七要素和七个决策点全部过一遍,圈出你还没想清楚的地方。把这些地方想明白再动手,后面返工的概率会小很多。