feat: 实现 LLM 文言文摘要生成,优化 Session 创建逻辑
Some checks failed
Release / build (push) Failing after 3h11m18s
Some checks failed
Release / build (push) Failing after 3h11m18s
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user