feat(pipeline): 策略骨架缩短并强化策略生成决策边界

- 规则稿:章节重排为短骨架,去重复假设套话;探针模式三条占位,传统模式改为统计摘录句式。
- LLM:STRATEGY_SYSTEM 明确表单已定项不可反写,空项由数据补全,成稿禁止二次决策话术。
- API/前端:新增目标客群、主要对标、资源备注字段并传入 strategy_decisions。
- OpenAPI 与单测同步。

Made-with: Cursor
This commit is contained in:
hub-gif 2026-04-17 17:04:24 +08:00
parent 932c3d6aeb
commit 16d64565a3
7 changed files with 149 additions and 81 deletions

View File

@ -12,17 +12,24 @@ from ..reporting.strategy_draft import (
)
from .llm_client import call_llm, estimate_chat_input_tokens, llm_context_window_size
STRATEGY_SYSTEM = """你是市场策略顾问,根据**结构化监测摘要**与业务侧填写的**决策字段**,把「规则底稿」润色为可读的策略 Markdown
STRATEGY_SYSTEM = """你是市场策略顾问,根据**结构化监测摘要**与业务侧填写的**决策字段**,把「规则底稿」写成**短、可执行**的策略 Markdown 成稿
**规则**
- 输入 JSON `rules_draft_markdown`规则引擎生成的底稿与同任务数据一致`structured_brief`摘要子集`strategy_decisions``business_notes` 可选 `report_strategy_excerpt`与同任务宿主报告**第九章**策略与机会正文同源来自已落盘产物
- **与报告第九章对齐硬性 `report_strategy_excerpt` 非空时**润色后的全文在**战略方向与主要判断**上须与该节选**一致**不得写出与之**明显矛盾**的结论如定价档位差异化主线主要风险判断 `business_notes` `strategy_decisions` 与节选冲突须在正文适当位置简短说明与报告第九章策略归纳不一致之处见业务备注类表述**不得**把节选与 `structured_brief` 中均未出现的数字当作既定事实
- ** `report_strategy_excerpt` 为空或仅为占位说明**表示报告侧未生成或未重跑第九章大模型正文仅依据 `rules_draft_markdown` `structured_brief` 润色**不得编造**与可能存在的报告第九章结论
- **不得编造**输入中不存在的销量占比价格数字若底稿与摘要中有数字须保持一致表述集中度时用第一大份额前三家合计等中文**不要用** CR1CR3 等缩写
- `structured_brief` `matrix_overview_for_llm` 或矩阵相关字段策略中应**呼应**细分类目分组与竞品矩阵结论不得无故删光矩阵相关建议
- 可调整段落衔接标题层级列表与表格呈现使更易读可补充建议待业务确认类表述但不虚构竞品名称或数据
- **仅输出** Markdown 正文不要 ``` 围栏包裹全文
- **输出完整性**须收束各小节与全文勿在句子或列表中途戛然而止"""
**输入**`rules_draft_markdown`规则骨架与同任务数据一致`structured_brief`摘要子集`strategy_decisions``business_notes`可选 `report_strategy_excerpt`与同任务宿主报告**第九章**策略与机会正文同源
**决策边界硬性**
- **业务已在 `strategy_decisions` 中填写的项**角色时间成功标准战场一句话定位勾选竞争倾向四柱目标客群/对标/资源备注等视为**已定决策**成稿须**落实为具体执行句****不得**改写成相反结论或再要求用户请选择
- **表单中为空或占位 *待填**骨架占位*的项**由你结合 `structured_brief``report_strategy_excerpt`若非空与数据摘录**补全为可执行表述**补全须与数据方向一致**不得**编造输入中不存在的销量GMV未给出的价格或占比
- **成稿阶段禁止**再写一轮请业务决策待确认后再定假设待验证**二次决策话术**不确定性用一句带过即可需下周用原评论抽样核对勿重复堆砌
**与报告第九章对齐 `report_strategy_excerpt` 非空时**战略方向与主要判断须与该节选**一致**不得明显矛盾 `business_notes` 或表单与节选冲突正文中简短点明与报告第九章归纳差异见业务备注**不得**把节选与 `structured_brief` 均未出现的数字当作事实
** `report_strategy_excerpt` 为空**仅依据底稿与摘要润色**不得编造**报告第九章结论
**数据**不得编造销量占比价格数字底稿与摘要中的数字须保持一致集中度用第一大份额前三家合计等中文**不要用** CR1CR3
**矩阵** `structured_brief` 含矩阵相关字段**呼应**细分类目与竞品矩阵结论不得无故删光
**输出** Markdown 正文不要 ``` 围栏须收束各小节与全文勿中途截断"""
STRATEGY_USER_PREFIX = """请基于以下 JSON 输出最终策略稿Markdown\n\n"""
@ -93,8 +100,8 @@ def generate_strategy_draft_markdown_llm(
}
if report_uses_chapter8_text_mining_probe(report_config):
payload["structured_brief_omission_note"] = (
"已启用第八章文本挖掘:本 JSON 中的 structured_brief 已省略关注词/场景子串计数字段,"
"避免与当前报告正文口径冲突;请依规则底稿第五节说明与报告 §8 自拟假设,勿逐条编造子串命中列表。"
"已启用第八章文本挖掘:structured_brief 已省略关注词/场景子串计数字段,避免与报告正文口径冲突。"
"请依报告 §8 与摘要其他字段,将底稿第五节写成具体执行要点(需求焦点、场景、传播),勿逐条编造子串命中列表。"
)
raw = json.dumps(payload, ensure_ascii=False)
if len(raw) > 500_000:

View File

@ -1,8 +1,8 @@
"""
市场策略 Markdown 草稿侧重**策略制定框架**目标战场定位支柱行动
基于同任务结构化摘要与可选业务备注规则生成附录为关键数据速览
市场策略 Markdown 草稿**规则骨架**占位 + 少量数据摘录供业务与大模型成稿对齐
后续可接 LLM 润色当前无模型调用便于验收与追溯
- 决策在策略生成表单完成未填项由大模型结合摘要与报告节选补全
- 骨架刻意短可执行避免与成稿重复的假设 / 待验证套话
"""
from __future__ import annotations
@ -121,7 +121,7 @@ def build_strategy_draft_markdown(
strategy_decisions: dict[str, Any] | None = None,
report_config: dict[str, Any] | None = None,
) -> str:
"""生成可下载的 Markdown策略架为主,附录为数据速览。"""
"""生成可下载的 Markdown策略架为主,附录为数据速览。"""
use_ch8_probe = report_uses_chapter8_text_mining_probe(report_config)
d = strategy_decisions or {}
pos = _esc(d.get("positioning_choice") or "").strip()
@ -129,7 +129,8 @@ def build_strategy_draft_markdown(
lines: list[str] = [
f"# 市场策略制定草稿 · 「{kw}",
"",
"> 本稿用于**辅助制定市场策略**;由规则根据本批次结构化摘要与业务备注生成,**非大模型自由发挥**,定稿前请业务修订。",
"> **骨架说明**:本页为**规则骨架**(占位与少量摘录)。勾选大模型生成时,在骨架与数据上写**短、可执行**成稿。"
"**决策在策略生成表单完成**;未填项由模型结合本任务摘要与报告节选补全,**成稿不再写「请再选 / 请决策」式套话**。",
"",
]
if generated_at_iso:
@ -140,7 +141,7 @@ def build_strategy_draft_markdown(
[
"---",
"",
"## 一、战略背景与目标(请业务补全)",
"## 一、目标与边界",
"",
_goal_bullet("本品角色", str(d.get("product_role") or ""), "新品 / 追赶 / 防守 / 拓品类 …"),
_goal_bullet("时间范围", str(d.get("time_horizon") or ""), "如:本季度 / 未来 12 周"),
@ -149,7 +150,22 @@ def build_strategy_draft_markdown(
str(d.get("success_criteria") or ""),
"如:搜索位次、转化率、声量、复购 …",
),
_goal_bullet("非目标(明确不做什么)", str(d.get("non_goals") or ""), "可选"),
_goal_bullet("非目标", str(d.get("non_goals") or ""), "明确不做什么(可选)"),
_goal_bullet(
"目标客群",
str(d.get("audience_segment") or ""),
"一句话:为谁、什么场景(可选)",
),
_goal_bullet(
"主要对标",
str(d.get("competitor_reference") or ""),
"品牌或价位带参照(可选)",
),
_goal_bullet(
"资源与预算备注",
str(d.get("resource_notes") or ""),
"人力、投放、产能等量级(可选)",
),
"",
]
)
@ -159,7 +175,7 @@ def build_strategy_draft_markdown(
comm_n = scope.get("comment_flat_rows")
lines.extend(
[
"## 二、战场界定(监测语境)",
"## 二、战场与样本",
"",
f"- **监测关键词 / 货架语境**{kw}",
f"- **批次**{_esc(brief.get('batch_label')) or ''}",
@ -167,22 +183,21 @@ def build_strategy_draft_markdown(
)
if merged_n is not None or comm_n is not None:
lines.append(
f"- **深入样本规模**:深入 SKU ≈ {_num(merged_n)};评价扁平条数 ≈ {_num(comm_n)}"
"*策略含义:样本越大,以下「假设」越需抽样复核原评论。*"
f"- **深入样本**:深入 SKU ≈ {_num(merged_n)};评价扁平条数 ≈ {_num(comm_n)}"
)
bf = _esc(d.get("battlefield_one_line") or "").strip()
if bf:
lines.append(f"- **一句话战场**{bf}")
else:
lines.append(
"- **一句话战场***请用业务语言写:我们在哪个需求场景、与谁抢同一批用户?)*"
"- **一句话战场***在哪个需求场景、与谁抢同一批用户?)*"
)
lines.append("")
conc = brief.get("concentration") or {}
shops = conc.get("shops_from_list") or {}
dbrand = conc.get("detail_brand_among_merged") or {}
lines.extend(["## 三、竞争格局 → 策略含义", ""])
lines.extend(["## 三、竞争结构(摘录)", ""])
n_shop = _cr_narrative(
"列表侧店铺集中度",
concentration_first_share(shops),
@ -200,23 +215,20 @@ def build_strategy_draft_markdown(
if n_brand:
lines.append(n_brand)
if not n_shop and not n_brand:
lines.append("*本摘要未含集中度指标,请结合本批次竞争结构数据补全后再写判断。*")
lines.append("*本摘要未含集中度指标,请结合本批次竞争结构数据补全。*")
lines.extend(
[
"",
"**可下判断的提问(自测)**",
"",
"- 若头部已占稳心智,本品是**侧翼**还是**正面替代**",
"- 店铺/品牌分散时,是否适合用**细分场景**或**内容教育**切入?",
"- **自测**:头部已占稳心智时,侧翼还是正面替代?分散时是否用细分场景或内容教育切入?",
"",
]
)
stance = _esc(d.get("competitive_stance") or "").strip()
stance_line = {
"flank": "- **本品倾向**倾向**侧翼切入**,避免与头部正面硬碰。",
"head_on": "- **本品倾向**倾向**正面替代**,对标头部主战场。",
"both": "- **本品倾向**计划**分层推进**(部分场景侧翼、部分场景正面)。",
"undecided": "- **本品倾向****尚未拍板**,需在会议中对齐后再定主战场叙事。",
"flank": "- **本品倾向**侧翼切入,避免与头部正面硬碰。",
"head_on": "- **本品倾向**正面替代,对标头部主战场。",
"both": "- **本品倾向**分层推进(部分场景侧翼、部分场景正面)。",
"undecided": "- **本品倾向***(表单未选;成稿时据数据写清倾向)*",
}.get(stance)
if stance_line:
lines.append(stance_line)
@ -224,16 +236,15 @@ def build_strategy_draft_markdown(
mix = brief.get("category_mix_top") or []
if mix:
lines.append("### 类目结构提示Top")
lines.append("### 类目结构Top")
lines.append("")
lines.append("*以下仅作「货架长什么样」的速记。*")
for item in mix[:6]:
if isinstance(item, dict):
lines.append(f"- {_esc(item.get('label'))}{_num(item.get('count'))}")
lines.append("")
pst = brief.get("price_stats") or {}
lines.extend(["## 四、价格带与定位项(启发式", ""])
lines.extend(["## 四、价格带与定位(业务已选)", ""])
if pst.get("n"):
src = _esc(brief.get("price_stats_source")) or ""
lines.extend(
@ -241,46 +252,46 @@ def build_strategy_draft_markdown(
f"- **价格来源**{src},有效价样本 n = {_num(pst.get('n'))}",
f"- **展示价区间**{_num(pst.get('min'))} {_num(pst.get('max'))}**中位数** {_num(pst.get('median'))}",
"",
"**定位选项(请勾一条或改写,并写明理由**",
"**主定位(与表单一致**",
"",
f"- {_pos_mark(pos, 'top')} **贴顶**对标中高位或头部价位带,强调品质/成分/背书。",
f"- {_pos_mark(pos, 'top')} **贴顶**中高位或头部价位带,强调品质/成分/背书。",
f"- {_pos_mark(pos, 'mid')} **卡腰**:围绕中位数一带,强调性价比与场景匹配。",
f"- {_pos_mark(pos, 'entry')} **下探**:贴近区间下限,强调入门与拉新(注意毛利与品牌调性)。",
f"- {_pos_mark(pos, 'different')} **另起带**刻意避开主价格带,用规格/组合/服务差异化。",
f"- {_pos_mark(pos, 'entry')} **下探**:贴近区间下限,强调入门与拉新(注意毛利与调性)。",
f"- {_pos_mark(pos, 'different')} **另起带**避开主价格带,用规格/组合/服务差异化。",
"",
]
)
else:
lines.append("*摘要中无价带统计,请结合本批次价格相关数据补全后再填上表。*")
lines.append("*摘要中无价带统计,请结合本批次价格数据补全。*")
lines.append("")
lines.extend(
[
"**定位选项(请勾一条或改写,并写明理由**",
"**主定位(与表单一致**",
"",
f"- {_pos_mark(pos, 'top')} **贴顶**对标中高位或头部价位带,强调品质/成分/背书。",
f"- {_pos_mark(pos, 'top')} **贴顶**中高位或头部价位带,强调品质/成分/背书。",
f"- {_pos_mark(pos, 'mid')} **卡腰**:围绕中位数一带,强调性价比与场景匹配。",
f"- {_pos_mark(pos, 'entry')} **下探**:贴近区间下限,强调入门与拉新(注意毛利与品牌调性)。",
f"- {_pos_mark(pos, 'different')} **另起带**刻意避开主价格带,用规格/组合/服务差异化。",
f"- {_pos_mark(pos, 'entry')} **下探**:贴近区间下限,强调入门与拉新(注意毛利与调性)。",
f"- {_pos_mark(pos, 'different')} **另起带**避开主价格带,用规格/组合/服务差异化。",
"",
]
)
ckw = brief.get("comment_focus_keywords") or []
usc = brief.get("usage_scenarios") or []
lines.extend(["## 五、用户需求与场景 — 可写成策略的假设", ""])
lines.extend(["## 五、用户与评论侧", ""])
if use_ch8_probe:
lines.extend(
[
"*当前任务报告以**第八章评论侧文本挖掘**为主线(替代原关注词/场景条形图为主呈现)时,**请勿**再逐条照搬「子串命中次数」式假设列表——结构化摘要里仍可能含 `comment_focus_keywords` / `usage_scenarios` 等字段,**与当前报告正文展示口径可能不一致**。*",
"*当前任务报告以**第八章评论侧文本挖掘**为主呈现时,此处**不**逐条罗列子串命中次数(与报告 §8 口径一致)。*",
"",
"*请结合报告中 **§8** 评论与情感归纳、文本挖掘小节,以及评价原文抽样,自拟若干条「待验证假设」(需可复核、可证伪)。*",
"- **需求焦点***(骨架占位;成稿写 12 句可执行结论)*",
"- **场景侧重***(骨架占位)*",
"- **传播切入点***(骨架占位)*",
"",
]
)
else:
lines.append(
"*下列由关注词/场景**计数**转化而来,是「待验证假设」而非结论;请结合评价原文抽样修订。*"
)
lines.append("*下列为关注词/场景**统计摘录**(口径同本批次摘要);成稿时写成具体动作,勿重复统计句。*")
lines.append("")
if ckw:
for item in ckw[:8]:
@ -288,8 +299,7 @@ def build_strategy_draft_markdown(
w = _esc(item.get("word"))
c = _num(item.get("count"))
lines.append(
f"- **假设**:用户决策中「{w}」被频繁提及(约 {c} 次统计命中)—— "
f"*可追问:本品故事是否正面回应?传播关键词是否覆盖?*"
f"- 「{w}」:子串统计命中约 **{c}** 次(口径同报告关注词)。"
)
if usc:
for item in usc[:6]:
@ -298,19 +308,18 @@ def build_strategy_draft_markdown(
cn = _num(item.get("count"))
sh = _pct(item.get("share_of_text_units"))
lines.append(
f"- **场景命题**:「{sc}」在预设场景中约 {cn} 条、约占 {sh} 文本单元—— "
f"*可追问:主图/详情/客服话术是否对齐该场景?*"
f"- 场景「{sc}」:约 **{cn}** 条,约占 **{sh}** 文本单元(预设场景分组)。"
)
if not ckw and not usc:
lines.append("*摘要中无关注词/场景组结果,请补全评论侧分析后再写本节。*")
lines.append("*摘要中无关注词/场景组,请结合评论侧分析补全本节。*")
lines.append("")
hints = brief.get("strategy_hints") or []
lines.extend(
[
"## 六、机会方向与策略支柱(草案)",
"## 六、机会与策略支柱",
"",
"### 规则引擎提示(来自摘要 `strategy_hints`",
"### 摘要提示(`strategy_hints`",
"",
]
)
@ -318,7 +327,7 @@ def build_strategy_draft_markdown(
for h in hints:
lines.append(f"- {_esc(h)}")
else:
lines.append("*(当前无自动线索,请结合本批次结论手写 35 条机会*")
lines.append("*(当前无自动线索*")
pp = str(d.get("pillar_product") or "")
pr = str(d.get("pillar_price") or "")
pch = str(d.get("pillar_channel") or "")
@ -326,10 +335,10 @@ def build_strategy_draft_markdown(
lines.extend(
[
"",
"### 策略支柱 — 请业务逐项填空",
"### 策略支柱(表单已填优先)",
"",
"| 支柱 | 本品打算怎么做 | 与头部差异 | 证据 / 出处 |",
"|------|----------------|------------|-------------|",
"| 支柱 | 本品动作 | 与头部差异 | 证据 / 出处 |",
"|------|----------|------------|-------------|",
f"| 产品 | {_pillar_cell(pp)} | *待填* | *§* |",
f"| 价格 | {_pillar_cell(pr)} | *待填* | *§* |",
f"| 渠道/触点 | {_pillar_cell(pch)} | *待填* | *§* |",
@ -342,17 +351,17 @@ def build_strategy_draft_markdown(
rp = bool(d.get("ack_risk_price"))
rc = bool(d.get("ack_risk_concentration"))
rk_kw = (
"评论侧量化/关键词归纳是否**以偏概全**?(需原评论抽样)"
"评论侧归纳是否以偏概全?(需原评论抽样)"
if use_ch8_probe
else "关注词/场景是否**以偏概全**?(需原评论抽样)"
else "关注词/场景统计是否以偏概全?(需原评论抽样)"
)
lines.extend(
[
"## 七、风险与待证伪",
"## 七、风险核对项",
"",
_risk_line(rk, rk_kw),
_risk_line(rp, "价格带是否含大促/异常挂价?(需核对清洗规则)"),
_risk_line(rc, "列表集中度与深入样本品牌是否**矛盾**?(需解释渠道差异)"),
_risk_line(rc, "列表集中度与深入样本品牌是否不一致?(需解释渠道差异)"),
"",
]
)
@ -360,21 +369,19 @@ def build_strategy_draft_markdown(
notes = _esc(business_notes)
lines.extend(
[
"## 八、业务约束与内部判断",
"## 八、业务约束与备注",
"",
(notes if notes else "*(未填写。建议补充:渠道红线、价位策略、竞品对标名单、预算量级等。)*"),
(notes if notes else "*(未填写业务备注。)*"),
"",
]
)
lines.extend(
[
"## 九、建议下一步(策略向",
"## 九、下一步(可执行",
"",
"- [ ] 开会对齐:**§一** 目标与 **§八** 约束,确认 12 条主策略命题。",
"- [ ] 为 **§六** 策略支柱表格每一行各找 **1 条数据证据**(注明出处)。",
"- [ ] 产出 **12 周节奏表**(里程碑 + 负责人),与本品排期挂钩。",
"- [ ] 定义 **3 个可观测指标**(周或双周复盘)。",
"- [ ] 对齐 **§一** 目标与 **§八** 约束,锁定 12 条主命题。",
"- [ ] 为 **§六** 支柱各补 **1 条数据证据** + **12 周内可交付动作**(负责人 + 时间)。",
"",
"---",
"",

View File

@ -438,6 +438,15 @@ class StrategyDraftRequestSerializer(serializers.Serializer):
pillar_comm = serializers.CharField(
required=False, allow_blank=True, default="", max_length=800, trim_whitespace=False
)
audience_segment = serializers.CharField(
required=False, allow_blank=True, default="", max_length=500, trim_whitespace=False
)
competitor_reference = serializers.CharField(
required=False, allow_blank=True, default="", max_length=800, trim_whitespace=False
)
resource_notes = serializers.CharField(
required=False, allow_blank=True, default="", max_length=1000, trim_whitespace=False
)
ack_risk_keywords = serializers.BooleanField(required=False, default=False)
ack_risk_price = serializers.BooleanField(required=False, default=False)
ack_risk_concentration = serializers.BooleanField(required=False, default=False)

View File

@ -26,7 +26,7 @@ class StrategyDraftTests(SimpleTestCase):
self.assertIn("任务 ID**99", md)
self.assertIn("假设A", md)
self.assertIn("重点:华东", md)
self.assertIn("战略背景与目标", md)
self.assertIn("目标与边界", md)
self.assertIn("市场策略制定草稿", md)
def test_strategy_decisions_merge(self) -> None:
@ -52,9 +52,9 @@ class StrategyDraftTests(SimpleTestCase):
self.assertIn("- [ ] **贴顶**", md)
self.assertIn("侧翼切入", md)
self.assertIn("| 产品 | 做低糖配方 |", md)
self.assertIn("- [x] 关注词/场景是否**以偏概全**", md)
self.assertIn("- [x] 关注词/场景统计是否以偏概全", md)
self.assertIn("- [ ] 价格带是否含大促", md)
self.assertIn("- [x] 列表集中度与深入样本品牌是否**矛盾**", md)
self.assertIn("- [x] 列表集中度与深入样本品牌是否不一致", md)
def test_chapter8_probe_omits_focus_scenario_count_bullets(self) -> None:
brief = {
@ -76,8 +76,8 @@ class StrategyDraftTests(SimpleTestCase):
report_config={"chapter8_text_mining_probe": True},
)
self.assertIn("文本挖掘", md)
self.assertNotIn("假设**:用户决策中「口感」", md)
self.assertNotIn("场景命题**「控糖", md)
self.assertNotIn("子串统计命中约 **501**", md)
self.assertNotIn("场景「控糖", md)
def test_legacy_report_shows_focus_scenario_bullets(self) -> None:
brief = {
@ -98,5 +98,5 @@ class StrategyDraftTests(SimpleTestCase):
brief=brief,
report_config={"chapter8_text_mining_probe": False},
)
self.assertIn("假设**:用户决策中「口感」", md)
self.assertIn("场景命题**「控糖/血糖相关」", md)
self.assertIn("「口感」:子串统计命中约 **501** 次", md)
self.assertIn("场景「控糖/血糖相关」:约 **305** 条", md)

View File

@ -133,6 +133,9 @@ class JobStrategyDraftView(APIView):
"pillar_price": vd.get("pillar_price") or "",
"pillar_channel": vd.get("pillar_channel") or "",
"pillar_comm": vd.get("pillar_comm") or "",
"audience_segment": vd.get("audience_segment") or "",
"competitor_reference": vd.get("competitor_reference") or "",
"resource_notes": vd.get("resource_notes") or "",
"ack_risk_keywords": bool(vd.get("ack_risk_keywords")),
"ack_risk_price": bool(vd.get("ack_risk_price")),
"ack_risk_concentration": bool(vd.get("ack_risk_concentration")),

View File

@ -549,6 +549,18 @@ components:
pillar_comm:
type: string
maxLength: 800
audience_segment:
type: string
maxLength: 500
description: 目标客群一句话(可选)
competitor_reference:
type: string
maxLength: 800
description: 主要对标品牌或价位带(可选)
resource_notes:
type: string
maxLength: 1000
description: 资源与预算量级备注(可选)
ack_risk_keywords:
type: boolean
default: false

View File

@ -48,6 +48,9 @@ const decisions = reactive({
pillar_price: '',
pillar_channel: '',
pillar_comm: '',
audience_segment: '',
competitor_reference: '',
resource_notes: '',
ack_risk_keywords: false,
ack_risk_price: false,
ack_risk_concentration: false,
@ -89,6 +92,9 @@ function buildPayload() {
pillar_price: decisions.pillar_price,
pillar_channel: decisions.pillar_channel,
pillar_comm: decisions.pillar_comm,
audience_segment: decisions.audience_segment,
competitor_reference: decisions.competitor_reference,
resource_notes: decisions.resource_notes,
ack_risk_keywords: decisions.ack_risk_keywords,
ack_risk_price: decisions.ack_risk_price,
ack_risk_concentration: decisions.ack_risk_concentration,
@ -176,7 +182,7 @@ watch(
<p class="hint-top">
选择<strong>已成功</strong>任务在下方填空与勾选<strong>默认</strong>使用大模型在规则底稿与同任务数据摘要基础上成稿需服务端已配置网关若需更快不调用智能服务可勾选本次仅生成规则稿策略配置与分析报告生成页的<strong>报告配置</strong>相互独立策略稿与宿主报告第九章的归纳<strong>默认对齐</strong>提交后跳转到
<RouterLink to="/jd/strategy-view">策略稿预览</RouterLink>
未填项在文稿中仍保留占位提示
<strong>决策在本页完成</strong>已填项会写入底稿并由大模型落实为执行句未填项由大模型结合数据补全成稿不再重复请再选式表述
</p>
<div class="toolbar">
@ -226,6 +232,30 @@ watch(
<span>非目标</span>
<textarea v-model="decisions.non_goals" rows="2" placeholder="明确不做什么(可选)" />
</label>
<label class="fld fld-block">
<span>目标客群</span>
<input
v-model="decisions.audience_segment"
type="text"
placeholder="一句话:为谁、什么场景(可选)"
/>
</label>
<label class="fld fld-block">
<span>主要对标</span>
<input
v-model="decisions.competitor_reference"
type="text"
placeholder="品牌或价位带参照(可选)"
/>
</label>
<label class="fld fld-block">
<span>资源与预算备注</span>
<textarea
v-model="decisions.resource_notes"
rows="2"
placeholder="人力、投放、产能等量级(可选)"
/>
</label>
</fieldset>
<fieldset class="fieldset">