
Agno 文件系统 Namespaces 实战多租户隔离、共享与按用户细分的文件存储【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno导读本指南围绕 agno 的 FileSystem Namespaces 机制展开讲解如何为 Agent 的持久化文件存储划分命名空间从单 Agent 服务多用户的{user_id}模板化隔离到用 callable 工具工厂实现 VIP/租户分层的任意策略再到两个 Agent 通过共享命名空间名实现生产者写、消费者只读的协作模式。读完你能够理解 namespaces 的规范化规则、fail-closed 安全语义并直接复用仓库中的三个可运行示例。什么是 Namespace为 Agent 文件存储命名在 agno 中FileSystem为 Agent 提供一套跨会话、跨 run 持久化的私有文件系统。namespace就是给这份文件存储起的名字它决定了同一后端上的哪些文件属于谁。核心规则只有三条命名一个 namespace 是可选的cookbook 中其它所有示例都直接使用默认存储FileSystem(db)会自动落到默认命名空间同一个后端 同一个名字 同一份文件不同的名字 完全隔离。共享是显式的靠名字来实现隔离是按规范化后的名字计算的namespace 会被统一转为小写并做 URL 安全化lowercase 且 URL-safe因此BANK、bank与BaNk指向同一个存储。何时才需要显式命名当你在同一后端上需要多个存储时实践中就是两类场景隔离用户或在 Agent 之间刻意共享。Namespace 的规范化规则与模板占位符FileSystem的构造签名见 fs.py如下def __init__( self, backend: Any None, namespace: str DEFAULT_NAMESPACE, # 默认 default *, db: Optional[BaseDb] None, max_file_bytes: int 1_000_000, # 单文件上限 1MB max_namespace_bytes: int 20_000_000 # 单命名空间上限 20MB ) - None其中backend与db必须二选一同时传或都不传都会抛ValueError传入SqliteDb/PostgresDb这类存储句柄时_as_backend()会自动将其包装为DbFileSystem使 Agent 的文件与其会话、记忆共用同一个数据库。规范化小写 URL 安全namespace 的规范化逻辑在 _paths.py 的sanitize_namespace_segment与normalize_namespace中实现先做 NFC 归一化再.lower()小写仅保留 URL 安全字符a-z0-9.-_/其余一律百分号编码如ü会编码为%c3%bc且整体再次小写以保证幂等之所以编码而非拒绝、编码而非 slug 化是因为用户 id 是任意输入slug 化不是单射的a b与a-b会被折叠成同一个 namespace导致两个租户静默共享文件而百分号编码是可逆的不同的 id 永远保持不同。模板占位符{user_id}、{agent_id}、{team_id}namespace 中可以嵌入模板占位符如assistant/{user_id}。源码只承认这三个占位符见 _paths.py 的TEMPLATE_PLACEHOLDERS且解析规则严格占位符只在每次工具调用时由框架注入的 run context 解析{user_id}取自run_context.user_id{agent_id}、{team_id}分别取自注入的 agent/team 的id绝不来自模型提供的参数——提示词无法把文件重定向到别人的命名空间解析时占位符的值必须是单个路径段不含/不含花括号见normalize_template_value例如resolve(user_idu42/../u43)会直接抛InvalidPathError两个占位符之间必须有分隔符{user_id}{team_id}会被拒绝因为(a,bc)与(ab,c)无法被唯一地反解回两个值可能让两对不同的组合共享同一个存储调用时若某个占位符的值缺失例如匿名 run 没有 user_id会fail closed——抛出InvalidPathError而不是静默回退到共享命名空间。# 程序化绑定模板resolve() 返回绑定后的实例 bound fs.resolve(user_idu42) # namespace radar/u42 other fs.resolve(user_idu43) # 完全隔离 bound.append(seen/log.md, x\n) assert other.read(seen/log.md) is None # 互相不可见单元测试 test_fs.py 验证了这套行为resolve绑定并隔离、拒绝多段值、部分解析只绑user_id不绑team_id后实例仍保持 templated 且任何文件操作都会抛错、非模板实例resolve原样返回自身。大小写与身份系统的坑由于 namespace 按小写规范化Alice与alice会落入同一个存储。如果你的身份系统把这两个 id 视为两个不同的人务必在上游先做归一化再把 id 写进模板。身份只在你写入名字的那个位置生效这是整个隔离模型的安全边界。场景一basic.py —— 单 Agent 服务多用户的声明式隔离最典型的用法是一个静态 Agent 实例通过模板化的{user_id}为每个终端用户提供独立的文件存储——不需要工厂、不需要为每个用户创建 Agent 对象也不存在提示词重定向命名空间的可能。核心代码basic.pydb SqliteDb(db_fileDB_FILE) fs FileSystem(db, namespaceassistant/{user_id}) # 模板化命名空间 agent Agent( modelOpenAIResponses(idgpt-5.5), tools[fs.tools()], instructions[ You are a project assistant. Keep your working notes in your files., fs.instructions(), # 组合使用fs.tools() 不再自动附加指令 ], ) # 每次 run 携带 user_id模型无法影响它 agent.print_response(Append to work-log.md: Resolved a duplicate-charge refund..., user_idalice) agent.print_response(Append to work-log.md: Investigated a failed invoice..., user_idbob)运行时行为有三点值得注意隔离assistant/alice与assistant/bob是两个存储。alice 询问我记录了哪些工作日志时只会看到自己的内容匿名 run 失败关闭不带user_id的 run 会直接报错this agents files require user_id for this run and none was provided而不会塌缩进某个共享存储——八个工具仍然注册可用但每一次调用都会失败后端直证脚本最后用fs.resolve(user_idalice).read(work-log.md)直接从后端读取打印出两个命名空间各自的独立内容。对应测试日志 TEST_LOG.md 记录了该示例的 PASS 结果与完整工具调用轨迹。场景二custom_factory.py —— callable 工具工厂实现任意策略当单一的{user_id}占位符不够用时把tools参数换成一个callable 工具工厂。该 callable 在每次 run 时接收可信的RunContext按任意逻辑角色、租户、自定义 key决定命名空间结果会按用户缓存。核心代码custom_factory.pyVIP_USERS {alice} def fs_for_user(run_context: RunContext) - List: # fail closed匿名 run 直接拒绝避免 user_idNone 插值出 support/standard/None # 让所有匿名调用者共享一个命名空间 if not run_context.user_id: raise ValueError(this agents files require a user_id and none was provided for this run) tier vip if run_context.user_id in VIP_USERS else standard namespace fsupport/{tier}/{run_context.user_id} return [FileSystem(db, namespacenamespace).tools()] agent Agent( modelOpenAIResponses(idgpt-5.5), toolsfs_for_user, # callable而非工具列表 instructions[ You are a support assistant. Keep your case notes in your files., FileSystem.instructions(), # 类级调用不依赖任何实例/命名空间 ], )关键设计点策略归属清晰匿名 run 是否共享一个匿名命名空间由工厂自己决定是一个显式选择而不是意外得来的默认行为指令与命名空间解耦工厂为每个用户新建FileSystem所以指令必须从类上取FileSystem.instructions()它只描述工具本身绝不绑定某个命名空间验证脚本用FileSystem(db, namespacesupport/vip/alice)与FileSystem(db, namespacesupport/standard/carol)直接读后端确认 VIP 用户 alice 落在专属层级、普通用户 carol 落在 standard 层级。场景三shared_namespace.py —— 两个 Agent 显式共享一个存储隔离的另一面是共享两个 Agent 通过挂载同一个 namespace 名字共享文件。生产者拿到完整工具面消费者则用tools(read_onlyTrue)instructions(read_onlyTrue)挂载三个只读工具read_file、list_files、search_content只能查阅记录、没有任何写入手段。核心代码shared_namespace.pydb SqliteDb(db_fileDB_FILE) producer_fs FileSystem(db, namespaceresearch/decisions) consumer_fs FileSystem(db, namespaceresearch/decisions) # 同名 共享 recorder Agent( modelOpenAIResponses(idgpt-5.5), tools[producer_fs.tools()], instructions[You record engineering decisions., producer_fs.instructions()], ) consumer_toolkit consumer_fs.tools(read_onlyTrue) answerer Agent( modelOpenAIResponses(idgpt-5.5), tools[consumer_toolkit], instructions[You answer questions about past engineering decisions., consumer_fs.instructions(read_onlyTrue)], )只读工具面的内部实现read_onlyTrue的工具面由 toolkit.py 的READ_ONLY_TOOLS定义[read_file, list_files, search_content]。注意两点源码注释与 TEST_LOG.md 均明确记录早期版本只读面还包含check_lines现在它是四个工具、默认翻转后是三个——check_lines只能通过include_tools显式点名加入read_only只约束工具面同一个FileSystem对象在 Python 侧仍然可以调用write()。所以消费者必须只拿到tools(read_onlyTrue)构造的工具包而绝不能拿到FileSystem对象本身。工具面全貌完整的 FileSystem 工具面共九个FULL_TOOLSread_file、write_file、append_file、replace_lines、list_files、search_content、check_lines、move_file、delete_file。默认注册笔记七件套不含check_lines与delete_fileallow_deleteTrue才会加入delete_file破坏性操作默认关闭归档走move_file到archive/目录才是推荐流程。何时使用 Namespace决策清单任何面向用户、需要保留工作状态的 Agent命名空间里不写{user_id}所有用户就会共享同一个文件存储超出单一占位符的角色/租户级范围划分用custom_factory.py的 callable 工厂方案一个 Agent 生产记录、另一个 Agent 查阅用shared_namespace.py的共享名 只读工具面方案先掌握单租户基础请阅读 01_getting_started 入门指南想从脚本里直接检查任意命名空间的内容请参考 05_operations 操作篇。运行示例python cookbook/13_filesystem/04_namespaces/basic.py python cookbook/13_filesystem/04_namespaces/custom_factory.py python cookbook/13_filesystem/04_namespaces/shared_namespace.py运行前提需要OPENAI_API_KEY三个示例均使用OpenAIResponses示例中指定的模型为gpt-5.5。示例会在tmp/下生成带随机后缀的 SQLite 数据库文件如agent_fs_tenants_uuid.db方便重复运行而不互相污染。源码路径速查README本指南原文basic.py —— 模板化多用户隔离示例custom_factory.py —— callable 工具工厂示例shared_namespace.py —— 共享命名空间示例FileSystem 核心实现含resolve、_resolve_from_context、tools、instructions命名空间规范化与模板解析sanitize_namespace_segment、normalize_namespace、parse_namespace_template、normalize_template_value工具面实现READ_ONLY_TOOLS、DEFAULT_TOOLS、FULL_TOOLS命名空间相关单元测试test_resolve_binds_and_isolates、test_unresolved_programmatic_calls_raise、test_resolve_rejects_multi_segment_value等示例测试日志【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考