From 547424fff6f1b22cc04e24aceaae0f6bfb3a4d26 Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Fri, 28 Nov 2025 16:51:28 +0800 Subject: [PATCH] update pay function --- mcp_server.py | 33 ++++++++++++++++ .../MeetingRoom/MeetingMessageBubble.js | 39 ++++++++++++++++--- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/mcp_server.py b/mcp_server.py index 8c2838ce..773d405d 100644 --- a/mcp_server.py +++ b/mcp_server.py @@ -2361,6 +2361,36 @@ MEETING_MODEL_CONFIGS = { }, } + +def clean_deepseek_tool_markers(content: str) -> str: + """ + 清理 DeepSeek 模型输出中的工具调用标记 + DeepSeek 有时会以文本形式输出工具调用,格式如: + <|tool▁calls▁begin|><|tool▁call▁begin|>tool_name<|tool▁sep|>{"args": "value"}<|tool▁call▁end|><|tool▁calls▁end|> + """ + import re + if not content: + return content + + # 清理 DeepSeek 工具调用标记 + # 匹配 <|tool▁calls▁begin|> ... <|tool▁calls▁end|> 整个块 + pattern = r'<|tool▁calls▁begin|>.*?<|tool▁calls▁end|>' + cleaned = re.sub(pattern, '', content, flags=re.DOTALL) + + # 也清理可能残留的单个标记 + markers = [ + '<|tool▁calls▁begin|>', + '<|tool▁calls▁end|>', + '<|tool▁call▁begin|>', + '<|tool▁call▁end|>', + '<|tool▁sep|>', + ] + for marker in markers: + cleaned = cleaned.replace(marker, '') + + return cleaned.strip() + + # 每个角色可用的工具列表 ROLE_TOOLS = { "buffett": ["search_china_news", "search_research_reports", "get_stock_basic_info", "get_stock_financial_index"], @@ -2663,6 +2693,9 @@ async def stream_role_response( "content": content } + # 清理 DeepSeek 工具调用标记 + full_content = clean_deepseek_tool_markers(full_content) + # 发送完成事件 yield { "type": "content_done", diff --git a/src/views/AgentChat/components/MeetingRoom/MeetingMessageBubble.js b/src/views/AgentChat/components/MeetingRoom/MeetingMessageBubble.js index 19845976..4d4b22b3 100644 --- a/src/views/AgentChat/components/MeetingRoom/MeetingMessageBubble.js +++ b/src/views/AgentChat/components/MeetingRoom/MeetingMessageBubble.js @@ -38,6 +38,32 @@ import { import { getRoleConfig, MEETING_ROLES } from '../../constants/meetingRoles'; import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts'; +/** + * 清理 DeepSeek 模型输出中的工具调用标记 + * DeepSeek 有时会以文本形式输出工具调用,格式如: + * <|tool▁calls▁begin|><|tool▁call▁begin|>tool_name<|tool▁sep|>{"args": "value"}<|tool▁call▁end|><|tool▁calls▁end|> + */ +const cleanDeepseekToolMarkers = (content) => { + if (!content) return content; + + // 清理 DeepSeek 工具调用标记(匹配整个块) + let cleaned = content.replace(/<|tool▁calls▁begin|>[\s\S]*?<|tool▁calls▁end|>/g, ''); + + // 清理可能残留的单个标记 + const markers = [ + '<|tool▁calls▁begin|>', + '<|tool▁calls▁end|>', + '<|tool▁call▁begin|>', + '<|tool▁call▁end|>', + '<|tool▁sep|>', + ]; + markers.forEach((marker) => { + cleaned = cleaned.split(marker).join(''); + }); + + return cleaned.trim(); +}; + /** * 解析 deepmoney 格式的内容 * 格式: 思考过程回答内容 @@ -48,10 +74,13 @@ import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts'; const parseDeepmoneyContent = (content) => { if (!content) return { thinking: null, answer: '' }; + // 先清理 DeepSeek 工具调用标记 + const cleanedContent = cleanDeepseekToolMarkers(content); + // 匹配 ... 标签 - const thinkMatch = content.match(/([\s\S]*?)<\/think>/i); + const thinkMatch = cleanedContent.match(/([\s\S]*?)<\/think>/i); // 匹配 ... 标签 - const answerMatch = content.match(/([\s\S]*?)<\/answer>/i); + const answerMatch = cleanedContent.match(/([\s\S]*?)<\/answer>/i); // 如果有 answer 标签,提取内容 if (answerMatch) { @@ -64,7 +93,7 @@ const parseDeepmoneyContent = (content) => { // 如果只有 think 标签但没有 answer 标签,可能正在流式输出中 if (thinkMatch && !answerMatch) { // 检查 think 后面是否有其他内容 - const afterThink = content.replace(/[\s\S]*?<\/think>/i, '').trim(); + const afterThink = cleanedContent.replace(/[\s\S]*?<\/think>/i, '').trim(); // 如果 think 后面有内容但不是 answer 标签包裹的,可能是部分输出 if (afterThink && !afterThink.startsWith('')) { return { @@ -78,10 +107,10 @@ const parseDeepmoneyContent = (content) => { }; } - // 如果没有特殊标签,返回原内容 + // 如果没有特殊标签,返回清理后的内容 return { thinking: null, - answer: content, + answer: cleanedContent, }; };