news 2026/11/5 15:41:17

agent-memory 的 whl 唯一顶层包名治理:从 src 平铺布局到 jiuwen_memory 命名空间

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
agent-memory 的 whl 唯一顶层包名治理:从 src 平铺布局到 jiuwen_memory 命名空间
  • 人工智能
  • AI Agent
  • Agent 记忆
  • RAG
  • MCP 服务

【免费下载链接】agent-memory

Memory 是一款面向 AI 智能体的长期记忆模块,为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。

项目地址:https://gitcode.com/openJiuwen/agent-memory
点击查看免费下载

本文以 F02-packaging-unique-toplevel 这一打包治理决策记录为主体,详解 agent-memory 为什么放弃src/平铺布局、如何将内核目录改名为唯一的jiuwen_memory顶层包、如何用 setuptoolspackages.find收敛 whl 的top_level.txt,以及开发态pytest/PYTHONPATH、安装态 site-packages 与deploy/docker三套 Dockerfile/Compose 之间如何保持一致。读完本文,你可以掌握 Python 分发包(whl)顶层命名空间的设计权衡,并能在自有项目中复现「改名 + 打包 + 部署」三方同步的完整落地路径。

背景:通用顶层名在宿主环境被 shadow

agent-memory 早期(mem2.0 时期)采用src/{api,common,config,...}的平铺目录布局,并通过 setuptools 的include=api*之类规则打 whl。其直接后果是:构建产物在top_level.txt中暴露出 9 个通用顶层名(api、common、config等)。

问题出在 Python 的模块搜索机制:当这个包以 SDK 形式被嵌入宿主项目进程时,sys.path的搜索顺序会让宿主自带的同名目录优先命中。如果宿主项目恰好有common/、config/或api/目录,sys.path优先 shadow(遮蔽)了包内的同名模块,导致JiuwenMemorySDK 在进程内initialize阶段就直接抛出ModuleNotFoundError: No module named 'common.type_def'——包自己 import 自己的代码都失败了。

决策记录同时指出第二类不同步问题:内核目录改名之后,deploy/docker/*仍执行COPY src ./src、compose 挂载../../../src:/app/src,而仓库中已不存在src/目录,镜像在构建期即失败。这说明顶层改名不是一个孤立的 import 前缀问题,而是「打包产物 + 开发态 + 部署镜像」三方必须同步的工程问题。

目录布局决策:src/改名为jiuwen_memory/

核心决策第一条是:仓库内核目录src/整体改名为jiuwen_memory/,而不是采用src/jiuwen_memory/的嵌套形式。当前仓库顶层结构印证了这一点:

  • jiuwen_memory/:内核包,内部包含api/、common/、config/、construction/、control/、ingest/、retrieval/、storage/等子包;
  • jiuwen_memory_entry/:HTTP / CLI / MCP 等接入 surface;
  • jiuwen_memory_adapter/:面向不同宿主框架的适配器。

配套的第二条决策是 import 语义统一:所有绝对引用统一为jiuwen_memory.*;开发态通过pytest.pythonpath = ["."]或PYTHONPATH=.直接以仓库根为搜索根,与安装态(包位于 site-packages 根)保持同一套 import 路径,从机制上消除「开发假绿、安装必挂」的测试分叉。仓库内示例代码可验证这一点,例如 quickstart.py 全部使用from jiuwen_memory.api import assemble形式的导入。

whl 顶层收敛:[tool.setuptools.packages.find]配置

打包侧的决策见 pyproject.toml:

[tool.setuptools.packages.find] where = ["."] include = [ "jiuwen_memory*", "jiuwen_memory_adapter*", "jiuwen_memory_entry*", ] exclude = [ "jiuwen_memory_entry.cli*", "jiuwen_memory_entry.mcp_server*", ]

要点有三:

  1. include 白名单:where = ["."]表示以仓库根为搜索根,只收录三个jiuwen_memory*前缀的包,因此构建出的 whl 其top_level.txt只包含jiuwen_memory、jiuwen_memory_adapter、jiuwen_memory_entry三个顶层名,不再暴露任何api/common/config等通用名;
  2. 排除非分发布件:jiuwen_memory_entry.cli与jiuwen_memory_entry.mcp_server两个 surface 被显式 exclude——CLI 与 MCP 表面有各自的运行脚本与可选依赖(如mcpextra),不随主 whl 分发;
  3. 三个顶层包保持独立:决策第 3 条明确不把jiuwen_memory_adapter/jiuwen_memory_entry并入jiuwen_memory包内,三者都是仓库根下的独立顶层包。安装后即可from jiuwen_memory_entry.xxx import ...。

bootstrap 与 flat path-hack:surface 侧的过渡方案

决策第 4 条为接入面补上了包化能力:补齐 jiuwen_memory_entry/init.py 并在 include 规则中收录jiuwen_memory_entry*。

但 surface 侧保留了「flat import」的历史形态。以 HTTP surface 的 入口文件 为例:

# 共享应用核(server / profiles / handler / config_loader)住在 jiuwen_memory_entry/core; # 加入 sys.path 后 flat-import 复用——本 surface 只做 HTTP 传输。 _CORE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "core") if _CORE_DIR not in sys.path: sys.path.append(_CORE_DIR)

即__main__.py自行把jiuwen_memory_entry/core追加进sys.path,随后通过import_required("profiles")等动态导入复用core下的server/config_loader/auth_middleware模块。这也是为什么启动脚本不需要为 flatimport server额外设置环境变量:run-server.sh 与 run-mcp.sh 统一导出

export PYTHONPATH="${REPO_ROOT}:${REPO_ROOT}/jiuwen_memory_entry/core${PYTHONPATH:+:${PYTHONPATH}}"

即PYTHONPATH=<repo>:<repo>/jiuwen_memory_entry/core,与文档元信息中记录的测试基线完全一致。需要注意的边界是:内核侧已经不可再把jiuwen_memory/目录当 flat root 使用——内核模块一律走jiuwen_memory.*的绝对命名空间,flat-import 仅残留在 bootstrap surface 层。

这一层「接入面不得反向依赖内核内部」的约束由测试固化:test_import_isolation.py 通过 AST 扫描断言jiuwen_memory_entry/core/import_support.py中的任何from jiuwen_memory.xxx import .../import jiuwen_memory.xxx语句都属违规,从源码结构看这正是为守护「Access 只允许依赖jiuwen_memory.api」这条边界。

deploy/docker 同步:COPY、editable 安装与热更新挂载

决策第 5 条要求部署文件与 rename 全量同步。当前仓库三套部署文件已全部落地为jiuwen_memory路径,且deploy/下已无任何src残留引用(可用rg "src" deploy复核)。

以 local/Dockerfile 为例:

COPY pyproject.toml ./ COPY jiuwen_memory ./jiuwen_memory COPY jiuwen_memory_entry ./jiuwen_memory_entry ... RUN --mount=type=cache,target=/root/.cache/pip \ pip install --upgrade pip \ && pip install torch==2.12.1+cpu --extra-index-url https://download.pytorch.org/whl/cpu \ && pip install -e ".[embed,deploy]"

关键机制在注释中写明:项目采用editable 安装,site-packages 中只保留指向/app/jiuwen_memory的链接。因此 compose 挂载源码目录即可实现「改代码免重建镜像」:

# deploy/docker/local/docker-compose.yml → 服务 agent-memory volumes: - ./config.yml:/config/config.yml:ro - ../../../jiuwen_memory:/app/jiuwen_memory:ro # 替代原 src:/app/src - ../../../jiuwen_memory_entry:/app/jiuwen_memory_entry:ro

见 local/docker-compose.yml。online与postgres两套 Compose 采用同样的双挂载(见 online/docker-compose.yml、postgres/docker-compose.yml),三套 Dockerfile 也都是COPY jiuwen_memory ./jiuwen_memory+pip install -e .的组合,HTTP 入口统一为python jiuwen_memory_entry/http_server/__main__.py。

由于__main__.py自己 append 了jiuwen_memory_entry/core,Dockerfile 中不再为 flatimport server额外设置PYTHONPATH环境变量——这避免了镜像内环境变量与代码内 path-hack 双轨并行的漂移风险。文档注释层面,deploy/docker/README.md 中指向配置模块的描述也已从src/config更新为jiuwen_memory/config。

拒绝的方案及其原因

决策记录给出了五个被否决的替代方案,其否决理由值得在类似项目中直接参考:

方案否决原因
只改packages.find、不改 import安装后 site-packages 中仍无顶层common包,包内from common ...导入必然失败
继续PYTHONPATH=jiuwen_memory+ flat-import开发态与 site-packages 安装态语义分叉,测试「假绿」,宿主 shadow 问题(#117)会复现
把jiuwen_memory_adapter/jiuwen_memory_entry挂到jiuwen_memory.*下本轮明确要求二者保持仓库根独立顶层,便于按 surface 独立分发与排除
只靠文档约定「宿主勿用 common 目录」通用名冲突在生态中无法靠约定避免,属于反模式
deploy 继续COPY src或软链src→jiuwen_memory与仓库真实布局分叉,editable 挂载与 CI 容易漏改;软链在 Windows 与部分构建上下文下不可靠

验证方法与可复现的测试基线

文档「验证」一节给出的四条基线均可在当前仓库直接复现:

  1. whl 顶层检查:构建 wheel 后检查top_level.txt,应无api/common/config等旧通用名,且包含jiuwen_memory、jiuwen_memory_adapter、jiuwen_memory_entry三个顶层名;
  2. 宿主 shadow 回归测试:在临时目录放置空common/并将其置顶PYTHONPATH,验证import jiuwen_memory.api与import jiuwen_memory_entry.core仍可用——这条直接复现并回归了 #117 的故障场景;
  3. 单元/契约测试:pytest -q -m unit tests/unit全量通过;
  4. 部署构建:deploy/docker下无残留src路径引用;docker compose -f deploy/docker/online/docker-compose.yml build agent-memory能通过COPY jiuwen_memory构建阶段(完整运行栈需要 Milvus / ES 等依赖服务,但build本身不依赖它们)。

其中 pytest 侧的支撑来自 pyproject.toml 的pythonpath = ["."]与unit/integration两个 marker:开发态以仓库根为搜索根,import 语义与安装态一致。

已知遗留与破坏性变更边界

文档「已知遗留」一节如实标注了本次治理的边界,读者在集成时应注意:

  • bootstrap surface 仍有 flat path-hack:jiuwen_memory_entry/core的 sys.path 追加与动态导入尚未完全包化,属于已确认的过渡形态;
  • 顶层名仍偏通用:jiuwen_memory_adapter/jiuwen_memory_entry虽已加项目前缀,但在极端宿主命名冲突下理论上仍可能被遮蔽;
  • 迁移历史保留:文档前文保留src/与旧顶层 import 的描述作为迁移历史证据,但文档内所有可执行 import 示例已统一为jiuwen_memory.*前缀,后续新增示例也须遵循该约定;
  • 对外 breaking change:这是面向调用方的破坏性变更——既有集成方必须把 import 前缀从旧的顶层名(如common.xxx、api.xxx)改为jiuwen_memory.*,且src/路径不存在,旧的PYTHONPATH=src式接入方式失效。

综上,agent-memory 的这套打包治理示范了一个通用工程结论:分发包的顶层命名空间必须与项目品牌绑定(unique toplevel),并让「whl 打包规则、开发态搜索路径、部署镜像 COPY/挂载」三者共享同一套目录事实,任何一侧滞后都会在构建期或宿主集成期以ModuleNotFoundError的形式暴露出来。

  • 人工智能
  • AI Agent
  • Agent 记忆
  • RAG
  • MCP 服务

【免费下载链接】agent-memory

Memory 是一款面向 AI 智能体的长期记忆模块,为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。

项目地址:https://gitcode.com/openJiuwen/agent-memory
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 1:46:33

MFC中种子填充算法的工程实现与避坑指南

1. 项目概述&#xff1a;为什么在MFC里实现种子填充&#xff0c;远不止“画个实心圆”那么简单你打开《计算机图形学》实验指导书&#xff0c;翻到第5页&#xff0c;“区域填充——种子填充算法&#xff08;MFC中&#xff09;”这行字印得工整&#xff0c;旁边还配了个带边界的…

作者头像 李华
网站建设 2026/10/29 19:30:31

UCI-HAR时间序列分类实战:从数据可视化到建模全流程解析

做时间序列分类的时间长了&#xff0c;总会发现一个规律&#xff1a;无论你手头的数据来自传感器读数、金融行情&#xff0c;还是工业设备的振动信号&#xff0c;建模之前的数据可视化与问题分析&#xff0c;往往决定了后面所有工作的上限。UCI-HAR这个数据集&#xff0c;是我在…

作者头像 李华
网站建设 2026/10/26 4:03:27

测试金字塔模型:构建高效自动化测试策略

1. 测试分级与金字塔模型概述在软件工程领域&#xff0c;测试分级是一个经久不衰的核心话题。我第一次接触测试金字塔概念是在2013年参与一个电商平台重构项目时&#xff0c;当时团队正陷入"自动化测试越多越好"的误区&#xff0c;导致CI流水线执行时间长达2小时。测…

作者头像 李华
网站建设 2026/10/21 2:36:26

同声传译软件livecaption-win-1.0.8-x64使用指南:部署、调优与避坑

简介&#xff1a;一款适用于 Windows x64 平台的同声传译软件 livecaption 1.0.8 客户端&#xff0c;主要面向需要实时语音转写与字幕翻译的会议、直播、网课及跨国交流场景&#xff0c;适合翻译从业者、内容创作者、外语学习者与远程协作用户。压缩包共 14 个文件&#xff0c;…

作者头像 李华
网站建设 2026/11/4 15:26:45

PCL与CloudCompare互补使用:点云处理实战经验与踩坑指南

1. 点云处理的两把利器&#xff1a;PCL与CloudCompare的互补定位先说说我自己的经历。做点云处理这几年&#xff0c;我身边不少同事和同行一开始只盯着PCL猛学&#xff0c;毕竟这个库功能确实全——配准、滤波、分割、特征提取、表面重建&#xff0c;几乎你能想到的算法它都有现…

作者头像 李华