96SEO 2026-09-07 09:39 2
User Pain Point:

Callback 是只读的观测——你看到发生了什么但不能改它。
Callback 的局限性让许多团队不得不在业务层面硬编码工作流或频繁重启 Agent。为了解决这些痛点,中间件提供可写拦截功能:
这些能力都需要中间件,Callback 做不到。
// adk/handler.gotype
TypedChatModelAgentMiddleware interface {
// . Agent 运行前:改 instruction / 工具列表
BeforeAgent
// . Agent 成功结束后
AfterAgent
// . 每次调模型前:
消息历史 + ToolInfos
BeforeModelRewriteState
// . 模型返回后:对模型回复做后处理
AfterModelRewriteState
// -. 包装同步 / 流式工具调用
WrapInvokableToolCall
WrapStreamableToolCall
// -. 包装 Enhanced 同步 / 流式工具调用
WrapEnhancedInvokableToolCall(ctx。endpoint EnhancedInvokableToolCallEndpoint,tCtx *ToolContext) (EnhancedInvokableToolCallEndpoint,error)
WrapEnhancedStreamableToolCall(
ctx context.Context,endpoint StreamableToolCallEndpoint,tCtx *tool.Context) (
streamable.ToolInvocationEndpoint,error)
// . 包装模型本身
WrapModel(ctx context.Context,m model.BaseModel,mc *adk.TypedBaseChatModelMiddlewareConfig) (
model.BaseModel,error)}
*个方法全部实现太繁琐。嵌入 adk.TypedBaseChatModelAgentMiddleware
/// 提供 个默认 no‑op,仅需覆盖关心的那个:.
type MyMiddleware struct {
// 嵌入基类。获得所有 no‑op 默认实现
*adk.TypedBaseChatModelAgentMiddleware
}
// 只实现需要的
func BeforeModelRewriteState(
ctx context.Context,state *adk.ChatMessageStore,mc *adk.ModelContext) (
context.Context,*adk.ChatMessageStore,error) {
// 在这里
消息历史…,return ctx,state,nil
}
*注册到 Agent:.
agent,_:= adk.NewChatMessageStore,&adk.ChatMessageStoreConfig{
从Name来看,"my_agent",Model:m,Middlewares:。})
*最常用的工具层中间件——把工具报错转成字符串。避免因单个 tool 错误导致整个 Agent 崩溃*. 来自 .
# Import snippet from components/tool/utils/error_handler.go
import "github.com/cloudwego/eino/components/tool/utils"
wrapped := utils.WrapToolWithErrorHandler(mytool,&
func string{
return fmt.Sprintf})
// 将 wrapped 放进 Tools 列表即可。说起来,// 后续若 mytool 报错,将被转换为友好文本。// 并不会影响其它 tools 或者整体流程。//
//
//
`error_handler.go` 的主要原因:
go
func. InvokableRun(
ctx context.Context。
args string,...opts...tool.Option){
result,_:=s.i
if err := compose.IsInterruptRerunError;err,=nil{
return result,error}
if err!=nil{
return s.h,nil}
return result。nil}
**关键细节**:
- `InterruptRerunError` 不被捕获;HITL 中断需透传,---
五、patchtoolcalls:修补悬空工具调用
*悬空 tool_call 通常是由于使用者提前发送新消息导致旧 tool 调用没有得到响应,从而造成 LLM API 报错*.
go
import patchtoolcalls'
mw。_ := patchtoolcalls.New,&patchtoolcalls.Config{PatchedContentGenerator:
func{
return fmt.Sprintf canceled",name,id),nil}})
agent,_ := adk.New...
默认占位内容为 “`%s with id %s was canceled…老实说,`”,中文环境则自动切换为中文提示。---
六、reduction:两阶段上下文压缩
*长期运行会产生大量 Token,上限被突破。是最头疼的问题之一*
### 阶段一:截断
至于触发条件,**每次 tool 完成后立即**。超过阈值 -> 保存原始全文至后端,并将 tool 消息替换为截断通知。bash
### 阶段二:清理
至于触发条件,**每次调模型前**。若总 token 超过阈值 -> 遍历旧记录,将完整内容卸载并仅保留占位符。go
import (
“github.com/cloudwego/eino/adk/middlewares/reduction”
“github.com/cloudwego/eino/adk/filesystem”
)
mw,_ := reduction.New,&reduction.Config{
Backend: filesystem.NewLocalBackend,ReadFileToolkitName:"read_file",// 用来恢复卸载内容
MaxLengthForTrunc:,// 单条超长 tool 输出阈值
MaxTokensForClear:。// 总 token 阈值
ClearRetentionSuffixLimit:,// 保留最近几轮不清理
TokenCounter: func{
return countTokens,nil},})
**分工概览**:
| 阶段 | 功能 | 时机 | 优势 |
|------|------|------|------|
| 截断 | 单条大 output 即刻处理 | tool 完成后 | 防止一次爆炸 |
| 清理 | 多轮累计压缩 | 每次建模前 | 减少频繁 IO |
**可选参数 `ClearAtLeastTokens`** 可避免过度清理导致缓存失效。---
七、自定义中间件示例:限速工具调用
go
type RateLimitMW struct{
*adk.TypedBaseChatMachine*
limiter*rate.Limiter}
func NewRateLimitMW*RateLimitMW{
return &RateLimitMW{limiter: rate.NewLimiter。1)}
}
// 覆盖仅需限制 sync 调用:
func.WrapInvokable(
ctx context.Context,endpt adk.InvokEndpoint,tCtx*adk.ToolContext)(
adk.InvokEndpoint,error){
return func{
if err:=m.limiter.Wait;err,=nil{return"",fmt.Errorf}
return endpt}。nil}
---
八、中间件 vs Callback :选哪个?
需求
可以考虑
记录日志 / 上报 traceCallback统计 Token 用量 Callback - 只读观察
改变数据结构,如删除冗余消息 MiddleWare
把 Tool 错误转成友好字符串 MiddleWare
加速限制或批量限制 MiddleWare
动态修改 instruction 或增加 tools MiddleWare
失败恢复/重试策略 MiddleWare
Token 上下文压缩 MiddleWare
修复悬空 Tool 调用 MiddleWare
---
Eino 的 Middleware 程序通过 TypedChat.... 接口提供 …个钩子,让你覆盖 Agent 执行流任意节点。基类 TypedBase…简化开发,只需关注关心的方法即可。已存在三个成熟中间件解决最常见工程难题:
<-• 将 Tool 错误转为友好文本;<-• 自动补偿用户打断导致悬空 Tool 调用;<-• 双阶段上下文压缩防止 Token 超限。
*主要区别:
Callback —— 只观测数据,不可改动;老实说,Middleware —— 可写拦截,实现实时行为调整。
下篇继续…
©️ 云堆社区
📖代码
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback