feat: 新增FAQ条目答案策略字段,支持'all'和'random'两种模式

This commit is contained in:
wizardchen
2025-12-15 17:22:09 +08:00
committed by lyingbug
parent 8b6731439a
commit de9b6dfd31
3 changed files with 63 additions and 31 deletions
+2
View File
@@ -22,6 +22,7 @@ type FAQEntry struct {
SimilarQuestions []string `json:"similar_questions"`
NegativeQuestions []string `json:"negative_questions"`
Answers []string `json:"answers"`
AnswerStrategy string `json:"answer_strategy"`
IndexMode string `json:"index_mode"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
@@ -36,6 +37,7 @@ type FAQEntryPayload struct {
SimilarQuestions []string `json:"similar_questions,omitempty"`
NegativeQuestions []string `json:"negative_questions,omitempty"`
Answers []string `json:"answers"`
AnswerStrategy *string `json:"answer_strategy,omitempty"`
TagID string `json:"tag_id,omitempty"`
TagName string `json:"tag_name,omitempty"`
IsEnabled *bool `json:"is_enabled,omitempty"`
+17
View File
@@ -3990,6 +3990,11 @@ func (s *knowledgeService) chunkToFAQEntry(chunk *types.Chunk, kb *types.Knowled
if meta == nil {
meta = &types.FAQChunkMetadata{StandardQuestion: chunk.Content}
}
// 默认使用 all 策略
answerStrategy := meta.AnswerStrategy
if answerStrategy == "" {
answerStrategy = types.AnswerStrategyAll
}
entry := &types.FAQEntry{
ID: chunk.ID,
ChunkID: chunk.ID,
@@ -4002,6 +4007,7 @@ func (s *knowledgeService) chunkToFAQEntry(chunk *types.Chunk, kb *types.Knowled
SimilarQuestions: meta.SimilarQuestions,
NegativeQuestions: meta.NegativeQuestions,
Answers: meta.Answers,
AnswerStrategy: answerStrategy,
IndexMode: kb.FAQConfig.IndexMode,
UpdatedAt: chunk.UpdatedAt,
CreatedAt: chunk.CreatedAt,
@@ -4110,11 +4116,22 @@ func (s *knowledgeService) resolveTagID(ctx context.Context, kbID string, payloa
}
func sanitizeFAQEntryPayload(payload *types.FAQEntryPayload) (*types.FAQChunkMetadata, error) {
// 处理 AnswerStrategy,默认为 all
answerStrategy := types.AnswerStrategyAll
if payload.AnswerStrategy != nil && *payload.AnswerStrategy != "" {
switch *payload.AnswerStrategy {
case types.AnswerStrategyAll, types.AnswerStrategyRandom:
answerStrategy = *payload.AnswerStrategy
default:
return nil, werrors.NewBadRequestError("answer_strategy 必须是 'all' 或 'random'")
}
}
meta := &types.FAQChunkMetadata{
StandardQuestion: strings.TrimSpace(payload.StandardQuestion),
SimilarQuestions: payload.SimilarQuestions,
NegativeQuestions: payload.NegativeQuestions,
Answers: payload.Answers,
AnswerStrategy: answerStrategy,
Version: 1,
Source: "faq",
}
+44 -31
View File
@@ -11,12 +11,13 @@ import (
// FAQChunkMetadata 定义 FAQ 条目在 Chunk.Metadata 中的结构
type FAQChunkMetadata struct {
StandardQuestion string `json:"standard_question"`
SimilarQuestions []string `json:"similar_questions,omitempty"`
NegativeQuestions []string `json:"negative_questions,omitempty"`
Answers []string `json:"answers,omitempty"`
Version int `json:"version,omitempty"`
Source string `json:"source,omitempty"`
StandardQuestion string `json:"standard_question"`
SimilarQuestions []string `json:"similar_questions,omitempty"`
NegativeQuestions []string `json:"negative_questions,omitempty"`
Answers []string `json:"answers,omitempty"`
AnswerStrategy AnswerStrategy `json:"answer_strategy,omitempty"`
Version int `json:"version,omitempty"`
Source string `json:"source,omitempty"`
}
// GeneratedQuestion 表示AI生成的单个问题
@@ -162,37 +163,49 @@ func CalculateFAQContentHash(meta *FAQChunkMetadata) string {
return hex.EncodeToString(hash[:])
}
// AnswerStrategy 定义答案返回策略
type AnswerStrategy string
const (
// AnswerStrategyAll 返回所有答案
AnswerStrategyAll AnswerStrategy = "all"
// AnswerStrategyRandom 随机返回一个答案
AnswerStrategyRandom AnswerStrategy = "random"
)
// FAQEntry 表示返回给前端的 FAQ 条目
type FAQEntry struct {
ID string `json:"id"`
ChunkID string `json:"chunk_id"`
KnowledgeID string `json:"knowledge_id"`
KnowledgeBaseID string `json:"knowledge_base_id"`
TagID string `json:"tag_id"`
IsEnabled bool `json:"is_enabled"`
IsRecommended bool `json:"is_recommended"`
StandardQuestion string `json:"standard_question"`
SimilarQuestions []string `json:"similar_questions"`
NegativeQuestions []string `json:"negative_questions"`
Answers []string `json:"answers"`
IndexMode FAQIndexMode `json:"index_mode"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
Score float64 `json:"score,omitempty"`
MatchType MatchType `json:"match_type,omitempty"`
ChunkType ChunkType `json:"chunk_type"`
ID string `json:"id"`
ChunkID string `json:"chunk_id"`
KnowledgeID string `json:"knowledge_id"`
KnowledgeBaseID string `json:"knowledge_base_id"`
TagID string `json:"tag_id"`
IsEnabled bool `json:"is_enabled"`
IsRecommended bool `json:"is_recommended"`
StandardQuestion string `json:"standard_question"`
SimilarQuestions []string `json:"similar_questions"`
NegativeQuestions []string `json:"negative_questions"`
Answers []string `json:"answers"`
AnswerStrategy AnswerStrategy `json:"answer_strategy"`
IndexMode FAQIndexMode `json:"index_mode"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
Score float64 `json:"score,omitempty"`
MatchType MatchType `json:"match_type,omitempty"`
ChunkType ChunkType `json:"chunk_type"`
}
// FAQEntryPayload 用于创建/更新 FAQ 条目的 payload
type FAQEntryPayload struct {
StandardQuestion string `json:"standard_question" binding:"required"`
SimilarQuestions []string `json:"similar_questions"`
NegativeQuestions []string `json:"negative_questions"`
Answers []string `json:"answers" binding:"required"`
TagID string `json:"tag_id"`
TagName string `json:"tag_name"`
IsEnabled *bool `json:"is_enabled,omitempty"`
IsRecommended *bool `json:"is_recommended,omitempty"`
StandardQuestion string `json:"standard_question" binding:"required"`
SimilarQuestions []string `json:"similar_questions"`
NegativeQuestions []string `json:"negative_questions"`
Answers []string `json:"answers" binding:"required"`
AnswerStrategy *AnswerStrategy `json:"answer_strategy,omitempty"`
TagID string `json:"tag_id"`
TagName string `json:"tag_name"`
IsEnabled *bool `json:"is_enabled,omitempty"`
IsRecommended *bool `json:"is_recommended,omitempty"`
}
const (