给deerflow2.0增加一个模型选择器,实现模型热重载
·
模型选择器实现指南

本文档详细记录了在 DeerFlow 项目中增加模型选择器的完整方法和过程。
一、功能概述
模型选择器允许用户在前端界面选择不同的 LLM 模型,并在运行时使用选定的模型执行任务。主要特性包括:
- 实时模型切换,无需重启服务
- 支持配置文件中的所有模型
- 中间件(标题生成、摘要、记忆)可独立配置模型
- 配置热重载机制
二、实现架构
2.1 整体数据流
用户选择模型
│
▼
模型切换器 UI (localStorage + 事件通知)
│
▼
前端状态管理 (useLocalSettings hook)
│
▼
ChatPage 传递 context 到 useThreadStream
│
▼
thread.submit(config.configurable)
│
▼
后端 make_lead_agent 解析 model_name
│
▼
create_chat_model(name=model_name)
│
▼
执行任务时使用选定模型
2.2 关键组件
| 组件 | 位置 | 职责 |
|---|---|---|
| 模型切换器 UI | public/model-switcher/index.html |
展示模型列表,处理用户选择 |
| 后端 API | backend/app/gateway/routers/models.py |
提供模型列表、默认模型设置、配置重载接口 |
| 配置管理 | backend/packages/harness/deerflow/config/app_config.py |
管理应用配置,支持热重载 |
| 前端状态 | frontend/src/core/hooks/useLocalSettings.ts |
管理本地设置状态和事件通知 |
| 线程通信 | frontend/src/core/threads/hooks.ts |
将模型名称传递到后端 |
| 代理创建 | backend/packages/harness/deerflow/agents/lead_agent/agent.py |
根据运行时配置创建代理和模型 |
三、详细实现步骤
3.1 前端模型切换器 UI
文件: frontend/public/model-switcher/index.html
功能:
- 从后端 API 获取模型列表
- 显示当前选中的模型
- 允许用户切换模型
- 支持配置重载
关键代码:
// 获取模型列表
async function fetchModels() {
const res = await fetch(apiBase + '/api/models');
const data = await res.json();
renderModelList(data);
}
// 切换模型
async function switchModel(name) {
await fetch(apiBase + '/api/model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model_name: name })
});
// 更新本地存储并触发事件
localStorage.setItem('df_model_name', name);
dispatchEvent(new CustomEvent('df-settings-changed', { detail: { model_name: name } }));
}
// 重载配置
async function reloadConfig() {
await fetch(apiBase + '/api/model/reload', { method: 'POST' });
fetchModels();
}
部署:
将 model-switcher 目录放置在 frontend/public/ 下,通过 iframe 嵌入主应用。
3.2 后端 API 路由
文件: backend/app/gateway/routers/models.py
新增接口:
| 接口 | 方法 | 功能 |
|---|---|---|
/api/models |
GET | 获取所有可用模型列表 |
/api/model |
POST | 设置默认模型 |
/api/model/reload |
POST | 热重载配置文件 |
关键代码:
@router.post("/model", response_model=SetDefaultModelResponse)
async def set_default_model(request: SetDefaultModelRequest) -> SetDefaultModelResponse:
success = set_default_model(request.model_name)
return SetDefaultModelResponse(success=success)
@router.post("/model/reload", response_model=ReloadConfigResponse)
async def reload_model_config() -> ReloadConfigResponse:
config = reload_app_config()
return ReloadConfigResponse(
success=True,
models_count=len(config.models),
)
3.3 配置管理增强
文件: backend/packages/harness/deerflow/config/app_config.py
关键修改:
set_default_model()- 运行时设置默认模型reload_app_config()- 热重载配置文件reset_app_config()- 重置配置缓存
def set_default_model(model_name: str) -> bool:
"""Set the default model at runtime."""
global _app_config
if _app_config is None:
_app_config = AppConfig.from_file()
model_config = _app_config.get_model_config(model_name)
if model_config is None:
return False
_app_config.default_model = model_name
return True
def reload_app_config(config_path: str | None = None) -> AppConfig:
"""Reload the config from file and update the cached instance."""
global _app_config
_app_config = AppConfig.from_file(config_path)
return _app_config
导出配置: backend/packages/harness/deerflow/config/__init__.py
from .app_config import get_app_config, reload_app_config, set_default_model
__all__ = [
"get_app_config",
"reload_app_config",
"set_default_model",
# ... other exports
]
3.4 前端状态管理
文件: frontend/src/core/hooks/useLocalSettings.ts
功能:
- 监听
df-settings-changed事件 - 同步 localStorage 中的模型名称
- 更新全局设置状态
关键代码:
useEffect(() => {
const handleSettingsChanged = (e: Event) => {
const detail = (e as CustomEvent).detail;
if (detail?.model_name) {
setSettings(prev => ({
...prev,
context: { ...prev.context, model_name: detail.model_name }
}));
}
};
window.addEventListener('df-settings-changed', handleSettingsChanged);
return () => window.removeEventListener('df-settings-changed', handleSettingsChanged);
}, []);
3.5 线程通信参数传递
文件: frontend/src/core/threads/hooks.ts
关键修改:
将 model_name 通过 config.configurable 传递到后端。
await thread.submit(
{ messages: [...] },
{
threadId: threadId,
config: {
recursion_limit: 1000,
configurable: {
...context,
model_name: context.model_name,
// ... other configurable options
},
},
},
);
注意事项:
- 参数必须放在
config.configurable中,LangGraph SDK 才能正确传递 - 不能放在顶层
context参数中
3.6 后端代理模型解析
文件: backend/packages/harness/deerflow/agents/lead_agent/agent.py
关键修改:
- 在
make_lead_agent()中解析运行时模型名称
def make_lead_agent(config: RunnableConfig) -> LeadAgent:
cfg = config.get("configurable", {})
requested_model_name = cfg.get("model_name")
# 解析最终使用的模型名称
agent_model_name = agent_config.model if agent_config and agent_config.model else _resolve_model_name(requested_model_name)
# 创建模型实例
model = create_chat_model(name=agent_model_name, thinking_enabled=thinking_enabled)
_resolve_model_name()函数
def _resolve_model_name(requested_name: str | None = None) -> str:
"""Resolve the model name based on request and config."""
if requested_name:
return requested_name
config = get_app_config()
return config.default_model if config.default_model else config.models[0].name
3.7 中间件模型配置
文件: config.yaml
三个中间件支持独立配置模型:
# 标题生成中间件
title:
enabled: true
model_name: deepseek-r1:1.5b # 使用本地模型,节省成本
# 摘要中间件
summarization:
enabled: true
model_name: deepseek-r1:1.5b
trigger:
- type: tokens
value: 15564
# 记忆中间件
memory:
enabled: true
model_name: deepseek-r1:1.5b
四、模型配置示例
4.1 远程 API 模型(火山引擎豆包)
models:
- name: doubao-seed-evolving
display_name: doubao-seed-evolving
use: deerflow.models.patched_deepseek:PatchedChatDeepSeek
model: doubao-seed-evolving
api_base: https://ark.cn-beijing.volces.com/api/v3
api_key: $VOLCENGINE_API_KEY
supports_thinking: true
supports_vision: false
4.2 本地 Ollama 模型
models:
- name: deepseek-r1:1.5b
display_name: DeepSeek-R1 1.5B Local Ollama
use: langchain_openai:ChatOpenAI
model: deepseek-r1:1.5b
api_key: dummy
base_url: http://localhost:11434/v1
max_tokens: 2048
supports_vision: false
注意事项:
- 本地 Ollama 模型必须使用
langchain_openai:ChatOpenAI api_key可以是任意值(Ollama 不需要认证)base_url指向本地 Ollama 服务
五、测试验证
5.1 验证配置加载
# 验证模型列表
python -c "from deerflow.config import get_app_config; cfg = get_app_config(); print([m.name for m in cfg.models])"
# 验证中间件配置
python -c "from deerflow.config import reload_app_config; reload_app_config(); from deerflow.config.summarization_config import get_summarization_config; print(get_summarization_config().model_name)"
5.2 验证模型创建
python -c "from deerflow.models import create_chat_model; m = create_chat_model(name='deepseek-r1:1.5b'); print(type(m).__name__)"
# 输出: ChatOpenAI
5.3 验证 API 接口
# 获取模型列表
curl http://localhost:8001/api/models
# 设置默认模型
curl -X POST http://localhost:8001/api/model \
-H "Content-Type: application/json" \
-d '{"model_name": "doubao-seed-evolving"}'
# 重载配置
curl -X POST http://localhost:8001/api/model/reload
七、代码修改清单
| 文件 | 修改类型 | 说明 |
|---|---|---|
frontend/public/model-switcher/index.html |
新增 | 模型切换器 UI |
backend/app/gateway/routers/models.py |
新增 | 模型管理 API |
backend/packages/harness/deerflow/config/app_config.py |
修改 | 增加配置重载和默认模型设置 |
backend/packages/harness/deerflow/config/__init__.py |
修改 | 导出新函数 |
frontend/src/core/hooks/useLocalSettings.ts |
修改 | 监听模型切换事件 |
frontend/src/core/threads/hooks.ts |
修改 | 通过 configurable 传递模型名称 |
backend/packages/harness/deerflow/agents/lead_agent/agent.py |
修改 | 解析运行时模型名称 |
config.yaml |
修改 | 配置中间件模型 |
八、总结
模型选择器的实现涉及前端 UI、状态管理、API 通信和后端配置解析等多个环节。核心要点是:
- 参数传递: 通过
config.configurable将模型名称从前端传递到后端 - 配置热重载: 支持不重启服务更新配置
- 中间件独立: 中间件可以使用与主代理不同的模型,降低成本
- 本地模型支持: 通过 OpenAI 兼容接口连接本地 Ollama 服务
通过这些修改,用户可以在运行时灵活切换模型,同时中间件使用轻量级本地模型来节省 API 费用。
更多推荐




所有评论(0)