feat(tenant): inject brand description context into every generation path
Include the current brand description in template, custom, imitation, and KOL article-generation prompts while bounding prompt growth. - Add a shared brand-context builder that resolves the current brand, compacts long descriptions, and caps rendered output at 2000 runes. - Snapshot a structured brand prompt context on queued tasks so old jobs stay reproducible and retries stay stable. - Route brand-profile facts through the existing typed fact guard so founding dates and year counts get the same pre-persistence validation as RAG facts, with brand facts outranking conflicting RAG facts. - Fix the KOL creator to attach the brand scope its worker consumes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,15 +39,16 @@ type PromptRuleGenerationService struct {
|
||||
}
|
||||
|
||||
type promptRuleGenerationJob struct {
|
||||
OperatorID int64
|
||||
TenantID int64
|
||||
ArticleID int64
|
||||
TaskID int64
|
||||
ReservationID int64
|
||||
Prompt string
|
||||
InputParams map[string]interface{}
|
||||
InitialTitle string
|
||||
WebSearch llm.WebSearchOptions
|
||||
OperatorID int64
|
||||
TenantID int64
|
||||
ArticleID int64
|
||||
TaskID int64
|
||||
ReservationID int64
|
||||
Prompt string
|
||||
InputParams map[string]interface{}
|
||||
InitialTitle string
|
||||
WebSearch llm.WebSearchOptions
|
||||
KnowledgeFactConstraints []KnowledgeFactConstraint
|
||||
}
|
||||
|
||||
type GenerateFromRuleRequest struct {
|
||||
@@ -282,6 +283,10 @@ func (s *PromptRuleGenerationService) enqueuePromptRuleGeneration(ctx context.Co
|
||||
if rule.Status != "enabled" {
|
||||
return nil, response.ErrBadRequest(40017, "prompt_rule_disabled", "prompt rule is disabled")
|
||||
}
|
||||
brandPromptContext, err := loadBrandPromptContext(ctx, s.pool, input.TenantID, *input.BrandID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extra := input.ExtraParams
|
||||
generationMode := strings.TrimSpace(extractString(extra, "generation_mode"))
|
||||
@@ -346,6 +351,7 @@ func (s *PromptRuleGenerationService) enqueuePromptRuleGeneration(ctx context.Co
|
||||
inputParams["knowledge_group_ids"] = rule.KnowledgeGroupIDs
|
||||
}
|
||||
inputParams = attachPromptRuleSnapshot(inputParams, rule)
|
||||
inputParams = attachBrandPromptContext(inputParams, brandPromptContext)
|
||||
|
||||
knowledgePrompt := ""
|
||||
if len(rule.KnowledgeGroupIDs) > 0 {
|
||||
@@ -363,6 +369,7 @@ func (s *PromptRuleGenerationService) enqueuePromptRuleGeneration(ctx context.Co
|
||||
return nil, resolveErr
|
||||
}
|
||||
knowledgePrompt = s.knowledge.RenderPromptSection(knowledgeContext)
|
||||
inputParams = attachKnowledgeFactConstraints(inputParams, knowledgeContext.FactConstraints)
|
||||
if knowledgePrompt != "" {
|
||||
inputParams[generationPayloadKnowledgePrompt] = knowledgePrompt
|
||||
}
|
||||
@@ -559,7 +566,7 @@ func (s *PromptRuleGenerationService) executeGeneration(ctx context.Context, job
|
||||
req.WebSearch = &job.WebSearch
|
||||
}
|
||||
|
||||
result, err := s.llm.Generate(ctx, req, func(delta string) {
|
||||
result, err := GenerateArticleWithKnowledgeFactGuard(ctx, s.llm, req, job.KnowledgeFactConstraints, func(delta string) {
|
||||
if runtimeCfg.StreamEnabled && s.streams != nil && delta != "" {
|
||||
s.streams.AppendDelta(job.ArticleID, job.TaskID, title, delta)
|
||||
}
|
||||
@@ -838,6 +845,9 @@ func buildPromptRuleGenerationPrompt(rule *promptRuleGenerationRecord, params ma
|
||||
if len(supplements) > 0 {
|
||||
sections = append(sections, prompts.PromptRuleSupplementSection(supplements))
|
||||
}
|
||||
if brandPrompt := RenderBrandPromptContext(extractBrandPromptContext(params)); brandPrompt != "" {
|
||||
sections = append(sections, brandPrompt)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(knowledgePrompt) != "" {
|
||||
sections = append(sections, knowledgePrompt)
|
||||
|
||||
Reference in New Issue
Block a user