用 Google Genkit Agents API 搭全栈 AI Agent(状态持久化 + 产物 + 流式)
你已经会用一堆智能体框架了,但每次产品从「能聊两句」升级到「多轮协作 + 长任务 + 前端实时更新」时,是不是都得把框架内部拆了重接?2026 年 7 月谷歌 Genkit(构建全栈 AI 应用的开源框架)发布预览版 Agents API,核心思路很聪明:把消息历史、工具执行循环、流式传输、状态持久化、前端协议全部塞进一个 chat() 接口背后。无论智能体跑在进程内还是挂在 HTTP 端点后,用法完全一致。本教程用 TypeScript 带你从零跑通一个「记状态、能产出文件、可流式对话」的全栈 Agent。
先搞懂:Genkit Agents API 解决什么痛点?
大多数框架把两类数据混在一起,结果一升级就崩。Genkit 明确区分了它们:
| 概念 | 通俗解释 | 例子 |
|---|---|---|
| 自定义状态(State) | 驱动「下一轮对话」的强类型应用数据 | 工作流进度、任务清单、已选实体 |
| 产物(Artifact) | 用户可单独查看 / 下载 / 版本管理的生成物 | 报告、代码补丁、旅行行程 |
| chat() 接口 | 一个抽象,统一上面所有能力 | 一次性应答、流式多轮、暂停等待人工确认 |
一个 Agent 对象贯穿三种形态:一次性回答、流式多轮对话、等待人工确认的暂停工具调用、独立运行的长耗时任务——全靠同一个对象,产品从聊天机器人迭代到多智能体工作流时不用换框架内部组件。
Step 1:准备环境并初始化 Genkit 项目
Genkit 是 Node 优先的框架,先确认你有 Node 20+,然后新建项目并装包:
# 新建目录并初始化
mkdir my-genkit-agent && cd my-genkit-agent
npm init -y
# 安装 Genkit 核心 + Google AI 插件(用 Gemini 当大脑)
npm install genkit @genkit-ai/ai @genkit-ai/googleai
# 可选:装 CLI 方便本地调试
npm install -D genkit-cli
GEMINI_API_KEY 注入即可,别写死在代码里。Step 2:定义你的第一个 Agent(chat 接口)
下面是一个最小可跑的 Agent:它维护一段对话历史,能多轮回答。关键就是 agent.chat() 返回的会话对象可以一直复用。
import { genkit } from 'genkit';
import { googleAI } from '@genkit-ai/googleai';
const ai = genkit({ plugins: [googleAI()] });
// 定义一个最简单的 Agent
const agent = ai.defineAgent(
{ name: 'helper', model: googleAI.model('gemini-2.5-flash') },
async (input) => {
return `收到:${input.prompt}`;
}
);
// 发起一轮对话
const session = agent.chat();
const r1 = await session.send('帮我规划一次三天两晚的上海出差');
console.log(r1.text);
session.send() 自动把历史带进去,不用自己拼 messages 数组。Step 3:给 Agent 加工具,让它真正「干活」
光能聊没用,得让它能查实时数据。我们加一个「查天气」工具:
const getWeather = ai.defineTool(
{ name: 'getWeather', description: '查询某城市天气',
inputSchema: z.object({ city: z.string() }) },
async ({ city }) => {
// 这里换成你真实的天气 API
return { city, tempC: 28, condition: '晴' };
}
);
const agent = ai.defineAgent(
{ name: 'tripPlanner', model: googleAI.model('gemini-2.5-flash'),
tools: [getWeather] },
async (input) => input.prompt
);
工具循环由框架接管:你不用写「if 用户问天气就调工具」的判断,Genkit 会在 chat() 内部自动跑「思考→调工具→再思考」循环,直到给出最终答案。
Step 4:区分「状态」与「产物」,让 Agent 会攒东西
这是 Genkit 最实用的设计:工具可以在当前会话里更新「状态」或「产物」,客户端实时收到变更。
const saveItinerary = ai.defineTool(
{ name: 'saveItinerary',
description: '把行程存成可下载的产物',
inputSchema: z.object({ markdown: z.string() }) },
async ({ markdown }, ctx) => {
// 产物:用户能单独下载/版本管理
ctx.artifacts.set('itinerary', { content: markdown });
return { ok: true };
}
);
// 同时在多轮中维护「已选城市」状态
// ctx.state.set('selectedCity', '上海')
Step 5:状态持久化(服务端 vs 客户端管理)
Genkit 提供两种持久化方案,二选一:
// 方案 A:服务端管理(推荐生产多实例)
// 内置 Firestore(生产)/ 内存(开发)/ 文件(本地测试)
const ai = genkit({
plugins: [googleAI()],
sessionStore: { kind: 'file', path: './sessions' }
});
// 客户端用 sessionId 重新连接,自动还原历史+状态+产物
// 方案 B:客户端管理(适合有数据驻留要求的场景)
// 不配存储,服务端每次返回完整状态,客户端回传
// 代价:会话变长后网络负载会增加
合规敏感场景选方案 B:服务端不持久化任何用户数据,满足严格的数据驻留约束。但代价是会话增长后每次请求都要带着完整状态往返。
Step 6:开启流式传输,前端实时显示
用 sendStream 替代 send,前端就能像打字机一样收到增量内容,连状态/产物变更也实时推送:
const { stream, response } = session.sendStream('把行程细化成每天安排');
// 前端:边收边渲染
for await (const chunk of stream) {
render(chunk.text); // 增量文本
}
const final = await response; // 最终完整结果
Step 7:部署成 HTTP 端点,同一个 Agent 复用
Genkit 的精髓:本地和线上是同一个 Agent 对象,不用为部署重写逻辑。
# 本地用开发者 UI 调试(带可视化 trace)
npx genkit start
# 部署到 Cloud Run / 任意 Node 服务
# 用 genkit/express 暴露 HTTP 端点
import { expressHandler } from 'genkit/express';
app.post('/agent/chat', expressHandler(agent));
chat() 抽象让你在「简易聊天」和「多智能体工作流」之间平滑升级,不用换框架。常见问题速查
| 现象 | 大概率原因 & 解决 |
|---|---|
| session.send 报模型未配置 | 没装 googleAI 插件或 GEMINI_API_KEY 未注入 |
| 工具没被调用 | 工具 description 太模糊,模型判断不需要 |
| 刷新页面后历史丢了 | 没配 sessionStore,或客户端没回传 sessionId |
| 流式卡住不动 | 用了 send 而非 sendStream,或前端没 await stream |