package subsession import ( "context" "fmt" "strings" "time" "git.yeij.top/AskaEth/Cyrene/ai-core/internal/model" "git.yeij.top/AskaEth/Cyrene/ai-core/internal/rag" "git.yeij.top/AskaEth/Cyrene/pkg/logger" ) // KnowledgeProvider searches the knowledge base for relevant information. type KnowledgeProvider struct { retriever *rag.Retriever } // NewKnowledgeProvider creates a knowledge subsession provider. func NewKnowledgeProvider(retriever *rag.Retriever) *KnowledgeProvider { return &KnowledgeProvider{retriever: retriever} } func (p *KnowledgeProvider) Type() model.SubSessionType { return model.SubSessionKnowledge } // knowledgeKeywords are trigger words from _index.md. Only run expensive embedding search if message matches. var knowledgeKeywords = []string{ "翁法罗斯", "泰坦", "城邦", "黑潮", "帝皇权杖", "黄金裔", "白厄", "阿格莱雅", "缇宝", "万敌", "那刻夏", "遐蝶", "风堇", "赛飞儿", "海瑟音", "刻律德菈", "哀丽秘榭", "昔涟", "星神", "浮黎", "轮回", "始源命途", "无漏净子", "剧情", "结局", "逐火", "盗火", "火种", "奥赫玛", "来古士", "世界观", "设定", "哲学", "浪漫", "哀怜", "有瑕", } func (p *KnowledgeProvider) CanHandle(_ context.Context, intent *model.IntentResult, userMessage string) bool { if intent == nil { return true } switch intent.Primary { case "knowledge", "technical", "how_to", "factual", "research": return true case "chat": // 仅当消息包含知识库相关关键词时才触发检索,避免每次聊天都跑 embedding msg := strings.ToLower(userMessage) for _, kw := range knowledgeKeywords { if strings.Contains(msg, strings.ToLower(kw)) { return true } } return false } return true } func (p *KnowledgeProvider) Priority() int { return 3 } func (p *KnowledgeProvider) Timeout() time.Duration { return 15 * time.Second } func (p *KnowledgeProvider) CreateContext(ctx context.Context, params CreateContextParams) ([]model.LLMMessage, error) { return []model.LLMMessage{ {Role: model.RoleSystem, Content: "知识库检索子会话"}, {Role: model.RoleUser, Content: params.UserMessage}, }, nil } func (p *KnowledgeProvider) Execute(ctx context.Context, subCtx []model.LLMMessage) (*model.SubSessionResult, error) { userMessage := "" for i := len(subCtx) - 1; i >= 0; i-- { if subCtx[i].Role == model.RoleUser { userMessage = subCtx[i].Content break } } if userMessage == "" { return nil, fmt.Errorf("无法提取用户消息") } result := &model.SubSessionResult{ Type: model.SubSessionKnowledge, Confidence: 0, } if p.retriever == nil { result.Summary = "(知识库未就绪)" return result, nil } retrieval, err := p.retriever.Retrieve(ctx, userMessage, 3) if err != nil { logger.Printf("[knowledge-subsession] 知识检索失败: %v", err) result.Error = fmt.Sprintf("检索失败: %v", err) result.Summary = "(知识库检索失败)" return result, nil } if len(retrieval.Results) == 0 { result.Summary = "(未找到相关知识)" return result, nil } result.Summary = retrieval.Summary result.Confidence = 0.6 logger.Printf("[knowledge-subsession] 完成: 找到 %d 条知识", len(retrieval.Results)) return result, nil }