feat: 增强FAQ搜索功能,支持指定搜索字段(标准问题/相似问法/答案)

This commit is contained in:
wizardchen
2025-12-24 13:11:54 +08:00
parent e45b82e9be
commit 0bbd1450cc
10 changed files with 36 additions and 14 deletions
+1 -1
View File
@@ -139,7 +139,7 @@ func (t *GetDocumentInfoTool) Execute(ctx context.Context, args map[string]inter
ListPagedChunksByKnowledgeID(ctx, t.tenantID, id, &types.Pagination{
Page: 1,
PageSize: 1000,
}, []types.ChunkType{"text"}, "", "", "")
}, []types.ChunkType{"text"}, "", "", "", "")
if err != nil {
mu.Lock()
results[id] = &docInfo{
+1 -1
View File
@@ -1052,7 +1052,7 @@ func (t *KnowledgeSearchTool) formatOutput(
_, total, err := t.chunkService.GetRepository().ListPagedChunksByKnowledgeID(ctx,
t.tenantID, result.KnowledgeID,
&types.Pagination{Page: 1, PageSize: 1},
[]types.ChunkType{types.ChunkTypeText}, "", "", "",
[]types.ChunkType{types.ChunkTypeText}, "", "", "", "",
)
if err != nil {
logger.Warnf(
@@ -117,7 +117,7 @@ func (t *ListKnowledgeChunksTool) Execute(ctx context.Context, args map[string]i
}
chunks, total, err := t.chunkService.GetRepository().ListPagedChunksByKnowledgeID(ctx,
t.tenantID, knowledgeID, pagination, []types.ChunkType{types.ChunkTypeText, types.ChunkTypeFAQ}, "", "", "")
t.tenantID, knowledgeID, pagination, []types.ChunkType{types.ChunkTypeText, types.ChunkTypeFAQ}, "", "", "", "")
if err != nil {
return &types.ToolResult{
Success: false,
+15 -1
View File
@@ -80,6 +80,7 @@ func (r *chunkRepository) ListPagedChunksByKnowledgeID(
chunkType []types.ChunkType,
tagID string,
keyword string,
searchField string,
sortOrder string,
) ([]*types.Chunk, int64, error) {
var chunks []*types.Chunk
@@ -97,7 +98,20 @@ func (r *chunkRepository) ListPagedChunksByKnowledgeID(
}
if keyword != "" {
like := "%" + keyword + "%"
db = db.Where("(content LIKE ? OR metadata::text LIKE ?)", like, like)
switch searchField {
case "standard_question":
// Search only in standard_question field of metadata
db = db.Where("metadata->>'standard_question' ILIKE ?", like)
case "similar_questions":
// Search in similar_questions array of metadata
db = db.Where("metadata->'similar_questions'::text ILIKE ?", like)
case "answers":
// Search in answers array of metadata
db = db.Where("metadata->'answers'::text ILIKE ?", like)
default:
// Search in all fields (content and metadata)
db = db.Where("(content ILIKE ? OR metadata::text ILIKE ?)", like, like)
}
}
return db
}
@@ -337,7 +337,7 @@ func (s *agentService) getKnowledgeBaseInfos(ctx context.Context, kbIDs []string
pageResult, err := s.knowledgeService.ListFAQEntries(ctx, kbID, &types.Pagination{
Page: 1,
PageSize: 10,
}, "", "", "")
}, "", "", "", "")
if err == nil && pageResult != nil {
docCount = int(pageResult.Total)
if entries, ok := pageResult.Data.([]*types.FAQEntry); ok {
+1
View File
@@ -152,6 +152,7 @@ func (s *chunkService) ListPagedChunksByKnowledgeID(ctx context.Context,
"",
"",
"",
"",
)
if err != nil {
logger.ErrorWithFields(ctx, err, map[string]interface{}{
+3 -2
View File
@@ -2549,6 +2549,7 @@ func (s *knowledgeService) CloneChunk(ctx context.Context, src, dst *types.Knowl
"",
"",
"",
"",
)
chunkPage++
if err != nil {
@@ -2643,7 +2644,7 @@ func (s *knowledgeService) CloneChunk(ctx context.Context, src, dst *types.Knowl
// ListFAQEntries lists FAQ entries under a FAQ knowledge base.
func (s *knowledgeService) ListFAQEntries(ctx context.Context,
kbID string, page *types.Pagination, tagID string, keyword string, sortOrder string,
kbID string, page *types.Pagination, tagID string, keyword string, searchField string, sortOrder string,
) (*types.PageResult, error) {
if page == nil {
page = &types.Pagination{}
@@ -2663,7 +2664,7 @@ func (s *knowledgeService) ListFAQEntries(ctx context.Context,
}
chunkType := []types.ChunkType{types.ChunkTypeFAQ}
chunks, total, err := s.chunkRepo.ListPagedChunksByKnowledgeID(
ctx, tenantID, faqKnowledge.ID, page, chunkType, tagID, keyword, sortOrder,
ctx, tenantID, faqKnowledge.ID, page, chunkType, tagID, keyword, searchField, sortOrder,
)
if err != nil {
return nil, err
+9 -7
View File
@@ -28,12 +28,13 @@ func NewFAQHandler(knowledgeService interfaces.KnowledgeService) *FAQHandler {
// @Tags FAQ管理
// @Accept json
// @Produce json
// @Param id path string true "知识库ID"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Param tag_id query string false "标签ID筛选"
// @Param keyword query string false "关键词搜索"
// @Param sort_order query string false "排序方式: asc(按更新时间正序), 默认按更新时间倒序"
// @Param id path string true "知识库ID"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Param tag_id query string false "标签ID筛选"
// @Param keyword query string false "关键词搜索"
// @Param search_field query string false "搜索字段: standard_question(标准问题), similar_questions(相似问法), answers(答案), 默认搜索全部"
// @Param sort_order query string false "排序方式: asc(按更新时间正序), 默认按更新时间倒序"
// @Success 200 {object} map[string]interface{} "FAQ列表"
// @Failure 400 {object} errors.AppError "请求参数错误"
// @Security Bearer
@@ -50,9 +51,10 @@ func (h *FAQHandler) ListEntries(c *gin.Context) {
tagID := secutils.SanitizeForLog(c.Query("tag_id"))
keyword := secutils.SanitizeForLog(c.Query("keyword"))
searchField := secutils.SanitizeForLog(c.Query("search_field"))
sortOrder := secutils.SanitizeForLog(c.Query("sort_order"))
result, err := h.knowledgeService.ListFAQEntries(ctx, secutils.SanitizeForLog(c.Param("id")), &page, tagID, keyword, sortOrder)
result, err := h.knowledgeService.ListFAQEntries(ctx, secutils.SanitizeForLog(c.Param("id")), &page, tagID, keyword, searchField, sortOrder)
if err != nil {
logger.ErrorWithFields(ctx, err, nil)
c.Error(err)
+2
View File
@@ -19,6 +19,7 @@ type ChunkRepository interface {
// ListPagedChunksByKnowledgeID lists paged chunks by knowledge id.
// When tagID is non-empty, results are filtered by tag_id.
// sortOrder: "asc" for time ascending (updated_at ASC), default is time descending (updated_at DESC)
// searchField: specifies which field to search in (for FAQ: "standard_question", "similar_questions", "answers", "" for all)
ListPagedChunksByKnowledgeID(
ctx context.Context,
tenantID uint64,
@@ -27,6 +28,7 @@ type ChunkRepository interface {
chunkType []types.ChunkType,
tagID string,
keyword string,
searchField string,
sortOrder string,
) ([]*types.Chunk, int64, error)
ListChunkByParentID(ctx context.Context, tenantID uint64, parentID string) ([]*types.Chunk, error)
+2
View File
@@ -74,6 +74,7 @@ type KnowledgeService interface {
UpdateImageInfo(ctx context.Context, knowledgeID string, chunkID string, imageInfo string) error
// ListFAQEntries lists FAQ entries under a FAQ knowledge base.
// When tagID is non-empty, results are filtered by tag_id on FAQ chunks.
// searchField: specifies which field to search in ("standard_question", "similar_questions", "answers", "" for all)
// sortOrder: "asc" for time ascending (updated_at ASC), default is time descending (updated_at DESC)
ListFAQEntries(
ctx context.Context,
@@ -81,6 +82,7 @@ type KnowledgeService interface {
page *types.Pagination,
tagID string,
keyword string,
searchField string,
sortOrder string,
) (*types.PageResult, error)
// UpsertFAQEntries imports or appends FAQ entries asynchronously.