From 70c8e90f2eaefc3584994de04ed7d8ec2e3eaa22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=BE=85=E5=85=83?= <2401926342@qq.com> Date: Thu, 16 Apr 2026 15:49:03 +0800 Subject: [PATCH] Update environment configuration to switch OpenAI model from `gpt-5.4` to `gpt-4o-mini`. Introduce `_effective_llm_route_from_request` function in `api_server.py` to determine the effective LLM routing based on service keys and model compatibility. Update chat event handling to include LLM routing information in response data. Enhance logging for better traceability of API interactions. --- .env | 4 +- __pycache__/api_server.cpython-312.pyc | Bin 51850 -> 53257 bytes api_server.py | 34 +++++++++++++ logs/text2sql_api.log | 68 +++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 51a1bd1..4c48eb6 100644 --- a/.env +++ b/.env @@ -13,8 +13,8 @@ MODEL_PRIMARY=deepseek-chat OPENAI_API_KEY=sk-proj-FEb2ChHZK5Llm0tBkmNIT3BlbkFJbu0b0zQpTW8762yD6HDv OPENAI_BASE_URL=http://113.192.49.54:9080/v1 -OPENAI_MODEL=gpt-5.4 -# OPENAI_CHAT_MODEL=gpt-4o-mini +OPENAI_MODEL=gpt-4o-mini +# OPENAI_CHAT_MODEL= # 模型配置 # 主生成模型 diff --git a/__pycache__/api_server.cpython-312.pyc b/__pycache__/api_server.cpython-312.pyc index 0b55948dff330bfdc5d915542aca843f2601e585..b19096017a740fe726a4d67c01cee1dcb2e3661e 100644 GIT binary patch delta 8358 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 D(r@s; diff --git a/api_server.py b/api_server.py index ffecb31..bb1311b 100644 --- a/api_server.py +++ b/api_server.py @@ -275,6 +275,36 @@ def _conversation_nl_dict(reply: str) -> Dict[str, Any]: } +def _effective_llm_route_from_request(request: NLChatRequest) -> Dict[str, Any]: + """ + 计算“本次请求实际使用的 LLM 路由信息”(用于前端联调回显)。 + 注意:此处仅回显路由结果,不包含密钥等敏感信息。 + """ + model = _normalize_model_label(request.model) + sc = _infer_service_code(request.service_code, model) + + sc2 = sc + if sc2 == "deepseek" and not _has_deepseek_key(): + if _has_openai_key(): + sc2 = "openai" + if sc2 == "openai" and not _has_openai_key(): + if _has_deepseek_key(): + sc2 = "deepseek" + + # 与 _maybe_override_orch_llm 保持一致:网关不兼容时丢弃 model 覆盖,让下游走默认模型 + effective_model = model + if effective_model is not None: + if (sc2 or "").strip().lower() == "openai" and "deepseek" in effective_model.strip().lower(): + effective_model = None + elif (sc2 or "").strip().lower() == "deepseek" and effective_model.strip().lower().startswith("gpt"): + effective_model = None + + return { + "service_code": sc2, + "model": effective_model, + } + + def _normalize_lang_code(code: Optional[str]) -> str: raw = (code or "auto").strip() if not raw: @@ -670,6 +700,7 @@ async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]: async for pkt in _sse_stream_text_chunks("chat", reply): yield pkt data_dict = _conversation_nl_dict(reply) + data_dict["llm"] = _effective_llm_route_from_request(request) yield _sse_data({"code": 200, "msg": "success", "data": data_dict}) await _append_session_if_needed(request, text, data_dict) return @@ -760,6 +791,7 @@ async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]: pass data_dict = _nl_dict_from_generation(result) + data_dict["llm"] = _effective_llm_route_from_request(request) msg = "success" if result.valid else "partial" yield _sse_data({"code": 200, "msg": msg, "data": data_dict}) await _append_session_if_needed(request, text, data_dict) @@ -846,6 +878,7 @@ async def nl_chat(request: NLChatRequest): reply = _localized_conversation_reply(lang) logger.info("[API/chat] 对话意图: conversation(跳过 Text2SQL)") data_dict = _conversation_nl_dict(reply) + data_dict["llm"] = _effective_llm_route_from_request(request) await _append_session_if_needed(request, text, data_dict) return {"code": 200, "msg": "success", "data": data_dict} @@ -866,6 +899,7 @@ async def nl_chat(request: NLChatRequest): pass data_dict = _nl_dict_from_generation(result) + data_dict["llm"] = _effective_llm_route_from_request(request) response_data = NLChatSuccessData.model_validate(data_dict) msg = "success" if result.valid else "partial" if result.valid: diff --git a/logs/text2sql_api.log b/logs/text2sql_api.log index 7874c56..087ce80 100644 --- a/logs/text2sql_api.log +++ b/logs/text2sql_api.log @@ -105,3 +105,71 @@ ORDER BY m.ValueDate; 2026-04-16 13:48:13 INFO [agents.orchestrator] orchestrator.py:754 _validate_sql() | [validate] 程序+探针+LLM 汇总: valid=True err_count=0 warn_count=0 db_execution_status=0 sql_chars=494 2026-04-16 13:48:13 INFO [agents.orchestrator] orchestrator.py:921 generate() | [OK] SQL生成与验证通过(1次尝试) 2026-04-16 13:48:13 INFO [__main__] api_server.py:776 _chat_stream_events() | [API/stream] Text2SQL 完成: valid=True attempts=1 tables_used=['TSBTransferInstruction', 'VSBTransferInstruction', 'VSBHKRpt0431', 'VSBHKRpt0430', 'TSBAccountInstrumentMovement'] sql_chars=494 sql_head="-- 查询所有客户账户间股票转移记录\n-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移\nSELECT \n m.MovementID,\n m.AccountID AS FromAccountID,\n m.TransferToAccountID,\n m.InstrumentID,\n i.Name AS InstrumentSymbol,\n m.MovementType,\n m.Quantity AS TransferQuantity,\n m.ValueDate AS TransferDate\nFROM TSBAccountInstrumentMovement m\nLEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID\nWHERE m.MovementType = 'T'\n AND m.ValueDate = CAST(GETDATE() AS DATE)\nORDER BY m.ValueDate;" +2026-04-16 14:40:07 INFO [uvicorn.access] httptools_impl.py:483 send() | 192.168.3.210:53090 - "POST /g3sb/api/nl/chat/stream HTTP/1.1" 200 +2026-04-16 14:50:35 INFO [__main__] api_server.py:668 _chat_stream_events() | [API/stream] 开始: user_id='ACCOUNT' visitor_biz_id=None session_id='a68b69c0-d945-4553-869f-3538d42900f9' service_code='openai' model=None lang_code='zh' msg_chars=3 preview='123' dialog_context_chars=0 last_turn_was_data_query=False +2026-04-16 14:50:38 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-5.4, base_url=http://113.192.49.54:9080/v1 +2026-04-16 14:50:38 INFO [uvicorn.error] server.py:272 shutdown() | Shutting down +2026-04-16 14:50:38 ERROR [asyncio] base_events.py:1820 default_exception_handler() | Exception in callback BaseProactorEventLoop._start_serving..loop(<_OverlappedF...210', 55004))>) at D:\conda\Lib\asyncio\proactor_events.py:843 +handle: .loop(<_OverlappedF...210', 55004))>) at D:\conda\Lib\asyncio\proactor_events.py:843> +Traceback (most recent call last): + File "D:\conda\Lib\asyncio\events.py", line 88, in _run + self._context.run(self._callback, *self._args) + File "D:\conda\Lib\asyncio\proactor_events.py", line 858, in loop + self._make_socket_transport( + File "D:\conda\Lib\asyncio\proactor_events.py", line 647, in _make_socket_transport + return _ProactorSocketTransport(self, sock, protocol, waiter, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\conda\Lib\asyncio\proactor_events.py", line 613, in __init__ + super().__init__(loop, sock, protocol, waiter, extra, server) + File "D:\conda\Lib\asyncio\proactor_events.py", line 189, in __init__ + super().__init__(loop, sock, protocol, waiter, extra, server) + File "D:\conda\Lib\asyncio\proactor_events.py", line 335, in __init__ + super().__init__(*args, **kw) + File "D:\conda\Lib\asyncio\proactor_events.py", line 66, in __init__ + self._server._attach() + File "D:\conda\Lib\asyncio\base_events.py", line 296, in _attach + assert self._sockets is not None + ^^^^^^^^^^^^^^^^^^^^^^^^^ +AssertionError +2026-04-16 14:50:38 INFO [uvicorn.error] server.py:102 _serve() | Finished server process [37328] +2026-04-16 14:50:38 ERROR [uvicorn.error] on.py:134 send() | Traceback (most recent call last): + File "D:\conda\Lib\asyncio\runners.py", line 194, in run + return runner.run(main) + ^^^^^^^^^^^^^^^^ + File "D:\conda\Lib\asyncio\runners.py", line 118, in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\conda\Lib\asyncio\base_events.py", line 674, in run_until_complete + self.run_forever() + File "D:\conda\Lib\asyncio\windows_events.py", line 322, in run_forever + super().run_forever() + File "D:\conda\Lib\asyncio\base_events.py", line 641, in run_forever + self._run_once() + File "D:\conda\Lib\asyncio\base_events.py", line 1986, in _run_once + handle._run() + File "D:\conda\Lib\asyncio\events.py", line 88, in _run + self._context.run(self._callback, *self._args) + File "C:\Users\24019\AppData\Roaming\Python\Python312\site-packages\uvicorn\server.py", line 78, in serve + with self.capture_signals(): + ^^^^^^^^^^^^^^^^^^^^^^ + File "D:\conda\Lib\contextlib.py", line 144, in __exit__ + next(self.gen) + File "C:\Users\24019\AppData\Roaming\Python\Python312\site-packages\uvicorn\server.py", line 339, in capture_signals + signal.raise_signal(captured_signal) + File "D:\conda\Lib\asyncio\runners.py", line 157, in _on_sigint + raise KeyboardInterrupt() +KeyboardInterrupt + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "C:\Users\24019\AppData\Roaming\Python\Python312\site-packages\starlette\routing.py", line 645, in lifespan + await receive() + File "C:\Users\24019\AppData\Roaming\Python\Python312\site-packages\uvicorn\lifespan\on.py", line 137, in receive + return await self.receive_queue.get() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\conda\Lib\asyncio\queues.py", line 158, in get + await getter +asyncio.exceptions.CancelledError + +2026-04-16 14:50:43 INFO [utils.dialog_classifier] dialog_classifier.py:211 _classify_dialog_llm() | [dialog] intent=conversation (LLM) reply_chars=51 reply_preview='请具体说明你想查询什么数据,例如时间范围、品种、账户或指标。仅输入“123”我还无法判断你的查询需求。'