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:
@@ -251,7 +251,7 @@ func (w *ArticleGenerationWorker) handleTaskFailure(ctx context.Context, task te
|
||||
task.TaskType = strings.TrimSpace(task.TaskType)
|
||||
logCtx := generationWorkerTaskLogContext(task, stage, "", "failed", tenantapp.GenerationTaskResultFailure, 0, "")
|
||||
tenantapp.RecordGenerationTaskEvent(tenantapp.GenerationTaskEventFailure, logCtx)
|
||||
tenantapp.LogGenerationTaskWarn(w.logger, "article generation task failed", logCtx, zap.Error(taskErr))
|
||||
tenantapp.LogGenerationTaskWarn(w.logger, "article generation task failed", logCtx, tenantapp.GenerationTaskErrorFields(taskErr)...)
|
||||
var err error
|
||||
switch {
|
||||
case task.TaskType == kolGenerationTaskType && w.kolWorker != nil:
|
||||
|
||||
@@ -333,15 +333,11 @@ func dedupeKolIDs(ids []int64) []int64 {
|
||||
}
|
||||
|
||||
func buildKolKnowledgeQuery(input map[string]interface{}) string {
|
||||
parts := make([]string, 0, 8)
|
||||
if promptName := strings.TrimSpace(kolStringInput(input, "prompt_name")); promptName != "" {
|
||||
parts = append(parts, promptName)
|
||||
}
|
||||
if platformHint := strings.TrimSpace(kolStringInput(input, "platform_hint")); platformHint != "" {
|
||||
parts = append(parts, platformHint)
|
||||
}
|
||||
|
||||
promptName := strings.TrimSpace(kolStringInput(input, "prompt_name"))
|
||||
platformHint := strings.TrimSpace(kolStringInput(input, "platform_hint"))
|
||||
variables, _ := input["variables"].(map[string]interface{})
|
||||
keywords := make([]string, 0)
|
||||
keyPoints := make([]string, 0)
|
||||
if len(variables) > 0 {
|
||||
keys := make([]string, 0, len(variables))
|
||||
for key := range variables {
|
||||
@@ -353,17 +349,41 @@ func buildKolKnowledgeQuery(input map[string]interface{}) string {
|
||||
if valueText == "" {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("%s: %s", key, valueText))
|
||||
switch {
|
||||
case strings.Contains(strings.ToLower(key), "keyword") || strings.Contains(key, "关键词"):
|
||||
keywords = append(keywords, valueText)
|
||||
case strings.Contains(strings.ToLower(key), "brand") || strings.Contains(key, "品牌"):
|
||||
keyPoints = append(keyPoints, fmt.Sprintf("%s: %s", key, valueText))
|
||||
default:
|
||||
keyPoints = append(keyPoints, fmt.Sprintf("%s: %s", key, valueText))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(parts) == 0 {
|
||||
if renderedPrompt := strings.TrimSpace(kolStringInput(input, "rendered_prompt")); renderedPrompt != "" {
|
||||
parts = append(parts, renderedPrompt)
|
||||
renderedPrompt := strings.TrimSpace(kolStringInput(input, "rendered_prompt"))
|
||||
query := tenantapp.BuildKnowledgeQuery(tenantapp.KnowledgeQueryInput{
|
||||
TaskType: firstNonEmptyKolText(platformHint, "KOL 内容生成"),
|
||||
TemplateName: promptName,
|
||||
Title: firstNonEmptyKolText(promptName, renderedPrompt),
|
||||
Topic: firstNonEmptyKolText(promptName, renderedPrompt),
|
||||
PrimaryKeyword: firstNonEmptyKolText(strings.Join(keywords, "、"), promptName),
|
||||
Keywords: keywords,
|
||||
KeyPoints: strings.Join(keyPoints, "\n"),
|
||||
Extra: renderedPrompt,
|
||||
})
|
||||
if strings.TrimSpace(query) != "" {
|
||||
return kolLimitText(query, 2000)
|
||||
}
|
||||
return kolLimitText(renderedPrompt, 2000)
|
||||
}
|
||||
|
||||
func firstNonEmptyKolText(values ...string) string {
|
||||
for _, value := range values {
|
||||
if text := strings.TrimSpace(value); text != "" {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
return kolLimitText(strings.Join(parts, "\n"), 2000)
|
||||
return ""
|
||||
}
|
||||
|
||||
func kolValueString(value interface{}) string {
|
||||
|
||||
Reference in New Issue
Block a user