267 lines
7.2 KiB
Markdown
267 lines
7.2 KiB
Markdown
# 开发日志 - 2026-03-06
|
||
|
||
## 修复:深度思考内容不显示
|
||
|
||
### 问题描述
|
||
启用深度思考后,后端日志显示已启用深度思考功能,但前端没有显示深度思考内容。
|
||
|
||
### 根本原因
|
||
前端 `src/services/api.ts` 中的 `streamChat` 方法只处理了普通 `content`,完全忽略了后端返回的 `reasoning_content`(深度思考内容)。
|
||
|
||
### 解决方案
|
||
|
||
#### 1. 前端 `src/services/api.ts`
|
||
|
||
添加 `StreamChunk` 接口,区分内容类型:
|
||
|
||
```typescript
|
||
// 流式响应块类型
|
||
export interface StreamChunk {
|
||
type: "content" | "reasoning";
|
||
text: string;
|
||
}
|
||
```
|
||
|
||
修改 `streamChat` 方法同时处理两种内容:
|
||
|
||
```typescript
|
||
const delta = data.choices?.[0]?.delta;
|
||
|
||
// 处理深度思考内容(reasoning_content)
|
||
const reasoningContent = delta?.reasoning_content;
|
||
if (reasoningContent) {
|
||
yield { type: "reasoning", text: reasoningContent };
|
||
}
|
||
|
||
// 处理普通内容
|
||
const content = delta?.content;
|
||
if (content) {
|
||
yield { type: "content", text: content };
|
||
}
|
||
```
|
||
|
||
#### 2. 前端 `src/components/chat/ChatMain.vue`
|
||
|
||
修改流式处理逻辑,将 `reasoning` 类型内容包装成 `<think>` 标签:
|
||
|
||
```typescript
|
||
let isInReasoning = false;
|
||
|
||
for await (const chunk of stream) {
|
||
if (chunk.type === "reasoning") {
|
||
if (!isInReasoning) {
|
||
isInReasoning = true;
|
||
fullText += "<think>\n";
|
||
}
|
||
fullText += chunk.text;
|
||
} else {
|
||
if (isInReasoning) {
|
||
isInReasoning = false;
|
||
fullText += "\n</think>\n";
|
||
}
|
||
fullText += chunk.text;
|
||
}
|
||
}
|
||
|
||
// 如果最后还在深度思考块中,关闭它
|
||
if (isInReasoning) {
|
||
fullText += "\n</think>";
|
||
}
|
||
```
|
||
|
||
`<think>` 标签会被 `markstream-vue` 库识别,并由 `ThinkingNode` 组件渲染。
|
||
|
||
---
|
||
|
||
## 功能:图片/文件附件自动切换模型
|
||
|
||
### 需求
|
||
当用户上传图片或文件(PDF、DOCX等)时,无论前端选择了什么模型,后端都应强制使用 `glm-4.6v` 模型(支持多模态)。
|
||
|
||
### 解决方案
|
||
|
||
#### 后端 `server/adapters/glm_adapter.py`
|
||
|
||
**修改 `_build_messages` 方法**:
|
||
|
||
返回值从 `(messages, has_vision)` 改为 `(messages, has_vision, has_files)`:
|
||
|
||
```python
|
||
def _build_messages(
|
||
self, request: ChatCompletionRequest
|
||
) -> tuple[List[Dict], bool, bool]:
|
||
"""
|
||
构建 GLM 格式的消息
|
||
返回:(消息列表, 是否包含图片, 是否包含文件附件)
|
||
"""
|
||
messages = []
|
||
has_vision = False
|
||
has_files = bool(request.files) # 检查是否有文件附件
|
||
# ... 处理消息 ...
|
||
return messages, has_vision, has_files
|
||
```
|
||
|
||
**修改 `_resolve_model` 方法**:
|
||
|
||
```python
|
||
def _resolve_model(self, model: str, has_vision: bool, has_files: bool = False) -> str:
|
||
"""解析实际使用的模型"""
|
||
model_lower = model.lower()
|
||
# 如果有图片或文件附件,强制使用 glm-4.6v(支持多模态)
|
||
if (has_vision or has_files) and model_lower not in VISION_MODELS:
|
||
logger.info(
|
||
f"[GLM] 检测到图片或文件附件,强制切换模型: {model} -> glm-4.6v"
|
||
)
|
||
return "glm-4.6v"
|
||
return model
|
||
```
|
||
|
||
**修改 `chat` 方法调用**:
|
||
|
||
```python
|
||
glm_messages, has_vision, has_files = self._build_messages(request)
|
||
actual_model = self._resolve_model(request.model, has_vision, has_files)
|
||
```
|
||
|
||
---
|
||
|
||
## 功能:DeepSeek 深度思考支持
|
||
|
||
### 需求
|
||
为 DeepSeek 的 `deepseek-reasoner` 模型添加深度思考支持,通过 `extra_body` 参数启用。
|
||
|
||
### 解决方案
|
||
|
||
#### 后端 `server/adapters/openai_adapter.py`
|
||
|
||
**添加支持深度思考的模型列表**:
|
||
|
||
```python
|
||
# DeepSeek 支持深度思考的模型
|
||
DEEPSEEK_THINKING_MODELS = {"deepseek-reasoner"}
|
||
```
|
||
|
||
**修改 `chat` 方法**:
|
||
|
||
```python
|
||
# DeepSeek 深度思考支持
|
||
extra_body = None
|
||
if self._provider_type == "deepseek" and request.deep_thinking:
|
||
if self._supports_thinking(request.model):
|
||
extra_body = {"thinking": {"type": "enabled"}}
|
||
kwargs["extra_body"] = extra_body
|
||
logger.info(f"[{provider_name}] 深度思考已启用: extra_body = {extra_body}")
|
||
```
|
||
|
||
**添加 `_supports_thinking` 方法**:
|
||
|
||
```python
|
||
def _supports_thinking(self, model: str) -> bool:
|
||
"""检查模型是否支持深度思考"""
|
||
return model.lower() in DEEPSEEK_THINKING_MODELS
|
||
```
|
||
|
||
**修改 `_stream_chat` 和 `_sync_chat` 方法**:
|
||
|
||
- 添加 `extra_body` 参数
|
||
- 增强 `reasoning_content` 日志输出
|
||
|
||
---
|
||
|
||
## 功能:模型列表从后端动态获取
|
||
|
||
### 需求
|
||
前端模型选择器中的模型列表改为从后端 API 获取,而非硬编码。
|
||
|
||
### 解决方案
|
||
|
||
#### 前端 `src/services/api.ts`
|
||
|
||
修改 `getModels` 方法,调用后端 API:
|
||
|
||
```typescript
|
||
async getModels(): Promise<ModelInfo[]> {
|
||
try {
|
||
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.MODELS}`, {
|
||
method: "GET",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`获取模型列表失败: HTTP ${response.status}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
// 后端返回格式: { object: "list", data: [...] }
|
||
return data.data || [];
|
||
} catch (error) {
|
||
console.error("获取模型列表失败:", error);
|
||
// 返回默认模型列表作为降级
|
||
return [...];
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 后端 `server/main.py`
|
||
|
||
已有 `/api/chat-ui/models` 端点:
|
||
|
||
```python
|
||
@app.get("/api/chat-ui/models")
|
||
async def get_models():
|
||
"""模型列表(聚合所有可用平台的模型)"""
|
||
from adapters import get_all_adapters
|
||
|
||
all_models = []
|
||
for provider, adapter in get_all_adapters().items():
|
||
if adapter.is_available():
|
||
models = adapter.list_models()
|
||
all_models.extend([m.to_dict() for m in models])
|
||
|
||
return {"object": "list", "data": all_models}
|
||
```
|
||
|
||
#### 特点
|
||
|
||
- **动态聚合**:自动聚合所有已配置 API Key 的平台模型
|
||
- **按需显示**:只有配置了 API Key 的平台才会显示模型
|
||
- **降级处理**:API 获取失败时返回默认模型列表
|
||
|
||
---
|
||
|
||
## 涉及文件
|
||
|
||
| 文件 | 修改类型 |
|
||
|------|----------|
|
||
| `src/services/api.ts` | 新增 `StreamChunk` 接口,修改 `streamChat` 方法,修改 `getModels` 方法 |
|
||
| `src/components/chat/ChatMain.vue` | 修改流式处理逻辑,支持 `reasoning` 类型 |
|
||
| `server/adapters/glm_adapter.py` | 修改 `_build_messages` 和 `_resolve_model` 方法 |
|
||
| `server/adapters/openai_adapter.py` | 添加 DeepSeek 深度思考支持 |
|
||
|
||
---
|
||
|
||
## 测试建议
|
||
|
||
1. **GLM 深度思考测试**:
|
||
- 选择支持深度思考的模型(如 glm-4.6v)
|
||
- 开启深度思考开关
|
||
- 发送问题,确认前端显示深度思考内容块
|
||
|
||
2. **DeepSeek 深度思考测试**:
|
||
- 选择 `deepseek-reasoner` 模型
|
||
- 开启深度思考开关
|
||
- 发送问题,确认后端日志显示 `extra_body = {'thinking': {'type': 'enabled'}}`
|
||
- 确认前端显示深度思考内容块
|
||
|
||
3. **模型自动切换测试**:
|
||
- 选择非多模态模型(如 glm-4-flash)
|
||
- 上传图片或 PDF 文件
|
||
- 确认后端日志显示模型切换为 glm-4.6v
|
||
- 确认多模态内容正确处理
|
||
|
||
4. **模型列表动态获取测试**:
|
||
- 检查前端控制台,确认调用了 `/api/chat-ui/models`
|
||
- 确认模型选择器显示后端返回的模型列表
|
||
- 停止后端服务,确认降级模型列表正常显示 |