news 2026/10/22 19:19:27

openJiuwen 记忆引擎基础模型:MemInfo 单条记忆信息结构全解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
openJiuwen 记忆引擎基础模型:MemInfo 单条记忆信息结构全解
  • 人工智能
  • AI Agent
  • Agent 框架
  • 工具调用
  • Agent 工作流
  • RAG
  • MCP Clients
  • 强化学习

【免费下载链接】agent-core-java

openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。

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

导读

MemInfo是 openJiuwen(agent-core-java)记忆引擎中描述单条记忆基础信息的核心数据模型,它贯穿长期记忆(LongTermMemory)的写入、检索与注入全链路:无论是用户画像分片、语义记忆、情景记忆,还是摘要与变量,最终都会以MemInfo的形式承载记忆 ID、内容、类型与时间戳。本文以 API 文档 MemInfo.md 为主体,结合仓库源码深度剖析其字段语义、JSON 序列化规则、构建方式及在记忆检索/注入流程中的真实调用关系,帮助你准确理解并正确使用该模型。

MemInfo 是什么:单条记忆的基础信息载体

MemInfo定义在com.openjiuwen.memory包下,源码位于 MemInfo.java。类的源码注释明确指出,它是 Python 版 openJiuwen Core 中openjiuwen/core/memory/long_term_memory.py里MemInfo的 Java 镜像实现,因此两套语言的记忆模型在语义上保持对齐。

从职责上看,MemInfo是记忆引擎中"一条记忆"的最小信息单元:它不承载检索打分(那属于MemResult),也不承载存储细节(那属于manage/mem_model下的各类MemoryUnit),它只负责把记忆的唯一标识、正文内容、记忆类型与产生时间这四个要素打包成一个可序列化、可传输、可构建的 Java 对象。

@JsonInclude(JsonInclude.Include.NON_NULL) public class MemInfo { @JsonProperty("mem_id") private String memId = ""; @JsonProperty("content") private String content = ""; @JsonProperty("type") private MemoryType type = MemoryType.USER_PROFILE; @JsonProperty("timestamp") private ZonedDateTime timestamp; // ... }

字段详解:四个字段承载一条记忆的完整信息

API 文档中列出了memId、content、type三个字段;从源码看,实际模型共包含四个字段,第四个timestamp用于记录记忆产生时间。各字段语义如下:

字段Java 类型JSON 键名默认值说明
memIdStringmem_id""记忆的唯一标识(memory id),由记忆引擎在存储时分配
contentStringcontent""记忆正文内容
typeMemoryTypetypeMemoryType.USER_PROFILE记忆类型枚举
timestampZonedDateTimetimestampnull记忆产生的时间戳

值得注意的细节(见 MemInfo.java):

  • JSON 键名映射:memId在序列化时映射为下划线风格的mem_id,与 Python 版实现保持一致,避免跨语言通信时字段名不一致。
  • 空值兜底策略:memId与content在构造器和 setter 中都会做null -> ""的空指针兜底(如this.memId = memId == null ? "" : memId;);type为null时回退为MemoryType.USER_PROFILE。
  • 非空才序列化:类级注解@JsonInclude(JsonInclude.Include.NON_NULL)意味着timestamp为null时不会被写入 JSON 输出,从而保持载荷精简。
  • 时间戳类型:使用java.time.ZonedDateTime承载带时区的时间信息,适合跨时区场景下的记忆回溯与排序。

type 字段与 MemoryType 记忆类型枚举

type字段的类型是com.openjiuwen.memory.manage.mem_model.MemoryType枚举(源码见 MemoryType.java),与 Python 版memory_unit.py中的MemoryType对齐。枚举定义如下:

枚举常量底层值(value)语义
FRAGMENT_MEMORYuser_profile用户画像分片记忆
USER_PROFILEuser_profile用户画像记忆(与FRAGMENT_MEMORY共用同一底层值)
SEMANTIC_MEMORYsemantic_memory语义记忆
EPISODIC_MEMORYepisodic_memory情景记忆
VARIABLEvariable变量记忆
SUMMARYsummary摘要记忆
UNKNOWNunknown未知/未识别类型

枚举提供了getValue()获取底层字符串值,以及静态方法fromValue(String)做反向解析:传入字符串与枚举底层值匹配则返回对应枚举,user_profile会被优先归一到USER_PROFILE,无法匹配时返回UNKNOWN。在记忆引擎内部,记忆类型字符串正是通过这个解析函数转换为MemoryType后再填入MemInfo.type的。

如何构建 MemInfo:构造器、Builder 与反序列化

API 文档提到"该类型通过 Lombok 生成构建器与访问器",但当前仓库的实际实现是手写编码的:源码中显式提供了无参构造器、全参构造器、四个 getter/setter,以及一个静态Builder内部类(见 MemInfo.java),并未使用 Lombok。三种构建方式各有用途:

方式一:静态 Builder(推荐,链式可读)

MemInfo info = MemInfo.builder() .memId("mem-2026-0001") .content("用户偏好使用 Java 与 Spring 技术栈") .type(MemoryType.USER_PROFILE) .timestamp(ZonedDateTime.now()) .build();

Builder 的字段初始值与构造器一致(memId=""、content=""、type=USER_PROFILE、timestamp=null),未显式设置的字段会落到这些默认值上。

方式二:全参构造器

MemInfo info = new MemInfo("mem-2026-0001", "记忆内容", MemoryType.SEMANTIC_MEMORY, ZonedDateTime.now());

构造器内部同样执行空值兜底:memId/content传null会变为"",type传null会变为USER_PROFILE。

方式三:无参构造器 + setter

MemInfo info = new MemInfo(); info.setMemId("mem-2026-0001"); info.setContent("记忆内容"); info.setType(MemoryType.EPISODIC_MEMORY); info.setTimestamp(ZonedDateTime.now());

无参构造器是 Jackson 反序列化 JSON(如{"mem_id":"...","content":"...","type":"semantic_memory","timestamp":"..."})时使用的入口,配合@JsonProperty注解即可完成JSON -> MemInfo的转换。

值语义:equals 与 hashCode

MemInfo重写了equals与hashCode(见 MemInfo.java),两个对象相等的判定条件为:memId与content用Objects.equals比较、type用枚举引用比较、timestamp用Objects.equals比较,四者全部一致才算相等。hashCode基于这四个字段组合计算。这意味着在测试断言、集合去重、缓存键值等场景中,MemInfo具备稳定的值语义,例如记忆检索结果可安全地与期望结果做assertEquals对比。

在记忆引擎中的真实使用场景

MemInfo并不是孤立的 DTO,它在 openJiuwen 长期记忆引擎中被多处直接使用,以下是从源码中确认的四个典型场景。

1. 分页查询用户记忆:getUserMemByPage

LongTermMemory的公开方法getUserMemByPage(String userId, String scopeId, int pageSize, int pageIdx, MemoryType memoryType)直接返回FutureList<MemInfo>(见 LongTermMemory.java)。其内部从检索管理器拉取原始数据后,逐条构建MemInfo:

results.add(new MemInfo( Objects.toString(item.get("id"), ""), Objects.toString(item.get("mem"), ""), memoryTypeFrom(item.getOrDefault("mem_type", MemoryType.UNKNOWN.getValue()), MemoryType.UNKNOWN), timestampFrom(item.get("timestamp")) ));

这里的memoryTypeFrom正是调用MemoryType.fromValue完成字符串到枚举的转换。同时该方法会做scopeId合法性校验,非法时会抛出MEMORY_GET_MEMORY_EXECUTION_ERROR错误;memoryType传null或UNKNOWN时表示不过滤类型、查询全部记忆。

2. 检索结果载体:MemResult.memInfo

记忆检索返回的MemResult(源码见 MemResult.java)内部包含一个MemInfo memInfo字段与一个double score打分字段。LongTermMemory.searchUserMem/searchUserHistorySummary返回的List<MemResult>中,每条结果都以MemInfo承载记忆本体(见 LongTermMemory.java 的toMemResults私有方法)。也就是说:MemResult = MemInfo(记忆本体)+ score(相似度打分)。

3. 上下文注入:构建 "Related Memories" 提示片段

在OpenJiuwenMemoryProvider(外部记忆提供者,源码见 OpenJiuwenMemoryProvider.java)中,模型调用前的记忆预取会把检索到的记忆拼装为提示词片段:

for (MemResult result : memResults) { MemInfo info = result.getMemInfo(); parts.add("- [" + typeValue(info) + "] " + contentValue(info) + " (score: " + formatScore(result.getScore()) + ")"); }

typeValue(info)读取info.getType()并转换为展示文本,contentValue(info)读取info.getContent()。检索结果的序列化输出同样以MemInfo字段为基础(id、content、type、score 四元组,见同文件 L404-L423)。

4. 会话运行时接入:OpenJiuwenMemoryRuntime

在OpenJiuwenMemoryRuntime(OpenJiuwenMemoryRuntime.java)中,检索结果同样通过mem.getMemInfo().getContent()提取记忆正文,供 Agent 运行时直接消费。

测试验证:检索结果中的 MemInfo 字段断言

仓库测试 LongTermMemoryTest.java 对searchUserMem的行为做了精确验证:模拟SearchManager分别返回USER_PROFILE、SEMANTIC_MEMORY、EPISODIC_MEMORY三类记忆,再断言返回结果按打分排序后的MemInfo字段:

assertEquals(List.of("semantic-id", "episodic-id"), results.stream() .map(result -> result.getMemInfo().getMemId()) .toList()); assertEquals(List.of(MemoryType.SEMANTIC_MEMORY, MemoryType.EPISODIC_MEMORY), results.stream() .map(result -> result.getMemInfo().getType()) .toList());

这段测试同时印证了两点:其一,检索排序按 score 从高到低进行(语义记忆 0.9 > 情景记忆 0.6);其二,MemInfo的memId、type字段通过getMemInfo()完整透出,MemInfo作为记忆检索结果的标准载体被稳定使用。

小结:MemInfo 的完整画像

维度结论
包路径com.openjiuwen.memory
源码位置memory/src/main/java/com/openjiuwen/memory/MemInfo.java
核心字段memId、content、type、timestamp
记忆类型由 MemoryType.java 枚举定义,支持画像/语义/情景/变量/摘要等类型
序列化Jackson +@JsonProperty(mem_id)+@JsonInclude(NON_NULL)
构建方式静态 Builder / 全参构造器 / 无参构造器 + setter
使用方LongTermMemory.getUserMemByPage、MemResult、OpenJiuwenMemoryProvider记忆注入、OpenJiuwenMemoryRuntime

总的来说,MemInfo是 openJiuwen 记忆引擎中信息密度高、复用面广的基础模型:上层 API(如LongTermMemory.getUserMemByPage,接口清单见 LongTermMemory.md)直接以它为返回类型,下层检索与注入逻辑又以它为数据载体。掌握它的字段语义、默认值与类型体系,是正确使用 openJiuwen 长期记忆能力(用户画像、语义/情景记忆、变量与摘要)的第一步。

  • 人工智能
  • AI Agent
  • Agent 框架
  • 工具调用
  • Agent 工作流
  • RAG
  • MCP Clients
  • 强化学习

【免费下载链接】agent-core-java

openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。

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

相关推荐

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

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

USB Type‑C 接口 EMI 如何设计

USB Type‑C 接口 EMI 设计最佳实践 针对 USB Type‑C 接口&#xff08;尤指带 USB3.x/USB4 SuperSpeed 差分对的版本&#xff09;&#xff0c;EMI 抑制应从屏蔽壳接地、共模噪声抑制、高速差分走线、端口滤波/ESD、电源滤波五个维度系统落实。一、连接器金属壳&#xff08;She…

作者头像 李华
网站建设 2026/10/21 17:31:07

为Agent构建专属网站:用Skills机制提升AI任务可靠性

1. 为什么我要给 Agent 单独做一个网站先说说我做这件事的起因。过去大半年&#xff0c;我一直在折腾各种 Agent 项目&#xff0c;从最简单的任务型助手到稍微复杂一点的多步骤工作流&#xff0c;踩的坑不算少。最让我头疼的不是模型能力不够&#xff0c;而是Agent 在真实任务里…

作者头像 李华
网站建设 2026/10/22 10:59:00

YOLOv8坦克检测实战:自建数据集训练全流程

简介&#xff1a;YoloV8坦克目标检测&#xff08;自建数据集&#xff09;是一份面向目标检测学习者的实战资源&#xff0c;以自采百度图片构建坦克检测数据集&#xff0c;并基于YoloV8完成训练与测试。原始约500张坦克图片经数据增强脚本扩充至近6000张&#xff0c;按比例划分训…

作者头像 李华
网站建设 2026/10/18 18:11:42

怎样挑选护眼优异的学习机?各价位段护眼机型深度解析

当孩子们在家使用电子屏幕的时间日益增多时&#xff0c;家长们探讨频次较高的话题已从“设备性能”转向了“究竟哪款学习机的护眼表现更为优异”。据国家卫健委统计数据显示&#xff0c;预计到 2025 年我国儿童青少年的总体近视率将高达 52.7%&#xff0c;其中小学生比例为 35.…

作者头像 李华
网站建设 2026/10/21 23:44:01

企业级Agent落地实战:从改PPT到核心业务链路的演进路径

1. 从“改PPT”这个梗说起&#xff1a;Agent落地为何总在边缘打转“大厂降价掀起 Agent 狂欢&#xff0c;为什么企业买回去只用来改 PPT&#xff1f;”——这句话我第一次看到的时候&#xff0c;正在帮一个朋友的公司做内部工具选型评估。当时会议室里坐着七八个人&#xff0c;…

作者头像 李华