diff --git a/pyproject.toml b/pyproject.toml index cd171a61..7274896e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,13 +5,16 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.11" dependencies = [ + "colorlog>=6.9.0", "dashscope>=1.23.2", "docx2txt>=0.9", "fastapi>=0.115.12", "flagembedding>=1.3.4", "langchain-community>=0.3.22", + "langchain-deepseek>=0.1.3", "langchain-huggingface>=0.2.0", "langchain-openai>=0.3.14", + "langchain-together>=0.3.0", "langgraph>=0.3.34", "langgraph-checkpoint-sqlite>=2.0.7", "langsmith>=0.3.37", diff --git a/server/routers/chat_router.py b/server/routers/chat_router.py index 19a62bc1..4a8e74e8 100644 --- a/server/routers/chat_router.py +++ b/server/routers/chat_router.py @@ -213,7 +213,7 @@ async def chat_agent(agent_name: str, try: async for msg, metadata in agent.stream_messages(messages, config_schema=runnable_config): - logger.debug(f"msg: {msg.model_dump()}, metadata: {metadata}") + # logger.debug(f"msg: {msg.model_dump()}, metadata: {metadata}") if isinstance(msg, AIMessageChunk): yield make_chunk(content=msg.content, msg=msg.model_dump(), diff --git a/src/agents/chatbot/configuration.py b/src/agents/chatbot/configuration.py index 18ce117a..dd8fd2d5 100644 --- a/src/agents/chatbot/configuration.py +++ b/src/agents/chatbot/configuration.py @@ -49,8 +49,8 @@ class ChatbotConfiguration(Configuration): "configurable": True, "options": [ "zhipu/glm-4-plus", - "siliconflow/Qwen/QwQ-32B", - "siliconflow/deepseek-ai/DeepSeek-V3", + "siliconflow/Qwen/Qwen2.5-72B-Instruct", + "siliconflow/Qwen/Qwen2.5-7B-Instruct", ], "description": "智能体的驱动模型" }, diff --git a/src/agents/react/graph.py b/src/agents/react/graph.py index 73001e6f..7de5b3df 100644 --- a/src/agents/react/graph.py +++ b/src/agents/react/graph.py @@ -1,18 +1,9 @@ import asyncio import uuid -from typing import Any -from datetime import datetime - -from langchain_core.runnables import RunnableConfig -from langgraph.graph import StateGraph, START, END -from langgraph.prebuilt import ToolNode, tools_condition -from langgraph.checkpoint.memory import MemorySaver -from langchain_community.tools.tavily_search import TavilySearchResults -from src.agents.registry import State, BaseAgent -from src.agents.utils import load_chat_model -from src.agents.react.configuration import ReActConfiguration, multiply +from src.agents.registry import BaseAgent +from src.agents.react.configuration import ReActConfiguration class ReActAgent(BaseAgent): name = "react" diff --git a/src/agents/tools_factory.py b/src/agents/tools_factory.py index 75e6de7d..739f0b75 100644 --- a/src/agents/tools_factory.py +++ b/src/agents/tools_factory.py @@ -133,17 +133,17 @@ def calculator(a: float, b: float, operation: str) -> float: raise ValueError(f"Invalid operation: {operation}, only support add, subtract, multiply, divide") @tool -def get_knowledge_graph(query: Annotated[str, "The query to get knowledge graph."]): - """Use this to get knowledge graph.""" +def query_knowledge_graph(query: Annotated[str, "The keyword to query knowledge graph."]): + """Use this to query knowledge graph.""" return graph_base.query_node(query, hops=2) _TOOLS_REGISTRY = { - "calculator": calculator, - "get_knowledge_graph": get_knowledge_graph, + "Calculator": calculator, + "QueryKnowledgeGraph": query_knowledge_graph, } if config.enable_web_search: - _TOOLS_REGISTRY["TavilySearchResults"] = TavilySearchResults(max_results=10) + _TOOLS_REGISTRY["WebSearchWithTavily"] = TavilySearchResults(max_results=10) diff --git a/src/models/__init__.py b/src/models/__init__.py index 19867377..7615816e 100644 --- a/src/models/__init__.py +++ b/src/models/__init__.py @@ -30,6 +30,32 @@ def select_model(model_provider=None, model_name=None): from src.models.chat_model import OpenModel return OpenModel(model_name) + if model_provider == "deepseek": + from langchain_deepseek import ChatDeepSeek + return OpenAIBase( + api_key=os.getenv(model_info["env"][0]), + base_url=model_info["base_url"], + model_name=model_name, + chat_open_ai=ChatDeepSeek( + model=model_name, + api_key=os.getenv(model_info["env"][0]), + base_url=model_info["base_url"], + ) + ) + + if model_provider == "together": + from langchain_together import ChatTogether + return OpenAIBase( + api_key=os.getenv(model_info["env"][0]), + base_url=model_info["base_url"], + model_name=model_name, + chat_open_ai=ChatTogether( + model=model_name, + api_key=os.getenv(model_info["env"][0]), + base_url=model_info["base_url"], + ) + ) + if model_provider == "custom": model_info = next((x for x in config.custom_models if x["custom_id"] == model_name), None) if model_info is None: diff --git a/src/models/chat_model.py b/src/models/chat_model.py index 47e0ca2e..5699a20d 100644 --- a/src/models/chat_model.py +++ b/src/models/chat_model.py @@ -5,13 +5,13 @@ from src.utils import logger, get_docker_safe_url from langchain_openai import ChatOpenAI class OpenAIBase(): - def __init__(self, api_key, base_url, model_name, **kwargs): + def __init__(self, api_key, base_url, model_name, chat_open_ai=None, **kwargs): self.api_key = api_key self.base_url = base_url self.client = OpenAI(api_key=api_key, base_url=base_url) self.model_name = model_name self.info = kwargs - self.chat_open_ai = ChatOpenAI(model=model_name, + self.chat_open_ai = chat_open_ai or ChatOpenAI(model=model_name, api_key=api_key, base_url=base_url) diff --git a/src/static/models.yaml b/src/static/models.yaml index 4cf9edbe..219e0bf5 100644 --- a/src/static/models.yaml +++ b/src/static/models.yaml @@ -70,6 +70,7 @@ MODEL_NAMES: - meta-llama/Llama-3.3-70B-Instruct-Turbo - meta-llama/Llama-3.3-70B-Instruct-Turbo-Free - deepseek-ai/DeepSeek-R1-Distill-Llama-70B-free + - Qwen/QwQ-32B dashscope: name: 阿里百炼 (DashScope) diff --git a/src/utils/logging_config.py b/src/utils/logging_config.py index 5a89ff68..26a48417 100644 --- a/src/utils/logging_config.py +++ b/src/utils/logging_config.py @@ -2,8 +2,10 @@ import logging import os from datetime import datetime +import pytz +from colorlog import ColoredFormatter -DATETIME = datetime.now().strftime('%Y-%m-%d-%H%M%S') +DATETIME = datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d-%H%M%S') # DATETIME = "debug" # 为了方便,调试的时候输出到 debug.log 文件 LOG_FILE = f'saves/log/project-{DATETIME}.log' @@ -18,20 +20,29 @@ def setup_logger(name, level=logging.DEBUG, console=True): if logger.hasHandlers(): logger.handlers.clear() - # File handler for logging to a file - file_handler = logging.FileHandler(LOG_FILE) + # 文件日志(无颜色) + file_handler = logging.FileHandler(LOG_FILE, encoding='utf-8') file_handler.setLevel(level) - - # Formatter for the logs - formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s') - file_handler.setFormatter(formatter) + file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s') + file_handler.setFormatter(file_formatter) logger.addHandler(file_handler) - # Console handler for logging to the console (optional) + # 控制台日志(有颜色) if console: console_handler = logging.StreamHandler() console_handler.setLevel(level) - console_handler.setFormatter(formatter) + color_formatter = ColoredFormatter( + "%(log_color)s%(asctime)s - %(levelname)s - %(name)s - %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + log_colors={ + 'DEBUG': 'cyan', + 'INFO': 'green', + 'WARNING': 'yellow', + 'ERROR': 'red', + 'CRITICAL': 'bold_red', + } + ) + console_handler.setFormatter(color_formatter) logger.addHandler(console_handler) return logger diff --git a/uv.lock b/uv.lock index 382ba7e0..7db9e09a 100644 --- a/uv.lock +++ b/uv.lock @@ -425,6 +425,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" }, ] +[[package]] +name = "colorlog" +version = "6.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d3/7a/359f4d5df2353f26172b3cc39ea32daa39af8de522205f512f458923e677/colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2", size = 16624, upload-time = "2024-10-29T18:34:51.011Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/51/9b208e85196941db2f0654ad0357ca6388ab3ed67efdbfc799f35d1f83aa/colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff", size = 11424, upload-time = "2024-10-29T18:34:49.815Z" }, +] + [[package]] name = "cryptography" version = "44.0.2" @@ -1282,6 +1294,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/40/aa440a7cd05f1dab5d7c91a1284eb776c3cf3eb59fa18ed39927650cfa38/langchain_core-0.3.59-py3-none-any.whl", hash = "sha256:9686baaff43f2c8175535da13faf40e6866769015e93130c3c1e4243e7244d70", size = 437656, upload-time = "2025-05-07T17:58:22.251Z" }, ] +[[package]] +name = "langchain-deepseek" +version = "0.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langchain-openai" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/7f/be5bcf99b3814214a02ac205bda66d49d55a7d5440d47223105cef5df063/langchain_deepseek-0.1.3.tar.gz", hash = "sha256:89dd6aa120fb50dcfcd3d593626d34c1c40deefe4510710d0807fcc19481adf5", size = 7860, upload-time = "2025-03-21T17:11:58.356Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/7d/51b60aa91fa77742fc461704e5a8497e856156ae878102e6942799a78915/langchain_deepseek-0.1.3-py3-none-any.whl", hash = "sha256:8588e826371b417fca65c02f4273b4061eb9815a7bfcd5eb05acaa40d603aa89", size = 7123, upload-time = "2025-03-21T17:11:57.481Z" }, +] + [[package]] name = "langchain-huggingface" version = "0.2.0" @@ -1324,6 +1349,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/a3/3696ff2444658053c01b6b7443e761f28bb71217d82bb89137a978c5f66f/langchain_text_splitters-0.3.8-py3-none-any.whl", hash = "sha256:e75cc0f4ae58dcf07d9f18776400cf8ade27fadd4ff6d264df6278bb302f6f02", size = 32440, upload-time = "2025-04-04T14:03:50.6Z" }, ] +[[package]] +name = "langchain-together" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "langchain-core" }, + { name = "langchain-openai" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/c4/64b92524121eaf4e805ade7ea68e71d52eab5e8fdad9b6b8e62f5a99eff4/langchain_together-0.3.0.tar.gz", hash = "sha256:c8a96377e49c065526435f766c6e1c7da3f7d054361326f079de8bd368ea76f2", size = 10247, upload-time = "2025-01-10T17:06:08.729Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/69/b3cbcf5b43acbc098c012ef75035fb0dc1e0f227f5161329ef9884a25ba4/langchain_together-0.3.0-py3-none-any.whl", hash = "sha256:4dcb4f6858c910c23d2268da1ed5f54e8cd01224ecf086dc7a8adbacdc6cb686", size = 12338, upload-time = "2025-01-10T17:06:06.678Z" }, +] + [[package]] name = "langdetect" version = "1.0.9" @@ -4515,13 +4555,16 @@ name = "yuxi-know" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "colorlog" }, { name = "dashscope" }, { name = "docx2txt" }, { name = "fastapi" }, { name = "flagembedding" }, { name = "langchain-community" }, + { name = "langchain-deepseek" }, { name = "langchain-huggingface" }, { name = "langchain-openai" }, + { name = "langchain-together" }, { name = "langgraph" }, { name = "langgraph-checkpoint-sqlite" }, { name = "langsmith" }, @@ -4549,13 +4592,16 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "colorlog", specifier = ">=6.9.0" }, { name = "dashscope", specifier = ">=1.23.2" }, { name = "docx2txt", specifier = ">=0.9" }, { name = "fastapi", specifier = ">=0.115.12" }, { name = "flagembedding", specifier = ">=1.3.4" }, { name = "langchain-community", specifier = ">=0.3.22" }, + { name = "langchain-deepseek", specifier = ">=0.1.3" }, { name = "langchain-huggingface", specifier = ">=0.2.0" }, { name = "langchain-openai", specifier = ">=0.3.14" }, + { name = "langchain-together", specifier = ">=0.3.0" }, { name = "langgraph", specifier = ">=0.3.34" }, { name = "langgraph-checkpoint-sqlite", specifier = ">=2.0.7" }, { name = "langsmith", specifier = ">=0.3.37" }, diff --git a/web/package.json b/web/package.json index df8796a5..02915579 100644 --- a/web/package.json +++ b/web/package.json @@ -23,6 +23,7 @@ "echarts-gl": "^2.0.9", "highlight.js": "^11.11.1", "less": "^4.3.0", + "lucide-vue-next": "^0.511.0", "marked": "^15.0.11", "marked-highlight": "^2.2.1", "md-editor-v3": "^5.5.1", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 86149c17..ebfdec73 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: less: specifier: ^4.3.0 version: 4.3.0 + lucide-vue-next: + specifier: ^0.511.0 + version: 0.511.0(vue@3.5.14) marked: specifier: ^15.0.11 version: 15.0.11 @@ -1644,6 +1647,11 @@ packages: peerDependencies: vue: '>=3.0.1' + lucide-vue-next@0.511.0: + resolution: {integrity: sha512-VSv0F3pHniGN7JMMzDcLFNMQbl8381+shNnHwV8hi+El7xl2ZL8qdNuzPoiBViKk8mTKK5K3ZDfmE/wEcTZVIQ==} + peerDependencies: + vue: '>=3.0.1' + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -4008,6 +4016,10 @@ snapshots: dependencies: vue: 3.5.14 + lucide-vue-next@0.511.0(vue@3.5.14): + dependencies: + vue: 3.5.14 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 diff --git a/web/src/components/AgentChatComponent.vue b/web/src/components/AgentChatComponent.vue index c4134a78..85aab5f3 100644 --- a/web/src/components/AgentChatComponent.vue +++ b/web/src/components/AgentChatComponent.vue @@ -19,10 +19,10 @@
请注意辨别内容的可靠性
+请注意辨别内容的可靠性
{{ value.description }}
+ +注意,部分模型对于 Tool Calling 的支持不稳定,建议采用{{ value.options }}
+