mirror of
https://github.com/primedigitaltech/market-assistant.git
synced 2026-07-21 23:41:39 +08:00
fix(llm): 策略稿润色预留 completion 预算,缓解输出截断
generate_strategy_draft_markdown_llm 按摘要/第九章节选/规则底稿分级收紧,满足最小 completion token 后再调用;底稿与 JSON 超限仍截断并提示。系统提示补充收束全文要求。 Made-with: Cursor
This commit is contained in:
parent
1229e49dbe
commit
f06fd12f1f
@ -18,7 +18,8 @@ STRATEGY_SYSTEM = """你是市场策略顾问,根据**结构化监测摘要**
|
|||||||
- **不得编造**输入中不存在的销量、占比、价格数字;若底稿与摘要中有数字,须保持一致;表述集中度时用「第一大……份额」「前三家合计」等中文,**不要用** CR1、CR3 等缩写;
|
- **不得编造**输入中不存在的销量、占比、价格数字;若底稿与摘要中有数字,须保持一致;表述集中度时用「第一大……份额」「前三家合计」等中文,**不要用** CR1、CR3 等缩写;
|
||||||
- 若 `structured_brief` 含 `matrix_overview_for_llm` 或矩阵相关字段,策略中应**呼应**细分类目分组与竞品矩阵结论,不得无故删光矩阵相关建议;
|
- 若 `structured_brief` 含 `matrix_overview_for_llm` 或矩阵相关字段,策略中应**呼应**细分类目分组与竞品矩阵结论,不得无故删光矩阵相关建议;
|
||||||
- 可调整段落衔接、标题层级、列表与表格呈现,使更易读;可补充「建议」「待业务确认」类表述,但不虚构竞品名称或数据;
|
- 可调整段落衔接、标题层级、列表与表格呈现,使更易读;可补充「建议」「待业务确认」类表述,但不虚构竞品名称或数据;
|
||||||
- **仅输出** Markdown 正文(不要 ``` 围栏包裹全文)。"""
|
- **仅输出** Markdown 正文(不要 ``` 围栏包裹全文);
|
||||||
|
- **输出完整性**:须收束各小节与全文,勿在句子或列表中途戛然而止。"""
|
||||||
|
|
||||||
STRATEGY_USER_PREFIX = """请基于以下 JSON 输出最终策略稿(Markdown)。\n\n"""
|
STRATEGY_USER_PREFIX = """请基于以下 JSON 输出最终策略稿(Markdown)。\n\n"""
|
||||||
|
|
||||||
@ -45,24 +46,86 @@ def generate_strategy_draft_markdown_llm(
|
|||||||
generated_at_iso=generated_at_iso,
|
generated_at_iso=generated_at_iso,
|
||||||
strategy_decisions=strategy_decisions,
|
strategy_decisions=strategy_decisions,
|
||||||
)
|
)
|
||||||
compact = compact_brief_for_llm(brief, max_chars=80_000)
|
excerpt_raw = (report_strategy_excerpt or "").strip()
|
||||||
excerpt = (report_strategy_excerpt or "").strip()
|
sys_prompt = STRATEGY_SYSTEM
|
||||||
payload = {
|
min_comp = _min_strategy_completion_tokens()
|
||||||
"job_id": job_id,
|
min_comp_relaxed = max(256, min_comp // 2)
|
||||||
"keyword": keyword,
|
|
||||||
"generated_at_iso": generated_at_iso,
|
def _payload_and_user(
|
||||||
"strategy_decisions": strategy_decisions,
|
*,
|
||||||
"business_notes": business_notes,
|
compact_max: int,
|
||||||
"structured_brief": compact,
|
excerpt_max: int,
|
||||||
"rules_draft_markdown": rules_md,
|
rules_max: int | None,
|
||||||
"report_strategy_excerpt": excerpt,
|
) -> str:
|
||||||
}
|
compact = compact_brief_for_llm(brief, max_chars=compact_max)
|
||||||
raw = json.dumps(payload, ensure_ascii=False)
|
ex = (
|
||||||
if len(raw) > 500_000:
|
_truncate_strategy_narrative(excerpt_raw, excerpt_max)
|
||||||
payload["rules_draft_markdown"] = rules_md[:200_000] + "\n\n…(底稿过长已截断,请勿编造截断后内容)\n"
|
if excerpt_raw
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
if rules_max is None:
|
||||||
|
rd = rules_md
|
||||||
|
else:
|
||||||
|
rd = _truncate_rules_draft_md(rules_md, rules_max)
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"job_id": job_id,
|
||||||
|
"keyword": keyword,
|
||||||
|
"generated_at_iso": generated_at_iso,
|
||||||
|
"strategy_decisions": strategy_decisions,
|
||||||
|
"business_notes": business_notes,
|
||||||
|
"structured_brief": compact,
|
||||||
|
"rules_draft_markdown": rd,
|
||||||
|
"report_strategy_excerpt": ex,
|
||||||
|
}
|
||||||
raw = json.dumps(payload, ensure_ascii=False)
|
raw = json.dumps(payload, ensure_ascii=False)
|
||||||
user = STRATEGY_USER_PREFIX + raw
|
if len(raw) > 500_000:
|
||||||
return call_llm(STRATEGY_SYSTEM, user)
|
payload["rules_draft_markdown"] = _truncate_rules_draft_md(rd, 200_000)
|
||||||
|
raw = json.dumps(payload, ensure_ascii=False)
|
||||||
|
return STRATEGY_USER_PREFIX + raw
|
||||||
|
|
||||||
|
for cap_brief, cap_excerpt, cap_rules in (
|
||||||
|
(80_000, 24_000, None),
|
||||||
|
(64_000, 20_000, None),
|
||||||
|
(48_000, 17_000, None),
|
||||||
|
(36_000, 14_000, None),
|
||||||
|
(28_000, 11_000, None),
|
||||||
|
(22_000, 9_000, None),
|
||||||
|
(18_000, 7_000, None),
|
||||||
|
(14_000, 5_000, None),
|
||||||
|
(12_000, 4_000, 220_000),
|
||||||
|
(10_000, 3_500, 180_000),
|
||||||
|
(10_000, 3_000, 150_000),
|
||||||
|
(9_000, 2_500, 120_000),
|
||||||
|
(8_000, 2_000, 100_000),
|
||||||
|
(8_000, 2_000, 70_000),
|
||||||
|
):
|
||||||
|
user = _payload_and_user(
|
||||||
|
compact_max=cap_brief,
|
||||||
|
excerpt_max=cap_excerpt,
|
||||||
|
rules_max=cap_rules,
|
||||||
|
)
|
||||||
|
if _strategy_prompt_ok_for_call(
|
||||||
|
sys_prompt, user, min_completion_tokens=min_comp
|
||||||
|
):
|
||||||
|
return call_llm(sys_prompt, user)
|
||||||
|
|
||||||
|
for cap_brief, cap_excerpt, cap_rules in (
|
||||||
|
(10_000, 2_000, 55_000),
|
||||||
|
(8_000, 1_500, 45_000),
|
||||||
|
(7_000, 1_200, 35_000),
|
||||||
|
):
|
||||||
|
user = _payload_and_user(
|
||||||
|
compact_max=cap_brief,
|
||||||
|
excerpt_max=cap_excerpt,
|
||||||
|
rules_max=cap_rules,
|
||||||
|
)
|
||||||
|
if _strategy_prompt_ok_for_call(
|
||||||
|
sys_prompt, user, min_completion_tokens=min_comp_relaxed
|
||||||
|
):
|
||||||
|
return call_llm(sys_prompt, user)
|
||||||
|
|
||||||
|
user = _payload_and_user(compact_max=6_000, excerpt_max=1_000, rules_max=28_000)
|
||||||
|
return call_llm(sys_prompt, user)
|
||||||
|
|
||||||
|
|
||||||
STRATEGY_OPPORTUNITIES_SYSTEM = """你是 B 端市场与增长顾问。输入 JSON 含 ``keyword``、``competitor_brief``(与本任务规则报告同源的结构化摘要,可能经裁剪,并含 ``matrix_overview_for_llm``),以及可选 ``prior_chapter_llm_narratives``(本报告 **第五至第八章** 已生成的大模型归纳节选,与正文**同源**)。
|
STRATEGY_OPPORTUNITIES_SYSTEM = """你是 B 端市场与增长顾问。输入 JSON 含 ``keyword``、``competitor_brief``(与本任务规则报告同源的结构化摘要,可能经裁剪,并含 ``matrix_overview_for_llm``),以及可选 ``prior_chapter_llm_narratives``(本报告 **第五至第八章** 已生成的大模型归纳节选,与正文**同源**)。
|
||||||
@ -97,6 +160,19 @@ STRATEGY_OPPORTUNITIES_USER_PREFIX = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _truncate_rules_draft_md(text: str, max_chars: int) -> str:
|
||||||
|
"""规则策略底稿过长时截断,避免 JSON 与 completion 预算挤占输出。"""
|
||||||
|
s = (text or "").strip()
|
||||||
|
if not s:
|
||||||
|
return ""
|
||||||
|
if len(s) <= max_chars:
|
||||||
|
return s
|
||||||
|
return (
|
||||||
|
s[: max_chars - 80].rstrip()
|
||||||
|
+ "\n\n…(规则底稿已截断,请勿编造截断后内容。)\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _truncate_strategy_narrative(text: str, max_chars: int) -> str:
|
def _truncate_strategy_narrative(text: str, max_chars: int) -> str:
|
||||||
s = (text or "").strip()
|
s = (text or "").strip()
|
||||||
if not s:
|
if not s:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user