首页
/ Agno 会话存储接入 Google Cloud Storage:基于 GcsJsonDb 的 JSON Blob 持久化完整实战指南

Agno 会话存储接入 Google Cloud Storage:基于 GcsJsonDb 的 JSON Blob 持久化完整实战指南

2026-09-08 11:22:04作者:薛曦旖Francesca

导读

本指南聚焦于 agno(Agno Agent 框架)中的一个具体问题:如何把 Agent 的会话(session)与运行(run)数据持久化到 Google Cloud Storage(GCS)。Agno 官方在 cookbook/06_storage/gcs 目录下提供了完整的接入示例,其核心是把 GCS 当做一个"JSON 文件仓库"——每个逻辑表对应桶里的一个 JSON Blob,通过 GcsJsonDb 完成读写。读完本文你将掌握:GcsJsonDb 的完整配置与全部构造参数含义、gcloud 认证与 IAM 权限配置、如何用 UUID 生成隔离桶名并跨 Agent 延续同一会话,以及在无 GCS 账号时如何用 Docker 启动 fake-gcs-server 做本地联调。


一、背景:存储抽象与 GcsJsonDb 的定位

Agno 的 Agent 在运行时会产生会话(session)、运行(run)、用户记忆(user memory)等状态数据。默认情况下这些数据仅存在于内存中,进程退出即丢失。为了让 Agent "记得上次聊到哪里",Agno 在 Agent 上暴露了 db 参数,接受一个实现统一接口的后端对象。

cookbook/06_storage 目录下,Agno 为同一套接口提供了多种实现:SQLite、Postgres、MySQL、MongoDB、Redis、DynamoDB,也包括纯 JSON 文件形态的 in_memory / json_db 后端。GCS 方案则是把这些 JSON 文件进一步搬到了云上:不再使用本地文件系统,而是把每一个逻辑表存储为 GCS 桶里的一个 JSON Blob(对象)。这样会话数据天然具备云端冗余、跨机器共享、无本地磁盘依赖的特性。

从源码实现看,GcsJsonDb 继承自 libs/agno/agno/db/base.py 中定义的 BaseDb,类定义于 libs/agno/agno/db/gcs_json/gcs_json_db.py#L44-L104。因此它对上层 Agent/Team/Workflow 暴露的能力与其他后端完全一致:会话的 upsert/查询/删除、run 记录管理、用户记忆(memory)的增删查、指标统计、知识库内容、trace/span 等。

关键概念:GcsJsonDb 与 SQL 后端的关键差异在于"没有表结构",因此其 table_exists() 恒返回 True(见 gcs_json_db.py)。它是用"一个 JSON 文件 + 全量读写"来模拟表语义的。


二、环境准备与依赖安装

官方 README 给出的最小安装命令:

uv pip install google-cloud-storage

如果使用官方示例脚本(涉及 Web 搜索工具与云端搜索),还需要一并安装:

uv pip install google-auth google-cloud-storage openai ddgs

其中:

  • google-cloud-storage:GcsJsonDb 底层依赖的官方 GCS 客户端。源码在 gcs_json_db.py#L38-L41 中通过 try: from google.cloud import storage 导入,一旦缺失会抛出明确提示 google-cloud-storage not installed. Please install it with pip install google-cloud-storage
  • google-auth:用于在示例脚本中调用 google.auth.default() 读取当前环境默认凭据;
  • openai:Agent 默认调用 OpenAI 模型所需的 SDK;
  • ddgs:DuckDuckGo 搜索工具链的依赖。

三、最小接入配置

把 GCS 作为 Agent 会话后端的代码非常简短。官方 README 给出的最小配置如下:

from agno.agent import Agent
from agno.db.gcs_json import GcsJsonDb

db = GcsJsonDb(
    bucket_name="your-bucket-name",
)

agent = Agent(
    db=db,
    add_history_to_context=True,
)

这段代码中:

  • GcsJsonDb(bucket_name=...) 仅强制要求桶名,其余参数都有默认值(详见下文第四节);
  • Agent(db=db) 把会话与运行数据落盘到该桶;
  • add_history_to_context=True 是关键:让 Agent 在生成回复前把历史消息放回上下文,从而在多轮对话中"记得"前文。

从这里也可以看到整个 cookbook 的统一用法:db 可以传入任一存储后端,示例脚本的对应完整实现见 cookbook/06_storage/gcs/gcs_json_for_agent.py


四、GcsJsonDb 构造参数全解析

将配置从"最小可用"扩展到"生产可用",需要理解每个参数的含义。对照构造函数源码 gcs_json_db.py#L44-L104 与基类 base.py#L330-L355,参数表如下:

参数 必填 默认值 作用
bucket_name ✅ 是 GCS 桶名,JSON Blob 的存放位置
prefix "agno/" 桶内对象路径前缀,用于组织文件;若结尾缺少 / 会自动补上
session_table agno_sessions 会话表对应 JSON 文件名(不含扩展名)
runs_table agno_runs(或 {session_table}_runs run 记录文件,一次 run 一条记录
memory_table agno_memories 用户记忆(memory)文件
metrics_table agno_metrics 每日指标统计文件
eval_table agno_eval_runs 评估运行记录文件
knowledge_table agno_knowledge 知识库内容文件
traces_table agno_traces 追踪(trace)记录文件
spans_table agno_spans span 记录文件
project GCP 项目 ID;不传时使用客户端默认项目
credentials GCP 凭据对象;不传时使用 ADC 默认凭据
id 自动生成 数据库实例 ID,内部由 bucket_name + project + prefix 作为种子生成,通常无需手动指定

几个值得注意的实现细节:

  1. 表名 = 文件名_get_blob_name()(见 gcs_json_db.py#L110-L112)将文件名拼接为 f"{prefix}{filename}.json",即每个逻辑表对应桶中一个形如 agno/agno_sessions.json 的 JSON 对象。
  2. 存储形态是"列表 JSON"_write_json_file()gcs_json_db.py#L153-L175)用 json.dumps(data, indent=2, default=str) 把整张"表"(一个行字典列表)序列化后写入 Blob,content-type 为 application/json;新建文件时先写入空列表 []
  3. 全量读改写模型:从源码可以看出,每次 upsert 都是"整文件读出 → 内存中增删改 → 整文件写回"。这在会话数据量级下简单可靠,但意味着 GcsJsonDb 的批量写入(upsert_sessionsupsert_memories)不支持高效批量原语,源码会记录日志并退化为逐条 upsert(见 gcs_json_db.py#L761-L776)。
  4. 错误不静默:读写 Blob 时,除 NotFound(文件不存在)按空数据处理外,任何认证失败、网络错误、配额问题都会记录日志后向上抛出,避免"调用方误以为写入成功"。

五、认证(Authentication)

GCS 客户端需要有效凭据才能访问桶。官方 README 提供了两种标准方式:

# 方式一:使用 gcloud CLI 的应用默认凭据
gcloud auth application-default login

# 方式二:使用服务账号 JSON 文件的环境变量
export GOOGLE_APPLICATION_CREDENTIALS="path/to/service-account.json"

两种方式均通过 ADC(Application Default Credentials) 生效。GcsJsonDb 构造时若不显式传入 credentials,其内部的 gcs.Client(project=project, credentials=credentials)gcs_json_db.py#L103)会自动读取环境中的默认凭据。

示例脚本 gcs_json_for_agent.py#L22-L34 演示的是另一种显式写法——用 google.auth.default() 一次性取回凭据与项目 ID,再显式传给 GcsJsonDb

credentials, project_id = google.auth.default()

db = GcsJsonDb(
    bucket_name=unique_bucket_name,
    prefix="agent/",
    project=project_id,
    credentials=credentials,
)

六、IAM 权限(Permissions)

即使认证通过,账号也需要对目标桶具备读写权限。README 给出的 IAM 授权方式是为用户绑定 roles/storage.admin

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member="user:your-email@example.com" \
    --role="roles/storage.admin"

实际落地时建议按最小权限原则收敛为 roles/storage.objectAdmin(读写对象)或 roles/storage.objectViewer(只读),并确认:

  • 目标 GCS 桶已存在(GcsJsonDb 不会自动建桶,只读写桶内对象);
  • 账号对该桶有 storage.objects.get/list/create/delete 权限;
  • 若使用服务账号,需要保证其被授予相应角色的成员权限,并导出对应的 key 到 GOOGLE_APPLICATION_CREDENTIALS

七、示例脚本深度拆解:多 Agent 会话延续 + 桶内容 Dump

cookbook/06_storage/gcs/gcs_json_for_agent.py 是该目录的核心示例,比 README 的最小片段更完整。它展示了三件事:生成唯一桶名、两个 Agent 共享同一会话、按开关导出桶内会话数据

7.1 调试开关 DEBUG_MODE

脚本顶部定义了一个模块级全局变量:

DEBUG_MODE = False

README 明确说明:把它设为 True 后,脚本会在执行结束时打印桶内各会话的 memory 内容,方便你确认数据确实落到了 GCS。对应代码段(gcs_json_for_agent.py#L68-L74)为:

if DEBUG_MODE:
    print(f"\nBucket {db.bucket_name} contents:")
    sessions = db.get_sessions(session_type=SessionType.AGENT)
    for session in sessions:
        print(f"Session {session.session_id}:\n\t{session.memory}")
        print("-" * 40)

db.get_sessions() 是 BaseDb 定义的标准查询入口,支持按 session_typeAGENT / TEAM / WORKFLOW,枚举定义于 libs/agno/agno/db/base.py)过滤,返回的每条 session 携带其 memory 字段。

7.2 用 UUID 生成彼此隔离的桶名

在多租户或测试场景,手动指定桶名容易冲突。脚本的做法是用一个基础名加 UUID4 前 12 位生成唯一桶名:

import uuid

base_bucket_name = "example-gcs-bucket"
unique_bucket_name = f"{base_bucket_name}-{uuid.uuid4().hex[:12]}"

这避免了多次运行脚本时反复读写同一个桶造成数据串扰,是沙箱/演示环境的好习惯。脚本同时以 prefix="agent/" 组织目录前缀,使会话相关 JSON 集中在 agent/ 前缀下。

7.3 跨 Agent 延续同一个会话

脚本先创建 agent1,用两个问题开启对话:

agent1 = Agent(
    db=db,
    tools=[WebSearchTools()],
    add_history_to_context=True,
    debug_mode=DEBUG_MODE,
)

agent1.print_response("How many people live in Canada?")
agent1.print_response("What is their national anthem called?")

随后创建 agent2,并显式传入 session_id=agent1.session_id

agent2 = Agent(
    db=db,
    session_id=agent1.session_id,
    tools=[WebSearchTools()],
    add_history_to_context=True,
    debug_mode=DEBUG_MODE,
)

agent2.print_response("What's the name of the country we discussed?")
agent2.print_response("What is that country's national sport?")

这正是本示例最有价值的部分:agent2 是一个全新的 Agent 对象,但因为指向同一个 session_id 且共享同一个 db,它能够基于 agent1 产生的历史上下文回答"we discussed"所指的国家。后续问题即使换一台机器、重启进程,只要桶内会话数据还在,就可以继续对话。这验证了会话持久化对"Agent 状态可恢复"的意义。

7.4 执行流程

gcloud init
gcloud auth application-default login
python gcs_json_for_agent.py

gcloud init 用于初始化项目配置,gcloud auth application-default login 建立本地 ADC。运行结束后,会话与 run 数据便持久化在桶中。


八、本地联调:用 fake-gcs-server 模拟 GCS

没有真实 GCS 账号或不想产生云成本时,README 推荐使用开源的 fake-gcs-server(一个兼容 GCS 对象存储 API 的本地模拟器,通过 Docker 运行)完成存储功能联调。

8.1 创建 docker-compose.yml

先在项目根目录创建 docker-compose.yml(README 原样内容):

version: '3.8'
services:
  fake-gcs-server:
    image: fsouza/fake-gcs-server:latest
    ports:
      - "4443:4443"
    command: ["-scheme", "http", "-port", "4443", "-public-host", "localhost"]
    volumes:
      - ./fake-gcs-data:/data

要点说明:

  • 本地模拟器以 http 协议监听 4443 端口;
  • -public-host localhost 保证客户端访问地址解析正确;
  • 宿主机目录 ./fake-gcs-data 挂载到容器 /data,模拟器的数据落在本地,便于检查/清理。

8.2 启动与指向模拟器

docker-compose up -d

启动后,通过环境变量 STORAGE_EMULATOR_HOSTgoogle-cloud-storage 客户端把 API 调用全部指向本地端点:

export STORAGE_EMULATOR_HOST="http://localhost:4443"
python gcs_json_for_agent.py

README 特别提醒了两点使用体验:

  1. 使用 fake-gcs-server 时不会强制校验认证,无需配置真实凭据;
  2. google-cloud-storage 客户端会自动探测 STORAGE_EMULATOR_HOST,因此上面的代码无需做任何改动即可切换到模拟环境——这正是存储层抽象带来的便利:同一份 GcsJsonDb 代码,真实环境读真实桶,测试环境读本地模拟桶。

小提示:示例脚本与 README 中的文件名略有差异(脚本实为 gcs_json_for_agent.py),运行时以目录内实际存在的脚本为准。


九、从源码看 GcsJsonDb 的读写可靠性设计

当把"数据库"交给一个对象存储服务时,可靠性取决于客户端的异常处理。GcsJsonDb 的读写实现值得借鉴:

  • 读取路径_read_json_filegcs_json_db.py#L114-L151):先 download_as_bytes().decode("utf-8")json.loads;捕获 NotFound 视为"文件尚不存在",若 create_table_if_not_found=True 则自动上传 [] 初始化;其余异常(权限、配额、网络)与 JSON 解析错误都会记录日志后原样抛出,注释中明确写道"一个被吞掉的空列表返回会让调用方误以为表为空";
  • 写入路径_write_json_filegcs_json_db.py#L153-L175):json.dumps(...)upload_from_string,任何失败都会记录并抛出,绝不静默——否则调用方会误以为数据已经落盘;
  • 会话与 run 分离存储:会话记录与其 run 记录分别存放在不同 JSON 文件(agno_sessions.jsonagno_runs.json),查询会话时会从 run 文件回填该会话的历史 run 并与旧版 runs 字段合并(gcs_json_db.py#L631-L636),这也是删除会话时级联清理 run 记录的由来。

此外,GcsJsonDb 还提供了与基类一致的会话过滤、排序、分页能力(按 user_idagent_id、时间戳过滤,sort_by/sort_order 排序,limit/page 分页),由于没有查询引擎,这些都在内存中完成;排序辅助逻辑集中在 libs/agno/agno/db/gcs_json/utils.py 中(含 updated_at 缺失时回退 created_at 的处理)。指标统计(calculate_metrics)也由 utils.py 提供的日期/会话数据聚合工具支撑。


十、生产使用建议与限制小结

综合官方文档与源码,将 GcsJsonDb 用于生产或团队项目时,建议关注以下事实:

  1. 桶需预先创建:GcsJsonDb 只负责桶内对象的读写,不负责建桶;
  2. 权限按最小化授予:认证上优先用服务账号 + GOOGLE_APPLICATION_CREDENTIALS,权限上从 roles/storage.objectViewer / objectAdmin 起步,而非直接使用 roles/storage.admin
  3. "全量读改写"的适用边界:每次 upsert 都会重写对应表的整个 JSON 文件,适合会话级数据量;高频、超大批量写入场景请优先考虑 SQL/NoSQL 类后端;
  4. 调试手段丰富:既可用 DEBUG_MODE=True 在脚本内打印桶内会话与 memory,也可在本地用 fake-gcs-server 把整个读写链路跑通后再切换到真实桶;
  5. 关联代码路径:本方案的实现位于 libs/agno/agno/db/gcs_json/gcs_json_db.py,辅助排序/指标函数位于 libs/agno/agno/db/gcs_json/utils.py,导出入口在 libs/agno/agno/db/gcs_json/init.py,示例与测试说明分别见 cookbook/06_storage/gcs/gcs_json_for_agent.pycookbook/06_storage/gcs/TEST_LOG.md,可在此基础上扩展自己的多 Agent 共享会话、用户记忆或指标上报场景。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389