- Kimi k2.5 强制传参拦截: 当 provider=kimi 且 model 包含 k2.5 时, 从请求体中 delete temperature/top_p/presence_penalty/frequency_penalty, 彻底解决 HTTP 400 报错 - 完善导出AI日志: 新增 lastExchangeLog 状态, 记录每次调用的 完整请求体(requestPayload)、原始响应(responsePayload)、 错误详情(errorDetail含status/statusText/responseText)、模型配置 - 更新导出按钮 JSON 结构, 包含 lastExchange 字段
118 lines
3.6 KiB
Markdown
118 lines
3.6 KiB
Markdown
# 功能变更实现方案文档(20260419_2249)
|
||
|
||
## 实现方案 A:Kimi k2.5 参数拦截
|
||
|
||
### 变更点
|
||
`ReportEditor.tsx` 中 `handleAIGenerate` 函数的请求体构建部分(当前行号约 948-962)。
|
||
|
||
### 具体实现
|
||
1. 在构建 `body` 前,先创建一个 `payload` 对象:
|
||
```ts
|
||
const payload: any = {
|
||
model: modelName,
|
||
messages: [
|
||
{ role: 'system', content: systemPrompt },
|
||
{ role: 'user', content: messageContent }
|
||
],
|
||
temperature: 0.3
|
||
};
|
||
```
|
||
2. 增加条件判断:
|
||
```ts
|
||
const isKimiK25 = settings.activeAiProvider === 'kimi' && /k2\.5/i.test(modelName);
|
||
if (isKimiK25) {
|
||
delete payload.temperature;
|
||
delete payload.top_p;
|
||
delete payload.presence_penalty;
|
||
delete payload.frequency_penalty;
|
||
}
|
||
```
|
||
3. `fetch` 的 `body: JSON.stringify(payload)`
|
||
|
||
### 设计理由
|
||
- 使用 `delete` 而非覆盖为固定值,是因为 Kimi 官方文档明确禁止这些参数出现;即使设为 `1.0` 仍可能触发校验失败
|
||
- 条件判断放在 `settings` 读取后立即执行,确保使用用户实际配置的 provider 和 modelName
|
||
- 正则 `/k2\.5/i` 兼容可能的模型 ID 变体(如 `kimi-k2.5`、`kimi-k2.5-preview` 等)
|
||
|
||
---
|
||
|
||
## 实现方案 B:完善 AI 日志导出
|
||
|
||
### 变更点 1:新增 `lastExchangeLog` 状态
|
||
在 `ReportEditor.tsx` 的 state 定义区(`chatMessages` 附近)新增:
|
||
```ts
|
||
const [lastExchangeLog, setLastExchangeLog] = useState<{
|
||
startTime: string;
|
||
modelConfig: { provider: string; endpoint: string; modelName: string };
|
||
requestPayload: any;
|
||
responsePayload: any | null;
|
||
errorDetail: { status: number; statusText: string; responseText: string; message: string } | null;
|
||
} | null>(null);
|
||
```
|
||
|
||
### 变更点 2:在 `handleAIGenerate` 中记录日志
|
||
将函数重构为在关键节点捕获数据:
|
||
|
||
**A. 请求前记录:**
|
||
```ts
|
||
const logEntry = {
|
||
startTime: new Date().toISOString(),
|
||
modelConfig: { provider: settings.activeAiProvider || 'kimi', endpoint: apiEndpoint, modelName },
|
||
requestPayload: { ...payload },
|
||
responsePayload: null,
|
||
errorDetail: null
|
||
};
|
||
```
|
||
|
||
**B. 错误处理增强:**
|
||
当前错误处理只有:
|
||
```ts
|
||
if (!response.ok) throw new Error(`API 请求失败: ${response.status}`);
|
||
```
|
||
改为:
|
||
```ts
|
||
if (!response.ok) {
|
||
const errorText = await response.text();
|
||
logEntry.errorDetail = {
|
||
status: response.status,
|
||
statusText: response.statusText,
|
||
responseText: errorText,
|
||
message: `API 请求失败: ${response.status}`
|
||
};
|
||
setLastExchangeLog(logEntry);
|
||
throw new Error(`API 请求失败: ${response.status} - ${errorText}`);
|
||
}
|
||
```
|
||
|
||
**C. 成功响应记录:**
|
||
在解析 `responseJson` 后:
|
||
```ts
|
||
logEntry.responsePayload = responseJson;
|
||
setLastExchangeLog(logEntry);
|
||
```
|
||
|
||
### 变更点 3:更新导出按钮
|
||
在「导出 AI 日志」按钮的 `onClick` 中,将 `lastExchangeLog` 加入导出数据:
|
||
```ts
|
||
const data = {
|
||
exportAt: new Date().toISOString(),
|
||
url: window.location.href,
|
||
messages: chatMessages,
|
||
lastExchange: lastExchangeLog,
|
||
metadata: { ... }
|
||
};
|
||
```
|
||
|
||
### 设计理由
|
||
- `lastExchangeLog` 只记录最后一次调用,避免无限增长导致内存/状态膨胀
|
||
- 错误时捕获 `response.text()` 获取 Kimi 官方返回的详细错误 JSON(通常包含 `error.code` 和 `error.message`)
|
||
- `requestPayload` 深拷贝防止后续 `delete` 操作污染日志记录
|
||
- 使用 `useState` 而非 `useRef`,因为导出按钮需要读取最新值并触发重渲染显示状态
|
||
|
||
---
|
||
|
||
## 依赖与兼容性
|
||
- 无新增 npm 依赖
|
||
- TypeScript 类型在组件内部定义,不影响 `src/types.ts`
|
||
- 向后兼容:旧数据无 `lastExchangeLog`,导出时字段为 `null`
|