From f492e2974950fb5340278cea4e36448c17673f4b 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 16:26:58 +0800
Subject: [PATCH] Refactor `_chat_stream_events` in `api_server.py` to
standardize SSE response format by removing additional status codes and
consolidating output into a unified JSON structure. Update logging to enhance
clarity on streaming events and improve error handling. Adjust documentation
to reflect changes in event data structure.
---
__pycache__/api_server.cpython-312.pyc | Bin 53257 -> 52966 bytes
api_server.py | 17 +-
.../length.bin | Bin 4000 -> 4000 bytes
logs/text2sql_api.log | 211 +++++-------------
4 files changed, 59 insertions(+), 169 deletions(-)
diff --git a/__pycache__/api_server.cpython-312.pyc b/__pycache__/api_server.cpython-312.pyc
index b19096017a740fe726a4d67c01cee1dcb2e3661e..b4a19b4492e83e7264cd42dc27f3876897e51dbf 100644
GIT binary patch
delta 3111
zcmZuz4Ny~87Jm1=yq7>AKuGup10ou01^
UMV>3DG)>ln06;=p}$)5OAsx
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
M@^G&5%Q>z1Uw6-X%>V!Z
delta 3370
zcma)8eNmZs~veeB@$1spDxq-gI9fjWe?
zBr`&0Jc*vvq*e_V744QnDye%Q6LrP$0Fv9sW>o8*va_`v``EMZb7>Ge{jv8Pe)so$
zywCf5yzga3w)4SO-q5GlM{?}3ulsn3cgI14;In)+f#VvY8;lL626Ka@!P*ehV1o}I
zj)%6#bD-Ln3kx?{1c{SW(CeGS$N2Q{(k8P$3ZvlT=YlbiS#=lTVMW!8#WC$
zqx$wb&A2qw;WYeeR*ZIhG5#@|r2TaMr
z^D+3@r*HO@q{WNBB8t`29q-ZWM^))WutYqX+KvaV+{t(i)SJN5Gcf=)sMlDFd~Q@4*e5WEV2J+j&%Ci*8-JOHI-W`NbRQ*WM;AzahVGlHL1-y=HMxg({j_~mD9{Dx!+M(EZ!mZ?Txs5{8zZEP{(5RpQ
z$19VfnaNtid$?-ClzdYSTzNJlSIJ@go|5tZ*%Q+0Qq4cJII5;?3f3z4M|iw0l`Mw(
zy4<`3zkVyXT_xG~-V#1;Hyv%QZ{b)K`mvVd7vtNyTkmOP@krAh$((Oq*eivj0^vNU
zpIOa?D`~p6kFO@qwBLWZk$pq<@bq=&Pj@2hf+yB=!HQR-;I_4pMW007K?cJ@;at~4
z^bE?ZZQL-wbm=ns8d@T}Rb^%6UN60$>E$zP8&%}*u&DlN(~C@|xPwzmryzd`KB%{o
zX85kYf($^(^G9@S@zYC-pD3@Sn;>D`C)(kN6{Xa-q;x6#cioR<6a3Kd0EvYKf!SmW
zGzX?+DLKA`v04zS5jG<0^H_iE;~_(FNK-tdG048)lVny@Z0q#n_VYzIOqcDM2Vy#{7wva_&k=3R#^fQB
zwduZZ4V=!hrLxm={=wpYOGzlQG$fS5erl5=8>>{e4cQVl`ERw!1qY>W?i5
z845$1LYTi{YMp@-@BG2Lf%Ra0fzFddPFjguBb0
zLEUqwz<93;7xe0h+bHxJ3LH#0HC=E|Q=Q5p?y2fi**x+Y1?kMtmmIyw#Pwy9qD*z)
zZ9MW^m!l}Zjz4Q7McL}Jv6G7O`LlVXXomXi?TL(^v+J1GxfD{AC!9+akUI)~K?s>$CMH}=B_4-xG0liP*M)fvsE8+97~s{&bp+8sSk?nZgL%}>nldoPB6)~hD
zi^K^-d<61H4f7l_X+3fL(8L^%mA@1%vIv)~BGX)o!)9JeAS}~M4ibm2WUVKYzm%>R
zG6?ca!ILBFHo8>om@jBf6Fb;^9CA&wo{$b$2VaO?Oi>_vU!JWcf08@5PaxCRGmUcR
zXd|+E22K@SiTo;F%q<8l2wRyB)H{0A+tK(c^zTT}{Tb<_2s`2Wj`=y873K)V>ayihdAehn_lb0eRO&0OE%|iKb4rv|Mqhc24?f#nP4>cLZ={Jm
zEWH*v@P?kKNBaa@+uY(Arfq}&v|S+Y!TWpM;@_COUrzbU9Ad&o?orVr?4^9{Xd~3N
zyTyx4?vjVvml4tr_wLJApGJp12<&r;gN(i>AKKSK$OTx?Vbfs@8bWA<*xY}+!=dQ6?|7lf>QBXOk@p%Ve-^4d1hE#QR*vu
zk{*VIT~6_579v)z?fM;wyTB;@9${QFP&^EuzLOGt9qHO|ET*&_NfSBtRZfF~Bd5t1
zpg+1m
zj~X?t!?jfi!|3-2veWRzi44;}P?ph4MHOxa=gIlbFHv2MZpz*Y`{$VMYM40%aGkUy
z;-0AL#5fwNG)vh{(VF4>$vAQyuAX!lY*-rm!=zLy*l{9W&iU&(l@9;OQT&R~{b1;|
z*L5*EEUZ}0E*V}}ir0eTEueVxDV}cn69S%PiidPqEtM}V_mxvTniP*C#gj+zNKrgT
z6b}sDiGXvbI6aCZqc|Ljvlx!3dS*%4a#{(ydrj&nR2!hXH;d%T-}GKlspqN4o!1_g
JKX_j!{ty0mpOgRq
diff --git a/api_server.py b/api_server.py
index bb1311b..39b62af 100644
--- a/api_server.py
+++ b/api_server.py
@@ -659,7 +659,9 @@ async def _run_generate(
async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]:
if not request.message or not request.message.strip():
lang = _normalize_lang_code(request.lang_code)
- yield _sse_data({"code": 400, "msg": _localized_empty_input_reply(lang), "data": None})
+ yield _sse_data(
+ {"stage": "sql_gen", "stream_kind": "content", "content": _localized_empty_input_reply(lang)}
+ )
return
text = request.message.strip()
orch = get_orchestrator()
@@ -696,16 +698,13 @@ async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]:
len(reply),
reply[:500] + ("…" if len(reply) > 500 else ""),
)
- yield _sse_data({"stage": "orchestrator", "stream_kind": "content", "content": "CHAT"})
- async for pkt in _sse_stream_text_chunks("chat", reply):
+ async for pkt in _sse_stream_text_chunks("sql_gen", 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
- yield _sse_data({"stage": "orchestrator", "stream_kind": "content", "content": "DATA_QUERY"})
dialect = resolve_sql_dialect(os.getenv("TEXT2SQL_DIALECT", "sqlserver"))
dc_ctx = (dialog_block or "").strip() or None
top_k = 20
@@ -759,7 +758,7 @@ async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]:
result = holder["result"]
except Exception as e:
logger.error(f"[API/stream] 生成异常: {e}", exc_info=True)
- yield _sse_data({"code": 500, "msg": str(e), "data": None})
+ yield _sse_data({"stage": "sql_gen", "stream_kind": "content", "content": str(e)})
return
sql_out = (result.sql or "").strip()
@@ -792,8 +791,6 @@ async def _chat_stream_events(request: NLChatRequest) -> AsyncIterator[bytes]:
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)
@@ -919,8 +916,8 @@ async def nl_chat(request: NLChatRequest):
async def nl_chat_stream(request: NLChatRequest):
"""
自然语言对话流式接口(SSE)。
- 事件体为 JSON:分片 `data: {"stage","stream_kind","content"}`(例:sql_gen 时
- `stream_kind` 为 `content`)或结束包 `{code, msg, data}`。
+ 事件体为 JSON:仅发送分片 `data: {"stage":"sql_gen","stream_kind":"content","content":"..."}`,
+ 流结束表示完成;不再发送额外的结束包。
"""
return StreamingResponse(
_chat_stream_events(request),
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 35d3e3f2d1dd4c04ee0c6f4a11e8ce5956420f64..d1fa5fe9b7b0ce3292b49c25b0aa11a055477be1 100644
GIT binary patch
literal 4000
zcmXRowdChCMh1q4oEiT?Gy{VK2Z%huIUOt>!_dOO1ms7sfkYV?ws=G6h!YUH@MSlc
z!3^PIu#tqR!sLgV;=|y`5Wo<^;148q8O#_=8JvKmH-kBY1yGcMfd#6L5yD^<1@hBp
zurp8k)VeD4++|s?SHWsPzGGm3@nJL<0}oi70qlDy6G%aW0WQD_Wf?J;Fc>fxGFSrn
zFf-taMj4|aFd71*Aut*OqaiRF0;3@?8UmvsFvvncQb{9*fsdhKkU4AAIin#kqC)@x
DbKM(I
literal 4000
zcmb7`TW}o36^46uXLe_#z3aBSl2&W$W?8-p6JsvEV_6s57~8Vk#x{c4wJlGFgb=WC
zf>ntz3(3P&K~+@2Z@l3bic1w$yZ}j6s={rJ9=rurDJOXXUfNner1F&0=ZqjTTB1sq
zT7ABA`ah?8EJ
zjGOFbFaBFE{-qZueUyFT#YrDwfA!)^`UNk(r1#g4ve$k3<@H|+=>7Fg_M%T8VP6BQ
z{ZV}@|CfN?Uw`HO|1O~S*N?LA0`>j-xAJcU^#1x$_K{D&eE)9;^#1xLdF?zW?C*
z{qLYUYZ^;H@6bZ*
zIt#)45X=w3+z@C&Fu%Xn(>pg>IkTYm)>aS9jl0POeV|tCo7-P`YC-R-^$*P*aCa=|
zL$%()xe2#tK_8U*DJ>VNna!0c8CK?PGgc`}LzyzdtVHEm8AULem2@N0LTF-E9HuoR
z#F&+G+hrUfL7F5&N=-W}(+C+Ac}}(0th75QI}ozWidBxu970|tD9KKQ
zE~PPKH$s6~ZEi{SAQYL^?p~Iw5LPoQ<34bw7okrTy)63?22{2Sau8vS(!3yt5Y{Tq
zb~%i&PAzAHT#vAUS=sr5+=#G=>TE_Bq15*vY@yWmBK$;cVM=aAxKBmOavQ?^YSm@=
z0K$WGsUAYuPSbWE?9`am;*QB(8scui?0in{A>0d?n;%+ym~bCpta3t*67B~~R4&Oe
z!g0W)Ysm@1NkEnP0O3K@PRT=rj{vI09wvO$!y|-80o9E@MmPni9*^UM(}1zcv^+t`
zQF~6FBzz1fUzDc^PXlJ$`{WtI#{rYBDQ5_u092`-B(yzkiLgxC#j}LxJnebHS-^Nj
z$P0uHM&nWt{uD6fcFU&-e+HOwACf;Od>XLDJs^KU_>70YBzzXI)jcJjBfJRM<_dX<
z@Oi+F`MA7H_$xrQj9(MJ0GM>+@(SV35G`X@i0&_-s=J49FQ6*)FyTHxwa8Jz{WN)T
zjBp%K)tw-m1dLZ4d4TXBVA74rLxhh2X50tmVZui}JVJOBu*IE}#|Wo9JWelqKRahA+yq
zgy#U&^KqVV77(7EI~NF@5KDE{;IFkriABT0Ru6+I(UkCr
zC_8TCYq@PQ4C8I9chP{+o29Hm!mzb^F=X`C&5%*7n`^;2tu+}Vce6dlq;_|=)(oC}
z+-R*AG-J0WBVl7&tMv@aFd8HGl5yJ_t{cj8w@EYhY4wP1G}U98v85i-j9tK*F^>PY
zljE+Mz`k#9GVR9J!@JET$6Gzm10F;ZxOA$71?syL_2RsyUFPgS)LU+o)dYV7oEIQbn!0H&AUZ`7jRCq(<6$!C|2>+
z$T6o^^zlBl<4(UA-~(ci4~jK>4f+z!kXXytieWx1*70@dOFHYt2EGC9l(SK6;+xP;
zJDbG_AJJIJn1!P-*h=wPI1z&lyl^lE8+hS-3^wq>F&S*&h0`+F%0>w;z&wlSeg8tRu?=2m@5%y*uLvP() | [OK] 已加载配置文件: C:\Users\24019\Desktop\backman-camel\.env
-2026-04-16 13:35:29 INFO [__main__] api_server.py:1120 () | 启动服务: http://0.0.0.0:8041
-2026-04-16 13:35:29 INFO [__main__] api_server.py:1121 () | API文档: http://0.0.0.0:8041/docs
-2026-04-16 13:35:29 INFO [uvicorn.error] server.py:92 _serve() | Started server process [37328]
-2026-04-16 13:35:29 INFO [uvicorn.error] on.py:48 startup() | Waiting for application startup.
-2026-04-16 13:35:29 INFO [__main__] api_server.py:811 lifespan() | ============================================================
-2026-04-16 13:35:29 INFO [__main__] api_server.py:812 lifespan() | Text2SQL API Server 启动中...
-2026-04-16 13:35:29 INFO [__main__] api_server.py:813 lifespan() | ============================================================
-2026-04-16 13:35:29 INFO [main] main.py:126 setup_environment() | [OK] 环境检查通过
-2026-04-16 13:35:29 INFO [main] main.py:127 setup_environment() | - Schema: data\schemas\G3SB_MCDataDictionary_table_structure.json
-2026-04-16 13:35:29 INFO [main] main.py:128 setup_environment() | - LLM: openai
-2026-04-16 13:35:29 INFO [main] main.py:154 load_schema() | 加载Schema: ./data/schemas/G3SB_MCDataDictionary_table_structure.json
-2026-04-16 13:35:29 INFO [main] main.py:156 load_schema() | 表注释(meta): ./data/schemas/G3SB_MCDataDictionary_table_meta.json
-2026-04-16 13:35:30 INFO [schema.loader] loader.py:107 load_from_json() | [OK] 加载Schema完成(G3SB schemas): G3SB_MCDataDictionary_table_structure, 共2516张表
-2026-04-16 13:35:30 INFO [main] main.py:163 load_schema() | [OK] Schema加载完成: G3SB_MCDataDictionary_table_structure, 共2516张表, 59196个字段
-2026-04-16 13:35:33 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 13:35:35 INFO [utils.embedding] embedding.py:144 __init__() | 使用 OpenAI Embedding API:model=text-embedding-ada-002,base_url=http://113.192.49.54:9080/v1,max_batch=100
-2026-04-16 13:35:37 INFO [utils.fewshot_chroma_store] fewshot_chroma_store.py:86 __init__() | [OK] FewShotChromaStore: 磁盘 data\embeddings\chroma_fewshot collection=fewshot_samples count=50
-2026-04-16 13:35:37 INFO [utils.fewshot_selector] fewshot_selector.py:128 _init_chroma_mode() | [Few-shot] 已从向量库加载(Chroma 50 条,data\embeddings\chroma_fewshot)
-2026-04-16 13:35:37 INFO [utils.fewshot_selector] fewshot_selector.py:159 _init_chroma_mode() | [OK] Few-shot 使用 Chroma(50 条)
-2026-04-16 13:35:37 INFO [agents.orchestrator] orchestrator.py:116 __init__() | Few-shot已启用: top_k=3, min_rating=7
-2026-04-16 13:35:37 INFO [agents.orchestrator] orchestrator.py:127 __init__() | [OK] Text2SQLOrchestrator初始化完成: max_retry=2, use_vector_search=True, fewshot=on, nl→zh_norm=on
-2026-04-16 13:35:37 INFO [__main__] api_server.py:132 get_orchestrator() | [OK] Orchestrator 初始化完成
-2026-04-16 13:35:37 INFO [__main__] api_server.py:817 lifespan() | [OK] 服务已就绪
-2026-04-16 13:35:37 INFO [uvicorn.error] on.py:62 startup() | Application startup complete.
-2026-04-16 13:35:37 INFO [uvicorn.error] server.py:224 _log_started_message() | Uvicorn running on http://0.0.0.0:8041 (Press CTRL+C to quit)
-2026-04-16 13:35:52 INFO [uvicorn.access] httptools_impl.py:483 send() | 127.0.0.1:23615 - "POST /g3sb/api/nl/chat/stream HTTP/1.1" 200
-2026-04-16 13:35:52 INFO [__main__] api_server.py:668 _chat_stream_events() | [API/stream] 开始: user_id='anonymous' visitor_biz_id=None session_id=None service_code=None model='gpt-4o-mini' lang_code='auto' msg_chars=15 preview='所有客户账户之间的股票转移记录' dialog_context_chars=0 last_turn_was_data_query=False
-2026-04-16 13:35:55 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
-2026-04-16 13:35:55 INFO [utils.dialog_classifier] dialog_classifier.py:261 classify_dialog() | [dialog] intent=text2sql (hybrid fast: query hint) preview='所有客户账户之间的股票转移记录'
-2026-04-16 13:35:55 INFO [__main__] api_server.py:715 _chat_stream_events() | [GEN/API/stream] dialect=tsql top_k=20 dialog_context_chars=0 question_len=15 preview='所有客户账户之间的股票转移记录'
-2026-04-16 13:35:57 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
-2026-04-16 13:36:00 INFO [agents.orchestrator] orchestrator.py:803 generate() | [GEN] 问句已归一中文:所有客户账户的股票转移记录
-2026-04-16 13:36:00 INFO [agents.orchestrator] orchestrator.py:816 generate() | [GEN] 开始生成SQL: question_chars=13 preview='所有客户账户的股票转移记录' dialog_context_chars=0
-2026-04-16 13:36:00 INFO [agents.orchestrator] orchestrator.py:831 generate() | 尝试 #1
-2026-04-16 13:36:00 INFO [schema.indexer] indexer.py:82 __init__() | [OK] 初始化SchemaIndexer(Chroma磁盘 path=data\embeddings\chroma): collection=schema_tables, count=2516
-2026-04-16 13:36:00 INFO [schema.indexer] indexer.py:106 ensure_index_for_schema() | Schema 向量索引已就绪(2516 张表),跳过向量化
-2026-04-16 13:36:00 INFO [agents.orchestrator] orchestrator.py:188 _coarse_filter() | [Orchestrator] 开始向量检索: query_chars=13 query_preview='所有客户账户的股票转移记录'
-2026-04-16 13:36:02 INFO [utils.embedding] embedding.py:163 _set_dim_from_vector() | [OK] Embedding 向量维度:1536
-2026-04-16 13:36:03 INFO [schema.indexer] indexer.py:244 search() | Schema 向量检索: query_chars=13 命中=20(阈值=0.1)top=[('VSBHKRpt0430', 0.8264), ('VSBHKRpt0431', 0.8188), ('TSBTransferInstruction', 0.8147), ('VSBTransferInstruction', 0.8134), ('VSBHKRpt0397', 0.8126), ('VSBHKRpt0672', 0.8117), ('VSBHKRpt0090C', 0.81), ('VSBHKRpt0570', 0.8084), ('VSBHKRpt1030A', 0.8077), ('VSBRpt0999E', 0.8065), ('VSBRpt0999C', 0.8064), ('TSBAccountEntitlementRelease', 0.8063), ('VSBRpt0999A', 0.8059), ('TSBAccountInstrumentMovement', 0.8038), ('VSBTransferInstructionGenerationByAccountContract', 0.8033)]
-2026-04-16 13:36:03 INFO [agents.orchestrator] orchestrator.py:204 _coarse_filter() | [Orchestrator] 向量粗筛: 命中=20 张(阈值内),表名+分: [('VSBHKRpt0430', 0.8264), ('VSBHKRpt0431', 0.8188), ('TSBTransferInstruction', 0.8147), ('VSBTransferInstruction', 0.8134), ('VSBHKRpt0397', 0.8126), ('VSBHKRpt0672', 0.8117), ('VSBHKRpt0090C', 0.81), ('VSBHKRpt0570', 0.8084), ('VSBHKRpt1030A', 0.8077), ('VSBRpt0999E', 0.8065), ('VSBRpt0999C', 0.8064), ('TSBAccountEntitlementRelease', 0.8063), ('VSBRpt0999A', 0.8059), ('TSBAccountInstrumentMovement', 0.8038), ('VSBTransferInstructionGenerationByAccountContract', 0.8033), ('VSBRpt0060', 0.8021), ('XCGatewayStockReconciliationReport', 0.802), ('TSBAccountEntitlementHold', 0.8013), ('WSBBatchLocationTransferDetail', 0.8012), ('VCAccountCashMovement', 0.8012)]
-2026-04-16 13:36:07 INFO [agents.orchestrator] orchestrator.py:258 _llm_select_tables() | LLM精筛选中表:['VSBHKRpt0430', 'VSBHKRpt0431', 'TSBTransferInstruction', 'VSBTransferInstruction', 'TSBAccountInstrumentMovement'] | reasoning_chars=181 reasoning_preview='问题涉及客户账户的股票转移记录,VSBHKRpt0430和VSBHKRpt0431提供了客户股票的日常转移报告和账户工具移动报告,TSBTransferInstruction和VSBTransferInstruction则记录了账户转移指令,TSBAccountInstrumentMovement包含账户工具的移动交易信息,这些表共同覆盖了股票转移的各个方面。'
-2026-04-16 13:36:07 INFO [agents.orchestrator] orchestrator.py:859 generate() | 选中表:['VSBHKRpt0430', 'VSBHKRpt0431', 'TSBTransferInstruction', 'VSBTransferInstruction', 'TSBAccountInstrumentMovement'],扩展后:['TSBTransferInstruction', 'VSBTransferInstruction', 'VSBHKRpt0431', 'VSBHKRpt0430', 'TSBAccountInstrumentMovement']
-2026-04-16 13:36:08 INFO [utils.fewshot_selector] fewshot_selector.py:209 select_best_with_score() | [Few-shot] best_with_score: qid=Q2 score=0.9575 preview='列出今日所有客户账户之间的股票转移记录。'
-2026-04-16 13:36:08 INFO [agents.orchestrator] orchestrator.py:432 _generate_sql_golden_adapt() | [GEN] 黄金 few-shot 条件适配: qid=Q2 score=0.9575
-2026-04-16 13:36:12 INFO [agents.orchestrator] orchestrator.py:450 _generate_sql_golden_adapt() | 生成的SQL(黄金适配,chars=494):
+2026-04-16 16:22:05 INFO [utils.repo_logging] repo_logging.py:79 configure_text2sql_api_logging() | 日志文件: C:\Users\24019\Desktop\backman-camel\logs\text2sql_api.log
+2026-04-16 16:22:10 INFO [__main__] api_server.py:85 () | [OK] 已加载配置文件: C:\Users\24019\Desktop\backman-camel\.env
+2026-04-16 16:22:10 INFO [__main__] api_server.py:1108 () | 启动服务: http://0.0.0.0:8041
+2026-04-16 16:22:10 INFO [__main__] api_server.py:1109 () | API文档: http://0.0.0.0:8041/docs
+2026-04-16 16:22:10 INFO [uvicorn.error] server.py:92 _serve() | Started server process [33080]
+2026-04-16 16:22:10 INFO [uvicorn.error] on.py:48 startup() | Waiting for application startup.
+2026-04-16 16:22:10 INFO [__main__] api_server.py:799 lifespan() | ============================================================
+2026-04-16 16:22:10 INFO [__main__] api_server.py:800 lifespan() | Text2SQL API Server 启动中...
+2026-04-16 16:22:10 INFO [__main__] api_server.py:801 lifespan() | ============================================================
+2026-04-16 16:22:10 INFO [main] main.py:126 setup_environment() | [OK] 环境检查通过
+2026-04-16 16:22:10 INFO [main] main.py:127 setup_environment() | - Schema: data\schemas\G3SB_MCDataDictionary_table_structure.json
+2026-04-16 16:22:10 INFO [main] main.py:128 setup_environment() | - LLM: openai
+2026-04-16 16:22:10 INFO [main] main.py:154 load_schema() | 加载Schema: ./data/schemas/G3SB_MCDataDictionary_table_structure.json
+2026-04-16 16:22:10 INFO [main] main.py:156 load_schema() | 表注释(meta): ./data/schemas/G3SB_MCDataDictionary_table_meta.json
+2026-04-16 16:22:10 INFO [schema.loader] loader.py:107 load_from_json() | [OK] 加载Schema完成(G3SB schemas): G3SB_MCDataDictionary_table_structure, 共2516张表
+2026-04-16 16:22:10 INFO [main] main.py:163 load_schema() | [OK] Schema加载完成: G3SB_MCDataDictionary_table_structure, 共2516张表, 59196个字段
+2026-04-16 16:22:14 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
+2026-04-16 16:22:17 INFO [utils.embedding] embedding.py:144 __init__() | 使用 OpenAI Embedding API:model=text-embedding-ada-002,base_url=http://113.192.49.54:9080/v1,max_batch=100
+2026-04-16 16:22:19 INFO [utils.fewshot_chroma_store] fewshot_chroma_store.py:86 __init__() | [OK] FewShotChromaStore: 磁盘 data\embeddings\chroma_fewshot collection=fewshot_samples count=50
+2026-04-16 16:22:19 INFO [utils.fewshot_selector] fewshot_selector.py:128 _init_chroma_mode() | [Few-shot] 已从向量库加载(Chroma 50 条,data\embeddings\chroma_fewshot)
+2026-04-16 16:22:19 INFO [utils.fewshot_selector] fewshot_selector.py:159 _init_chroma_mode() | [OK] Few-shot 使用 Chroma(50 条)
+2026-04-16 16:22:19 INFO [agents.orchestrator] orchestrator.py:116 __init__() | Few-shot已启用: top_k=3, min_rating=7
+2026-04-16 16:22:19 INFO [agents.orchestrator] orchestrator.py:127 __init__() | [OK] Text2SQLOrchestrator初始化完成: max_retry=2, use_vector_search=True, fewshot=on, nl→zh_norm=on
+2026-04-16 16:22:19 INFO [__main__] api_server.py:132 get_orchestrator() | [OK] Orchestrator 初始化完成
+2026-04-16 16:22:19 INFO [__main__] api_server.py:805 lifespan() | [OK] 服务已就绪
+2026-04-16 16:22:19 INFO [uvicorn.error] on.py:62 startup() | Application startup complete.
+2026-04-16 16:22:19 INFO [uvicorn.error] server.py:224 _log_started_message() | Uvicorn running on http://0.0.0.0:8041 (Press CTRL+C to quit)
+2026-04-16 16:22:20 INFO [uvicorn.access] httptools_impl.py:483 send() | 127.0.0.1:14651 - "POST /g3sb/api/nl/chat/stream HTTP/1.1" 200
+2026-04-16 16:22:20 INFO [__main__] api_server.py:669 _chat_stream_events() | [API/stream] 开始: user_id='anonymous' visitor_biz_id=None session_id=None service_code=None model='gpt-4o-mini' lang_code='auto' msg_chars=15 preview='所有客户账户之间的股票转移记录' dialog_context_chars=0 last_turn_was_data_query=False
+2026-04-16 16:22:23 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
+2026-04-16 16:22:23 INFO [utils.dialog_classifier] dialog_classifier.py:261 classify_dialog() | [dialog] intent=text2sql (hybrid fast: query hint) preview='所有客户账户之间的股票转移记录'
+2026-04-16 16:22:23 INFO [__main__] api_server.py:712 _chat_stream_events() | [GEN/API/stream] dialect=tsql top_k=20 dialog_context_chars=0 question_len=15 preview='所有客户账户之间的股票转移记录'
+2026-04-16 16:22:26 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
+2026-04-16 16:22:29 INFO [agents.orchestrator] orchestrator.py:803 generate() | [GEN] 问句已归一中文:所有客户账户的股票转移记录
+2026-04-16 16:22:29 INFO [agents.orchestrator] orchestrator.py:816 generate() | [GEN] 开始生成SQL: question_chars=13 preview='所有客户账户的股票转移记录' dialog_context_chars=0
+2026-04-16 16:22:29 INFO [agents.orchestrator] orchestrator.py:831 generate() | 尝试 #1
+2026-04-16 16:22:29 INFO [schema.indexer] indexer.py:82 __init__() | [OK] 初始化SchemaIndexer(Chroma磁盘 path=data\embeddings\chroma): collection=schema_tables, count=2516
+2026-04-16 16:22:29 INFO [schema.indexer] indexer.py:106 ensure_index_for_schema() | Schema 向量索引已就绪(2516 张表),跳过向量化
+2026-04-16 16:22:29 INFO [agents.orchestrator] orchestrator.py:188 _coarse_filter() | [Orchestrator] 开始向量检索: query_chars=13 query_preview='所有客户账户的股票转移记录'
+2026-04-16 16:22:30 INFO [utils.embedding] embedding.py:163 _set_dim_from_vector() | [OK] Embedding 向量维度:1536
+2026-04-16 16:22:31 INFO [schema.indexer] indexer.py:244 search() | Schema 向量检索: query_chars=13 命中=20(阈值=0.1)top=[('VSBHKRpt0430', 0.8264), ('VSBHKRpt0431', 0.8188), ('TSBTransferInstruction', 0.8147), ('VSBTransferInstruction', 0.8134), ('VSBHKRpt0397', 0.8126), ('VSBHKRpt0672', 0.8117), ('VSBHKRpt0090C', 0.81), ('VSBHKRpt0570', 0.8084), ('VSBHKRpt1030A', 0.8077), ('VSBRpt0999E', 0.8065), ('VSBRpt0999C', 0.8064), ('TSBAccountEntitlementRelease', 0.8063), ('VSBRpt0999A', 0.8059), ('TSBAccountInstrumentMovement', 0.8038), ('VSBTransferInstructionGenerationByAccountContract', 0.8033)]
+2026-04-16 16:22:31 INFO [agents.orchestrator] orchestrator.py:204 _coarse_filter() | [Orchestrator] 向量粗筛: 命中=20 张(阈值内),表名+分: [('VSBHKRpt0430', 0.8264), ('VSBHKRpt0431', 0.8188), ('TSBTransferInstruction', 0.8147), ('VSBTransferInstruction', 0.8134), ('VSBHKRpt0397', 0.8126), ('VSBHKRpt0672', 0.8117), ('VSBHKRpt0090C', 0.81), ('VSBHKRpt0570', 0.8084), ('VSBHKRpt1030A', 0.8077), ('VSBRpt0999E', 0.8065), ('VSBRpt0999C', 0.8064), ('TSBAccountEntitlementRelease', 0.8063), ('VSBRpt0999A', 0.8059), ('TSBAccountInstrumentMovement', 0.8038), ('VSBTransferInstructionGenerationByAccountContract', 0.8033), ('VSBRpt0060', 0.8021), ('XCGatewayStockReconciliationReport', 0.802), ('TSBAccountEntitlementHold', 0.8013), ('WSBBatchLocationTransferDetail', 0.8012), ('VCAccountCashMovement', 0.8012)]
+2026-04-16 16:22:35 INFO [agents.orchestrator] orchestrator.py:258 _llm_select_tables() | LLM精筛选中表:['VSBHKRpt0430', 'VSBHKRpt0431', 'TSBTransferInstruction', 'VSBTransferInstruction', 'TSBAccountInstrumentMovement'] | reasoning_chars=192 reasoning_preview='问题涉及客户账户的股票转移记录,VSBHKRpt0430和VSBHKRpt0431提供了客户股票的日常转移报告和账户工具移动报告,TSBTransferInstruction和VSBTransferInstruction包含账户转移指令的详细信息,TSBAccountInstrumentMovement记录账户工具的移动交易。这些表共同涵盖了股票转移的各个方面,确保了信息的完整性。'
+2026-04-16 16:22:35 INFO [agents.orchestrator] orchestrator.py:859 generate() | 选中表:['VSBHKRpt0430', 'VSBHKRpt0431', 'TSBTransferInstruction', 'VSBTransferInstruction', 'TSBAccountInstrumentMovement'],扩展后:['TSBAccountInstrumentMovement', 'TSBTransferInstruction', 'VSBHKRpt0431', 'VSBHKRpt0430', 'VSBTransferInstruction']
+2026-04-16 16:22:37 INFO [utils.fewshot_selector] fewshot_selector.py:209 select_best_with_score() | [Few-shot] best_with_score: qid=Q2 score=0.9575 preview='列出今日所有客户账户之间的股票转移记录。'
+2026-04-16 16:22:37 INFO [agents.orchestrator] orchestrator.py:432 _generate_sql_golden_adapt() | [GEN] 黄金 few-shot 条件适配: qid=Q2 score=0.9575
+2026-04-16 16:22:41 INFO [agents.orchestrator] orchestrator.py:450 _generate_sql_golden_adapt() | 生成的SQL(黄金适配,chars=494):
-- 查询所有客户账户间股票转移记录
-- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移
SELECT
@@ -61,115 +61,8 @@ LEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID
WHERE m.MovementType = 'T'
AND m.ValueDate = CAST(GETDATE() AS DATE)
ORDER BY m.ValueDate;
-2026-04-16 13:36:12 INFO [db.engine] engine.py:45 get_engine() | SQLAlchemy engine initialized from database_url
-2026-04-16 13:36:12 INFO [db.dbhub_tools] dbhub_tools.py:627 _execute_sql() | _execute_sql 执行语句数=1 readonly=True max_rows=1
-2026-04-16 13:36:15 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:36:15 INFO [agents.orchestrator] orchestrator.py:921 generate() | [OK] SQL生成与验证通过(1次尝试)
-2026-04-16 13:36:15 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 13:47:46 INFO [uvicorn.access] httptools_impl.py:483 send() | 127.0.0.1:27791 - "POST /g3sb/api/nl/chat/stream HTTP/1.1" 200
-2026-04-16 13:47:46 INFO [__main__] api_server.py:668 _chat_stream_events() | [API/stream] 开始: user_id='anonymous' visitor_biz_id=None session_id=None service_code=None model='gpt-4o-mini' lang_code='auto' msg_chars=15 preview='所有客户账户之间的股票转移记录' dialog_context_chars=0 last_turn_was_data_query=False
-2026-04-16 13:47:49 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
-2026-04-16 13:47:49 INFO [utils.dialog_classifier] dialog_classifier.py:261 classify_dialog() | [dialog] intent=text2sql (hybrid fast: query hint) preview='所有客户账户之间的股票转移记录'
-2026-04-16 13:47:49 INFO [__main__] api_server.py:715 _chat_stream_events() | [GEN/API/stream] dialect=tsql top_k=20 dialog_context_chars=0 question_len=15 preview='所有客户账户之间的股票转移记录'
-2026-04-16 13:47:52 INFO [llm.openai_client] openai_client.py:55 __init__() | [OK] OpenAIClient初始化: model=gpt-4o-mini, base_url=http://113.192.49.54:9080/v1
-2026-04-16 13:47:54 INFO [agents.orchestrator] orchestrator.py:803 generate() | [GEN] 问句已归一中文:所有客户账户的股票转移记录
-2026-04-16 13:47:54 INFO [agents.orchestrator] orchestrator.py:816 generate() | [GEN] 开始生成SQL: question_chars=13 preview='所有客户账户的股票转移记录' dialog_context_chars=0
-2026-04-16 13:47:54 INFO [agents.orchestrator] orchestrator.py:831 generate() | 尝试 #1
-2026-04-16 13:47:54 INFO [schema.indexer] indexer.py:106 ensure_index_for_schema() | Schema 向量索引已就绪(2516 张表),跳过向量化
-2026-04-16 13:47:54 INFO [agents.orchestrator] orchestrator.py:188 _coarse_filter() | [Orchestrator] 开始向量检索: query_chars=13 query_preview='所有客户账户的股票转移记录'
-2026-04-16 13:47:56 INFO [schema.indexer] indexer.py:244 search() | Schema 向量检索: query_chars=13 命中=20(阈值=0.1)top=[('VSBHKRpt0430', 0.8264), ('VSBHKRpt0431', 0.8188), ('TSBTransferInstruction', 0.8147), ('VSBTransferInstruction', 0.8134), ('VSBHKRpt0397', 0.8126), ('VSBHKRpt0672', 0.8117), ('VSBHKRpt0090C', 0.81), ('VSBHKRpt0570', 0.8084), ('VSBHKRpt1030A', 0.8077), ('VSBRpt0999E', 0.8065), ('VSBRpt0999C', 0.8064), ('TSBAccountEntitlementRelease', 0.8063), ('VSBRpt0999A', 0.8059), ('TSBAccountInstrumentMovement', 0.8038), ('VSBTransferInstructionGenerationByAccountContract', 0.8033)]
-2026-04-16 13:47:56 INFO [agents.orchestrator] orchestrator.py:204 _coarse_filter() | [Orchestrator] 向量粗筛: 命中=20 张(阈值内),表名+分: [('VSBHKRpt0430', 0.8264), ('VSBHKRpt0431', 0.8188), ('TSBTransferInstruction', 0.8147), ('VSBTransferInstruction', 0.8134), ('VSBHKRpt0397', 0.8126), ('VSBHKRpt0672', 0.8117), ('VSBHKRpt0090C', 0.81), ('VSBHKRpt0570', 0.8084), ('VSBHKRpt1030A', 0.8077), ('VSBRpt0999E', 0.8065), ('VSBRpt0999C', 0.8064), ('TSBAccountEntitlementRelease', 0.8063), ('VSBRpt0999A', 0.8059), ('TSBAccountInstrumentMovement', 0.8038), ('VSBTransferInstructionGenerationByAccountContract', 0.8033), ('VSBRpt0060', 0.8021), ('XCGatewayStockReconciliationReport', 0.802), ('TSBAccountEntitlementHold', 0.8013), ('WSBBatchLocationTransferDetail', 0.8012), ('VCAccountCashMovement', 0.8012)]
-2026-04-16 13:48:00 INFO [agents.orchestrator] orchestrator.py:258 _llm_select_tables() | LLM精筛选中表:['VSBHKRpt0430', 'VSBHKRpt0431', 'TSBTransferInstruction', 'VSBTransferInstruction', 'TSBAccountInstrumentMovement'] | reasoning_chars=182 reasoning_preview='问题涉及客户账户的股票转移记录,VSBHKRpt0430和VSBHKRpt0431提供了客户股票的日常转移报告和账户工具移动报告,TSBTransferInstruction和VSBTransferInstruction包含账户转移指令的详细信息,TSBAccountInstrumentMovement记录账户工具的移动交易。这些表共同涵盖了股票转移的相关信息。'
-2026-04-16 13:48:00 INFO [agents.orchestrator] orchestrator.py:859 generate() | 选中表:['VSBHKRpt0430', 'VSBHKRpt0431', 'TSBTransferInstruction', 'VSBTransferInstruction', 'TSBAccountInstrumentMovement'],扩展后:['TSBTransferInstruction', 'VSBTransferInstruction', 'VSBHKRpt0431', 'VSBHKRpt0430', 'TSBAccountInstrumentMovement']
-2026-04-16 13:48:01 INFO [utils.fewshot_selector] fewshot_selector.py:209 select_best_with_score() | [Few-shot] best_with_score: qid=Q2 score=0.9575 preview='列出今日所有客户账户之间的股票转移记录。'
-2026-04-16 13:48:01 INFO [agents.orchestrator] orchestrator.py:432 _generate_sql_golden_adapt() | [GEN] 黄金 few-shot 条件适配: qid=Q2 score=0.9575
-2026-04-16 13:48:06 INFO [agents.orchestrator] orchestrator.py:450 _generate_sql_golden_adapt() | 生成的SQL(黄金适配,chars=494):
--- 查询所有客户账户间股票转移记录
--- 使用 TSBAccountInstrumentMovement,MovementType='T' 表示账户间转移
-SELECT
- m.MovementID,
- m.AccountID AS FromAccountID,
- m.TransferToAccountID,
- m.InstrumentID,
- i.Name AS InstrumentSymbol,
- m.MovementType,
- m.Quantity AS TransferQuantity,
- m.ValueDate AS TransferDate
-FROM TSBAccountInstrumentMovement m
-LEFT JOIN MCInstrument i ON m.InstrumentID = i.InstrumentID
-WHERE m.MovementType = 'T'
- AND m.ValueDate = CAST(GETDATE() AS DATE)
-ORDER BY m.ValueDate;
-2026-04-16 13:48:06 INFO [db.dbhub_tools] dbhub_tools.py:627 _execute_sql() | _execute_sql 执行语句数=1 readonly=True max_rows=1
-2026-04-16 13:48:08 INFO [openai._base_client] _base_client.py:1111 _sleep_for_retry() | Retrying request to /chat/completions in 0.481978 seconds
-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”我还无法判断你的查询需求。'
+2026-04-16 16:22:41 INFO [db.engine] engine.py:45 get_engine() | SQLAlchemy engine initialized from database_url
+2026-04-16 16:22:41 INFO [db.dbhub_tools] dbhub_tools.py:627 _execute_sql() | _execute_sql 执行语句数=1 readonly=True max_rows=1
+2026-04-16 16:22:44 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 16:22:44 INFO [agents.orchestrator] orchestrator.py:921 generate() | [OK] SQL生成与验证通过(1次尝试)
+2026-04-16 16:22:44 INFO [__main__] api_server.py:765 _chat_stream_events() | [API/stream] Text2SQL 完成: valid=True attempts=1 tables_used=['TSBAccountInstrumentMovement', 'TSBTransferInstruction', 'VSBHKRpt0431', 'VSBHKRpt0430', 'VSBTransferInstruction'] 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;"