diff --git a/backend/app/main.py b/backend/app/main.py
index 4adfeef4..d624002d 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -958,3 +958,82 @@ async def stop_ai_service():
"status": "not_running",
"message": "Ollama was not running"
}
+
+
+# LLM 配置管理
+class LLMConfig(BaseModel):
+ provider: str = "deepseek" # ollama, deepseek, openai, qwen
+ api_key: Optional[str] = None
+ deepseek_api_key: Optional[str] = None
+ openai_api_key: Optional[str] = None
+ qwen_api_key: Optional[str] = None
+
+
+@app.get("/ai/config")
+async def get_ai_config():
+ """
+ 获取当前 LLM 配置
+ """
+ from dotenv import load_dotenv
+ import os
+
+ # 重新加载环境变量
+ env_path = Path(__file__).parent.parent / ".env"
+ load_dotenv(env_path)
+
+ provider = os.getenv("LLM_PROVIDER", "ollama")
+
+ return {
+ "provider": provider,
+ "ollama_host": os.getenv("OLLAMA_HOST", "http://127.0.0.1:11434"),
+ "has_deepseek_key": bool(os.getenv("DEEPSEEK_API_KEY")),
+ "has_openai_key": bool(os.getenv("OPENAI_API_KEY")),
+ "has_qwen_key": bool(os.getenv("QWEN_API_KEY")),
+ }
+
+
+@app.post("/ai/config")
+async def update_ai_config(config: LLMConfig):
+ """
+ 更新 LLM 配置(需要重启后端生效)
+ """
+ from dotenv import load_dotenv
+ import os
+
+ env_path = Path(__file__).parent.parent / ".env"
+
+ # 读取现有 .env 文件
+ env_vars = {}
+ if env_path.exists():
+ load_dotenv(env_path)
+ # 保留现有配置
+ for key, value in os.environ.items():
+ if key.startswith(("DEEPSEEK_", "OPENAI_", "QWEN_", "OLLAMA_", "LLM_")):
+ env_vars[key] = value
+
+ # 更新配置
+ env_vars["LLM_PROVIDER"] = config.provider
+
+ # 保存 API 密钥
+ if config.deepseek_api_key:
+ env_vars["DEEPSEEK_API_KEY"] = config.deepseek_api_key
+ if config.openai_api_key:
+ env_vars["OPENAI_API_KEY"] = config.openai_api_key
+ if config.qwen_api_key:
+ env_vars["QWEN_API_KEY"] = config.qwen_api_key
+
+ # 写入 .env 文件
+ with open(env_path, "w") as f:
+ for key, value in env_vars.items():
+ # 只保存 LLM 相关的环境变量
+ if key.startswith(("DEEPSEEK_", "OPENAI_", "QWEN_", "OLLAMA_", "LLM_")):
+ f.write(f"{key}={value}\n")
+
+ print(f"[AI] LLM 配置已更新: provider={config.provider}")
+
+ return {
+ "status": "success",
+ "message": "配置已保存,请重启后端服务生效",
+ "provider": config.provider,
+ "requires_restart": True
+ }
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index b5148331..2e87a337 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -24,6 +24,7 @@ import { darkTheme } from 'naive-ui'
import SignalDashboard from './components/SignalDashboard.vue'
import ExperimentBoard from './components/ExperimentBoard.vue'
import ContextManager from './components/ContextManager.vue'
+import LLMSettings from './components/LLMSettings.vue'
const theme = ref(darkTheme)
const activeKey = ref('signals')
@@ -31,7 +32,8 @@ const activeKey = ref('signals')
const menuOptions: MenuOption[] = [
{ label: '信号总线', key: 'signals' },
{ label: '实验看板', key: 'experiments' },
- { label: '认知核心', key: 'context' }
+ { label: '认知核心', key: 'context' },
+ { label: '⚙️ 设置', key: 'settings' }
]
const currentComponent = computed(() => {
@@ -39,6 +41,7 @@ const currentComponent = computed(() => {
case 'signals': return SignalDashboard
case 'experiments': return ExperimentBoard
case 'context': return ContextManager
+ case 'settings': return LLMSettings
default: return SignalDashboard
}
})
diff --git a/frontend/src/components/LLMSettings.vue b/frontend/src/components/LLMSettings.vue
new file mode 100644
index 00000000..01b956b6
--- /dev/null
+++ b/frontend/src/components/LLMSettings.vue
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+
+
+ {{ option.label }}
+ 云端
+ 本地
+
+
+
+
+
+
+
+ {{ providerInfo.text }}
+
+
+
+
+ API 密钥配置
+
+
+
+
+
+ 获取地址: platform.deepseek.com
+
+
+
+
+
+
+
+
+ 获取地址: platform.openai.com
+
+
+
+
+
+
+
+
+ 获取地址: dashscope.console.aliyun.com
+
+
+
+
+
+
+
+
+ 🔄 检测状态
+
+
+
+
+
+
+
+ 保存配置
+
+
+ 需要重启后端
+
+
+
+
+
+
+ DeepSeek 已配置
+ OpenAI 已配置
+ Qwen 已配置
+
+
+
+
+
+
+
+ 重启后端服务
+
+ LLM 配置已更改,需要重启后端服务才能生效。
+
+
+ 取消
+
+ 确认重启
+
+
+
+
+
+
+
+