diff --git a/backend/api/chat_router.py b/backend/api/chat_router.py index 2ca43b8..84aa407 100644 --- a/backend/api/chat_router.py +++ b/backend/api/chat_router.py @@ -5,6 +5,7 @@ """ from __future__ import annotations +import functools import json import os from datetime import datetime, timezone @@ -680,16 +681,27 @@ def _wrap_mcp_tool_safe(tool): 这样 LangChain Agent 在工具调用失败时仍能写入对应的 ToolMessage, 保持 checkpoint 中消息历史的完整性,避免下次对话因 tool_calls 缺少 配对回复而触发 LLM 400 BadRequest 错误。 + + langchain_mcp_adapters 生成的工具使用 response_format='content_and_artifact', + _arun 必须返回 (content, artifact) 元组,不能返回裸字符串。 """ original_arun = tool._arun + expects_tuple = getattr(tool, "response_format", "content") == "content_and_artifact" + def _as_tool_result(content): + return (content, None) if expects_tuple else content + + @functools.wraps(original_arun) async def safe_arun(*args, **kwargs): try: - return await original_arun(*args, **kwargs) + result = await original_arun(*args, **kwargs) + if expects_tuple and not isinstance(result, tuple): + return _as_tool_result(result) + return result except Exception as exc: error_msg = f"工具 [{tool.name}] 调用失败: {exc}" logger.warning(f"MCP 工具异常已捕获,返回错误字符串以维持对话完整性: {error_msg}") - return error_msg + return _as_tool_result(error_msg) tool._arun = safe_arun return tool diff --git a/mcp-server-demo/Dockerfile b/mcp-server-demo/Dockerfile index 31ceecf..4fa16db 100644 --- a/mcp-server-demo/Dockerfile +++ b/mcp-server-demo/Dockerfile @@ -8,15 +8,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY pyproject.toml ./ COPY excel_analyzer.py server.py ./ -RUN pip install --no-cache-dir --upgrade pip -timeout 120 --retries 10 \ - && pip install --no-cache-dir -timeout 120 --retries 10\ - "mcp>=1.27.2" \ - "python-dotenv>=1.0.0" \ - "httpx>=0.28.0" \ - "uvicorn>=0.48.0" \ - "pandas>=2.0.0" \ - "openpyxl>=3.1.0" \ - "xlrd>=2.0.1" +RUN pip install --no-cache-dir --upgrade pip \ + && pip install --no-cache-dir --timeout 120 --retries 10 . ENV MCP_HOST=0.0.0.0 ENV MCP_PORT=8010