智能体跑起来不难真正难的是它跑起来之后你还能不能管住它。最近一年我陆续接了不少智能体项目发现当系统里的 agent 从 1 个变成 5 个、10 个当客服、知识库、工单处理、数据分析这些智能体开始互相调用之后最让人头疼的问题已经从能不能答对变成了它在干什么、烧了多少钱、我能不能在出事之前拦住它。微软开源的智能体治理工具包 AGTAgent Governance Toolkit就是冲着这三个问题来的。这篇文章我会从组件原理讲到生产落地把控制器、预算追踪、观测追踪这几块的核心逻辑拆开说清楚也会把我接入过程中踩过的坑一并列出来。如果你正在做多智能体系统、智能体平台或者手头智能体已经产生了不小的模型开销这篇应该能帮你少走不少弯路。1. 失控的智能体集群为什么需要治理层1.1 三个典型的失控场景先说第一个场景多个智能体互相调用调用链一旦深了没人说得清某次回答到底是哪个 agent 给的。用户看到一个答非所问的回复你想排查结果日志散落在三个服务的文件里你只能靠时间戳手工拼链路拼到一半发现还有两个超时记录没对上。这种问题我接过不止一次每回都是大半天耗进去。第二个场景是成本失控。智能体接的工具越多token 消耗越隐蔽。一个查一下库存并生成周报的请求背后可能先调商品检索、再查数据库、又让模型总结了三遍。单个请求看起来没多少钱但并发一上来月底账单数字跳得比你想象快得多。更麻烦的是你根本不知道钱花在哪个环节了。第三个场景最容易被忽略你无法在智能体运行期间干预它。它可能正在反复调用一个报错的工具每次都消耗 token每次都失败但它还在重试。你想拦却没有一个统一的入口去叫停。这三个场景本质上是同一个问题——缺少治理层。治理不是限制智能体的能力而是给智能体装上仪表盘和刹车看得到状态控得住流量踩得住刹车。1.2 AGT 的定位给智能体加一道闸门AGT 是微软开源的一套治理框架官方定位就是控制智能体行为与成本。它不替代 LangChain、LangGraph 这类智能体框架也不替代 Dify 这类智能体平台而是跑在智能体和调用方之间作为一个统一的入口层。用交通来类比智能体是路上的车AGT 是路口那套红绿灯加监控系统它不替你开车但决定哪辆车能过、当前路段花费上限是多少以及出事之后能不能完整回放事故现场。理解这层定位很重要。它意味着 AGT 的接入方式不是重构你的智能体而是在智能体前面加一道统一闸门。所有外部请求先经过治理层再分发到具体智能体所有模型调用产生的 token 消耗在治理层被计量所有关键决策和调用路径在治理层留下记录。组件设计全部围绕这三个目标展开往下拆就顺理成章了。2. AGT 核心组件拆解控制器、预算追踪、观测追踪的分工AGT 的核心包是 agent_governance里面最主要的组件有三个Smart Controller智能控制器、Budget Tracker预算跟踪器、Tracer跟踪器。三者协作的节奏可以概括成一句话先决定找谁再决定能不能花钱最后留下证据。2.1 Smart Controller请求进来之后该找谁Smart Controller 是整个治理链路的总入口。一个请求到达时它先回答这个请求该交给哪个智能体处理。它内置了几种路由模式我实际用得最多的是这两种Auto Router基于规则自动选智能体核心是关键词匹配。配置直观适合规则明确的场景。Semantic Router语义路由。请求先转成 embedding再和历史样本或智能体能力描述计算相似度选中最匹配的智能体。另外还有 Smart Switch 和 Retry 机制前者负责在某个智能体失败或超时时把请求切到备选智能体后者负责对可控的失败做有限重试。我从实际项目里得到的经验是早期不要太依赖纯语义路由。你可以在控制器里维护一张路由规则表每个智能体对应一组关键词和一段能力描述请求来的时候关键词匹配优先、语义匹配兜底。等跑一阵子收集到足够的流量数据以后再把高频路由规则逐步切换成语义优先这样误判率会低很多。2.2 Budget Tracker花多少钱、能否继续花Budget Tracker 管的是成本治理的核心职责是判断当前会话或当前用户已经消耗了多少预算还允不允许继续消耗。常见的几个内置实现类型计量对象适用场景Simple Budget Tracker请求次数按调用量计费或限流的场景Token Budget Tracker输入输出 token 总数模型按 token 计费的主流场景自定义 Tracker自定义指标预算口径特殊的业务预算可以分层注册这是 AGT 一个非常实用的设计。你能给整个应用设总预算也能给某个智能体单独设预算还能按用户维度设置预算。请求进来时预算检查沿着治理链路逐层往上走任意一层超了请求就进不了执行环节。Token 成本的计算公式本身不复杂但容易算错单次请求成本 输入 token 数 × 输入单价 输出 token 数 × 输出单价 各次工具调用的 token 消耗之和容易被忽略的是第三部分。大模型每次调用工具都会把工具返回的结果重新拼接进上下文再读一遍所以工具调用的中间 token 会重复累计。在 Token Budget Tracker 里一个请求的开始 token 数和结束 token 数之间的差值才是这次请求的真实消耗。很多人只统计了最终输入和最终输出中间工具调用的钱根本没算进去。2.3 Tracer每一步都留下记录Tracer 相当于行车记录仪。它的工作机制是事件回调请求开始、智能体选中、模型调用、工具调用、请求结束每个关键节点都会触发事件Tracer 把这些事件全部记录下来。记录的内容至少要覆盖四类信息链路信息请求 ID、父请求 ID、智能体 ID能还原整条调用路径决策信息控制器选的哪个智能体命中的是哪条路由规则资源信息模型名称、输入输出 token 数、工具调用次数、耗时结果信息是否成功、错误码、输出内容摘要有了这些数据那个错误回答到底是哪个 agent 给的就不再是无头公案了一条链路日志就能定位到具体环节。3. 零基础接入 AGT最小可用配置完整复现理论说完了下面进入实操。我尽量把每一步写清楚包括中间容易踩坑的位置。3.1 安装与项目结构规划安装很简单一条命令pip install agent-governance但我建议你在项目结构上多花点心思。治理逻辑和业务逻辑应该分开我习惯这样组织governance/ controllers.py # 智能控制器定义 budgets.py # 预算跟踪器定义 tracers.py # 跟踪器定义 main.py # 组装治理链路这么分层的好处是以后调整预算策略或者换路由规则不需要动任何业务智能体的代码。治理层和业务层解耦得越彻底后续维护成本越低。3.2 写一个最简单的受治理智能体先定义一个最朴素的智能体回调函数这里故意不引入任何智能体框架用函数代替方便看清楚治理链路本身# governance/controllers.py def customer_service_agent(context): 售后客服智能体处理退货、退款、物流查询 response llm_chat(messagescontext.messages) return response然后组装治理链路。核心流程是先建 Tracer再建 Budget Tracker最后建 Smart Controller把三者串联起来# governance/main.py from agent_governance.governance import Governance from agent_governance.budget_tracker.token_budget_tracker import TokenBudgetTracker from agent_governance.tracer.tracer import Tracer from agent_governance.controller.smart_controller import SmartController def run_governed_agent(user_query: str, user_id: str): # 1. 按会话维度创建预算跟踪器 budget_tracker TokenBudgetTracker(max_token_limit22500) # 2. 创建全局追踪器 tracer Tracer(session_iduser_id) # 3. 组装控制器路由规则 预算 追踪 controller SmartController( routersemantic, budget_trackerbudget_tracker, tracertracer, ) # 4. 执行请求经过治理链路分发到对应智能体 result controller.execute( request_contentuser_query, executorlambda context: call_agent_with_gauge( context, budget_tracker ), ) return result这里最关键的一步是call_agent_with_gauge。智能体函数内部真正调用模型时要用 gauge 包一层让预算追踪器能实时拿到 token 消耗def call_agent_with_gauge(context, budget_tracker): with gauge(budget_trackerbudget_tracker): if context.routed_agent_id customer_service: return customer_service_agent(context) elif context.routed_agent_id knowledge_base: return knowledge_base_agent(context) else: return default_agent(context)如果你跳过这一步只是把模型调用裸写在智能体函数里那么 Budget Tracker 永远拿不到真实 token 消耗预算等于没设。3.3 注册控制器与追踪器的正确时机接入的时候有一个高频问题控制器和追踪器应该做成全局单例还是每次请求新建我实测下来的结论是Smart Controller 可以做成全局单例因为路由规则本身是静态配置Tracer 也可以全局复用但每条请求链路必须传入独立的请求 ID否则日志没法按链路串起来。而 Budget Tracker 强烈建议按会话维度创建预算通常是按用户或会话口径算的如果做成全局单例一个用户把预算耗尽全平台所有用户都会被拦下来那就是事故了。4. 成本治理实战预算如何设置、触发后怎么办4.1 预算指标设计token 预算的计算与分配设置预算最忌讳拍脑袋合理的做法是先量化再设阈值。我的习惯是先跑一周无治理模式只开 Tracer 收集真实消耗数据统计每个智能体的单请求平均 token 消耗和 P95 token 消耗按以下公式设置预算单请求预算 P95 消耗 × 1.5会话预算 单请求平均消耗 × 预计单会话最大请求数用户日预算 会话预算 × 预计日会话数举个例子。假设客服智能体单请求平均消耗 8000 tokenP95 是 15000那么单请求预算设为 22500会话预算按 10 次请求算设为 80000用户日预算按 3 个会话算设为 240000。这个设计思路是正常请求不会被误伤但异常暴涨会被兜住。P95 乘以 1.5 这个系数能覆盖绝大多数正常波动同时也能拦住那些因为提示词 bug 或循环调用导致的 token 翻倍。4.2 动态路由与预算触发的协同预算触发之后怎么办很多人的第一反应是直接报错拒绝请求。但更好的做法不是粗暴拒绝而是触发降级。我在项目里验证过一个组合语义路由 Token 预算 降级智能体。一个请求进来语义路由本来选中了重模型智能体比如 GPT-4o 级别的大模型但它所在的会话预算只剩 5000 token明显不够跑一个复杂任务。这时候预算前置检查会直接拦截拦截动作通过控制器内部的通知机制传给 Controller控制器就把请求重新路由到一个小模型智能体比如轻量模型。用户的请求仍然得到响应只是回答质量略有下降。系统不会因为预算超限直接挂掉也不会因为不设预算而烧掉巨额费用。这种预算前置检查 智能降级的组合是 AGT 在成本治理上最有价值的部分。4.3 费用上涨后的止损方案我实际遇到过一次知识库问答智能体上线了新提示词之后单请求 token 消耗暴涨到原来的 2.3 倍。如果没有预算拦截那一天就会烧掉一笔冤枉钱。我当时配置的是三层止损方案Budget Tracker 层设置单请求硬阈值超过直接阻止控制器层配置 fallback 智能体被拦截的请求自动切换监控层每小时按用户维度聚合一次 tracer 日志里的 token 消耗涨幅超过 50% 就告警止损的目标不是追求完全不花钱而是给每一笔花销设额度。这个思路跟信用卡额度是一回事额度不是为了不让你花钱而是为了防止透支失控。5. 行为治理实战可观测性的落地与分析5.1 追踪器收集哪些数据Tracer 能收集的数据很多但实践中没必要全都收集收集多了存储成本也上来了。我的建议是最少覆盖四类上文提到过这里展开说一下每类的用途链路信息排查问题的基础。一次回答是哪个智能体给的、它的上游请求是谁、有没有经过多次路由全靠链路 ID 串。决策信息有助于优化路由规则。命中哪条语义规则、置信度多少、为什么选它不选另一个智能体都记录在案。资源信息成本分析的基础。模型名、输入输出 token、工具调用次数、阶段耗时算成本和定位性能瓶颈都要用。结果信息判断智能体是否真的干完了活。有没有报错、错误码是什么、输出内容摘要是什么。5.2 一次典型请求的治理链路回放看一个实际案例。用户发来一条客服请求我要退货顺便查一下我的积分。结果是系统回复了退货政策但完全没有查积分。用 Tracer 回放整条链路看到的路径是请求进入治理层 → 语义路由把请求分给售后客服智能体 → 智能体调用退货政策工具 → 模型生成回复 → 流程结束。链路记录显示整个过程中积分查询工具从未被触达。定位到根因售后智能体的工具提示词里积分查询的触发条件写得不够明确模型判断用户的主要意图是退货把积分查询当成了次要诉求直接忽略了。这类做一半的行为问题在接入治理层之前几乎没法定位现在一条链路日志就把问题锁死在具体环节上修复起来很容易。5.3 基于追踪数据优化智能体选择策略追踪数据不仅能排查问题还能反向优化路由策略。我观测过一个现象某知识库智能体被语义路由选中的概率特别高但它的回答质量反而不如另一个更小的智能体。后来翻追踪日志发现是关键词路由的权重设置有问题几个高频业务词把所有流量都带到了那个大智能体上。调整方式很简单把控制器里这几个高频词的权重降下去增加一条指向小智能体的语义规则。改完之后小智能体的调用占比上升了 20%平均单请求成本下降了 15%回答满意度反而提升了。这就是治理层可观测性带来的直接收益不是靠感觉调优而是拿数据说话。6. AGT 在生产环境落地我踩过的坑与建议6.1 坑一拦截器和控制器功能混淆第一次接触 AGT 的时候很容易把拦截器Interceptor和控制器Controller搞混。实际上拦截器运行在控制器内部预算跟踪器的通知是经由拦截器机制来触发动作的。如果你在控制器外部又单独包了一层拦截逻辑就会导致同一个请求被双重拦截、预算判断重复执行。我的建议是拦截动作统一放在 Controller 内部的拦截器里外部只做治理链路的组装不要自己再造一套拦截层。6.2 坑二Budget Tracker 没有注册导致预算不生效这是我见过最多的问题定义了 Budget Tracker运行起来预算却完全没有反应。绝大多数原因是只创建了对象没有把它和控制器关联起来。AGT 的 Budget Tracker 要进入治理链路并且被控制器引用到预算是从治理链路的检查环节逐层触发的。如果只是在某个工具类里默默放了一个实例链路里根本感知不到它的存在。接入之后第一步就是验证预算有没有生效最简单的方式是设一个极低阈值跑一个请求看会不会被拦截通了再把阈值调回正常值。6.3 坑三自定义路由器的返回值格式不匹配写自定义路由器的时候返回值必须匹配 AGT 约定的结构一般需要包含目标智能体 ID、置信度等信息。如果你图省事返回一个普通字符串下游十有八九直接报类型错误。这类错误本身报错算快但很容易浪费调试时间。建议动手写自定义路由器之前先去看一眼源码里路由结果类的定义照着返回不要凭感觉构造。6.4 坑四追踪器事件处理器缺位导致日志丢失Tracer 本身只是发事件的真正把事件写进日志文件或数据库的是事件处理器。我第一次跑通的时候发现 Tracer 配置了、链路也走了但最后日志文件是空的排查了半天才发现是没挂事件处理器。正确的配置方式是给 Tracer 挂载一个内容处理器去消费 Tracing 事件并写入存储。只开 Tracer 不挂处理器等于装了行车记录仪但没插存储卡。6.5 什么场景不建议上 AGT最后说点反常识的。如果你的智能体项目只是单个 agent、单次调用既没有多智能体路由的需求也没有成本追踪的需求那么 AGT 这层治理就有点重了它带来的复杂度和学习成本收益偏低。但如果你正在做智能体平台、多智能体协作系统或者面向最终用户的智能体产品再或者你的智能体已经产生了可观的模型开销那 AGT 这类治理工具基本算必需品。智能体领域要走向成熟不可能一直停留在能跑就行的状态——治理能力是通往生产级应用的一道必过门槛。我在接入过程里最深的体会是治理层不应该在出事以后才补而应该在智能体规模还小、改动成本还低的时候就铺好。等到流量起来再回头加治理那时候每一处改动都要小心翼翼成本完全不是一个量级。