- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
导读
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 键名 | 默认值 | 说明 |
|---|---|---|---|---|
memId | String | mem_id | "" | 记忆的唯一标识(memory id),由记忆引擎在存储时分配 |
content | String | content | "" | 记忆正文内容 |
type | MemoryType | type | MemoryType.USER_PROFILE | 记忆类型枚举 |
timestamp | ZonedDateTime | timestamp | null | 记忆产生的时间戳 |
值得注意的细节(见 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_MEMORY | user_profile | 用户画像分片记忆 |
USER_PROFILE | user_profile | 用户画像记忆(与FRAGMENT_MEMORY共用同一底层值) |
SEMANTIC_MEMORY | semantic_memory | 语义记忆 |
EPISODIC_MEMORY | episodic_memory | 情景记忆 |
VARIABLE | variable | 变量记忆 |
SUMMARY | summary | 摘要记忆 |
UNKNOWN | unknown | 未知/未识别类型 |
枚举提供了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能力。
相关推荐
openJiuwen Agent 长期记忆引擎实践指南:openjiuwen.core.memory 模块全解析
openJiuwen Agent 长期记忆引擎实践指南:openjiuwen.core.memory 模块全解析 openjiuwen.core.memory
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen 记忆引擎(LongTermMemory)实战指南:配置、读写、检索与外部记忆接入
openJiuwen 记忆引擎(LongTermMemory)实战指南:配置、读写、检索与外部记忆接入 导读 本篇文章基于 openJiuwen agent c
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习DLSS Swapper:9 种 DLL、8 个游戏库,不更新游戏也能切换缩放版本
DLSS Swapper:9 种 DLL、8 个游戏库,不更新游戏也能切换缩放版本 如果你的游戏还停在上一代 DLSS,而新版早就发布,你又不想等厂商推送补丁、
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考