1. 我为什么认为 agent-native 是一次架构级别的转身
1.1 大多数"AI应用"其实只是调了个大模型接口
过去一年里我看过不少号称"AI 驱动"的产品,扒开外壳之后发现套路都差不多:传统后端不动,前端插一个聊天框,大模型被封装成一个 REST 接口,业务逻辑该怎么写还是怎么写。你问它"帮我查一下上周的订单",它确实能聊,但真正去翻数据库、改数据、触发流程的,还是你手写的那堆老代码。LLM 在这里只是一个人肉翻译器,把自然语言翻译成固定的几个入口参数。
这种做法的好处是稳妥,坏处是天花板很低。任何一个稍微复杂一点的任务,比如"把这三个客户的账单合并起来,去掉重复项,再生成一封沟通邮件",翻译器模式就会撞墙——如果后端没有一个现成的"合并账单并发电邮"接口,你就要为每一个新需求写一个新的接口。你越做越像在给大模型打工,而不是在利用大模型。
agent-native 的思路完全是另一个方向。它默认一件事:系统里真正的执行者是一个(或一群)AI Agent,而不是传统代码里的 controller 和 service。人的角色从"逐步操作软件"变成"表达意图、给出边界、验收结果"。这不是把 LLM 塞进现有系统的缝里,而是让 Agent 成为软件的主体,传统模块全部退化成它手里的工具。
1.2 两者最本质的区别在数据和控制流的方向
传统架构的控制流是"用户 → 界面 → 业务逻辑 → 数据",每一步都是确定性的,开发者能预判所有路径。agent-native 的控制流变成了"用户 → Agent →(规划→调用工具→观察结果→再规划)→ 数据",中间那一段是模型生成的、动态的、无法穷举的。这意味着你不能再靠"把所有分支都写出来"来保证系统正确,你得靠约束、护栏、评测和观测来兜底。
我第一次做这种转身时最直观的感受是:数据库表设计变了。以前订单表只需要存业务字段,现在要给 Agent 预留"意图记录""中间结果""任务状态"这些原来根本不会出现在业务表里的东西。API 设计也变了,以前接口给人看,要友好、简洁、有分页;现在接口给 Agent 看,要语义明确、参数自解释、错误信息可理解。连日志系统都变了,人看的日志按请求打就行,Agent 的日志得按轨迹打,一条任务可能横跨十几个工具调用。
所以我把 agent-native 定义成一种完整的架构身份:从底层的存储结构、中间层的接口设计,到上层的交互逻辑,全都围绕"自主 Agent 如何更好地理解、决策、行动"来重建。你不可能只在"提示词"层面玩出 agent-native,它不是咒语,是工程体系。
2. agent-native 架构的四个设计支点
2.1 工具不是接口,是一等公民
在传统架构里,一个 API 的价值取决于它的性能、稳定性和文档。在 agent-native 架构里,工具(tool/function)是 Agent 感知世界和改变世界的唯二通道,它的价值取决于"Agent 能不能在上下文中正确理解它并在合适的时机调用它"。
这意味着两件传统后端开发几乎不会做的事:第一,你要为每个工具写一段给"机器看"的自然语言描述,这段描述的质量直接影响模型的选型准确率;第二,你要让工具具备自我描述能力——Agent 在运行中可能需要发现新工具,而不是靠开发者在提示词里把全部工具列表硬编码进去。工具注册表(tool registry)在 agent-native 系统中的地位,相当于传统系统里的 API 网关。
我在实际操作里会为每个工具维护三份东西:JSON Schema 定义(参数结构)、给模型看的工具描述(两句话讲清楚干什么、什么时候用)、给人类看的文档(方便排查)。Schema 错了,模型会幻觉参数;描述模糊了,模型会在多个相似工具之间随机跳。这三样都做到位,工具层才算合格。
2.2 记忆与状态:从无状态接口到有状态主体
传统的 REST 接口默认无状态,每个请求自带完整上下文,用户身份靠 token 识别。但 Agent 天然有状态——它要记住用户刚才说过什么、自己已经做了哪几步、哪份文档已经读过了。如果你把状态全扔给模型上下文,很快就会撞上 context window 的上限;如果不做状态管理,Agent 多轮任务会反复犯同样的错。
我建议把 Agent 的状态分成三层来设计。短期记忆放当前任务的过程数据,比如已执行的工具调用序列、中间决策理由,这部分住在上下文窗口里;工作记忆放跨步骤的业务数据,比如正在处理的订单列表、已经合并的账单 ID,这部分要落到 Redis 或专门的 state store 里;长期记忆放用户偏好、历史结论、可复用的经验,这部分落到向量库或结构化存储里。三层之间要有明确的读写接口,而不是让 Agent 自己拿上下文塞。
踩过一个很典型的坑:一开始图省事,让 Agent 把全部中间结果都存在上下文里,结果任务一长,模型开始把旧数据当新数据用,甚至把两个订单的信息混在一起。后来改成"关键业务数据必须落库,上下文里只保留引用 ID",准确率立刻上去一截。
2.3 从请求-响应到持续运行的事件循环
传统 Web 应用是短连接思维:一个请求进来,一个响应出去,完事。Agent 系统是长任务思维:一个目标进来,Agent 要规划、调用工具、等待反馈、失败重试、可能要征求用户意见,整个过程可能是几十秒,也可能是几小时。
这就要求你的运行时(runtime)具备事件循环能力。我常用的是一个非常朴素的状态机:待处理(pending)→ 规划中(planning)→ 工具调用中(tool_use)→ 等待反馈(waiting_input)→ 完成(done)→ 失败(failed),任何一种中间状态都可以被打断、恢复、超时处理。数据库里有一条任务表,字段包括目标、状态、已用预算、agent 上下文句柄、下一步 pending 的动作。
为什么强调这一点?因为生产环境里 Agent 一定会遇到"调用第三方接口 30 秒没返回""用户临时打断要求换个方案""模型服务限流"这类情况。如果你的运行时假设 Agent 是一次性同步调用,这些场景全都会变成线上事故。把整个运行过程改造成可恢复的事件流之后,我处理这类问题的思路就从"保证不出错"变成了"出错后能回到任意检查点继续"。
2.4 上下文即产品:上下文工程而不是提示词工程
现在圈子里还在热烈讨论"提示词工程",但在 agent-native 架构里,我更愿意提"上下文工程"。因为决定一个 Agent 行为质量的,不是那几句 system prompt 写得有多花哨,而是它在每一步决策时手里到底握着什么信息。
上下文工程的本质是信息编排。你要在正确的时刻,把正确的信息放进模型视野,把无关信息挡在外面。比如一个处理售后的 Agent,它查用户订单时只需要该用户的近期订单摘要,不需要把全量订单历史全塞给它;它调用退款工具之前,给它的上下文是退款政策摘要和本次订单明细,而不是漫无边际的产品手册。
实际操作时我会给上下文划分区域:固定指令区(系统人设与硬性约束)、动态记忆区(任务状态与中间结果)、工具反馈区(最近一次工具返回数据)、用户输入区(最新指令)。每个区域有 token 预算,比如固定指令区常年控制在 2k token 以内,动态记忆区控制在 8k 以内,超了就做摘要压缩。这样既不浪费钱,又不会因为上下文过载导致模型"忘事"。这四类设计做完,agent-native 的地基基本稳了,接下来要把地基上的"砖"一块块砌好。
3. 把 API 改造成 Agent 能"看懂"的东西
3.1 工具定义的质量决定了 Agent 的下限
接手过不少团队的 Agent 项目,我发现一个共性规律:凡是 Agent 表现差的项目,八成问题出在工具层,只有两成出在模型本身。模型再聪明,如果递给它的工具是"黑盒",它也只能靠猜。
一个合格的工具定义至少要说清四件事:这个工具是干什么的、什么时候该用它、什么时候不该用、每个参数到底是什么意思。例如有一个"彻底删除订单"的接口,如果描述只写"删除订单",模型很可能在用户说"把不需要的订单清一下"的时候,直接调用它把数据抹了。你需要在描述里加上"本工具会物理删除订单且不可恢复,仅在产品经理明确要求清除测试数据时使用;普通取消请求应调用'取消订单'工具"。这种描述看似啰嗦,但它是 Agent 不犯低级错误的关键保障。
3.2 一个工具描述改写的前后对比
我拿一个真实例子说明改写的效果。之前有个工具,原来的描述是这样的:
get_orders(user_id, status, page)描述写的是:"获取订单列表。"——就这一句。结果是 Agent 经常在查询时需要翻页却不知道传什么参数,或者把用户 ID 和订单状态搞混,导致返回错误数据。
我改成了这样:
{ "name": "get_orders", "description": "根据用户 ID 查询该用户的订单列表。当用户询问'我买了什么''订单到哪了'时使用。返回数据按创建时间倒序排列,每页默认 20 条。若要获取下一页,请使用返回结果中的 page_token 并传入相同参数。历史订单超过 90 天的不会出现在结果中,如需查询请使用 search_archived_orders 工具。", "parameters": { "user_id": {"type": "string", "description": "用户唯一标识,格式为 uuid,来自用户会话上下文"}, "status": {"type": "string", "enum": ["pending", "paid", "shipped", "completed", "cancelled"], "description": "按订单状态筛选;不传时返回全部状态"}, "page_token": {"type": "string", "description": "分页游标,由上一次调用的返回结果提供,首次查询不传"} } }改了之后效果立竿见影:工具选错率降低,需要人工介入纠正的对话轮次少了大约 60%。我把这归因为三个字——自解释。工具能自解释,Agent 就不需要靠猜,也不需要靠 system prompt 里的各种"防呆咒语"。
3.3 工具注册、发现与冲突处理
当单个 Agent 的工具数量超过 20 个之后,另一个问题会浮出来:模型在每一步决策时要从几十个工具里选一个,选错的概率迅速上升。我见过一上来就挂 60 个工具的 Agent,效果反而比只挂 8 个工具时差得多。
解决思路不是"减少能力",而是"分级暴露"。我把工具按使用频率和风险等级分成三层:常驻层是 Agent 一问一答必然要用的工具,比如查询、算数、格式化,始终在上下文中;按需层是根据任务类型动态加载的领域工具,比如处理退款时挂载退款相关工具;特权层是高风险操作,比如删除数据、发送邮件给客户、修改价格,默认不暴露,只有在 Agent 明确输出"需要权限"信号并且人工授权之后才挂载。这个方案实操下来,工具选择的准确率提高很明显,而且顺带解决了安全问题——高风险工具不在视野里,Agent 自然不可能误调。
冲突处理是另一个容易忽略的点。当两个工具功能相似时(比如"修改订单地址"和"修改订单收货人"),模型会随机选。我的做法是保留一个,另一个要么合并参数,要么在描述里写清楚"此工具不处理收货人变更,请调用 XX 工具"。工具层史上最经典的 bug 就是这么来的——一个不存在的分支让 Agent 在循环里反复横跳,后来才知道是工具描述没写清楚边界。
3.4 用协议思维做工具层:MCP 只是开始
最近 Model Context Protocol(MCP)很火,很多人问我要不要上。我的看法是:MCP 解决的是"工具如何被标准化地暴露给 Agent"的问题,它把每个工具封装成标准化的 resource/tool/prompt 三种原语,让 Agent 可以在运行时动态发现工具。这确实是 agent-native 架构缺的一块拼图。
但协议不是银弹。MCP 标准化了传输格式,没有标准化工具内部的业务语义。你依然要花力气写工具描述、做权限控制、设计错误码。我更愿意把它当作一种工程规范来用:所有内部工具都走同一套 schema 标准,未来接外部 Agent 生态时无缝迁移。先把内部的工具治理做好,再考虑协议级别的问题,顺序不要反。
4. 单 Agent 打天下,还是上多 Agent 协作
4.1 什么时候拆分 Agent
我刚入局时迷信"一个超级 Agent 干所有事",很快发现它撑不住。原因不是模型能力不够,而是上下文管理和工具选择失去了焦点。一个 Agent 又管数据分析又管客户沟通又管退款审批,它的上下文里全是互相冲突的指令,工具列表长到模型开始瞎选。
拆分的信号有三个:任务之间的工具集几乎不重叠;任务对状态的读写边界清晰;不同任务需要不同的人设和回复风格。比如客服机器人就可以拆成三个:客服 Agent(处理咨询)、售后 Agent(处理退换货)、质检 Agent(审核高风险操作)。它们各管一摊,工具集互不干扰,状态也有明确的领域边界。满足这三个条件时,拆开一定比混着好。
4.2 常见编排模式:编排者-工人、流水线、混合
多 Agent 协作的编排模式,我在项目里用的主要有三种。
编排者-工人模式(orchestrator-worker):主 Agent 负责拆解目标、分配子任务、汇总结果,工人 Agent 只干一件事。适合任务类型多但每类任务独立的场景,比如"写一份市场分析报告"——编排者决定去查数据、读竞品页面、生成图表、写结论,分别派给不同工人。
流水线模式(pipeline):每个 Agent 处理固定阶段的输入并输出给下一个。适合流程固化、顺序稳定的场景,比如"舆情预警→摘要生成→风险定级→通知值班人",每个环节的 Agent 只用关心自己那一截数据。
混合模式:大部分任务走流水线,遇到异常由编排者介入重新规划。这是生产环境中我最常用的,既享受了流水线的稳定,又保留了编排者的灵活性。
调度参数上有一个很实际的建议:给每个子任务设置独立的超时和重试次数。比如查询类工具超时 10 秒最多重试 2 次,生成类任务超时 60 秒最多重试 1 次。别把重试交给 Agent 自己决定,模型在失败时往往会"换个说法再试一次",这在某些场景等同于刷钱。
4.3 多 Agent 最难的不是通信,是共享状态
多 Agent 系统里,大家第一反应是设计 Agent 之间的消息协议。但我在实践中发现更难的是共享状态的控制。多个 Agent 并发跑,都要读写同一个订单对象,谁能改、谁只能读、改坏了怎么回滚,这些问题不早设计好,协作模式再漂亮也会崩。
我的方案是引入"工作台"概念:每个业务对象有一个 owner Agent,其他 Agent 只能通过 owner 的接口间接读写。比如订单的 owner 是售后 Agent,质检 Agent 想给订单加一个"风险标记",它不能直接改订单表,只能调用售后 Agent 暴露的"add_risk_flag" 工具。这跟传统后端里的"聚合根"思想很像,只不过现在执行者从代码换成了 Agent。谁拥有这个对象,谁就对它的数据一致性负责,这样即使 Agent 行为不可预测,数据损坏的范围也被圈住了。
4.4 用 Message Bus 还是用记忆共享
多 Agent 通信有两种实现路线,我两种都试过。一种是消息总线(Message Bus),Agent 之间发事件,比如"订单状态已变更";另一种是共享记忆区,Agent 都可以读取一个公共的"黑板",在上面写过程信息。前者适合事件驱动、实时性要求高的流程,后者适合有大量上下文需要分阶段积累的任务。
我的建议是别二选一,而是区分信息类型:任务指令走消息总线,语义是"请你去做这件事,做完回复我";过程事实写共享黑板,语义是"这个任务的最新状态长这样"。两者都在同一套事件系统上实现,只是消息类型和权限不同。有一次我把两类信息混在一个 channel 里,结果 Agent 把别人的中间结果当成给自己的指令执行,那场面相当混乱。
5. Agent 可观测性与评测:比传统测试难一个量级
5.1 没有轨迹追踪,Agent 项目等于盲飞
传统后端调一个接口,链路追踪是锦上添花;Agent 项目求一个链路口径混乱、调用随便失败,链路追踪则是保命底线。一个 Agent 任务从用户输入到最终输出,中间可能有十几轮"模型推理→工具调用→结果回填",任何一轮出了问题,最终结果都可能是垃圾。你必须在每一轮把思考过程、工具调用参数、工具返回值、模型响应全部落日志。
我在项目里直接采用 trace 机制:一个任务一条 trace,每个工具调用一个 span。关键字段包括:本轮模型的完整输入(当时的上下文快照)、输出内容、工具名、工具参数、工具返回状态码、耗时。排查一次回答质量下降的问题,我通常直接看轨迹而不是重新跑一遍,因为 Agent 的执行是非确定性的,重跑大概率复现不了原问题。
5.2 评估 Agent 要拆成四个维度
Agent 评测和传统功能测试有个根本差别:没有固定的"期望输出"。同一个问题,Agent 可能用完全不同的路径完成,但结果都可能正确。所以不能用单元测试那套思路,我拆成四个维度来做评估。
任务完成率:给定一组标准任务,人工或用一个裁判模型判断 Agent 是否达成了目标。这个指标最直接。
工具调用有效率:统计所有工具调用里,真正对推进任务有贡献的比例。如果 Agent 反复调同一个工具且参数一模一样,说明它陷入死循环。这一维度我定了一个硬性指标:连续两次相同参数的调用视为异常,要触发中断。
成本与延迟:每一千个任务的平均 token 消耗、平均调用次数、p95 延迟。Agent 项目里模型费用不是线性的,因为一次任务的调用次数不可控,不设预算真的会失控。
有害行为率:Agent 是否触发了高风险工具、是否泄露敏感信息、是否在没有授权时执行破坏性操作。这是一个一票否决的指标,只要有害行为超过阈值,系统必须下线。
5.3 成本治理:给 Agent 装上"预算表"
我第一次跑正式 Agent 产品时,一个月成本比预期高了两倍,原因后来一查,就是少量任务失控,单个任务调了上百次工具。治理思路不能靠模型自觉,要靠运行时约束。
我在运行时核心做三件事。第一,步数上限:单个任务最多允许 N 次工具调用,超了就强制中断并要求 Agent 总结已做事项,交给用户决定是否继续。第二,预算上限:按任务维护一个 token 计数器,模型调用前检查本次预估 token 是否会超预算,超了就拒绝执行下一步。第三,成本熔断:设置单任务成本阈值,一旦超过阈值自动降级为"只读模式",Agent 只能查询不能写操作,直到用户确认加预算。滴几个月的经验下来,这套约束让账单回归理性,虽然偶尔会中断一些真实需要长任务的场景,但总体收益远大于损失。
6. 从踩坑到落地:几条操作层面的建议
6.1 先在流程最稳定的环节引入 Agent
讲完架构层面的东西,说点落地顺序的建议。很多团队上来就想让 Agent 处理所有客户消息,结果被各种 edge case 淹没。我的建议是反着来:先从流程最稳定、容错最好、人类已经高度标准化了的环节开始。比如把"工单自动分诊"给 Agent 做,而不是先把"客户投诉处理"交给 Agent。分诊任务结构清晰、判断边界明确、错了也不会造成大事故,非常适合作为 agent-native 架构的第一个练兵场。
第一个场景跑通之后,你会积累一套自己的"Agent 靠谱度"感觉——大概能预估模型在什么条件下靠谱、什么条件下需要人兜底。带着这个感觉,再逐步把更复杂的环节接进来,比一上来就搞大而全稳妥得多。
6.2 给 Agent 设置三类护栏
Agent 的自主性是一把双刃剑。我在生产环境里固定用三类护栏兜底。操作护栏:高风险工具必须人工授权,授权采用一次性 token 机制,用户点了"允许"之后这个 token 只能用一次。信息护栏:设置敏感信息过滤规则,Agent 的输入输出都要过一遍脱敏层,身份证号、手机号这类字段在进入模型之前就打码。行为护栏:定义 Agent 不能自主执行的动作清单,包括承诺赔偿、修改价格、对外发布内容,这些只能由人来做,Agent 最多生成建议并附上草稿。
6.3 我的实践经验:先跑通再优化,先约束再扩展
最后分享一点个人体会。我在 agent-native 这条路上最大的教训是:不要试图第一次就构建一个完美的自主系统。自主性的边界应该随着评测体系的完善逐步放宽。一开始把 Agent 的决策权限设得很窄,跑通了,评测指标稳了,再一点点扩大它的自主范围。这比一开始就全放开,然后被线上事故打回原形要划算得多。
另一个小技巧:给 Agent 系统留一个"手动降级开关"。遇到大规模异常时,一键把系统切换回纯人工模式。这个开关我从来没真正用过,但它的存在让整个团队敢放手去升级,那种心理安全感在长期迭代里非常重要。agent-native 是方向,但不是一蹴而就的工程,用迭代的心态做,每次只前进一步,慢一点反而快。