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,
}),
) 构建自定义中间件
预构建的中间件涵盖了常见场景,但该系统的真正强大之处在于编写你自己的中间件。想象一下,你正在构建一个智能体客服应用,需要确保模型绝不提及竞争对手产品或内部定价数据。与其将这些规则编码到每个提示词中,不如通过中间件以确定性的方式强制执行它们。
自定义中间件在所有语言中都遵循一个简单的约定:提供一个名称和一个返回所需钩子的工厂函数。该工厂函数在每次 `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 来检查、测试和调试你的应用程序,包括中间件的执行。当你注册中间件时,它会在开发者 UI 中变得可见:你可以检查其配置、追踪通过每个钩子层的执行过程,并测试不同的组合。
我们对 Genkit 中间件为你的应用解锁的能力感到兴奋,并期待看到你将构建哪些自定义中间件来解决你的用例。请查看中间件文档以深入了解,或者如果你是框架新手,可以从 Genkit 入门开始。
对新的预构建中间件有想法?请提交一个 issue。我们很乐意听取哪些改进能提升你的开发体验!
编码愉快!🚀
- AI
- 公告
- 学习
- 影响