SuperAPI AI 工具集

ag2-middleware

智能体与模型

查看项目

更新于 10-15 11:12

技能介绍

用途

中间件(Middleware)用于处理应当跨多次运行一致生效的横切行为,且无需修改智能体、模型客户端或工具本身。常见使用场景包括:日志、追踪与计时;瞬时失败重试;在请求到达模型前裁剪历史;限制或估算 Token 用量;改写工具参数或结果;在工具运行前执行策略校验;审计人类输入请求。

四个钩子

BaseMiddleware 暴露四个异步钩子,只实现需要的即可:

钩子 包裹对象 用途
on_turn(call_next, event, context) → ModelResponse 整个智能体回合 总延迟、请求/响应检查、回合级策略
on_llm_call(call_next, events, context) → ModelResponse 每次 LLM API 调用 重试、日志、历史裁剪、请求改写、缓存
on_tool_execution(call_next, event, context) → ToolResultType 每次工具调用 参数校验、结果脱敏、失败回退、访问控制
on_human_input(call_next, event, context) → HumanMessage 每次 context.input() 审计、改写提示、自动短路、限流

每个实例每回合创建一次,可在 self 上保存回合级状态。同一个实例可实现多个钩子。

内置中间件

可从 ag2.middleware 导入:

中间件 用途 构造参数
LoggingMiddleware 记录回合开始/结束、每次 LLM 调用、每次工具执行 无参数
RetryMiddleware 重试失败的 LLM 调用 max_retries=N, retry_on=ExceptionClass
HistoryLimiter 在 LLM 调用前限制事件数量 max_events=N
TokenLimiter 在 LLM 调用前按字符估算 Token 预算上限 max_tokens=N, chars_per_token=4
TelemetryMiddleware OpenTelemetry GenAI span(参见 ag2-telemetry) 参见 telemetry 技能

注册方式

智能体级

对每个回合生效:

from ag2 import Agent
from ag2.config import OpenAIConfig
from ag2.middleware import LoggingMiddleware, RetryMiddleware

agent = Agent(
    "assistant",
    config=OpenAIConfig(model="gpt-4o-mini"),
    middleware=[
        LoggingMiddleware(),
        RetryMiddleware(max_retries=2),
    ],
)

调用级

为单个回合添加临时中间件,agent.ask(...) 和 reply.ask(...) 均接受该参数:

from ag2.middleware import TokenLimiter

reply = await agent.ask("Summarise the latest messages.", middleware=[LoggingMiddleware()])
next_turn = await reply.ask("Now answer in one paragraph.", middleware=[TokenLimiter(max_tokens=4000)])

调用级中间件追加在智能体中间件列表之后。

执行顺序

中间件按注册顺序运行,类似嵌套的 with 块。注册 [A, B, C] 时进入顺序为 A → B → C,退出顺序为 C → B → A:

enter A
  enter B
    enter C
      <LLM call>
    exit C
  exit B
exit A

这在混合日志、改写与重试时很重要。若希望 RetryMiddleware 重试的是改写后的请求,改写应放在重试内部;若希望每次重试尝试都被单独记录,日志应放在重试内部。

编写自定义中间件

继承 BaseMiddleware 并实现需要的钩子:

import logging
from collections.abc import Sequence
from ag2 import Agent, Context
from ag2.config import OpenAIConfig
from ag2.events import BaseEvent, ModelResponse, ToolCallEvent
from ag2.middleware import BaseMiddleware, LLMCall, Middleware, ToolExecution

class AuditMiddleware(BaseMiddleware):
    def __init__(self, event: BaseEvent, context: Context, logger: logging.Logger) -> None:
        super().__init__(event, context)
        self.logger = logger

    async def on_llm_call(self, call_next: LLMCall, events: Sequence[BaseEvent], context: Context) -> ModelResponse:
        self.logger.info("Calling model with %d events", len(events))
        response = await call_next(events, context)
        self.logger.info("Model returned: %s", response)
        return response

    async def on_tool_execution(self, call_next: ToolExecution, event: ToolCallEvent, context: Context):
        self.logger.info("Executing tool: %s", event.name)
        return await call_next(event, context)

agent = Agent(
    "assistant",
    config=OpenAIConfig(model="gpt-4o-mini"),
    middleware=[
        Middleware(AuditMiddleware, logger=logging.getLogger("ag2.audit")),
    ],
)

如果中间件需要 event 和 context 之外的构造参数,注册时用 Middleware(YourClass, ...) 包装。零配置中间件可直接传入(middleware=[LoggingMiddleware()])。

工具级 vs 智能体级

仅针对单个工具的行为(该工具输出的校验、脱敏、审批闸门),应使用工具中间件——在 @tool、@agent.tool 或 Toolkit 上设置 middleware=[hook]。内置的 approval_required()(参见 ag2-hitl)即为工具中间件。

智能体中间件运行在工具中间件之外:BaseMiddleware.on_tool_execution() 能看到包含工具级钩子在内的完整执行过程。

如何选择钩子

  • on_turn → 关于整个请求/响应生命周期的行为。
  • on_llm_call → 关于进入/离开模型内容的行为。
  • on_tool_execution → 跨多个工具的工具安全/审计/结果塑形。
  • 工具级中间件(非 BaseMiddleware)→ 单个工具定义的行为。
  • on_human_input → 拦截 HITL 请求/响应。

深入阅读

  • references/builtin_middleware.md — 各内置中间件的参数、常见场景配方与适用时机。
  • website/docs/user-guide/middleware.mdx — 完整参考、顺序示例、自定义中间件准则。
  • website/docs/user-guide/tools/tool_middleware.mdx — 每工具钩子(不同的心智模型——普通异步可调用对象,而非 BaseMiddleware)。
  • OpenTelemetry 埋点请参见 ag2-telemetry。

常见陷阱

  • 忘记为构造参数使用 Middleware(...):middleware=[AuditMiddleware](无包装)仅在类只需要 event 和 context 时可用,否则需包装:middleware=[Middleware(AuditMiddleware, logger=...)]。
  • 改写顺序意外:中间件按注册顺序运行。若中间件 A 裁剪历史而 B 记录它,应注册 [A, B],使 B 看到裁剪后的视图。
  • 调用级中间件不会替换智能体中间件:它是追加的,智能体中间件仍会运行。
  • 一个中间件做五件事:保持钩子职责聚焦。将日志+重试+改写+策略放在一个类中难以推理与排序,应拆成多个实例。
  • 在 on_tool_execution 中按 event.name 分支处理单个工具:这是坏味道;单个工具的行为用工具级中间件,on_tool_execution 留给横切策略。
  • 把 OpenTelemetry 埋点写进自定义代码:已有 TelemetryMiddleware,参见 ag2-telemetry。