feat(knowledge): multi-query retrieval with LLM query rewrite
Add a shared structured query builder (knowledge_query.go) and switch all generation paths to it, so retrieval queries carry task intent (type, brand, region, keywords, key points) instead of a raw prompt. ResolveContext now rewrites the query into multiple sub-questions via the URL-markdown model, embeds and searches each, and merges/dedupes candidates before rerank; falls back to parsed fallback questions when rewrite is unavailable or returns too few. Resolve logs gain query list, count, and rewrite stage/model for observability. - knowledge_query.go/_test.go: BuildKnowledgeQuery + intent normalization - knowledge_service.go: per-query embed/search loop, query rewrite, logs - template_prompt/template_service/prompt_generate/article_imitation/ kol_generation_worker: adopt the shared query builder - generation_observability: richer task error logging
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/geo-platform/tenant-api/internal/shared/response"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -91,6 +92,34 @@ func TestGenerationTaskMetricsRecordsEventsAndPrometheus(t *testing.T) {
|
||||
assert.True(t, strings.HasSuffix(lastEventLine, " 1"), lastEventLine)
|
||||
}
|
||||
|
||||
func TestFormatGenerationFailureKeepsAppErrorBriefForUI(t *testing.T) {
|
||||
err := response.ErrServiceUnavailable(50353, "embedding_failed", "request siliconflow: timeout")
|
||||
|
||||
got := formatGenerationFailure("knowledge_resolve", err)
|
||||
|
||||
assert.Equal(t, "知识库检索失败 [knowledge_resolve]: embedding_failed", got)
|
||||
}
|
||||
|
||||
func TestGenerationTaskErrorFieldsIncludesAppErrorDetailForLogs(t *testing.T) {
|
||||
err := response.ErrServiceUnavailable(50353, "embedding_failed", "request siliconflow: timeout")
|
||||
|
||||
fields := GenerationTaskErrorFields(err)
|
||||
values := map[string]any{}
|
||||
for _, field := range fields {
|
||||
switch {
|
||||
case field.String != "":
|
||||
values[field.Key] = field.String
|
||||
case field.Integer != 0:
|
||||
values[field.Key] = int(field.Integer)
|
||||
}
|
||||
}
|
||||
|
||||
assert.Equal(t, "embedding_failed", values["error_message"])
|
||||
assert.Equal(t, "request siliconflow: timeout", values["error_detail"])
|
||||
assert.Equal(t, 50353, values["error_code"])
|
||||
assert.Equal(t, 503, values["http_status"])
|
||||
}
|
||||
|
||||
func findPrometheusMetricLine(output, metricName string) string {
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
if strings.HasPrefix(line, metricName+"{") || strings.HasPrefix(line, metricName+" ") {
|
||||
|
||||
Reference in New Issue
Block a user