ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Agent形态频繁变化,基础设施该为谁而建?

Agent形态频繁变化,基础设施该为谁而建? 最近和几个后端团队聊 Agent 项目大家有一个共同的困惑Agent 的形态变化太快了。今天产品经理说要做一个能聊天的 Bot明天说要把内部审批流程接进来后天又说要搞一个 Multi-Agent 系统让不同角色互相协作。研发跟着需求把框架换了一轮又一轮每次框架一变原来的工程结构就要跟着推倒重排。这时候所有人都开始问同一个问题既然 Agent 形态一天一个样底层 Infra 到底该为谁而建这篇文章不打算预测 Agent 的终极形态也不推销某个具体框架。我想从工程视角拆一下 Agent 演进过程中真正稳定的部分讨论基础设施应该服务哪些对象并给出一个最小可运行的 Agent 工程骨架以及记忆、工具、可观测性、安全等关键模块的建设思路。适合正在做 Agent 开发或者准备搭建 Agent 基础设施的开发者阅读。1. 背景与核心概念Agent 形态为什么变化这么快1.1 从 Chatbot 到 Agent到底变了什么很多人会把 Agent 和 Chatbot 混在一起实际上两者的工程形态差异很大。早期的 Chatbot 本质上是“你给我一段话我返回一段话”即使接入了大模型核心链路也只是一个标准的问答接口用户输入、检索上下文、调用 LLM、返回文本。这种架构非常稳定Infra 只需要服务好模型请求、缓存和限流就可以了。但 Agent 不一样。Agent 的核心特征是有“目标导向的执行循环”它会自己决定下一步该做什么可能会调用工具、读取记忆、修正计划然后继续执行直到完成目标或达到最大轮数。这个过程里有决策、有工具调用、有中间结果回填甚至还有多个 Agent 之间互相通信。你会发现Chatbot 场景下稳定的“请求-响应”模型在 Agent 场景下变得不再够用。这就解释了为什么“形态一天一个样”不只是产品需求在变而是 Agent 本身就是一个还在快速演化的范式。从 ReAct 风格的单 Agent 循环到 Plan-and-Execute再到 Reflection 模式再到 Multi-Agent每个范式对后端的要求都不一样。Infra 如果跟着某个范式绑定就必然要频繁重写。1.2 什么是 Agent Infra这里需要区分两个概念模型 Infra 和 Agent Infra。模型 Infra 更多指 GPU 资源、推理服务、KV Cache、模型网关这些偏向模型训练和推理的设施。而 Agent Infra 指的是承载 Agent 开发、运行、观察、治理的应用基础设施包括任务调度、状态持久化、记忆存储、工具调用框架、权限与审计、可观测性、限流与成本控制。很多人会把这两层混在一起谈结果就是一个业务团队连 GPU 资源都没有却要模仿大厂的“模型 Infra 建设方案”开会讨论推理加速、分布式 KV Cache。这些内容有价值但对大多数做 Agent 应用的公司来说优先级并不高。真正决定 Agent 能不能上生产的是另一类问题任务跑到一半挂了怎么办工具调用权限怎么控制用户数据怎么隔离一次 Agent 执行花了多少钱所以讨论 Agent Infra我认为更接近讨论“面向 Agent 的应用中间件”而不是“面向大模型推理的底层设施”。这层抽象做得好上层 Agent 不管怎么换形态底层都能稳定承接。1.3 “为谁而建”是一个真实架构问题很多团队在做架构设计时第一反应是去抄开源项目的目录结构或者照搬大厂案例但抄到一半就发现怎么都不对劲。原因往往不是技术不行而是没有想清楚这套 Infra 到底为谁服务。比如如果 Infra 是为“模型调用方”建的那么核心能力是模型路由、多模型切换、上下文缓存、Token 计费业务层只要一个稳定的模型网关就够了。如果 Infra 是为“Agent 运行时”建的那么核心能力是状态管理、任务恢复、工具执行沙箱需要的是类似工作流引擎的调度能力。如果 Infra 是为“业务应用”建的那么核心能力是租户隔离、权限控制、审计日志、数据脱敏本质上更需要一套成熟的应用后端能力。这三个目标并不互斥但优先级不同。把目标当成“必须同时满足”Infra 的复杂度会迅速失控。这也是标题里“到底该为谁而建”这个问题的意义所在不先回答这个问题后面的选型、编码、架构讨论都会变成无休止的争论。2. Agent 形态演进与技术栈现状2.1 常见 Agent 形态对比在 Agent 开发领域目前比较常见的形态可以归纳为四种。第一种是“对话增强型”本质还是 Chatbot但加入了 RAG 或工具查询能力模型根据用户问题决定是否检索外部知识。第二种是“工具调用型”模型在对话中输出结构化调用指令后端执行工具并把结果返回给模型也就是当前最普遍的 Function Calling 形态。第三种是“自主任务型”模型具备更完整的计划、执行、验证循环可以独立完成多步操作算是真正意义上的单 Agent。第四种是“多 Agent 协作型”多个 Agent 各自承担不同角色通过任务分发和结果汇总完成复杂工作。从 Infra 的角度看这四种形态对后端的要求是层层递进的。对话增强型只需要模型网关、知识库、会话管理工具调用型需要工具注册中心、参数校验、执行结果回填自主任务型需要任务状态机、持久化、失败重试多 Agent 协作型还需要通信协议、共享内存和协调调度。如果一上来就按第四种形态设计 Infra会发现前三种场景根本用不上那么多东西反而增加维护成本。2.2 Agent 运行时的核心组件抛开具体框架一个 Agent 运行时的核心组件其实很固定主要包括五个部分。LLM 交互层负责模型的接入、Prompt 组装、结构化输出解析是最基本的一层。工具层负责工具的注册、发现、参数校验和执行是 Agent 与外界系统交互的通道。记忆层负责短期上下文和长期知识的读取、写入和检索决定了 Agent 能不能跨会话使用经验。编排层负责决策循环、步骤控制、失败重试和终止条件是 Agent 的“大脑骨架”。安全与审计层负责权限控制、数据脱敏、操作记录和成本监控是生产可用性的底线。你会发现无论使用 LangChain 还是 LangGraph或者干脆自研这五层都是绕不开的。真正不同的只是每一层用哪个库、自己封装多少。Infra 层的任务就是把这五层能力抽象成稳定的服务而不是把它们和某个具体框架耦合在一起。2.3 框架生态热的快稳定的少现在 Agent 框架的生态变化非常快新的项目不断出现老项目的接口也在频繁调整。有的框架擅长流程编排有的框架擅长多角色协作有的框架把开发者体验做得很好还有的框架直接在云端提供编排和模型服务。选型时最怕的不是选错而是每三个月换一次框架。面对这种生态我的建议是框架可以换但内部接口不要跟着换。在团队内部把模型调用、工具执行、记忆读写都封装成自己的内部 API无论底层用 LangChain 还是自研实现替换成本都会小很多。不要把框架的类直接泄漏到业务代码里否则框架一升级整个项目都要跟着迁移。另外现在也有一些开放协议在尝试统一 Agent 的工具接入和数据访问标准例如 MCP。这类协议的意义在于工具调用和数据源的接入方式开始标准化Agent 框架和底层 Infra 之间的边界也更容易划清。但协议还处在演进阶段实际接入时仍然需要做好兼容层。3. Infra 的三个服务层次先想清楚为谁建3.1 第一层为模型服务而建这一层面对的是模型服务和底层推理资源。典型能力包括多模型路由、上下文缓存、推理加速、Token 计费和模型灰度切换。如果团队规模足够大自研模型网关的价值很明显因为直接节约模型调用成本还能提升稳定性。但对大多数应用团队来说这层直接使用云厂商或模型服务商的 API 网关就可以了没有必要自己造轮子。尤其是当前模型供应商本身提供了较强的鉴权、计费和限流能力自建一层网关更多是锦上添花而不是雪中送炭。如果团队规模不到几十个模型调用并发花大量精力优化模型层很可能是一种浪费。3.2 第二层为 Agent 运行时而建这一层面对的是 Agent 本身的执行过程。核心要解决的问题是Agent 任务不是一次 HTTP 请求能完成的它可能执行几十步甚至跨越几分钟、几小时。执行过程中可能遇到模型超时、工具异常、进程重启这时候需要任务状态机来记录执行进度让任务可以被暂停、恢复或重新调度。这一层的建设价值很高而且比较稳定。无论上层 Agent 是哪种形态都需要状态持久化、失败重试和任务队列。具体实现上可以用 Redis 保存中间状态用消息队列做异步调度也可以用开源工作流引擎做底层。关键是抽象出一个“Agent 执行器”的概念提交任务、查询进度、取消任务、回调结果业务层只需要面对这几个接口。3.3 第三层为业务应用而建这一层是大多数团队最容易忽视也最影响生产上线的一层。Agent 一旦开始执行真实业务操作就会涉及用户数据、身份权限、操作审计、资源配额、成本控制。比如一个 Agent 能调用 CRM 系统的写入接口那它到底能用哪个账号写入写入的数据归属哪个租户每一步操作有没有日志一个用户能不能通过 Prompt 注入诱导 Agent 执行越权操作这些问题如果不提前设计Agent 项目只能停留在 Demo 阶段。很多团队 Demo 跑得很顺利一上线就发现权限模型不匹配、审计缺失、成本不可控又回到传统的应用后端改造。实际上Agent 的用户身份传递、数据权限隔离、审计日志这些能力和业务系统是强相关的必须由懂业务的团队来定义不能完全交给框架。3.4 大多数团队应该选哪一层如果让我给一条务实建议那就是不要在模型层过度投入不要在框架层过度绑定把主要精力放在第二层和第三层尤其要围绕“Agent 运行时”和“业务安全边界”来建 Infra。理由是模型层有太多现成的替代方案框架层变化太快而运行时的稳定性和业务安全边界是每个做 Agent 应用的公司都绕不开的。先把任务状态、工具权限、审计、成本这四个问题解决Agent 工程的地基才算稳。后续不管模型换成哪个框架升级到哪个版本Infra 都不会被轻易推翻。4. 实战一个最小可运行的 Agent 工程骨架下面用一个最小可运行的示例演示如何拆出“工具层”和“Agent 循环层”。这个示例不依赖任何第三方框架只用 Python 标准库方便理解核心思路。4.1 项目结构与环境先创建项目目录mkdir agent-demo cd agent-demo建议使用 Python 3.9 及以上版本示例代码只需要标准库不需要额外安装依赖。项目结构如下agent-demo/ ├── tools.py # 工具定义与注册 ├── agent_loop.py # Agent 执行循环 └── main.py # 入口演示这里把工具和 Agent 循环分成两个文件是为了体现“工具层与编排层解耦”的思想。工具只负责自己的执行逻辑Agent 循环只负责决策和调度。4.2 定义工具层先创建tools.py定义几个演示用的工具。真实项目中这些工具可以换成查询订单、写入工单、调用内部 API 等业务操作。# tools.py from typing import Callable, List class Tool: def __init__(self, name: str, description: str, func: Callable): self.name name self.description description self.func func def run(self, **kwargs): return self.func(**kwargs) def add(a: float, b: float) - float: return a b def calc_avg(nums: List[float]) - float: return sum(nums) / len(nums) def get_weather(city: str) - str: # 演示用函数真实场景请对接气象服务 return f城市 {city} 今天晴转多云气温 18~26 度。 def build_default_tools() - List[Tool]: return [ Tool(add, 计算两个数字的和, add), Tool(calc_avg, 计算一组数值的平均值, calc_avg), Tool(get_weather, 查询城市天气, get_weather), ]这里的关键是Tool类把函数包装成统一对象后续 Agent 循环只需要根据工具名找到对象并调用即可不需要关心内部实现。4.3 实现 Agent Loop接着创建agent_loop.py实现一个极简的 ReAct 风格 Agent 循环模型决定是否调用工具、生成工具参数、执行工具、把结果返回给模型然后进入下一轮。# agent_loop.py import json from typing import Dict, List from tools import Tool class SimpleAgent: def __init__(self, tools: List[Tool], max_steps: int 5): self.tools {t.name: t for t in tools} self.max_steps max_steps self.history: List[Dict[str, str]] [] def _llm(self, messages: List[Dict[str, str]]) - str: 模拟大模型返回的决策文本。 真实项目中这里应接入 OpenAI、通义、DeepSeek 等模型服务 并优先使用 Function Calling 或结构化输出而不是手工解析文本。 last_user messages[-1][content] # 工具执行结果直接透传 if messages[-1][role] user and last_user.startswith(工具 ): return last_user if 打招呼 in last_user: return 你好我是 Agent。你可以告诉我你想解决的问题。 if 计算 in last_user and in last_user: expr last_user.split(计算)[1].strip() left, right expr.split() return f需要调用工具 add参数为 {{a: {left.strip()}, b: {right.strip()}}} if 平均 in last_user: array_str last_user.split(平均)[1].strip() return f需要调用工具 calc_avg参数为 {{nums: {array_str}}} if 天气 in last_user: city ( last_user.replace(天气, ) .replace(怎么样, ) .replace(如何, ) .replace(, ) .replace(?, ) .strip() ) return f需要调用工具 get_weather参数为 {{city: {city}}} return 我不太确定怎么处理这个问题。 def _parse_tool_call(self, text: str): 从模拟决策文本中解析工具名和参数 JSON。 name text.split(参数为)[0].strip().replace(需要调用工具 , ) args_text text.split(参数为)[1].strip() return name, args_text def run(self, user_input: str) - str: messages: List[Dict[str, str]] [ {role: user, content: user_input} ] for _ in range(self.max_steps): response self._llm(messages) self.history.append({role: assistant, content: response}) if 需要调用工具 not in response: return response try: tool_call_text response.split(需要调用工具)[1].strip() tool_name, args_text self._parse_tool_call(tool_call_text) tool self.tools[tool_name] args json.loads(args_text) result tool.run(**args) observation f工具 {tool_name} 返回{result} except Exception as e: observation f工具调用失败{e} messages.append({role: assistant, content: response}) messages.append({role: user, content: observation}) return 达到最大步骤数任务未完成。这段代码模拟的是真实 Agent Loop 的核心骨架。真实项目中_llm会替换为真实模型调用返回的也不再是“加工过的文本”而是结构化的工具调用指令例如函数名和参数。但整体循环逻辑是相似的模型决定动作系统执行动作结果回填到上下文模型继续决策。4.4 编写入口并验证最后创建main.py运行几个典型输入# main.py from agent_loop import SimpleAgent from tools import build_default_tools def main(): agent SimpleAgent(build_default_tools(), max_steps3) cases [ 你好请打招呼, 计算 12, 计算 平均 [1,2,3,4,5], 北京天气如何, ] for case in cases: print(f用户{case}) print(fAgent{agent.run(case)}\n) if __name__ __main__: main()运行命令python main.py预期输出类似用户你好请打招呼 Agent你好我是 Agent。你可以告诉我你想解决的问题。 用户计算 12 Agent工具 add 返回3 用户计算 平均 [1,2,3,4,5] Agent工具 calc_avg 返回3.0 用户北京天气如何 Agent工具 get_weather 返回城市 北京 今天晴转多云气温 18~26 度。这个示例虽然简单但已经包含了一个 Agent 最基本的流程接收目标、模型决策、调用工具、观察结果、继续决策或终止。你可以在这个骨架上继续扩展记忆、权限、流控和能力而不必急着引入重量级框架。4.5 生产配置示例如果把上面的骨架放到生产环境通常还需要一份配置来描述模型、工具、安全策略和成本配额。下面是一个配置思路示例字段需要结合你实际使用的中间件和模型服务调整# config.yaml model: provider: your-model-provider name: your-model-name base_url: http://your-model-gateway/v1 temperature: 0.2 max_tokens: 2048 agent: max_steps: 8 memory: type: vector top_k: 5 tools: - calculator - weather - internal-order-query security: sandbox: docker allowed_tool_domains: [] audit_log: true user_context_field: x-user-id cost: budget_per_request: 0.05 alert_threshold: 10这份配置的核心是两点一是工具列表来自配置而不是硬编码方便上线新工具时无需改代码二是成本和审计默认开启。生产环境 Agent 一旦调用真实业务接口这两项是必须有的。5. 关键基础设施模块记忆、工具、可观测性与安全5.1 记忆层短期上下文与长期知识分开设计记忆是 Agent 区别于普通 Chatbot 的重要能力但很多团队在实现时容易把“记忆”想得过于神秘。拆开来看短期记忆就是当前任务或会话中的上下文通常直接放在模型的消息列表里量大了就需要摘要压缩。长期记忆则是跨会话持久化的知识通常包括用户画像、历史偏好、领域知识等需要存储和检索能力支撑。工程实现上长期记忆最常见的方式是向量数据库加关键词索引组合。向量库负责语义召回关键词索引负责精确匹配。需要注意的是记忆数据也是用户数据必须遵循最小权限原则不能因为 Agent 需要“记忆”就无限制地收集和使用数据。记忆读写的权限、生命周期和删除策略都要在业务层单独设计。5.2 工具调用与 MCP能力接入的标准化工具调用是 Agent 产生实际价值的核心也是 Infra 最需要管控的部分。基础形态是 Function Calling模型输出结构化调用意图后端统一执行。再进一步可以使用 MCP 这类开放协议来接入数据和工具让 Agent 不直接依赖某个私有 SDK。这里顺便说一个容易混淆的点MCP 与 Skill 的区别。MCP 更像“能力接入协议”解决的是工具和数据源怎么连的问题Skill 更偏“能力使用模板”解决的是 Agent 该怎么用这些能力的问题。两者不是替代关系而是同一套 Agent 基础设施里不同层次的东西。建 Infra 时把工具接入协议标准化把技能模板沉淀成可复用资产两者配合才能更好地支撑多种 Agent 形态。5.3 可观测性没有 Trace 就无法运维 AgentAgent 的调试难度明显高于普通接口。一个用户问题可能触发多轮模型调用、多次工具执行、多次记忆读取过程中任何一步出错都可能产生不符合预期的结果。这时候如果没有完整的链路追踪排查问题会非常痛苦。可以参考 OpenTelemetry 的思路为每次 Agent 执行生成 traceId把每一步 LLM 调用、工具调用、记忆读取都打上 span。记录的字段至少包括模型 name、输入输出摘要、Token 消耗、耗时、工具名、执行结果、错误信息。这样当用户反馈“Agent 回答不对”可以先从 trace 里看是哪一步调用导致的问题是模型决策错误、工具数据不准还是上下文被污染。审计日志和安全相关的敏感信息则不能只放在 trace 里还需要单独持久化并设置访问权限。5.4 安全与成本控制Agent 安全涉及面比较广最容易被忽略的是工具权限和 Prompt 注入。工具权限方面一个 Agent 能调用的 API 必须明确授权不能把内部系统的写接口直接暴露给模型。Prompt 注入方面外部用户输入如果混合在工具返回内容中模型很可能被诱导执行非预期动作因此要在工具结果与用户输入之间做分隔甚至对高风险操作做二次确认。成本控制则是另一个生产难题。Agent 的 Token 消耗不像普通对话那样容易预估多轮工具调用可能让一次任务的成本放大好几倍。常见做法是设置单次请求预算、任务最大步骤数、模型调用次数上限并在异常增长时触发告警。基础设施层还需要支持配额能力比如给每个租户或每个业务线设置独立的成本上限。6. 常见问题与排查思路6.1 高频报错与排查速查表下面这张表整理了几个 Agent 开发中高频出现的问题可以当作排查清单使用。问题现象常见原因解决思路Agent 执行到一半报错终止模型输出格式不符合要求或工具执行抛异常查看 trace确认终止发生在哪一步加入重试与降级逻辑执行器响应超时模型服务超时、工具调用耗时过长、网络抖动设置超时时间拆分子任务考虑异步执行和回调工具调用返回内容无法解析模型没有按约定输出结构化参数使用 Function Calling 或强制 JSON 输出增加参数校验上下文越来越长成本快速上涨短期记忆没有压缩历史消息一直追加实现摘要压缩控制上下文长度优化 RAG 召回策略不同用户会话数据串号记忆层没有按租户/用户隔离在记忆读写接口显式传递用户维度并增加隔离校验多 Agent 之间沟通死循环没有设置最大轮数和终止条件增加任务超时、最大协作轮数、人工介入开关6.2 典型问题展开执行器响超时“the agent execution provider did not respond in time”这类报错通常意味着 Agent 执行器向模型服务或某个执行 provider 发起的请求没有在限定时间内返回或者异步任务长时间没有状态更新。排查时先确认超时发生在哪一段如果是模型调用超时查看模型服务的负载和限流如果是工具调用超时检查下游接口的耗时和网络连通性如果是整个 Agent 任务超时则要考虑任务本身设计得太复杂超过了一个请求能承载的范围。解决办法通常有三类一是缩短同步等待时间把长任务改造成异步轮询或事件回调二是增加超时重试但要注意重试必须考虑幂等性避免工具被重复执行三是将大任务拆成多个子任务每个子任务独立记录状态这样单步失败不需要整体重跑。6.3 工具调用异常与重试策略工具调用报错是 Agent 上线后最常见的稳定性问题。比如模型生成了不存在的工具名或者参数类型不合法再比如下游接口偶发 5xx。这些错误如果直接抛给用户体验很差如果盲目重试又可能造成重复扣费或重复写入。更合理的做法是模型层使用结构化工具调用避免自由文本解析参数层使用 Pydantic 或 JSON Schema 做校验不合法就不执行执行层记录错误类型对可重试的异常做有限次数重试对不可重试的异常直接返回模型让模型换个方式解决。所有工具调用的请求、响应和错误信息都要写入审计日志方便回溯。7. 最佳实践与工程建议7.1 基础设施层保持框架无关这是我认为最重要的一条。Agent 框架迭代速度太快任何“把框架能力直接当作 Infra”的做法都会绑架后续演进。更好的策略是定义自己的内部接口例如模型网关接口、工具执行接口、任务状态接口然后让框架适配你自己的接口而不是反过来让你的代码适配框架。这样做的代价是前期要多写一些封装代码但换来的是后续换框架、升级框架、甚至同时使用多个框架时的自由度。实际项目中你会发现团队真正需要保留的是自己的业务逻辑、工具定义和权限模型而不是某个框架的 API。7.2 接口设计把 Agent 当作服务而不是脚本不要把 Agent 调用做成一个同步函数尤其是任务可能超过几秒钟的场景。建议把 Agent 执行设计成异步任务提交任务、返回任务 ID、通过轮询或 Webhook 获取结果。任务状态至少包含 pending、running、succeeded、failed、timeout 等几种。这个设计能解决很多生产问题。比如用户刷新页面后任务仍在后台执行比如多个任务可以并发调度比如任务失败后可以单独重跑而不影响其他任务。它也让 Infra 层的任务队列、状态存储、恢复机制有了落脚点。7.3 先单 Agent后多 Agent很多团队一上来就规划多 Agent 协作试图让多个角色互相开会结果调试成本飙升。我的建议是先用单 Agent 跑通业务闭环确认数据、工具、权限、审计都正确再把复杂流程拆给多个 Agent。多 Agent 的复杂度不是叠加而是乘法通信、冲突、终止条件都需要额外设计。如果确实需要多 Agent也尽量让通信过程可控。比如采用“主从模式”由一个主 Agent 负责任务拆分和结果汇总子 Agent 只处理明确子任务。相比完全对等的多 Agent 协商这种模式更容易控制风险和排查问题。7.4 落地顺序建议一个可落地的顺序大致如下先做模型网关和工具调用框架保证“模型能稳定调用已注册工具”然后做任务状态与持久化保证“任务挂了能恢复、能追踪”接着做审计、权限与成本控制保证“每一步操作可追溯、有边界”最后才考虑记忆增强、多 Agent 编排等扩展能力。这个顺序的核心是“先确定性后智能性”。Agent 的想法可以很开放但工程底座必须确定。每一步都有日志、有状态、有权限边界Agent 的智能才能安全地释放出来。8. 总结在变化中寻找确定性回到最初的问题Agent 形态一天一个样Infra 到底该为谁而建我的观点是不为某个风口建不为某个框架建而为“业务变化速度”和“工程确定性”建。把模型、工具、记忆、任务状态这些能力沉淀成内部服务让上层 Agent 形态可以快速重排这才是在不确定中保持确定性的方式。如果你的团队正在纠结 Agent 基建怎么搭可以先放下对最新框架的追逐回来看一眼自己的业务边角和成本账单从那里出发反而更容易找到答案。
返回列表