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:
@@ -287,6 +287,10 @@ func (s *TemplateService) Generate(ctx context.Context, templateID int64, req Ge
|
||||
if err := s.llm.Validate(); err != nil {
|
||||
return nil, response.ErrServiceUnavailable(50311, "llm_unavailable", err.Error())
|
||||
}
|
||||
brandPromptContext, err := loadBrandPromptContext(ctx, s.pool, actor.TenantID, brandID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initialTitle := resolveArticleTitle(req.InputParams, "")
|
||||
wizardStateJSON, err := json.Marshal(normalizeWizardState(req.WizardState, wizardStateCurrentStep(req.WizardState)))
|
||||
@@ -300,11 +304,13 @@ func (s *TemplateService) Generate(ctx context.Context, templateID int64, req Ge
|
||||
}
|
||||
|
||||
taskInputParams := cloneInputParams(req.InputParams)
|
||||
taskInputParams["brand_id"] = brandID
|
||||
taskInputParams["enable_web_search"] = req.EnableWebSearch
|
||||
if req.WebSearchLimit != nil {
|
||||
taskInputParams["web_search_limit"] = *req.WebSearchLimit
|
||||
}
|
||||
taskInputParams = attachTemplateSnapshot(taskInputParams, templateRecord)
|
||||
taskInputParams = attachBrandPromptContext(taskInputParams, brandPromptContext)
|
||||
inputJSON, _ := json.Marshal(taskInputParams)
|
||||
|
||||
tx, err := s.pool.Begin(ctx)
|
||||
@@ -480,8 +486,16 @@ func (s *TemplateService) executeGeneration(ctx context.Context, job generationJ
|
||||
}
|
||||
RecordGenerationTaskEvent(GenerationTaskEventTransition, generationJobLogContext(job, "task_status_running", "", GenerationTaskStatusRunning, GenerationTaskResultSuccess))
|
||||
LogGenerationTaskInfo(s.logger, "article generation task marked running", generationJobLogContext(job, "task_status_running", "", GenerationTaskStatusRunning, GenerationTaskResultSuccess))
|
||||
brandID, brandPromptContext, err := ResolveGenerationBrandPromptContext(ctx, s.pool, job.TenantID, job.ArticleID, job.Params)
|
||||
if err != nil {
|
||||
s.failGeneration(ctx, job, title, "brand_context_load", err)
|
||||
return
|
||||
}
|
||||
job.Params["brand_id"] = brandID
|
||||
job.Params = attachBrandPromptContext(job.Params, brandPromptContext)
|
||||
|
||||
knowledgePrompt := ""
|
||||
var knowledgeFactConstraints []KnowledgeFactConstraint
|
||||
if knowledgeGroupIDs := extractKnowledgeGroupIDs(job.Params["knowledge_group_ids"]); len(knowledgeGroupIDs) > 0 {
|
||||
if s.knowledge == nil {
|
||||
s.failGeneration(ctx, job, title, "knowledge_resolve", fmt.Errorf("knowledge service is not configured"))
|
||||
@@ -490,7 +504,7 @@ func (s *TemplateService) executeGeneration(ctx context.Context, job generationJ
|
||||
knowledgeContext, resolveErr := s.knowledge.ResolveContext(
|
||||
ctx,
|
||||
job.TenantID,
|
||||
int64(extractInt(job.Params, "brand_id")),
|
||||
brandID,
|
||||
knowledgeGroupIDs,
|
||||
buildGenerationKnowledgeQuery(job.TemplateKey, job.TemplateName, job.Params),
|
||||
)
|
||||
@@ -499,6 +513,7 @@ func (s *TemplateService) executeGeneration(ctx context.Context, job generationJ
|
||||
return
|
||||
}
|
||||
knowledgePrompt = s.knowledge.RenderPromptSection(knowledgeContext)
|
||||
knowledgeFactConstraints = knowledgeContext.FactConstraints
|
||||
}
|
||||
|
||||
prompt := buildGenerationPrompt(job.TemplateKey, job.TemplateName, job.PromptTemplate, job.Params, knowledgePrompt)
|
||||
@@ -511,7 +526,8 @@ func (s *TemplateService) executeGeneration(ctx context.Context, job generationJ
|
||||
if job.WebSearch.Enabled {
|
||||
generateReq.WebSearch = &job.WebSearch
|
||||
}
|
||||
result, err := s.llm.Generate(ctx, generateReq, func(delta string) {
|
||||
knowledgeFactConstraints = MergeKnowledgeFactConstraints(brandPromptContext.FactConstraints, knowledgeFactConstraints)
|
||||
result, err := GenerateArticleWithKnowledgeFactGuard(ctx, s.llm, generateReq, knowledgeFactConstraints, func(delta string) {
|
||||
if runtimeCfg.StreamEnabled && delta != "" {
|
||||
s.streams.AppendDelta(job.ArticleID, job.TaskID, title, delta)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user