ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Agent基础设施该为谁而建?核心是运行时的五层共性结构

Agent基础设施该为谁而建?核心是运行时的五层共性结构 Agent 形态变化快这不是新鲜事。从早期的单轮工具调用到 ReAct 循环、Plan-and-Execute、多 Agent 协作再到 Harness、Skill、MCP 这些新词不断冒出来真正做工程的团队会发现一个尴尬事实你今天为某个 Agent 框架写的调度逻辑、工具封装、状态管理三个月后大概率要重写。问题不在 Agent 本身而在于我们把基建建在了“形态”上而不是建在“结构”上。这篇文章想聊清楚一件事Agent Infra 到底该为谁而建我的观点是Infra 不应该跟着具体 Agent 产品走而应该服务 Agent 运行时的共性层也就是所有 Agent 都需要的执行循环、记忆、工具路由、控制、可观测这五层。下面会拆开讲每一层的抽象边界哪些东西值得建哪些东西现在碰就是过度设计以及一套可以分批落地的建设路径。如果你正在做 Agent 应用或者团队正在选型底层框架这篇文章可以帮你少走弯路。1. 先看清楚问题Agent 形态变化到底变的是什么先不急着谈 Infra先梳理一个事实过去一年 Agent 的形态到底变了多少次。最早大家做的是“大模型 工具调用”本质上一个函数里塞几个 Tool让模型选一个执行一次性返回结果。后来发现单次调用解决不了复杂任务于是有了 ReAct 风格的循环推理、行动、观察、再推理。再后来是 Plan-and-Execute先让模型生成一个计划再逐步执行。到了多 Agent 阶段又开始拆角色有 Planner、Executor、Reviewer每个角色一个模型实例或一个 Prompt 配置。最近热词里的 Harness、Skill、CLI 通用标准本质上又是新一轮抽象试图把 Agent 的“外壳”和“技能”规范化。这些变化看起来眼花缭乱但拆开看所有 Agent 形态都共享同一个最小结构感知接收用户输入、工具返回结果、环境状态。决策由模型根据当前上下文决定下一步动作。行动调用工具、写代码、发请求、操作外部系统。这三个动作周而复始构成了 Agent 的基本循环。形态变化的只是“外壳”循环基本没变。所以Agent Infra 最该抓住的是那个“循环”而不是循环外面不断变化的“戏法”。如果你把基建建在具体形态上比如专门为某个多 Agent 框架写一套消息协议为某个 Harness 写一套 Skill 加载器那形态一变基建就废。反过来如果你把基建建在“循环 上下文 工具 控制”上形态怎么变底层都能接住。2. Agent Infra 的边界该为谁而建讨论 Infra最难的是划边界。边界划得太窄框架一换就推倒重来边界划得太宽什么都抽象结果什么都不能直接用。这里给一个 Agent 系统的四层划分方便讨论层级职责典型例子变化速度产品层面向用户的界面、交互流程、Agent 人设客服 Agent、编程助手、数据分析 Agent极快运行时层循环执行、上下文管理、工具调度、记忆读写Agent 执行引擎、Memory Store、Tool Registry中慢模型层推理能力、模型路由、Prompt 模板GPT、Claude、Qwen模型网关中基础资源层算力、对象存储、数据库、消息队列GPU 集群、向量库、Redis慢Agent Infra 应该服务的是运行时层外加横跨所有层的控制与可观测能力。原因很简单模型层变化快但你控制不了太多基础资源层稳定但和 Agent 没有直接关系产品层变化快到你根本追不上。只有运行时层是 Agent 系统的“骨架”它的变化速度相对可控又足够通用。判断你建的基建到底对不对有一个很简单的标准如果今天把你现在用的 Agent 框架换成另一个你的记忆模块、工具注册表、日志链路、权限控制还能不能原样保留如果能说明你建的是 Agent Infra。如果不能说明你建的只是某个框架的插件本质上是“项目代码”不是“基础设施”。另一个反向判断标准是你建的东西是不是在替产品层做决定比如你规定 Agent 必须用某个 Prompt 模板、必须按照某个角色顺序执行那你就越界了。运行时可以提供服务但不应该规定产品怎么设计。换句话说Agent Infra 是“可复用的执行环境”而不是“另一个 Agent 框架”。3. 运行时Agent 的循环是基础设施的核心Agent Infra 最核心的部分是那个“执行循环”。不管形态怎么变Agent 本质上就是一个循环模型推理决定动作执行动作把结果放回上下文再进入下一轮。这一层该用什么方式实现两种主流方案。第一种是“让每个 Agent 自己写循环”。也就是你用一个通用大模型 SDK然后在业务代码里自己写while循环自己维护上下文自己调工具。这种方式灵活但坏处是循环逻辑散落在各个业务代码里工具调用失败要自己处理上下文管理要自己实现出了问题排查也很费劲。第二种是“运行时统一处理循环”。也就是把循环抽象到平台层业务只需要提供工具和终止条件运行时负责调度。这种方式更适合做成 Infra因为循环的可靠性、重试、日志、成本控制都能统一处理。下面给一个最简的 Agent 运行时循环伪代码展示运行时层的核心逻辑class AgentRuntime: def __init__(self, model_client, tool_registry, max_steps20): self.model_client model_client self.tool_registry tool_registry self.max_steps max_steps self.history [] def run(self, task: str) - str: self.history.append({role: user, content: task}) for step in range(self.max_steps): response self.model_client.chat(self.history) action self.parse_action(response) if action.type finish: return action.output if action.type tool_call: tool_result self.tool_registry.call( action.tool_name, action.arguments ) self.history.append({ role: tool, tool_name: action.tool_name, content: tool_result }) else: self.history.append({role: assistant, content: response.text}) raise MaxStepsExceededError(fReached max steps: {self.max_steps})从这个伪代码里能看出运行时要做的事不多但很关键维护循环、调用模型、批量工具执行、结果回填、步骤上限控制。这里就要提到最近热词里经常看到的 Harness 和 Agent 的区别。Harness 可以理解为一个更完整的“执行容器”不仅管理模型推理循环还管理上下文打包、安全性检查、任务边界让 Agent 开发者只关注“技能”和“工具”。普通 Agent 框架则更偏向让开发者直接写业务逻辑。其实不用纠结 Harness 和 Agent 谁高级。对 Infra 而言你要的是“执行容器”这件事稳定存在。至于它叫 Harness 还是 Runtime是以后的事。运行时设计最值得注意的还有两个点。第一停止条件不能只靠模型自觉。很多 Agent 卡死就是因为模型一直不输出 Finish或者一直重复调用同一个工具。所以步骤上限、Token 上限、执行时间上限必须有缺一个都不行。第二失败恢复要有独立策略。工具调用失败很常见但失败不应该让整个 Agent 崩溃而是应该有“重试、换工具、告知模型、终止”四种可选策略。这四种策略应该由运行时统一支持而不是每个 Agent 自己写。4. 记忆最容易被业务形态污染的层记忆是整个 Agent 系统里最容易被误解、也最容易被“业务化”的层。很多人做 Agent 记忆是从自己的业务需求出发设计了一张 UserID ChatID Message 的数据库表然后再加一个向量库存 embedding。结果 Agent 形态一换这套记忆结构完全不能用。这是典型的“把记忆建在了产品层”。从运行时角度看Agent 记忆至少可以分成四类记忆类型作用典型实现生命周期短期对话记忆当前任务的多轮上下文消息列表、上下文窗口任务内工作记忆当前任务中间结果、临时状态JSON 状态、变量池任务内长期记忆跨任务的用户偏好、历史事实向量库 元数据库跨任务程序化记忆工具使用习惯、任务模板Skill、少量示例、规则长期稳定Infra 层要做的是提供一套统一的记忆读写接口至于底层存哪里、用什么向量库那是实现细节。最简单的接口设计class MemoryStore: def save_episode(self, agent_id: str, task_id: str, messages: list) - None: ... def load_episode(self, agent_id: str, task_id: str) - list: ... def save_fact(self, agent_id: str, key: str, value: str, namespace: str) - None: ... def query_facts(self, agent_id: str, query: str, namespace: str, top_k: int) - list: ... def save_state(self, agent_id: str, task_id: str, state: dict) - None: ... def load_state(self, agent_id: str, task_id: str) - dict: ...这套接口的价值在于不论你今天是单 Agent明天是多 Agent后天是 Harness你的记忆模块都不需要重写。更重要的一个点任务状态的管理最好采用快照或事件追加的方式而不是直接改数据库记录。Agent 在多轮执行中状态随时可能变化而且一旦失败要能恢复到某个检查点。用事件日志记录每一步状态变化比粗暴覆盖数据库更容易回溯和排查。这里也顺带推荐一个思路每个任务开始时给任务分配一个task_id并把初始请求、初始上下文、模型配置、工具列表全部记录为一条“任务快照”。任务执行完后把最终输出、Token 消耗、工具调用序列也记录到同一份快照。这样长期记忆才能有数据可用否则长期记忆存进去的都是“无来源的碎片”。5. 工具Skill、MCP 与工具路由的取舍工具层是 Agent 产品差异最大的地方也是 Infra 设计最容易过度抽象的地方。现在业界有几个容易混淆的概念Tool、Skill、MCP。简单理解Tool 是单个可调用能力比如“搜索天气”“读取文件”。Skill 是一组有组织的技能通常包含工具、提示词、校验逻辑和示例可以理解为一个“能力包”。MCP 是一种让模型和外部数据/工具连接的开放协议核心价值是把工具从“写死代码”变成“动态发现和调用”。对 Infra 团队来说工具层真正值得建的东西只有三件工具注册表、工具调用审计、工具结果标准化。至于工具本身能直接对接 MCP 就对接 MCP不要自己发明一套协议再走一遍适配。工具注册表的设计要点是把工具的元数据和实现解耦。注册表里存的是 schema实际调用时通过名称找到 handler。TOOL_REGISTRY {} def register_tool(name: str, schema: dict, handlerNone): TOOL_REGISTRY[name] { schema: schema, handler: handler, } def call_tool(name: str, arguments: dict): if name not in TOOL_REGISTRY: return {error: ftool {name} not found} entry TOOL_REGISTRY[name] # 这里统一做参数校验、鉴权、审计 validate_arguments(entry[schema], arguments) audit_tool_call(name, arguments) result entry[handler](**arguments) return {tool: name, result: result}工具路由不要做得太重。Agent 需要的是一个“能通过名字和参数找到执行器”的注册表而不是一个复杂的服务发现框架。你真正要花心思的是工具调用审计谁在什么任务里调了哪个工具、传了什么参数、返回了什么结果。有了这个记录后面做安全审计和效果评估才有数据。一个容易踩坑的地方是试图把所有工具统一成一种“万能调用格式”。实际上不同工具的参数风格差异巨大过度抽象只会让每个工具都要写一段适配代码。合理的做法是保留工具 schema 的灵活性只在结果回传给模型之前做统一格式化这样既能简化适配又能保证模型可理解。另外要留意工具冲突问题。当多个 Agent 共享同一批工具时要防止一个 Agent 的执行错误影响其他 Agent。Infra 层可以给工具调用加资源隔离或者并发限制比如同一时刻某个工具最多被多少个 Agent 调用这个限制在工具注册表上直接配置。6. 控制平面Agent 安全的落地形态Agent 安全问题最近提得很多。但真正的问题是安全控制应该放在哪一层答案应该是独立的“控制平面”而不是散落在各个 Agent 代码里。控制平面和运行时平行负责检查、放行、拦截、审计。Agent 安全最少要覆盖五个方面身份与权限这个 Agent 代表谁能访问哪些资源。工具级访问控制不是所有 Agent 都能调用所有工具。数据保护出域数据、日志数据、记忆数据要脱敏。操作审批高危操作发消息、付钱、删数据需要人工确认。依赖审计Agent 依赖的模型、框架、第三方库要能追溯版本。其中工具级访问控制是刚需。比如一个只读的文档总结 Agent就不应该被允许调用“发送邮件”工具。这个约束不能写在业务代码里让开发者自觉遵守而应该由运行时统一强制。一个精简的访问控制示例AGENT_POLICIES { doc_summarizer: { allowed_tools: [read_file, search_docs], allowed_domains: [*.internal.example.com], max_tokens: 100000, } } def check_tool_allowed(agent_id: str, tool_name: str) - bool: policy AGENT_POLICIES.get(agent_id, {}) return tool_name in policy.get(allowed_tools, [])安全控制不能只做拦截还要做记录。每一次拦截都应该有一条日志说明“哪个 Agent 在哪个任务里试图调用什么工具为什么被拦截”。这套日志不仅是合规要求更是后续调整权限策略的依据。在多 Agent 协作场景下控制平面还要增加一层信任边界。Agent A 调用 Agent B 时B 应该能看到“调用者是谁、调用目标任务是什么、权限边界是什么”。不能让一个低权限 Agent 通过调用高权限 Agent 来绕过访问控制。这里也要提醒一句安全不是一次配置就能完成的。Agent 产品上线后要定期检查权限配置新工具上线时要重新做一次权限评估。最好把 Agent 安全策略纳入 CI/CD 审查而不是等出了事再补救。7. 可观测性没有 trace 就谈不上 Agent InfraAgent 系统排查问题比传统后端系统难得多。传统系统一次请求的调用链是清晰的而 Agent 的一次任务可能包含十几轮模型推理、几十次工具调用而且每一步都可能出现意外。所以 Agent Infra 必须从第一天就内建可观测性。三个核心维度模型调用观测每次模型调用的 prompt、响应、Token 消耗、延迟。工具调用观测哪个 Agent 调了哪个工具、参数是什么、结果是什么、耗时多久。任务级观测整个任务从开始到结束的完整 trace、状态变化、哪一步花了最多时间。实际埋点时要做到“自动采集”不能指望业务开发者手动加日志。contextmanager def trace_step(step_name: str, **attributes): step_id generate_id() start time.monotonic() try: yield step_id except Exception: attributes[error] traceback.format_exc() raise finally: elapsed time.monotonic() - start emit_trace({ step_id: step_id, name: step_name, elapsed_ms: round(elapsed * 1000, 2), **attributes, })有了这份 trace你就可以回答这些问题Agent 为什么花了 3 分钟因为模型推理慢还是工具调用慢工具被连续调用了 5 次都没有失败是不是 Prompt 设计有问题Token 都消耗在哪里了这些问题不靠 trace靠经验猜效率极低。可观测性和评估是两回事。可观测性回答的是“Agent 发生了什么”评估回答的是“Agent 做得好不好”。前者是底子后者是上层。很多团队一上来就想做 Agent 效果评估结果发现连 trace 都没有效果不好没法归因。所以顺序应该是先可观测再评估。8. 分批建设的路径先最小运行再逐步补齐这一节给你一套 Agent Infra 的分阶段建设路径。核心原则是不要一步到位也不要什么都不建。第一阶段先跑通最小运行时。选一个 Agent 框架或自己写一个轻量循环先把“模型调用 工具调用 上下文维护”跑通。这个阶段不要写太多抽象把任务跑起来是最重要的。第二阶段固定工具注册表和审计日志。不管用任何框架工具调用都要经过一个统一入口并且记录完整调用日志。这一步做完你就有了排查问题的基础。第三阶段抽象记忆和状态。把记忆从业务代码里抽出来用统一接口读写。这一步做完你换 Agent 框架时记忆模块就能保留下来。第四阶段接入控制平面。给 Agent 配置权限、工具白名单、数据脱敏规则。这个阶段越早做越好但可以不必一开始就做全套先保住“最小权限 高危操作审批”。第五阶段多 Agent 协作与路由。前四步都做完了再开始考虑多 Agent 之间的消息路由、信任边界、任务分发。很多团队一上来就搞多 Agent结果每个 Agent 连单 Agent 的稳定性都没解决最后整个系统非常脆弱。再强调一次Agent 形态还在飞速变化你今天为“某个形态”建的基建很有可能明天就要推翻。但运行时的循环、工具注册表、统一记忆接口、控制平面、可观测性这些无论形态怎么变都需要。建设的重心放在这五件事上性价比最高。9. 常见误区与排查清单下面整理了一份 Agent 基建建设过程中常见的问题和排查方向方便你对照检查。问题现象可能原因排查方式解决方案Agent 循环不终止没有设置步骤上限或模型一直不输出结束标记查看运行时日志中步骤数配置 max_steps 和 Token 上限工具被连续重复调用Prompt 指令不清或工具返回结果模型不认可查看 trace 里的工具调用序列优化 Prompt给结果加明确格式上下文溢出每轮都把完整历史塞给模型计算每轮 Token 消耗引入上下文裁剪、摘要压缩、滑动窗口任务中断后无法恢复没有状态快照状态只存在内存里检查任务状态记录引入任务级快照和事件日志记忆串话不同任务共用一套记忆且没有区分 namespace检查长期记忆的写入来源用 task_id namespace 隔离记忆工具调用越权权限配置只写在业务代码里检查工具调用日志中是否有非预期调用把权限收口到控制平面定位问题靠猜没有任务级 trace看有没有 trace 平台优先补可观测性再谈优化换框架就要改核心逻辑基建绑定了产品形态检查运行时层是否依赖具体框架 SDK抽象出运行时层和框架解耦这些问题里最值得提醒的是“上下文溢出”。很多人以为 Agent 只要模型够大就能记住一切实际上上下文窗口再大也有上限。更合理的做法是让 Agent 养成“主动裁剪”的习惯把对话历史摘要化只保留当前任务的关键信息。10. 落地原则与意见最后还是回到标题的问题Infra 到底该为谁而建我的答案是不是为今天某个 Agent 形态而建而是为 Agent 系统里那些“无论形态怎么变都不变的结构”而建。这些结构包括执行循环、上下文管理、工具注册表、记忆接口、控制平面、可观测链路。这些是 Agent 系统真正的骨架也是基础设施的合理边界。在建设新的 Agent Infra 时你始终可以问自己一个问题如果明天 Agent 的形态换了一个新的外壳我这套东西还剩下多少能用剩得越多说明你建得越对剩得越少说明你只是把框架的插件写成了自己的代码。最值得先动手的不是设计完美的框架而是把“循环 工具注册 日志”这个最小闭环跑通。有了它后续的形态变化你都能接得住。
返回列表