From 85ad31348eabab8a12acd0fb44fb3529dea67755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=BE=85=E5=85=83?= <2401926342@qq.com> Date: Wed, 15 Apr 2026 17:33:07 +0800 Subject: [PATCH] Implement follow-up detection in dialog context to prevent context pollution in multi-topic conversations. Introduce `is_likely_follow_up` function to determine when to inject session history based on user input. Adjust `_load_session_text2sql_context` to conditionally include context based on follow-up status, enhancing SQL generation accuracy. Update relevant API endpoints to pass user text for improved context handling. --- IMPACT_ANALYSIS.md | 41 ++++++++++++++++++ TASK_SUMMARY.md | 32 ++++++++++++++ __pycache__/api_server.cpython-312.pyc | Bin 35420 -> 35574 bytes api_server.py | 10 +++-- backend/llm/openai_client.py | 0 .../dialog_context.cpython-312.pyc | Bin 6223 -> 7335 bytes backend/utils/dialog_context.py | 23 ++++++++++ .../length.bin | Bin 4000 -> 4000 bytes 8 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 TASK_SUMMARY.md create mode 100644 backend/llm/openai_client.py diff --git a/IMPACT_ANALYSIS.md b/IMPACT_ANALYSIS.md index 7a04970..1540f67 100644 --- a/IMPACT_ANALYSIS.md +++ b/IMPACT_ANALYSIS.md @@ -42,6 +42,47 @@ --- +# Impact Analysis Report — 方案A:新话题禁用 dialog_context(防上下文污染) + +## 1. 改动概览 + +- **背景与目标**:同一会话内出现多个不同话题时,历史摘要(含上轮 SQL)注入 Text2SQL 易造成上下文污染,导致选表/条件串话。本次引入“续问判定”规则:仅在疑似续问时注入少量上文;新话题默认不注入上文。 +- **涉及模块**:`api_server.py`、`backend/utils/dialog_context.py`。 +- **改动类型**:缺陷修复 / 行为优化(仅影响带 `session_id` 且存在历史消息的请求)。 + +## 2. 方法级改动分析 + +| 位置 | 变更 | +|------|------| +| `backend/utils/dialog_context.py` `is_likely_follow_up` | 新增:基于用户文本的轻量续问判定(关键字/短句规则),用于决定是否需要注入上文。 | +| `api_server.py` `_load_session_text2sql_context` | 调整:新增 `user_text` 入参;根据 `is_likely_follow_up(user_text)` 选择 `max_pairs=2` 或 `0`,并据此构造 `dialog_context`。 | +| `api_server.py` 两个入口 | 调整:`/g3sb/api/nl/chat` 与 `/g3sb/api/nl/chat/stream` 调用 `_load_session_text2sql_context(request, text)`。 | + +## 3. 调用方与影响范围分析 + +- **调用方**:`/g3sb/api/nl/chat`、`/g3sb/api/nl/chat/stream`(请求带 `session_id` 且历史不为空时生效)。 +- **行为变化**: + - **新话题**(非续问):`dialog_context` 变为空(不再携带历史摘要),降低串话风险。 + - **续问**:仅携带最近 **2** 轮(原默认最多 8 轮),降低旧话题回流概率。 +- **破坏性变更**:否(对外 API 入参/出参未变;仅内部上下文组装策略变化)。 + +## 4. 风险与回滚 + +- **风险级别**:中(可能把少量“隐式续问”误判为新话题,导致指代消解能力下降;但能显著降低跨话题污染)。 +- **回滚**:回退本次提交(或将 `max_pairs` 固定恢复为 8 / 去掉续问判定)。 + +**回滚方式是否简单**:是。 + +## 5. 验证与测试 + +- 建议手工: + - 同一 session:话题A生成 SQL → 话题B(无续问词)应不再引用 A 的表/条件。 + - 同一 session:首轮查询 → 次轮“再/按上面/沿用口径”续问,应仍能沿用上轮 SQL 的业务口径。 + +## 6. 配置变更 + +- 无。 + # Impact Analysis Report — 库探针追问与交付分支(追加) ## 1. 改动概览 diff --git a/TASK_SUMMARY.md b/TASK_SUMMARY.md new file mode 100644 index 0000000..e8b7600 --- /dev/null +++ b/TASK_SUMMARY.md @@ -0,0 +1,32 @@ +## 任务基本信息 + +- **任务**:方案A:同一聊天框多话题时避免上下文污染(新话题禁用 `dialog_context`) +- **项目**:`backman-camel`(FastAPI Text2SQL API) +- **范围**:后端接口 `/g3sb/api/nl/chat`、`/g3sb/api/nl/chat/stream` 的会话上文注入策略 + +## 改动说明 + +- **新增**:`backend/utils/dialog_context.py` 增加 `is_likely_follow_up(user_text)`,用于轻量判断是否为续问/沿用口径。 +- **调整**:`api_server.py` `_load_session_text2sql_context(request, user_text)` 在构造上文时: + - **续问**:注入最近 2 轮会话摘要 + - **新话题**:不注入历史摘要(`max_pairs=0`) +- **目的**:减少多话题情况下历史 SQL/条件回流导致的串话与错误 SQL。 + +## 影响与风险 + +- **破坏性变更**:否(对外 API 不变) +- **风险等级**:中 + - 可能将少量“隐式续问”误判为新话题,导致指代消解能力下降 + - 但能显著降低跨话题上下文污染导致的 SQL 错误 +- **回滚**:回退本次改动即可恢复旧策略(或将 `max_pairs` 恢复为默认值 8) + +## 测试与验证 + +- 建议手工验证: + - 同一 session:先做话题A数据查询,再提一个完全不同话题B(无“再/按上面”等续问词),应不再引用 A 的表/过滤条件。 + - 同一 session:首轮查询后,第二轮使用“再/按上面/沿用口径”等续问词,应仍能续用上轮口径生成 SQL。 + +## 后续事项 + +- 若误判率偏高,可迭代 `is_likely_follow_up` 规则(补充关键词/短语),或升级为轻量 LLM 判别器(方案B)。 + diff --git a/__pycache__/api_server.cpython-312.pyc b/__pycache__/api_server.cpython-312.pyc index b8a486778a160b42c3716e22c97c028cdb541508..00a519a40d8332e5849623524bcedc6eef12a937 100644 GIT binary patch delta 7923 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%0A)BL z;*Gs|S>)N<(2$3)>4f-lZ~jb*bBT+Lb2*%65x>^JG0%qoEP9n#vhR4R#H@d^09;Os t{oB4WRx*PXUQC~H*#_VL%$#;vhVNy&#h&|T2bBJNeJtxht1O}1{|B}6o>Tw; delta 7748 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 Dict[str, Any]: async def _load_session_text2sql_context( request: NLChatRequest, + user_text: str, ) -> tuple[str, bool]: """ 在写入本轮之前读取会话历史,构造 Text2SQL 上文,并判断上一轮助手是否为数据查询。 @@ -266,7 +268,9 @@ async def _load_session_text2sql_context( if not items: return "", False last_data = last_assistant_was_data_query(items) - block, _n = messages_to_text2sql_context(items) + # 方案A:仅在“续问/沿用口径”时注入少量上文;新话题直接清空,避免上下文污染 SQL。 + max_pairs = 2 if is_likely_follow_up(user_text) else 0 + block, _n = messages_to_text2sql_context(items, max_pairs=max_pairs) return block, last_data @@ -377,7 +381,7 @@ async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]: return text = request.message.strip() orch = get_orchestrator() - dialog_block, last_data = await _load_session_text2sql_context(request) + dialog_block, last_data = await _load_session_text2sql_context(request, text) classified = await asyncio.to_thread( classify_dialog, text, @@ -461,7 +465,7 @@ async def nl_chat(request: NLChatRequest): text = request.message.strip() logger.info(f"[API] 问题: {text[:100]}...") orch = get_orchestrator() - dialog_block, last_data = await _load_session_text2sql_context(request) + dialog_block, last_data = await _load_session_text2sql_context(request, text) classified = await asyncio.to_thread( classify_dialog, text, diff --git a/backend/llm/openai_client.py b/backend/llm/openai_client.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/utils/__pycache__/dialog_context.cpython-312.pyc b/backend/utils/__pycache__/dialog_context.cpython-312.pyc index 12aaefce733078e20e03ea967fb9451889a57ab0..a12f9d8931db298b2dffef5ef0a85ba3e6d16097 100644 GIT binary patch delta 1997 zcmZ8i{ZA8j7{9yr=nHQZDxh;(#SPAh%Hpy)H@Ax5rYH(^FE#9fy^|IDLcVQvm}V_1 z0~IEu4w-`}h{9Bq4Kq=2`~k~04JNvCi;4D*HZhTf?U!Xg?0K$K%)U*Y=kq+@=k1>7 zx$CcM2G$k)l%8&+;5@WGbXJ-v>M;t*qfG#M=1E6EVMya*?W{lxT33o&XVtR zH@J;Sx33|{kPfBzA60;>C z*s}$bU^t?+n}vCT5%_!|OGpKtBV-F{z;i{DkS=6&GY0DUpI{a;kEGc18Z_Mej$eKb z1qz_9Livlf;MCZ_)Ywo^Zf{l2UJokYPfVR048|t9l&-76sipzt)Id;fIjtOR3r0te z#e4dYMMuL*Pwy;>j$TBhTvipaiDB^m8kAK#%MpPgBBk}{tUn+*l!z#I4=O|b@|l}c zyV*vaj|ZoQzL`a_iDqT2 zKPmK{mz$b`vEK7ZMcKqHa1KVtyX4l+q;mMM^3}CjL22t#6Seh0BF-^8M0Ex%Pz^=V zGuNnyPE*V=evlF;NGHcFX!b3nD3ar!T_TFA(?zUocK$O9LN{prhNS2J?LyD&k`b#Y zjtwYaZ?wRPjx|BsqBp;UX(=t&mF~;2TUV6MW&m>I=||yi7@ypJ0VW$ib>&gGXX^Bk z*sZa6^9i}7U+Elr96qFmv5|miu@r5v$W4v0E2GNDpxks`9`1;Tnorq5s1jp#cYyEWc8Avd*w2;;-@zw1@bM8JEi#UfEZ%2xp-Oiiaz#_VHD+V|YkFS(;%GO1r0w*Hoyc0bb`)frog z5ASc!IuyK{x8h!2@twTl;iY%;*51#|{yjDGu4&ml6L-hN4KAHDt(;6Px~(mmfsmAg zK?*0*Pq!~7IPN&^QUF)xQTPI^0>%ZW(z~i zBTtykEWI$YR)3&yG1{^9HN@|eH2cH`iQZ50LFdC9xFPBxS&>Qoa`rXQtr_`OU#AVN z0;twerkYE}O;($g-?^)_@?#rWgqIkZGe~+O?iYzq6i6Xz)iUwRL|#JjG7=8S3M838 zIGw~g{i53^(QdLDwQG=IQKT3N2F~#5fX-F-S9(7CHfXkwEXpWhUw9p$q{ZP8{F;(y z)sizo8i zbxO2Hq65SP%1Excn$C&@%*)s+5FI1k<_B~L{uU@ss~V^Yq!c3h1H_Yf=oFF%_le94 z07)9B$4_iY9XP7bpmynbEtd0-x!mdV@80Be_;El;{$ncj z0hRH9GDQB!T~RQtr*bUqm8a|-_GyMXKl^X7YR_I35+=oCcwq|NXibzae=<6N$H?!nh(p{M; zs+ei2ni(21vou5F8?vd>EY-xEqdHB9InS~*NmI`wn)Lrib2Po7ntN8GMm{Kz55YU- zS(!`UFtv~FzCM0sM7iR6U@h@zi#frfS`JFefUY$?@SV9?k3mid^T7-CT4YD+d{?h1 zBo~}at&HpyJXe-x!E~gtH3-ToRBu;uIErP)e{RA zuix#fTdp@VVa<6n;@OW?YR+n-0io=a*cVlWE^p$w(CQ70&~F*S5T$F`X@9B3x*5d% z4Wlop6pLwm9Ug17=jSbFKByPZKODr<2a(pBleK%zvHH~b_2&51+U+~xj|E}Vu>F9Q zzL5Z{1RYPrFW7DBx7bB6#S(v7_lba?Q9{UeBtqn0afu9WNy$wq6X>O*ksURdEse>T F;Ws|?#(e+) diff --git a/backend/utils/dialog_context.py b/backend/utils/dialog_context.py index ad3d4b3..1b9209f 100644 --- a/backend/utils/dialog_context.py +++ b/backend/utils/dialog_context.py @@ -6,6 +6,7 @@ from __future__ import annotations import json import logging +import re from typing import Any, Dict, List, Tuple logger = logging.getLogger(__name__) @@ -14,6 +15,28 @@ _MAX_ASSISTANT_SQL_CHARS = 1400 _MAX_ASSISTANT_TEXT_CHARS = 900 _MAX_BLOCK_CHARS = 7500 +# 续问/指代常见触发词:用于判定是否需要注入会话上文,避免多话题串扰。 +# 规则应偏保守:宁可把新话题当作“无上文”也不要带入无关上下文污染 SQL。 +_FOLLOW_UP_PATTERN = re.compile( + r"(再|继续|同样|沿用|还是|照旧|刚才|上面|上一条|上一个|上次|上述|这个SQL|这条SQL|按上面|按刚才|在此基础上|同一口径|同口径|按之前|改成|改为|加上|加一下|筛一下|过滤一下|补充|补一下|追加|优化一下|调整一下|换成|换为)", + re.IGNORECASE, +) + + +def is_likely_follow_up(user_text: str) -> bool: + """ + 仅基于用户本轮文本做“是否续问”的轻量判断。 + True -> 允许注入少量上文(最近 1~2 轮),用于指代消解/沿用口径 + False -> 新话题,禁用上文,避免上下文污染 + """ + t = (user_text or "").strip() + if not t: + return False + # 很短的“再来一个/同上/继续”等通常是续问 + if len(t) <= 10 and _FOLLOW_UP_PATTERN.search(t): + return True + return bool(_FOLLOW_UP_PATTERN.search(t)) + def _truncate(s: str, max_len: int) -> str: s = (s or "").strip() diff --git a/data/embeddings/chroma_fewshot/9756e6ea-6d51-4e24-a490-4a58f0a585b9/length.bin b/data/embeddings/chroma_fewshot/9756e6ea-6d51-4e24-a490-4a58f0a585b9/length.bin index a1bf4d6e03c2efaa3385e05954df08afd771801a..e601c072013a0927a4bab1aee495b794467520a8 100644 GIT binary patch literal 4000 zcmeHKcYG8@6#jPaa+h+sTzUwE&|3rqq>DrpR1`Z12qwT0;D8V=2Ly6wsCuC&2r7yN zjo19+fcfZ+hUYU7s-|W1Z%UjudT9yQ4 zhWFPHoR%&3YJ4a*gyzKP*tFrl^Sv5NwzZrNYOM* zZ;+#8kmk1_b%2K1%2dr?ddDv5v<{E+h#an~;m~6>^14uNR=a41IhiG9d?~ zz|sxwxAin#>O%>#CV7Z_?MNjZEsBx2~&6>B!xTpS_ z+wPk79XfXE+@px)N{euQS zkd-}T=rHH-oDm~Oxkir}n>#LVygT1BVdA8M$x{lwz6Xn@PMbbs=B$Sv_7~5dGk4x2 zkIrB4*uq7RKk?+^r=DK&%(Kruzx0I{OI}*`@++^t_IhdA@;6qjd~?<6HEZ8`d)+(l zuHUe6Q+dVa_qJ@^wtdIWUAy<}egA`fAAYp|z{j6_`q}3P4;}vE%dfsZa`f2oZ@&HR z`yWo6{PCw#r+=4mDXv4wrGbAXpfHc>x9lE9n5VQc+I7JDI`p0yRvJLl6Q-xV%dm<>JAFw>Ih^Z z8$&P@!{Eelo*1+Zf$Fx8x=htiK>amLRI;_STti`q<*#>OHCX|zxz1V{- zIEF*mjvd&ET{wgNIDrE})`xMBqW494EtH>LM^T02fqEp$br`p&a;#A_$3%`|+qC3- zH;!U0e4O9NQQ_$0tD^|yg-zj(74BG}Gl7v3#W99sGRJg|tvPn*n8mS(V>w4v$aTjG zuL_E)2cW2W0E(&yps0EPimC^osCod3st2H`>Dq*fst2IZnZ`&_vp5!UEa#{SxfX!J z%MxKwX`cvp9a@t=eDW5hV0-D?SocIc&+qv`tM zPWPk>jn^*5I_;V+mOKm>S_2Kcf03meW1Q#-FZppae`6-Cq#AsN+F5F>b~0f@YH8G3 zP-9>3Inq^8J5TKbHTnkCi_{nez2`_W4I$yreZgyUC)SipI-ATUlWZ1s#KaCOA~T%| zRywQbPNE9}ProLa->&-ojW54;KV+tKjnnLOl&|nt@^R&R2<(gh|9)UKfa;C*AB*)3 za!ob*qDSZG9I~DvcmwGyOc7Pg7f&|%hEDXHwS2E+LeZuuDx!bi@6Ee1jWeP%Z)nqnwrbSe_McHq~ux#yA4_(XJgW8CaNHa`_=wQ~L{)uO^G{GWRL`Rbv$**i}op|a-I z%D3`=viRcRXxuzg?>~4XHkWAH5L+(tH*BY^(@t5~x~)r?Ve9jscDNtTPF1~o5(zyX z`FZ)h@TPm4!n1MnzE%DU1g23U+r(ng(PhVk*lq3BVaNYMcDT8>It##kH22-Zb=M80 zVeh`fDDrViG`oALp-dOcZ;f7gxC7kb&YlVK`SE3F5}nL=IUIt?XsZ89yuaK4?Uvu)z9&_5G#k4Gw0am_@y#A2? zh+-QQ?k8R6%ZPDYF@|OIw@kDLOYXeA)UVw3>4LnX;lCJz0#&HCUw_b+n2B+@gP4fr zwhW!<3)zSX{h;?vTx*plI8%$SWnX2x)8M|`SQDRz(>mFhxWJ43L%mWTa3sH+G3e4G zOUXdayJMZ@pbmIIZH%qM<@>-+k$t(E{Dz9k9xpGiGe@mk}t?6^% zz!S~jidJJXaEnvq7GHYJPRI{FoX&iY1T`E+nH<6wesD^sR)XS`%nv+WkDkYeWo>OCFp@u}CnIz$_Cn2sL!;e2`{XVlm$@w={d zlQ@=Z{aG`67ynDGHMz-nypRXZvU9?%(hLvk0o{m~{IeIRDf%VnXR@K!ytDlP# z$*_~%LvN_^4MuN0qgd`~=4__7X3C9zNk8gV4#_3wV2*5?e7k<+&KUX-|BLV)k~s8= P*C*+j?i{42Eob}zkr(Y`