diff --git a/agents.md b/agents.md index 2bb4a77..4d5823b 100644 --- a/agents.md +++ b/agents.md @@ -98,9 +98,10 @@ - 实现向量生成和相似度检索 4. **会话管理** - - 自动创建 Session(首次输入时) - - 手动创建(/new 命令) - - 消息摘要生成 + - 自动创建 Session(首次输入聊天消息时) + - 手动创建(/new 命令,只是重置 currentSession) + - LLM 生成摘要(文言文风格) + - summary_timeout 配置(默认 30 秒) 5. **UI 优化** - 合并状态显示到单行 @@ -112,7 +113,7 @@ - 合并到 hxclaw 的会话摘要上下文 - AI 同时看到长期记忆和会话摘要 -5. **JSON 导出** +7. **JSON 导出** - 退出时自动导出 - 手动导出 @@ -147,6 +148,21 @@ tts: enabled: false # 全局开关(默认关闭) port: 9876 # mimo-tts daemon 端口 auto: true # AI 回复后自动朗读 + +# 聊天记忆体配置 +memory: + enabled: true # 启用开关 + auto_session: true # 自动创建 Session + auto_export: true # 退出时自动导出 + summary_timeout: 30 # 摘要生成超时(秒) + vector: + api_key: "" # 硅基流动 API Key + base_url: "https://api.siliconflow.cn/v1" + model: "BAAI/bge-m3" + recall: + keywords: ["之前", "聊过", "记得"] + auto_recall: true + similarity_threshold: 0.7 ``` 配置加载优先级: diff --git a/changelog.md b/changelog.md index e80feb9..eb30fce 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,18 @@ ### v0.3.0 (2026-04-27) +- **Session 创建逻辑优化** + - Session 只在用户输入聊天消息时创建 + - /new 命令只重置 currentSession,不立即创建 + - 退出后重新进入算作新会话 + - 配置项:auto_session(默认 true) + +- **LLM 生成摘要** + - Chat 摘要:调用 LLM 生成极简文言文概述 + - Session 摘要:每次对话后用 LLM 精简整合 + - 配置项:summary_timeout(默认 30 秒) + - 容错处理:超时失败回退到简单截断 + - **双记忆系统合并** - 读取 picoclaw 的 MEMORY.md 作为长期记忆 - 合并到 hxclaw 的会话摘要上下文 @@ -105,6 +117,10 @@ - [x] 4 个查询场景(RecallHistory, RecallTopic...) - [x] 三重检测机制 - [x] MongoDB 风格导出 +- [x] Session 创建逻辑优化(输入消息时自动创建) +- [x] /new 命令(只重置 currentSession) +- [x] LLM 生成摘要(文言文风格) +- [x] summary_timeout 配置 --- @@ -114,8 +130,6 @@ - [ ] 命令行参数支持(--theme, --tts 等) - [ ] 多语言支持 -- [ ] /new 命令开始新会话 -- [ ] /memory list|show 命令 - [ ] 命令提示/补全功能(输入 / 显示内置命令列表) --- @@ -137,6 +151,8 @@ - [x] 集成 libSQL 数据库 - [x] 实现独立上下文系统 - [x] UI 状态合并显示 +- [x] LLM 生成摘要(文言文风格) +- [x] Session 自动创建逻辑 --- diff --git a/cmd/hxclaw/internal/config.go b/cmd/hxclaw/internal/config.go index a405954..8ae3339 100644 --- a/cmd/hxclaw/internal/config.go +++ b/cmd/hxclaw/internal/config.go @@ -68,6 +68,8 @@ type MemoryConfig struct { AutoSession bool `yaml:"auto_session"` // AutoExport 退出时自动导出 AutoExport bool `yaml:"auto_export"` + // SummaryTimeout 摘要生成超时时间(秒) + SummaryTimeout int `yaml:"summary_timeout"` // Vector 向量服务配置 Vector VectorConfig `yaml:"vector"` // Recall 检索配置 @@ -121,10 +123,11 @@ var ( Auto: true, }, Memory: MemoryConfig{ - Enabled: true, - DBPath: "", - AutoSession: true, - AutoExport: true, + Enabled: true, + DBPath: "", + AutoSession: true, + AutoExport: true, + SummaryTimeout: 20, Vector: VectorConfig{ APIKey: "", BaseURL: "https://api.siliconflow.cn/v1", @@ -222,6 +225,7 @@ memory: enabled: true auto_session: true auto_export: true + summary_timeout: 30 vector: api_key: "" base_url: "https://api.siliconflow.cn/v1" @@ -302,6 +306,9 @@ func mergeConfig(userCfg, projCfg *Config) *Config { if projCfg.Memory.AutoExport { result.Memory.AutoExport = projCfg.Memory.AutoExport } + if projCfg.Memory.SummaryTimeout > 0 { + result.Memory.SummaryTimeout = projCfg.Memory.SummaryTimeout + } if projCfg.Memory.Vector.APIKey != "" { result.Memory.Vector.APIKey = projCfg.Memory.Vector.APIKey } diff --git a/cmd/hxclaw/internal/memory/db.go b/cmd/hxclaw/internal/memory/db.go index c9979c2..c589589 100644 --- a/cmd/hxclaw/internal/memory/db.go +++ b/cmd/hxclaw/internal/memory/db.go @@ -9,6 +9,7 @@ import ( "github.com/google/uuid" "github.com/hxclaw/hxclaw/cmd/hxclaw/internal" + "github.com/sipeed/picoclaw/pkg/agent" _ "github.com/tursodatabase/libsql-client-go/libsql" ) @@ -18,8 +19,9 @@ type DB struct { } var ( - db *DB - cfg *DBConfig + db *DB + cfg *DBConfig + summaryAgent *agent.AgentLoop ) type DBConfig struct { @@ -43,7 +45,9 @@ func GetDefaultDBPath() string { return getDefaultDBPath() } -func Init(opts ...DBSOption) error { +func Init(agentLoop *agent.AgentLoop, opts ...DBSOption) error { + summaryAgent = agentLoop + memoryCfg := internal.GetProjectConfig().Memory cfg = &DBConfig{ diff --git a/cmd/hxclaw/internal/memory/save.go b/cmd/hxclaw/internal/memory/save.go index 8ae9877..3654b4f 100644 --- a/cmd/hxclaw/internal/memory/save.go +++ b/cmd/hxclaw/internal/memory/save.go @@ -1,6 +1,7 @@ package memory import ( + "context" "fmt" "os" "path/filepath" @@ -14,6 +15,56 @@ var lastContext string var ErrNeedNewSession = fmt.Errorf("需要创建新会话") +func generateChatSummary(userInput, aiReply string) string { + if summaryAgent == nil { + return GenerateSummary(userInput, aiReply) + } + + memoryCfg := internal.GetProjectConfig().Memory + timeout := time.Duration(memoryCfg.SummaryTimeout) * time.Second + if timeout <= 0 { + timeout = 30 * time.Second + } + + prompt := fmt.Sprintf(`用极简文言文概括对话,一句话,只包含最关键信息(如人名、地点、事件、核心结论): +问:%s +答:%s`, userInput, aiReply) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + resp, err := summaryAgent.ProcessDirect(ctx, prompt, "summary:chat") + if err != nil { + return GenerateSummary(userInput, aiReply) + } + return strings.TrimSpace(resp) +} + +func generateSessionSummary(oldSummary, userInput, aiReply string) string { + if summaryAgent == nil { + return GenerateSummary(oldSummary, oldSummary+"\n"+aiReply) + } + + memoryCfg := internal.GetProjectConfig().Memory + timeout := time.Duration(memoryCfg.SummaryTimeout) * time.Second + if timeout <= 0 { + timeout = 30 * time.Second + } + + prompt := fmt.Sprintf(`精简整合以下历史,提取关键信息,去除冗余描述,保留核心要点: +历史:%s +新对话:问%s 答%s`, oldSummary, userInput, aiReply) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + resp, err := summaryAgent.ProcessDirect(ctx, prompt, "summary:session") + if err != nil { + return GenerateSummary(oldSummary, oldSummary+"\n"+aiReply) + } + return strings.TrimSpace(resp) +} + func GetContextPrompt(userInput string) string { db := GetDB() if db == nil { @@ -227,8 +278,16 @@ func SaveChat(userInput, aiReply string, useSessionSummary bool) (int, error) { // 获取或创建 Session session := currentSession + if session == nil && memoryCfg.AutoSession { + // 自动创建 session + newSession, err := CreateNewSession() + if err != nil { + return 0, fmt.Errorf("自动创建会话失败: %v", err) + } + session = newSession + } + if session == nil { - // 如果没有 session,返回错误让用户创建 return 0, ErrNeedNewSession } @@ -243,7 +302,7 @@ func SaveChat(userInput, aiReply string, useSessionSummary bool) (int, error) { // 添加 AI 回复 chat.AddAIReply(aiReply) - chat.Summary = GenerateSummary(userInput, aiReply) + chat.Summary = generateChatSummary(userInput, aiReply) chat.UpdatedAt = time.Now().Unix() // 生成并保存向量 @@ -261,7 +320,7 @@ func SaveChat(userInput, aiReply string, useSessionSummary bool) (int, error) { // 只有普通对话才更新 session summary,recall 查询保持原 summary if useSessionSummary { - session.Summary = GenerateSummary("", session.Summary+"\n"+aiReply) + session.Summary = generateSessionSummary(session.Summary, userInput, aiReply) } session.UpdatedAt = time.Now().Unix() @@ -276,7 +335,11 @@ func SaveChat(userInput, aiReply string, useSessionSummary bool) (int, error) { // 恢复原始 session summary(避免 recall 结果污染) session.Summary = originalSummary - currentSession = session + + // 首次自动创建后赋值 currentSession + if currentSession == nil { + currentSession = session + } return len(session.ChatIDs), nil } diff --git a/cmd/hxclaw/main.go b/cmd/hxclaw/main.go index 955ec31..0c512db 100644 --- a/cmd/hxclaw/main.go +++ b/cmd/hxclaw/main.go @@ -72,7 +72,7 @@ func main() { dbPath = memory.GetDefaultDBPath() } fmt.Printf("初始化记忆体,db_path: %s\n", dbPath) - if err := memory.Init(memory.WithDBPath(dbPath)); err != nil { + if err := memory.Init(agentLoop, memory.WithDBPath(dbPath)); err != nil { fmt.Fprintf(os.Stderr, "警告:初始化记忆体失败: %v,将使用无记忆模式\n", err) } else { fmt.Println("记忆体初始化成功") @@ -435,13 +435,8 @@ func handleTTSCommandSimple(input string) { } func handleNewSessionCommand(rl *internal.Readline, basePrompt string) { - uuid, err := memory.CreateNewSession() - if err != nil { - fmt.Printf("创建新会话失败: %v\n", err) - return - } - fmt.Printf("已创建新会话: %s\n", uuid) currentSession = nil + fmt.Println("已重置会话,输入聊天消息后将创建新会话") } func handleMemoryCommand(input string) { diff --git a/project.config.yml b/project.config.yml index cce7cc5..5582084 100644 --- a/project.config.yml +++ b/project.config.yml @@ -26,6 +26,7 @@ memory: enabled: false auto_session: true auto_export: true + summary_timeout: 30 vector: base_url: "https://api.siliconflow.cn/v1" model: "BAAI/bge-m3"