Documentation
¶
Overview ¶
Package action 实现记忆系统的核心操作。
架构概述 (Zep 风格三层子图模型) ¶
记忆系统采用 Zep/Graphiti 风格的三层子图模型,通过 Action Chain 模式处理记忆的写入和检索。
┌─────────────────────────────────────────────────────────────┐
│ Memory │
│ 统一入口,协调各 Action 的执行 │
└─────────────────────────────────────────────────────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Add │ │ Retrieve │
│ Flow │ │ Flow │
└──────────┘ └──────────┘
三层子图模型 ¶
┌─────────────────────────────────────────────────────────────┐ │ Three-Layer Subgraph │ │ │ │ Layer 3: Summary (主题摘要) │ │ ▲ │ │ Layer 2: Entity + Edge (实体 + 关系) │ │ ▲ │ │ Layer 1: Episode (原始对话) │ │ │ └─────────────────────────────────────────────────────────────┘
数据类型 ¶
Episode: 原始对话记录 (Layer 1)
存储每条对话消息 (role + content)
生成 embedding 用于向量检索
生成 topic 用于主题检测
生成 topic_embedding 用于主题相似度计算
存储在 OpenSearch
Entity: 实体节点 (Layer 2)
从对话中提取的实体 (人物、地点、事物、事件等)
存储在 Neo4j
Edge: 关系边 (Layer 2)
实体间的关系 (如: 喜欢、认识、住在)
包含 fact 字段描述事实
支持双时间轴 (ValidAt/InvalidAt)
存储在 Neo4j
Summary: 主题摘要 (Layer 3)
检测到主题变化时生成的对话摘要
基于 TopicEmbedding 相似度检测主题变化
存储在 OpenSearch (向量检索)
数据流 ¶
## Add 流程 (写入)
对话消息
│
▼
┌─────────────────────────────────────────────────────────┐
│ EpisodeStorageAction │
│ - 将每条消息转换为 Episode │
│ - 生成 embedding │
│ - 生成 topic (LLM) │
│ - 生成 topic_embedding │
│ - 存储到 OpenSearch │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ ExtractionAction │
│ - LLM 提取 Entity (实体) │
│ - LLM 提取 Edge (关系三元组) │
│ - 存储到 Neo4j │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ SummaryAction │
│ - 计算 TopicEmbedding 相似度 │
│ - 检测主题变化 (相似度 < 阈值) │
│ - 生成对话摘要 (LLM) │
│ - 存储到 OpenSearch │
└─────────────────────────────────────────────────────────┘
## Retrieve 流程 (检索)
查询文本
│
▼
┌─────────────────────────────────────────────────────────┐
│ RetrievalAction │
│ - 生成查询 embedding │
│ - 向量检索 Episodes (OpenSearch) │
│ - 向量检索 Entities (Neo4j) │
│ - 向量检索 Summaries (OpenSearch) │
│ - 图遍历扩展相关 Entities/Edges │
└─────────────────────────────────────────────────────────┘
│
▼
格式化为 MemoryContext (用于 LLM Prompt)
Action 类型 ¶
## EpisodeStorageAction
将原始对话存储为 Episode:
- 输入:AddContext.Messages (对话消息列表)
- 输出:AddContext.Episodes (Episode 列表)
- 功能:
- 为每条消息生成 ID、embedding、时间戳
- 调用 LLM 生成 topic (2-4 字主题标签)
- 生成 topic_embedding 用于主题相似度计算
## ExtractionAction
从对话中提取实体和关系:
- 输入:AddContext.Messages (对话消息)
- 输出:AddContext.Entities, AddContext.Edges
- 功能:调用 LLM 提取实体 (Entity) 和关系 (Edge)
- 实体类型:person, place, thing, event, emotion, activity
## SummaryAction
检测主题变化并生成摘要:
- 输入:AddContext.Episodes
- 输出:AddContext.Summaries
- 功能:
- 加载历史 user Episode
- 计算 TopicEmbedding 余弦相似度
- 相似度 < 阈值时触发摘要生成
- 调用 LLM 生成对话摘要
- 存储到 OpenSearch
## RetrievalAction
混合检索相关记忆:
- 输入:RecallContext.Query (查询文本)
- 输出:RecallContext.Episodes, Entities, Edges, Summaries
- 检索策略:
- Episodes: 向量相似度检索
- Entities: 名称匹配 + 图遍历
- Summaries: 向量相似度检索
- Edges: 通过关联实体获取
- 可选:MaxHops 参数控制图遍历深度
BaseAction 公共能力 ¶
BaseAction 提供所有 Action 的公共方法:
- Generate: 调用 LLM 生成内容,自动记录 token 使用量
- GenEmbedding: 生成文本向量表示
- CosineSimilarity: 计算向量余弦相似度
- DocToEpisode: 将存储文档转换为 Episode 结构
LLM 输出类型 ¶
- TopicResult: topic prompt 输出 (定义在 episode.go)
- SummaryResult: summary prompt 输出 (定义在 summary.go)
- ExtractionResult: extraction prompt 输出 (定义在 extraction.go)
存储后端 ¶
- OpenSearch: Episode/Summary 向量存储,支持混合检索 (向量 + BM25)
- Neo4j: Entity/Edge 图存储,支持图遍历查询
使用示例 ¶
// 创建 Memory 实例
mem := action.NewMemory()
// 从对话添加记忆
addResp, err := mem.Add(ctx, &domain.AddRequest{
AgentID: "jarvis",
UserID: "user-123",
SessionID: "session-456",
Messages: []domain.Message{
{Role: "user", Name: "阿信", Content: "我今天去了星巴克"},
{Role: "assistant", Name: "贾维斯", Content: "星巴克的咖啡怎么样?"},
},
})
// addResp.Episodes: 2 条原始对话 (含 topic)
// addResp.Entities: 提取的实体 (阿信, 星巴克)
// addResp.Edges: 提取的关系 (阿信 -[去过]-> 星巴克)
// addResp.Summaries: 主题变化时生成的摘要
// 检索相关记忆
retResp, err := mem.Retrieve(ctx, &domain.RetrieveRequest{
AgentID: "jarvis",
UserID: "user-123",
Query: "用户喜欢喝什么",
Options: domain.RetrieveOptions{
IncludeEpisodes: true,
IncludeEntities: true,
IncludeEdges: true,
IncludeSummaries: true,
MaxHops: 2,
},
})
// 获取格式化的记忆上下文 (用于 LLM Prompt)
memoryContext := retResp.MemoryContext
Index ¶
- Constants
- func FormatMemoryContext(c *domain.RecallContext) string
- type BaseAction
- func (b *BaseAction) CosineSimilarity(vec1, vec2 []float32) float64
- func (b *BaseAction) DocToEdge(doc map[string]any) *domain.Edge
- func (b *BaseAction) DocToEntity(doc map[string]any) *domain.Entity
- func (b *BaseAction) DocToEpisode(doc map[string]any) *domain.Episode
- func (b *BaseAction) DocToSummary(doc map[string]any) *domain.Summary
- func (b *BaseAction) GenEmbedding(ctx context.Context, embedderName, text string) ([]float32, error)
- func (b *BaseAction) Generate(c *domain.AddContext, promptName string, input map[string]any, output any) error
- type EpisodeStorageAction
- type ExtractedEntity
- type ExtractedRelation
- type ExtractionAction
- type ExtractionResult
- type Memory
- type RetrievalAction
- type SummaryAction
- type SummaryResult
- type TopicResult
Constants ¶
const ( DefaultMaxTokens = 2000 // 总 token 预算 DefaultMaxSummaries = 3 // Summary 最大数量 DefaultMaxEdges = 10 // Edge 最大数量 DefaultMaxEntities = 5 // Entity 最大数量 DefaultMaxEpisodes = 5 // Episode 最大数量 // token 估算系数(中文约 1.5 字符/token) CharsPerToken = 1.5 )
默认预算配置
const (
EmbedderName = "ark/doubao-embedding-text-240715"
)
const (
LabelEntity = "Entity"
)
Variables ¶
This section is empty.
Functions ¶
func FormatMemoryContext ¶
func FormatMemoryContext(c *domain.RecallContext) string
FormatMemoryContext 将检索结果格式化为 LLM prompt
Types ¶
type BaseAction ¶
type BaseAction struct {
// contains filtered or unexported fields
}
BaseAction 提供 Action 的公共能力
func (*BaseAction) CosineSimilarity ¶
func (b *BaseAction) CosineSimilarity(vec1, vec2 []float32) float64
CosineSimilarity 计算两个向量的余弦相似度
func (*BaseAction) DocToEdge ¶
func (b *BaseAction) DocToEdge(doc map[string]any) *domain.Edge
DocToEdge 将 map 转换为 Edge
func (*BaseAction) DocToEntity ¶
func (b *BaseAction) DocToEntity(doc map[string]any) *domain.Entity
DocToEntity 将 map 转换为 Entity
func (*BaseAction) DocToEpisode ¶
func (b *BaseAction) DocToEpisode(doc map[string]any) *domain.Episode
DocToEpisode 将 map 转换为 Episode
func (*BaseAction) DocToSummary ¶
func (b *BaseAction) DocToSummary(doc map[string]any) *domain.Summary
DocToSummary 将 map 转换为 Summary
func (*BaseAction) GenEmbedding ¶
func (b *BaseAction) GenEmbedding(ctx context.Context, embedderName, text string) ([]float32, error)
GenEmbedding 生成文本的向量表示
func (*BaseAction) Generate ¶
func (b *BaseAction) Generate(c *domain.AddContext, promptName string, input map[string]any, output any) error
Generate 调用 LLM 生成内容
type EpisodeStorageAction ¶
type EpisodeStorageAction struct {
*BaseAction
// contains filtered or unexported fields
}
EpisodeStorageAction 将原始对话存储为 Episode
func NewEpisodeStorageAction ¶
func NewEpisodeStorageAction() *EpisodeStorageAction
NewEpisodeStorageAction 创建 EpisodeStorageAction
func (*EpisodeStorageAction) Handle ¶
func (a *EpisodeStorageAction) Handle(c *domain.AddContext)
Handle 执行 Episode 存储
type ExtractedEntity ¶
type ExtractedEntity struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
}
ExtractedEntity LLM 提取的实体
type ExtractedRelation ¶
type ExtractedRelation struct {
Subject string `json:"subject"` // 主体实体名
Predicate string `json:"predicate"` // 关系
Object string `json:"object"` // 客体实体名
Fact string `json:"fact"` // 事实描述
}
ExtractedRelation LLM 提取的关系
type ExtractionAction ¶
type ExtractionAction struct {
*BaseAction
// contains filtered or unexported fields
}
ExtractionAction 从对话中提取 Entity 和 Edge
func NewExtractionAction ¶
func NewExtractionAction() *ExtractionAction
NewExtractionAction 创建 ExtractionAction
func (*ExtractionAction) Handle ¶
func (a *ExtractionAction) Handle(c *domain.AddContext)
Handle 执行实体和关系提取
type ExtractionResult ¶
type ExtractionResult struct {
Entities []ExtractedEntity `json:"entities"`
Relations []ExtractedRelation `json:"relations"`
}
ExtractionResult LLM 提取结果
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory 统一的记忆操作入口
func (*Memory) Add ¶
func (m *Memory) Add(ctx context.Context, req *domain.AddRequest) (*domain.AddResponse, error)
Add 从对话中添加记忆 Zep 风格处理流程 (每个 Action 负责自己的持久化): 1. EpisodeStorageAction - 创建 + 存储 Episodes (OpenSearch) 2. ExtractionAction - 提取 + 存储 Entity/Edge (Neo4j) 3. TopicDetectionAction - 检测主题变化 -> 触发 MQ (异步生成摘要)
func (*Memory) Retrieve ¶
func (m *Memory) Retrieve(ctx context.Context, req *domain.RetrieveRequest) (*domain.RetrieveResponse, error)
Retrieve 检索相关记忆 支持向量检索 + 图遍历的混合检索
type RetrievalAction ¶
type RetrievalAction struct {
*BaseAction
// contains filtered or unexported fields
}
RetrievalAction 检索相关记忆 支持向量检索 + 图遍历的混合检索
func NewRetrievalAction ¶
func NewRetrievalAction() *RetrievalAction
NewRetrievalAction 创建 RetrievalAction
func (*RetrievalAction) HandleRecall ¶
func (a *RetrievalAction) HandleRecall(c *domain.RecallContext)
HandleRecall 执行记忆检索 按优先级检索:Summary > Edge > Entity > Episode
type SummaryAction ¶
type SummaryAction struct {
*BaseAction
// contains filtered or unexported fields
}
SummaryAction 摘要生成 Action 检测主题变化并生成摘要
type SummaryResult ¶
type SummaryResult struct {
Content string `json:"content"`
}
SummaryResult summary prompt 输出
type TopicResult ¶
type TopicResult struct {
Topic string `json:"topic"`
}
TopicResult topic prompt 输出