Memory 模块是 GlyphKeeper 的核心组件,负责维护游戏世界的持久化状态。它旨在解决传统 LLM 应用中的"灾难性遗忘"和"逻辑不一致"问题。
本模块采用了仿生学的双脑架构 (Bicameral Architecture),将游戏记忆分为理性的"左脑"和感性的"右脑":
-
左脑 (Left Brain) - 理性与规则:
- 负责处理结构化数据 (Structured Data)。
- 管理客观的游戏事实,如:位置坐标、物品栏清单、角色属性数值、开关状态。
- 特点:精确、逻辑严密、基于规则。存储在 PostgreSQL 关系型数据库中。
-
右脑 (Right Brain) - 感性与记忆:
- 负责处理非结构化数据 (Unstructured Data)。
- 管理模糊的叙事体验,如:场景的氛围描述、NPC 的过往经历、模组的背景故事、发生的历史事件。
- 特点:模糊、联想丰富、基于语义。存储在基于 LightRAG 的向量/图数据库中。
graph TB
subgraph Agent Layer ["Agent 层"]
Narrator["Narrator 叙事者"]
Archivist["Archivist 档案员"]
RuleKeeper["RuleKeeper 规则守护"]
end
subgraph Service Layer ["服务层 - 对外接口"]
Manager["MemoryManager<br/>对话记忆管理"]
RuleService["RuleService<br/>规则查询服务"]
Bridge["Bridge<br/>数据访问桥接"]
end
subgraph Data Access Layer ["数据访问层"]
Repos["Repositories<br/>(DAO层)"]
RAGEngine["RAG Engine<br/>(LightRAG封装)"]
end
subgraph Storage Layer ["存储层"]
WorldDB[("PostgreSQL<br/>world_* schema<br/>世界数据")]
RulesDB[("PostgreSQL<br/>coc7th_rules schema<br/>规则数据")]
VectorStore[("PGVector + NetworkX<br/>向量/图存储")]
end
Narrator --> Manager
Narrator --> Bridge
Archivist --> Repos
Archivist --> RAGEngine
RuleKeeper --> RuleService
Manager --> RAGEngine
RuleService --> RAGEngine
Bridge --> WorldDB
Repos --> WorldDB
RAGEngine --> VectorStore
RAGEngine --> WorldDB
RAGEngine --> RulesDB
style Manager fill:#e1f5ff
style RuleService fill:#ffe1f5
style Bridge fill:#f5ffe1
Memory 模块提供三个主要的对外接口,各司其职:
职责:管理对话记录的录入、固化和上下文构建
- 文件:manager.py
- 主要功能:
add_dialogue(): 添加对话记录_consolidate(): 定期将对话固化为摘要,存入 RAGbuild_prompt_context(): 为 Narrator 构建检索上下文
- 使用者:Narrator、主流程
- 适用场景:需要处理对话记忆时
职责:提供 COC7th 规则数据的查询接口
- 文件:rule_service.py
- 主要功能:
query_rule(): 查询规则知识库insert_rule_document(): 插入规则文档
- 使用者:RuleKeeper Agent、规则导入脚本
- 特点:使用独立的
coc7th_rulesschema,与世界数据完全隔离 - 适用场景:需要查询游戏规则时
职责:提供通用的、基于字典的数据访问接口,屏蔽 ORM 细节
- 文件:bridge.py
- 主要功能:
read_model(): 读取模型数据(返回字典)queue_model_update(): 将数据修改加入暂存队列commit_model_changes(): 提交所有暂存的修改
- 使用者:各类 Components (如 Health, Dice)
- 特点:支持自动合并同一实体的多次修改,简化事务管理
- 适用场景:组件需要读写游戏世界状态时
save_model_data(): 保存模型数据(创建或更新)transaction_context(): 事务上下文管理器
- 使用者:Components(如 DiceRoller、HealthSystem)、需要直接操作数据库的模块
- 适用场景:需要简单的 CRUD 操作,不想处理 ORM 复杂性时
职责:提供类型安全的 CRUD 接口和业务逻辑封装
- 文件夹:repositories/
- 主要类:
BaseRepository: 通用增删改查基类LocationRepository: 地点数据访问EntityRepository: 实体(NPC/调查员)数据访问InteractableRepository: 交互物数据访问ClueDiscoveryRepository: 线索发现数据访问KnowledgeRepository: 知识注册表数据访问SessionRepository: 游戏会话数据访问InvestigatorProfileRepository: 调查员档案数据访问
- 使用者:Archivist Agent、需要复杂查询的模块
- 适用场景:需要面向对象的数据访问、复杂关联查询时
职责:基于 LightRAG 的语义检索和知识插入
- 文件:RAG_engine.py
- 主要功能:
query(): 执行语义检索(支持 local/global/hybrid/naive 模式)insert(): 插入文档到知识库- 支持多 workspace 隔离(world_* 和 rules)
- 存储后端:
- Vector:PGVector (PostgreSQL)
- KV:PostgreSQL
- Graph:NetworkX
- 使用者:MemoryManager、RuleService、KnowledgeService
- 适用场景:需要语义检索、上下文召回时
- Workspace 隔离:每个世界使用独立 schema(如
world_the_haunting) - 规则数据隔离:规则数据存储在独立的
coc7th_rulesschema - 自动 Schema 切换:通过
search_path实现,由active_world配置控制
物理层 (Physical Layer)
-
Location(地点表):场景及其连接关系id,key,name,base_desc,tags,exits- 关联:
interactables,entities
-
Interactable(交互物表):物品、容器id,key,name,tags,state- 位置互斥:
location_id或carrier_id - 支持状态切换和携带者转移
-
Entity(实体表):NPC、怪物、调查员id,key,name,location_id,tags,stats,attacks- 关联:
location,inventory,dialogue_links,profile - 虚拟装备系统:通过
inventory关联 Interactable
逻辑层 (Logic Layer)
-
InvestigatorProfile(调查员档案):扩展 Entity 的调查员专属信息- 基础信息:
player_name,occupation,age,gender,residence,birthplace - 背景故事:
backstory(JSONB) - 资产描述:
assets_detail - 一对一关联 Entity
- 基础信息:
-
Knowledge(知识注册表):线索的逻辑开关id,rag_key,tags_granted- 指向 LightRAG 中的具体内容
-
ClueDiscovery(线索发现中间层):实现 N:N 映射- 来源:
interactable_id或entity_id(互斥) - 目标:
knowledge_id - 触发条件:
required_check(JSONB) - 情境描述:
discovery_flavor_text
- 来源:
控制层 (Control Layer)
-
GameSession(游戏会话):全局状态管理id,status,scenario_name,time_slot,beat_counteractive_global_tags,investigator_ids,opening
-
Event(事件表):状态转换规则trigger_condition,effect_script
记忆层 (Memory Layer)
-
DialogueRecord(对话记录):原始对话存档investigator_id,turn_number,role,contentis_consolidated: 是否已固化标记
-
MemoryTrace(记忆痕迹):对话摘要索引summary,start_turn,end_turn,tags,importance_score- 连接原始对话与 RAG 检索
存储架构
- Vector Store: PGVector (存储在 PostgreSQL 的
publicschema) - KV Store: PostgreSQL Table
- Graph Store: NetworkX (内存图 + 持久化序列化)
内容类型
- 世界设定 (Semantic Memory): 模组背景、NPC 历史、场景描述
- 游戏事件 (Episodic Memory): 对话摘要、玩家行动、剧情进展
- 规则文档 (Rules Memory): COC7th 规则、判定表、技能说明
LLM 的 Context Window 仅作为"工作记忆",所有的长期状态必须持久化到数据库中。
- 错误做法:让 LLM 记住"玩家有一把钥匙"。
- 正确做法:在
Inventory表中插入一条记录,LLM 需要时查询数据库。
Tag 是连接结构化数据与非结构化叙事的桥梁。
- 结构化:Entity 表中有
tags=["injured"]。 - 非结构化:RAG 检索时,会将
injured作为上下文注入,检索出"受伤后的行为模式"或"痛苦的呻吟声"等描述。
放弃了“物品直接包含线索”的一对一模式,引入 ClueDiscovery 中间层实现多对多映射。
- 复用性:多个物理载体(如尸体、血字)可指向同一个逻辑真相 (
Knowledge)。 - 情境区分:同一个真相,从不同来源获取时,拥有不同的检定难度 (
required_check) 和 发现描述 (discovery_flavor_text)。
from src.memory.database import get_db
from src.memory.repositories.location_repo import LocationRepository
async for session in get_db():
repo = LocationRepository(session)
loc = await repo.get_by_name("Library")
print(f"Location: {loc.name}, Exits: {loc.exits}")from src.memory.episodic_memory import EpisodicMemory
memory = EpisodicMemory()
# 记录事件,并关联相关 Tag
await memory.insert_game_event(
event_text="玩家试图撬开宝箱,但触发了毒针陷阱。",
related_tags=["trap_triggered", "poisoned"]
)# 基于当前情境(如:玩家中毒)检索相关记忆
context = await memory.retrieve_context(
query="我现在感觉如何?",
context_tags=["poisoned"]
)
print(context)
# 可能输出:你感到头晕目眩,伤口处传来阵阵麻痹感... (来自 RAG 检索)