feat: implement backend logic

This commit is contained in:
hetao
2025-06-11 13:17:54 +08:00
parent 397ac57235
commit c187ae511d
8 changed files with 1044 additions and 1001 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ dist/
wheels/ wheels/
*.egg-info *.egg-info
.coverage .coverage
.coverage.*
agent_history.gif agent_history.gif
static/browser_history/*.gif static/browser_history/*.gif

View File

@@ -32,6 +32,7 @@ dependencies = [
"arxiv>=2.2.0", "arxiv>=2.2.0",
"mcp>=1.6.0", "mcp>=1.6.0",
"langchain-mcp-adapters>=0.0.9", "langchain-mcp-adapters>=0.0.9",
"langchain-deepseek>=0.1.3",
] ]
[project.optional-dependencies] [project.optional-dependencies]

View File

@@ -23,6 +23,7 @@ class Configuration:
max_search_results: int = 3 # Maximum number of search results max_search_results: int = 3 # Maximum number of search results
mcp_settings: dict = None # MCP settings, including dynamic loaded tools mcp_settings: dict = None # MCP settings, including dynamic loaded tools
report_style: str = ReportStyle.ACADEMIC.value # Report style report_style: str = ReportStyle.ACADEMIC.value # Report style
enable_deep_thinking: bool = False # Whether to enable deep thinking
@classmethod @classmethod
def from_runnable_config( def from_runnable_config(

View File

@@ -101,7 +101,10 @@ def planner_node(
} }
] ]
if AGENT_LLM_MAP["planner"] == "basic": if (
AGENT_LLM_MAP["planner"] == "basic"
and not configurable.enable_deep_thinking
):
llm = get_llm_by_type(AGENT_LLM_MAP["planner"]).with_structured_output( llm = get_llm_by_type(AGENT_LLM_MAP["planner"]).with_structured_output(
Plan, Plan,
method="json_mode", method="json_mode",
@@ -114,7 +117,10 @@ def planner_node(
return Command(goto="reporter") return Command(goto="reporter")
full_response = "" full_response = ""
if AGENT_LLM_MAP["planner"] == "basic": if (
AGENT_LLM_MAP["planner"] == "basic"
and not configurable.enable_deep_thinking
):
response = llm.invoke(messages) response = llm.invoke(messages)
full_response = response.model_dump_json(indent=4, exclude_none=True) full_response = response.model_dump_json(indent=4, exclude_none=True)
else: else:

View File

@@ -6,6 +6,7 @@ from typing import Any, Dict
import os import os
from langchain_openai import ChatOpenAI from langchain_openai import ChatOpenAI
from langchain_deepseek import ChatDeepSeek
from src.config import load_yaml_config from src.config import load_yaml_config
from src.config.agents import LLMType from src.config.agents import LLMType
@@ -29,7 +30,9 @@ def _get_env_llm_conf(llm_type: str) -> Dict[str, Any]:
return conf return conf
def _create_llm_use_conf(llm_type: LLMType, conf: Dict[str, Any]) -> ChatOpenAI: def _create_llm_use_conf(
llm_type: LLMType, conf: Dict[str, Any]
) -> ChatOpenAI | ChatDeepSeek:
llm_type_map = { llm_type_map = {
"reasoning": conf.get("REASONING_MODEL", {}), "reasoning": conf.get("REASONING_MODEL", {}),
"basic": conf.get("BASIC_MODEL", {}), "basic": conf.get("BASIC_MODEL", {}),
@@ -47,7 +50,14 @@ def _create_llm_use_conf(llm_type: LLMType, conf: Dict[str, Any]) -> ChatOpenAI:
if not merged_conf: if not merged_conf:
raise ValueError(f"Unknown LLM Conf: {llm_type}") raise ValueError(f"Unknown LLM Conf: {llm_type}")
return ChatOpenAI(**merged_conf) if llm_type == "reasoning":
merged_conf["api_base"] = merged_conf.pop("base_url")
return (
ChatOpenAI(**merged_conf)
if llm_type != "reasoning"
else ChatDeepSeek(**merged_conf)
)
def get_llm_by_type( def get_llm_by_type(

View File

@@ -24,7 +24,6 @@ from src.prompt_enhancer.graph.builder import build_graph as build_prompt_enhanc
from src.rag.builder import build_retriever from src.rag.builder import build_retriever
from src.rag.retriever import Resource from src.rag.retriever import Resource
from src.server.chat_request import ( from src.server.chat_request import (
ChatMessage,
ChatRequest, ChatRequest,
EnhancePromptRequest, EnhancePromptRequest,
GeneratePodcastRequest, GeneratePodcastRequest,
@@ -81,6 +80,7 @@ async def chat_stream(request: ChatRequest):
request.mcp_settings, request.mcp_settings,
request.enable_background_investigation, request.enable_background_investigation,
request.report_style, request.report_style,
request.enable_deep_thinking,
), ),
media_type="text/event-stream", media_type="text/event-stream",
) )
@@ -98,6 +98,7 @@ async def _astream_workflow_generator(
mcp_settings: dict, mcp_settings: dict,
enable_background_investigation: bool, enable_background_investigation: bool,
report_style: ReportStyle, report_style: ReportStyle,
enable_deep_thinking: bool,
): ):
input_ = { input_ = {
"messages": messages, "messages": messages,
@@ -125,6 +126,7 @@ async def _astream_workflow_generator(
"max_search_results": max_search_results, "max_search_results": max_search_results,
"mcp_settings": mcp_settings, "mcp_settings": mcp_settings,
"report_style": report_style.value, "report_style": report_style.value,
"enable_deep_thinking": enable_deep_thinking,
}, },
stream_mode=["messages", "updates"], stream_mode=["messages", "updates"],
subgraphs=True, subgraphs=True,
@@ -156,6 +158,10 @@ async def _astream_workflow_generator(
"role": "assistant", "role": "assistant",
"content": message_chunk.content, "content": message_chunk.content,
} }
if message_chunk.additional_kwargs.get("reasoning_content"):
event_stream_message["reasoning_content"] = message_chunk.additional_kwargs[
"reasoning_content"
]
if message_chunk.response_metadata.get("finish_reason"): if message_chunk.response_metadata.get("finish_reason"):
event_stream_message["finish_reason"] = message_chunk.response_metadata.get( event_stream_message["finish_reason"] = message_chunk.response_metadata.get(
"finish_reason" "finish_reason"

View File

@@ -62,6 +62,9 @@ class ChatRequest(BaseModel):
report_style: Optional[ReportStyle] = Field( report_style: Optional[ReportStyle] = Field(
ReportStyle.ACADEMIC, description="The style of the report" ReportStyle.ACADEMIC, description="The style of the report"
) )
enable_deep_thinking: Optional[bool] = Field(
False, description="Whether to enable deep thinking"
)
class TTSRequest(BaseModel): class TTSRequest(BaseModel):

2007
uv.lock generated

File diff suppressed because it is too large Load Diff