先说明白这篇解决什么。大多数团队接 agent 的第一次翻车,都不是模型不行,而是「它把不该改的东西改了」——本地跑的时候没人管,接了真库就出事。Genkit Dart 1.0 里最值得用的能力,恰好是能治这个病的那个:让流程在关键步骤停下来,等一个明确的确认再继续。
第一步:装依赖,跑起本地开发界面
# 在已有的 Dart / Flutter 工程里加依赖
dart pub add genkit
# 起本地开发界面(可逐次查看每次调用的输入输出与链路)
dart run genkit:startgenkit start 会拉起一个本地 UI,这是这套工具真正的学习加速器:你不需要靠 print 猜模型收到了什么、返回了什么。下面每改一步,都在这个界面里看一眼再往下走。
第二步:把一段 AI 逻辑写成一个「有类型」的 flow
Genkit Dart 的核心是 flow:一段可观察、可测试、输入输出都有类型的处理单元。类型不是装饰,它决定了模型的结构化输出能不能被编译器接住。官方把「在 Dart 里定义一次 schema、让模型按它产出结构化结果」这件事交给了 schemantic。
// 只读流程:给一个订单号,回一段可读的说明,不写任何东西
final explainOrder = defineFlow(
name: 'explainOrder',
inputSchema: /* 订单号 */,
outputSchema: /* 一段文本 */,
fn: (input, ctx) async {
final res = await ai.generate(
prompt: '用三句话说明这个订单现在卡在哪:${input.orderId}',
);
return res.text;
},
);先写只读流程有两个好处:一是没有副作用,怎么试都不会把线上数据搞坏;二是它能把「模型接得上、类型对得上、链路看得见」这三件事一次验证完。等这段跑顺了,再谈写操作。
第三步:给写操作加一道「停下来问人」
要真正干活,就得让 agent 调工具改数据。Genkit Dart 的做法是在工具执行里返回 .interrupt(...):流程在这里暂停,把「我准备做什么」交出去让调用方决定,确认后再从原处继续。这比在业务代码里到处插 if (needConfirm) 干净得多——暂停是可恢复的,状态不靠你自己在外面维护。
// 写操作:不是直接执行,而是先抛出一个「待确认」
final refundOrder = defineFlow(
name: 'refundOrder',
fn: (req, ctx) async {
if (!req.confirmed) {
return ctx.interrupt(
reason: '准备给订单 ${req.orderId} 退款 ${req.amount},是否确认?',
resumeWith: (answer) => answer.approved,
);
}
return await doRefund(req.orderId, req.amount);
},
);这一段是整篇最值得抄的地方:把「要不要问人」的决策放进流程本身,而不是靠外层包一层审批。配套的做法是给每个写操作单独定一个「可放开」的顺序——先放开退款,稳了两周再放开改价,别一次全开。
第四步:把提示词从代码里挪出去
提示词写在代码字符串里,改一句话就要重新发版;Dotprompt 把它拆成独立的 .prompt 文件,提示词、模型选择与输出 schema 放在一起,改文案等于改配置。
---
model: googleai/gemini
input:
schema:
orderId: string
output:
format: text
---
用三句话说明订单 {{orderId}} 目前卡在哪一步,
只陈述事实,不要给建议。好处不只在「改起来方便」:提示词进版本管理之后,谁在什么时候改了什么、改完分数有没有动,都能和代码一样被回看。配合 genkit_middleware 里的自动重试,可以少写一批样板代码。
第五步:上链路,别再用 print 调试
本地用 genkit start 看,线上用 genkit_otel 把每次调用的链路导出到 OpenTelemetry。agent 出问题往往是「第几步开始歪的」,光看最后那句回复没用,得能逐段回放。
还有两个实验性能力,建议先别上生产
1.0 里放出了实验性的多轮持久 agent(defineAgent / remoteAgent,在 package:genkit/experimental.dart)和生成式 UI(genkit_a2ui)。它们能做的事很吸引人,但接口还在变动期;如果想试,放在分支里、别进主流程。
落地顺序(照着做就行)
- 写一个只读 flow,在 genkit start 里跑通,确认模型与类型都接得上
- 挑一个「失败了也能人工补救」的写操作,给它加 .interrupt,跑一遍确认能暂停、能恢复
- 把提示词搬进 .prompt 文件,纳入版本管理
- 接上 genkit_otel,把线上链路跑起来,再按「一次一类动作」的节奏放开权限
最后提醒一句:具体 API 签名以官方文档与 pub.dev 上的包版本为准,1.0 之后仍在快速迭代;文里的代码是结构示意,接进去之前先对着当前版本的文档核一遍参数名。