From 5e5a4b7376fe81f806ade6bc5ea59ba972d43d93 Mon Sep 17 00:00:00 2001 From: minorQAQ <202200120184@mail.sdu.edu.cn> Date: Wed, 3 Jun 2026 17:58:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=B7=A5=E5=85=B7=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E6=A0=BC=E5=BC=8F=E7=9A=84=E8=A1=A5=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/chatbot_agent.cpython-312.pyc | Bin 9574 -> 9712 bytes src/agent/__pycache__/llm.cpython-312.pyc | Bin 24140 -> 25815 bytes src/agent/chatbot_agent.py | 6 +- src/agent/history/data_base/chat_history.db | Bin 57344 -> 57344 bytes .../20260603_172211/ui_messages.json | 39 +++++++++++ .../20260603_175632/ui_messages.json | 39 +++++++++++ src/agent/llm.py | 61 ++++++++++++++++-- 7 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 src/agent/history/multi_inputs/20260603_172211/ui_messages.json create mode 100644 src/agent/history/multi_inputs/20260603_175632/ui_messages.json diff --git a/src/agent/__pycache__/chatbot_agent.cpython-312.pyc b/src/agent/__pycache__/chatbot_agent.cpython-312.pyc index 17813a57f9dc9dbe861aad473cf3ba6404097c4c..5669ab914356c63a3620a108034fb432a131a09a 100644 GIT binary patch delta 867 zcmZ{iO-vI}5XW~)zqTKg(iUlHi&#+F7!ia*BdLLu5Agt^7lNT(*iu?cOI{ZWNzp5Z z9wg%jibi9+nHWfk(ZobeP!D>OgK3C~(U^FHgBOj7JCG)F@Ev}cH~;^ZyVlyD#zE%;Sa)nm+QRynae zr(NalDNE-7m%pLpM94u5;&6fUaFVlBThFmF;6}K-C(F&3jc{4;nlPx{z~9;vU_u|? zYf_5w35lJQD_FA(O!F6^88`Xk;KyD5QQ(`eb#3^Cb;}oAQQTMGRu<~*}ro1dhi*0nSGvJ3T@+4onYQH+d@IbW{~gEsowC=qboG( zKPjOdp`u#8z)?}7VjXnt>58{7T2Ppm74A#&-do06sih_YjmxWG$0#1gbxR$L;YUjd zMzPwuTiYh5i+Vv6!_(1BMuizlfSPNCU2{a7WMLJJXIF%NoY?P8?Xz_I07AXu6CJ94?JSIFYcu-jKe1^Xy C+0Kyw delta 846 zcmZ{h%TE(g6vpS)K4$umVyCs(2l6yE2BJv8NKi~e6c^R7g-nK-u}sq4zi8ttNQPNhflDr=?#}_TYh^K9Nn&Xz-Rd-%Ep2eN&Q~f)RhQ8$a zk0+pW|2#ZvY2H%hS+E&5^E4uGEYwu=B-h2U2t4LvBnWT#cf6-$%o^r`0n_^2w?y&1uD=oYPWHDx-AVMG?*Cpt(Dz9!lltrF&` zZZJtJE2%KOkCu9A^(y8elDw8wY|-whR%Vi78cZ`79YtRsVhM`LEO`Wb$q}-)+n#f# zv89%GMmJOmr%D~KH8E@BPQjp#x2+OYVM RIa4hav{Cx9cB=au`3t9W#hL&B diff --git a/src/agent/__pycache__/llm.cpython-312.pyc b/src/agent/__pycache__/llm.cpython-312.pyc index 968a909a70826c48ddeaf7ff899b00f3ec2baf60..16446dffe9e184040e95bd8daf877f37818ac80d 100644 GIT binary patch delta 6106 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 BQ| dict: # ----- 打印工具调用信息 ----- if hasattr(response, 'tool_calls') and response.tool_calls: for tc in response.tool_calls: - tool_name = tc.get('name', 'unknown') - args = tc.get('args', {}) - # LangChain 中 tool_call 的 args 可能是 JSON 字符串,尝试解析 + # tc 是 ToolCall 对象,可直接访问 .name 和 .args + tool_name = tc.get('name') if isinstance(tc, dict) else tc.name + args = tc.get('args') if isinstance(tc, dict) else tc.args if isinstance(args, str): try: args = json.loads(args) diff --git a/src/agent/history/data_base/chat_history.db b/src/agent/history/data_base/chat_history.db index 8127b2bf1d8361fa5093388d5094ac830aee7746..597207190745435f4bf94b6f5c87d3a498017d21 100644 GIT binary patch delta 2399 zcmbVNO>7%Q6n045{CXxRkW|7DlP3LfA=#bXnc0n+BGF3^k&3vWq6KGny$d0UH#oK; z5NPYDNaRNGp&(SLs8J87mnc#O8zDf$UX8Id7oH&PnHZ47Rj-*Pxlm_Urn$barA~Z|~Ruw&QyY$?$?vJ?&j9YsbmKqAI)21sNWIt(cDi3EcgB*}gt10;#}@2y<= zd}*XF_b`{g)4S7iH}~*b>&=O+3&-=hvsYJAi6~&v{`vZJ^;{zeRx7T(x_aKKo%5SD zx3L`57Myypx#86-ZcuB~g9ux<>-L)0@ahY8bOz1`>s}44=DJX8{sctYx}1sxlC_`z z;#B*UdSB6Fp4Al4TKJ!9R+IaR;#f^-SIzd#U}^8}?&5Rf*w+2|AV*q-Z%1wq|336! zD4!2@TbJ__+hb+$|LJhbKlU+Xax&zmtb!|H=vLGB6^NmGZWNE%5J~v3);$JixaRq| z_BfoENPsggL=Ae zW0|A#q0nrUPvg)@X=9Uvh|pD0Z-AU}hot2+6(76uK%c4Lg)=j*ZMU?LHIy!0(r#bL zgN=1$9n(Dk(!1@}cTa^v!E}V|+=y=T;|U0uuCx-Vp!!e*`S_ma3~zzZu-)*6b-iL5 zQ!kXJ>}qux$4&drBx~QOxD&0#GdMp!Jbb^u96K||A2&T9Kvb9g*28%+u{CxYC*Pyy zg&{QuHI6R;+{F?Gg$+;Y@Fk>Tpd{SmB~{LIF|WZc5^vv}JRg%aPa)aY9znL4cFt7~ zTO!g8hXyhm-zuI&X3wUKaZ>(tedfXuBe`lfyvn;xul`=eU9~qha9+=K26psgf0TDP zjrA_D^h9~3iA)G%jM+?cS0pM#nIBT$fmXETq$6MjbF%^&6Y1Vlx6 zfkJHjJ`DVi_>b@}>jSP&;49pCS;|-0BO-&3Ye-txdwlq(f ztavYB^OlW1auWkMnD{OL4LZgr-lQu6)YD>*uIK)AwIGu;GlQ5?Q=rzE(zG-K!\n\n\nopen\n\n\nhttps://www.bilibili.com\n\n\n", + "output_type": "text", + "autoplay": false, + "audio_duration_seconds": null, + "audio_relpath": null + } + }, + { + "user": { + "content": [ + { + "type": "text", + "text": "现在几点了" + } + ] + }, + "assistant": { + "text": "\n\n\n", + "output_type": "text", + "autoplay": false, + "audio_duration_seconds": null, + "audio_relpath": null + } + } + ] +} \ No newline at end of file diff --git a/src/agent/history/multi_inputs/20260603_175632/ui_messages.json b/src/agent/history/multi_inputs/20260603_175632/ui_messages.json new file mode 100644 index 0000000..999dab1 --- /dev/null +++ b/src/agent/history/multi_inputs/20260603_175632/ui_messages.json @@ -0,0 +1,39 @@ +{ + "version": 2, + "turns": [ + { + "user": { + "content": [ + { + "type": "text", + "text": "现在几点了" + } + ] + }, + "assistant": { + "text": "现在是 2026年6月3日 17:56:36。", + "output_type": "text", + "autoplay": false, + "audio_duration_seconds": null, + "audio_relpath": null + } + }, + { + "user": { + "content": [ + { + "type": "text", + "text": "帮我打开b站和虎牙" + } + ] + }, + "assistant": { + "text": "好的!从截图中可以看到:\n\n1. **B站已经打开了**:第5个标签页显示的是\"啊哈啊哈! - bilibili\"\n2. **虎牙也打开了**:当前页面正在浏览虎牙直播网站,可以看到虎牙的Logo、导航栏(首页、直播、分类、视频、游戏等),以及正在播放的直播内容和右侧的推荐直播间\n\n两个网站都已经成功打开。当前显示的是虎牙直播页面,如果您想查看B站,可以点击第5个标签页切换到B站。", + "output_type": "text", + "autoplay": false, + "audio_duration_seconds": null, + "audio_relpath": null + } + } + ] +} \ No newline at end of file diff --git a/src/agent/llm.py b/src/agent/llm.py index 3554e0e..6f29272 100644 --- a/src/agent/llm.py +++ b/src/agent/llm.py @@ -12,7 +12,7 @@ from datetime import datetime as dt import requests from concurrent.futures import ThreadPoolExecutor, as_completed -from langchain_core.messages import HumanMessage, AIMessage, BaseMessage, SystemMessage +from langchain_core.messages import HumanMessage, AIMessage, BaseMessage, SystemMessage, ToolCall from langchain_core.outputs import ChatResult, ChatGeneration from langchain_openai import ChatOpenAI @@ -329,6 +329,19 @@ class ChatQwen(ChatOpenAI): return result def _create_chat_result(self, response, generation_info=None) -> ChatResult: + # ---------- 打印原始 tool_calls ---------- + try: + raw = response if isinstance(response, dict) else response.model_dump() + print("[RAW_RESPONSE]", json.dumps(raw, indent=2, ensure_ascii=False)) + choices = raw.get("choices", []) + if choices: + msg = choices[0].get("message", {}) + tool_calls = msg.get("tool_calls") + if tool_calls: + print("[RAW_TOOLCALLS]", json.dumps(tool_calls, indent=2, ensure_ascii=False)) + except Exception: + pass + result = super()._create_chat_result(response, generation_info) try: dumped = response if isinstance(response, dict) else response.model_dump(exclude={"choices": {"__all__": {"message": {"parsed"}}}}) @@ -338,6 +351,7 @@ class ChatQwen(ChatOpenAI): lc_msg = result.generations[i].message msg = choice.get("message") or {} ak = lc_msg.additional_kwargs + # 优先处理 reasoning 内容 merged = "" for key in ("reasoning_content", "reasoning_details", "reasoning"): merged = assistant_text(msg.get(key)) @@ -350,27 +364,66 @@ class ChatQwen(ChatOpenAI): lc_msg.content = merged elif raw_content: lc_msg.content = raw_content - # print(f"raw_content={raw_content!r}, merged={merged!r}, final={lc_msg.content!r}") + content_text = lc_msg.content if isinstance(lc_msg.content, str) else "" + + # 匹配 ... 块 pattern = re.compile(r'\s*(.*?)\s*', re.DOTALL) matches = pattern.findall(content_text) if matches: tool_calls = [] for idx, match in enumerate(matches): + # 先尝试 JSON 解析(兼容旧格式) try: call_data = json.loads(match) + tool_calls.append({ + "id": f"call_{idx}", + "type": "function", + "function": { + "name": call_data.get("name", ""), + "arguments": json.dumps(call_data.get("arguments", {})) + } + }) + continue # 解析成功,跳过 XML 尝试 except json.JSONDecodeError: + pass + + # 再尝试 XML 解析 + func_match = re.search(r'', match) + if not func_match: continue + func_name = func_match.group(1) + + params = {} + for param_match in re.finditer(r'\s*(.*?)\s*', match, re.DOTALL): + key = param_match.group(1) + value = param_match.group(2).strip() + # 可选:智能类型转换,先保持简单 + params[key] = value + tool_calls.append({ "id": f"call_{idx}", "type": "function", "function": { - "name": call_data.get("name", ""), - "arguments": json.dumps(call_data.get("arguments", {})) + "name": func_name, + "arguments": json.dumps(params) } }) + if tool_calls: ak["tool_calls"] = tool_calls + # 构造 LangChain 的 ToolCall 对象列表 + lc_tool_calls = [] + for idx, tc in enumerate(tool_calls): + lc_tool_calls.append( + ToolCall( + id=tc["id"], + name=tc["function"]["name"], + args=json.loads(tc["function"]["arguments"]) + ) + ) + lc_msg.tool_calls = lc_tool_calls + # 清理内容中的 XML/JSON 工具调用痕迹 cleaned = pattern.sub("", content_text).strip() lc_msg.content = cleaned if cleaned else "" except Exception: