fix(docker): 在 Dockerfile 中添加 libpq5 并更新 LangGraph 的部分特性以支持 PostgreSQL

同时更新默认模型为 Pro 分类
This commit is contained in:
Wenjie Zhang 2026-03-07 09:12:29 +00:00
parent 321221445d
commit d81bd1911a
6 changed files with 37 additions and 9 deletions

View File

@ -29,6 +29,7 @@ RUN set -ex \
&& apt-get install -y --no-install-recommends --fix-missing \ && apt-get install -y --no-install-recommends --fix-missing \
curl \ curl \
ffmpeg \ ffmpeg \
libpq5 \
libsm6 \ libsm6 \
libxext6 \ libxext6 \
# (D) 清理垃圾,减小体积 # (D) 清理垃圾,减小体积

View File

@ -37,7 +37,7 @@ class Config(BaseModel):
enable_content_guard: bool = Field(default=False, description="是否启用内容审查") enable_content_guard: bool = Field(default=False, description="是否启用内容审查")
# 模型配置 # 模型配置
default_model: str = Field(default="siliconflow/deepseek-ai/DeepSeek-V3.2") default_model: str = Field(default="default="siliconflow/Pro/deepseek-ai/DeepSeek-V3.2")
embed_model: str = Field(default="siliconflow/BAAI/bge-m3") embed_model: str = Field(default="siliconflow/BAAI/bge-m3")
# 运行时状态 (不持久化) # 运行时状态 (不持久化)

View File

@ -32,7 +32,7 @@
系统的默认对话模型可以在设置页面配置,也可以通过配置项 `default_model` 指定,格式统一为 `模型提供商/模型名称`,例如: 系统的默认对话模型可以在设置页面配置,也可以通过配置项 `default_model` 指定,格式统一为 `模型提供商/模型名称`,例如:
```yaml ```yaml
default_model: siliconflow/deepseek-ai/DeepSeek-V3.2 default_model: default="siliconflow/Pro/deepseek-ai/DeepSeek-V3.2
``` ```
## 自定义模型供应商 ## 自定义模型供应商

View File

@ -1,9 +1,11 @@
from __future__ import annotations from __future__ import annotations
import asyncio
import importlib.util import importlib.util
import os import os
import tomllib as tomli import tomllib as tomli
from abc import abstractmethod from abc import abstractmethod
from inspect import isawaitable
from pathlib import Path from pathlib import Path
from langgraph.checkpoint.memory import InMemorySaver from langgraph.checkpoint.memory import InMemorySaver
@ -28,6 +30,7 @@ class BaseAgent:
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.graph = None # will be covered by get_graph self.graph = None # will be covered by get_graph
self.checkpointer = None self.checkpointer = None
self._checkpointer_cm = None
self._async_conn = None self._async_conn = None
self.workdir = Path(sys_config.save_dir) / "agents" / self.module_name self.workdir = Path(sys_config.save_dir) / "agents" / self.module_name
self.workdir.mkdir(parents=True, exist_ok=True) self.workdir.mkdir(parents=True, exist_ok=True)
@ -156,6 +159,15 @@ class BaseAgent:
def reload_graph(self): def reload_graph(self):
"""重置 graph 缓存,强制下次调用 get_graph 时重新构建""" """重置 graph 缓存,强制下次调用 get_graph 时重新构建"""
self.graph = None self.graph = None
self.checkpointer = None
if self._checkpointer_cm is not None:
try:
loop = asyncio.get_running_loop()
except RuntimeError:
loop = None
if loop is not None:
loop.create_task(self._close_checkpointer_context())
logger.info(f"{self.name} graph 缓存已清空,将在下次调用时重新构建") logger.info(f"{self.name} graph 缓存已清空,将在下次调用时重新构建")
@abstractmethod @abstractmethod
@ -207,10 +219,14 @@ class BaseAgent:
else: else:
saver = AsyncPostgresSaver(conn_str) # type: ignore[call-arg] saver = AsyncPostgresSaver(conn_str) # type: ignore[call-arg]
if hasattr(saver, "__aenter__") and hasattr(saver, "__aexit__"):
self._checkpointer_cm = saver
saver = await saver.__aenter__()
setup_fn = getattr(saver, "setup", None) setup_fn = getattr(saver, "setup", None)
if callable(setup_fn): if callable(setup_fn):
result = setup_fn() result = setup_fn()
if hasattr(result, "__await__"): if isawaitable(result):
await result await result
logger.info(f"{self.name} 使用 postgres checkpointer") logger.info(f"{self.name} 使用 postgres checkpointer")
return saver return saver
@ -218,6 +234,17 @@ class BaseAgent:
logger.warning(f"初始化 postgres checkpointer 失败,回退 sqlite: {e}") logger.warning(f"初始化 postgres checkpointer 失败,回退 sqlite: {e}")
return None return None
async def _close_checkpointer_context(self):
if self._checkpointer_cm is None:
return
cm = self._checkpointer_cm
self._checkpointer_cm = None
try:
await cm.__aexit__(None, None, None)
except Exception as e:
logger.warning(f"关闭 postgres checkpointer 失败: {e}")
async def get_async_conn(self) -> aiosqlite.Connection: async def get_async_conn(self) -> aiosqlite.Connection:
"""获取异步数据库连接""" """获取异步数据库连接"""
if self._async_conn is not None: if self._async_conn is not None:

View File

@ -101,7 +101,7 @@ class DeepContext(BaseContext):
) )
subagents_model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field( subagents_model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
default="siliconflow/deepseek-ai/DeepSeek-V3.2", default="siliconflow/Pro/deepseek-ai/DeepSeek-V3.2",
metadata={ metadata={
"name": "Sub-agent Model", "name": "Sub-agent Model",
"description": "The model used by sub-agents (e.g., critique-agent, research-agent).", "description": "The model used by sub-agents (e.g., critique-agent, research-agent).",

View File

@ -47,23 +47,23 @@ class Config(BaseModel):
# 模型配置 # 模型配置
# ============================================================ # ============================================================
default_model: str = Field( default_model: str = Field(
default="siliconflow/deepseek-ai/DeepSeek-V3.2", default="siliconflow/Pro/deepseek-ai/DeepSeek-V3.2",
description="默认对话模型", description="默认对话模型",
) )
fast_model: str = Field( fast_model: str = Field(
default="siliconflow/THUDM/GLM-4-9B-0414", default="siliconflow/Qwen/Qwen3.5-9B",
description="快速响应模型", description="快速响应模型",
) )
embed_model: str = Field( embed_model: str = Field(
default="siliconflow/BAAI/bge-m3", default="siliconflow/Pro/BAAI/bge-m3",
description="默认 Embedding 模型", description="默认 Embedding 模型",
) )
reranker: str = Field( reranker: str = Field(
default="siliconflow/BAAI/bge-reranker-v2-m3", default="siliconflow/Pro/BAAI/bge-reranker-v2-m3",
description="默认 Re-Ranker 模型", description="默认 Re-Ranker 模型",
) )
content_guard_llm_model: str = Field( content_guard_llm_model: str = Field(
default="siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507", default="siliconflow/Qwen/Qwen3.5-9B",
description="内容审查LLM模型", description="内容审查LLM模型",
) )