面试知识库

M9 · Harness 治理框架与 Hook Pipeline#

简历 Bullet Point: 抽象 Agent 全生命周期 Hook Pipeline(6 Hook 点 / 15+ Hook 模块),从 400 行意大利面适配器重构为声明式装饰器注册,新增检查只改一个文件一行装饰器;所有控制面(截断/熔断/阶段门/漂移检测/终结纪律/预算闸/输出审核)统一 Hook 化


开场钩子#

M9 之前,所有运行时管控(截断、循环检测、检索预算、fork 预算、终结纪律)散在 middleware.py 的一个 400 行类里——ToolGuardMiddleware。每加一道检查就往这个类里塞代码,相互耦合、难以测试、改一处崩一片。

重构成 Hook Pipeline 后:6 个 Hook 点,每个检查是独立函数 + @harness_hook 一行装饰器注册。新增检查 = 加一个文件,不碰任何现有逻辑。


一、模块运作流程#

1.1 六个 Hook 点#

Hook 点触发时机典型 Hook
on_session_start会话开始阶段机复位、偏好注入
pre_think模型调用前压缩、预算路由、reasoning_boost
pre_tool_call工具执行前阶段门、安全白名单、熔断器、深度闸
post_tool_call工具执行后截断、循环检测、收尾催促、断言
post_reflect模型输出后漂移检测、终结纪律、阶段转移
on_session_end会话结束输出审核、脱敏

1.2 注册机制#

@harness_hook("pre_tool_call", priority=10)
async def phase_check(ctx, tool_name, tool_input):
    if not phase_machine.allows(tool_name):
        raise HookRejectSignal(sentinel_message)
python
  • priority 越小越先跑,保证执行顺序(如熔断闸最后、search_authority 早于 retrieval_charge)
  • HookRejectSignal 阻止工具执行,返回哨兵消息给模型
  • 异常不中断主流程(单个 Hook 崩不影响其他 Hook 和 Agent)

1.3 当前注册的 Hook 模块#

context_compress / drift_detector / phase_check / phase_transition / preference_inject / reasoning_boost / result_guard / security / session_hooks / step_validator / terminal_enforce / tool_breaker / tool_gates / tool_memo / assertion_handler

1.4 与中间件的分工#

Hook 能改(拦截工具、注入消息、修改状态)。LangChain Callback 只能看(AGUI 事件上报、工具 RT metrics、token 记账)。中间件栈只剩唯一适配器 HarnessAgentMiddleware


二、踩坑实录#

坑 1:Hook 空转——注册了但从未被调用#

  • Harness 断言/漂移检测在 M12 之前曾完全空转。原因是适配器没有调用对应 Hook 点。加端到端测试确认各闸真实开火。

坑 2:priority 契约易碎#

  • 熔断闸必须在阶段门之后(先确认工具合法再看熔断状态)。priority 数字约定没有测试保护。加测试钉死关键 priority 顺序。

坑 3:删除旧中间件时兼容层取舍#

  • ToolGuardMiddleware / ContextCompressionMiddleware 时不留兼容层。因为留了只会让新旧并存、行为不可预测。

三、面试问答#

Q1: 这种 Hook 模式和 Web 中间件有什么区别?#

粒度更细(6 个 Hook 点 vs request/response 两个)、context 更丰富(能看到工具参数/返回值/历史轨迹/阶段状态)。本质是 Web middleware 模式在 AI Agent 领域的领域特化

Q2: 为什么不用 LangGraph 的 StateGraph 做控制?#

StateGraph 适合”确定性条件分支”(if A then B)。Harness Hook 适合”横切关注点”(每个工具调用都要检查的通用逻辑)。两者正交:StateGraph 管流程图拓扑,Hook 管运行时行为约束。

Q3: Hook 之间如何通信?#

通过 HarnessState(共享状态对象)。Hook 不直接依赖其他 Hook,但可以读写同一个 state(如 terminal_reachedphase)。


四、诚实边界#

维度做了没做
Hook Pipeline6 点 / 15+ 模块运行时动态启停单个 Hook
测试priority 契约测试全组合交互测试
可观测日志记录各 Hook 触发Hook 执行时间 metrics