action

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 24, 2025 License: MIT Imports: 17 Imported by: 0

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

View Source
const (
	DefaultMaxTokens    = 2000 // 总 token 预算
	DefaultMaxSummaries = 3    // Summary 最大数量
	DefaultMaxEdges     = 10   // Edge 最大数量
	DefaultMaxEntities  = 5    // Entity 最大数量
	DefaultMaxEpisodes  = 5    // Episode 最大数量

	// token 估算系数(中文约 1.5 字符/token)
	CharsPerToken = 1.5
)

默认预算配置

View Source
const (
	EmbedderName = "ark/doubao-embedding-text-240715"
)
View Source
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 NewBaseAction

func NewBaseAction(name string) *BaseAction

NewBaseAction 创建 BaseAction

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 存储

func (*EpisodeStorageAction) Name

func (a *EpisodeStorageAction) Name() string

Name 返回 action 名称

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 执行实体和关系提取

func (*ExtractionAction) Name

func (a *ExtractionAction) Name() string

Name 返回 action 名称

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 NewMemory

func NewMemory() *Memory

NewMemory 创建 Memory 实例

func (*Memory) Add

Add 从对话中添加记忆 Zep 风格处理流程 (每个 Action 负责自己的持久化): 1. EpisodeStorageAction - 创建 + 存储 Episodes (OpenSearch) 2. ExtractionAction - 提取 + 存储 Entity/Edge (Neo4j) 3. TopicDetectionAction - 检测主题变化 -> 触发 MQ (异步生成摘要)

func (*Memory) Delete

func (m *Memory) Delete(ctx context.Context, id string) error

Delete 删除记忆

func (*Memory) Retrieve

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

func (*RetrievalAction) Name

func (a *RetrievalAction) Name() string

Name 返回 action 名称

type SummaryAction

type SummaryAction struct {
	*BaseAction
	// contains filtered or unexported fields
}

SummaryAction 摘要生成 Action 检测主题变化并生成摘要

func NewSummaryAction

func NewSummaryAction() *SummaryAction

NewSummaryAction 创建 SummaryAction

func (*SummaryAction) Handle

func (a *SummaryAction) Handle(c *domain.AddContext)

Handle 执行摘要生成

func (*SummaryAction) Name

func (a *SummaryAction) Name() string

Name 返回 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 输出

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL