Files
ragflow/internal/agent/retrievalbridge/enhancer.go
Hz_ a55a438b42 fix(go-agent): finish retrieval component (#17845)
- Prefer canonical `dataset_ids` over legacy `kb_ids` in Canvas
retrieval components.
- Cover selected and explicitly cleared dataset IDs with regression
tests.
- Add cross-language retrieval with dataset-specific embedding and
rerank models.
- Support vector and keyword similarity controls, metadata filtering,
TOC enhancement, and child-chunk expansion.
- Route Canvas retrieval across datasets and memories with compatible
embedding validation.
2026-08-05 15:48:54 +08:00

144 lines
4.0 KiB
Go

//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Package retrievalbridge connects the agent retrieval interfaces to the
// parent service package without making agent/tool import internal/service.
package retrievalbridge
import (
"context"
"fmt"
"ragflow/internal/engine"
"ragflow/internal/entity"
modelModule "ragflow/internal/entity/models"
"ragflow/internal/service"
"ragflow/internal/service/nlp"
)
// Enhancer delegates retrieval query and result enhancement to the existing
// service-layer implementations used by chunk and chat retrieval.
type Enhancer struct {
docEngine engine.DocEngine
metadataSvc *service.MetadataService
}
// NewEnhancer creates an Enhancer for the configured document engine.
func NewEnhancer(docEngine engine.DocEngine, metadataSvc *service.MetadataService) *Enhancer {
if metadataSvc == nil {
metadataSvc = service.NewMetadataService()
}
return &Enhancer{docEngine: docEngine, metadataSvc: metadataSvc}
}
// CrossLanguages translates the query into the configured languages using the
// tenant's default chat model.
func (e *Enhancer) CrossLanguages(
ctx context.Context,
tenantID, query string,
languages []string,
) (string, error) {
return service.CrossLanguages(ctx, tenantID, "", query, languages)
}
// FilterDocuments applies auto, semi-auto, or manual metadata filtering and
// constrains the result by any document scope supplied by upstream tools.
func (e *Enhancer) FilterDocuments(
ctx context.Context,
filter map[string]any,
query string,
chatModel *modelModule.ChatModel,
baseDocIDs []string,
kbIDs []string,
) ([]string, error) {
if e == nil || e.metadataSvc == nil {
return nil, fmt.Errorf("metadata service is not configured")
}
metadata, err := e.metadataSvc.GetFlattedMetaByKBs(ctx, kbIDs)
if err != nil {
return nil, err
}
docIDs, noMatches := service.ApplyMetaDataFilter(
ctx,
filter,
metadata,
query,
chatModel,
baseDocIDs,
kbIDs,
)
if noMatches {
return []string{service.NoMatchDocIDSentinel}, nil
}
return docIDs, nil
}
// LabelQuestion returns tag-based rank features for NLP reranking.
func (e *Enhancer) LabelQuestion(
ctx context.Context,
question string,
kbs []*entity.Knowledgebase,
) map[string]float64 {
if e == nil || e.metadataSvc == nil {
return nil
}
return e.metadataSvc.LabelQuestion(ctx, question, kbs)
}
// EnhanceTOC adds or boosts chunks selected through the document table of
// contents. The service enhancer mutates the supplied kbinfos map.
func (e *Enhancer) EnhanceTOC(
ctx context.Context,
chatModel *modelModule.ChatModel,
tenantIDs, kbIDs []string,
question string,
topN int,
chunks []map[string]any,
) ([]map[string]any, error) {
if e == nil {
return nil, fmt.Errorf("retrieval enhancer is not configured")
}
kbinfos := map[string]any{"chunks": chunks}
enhancer := service.NewTOCEnhancer(
e.docEngine,
chatModel,
tenantIDs,
kbIDs,
question,
topN,
)
if _, err := enhancer.Enhance(ctx, kbinfos); err != nil {
return nil, err
}
enhanced, ok := kbinfos["chunks"].([]map[string]any)
if !ok {
return nil, fmt.Errorf("TOC enhancer returned invalid chunks type %T", kbinfos["chunks"])
}
return enhanced, nil
}
// RetrieveByChildren aggregates child chunks under their parent chunks.
func (e *Enhancer) RetrieveByChildren(
ctx context.Context,
chunks []map[string]any,
tenantIDs []string,
) []map[string]any {
if e == nil || e.docEngine == nil {
return chunks
}
return nlp.RetrievalByChildren(chunks, tenantIDs, e.docEngine, ctx)
}