From 9375dc29ee4e9a49f41ce74998522985ecb89dfa Mon Sep 17 00:00:00 2001 From: gouhanke <12219217+gouhanke@user.noreply.gitee.com> Date: Thu, 5 Mar 2026 18:29:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/agent_service.cpython-312.pyc | Bin 3329 -> 2042 bytes server/__pycache__/config.cpython-312.pyc | Bin 2098 -> 713 bytes server/agent_service.py | 27 +------ server/config.py | 28 ------- server/mcp_tools.py | 73 ------------------ 5 files changed, 4 insertions(+), 124 deletions(-) delete mode 100644 server/mcp_tools.py diff --git a/server/__pycache__/agent_service.cpython-312.pyc b/server/__pycache__/agent_service.cpython-312.pyc index 50da02ecff5be939354b642a5d783103deef73fc..128ce3e2d43edd6eac39bfd27f101187a26d9a98 100644 GIT binary patch delta 1030 zcmYjQT}TvB6h3$Uc4qcRMe%31bzO5ehkn#nlyH$Y5|h%PjiA|wWot%p*-@C83}F|o zeDJ{_xqi0|TiDQO@KTgH>6BQ@Kja=6FL;g$n0#E<;qs3g>f@ zA*(Xsg67J(4Ug(Uz`!tQ;sR*W8bfCRsNPvwasQxHK}BD}vL-D%Gi4_x^yLqe*B{aY z$AlAd&`HP&=%6AER7P`Y>;k8<8mDs_Pku<}#sy6v8b8Y@B3?!@^bUVSnHvRUyPa+t zmq+%=Eda6}M?dxJ{2E)0@{o2p`Yb2{o?%jQQOL|>?2M_f_$Ajt2YqIu-6kz5`jYpP zcZWvPqeIDLVtA-1q%#xxl&vsD&eC(^W;02$=7=3&372QRYGXtTWN zIc$KY$X;E`UQ1*@5Z(=R?*zIJU0jpA$US!-kaWOZ;)O=Ce7FgSti&d)YFP%q6@vq; z%{z*Q@+i+vFzbx7`vRx21wId1XR%Hy@mYz~*CP%ei@}I+y0yGu|J#()$3jc~ynqL! zP*}*;{@3J$7Wk$9eptHP2YDXPNf$$nZvCgN&v3^_m<}%pl&9!u}|w z=V+qKY^A)N!dU{?EBAWo-_cezGlXx;9lkR}u^ton4oCBVU&x*H;n%5Gsoh{~Cm7oZ zZ3kmtf+P5o9KFXg(xs#A;7D17+Q7ExKeqZv-O~hn4WUh*OAIob5=z8{O_`~m^&~9NC=;6#eDU|Pc z>fO<{Yzjziqfh_?v4g^L&;T*ez8F>z_o;o1{8XSX66AoyRz?jJ0h%|qGGI06Luc=J zv>d5LSGw8Rnb{xid^59uZfX({wE4653wHwu{f!R%#?_h4%fKul6{%Q9IodNiHkcfP zDbMPx!R0uE&++b<(*+}t3%ES52aQlJ3fD{-BtTg=t#VF|WFpQtpb;VF7K2)3u)0opWr(hN*^a8B=9ftkDM97=P z>B0*V?Oty ze^6&(20g9Y=242voJsLSxLB~^Π#RLs-cm-C9Q7m71PnzdnMmYlhgLxgG9Wu)15 ztWqAXK~w80@IP-*rxMZarKNYRrT1yPv)Xf@`s)6T zcyA>>xE3F*_NM+J3GI<*e5g}gL<|21f+DLSNaqP2Wzj}QwY`e+9k^Gg) z_(2_@%glp1n6hXT-8}jwdkLr53=tF;_<#(qs2CavzvQ2YJ#RajAsh8D=iNvot(G>e zYk5Zoz)*=?vbB_8(QPgIE36JmTrfnk=dx!er{t;0Y&Ly-l5pq2KE+tCQi}sXY#KLR zT~-%#0FS(-DURm(|4P?xp4@Kn3SHm>Ab&?&;L*K3>wEhuvA#uqBbux>cT_u)m5zb6 zj)9HDYn8;IwZx%n%f3$s?+$Nt_1ruATj`l3#KamBLSl_Y&HdloG_I~i(qViHr$z4e z+rYi#S_)>@wQs|Tvk&Q0_^v(g; z|J%8<=rVf_UBWK#a3;lCaX6Qiq~u4GbOP~$+{1z>&uC5^2+7@m&`|f$nPng@3aV1{ zld+G-R;BK0>%OJ2+heQYPT(r7`{94Rb$>P5`pMOgudYVBA>=DPBWpb)>pe#*okwnQ zzm}f!sI3R=Y66P2xn>af0g!Dy?L4woquMQRrPY^>{%!vR4sb0so`8@`za=cQz_CYnp#rU}^7)bBd?R1L#uN}PF#EOxvmX1PYqT9O@$(P+BLD1Gz{-rDNftPVhJo84 zQ{gfGUf^2E_oLRKtc=bGN(_-6I zZ(g+UmNuu)UuoYZP+Sc?zr6^=i;=zYCG)nqzPG;;>xXQ)Ctlgpx3;J6-u(KWHx|W> z_`t)FuTT8x%IZY!ar|eC(WiUc7o}>lyOJDSOAbDKcQrZqI63hgF`=Pb{TtDayZyf# z`zCtu;qgCYexLdJ!}Z}zwX^pN^E30dREwhK16wr_Ot)5(6SW|UC02v+f7$QCVXn1} zH{&~aT;!IH0k_i1jYpW3eRw=9thBR~Pc&2cV3g7yM}R&GV~{_Ju)sqdp>W8gLbUwT z`X$Rml<6Czq*FdD%fBcox~H*T16!{?xe13}31Pu+7Cp*+WOY-07bQ(Tp^SYL$PKi~ zg!$KNuLODV-p@A?bhS2tPuv^YM9|e@BJkN7g6^T${W1HDj=WXrI;mzW0Uc>qN{$K7 z9xu1$;VnGm0>O6AM&diwzS~{6xv(N(-zslfng`6*?V=&Kj@#bztHako2B|BCO!p=3 zJ=@-bV|nE|)Oc=t)!e;^_o=#ZIV5<@yWe-Llc1nE#_k7FV==~mL6L9K;lHBEC#drY Y8hC=<`xdo5LA}p~0i5_J0^%<8A3>`OFaQ7m diff --git a/server/__pycache__/config.cpython-312.pyc b/server/__pycache__/config.cpython-312.pyc index 7878606142ba6fd317bbea419f3278c33245cf88..7a844521603e8cc6e2ae4d1a3a4ddfee6e8b7dc8 100644 GIT binary patch delta 193 zcmdlaaFR9pG%qg~0}xb3t;`f=Vqka-;=lkSl<`>y$e7NM!Vtxf!WhMv!W6}n!W_k% z!V<-j!WzYz!WPAr!XCw*!V$%h!WqR`$)(9%`k!I*5oSil$%d@{%zm0&lS9}RIj>~+ z3^MVTKyhkOS!$7fa(-S~X1ZQMC%PKX6T+!miKW$Xz4^lm!4M<|`2Z literal 2098 zcmah}TTl~M7(Tm6fS8bQ6NGXrQk4fUtxl&?D{Txrzzj(k60~d|(&#P-#)NJX6b5HP z0mZ>KSSg@YK`Sk&7-rfEHcI%61LK?^V1Dxk*Y9SbdRH<*>4})>! zPnC>N$MYzRgw~6cG^fd4GD!9kcGOFDz(&2;Zl@F-=`UIkQfv&-h3u$`v{tJDBoJ>3 zq}L;;x>=u~_HzNYN(~C1kk-cfSx=Xs@%g#-PC?`Lo@BXM6^AS5Has<5E_Zd)1WFvGSW6-(C# zPsfb;Lxz|xE42UI{^0|^=}I5!N~5}RzOtIvRrBiVb?`$1`WK0~3Y>kt7sUUQ*h?sT zj%oZa`g~*?P~?9`Vux}EAdk{|No7-jOu|~F;dEf)^jKtq0OF3h*;CMUy4(Gn5mX9Q zTsF2R*>Q1gK5h%lv7>J{i09ausEz6?fuJNU=MTh;*+beV$=OICsw?5uC0s7}1dhW2 z5|^jsiLkgB6c=wvp{nTTH=Fx4k6U6zL@#l?vH#oW{2rvR5iVKFit zzcMTh&BsS)%m!hqBtl5T!4E=|c-r@=2i8d<%1RNnm6avcO zkbLKQaw>oRtu%B`x-ug!-V_(lNugUcyR8jCMq zSiSy(_~5$S7X}#4u{0qK4vEVTAPDe+<-)WyxByCd5~{f&o%t+TE94T?M_fKuP#x_I z2v7Kh?&JWvN-c#^d*#PHq_ZUAp$$Iwg>~g>BcKKPKzbAdq zu8m*&2W4;;vM8(RU<2i}m>ZoAo2|j_5X$h_PBk5(nw(9PsmAH3w@|ib2k6W;YmHqX z_wEsjFz7I4a?}AT1vc9(7L&C`D0qp@)KqI1ij#(ecFNRbu6xm~@TFGlSVeGou)?as zmv8FQ@W}L0!y{6V&~lTg;d2p3jTsz74oX729XDGh|phtL5La^UW>M9dxwfBOaBl zlx&-5nryk$!f!YK+!QUT<5AJ0qOE-8foM@Rj|x`Gc1&=S-Iu!gs@h+2qGb&{Dt=V_ Q2EWY|Ek5`V6>d=RH*!FeM*si- diff --git a/server/agent_service.py b/server/agent_service.py index fa18580..361654d 100644 --- a/server/agent_service.py +++ b/server/agent_service.py @@ -1,5 +1,3 @@ -import asyncio - from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.messages import MultiModalMessage, TextMessage from autogen_core import Image @@ -7,12 +5,11 @@ from autogen_core.models import ModelFamily from autogen_ext.models.ollama import OllamaChatCompletionClient from . import config -from .mcp_tools import load_mcp_tools class AvatarAgentService: def __init__(self) -> None: - self._model_client = OllamaChatCompletionClient( + model_client = OllamaChatCompletionClient( model=config.OLLAMA_MODEL, model_info={ "vision": True, @@ -22,34 +19,18 @@ class AvatarAgentService: "structured_output": True, }, ) - self._agent: AssistantAgent | None = None - self._agent_lock = asyncio.Lock() - - async def _create_agent(self) -> AssistantAgent: - tools = await load_mcp_tools() - return AssistantAgent( + self._agent = AssistantAgent( name="avatar", - model_client=self._model_client, + model_client=model_client, system_message=config.SYSTEM_MESSAGE, - tools=tools or None, - reflect_on_tool_use=bool(tools), ) - async def _get_agent(self) -> AssistantAgent: - if self._agent is not None: - return self._agent - async with self._agent_lock: - if self._agent is None: - self._agent = await self._create_agent() - return self._agent - async def reply(self, user_text: str, image_b64: str) -> str: - agent = await self._get_agent() user_image = Image.from_base64(image_b64) multimodal_task = MultiModalMessage(source="user", content=[user_text, user_image]) ai_response = "" - async for message in agent.run_stream(task=multimodal_task): + async for message in self._agent.run_stream(task=multimodal_task): if isinstance(message, TextMessage) and message.source == "avatar": ai_response = message.content diff --git a/server/config.py b/server/config.py index f2178ac..41bfbcf 100644 --- a/server/config.py +++ b/server/config.py @@ -1,25 +1,6 @@ -import os -import shlex - - -def _env_bool(name: str, default: bool) -> bool: - value = os.getenv(name) - if value is None: - return default - return value.strip().lower() in {"1", "true", "yes", "on"} - - -def _env_args(name: str, default: str = "") -> list[str]: - value = os.getenv(name, default) - if not value.strip(): - return [] - return shlex.split(value) - - SYSTEM_MESSAGE = ( "你是一个友好、幽默的AI虚拟主播。你可以看到用户摄像头传来的画面,也能听到他们的话。" "请用简短、自然、热情的中文口语回答,每次回答控制在两三句话以内,不要输出任何 Markdown 格式。" - "当用户询问实时天气、最新新闻或网页信息时,优先使用可用工具先查询再回答。" ) WHISPER_MODEL_NAME = "base" @@ -33,12 +14,3 @@ OLLAMA_MODEL = "qwen3-vl:latest" SERVER_HOST = "0.0.0.0" SERVER_PORT = 8000 - -ENABLE_MCP_TOOLS = _env_bool("ENABLE_MCP_TOOLS", True) -MCP_SERVER_READ_TIMEOUT_SECONDS = float(os.getenv("MCP_SERVER_READ_TIMEOUT_SECONDS", "30")) - -MCP_WEATHER_SERVER_COMMAND = os.getenv("MCP_WEATHER_SERVER_COMMAND", "") -MCP_WEATHER_SERVER_ARGS = _env_args("MCP_WEATHER_SERVER_ARGS") - -MCP_WEBSEARCH_SERVER_COMMAND = os.getenv("MCP_WEBSEARCH_SERVER_COMMAND", "") -MCP_WEBSEARCH_SERVER_ARGS = _env_args("MCP_WEBSEARCH_SERVER_ARGS") diff --git a/server/mcp_tools.py b/server/mcp_tools.py deleted file mode 100644 index 3d32dfc..0000000 --- a/server/mcp_tools.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any - -from autogen_ext.tools.mcp import StdioServerParams, mcp_server_tools - -from . import config - - -@dataclass(frozen=True) -class MCPServerConfig: - name: str - command: str - args: list[str] - - -def _configured_servers() -> list[MCPServerConfig]: - if not config.ENABLE_MCP_TOOLS: - return [] - - servers: list[MCPServerConfig] = [] - if config.MCP_WEATHER_SERVER_COMMAND: - servers.append( - MCPServerConfig( - name="weather", - command=config.MCP_WEATHER_SERVER_COMMAND, - args=config.MCP_WEATHER_SERVER_ARGS, - ) - ) - if config.MCP_WEBSEARCH_SERVER_COMMAND: - servers.append( - MCPServerConfig( - name="websearch", - command=config.MCP_WEBSEARCH_SERVER_COMMAND, - args=config.MCP_WEBSEARCH_SERVER_ARGS, - ) - ) - return servers - - -async def load_mcp_tools() -> list[Any]: - configured_servers = _configured_servers() - if not configured_servers: - print("ℹ️ MCP 工具未配置,跳过加载。") - return [] - - loaded_tools: list[Any] = [] - tool_names: set[str] = set() - - for server in configured_servers: - params = StdioServerParams( - command=server.command, - args=server.args, - read_timeout_seconds=config.MCP_SERVER_READ_TIMEOUT_SECONDS, - ) - try: - server_tools = await mcp_server_tools(params) - for tool in server_tools: - if tool.name in tool_names: - print(f"⚠️ MCP 工具重名,已跳过: {tool.name}") - continue - loaded_tools.append(tool) - tool_names.add(tool.name) - print(f"✅ MCP 服务已加载: {server.name} ({len(server_tools)} tools)") - except Exception as exc: - print(f"⚠️ MCP 服务加载失败: {server.name}, error={exc}") - - if loaded_tools: - print(f"✅ MCP 工具总数: {len(loaded_tools)}") - else: - print("ℹ️ 未加载到任何 MCP 工具。") - return loaded_tools