Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
86 lines
2.6 KiB
Go
86 lines
2.6 KiB
Go
package chatpipeline
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/Tencent/WeKnora/internal/searchutil"
|
|
"github.com/Tencent/WeKnora/internal/types"
|
|
)
|
|
|
|
// filterHistoryResults retrieves history references and filters them by
|
|
// textual similarity to the current query. Only references that are above
|
|
// a Jaccard similarity threshold are kept, and their scores are discounted
|
|
// to reflect that they were not directly retrieved for the current query.
|
|
// Results already present in currentResults (by chunk ID) are excluded.
|
|
func filterHistoryResults(
|
|
ctx context.Context,
|
|
chatManage *types.ChatManage,
|
|
currentResults []*types.SearchResult,
|
|
) []*types.SearchResult {
|
|
const (
|
|
// minSimilarity is the minimum Jaccard similarity between the current
|
|
// query and a history chunk's content for it to be injected.
|
|
minSimilarity = 0.15
|
|
// historyScoreDiscount reduces the original score of history results
|
|
// to rank them below freshly-retrieved results of similar relevance.
|
|
historyScoreDiscount = 0.6
|
|
// maxHistoryResults caps the number of history results injected to
|
|
// avoid overwhelming the context with stale references.
|
|
maxHistoryResults = 3
|
|
)
|
|
|
|
raw := getSearchResultFromHistory(chatManage)
|
|
if len(raw) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Build a set of chunk IDs already in current results for fast dedup
|
|
existingIDs := make(map[string]struct{}, len(currentResults))
|
|
for _, r := range currentResults {
|
|
existingIDs[r.ID] = struct{}{}
|
|
}
|
|
|
|
// Use RewriteQuery if available (it's the cleaned-up retrieval query),
|
|
// otherwise fall back to the original query.
|
|
query := chatManage.RewriteQuery
|
|
if query == "" {
|
|
query = chatManage.Query
|
|
}
|
|
queryTokens := searchutil.TokenizeSimple(query)
|
|
|
|
var filtered []*types.SearchResult
|
|
for _, r := range raw {
|
|
if _, exists := existingIDs[r.ID]; exists {
|
|
continue
|
|
}
|
|
contentTokens := searchutil.TokenizeSimple(r.Content)
|
|
sim := searchutil.Jaccard(queryTokens, contentTokens)
|
|
if sim < minSimilarity {
|
|
pipelineInfo(ctx, "Merge", "history_filter_drop", map[string]interface{}{
|
|
"chunk_id": r.ID,
|
|
"similarity": sim,
|
|
})
|
|
continue
|
|
}
|
|
r.MatchType = types.MatchTypeHistory
|
|
r.Score = r.Score * historyScoreDiscount
|
|
r.Metadata = ensureMetadata(r.Metadata)
|
|
r.Metadata["history_similarity"] = strings.TrimRight(strings.TrimRight(
|
|
fmt.Sprintf("%.4f", sim), "0"), ".")
|
|
filtered = append(filtered, r)
|
|
|
|
pipelineInfo(ctx, "Merge", "history_filter_keep", map[string]interface{}{
|
|
"chunk_id": r.ID,
|
|
"similarity": sim,
|
|
"new_score": r.Score,
|
|
})
|
|
|
|
if len(filtered) >= maxHistoryResults {
|
|
break
|
|
}
|
|
}
|
|
return filtered
|
|
}
|