## 任务基本信息
- **任务**:方案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。
- **新增(本次补充)**:`backend/llm/openai_client.py`
- 提供 `OpenAIClient.chat` / `chat_with_json`(以及与 DeepSeekClient 对齐的若干便捷方法),用于接入 OpenAI 或 OpenAI 兼容网关。
- `.env` 增补 `OPENAI_MODEL/OPENAI_CHAT_MODEL` 的注释示例(不影响现有配置)。
## 影响与风险
- **破坏性变更**:否(对外 API 不变)
- **风险等级**:中
- 可能将少量“隐式续问”误判为新话题,导致指代消解能力下降
- 但能显著降低跨话题上下文污染导致的 SQL 错误
- **回滚**:回退本次改动即可恢复旧策略(或将 `max_pairs` 恢复为默认值 8)
## 测试与验证
- 建议手工验证:
- 同一 session:先做话题A数据查询,再提一个完全不同话题B(无“再/按上面”等续问词),应不再引用 A 的表/过滤条件。
- 同一 session:首轮查询后,第二轮使用“再/按上面/沿用口径”等续问词,应仍能续用上轮口径生成 SQL。
- 已执行:
- `python -m py_compile backend/llm/openai_client.py`
## 配置说明(补充)
- **LLM 切换**:通过 `.env` 的 `LLM_SERVICE_CODE` 在 `deepseek` / `openai` 之间切换(留空则按 Key 自动选择,优先 deepseek)。
## 前端参数适配(补充)
- **lang_code**:支持 `zh`(简体)、`tc`(繁体)、`en`(英语);在对话分支的默认引导文案/空输入提示中生效。
- **model**:请求体可传 `model` 覆盖默认模型名(与 `service_code` 搭配使用),用于按请求临时切换模型。
## 流式输出(补充)
- **`/g3sb/api/nl/chat/stream`**:`chat` 与 `sql_gen` 阶段的正文改为多段 SSE 分片推送(默认每段约 64 字符,可用环境变量 `SSE_STREAM_CHUNK_CHARS` 调整),与前端 `onDelta` 累加逻辑一致。
- **重复 SQL 修复(补充)**:为避免同一次 SSE 响应中出现两段 SQL(LLM 自吐 `...` + 服务端末尾补发 `{"sql":...}`),后端在透传 LLM delta 时会过滤掉任何 `...` 段,仅保留流结束时的标准结构化 `` 片段供前端解析。
- **现状约束**:由于当前前端会直接拼接展示 delta 且保留 ``,流式接口默认**不再补发**结构化 `{"sql":...}`,避免“SQL + 可见 ``”造成重复展示。
- **如需补发**:设置环境变量 `SSE_APPEND_SQL_DATA_TAG=true` 才会在流末尾补发结构化 ``(仅建议给会过滤 `` 的客户端使用)。
## 后续事项
- 若误判率偏高,可迭代 `is_likely_follow_up` 规则(补充关键词/短语),或升级为轻量 LLM 判别器(方案B)。