Files
zclaw_openfang/wiki/middleware.md
iven 5d88d129d1 docs(wiki): Phase B+C完成 — middleware/saas/security/memory 5节模板重构
- middleware.md: 集成契约+3不变量+执行流 (157→136行)
- saas.md: 移除安全重复→引用security.md+Token Pool算法 (231→173行)
- security.md: 吸收saas认证内容成为安全唯一真相源 (158→199行)
- memory.md: 最大压缩363→147行+Hermes洞察提炼+4不变量

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 21:42:24 +08:00

137 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 中间件链
updated: 2026-04-22
status: active
tags: [module, middleware, runtime]
---
# 中间件链
> 从 [[index]] 导航。关联模块: [[chat]] [[butler]] [[memory]] [[hands-skills]]
## 1. 设计决策
**中间件是请求处理的管道,每条聊天消息都经过完整链路。**
- **WHY 优先级排序 (0-999)**: 数值越小越先执行。宽范围设计允许在任意位置插入新中间件而无需重新编号。
- **WHY 注册顺序 != 执行顺序**: `kernel/mod.rs` 中 14 次 `chain.register()` 的代码顺序与运行时顺序无关chain 按 `priority()` 升序排列后执行。
- **WHY 6 类 14 层**: 进化(70-79) -> 路由(80-99) -> 上下文(100-199) -> 能力(200-399) -> 安全(400-599) -> 遥测(600-799),优先级范围即执行阶段。
- **WHY Stop/Block/AbortLoop**: 细粒度流控 -- Stop 中断 LLM 循环Block 阻止单次工具调用AbortLoop 终止整个 Agent 循环。命中后跳过所有后续中间件。
## 2. 关键文件 + 数据流
### 核心文件
| 文件 | 职责 |
|------|------|
| `crates/zclaw-runtime/src/middleware.rs` | `AgentMiddleware` trait + `MiddlewareChain` 执行引擎 |
| `crates/zclaw-runtime/src/middleware/` | 14 个中间件实现 (.rs) |
| `crates/zclaw-kernel/src/kernel/mod.rs:248-361` | `create_middleware_chain()` 注册入口 (14 次 register) |
| `crates/zclaw-saas/src/main.rs` | SaaS HTTP 中间件注册 (10 层) |
### 执行流
```
用户消息 -> AgentLoop
-> chain.run_before_completion(ctx)
-> [按 priority 升序] 每层 middleware.before_completion()
-> Continue: 下一层 | Stop(reason): 中断循环
-> LLM 调用
-> (工具调用时) chain.run_before_tool_call()
-> Allow | Block(msg) | ReplaceInput | AbortLoop
-> 工具执行
-> chain.run_after_tool_call()
-> chain.run_after_completion()
```
### 集成契约
| 方向 | 模块 | 接口 | 触发时机 |
|------|------|------|----------|
| Called by <- | kernel | `kernel/mod.rs:create_middleware_chain()` | Kernel 启动 |
| Calls -> | runtime | `MiddlewareChain::run_before_completion()` | 每条聊天请求 |
| Called by <- | saas | HTTP relay handler | SaaS relay 路由 |
| Provides -> | all | `AgentMiddleware` trait | 14 个实现 |
## 3. 代码逻辑
### 14 层 Runtime 中间件
| 优先级 | 中间件 | 文件 | 职责 | 注册条件 |
|--------|--------|------|------|----------|
| @78 | EvolutionMiddleware | `evolution.rs` | 推送进化候选项到 system prompt | 始终 |
| @80 | ButlerRouter | `butler_router.rs` | 语义技能路由 + system prompt 增强 + XML fencing | 始终 |
| @100 | Compaction | `compaction.rs` | 超阈值时压缩对话历史 | `compaction_threshold > 0` |
| @150 | Memory | `memory.rs` | 对话后自动提取记忆 + 注入检索结果 | 始终 |
| @180 | Title | `title.rs` | 自动生成会话标题 | 始终 |
| @200 | SkillIndex | `skill_index.rs` | 注入技能索引到 system prompt | `!skill_index.is_empty()` |
| @300 | DanglingTool | `dangling_tool.rs` | 修复缺失的工具调用结果 | 始终 |
| @350 | ToolError | `tool_error.rs` | 格式化工具错误供 LLM 恢复 | 始终 |
| @360 | ToolOutputGuard | `tool_output_guard.rs` | 工具输出安全检查 | 始终 |
| @400 | Guardrail | `guardrail.rs` | shell_exec/file_write/web_fetch 安全规则 | 始终 |
| @500 | LoopGuard | `loop_guard.rs` | 防止工具调用无限循环 | 始终 |
| @550 | SubagentLimit | `subagent_limit.rs` | 限制并发子 agent | 始终 |
| @650 | TrajectoryRecorder | `trajectory_recorder.rs` | 轨迹记录 + 压缩 | 始终 |
| @700 | TokenCalibration | `token_calibration.rs` | Token 用量校准 | 始终 |
> 注册顺序 (代码) 与执行顺序 (priority) 不同。Chain 按 priority 升序排列后执行。
### 10 层 SaaS HTTP 中间件
| 层级 | 中间件 | 职责 |
|------|--------|------|
| 公共路由 | `public_rate_limit_middleware` | 20次/分钟/IP |
| 公共+认证 | `api_version_middleware` | API 版本校验 |
| 公共+认证 | `request_id_middleware` | 请求 ID 注入 |
| 认证路由 | `rate_limit_middleware` | 5次/分钟/IP |
| 认证路由 | `auth_middleware` | JWT 认证 + 权限 |
| 认证路由 | `TimeoutLayer` | 请求超时 15s |
| Relay 路由 | `api_version_middleware` | 版本校验 |
| Relay 路由 | `request_id_middleware` | 请求 ID |
| Relay 路由 | `quota_check_middleware` | 配额检查 |
| 全局 | CORS / 其他 layer | 跨域等 |
### 不变量
- Priority 升序: 0-999, 数值越小越先执行
- 注册顺序 != 执行顺序; chain 按 priority 运行时排序
- Stop/Block/AbortLoop 立即中断, 不执行后续中间件
### 核心接口
```rust
trait AgentMiddleware: Send + Sync {
fn name(&self) -> &str;
fn priority(&self) -> i32 { 500 }
async fn before_completion(&self, ctx: &mut MiddlewareContext) -> Result<MiddlewareDecision>;
async fn before_tool_call(&self, ctx: &MiddlewareContext, tool_name: &str, tool_input: &Value) -> Result<ToolCallDecision>;
async fn after_tool_call(&self, ctx: &mut MiddlewareContext, tool_name: &str, result: &Value) -> Result<()>;
async fn after_completion(&self, ctx: &MiddlewareContext) -> Result<()>;
}
```
## 4. 活跃问题 + 陷阱
### 活跃问题
- **11/14 中间件无独立测试** (P2): 仅 `butler_router`(12) / `evolution`(4) / `trajectory_recorder`(4) 有测试,共 20 个。其余 11 层依赖集成测试覆盖。
- **SkillIndex 条件注册** (长期观察): 无技能时不注册,非 bug 但需关注空技能场景下的行为一致性。
### 历史陷阱
| 问题 | 根因 | 修复 |
|------|------|------|
| TrajectoryRecorder 未注册 | V13-GAP-01: 遗漏 `chain.register()` 调用 | 已在 @650 注册 |
| Admin 端点 404 而非 403 | admin_guard_middleware 返回码错误 | 已修复为 403 |
| DataMasking 中间件 | 增加延迟但无实际安全收益 | 04-22 移除 |
## 5. 变更日志
| 日期 | 变更 | 影响 |
|------|------|------|
| 04-22 | DataMasking 中间件移除 | 14->14 层 (替换为无), 减少 1 层无收益处理 |
| 04-22 | 跨会话记忆修复 | Memory 中间件去重+跨会话注入修复 |
| 04-22 | Wiki 一致性校准 | 数字与代码验证对齐 |
| 04-21 | Embedding 接通 | SkillIndex 路由 TF-IDF->Embedding+LLM fallback |
| 04-15 | Heartbeat 统一健康系统 | TrajectoryRecorder 痛点感知增强 |