From 7e7d3c9846e98ff0eae337ead917d4d65f78dccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=89=E9=91=AB=E5=8D=87?= Date: Thu, 2 Jul 2026 11:05:12 +0800 Subject: [PATCH] fix: truncate rwfx 3q context --- frontend-web/src/pages/AgentChatPage.tsx | 36 +++++++++++++++++-- .../task_external_context_middleware.py | 16 +++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/frontend-web/src/pages/AgentChatPage.tsx b/frontend-web/src/pages/AgentChatPage.tsx index bd1bc2f5..a67bfce8 100644 --- a/frontend-web/src/pages/AgentChatPage.tsx +++ b/frontend-web/src/pages/AgentChatPage.tsx @@ -66,6 +66,38 @@ import type { RwfxSqGateStartContext } from "@/strategy-components/components/ta /** 内置「模板数据转换器」agent 的稳定 id。仅此 agent 的对话页显示「页面模板 + 渲染预览」调试入口。 */ const TEMPLATE_BUILDER_AGENT_ID = "template-json-builder"; +const RWFX_SQ_REPORT_CONTEXT_MAX_CHARS = 12000; +const RWFX_SQ_REPORT_CONTEXT_TAIL_CHARS = 2000; + +function stringifyForHiddenContext(value: unknown): string { + if (typeof value === "string") return value; + try { + const text = JSON.stringify(value, null, 2); + return typeof text === "string" ? text : ""; + } catch { + return String(value ?? ""); + } +} + +function truncateMiddle(text: string, maxChars: number): string { + if (text.length <= maxChars) return text; + const marker = "\n\n...[内容过长,已截断中间部分]...\n\n"; + const tailChars = Math.min(RWFX_SQ_REPORT_CONTEXT_TAIL_CHARS, Math.floor(maxChars / 4)); + const headChars = Math.max(0, maxChars - marker.length - tailChars); + return `${text.slice(0, headChars)}${marker}${text.slice(-tailChars)}`; +} + +function compactSqReportForContext(report: unknown): unknown { + if (report == null) return null; + const serialized = stringifyForHiddenContext(report); + if (serialized.length <= RWFX_SQ_REPORT_CONTEXT_MAX_CHARS) return report; + return { + truncated: true, + originalChars: serialized.length, + maxChars: RWFX_SQ_REPORT_CONTEXT_MAX_CHARS, + content: truncateMiddle(serialized, RWFX_SQ_REPORT_CONTEXT_MAX_CHARS), + }; +} function rwfxSqReportRunContext( gateContext?: RwfxSqGateStartContext, @@ -78,9 +110,9 @@ function rwfxSqReportRunContext( title: "三情分析(3q)研判情报报告", usage: gateContext.sqReportStatus === "complete" - ? "这是任务分析(rwfx)问答的隐藏业务上下文。回答时应参考这些已完成的 3q 结果,但不要向用户说明页面注入了隐藏上下文,除非用户明确询问。" + ? "这是任务分析(rwfx)问答的隐藏业务上下文。回答时应参考这些已完成的 3q 结果;如 data.truncated=true,说明内容已截断,只能基于可见片段分析。不要向用户说明页面注入了隐藏上下文,除非用户明确询问。" : "3q 研判情报报告当前未提供有效结果。回答时不要编造 3q 结果,可仅基于任务信息继续分析。", - data: gateContext.sqReport ?? null, + data: compactSqReportForContext(gateContext.sqReport), }, }; } diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/task_external_context_middleware.py b/offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/task_external_context_middleware.py index 6ddf8f7c..ee00b97d 100644 --- a/offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/task_external_context_middleware.py +++ b/offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/task_external_context_middleware.py @@ -17,6 +17,17 @@ from langchain_core.messages import HumanMessage _CONTEXT_KEY = "task_external_context" _TAG = "task_external_context" +_MAX_CONTEXT_CHARS = 18000 +_TAIL_CONTEXT_CHARS = 2500 + + +def _truncate_middle(text: str, max_chars: int = _MAX_CONTEXT_CHARS) -> str: + if len(text) <= max_chars: + return text + marker = "\n\n...[隐藏任务上下文过长,已截断中间部分]...\n\n" + tail_chars = min(_TAIL_CONTEXT_CHARS, max_chars // 4) + head_chars = max(0, max_chars - len(marker) - tail_chars) + return f"{text[:head_chars]}{marker}{text[-tail_chars:]}" def _render_context(value: Any) -> str: @@ -25,9 +36,10 @@ def _render_context(value: Any) -> str: if isinstance(value, str): return value.strip() try: - return json.dumps(value, ensure_ascii=False, indent=2, default=str).strip() + text = json.dumps(value, ensure_ascii=False, indent=2, default=str).strip() except Exception: - return str(value).strip() + text = str(value).strip() + return _truncate_middle(text) def _task_context_from_request(request: Any) -> Any: