mirror of
https://github.com/primedigitaltech/market-assistant.git
synced 2026-07-21 23:41:39 +08:00
fix(llm): 策略与机会按 token 上限收敛输入,避免提示词过长失败
Made-with: Cursor
This commit is contained in:
parent
b0f71f196a
commit
c729d718c4
@ -829,6 +829,29 @@ def _truncate_strategy_narrative(text: str, max_chars: int) -> str:
|
||||
)
|
||||
|
||||
|
||||
def _llm_context_window_limit() -> int:
|
||||
"""与 ``AI_crawler.chat_completion_text`` 使用的上下文上限一致。"""
|
||||
raw = (os.environ.get("LLM_CONTEXT_WINDOW") or os.environ.get("OPENAI_CONTEXT_WINDOW") or "32768").strip()
|
||||
try:
|
||||
return max(4096, int(raw))
|
||||
except ValueError:
|
||||
return 32768
|
||||
|
||||
|
||||
def _estimate_chat_input_tokens(system_prompt: str, user_prompt: str) -> int:
|
||||
"""与 ``AI_crawler._estimate_chat_input_tokens`` 一致(保守估输入 token)。"""
|
||||
total_chars = len(system_prompt or "") + len(user_prompt or "")
|
||||
return int(total_chars * 0.55) + 512
|
||||
|
||||
|
||||
def _strategy_prompt_fits_context(system: str, user: str) -> bool:
|
||||
"""若为 False,``chat_completion_text`` 会在发请求前因过长而抛错。"""
|
||||
est = _estimate_chat_input_tokens(system, user)
|
||||
ctx = _llm_context_window_limit()
|
||||
buf = 256
|
||||
return est < ctx - buf - 256
|
||||
|
||||
|
||||
def generate_strategy_opportunities_llm(
|
||||
brief: dict[str, Any],
|
||||
*,
|
||||
@ -845,12 +868,20 @@ def generate_strategy_opportunities_llm(
|
||||
for k, v in (chapter_llm_narratives or {}).items()
|
||||
if isinstance(v, str) and v.strip()
|
||||
}
|
||||
_TARGET = 118_000
|
||||
sys_prompt = STRATEGY_OPPORTUNITIES_SYSTEM
|
||||
|
||||
def _user_from_payload(p: dict[str, Any]) -> str:
|
||||
return STRATEGY_OPPORTUNITIES_USER_PREFIX + json.dumps(p, ensure_ascii=False)
|
||||
|
||||
# 按「字符上限」递减尝试;最终以 token 估算为准(与 AI_crawler 一致),避免 JSON 仍超长导致整段失败。
|
||||
for cap_brief, cap_narr in (
|
||||
(100_000, 7_000),
|
||||
(72_000, 5_000),
|
||||
(52_000, 3_500),
|
||||
(40_000, 2_500),
|
||||
(48_000, 2_800),
|
||||
(42_000, 2_200),
|
||||
(36_000, 1_700),
|
||||
(30_000, 1_300),
|
||||
(26_000, 950),
|
||||
(22_000, 700),
|
||||
(18_000, 500),
|
||||
):
|
||||
compact = compact_brief_for_llm(brief, max_chars=cap_brief)
|
||||
narratives = {
|
||||
@ -862,13 +893,19 @@ def generate_strategy_opportunities_llm(
|
||||
}
|
||||
if narratives:
|
||||
payload["prior_chapter_llm_narratives"] = narratives
|
||||
raw = json.dumps(payload, ensure_ascii=False)
|
||||
if len(raw) <= _TARGET:
|
||||
user = STRATEGY_OPPORTUNITIES_USER_PREFIX + raw
|
||||
return _call_llm(STRATEGY_OPPORTUNITIES_SYSTEM, user)
|
||||
compact = compact_brief_for_llm(brief, max_chars=40_000)
|
||||
user = _user_from_payload(payload)
|
||||
if _strategy_prompt_fits_context(sys_prompt, user):
|
||||
return _call_llm(sys_prompt, user)
|
||||
|
||||
# 去掉各章节选,仅保留 brief
|
||||
for cap_brief in (40_000, 32_000, 26_000, 20_000, 16_000):
|
||||
compact = compact_brief_for_llm(brief, max_chars=cap_brief)
|
||||
payload = {"keyword": keyword, "competitor_brief": compact}
|
||||
user = _user_from_payload(payload)
|
||||
if _strategy_prompt_fits_context(sys_prompt, user):
|
||||
return _call_llm(sys_prompt, user)
|
||||
|
||||
compact = compact_brief_for_llm(brief, max_chars=14_000)
|
||||
payload = {"keyword": keyword, "competitor_brief": compact}
|
||||
user = STRATEGY_OPPORTUNITIES_USER_PREFIX + json.dumps(
|
||||
payload, ensure_ascii=False
|
||||
)
|
||||
return _call_llm(STRATEGY_OPPORTUNITIES_SYSTEM, user)
|
||||
user = _user_from_payload(payload)
|
||||
return _call_llm(sys_prompt, user)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user