Genkit 推出中间件系统:增强智能体AI应用的可控性与可靠性
阅读原文· developers.googleblog.comGenkit 的中间件系统把 agent 行为变成可编程的拦截点,重试、fallback、人机审批都能挂上,对用 Genkit 上生产的团队来说,是个能让应用更「硬」的更新。
Google开源框架Genkit近日推出其核心中间件系统,旨在提升智能体AI应用的可靠性与可控性。该系统允许开发者在生成调用、模型及工具层进行拦截,以注入自定义行为,如重试机制、模型回退以及人工介入的工具审批流程。通过创建并堆叠自定义中间件,开发者能够实现对模型输出的确定性控制。所有中间件的执行流程均可通过专用的开发者界面进行实时查看与调试,有效支持使用TypeScript、Go、Dart和Python构建生产就绪的智能体应用。
宣布 Genkit 中间件:拦截、扩展和强化您的智能体应用
Genkit 是一个开源框架,用于构建面向任何平台的全栈、AI 驱动及智能体应用,支持 TypeScript、Go、Dart 和 Python。构建生产就绪的智能体应用和 AI 功能不仅需要强大的模型和精心的提示词设计。您可能还需要重试和回退以实现最大可靠性,在破坏性工具调用前需人工批准,以及跨每一层的可观测性。
Genkit 通过中间件解决了这一问题:可组合的钩子,用于拦截生成调用(包括工具执行循环),并注入自定义行为。该中间件系统现已在 TypeScript、Go 和 Dart 中可用,Python 支持即将推出。
Genkit 中间件的工作原理
Genkit 中的每次 generate() 调用都会运行一个工具循环:模型生成输出,任何请求的工具被执行,结果反馈到新的模型调用中,如此循环直到模型完成。中间件钩子可以挂载到这个循环的三个层面上:
| 钩子 | 运行时机 | 典型用途 |
|---|---|---|
| 生成 | 每个工具循环迭代一次 | 上下文注入、消息重写、对话级逻辑 |
| 模型 | 每个模型 API 调用一次 | 重试、回退、缓存、延迟日志记录 |
| 工具 | 每个工具执行一次 | 人在回路中、沙箱隔离、按工具记录日志 |
预置中间件
Genkit 提供了多种预置中间件解决方案,用于常见用例。以下是当前可用的内容:
1. 重试
在临时性错误(如 RESOURCE_EXHAUSTED、UNAVAILABLE 等)上自动重试失败的模型 API 调用,采用带抖动的指数退避策略。仅重试模型调用;周围的工具循环不会被重放。
resp, err := genkit.Generate(ctx, g,
ai.WithModelName("googleai/gemini-flash-latest"),
ai.WithPrompt("Summarize the quarterly earnings report."),
ai.WithUse(&middleware.Retry{
MaxRetries: 3,
InitialDelayMs: 1000,
BackoffFactor: 2,
}),
) 2. 回退
当主要模型在指定的一组错误代码上失败时,切换到替代模型。当主要模型超出配额时,可用于回退到完全不同的提供商。
resp, err := genkit.Generate(ctx, g,
ai.WithModelName("googleai/gemini-flash-latest"),
ai.WithPrompt("Analyze this complex document..."),
ai.WithUse(&middleware.Fallback{
Models: []ai.ModelRef{
anthropic.ModelRef("claude-sonnet-4-6", nil), // fall back to Claude
},
Statuses: []core.StatusName{core.RESOURCE_EXHAUSTED},
}),
) 3. 工具审批
将工具执行限制在允许列表中。任何不在列表中的工具都会触发中断,从而在操作进行前实现人机回圈(人工确认)。
resp, _ := genkit.Generate(ctx, g,
ai.WithPrompt("Delete the temp files"),
ai.WithTools(deleteFilesTool),
ai.WithUse(&middleware.ToolApproval{
AllowedTools: []string{}, // empty = every tool call interrupts
}),
)
if len(resp.Interrupts()) > 0 {
interrupt := resp.Interrupts()[0]
// Prompt the user for approval, then resume with the approval flag.
approved, _ := deleteFilesTool.RestartWith(interrupt,
ai.WithResumedMetadata[DeleteInput](map[string]any{"toolApproved": true}),
)
resp, err := genkit.Generate(ctx, g,
ai.WithMessages(resp.History()...),
ai.WithTools(deleteFilesTool),
ai.WithToolRestarts(approved),
ai.WithUse(&middleware.ToolApproval{}),
)
fmt.Println(resp.Text())
} 4. 技能
扫描目录中的 SKILL.md 文件,并将其内容注入到系统提示词中。同时暴露一个 use_skill 工具,以便模型按需加载特定技能。
resp, err := genkit.Generate(ctx, g,
ai.WithPrompt("How do I deploy this service?"),
ai.WithUse(&middleware.Skills{SkillPaths: []string{"./skills"}}),
) 5. 文件系统
通过注入的工具(list_files、read_file,以及在启用写入时的 write_file 和 edit_file),为模型提供对本地文件系统的限定范围访问。路径安全性得到强制执行,确保模型永远无法逃逸根目录。
resp, err := genkit.Generate(ctx, g,
ai.WithPrompt("Create a hello world program in the workspace"),
ai.WithUse(&middleware.Filesystem{
RootDir: "./workspace",
AllowWriteAccess: true,
}),
) 构建自定义中间件
预构建的中间件覆盖了常见场景,但该系统的真正威力在于编写自己的中间件。假设你正在构建一个AI智能体客户支持应用,需要确保模型绝不提及竞争对手产品或内部定价数据。与其将规则编码到每个提示词中,不如通过中间件以确定性方式强制执行。
自定义中间件在所有语言中遵循一个简单约定:提供一个名称和一个工厂函数,该函数返回所需的钩子。工厂函数在每次 generate() 调用时被调用一次,你只需实现你需要的钩子。
以下是一个约20行代码的完整自定义内容过滤器:
// ContentFilter rejects model responses containing any forbidden term.
type ContentFilter struct {
ForbiddenTerms []string `json:"forbiddenTerms"`
}
func (ContentFilter) Name() string { return "app/contentFilter" }
func (f ContentFilter) New(ctx context.Context) (*ai.Hooks, error) {
return &ai.Hooks{
WrapModel: func(ctx context.Context, p *ai.ModelParams, next ai.ModelNext) (*ai.ModelResponse, error) {
resp, err := next(ctx, p)
if err != nil {
return nil, err
}
text := strings.ToLower(resp.Text())
for _, term := range f.ForbiddenTerms {
if strings.Contains(text, strings.ToLower(term)) {
return nil, fmt.Errorf("content filter: response contains %q", term)
}
}
return resp, nil
},
}, nil
} 你甚至可以组合和堆叠不同的中间件解决方案。中间件从左到右堆叠,第一个列出的为最外层包装,以此类推:
resp, err := genkit.Generate(ctx, g,
ai.WithModelName("googleai/gemini-flash-latest"),
ai.WithPrompt("What CRM should our customer use?"),
ai.WithUse(
&middleware.Retry{MaxRetries: 3}, // outer: retries the inner stack
&ContentFilter{ // inner: validates model output
ForbiddenTerms: []string{"CompetitorCRM", "RivalCo", "internal price"},
},
),
) 这里 Retry 包装了 ContentFilter,而 ContentFilter 又包装了模型调用。顺序很重要,Genkit 使其明确化。
如果你认为自己构建了一个对其他开发者有价值的中间件,你可以将其发布为包,供其他人受益!
开发者 UI 体验
你可以使用 Genkit 开发者 UI 检查、测试和调试你的应用,包括中间件执行。当你注册中间件时,它会在 Dev UI 中可见:你可以检查其配置、跟踪每个钩子层的执行轨迹,并测试不同的组合。
我们对 Genkit 中间件为你的应用解锁的能力感到兴奋,并期待看到你将构建哪些自定义中间件来解决你的用例。请查看中间件文档以深入了解,或者如果你刚接触该框架,可以从 Genkit 入门开始。
有关于新预构建中间件的想法?提交一个 Issue。我们很乐意听取您的建议,了解哪些改进能提升您的开发体验!
编码愉快!🚀
- AI
- 公告
- 学习
- 影响力