mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-13 02:24:44 +08:00
* fix: strip <think> tags from LLM output to prevent thinking text leakage (#781) Some models (e.g. DeepSeek-R1, QwQ via ollama) embed reasoning in content using <think>...</think> tags instead of the separate reasoning_content field. This causes thinking text to leak into both streamed messages and the final report. Fix at two layers: - server/app.py: strip <think> tags in _create_event_stream_message so ALL streamed content is filtered (coordinator, planner, etc.) - graph/nodes.py: strip <think> tags in reporter_node before storing final_report (which is not streamed through the event layer) The regex uses a fast-path check ("<think>" in content) to avoid unnecessary regex calls on normal content. * refactor: add defensive check for think tag stripping and add reporter_node tests (#781) - Add isinstance and fast-path check in reporter_node before regex, consistent with app.py - Add TestReporterNodeThinkTagStripping with 5 test cases covering various scenarios * chore: re-trigger review
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from functools import partial
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
@@ -900,6 +901,12 @@ def reporter_node(state: State, config: RunnableConfig):
|
||||
logger.debug(f"Current invoke messages: {invoke_messages}")
|
||||
response = get_llm_by_type(AGENT_LLM_MAP["reporter"]).invoke(invoke_messages)
|
||||
response_content = response.content
|
||||
# Strip <think>...</think> tags that some models (e.g. QwQ, DeepSeek) embed
|
||||
# directly in content instead of using the reasoning_content field (#781)
|
||||
if isinstance(response_content, str) and "<think>" in response_content:
|
||||
response_content = re.sub(
|
||||
r"<think>[\s\S]*?</think>", "", response_content
|
||||
).strip()
|
||||
logger.info(f"reporter response: {response_content}")
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,6 +6,7 @@ import base64
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from typing import Annotated, Any, List, Optional, cast
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -423,6 +424,11 @@ def _create_event_stream_message(
|
||||
if not isinstance(content, str):
|
||||
content = json.dumps(content, ensure_ascii=False)
|
||||
|
||||
# Strip <think>...</think> tags that some models (e.g. DeepSeek-R1, QwQ via ollama)
|
||||
# embed directly in content instead of using the reasoning_content field (#781)
|
||||
if isinstance(content, str) and "<think>" in content:
|
||||
content = re.sub(r"<think>[\s\S]*?</think>", "", content).strip()
|
||||
|
||||
event_stream_message = {
|
||||
"thread_id": thread_id,
|
||||
"agent": agent_name,
|
||||
|
||||
Reference in New Issue
Block a user