Browse Source
- Added supportsTools field to LLM models in various API endpoints. - Updated model creation and update functions to handle supportsTools. - Modified chat and agent APIs to utilize supportsTools for tool management. - Enhanced error handling and validation for new field in relevant endpoints. - Updated migration journal to include new model version for supportsTools.feat/ai-sdk-v6-upgrade
23 changed files with 2568 additions and 40 deletions
@ -0,0 +1,119 @@ |
|||
# Qwen3-VL 工具调用兼容性修复 |
|||
|
|||
## 问题描述 |
|||
|
|||
选择 `Qwen3-VL-8B-Instruct` 模型发送消息后,模型回复被误判为"仅返回思考过程"而被删除,用户看不到任何回复内容。 |
|||
|
|||
## 根本原因 |
|||
|
|||
Qwen3-VL 不支持 function calling/tools。当请求携带 `tools` 参数时,SiliconFlow 平台会将模型输出放到 `reasoning_content` 字段而非 `content` 字段: |
|||
|
|||
```json |
|||
// 带 tools 时 |
|||
{"delta":{"content":null,"reasoning_content":"Hello"}} |
|||
|
|||
// 不带 tools 时 |
|||
{"delta":{"content":"Hello"}} |
|||
``` |
|||
|
|||
同时前端 `validateAssistantContent` 只检查 `content` 是否为空,未考虑 `reasoning` 类型的 part,导致只有思考过程的消息被误删。 |
|||
|
|||
## 解决方案 |
|||
|
|||
### 1. parseMode 重构 |
|||
|
|||
将 `parseMode` 从 `openai`/`anthropic` 改为 `openai`/`openai-compatible`: |
|||
|
|||
- `openai`:使用 `@ai-sdk/openai` 的 `createOpenAI`(原生 OpenAI API) |
|||
- `openai-compatible`:使用 `@ai-sdk/openai-compatible` 的 `createOpenAICompatible`(兼容 API,如 SiliconFlow、DeepSeek) |
|||
|
|||
### 2. 模型表增加 supportsTools 字段 |
|||
|
|||
`llmModels` 表新增 `supportsTools` 字段(`integer("supports_tools").default(1).notNull()`): |
|||
|
|||
- `1`(true):模型支持工具调用,请求时正常传 tools 参数 |
|||
- `0`(false):模型不支持工具调用,请求时不传 tools 参数 |
|||
|
|||
### 3. 前端工具按钮禁用 |
|||
|
|||
不支持工具的模型,工具开关按钮自动禁用,tooltip 显示"当前模型不支持工具调用"。 |
|||
|
|||
### 4. 前端 validateAssistantContent 修复 |
|||
|
|||
增加 `reasoning` 类型检查,避免只有思考过程的消息被误删。 |
|||
|
|||
## 改动文件清单 |
|||
|
|||
### 数据库 |
|||
|
|||
| 文件 | 改动 | |
|||
|------|------| |
|||
| `packages/drizzle-pkg/lib/schema/llm.ts` | `LlmParseModes` 改为 `["openai", "openai-compatible"]`;`llmModels` 增加 `supportsTools` 字段 | |
|||
| `packages/drizzle-pkg/migrations/0018_colossal_barracuda.sql` | 迁移文件:`ALTER TABLE llm_models ADD supports_tools` | |
|||
|
|||
### 服务端 - resolveModel 实现 |
|||
|
|||
| 文件 | 改动 | |
|||
|------|------| |
|||
| `server/api/agent/chat/index.post.ts` | `resolveModel`:`openai` 用 `createOpenAI`,`openai-compatible` 用 `createOpenAICompatible`;`streamText` 中 `supportsTools=false` 时不传 tools | |
|||
| `server/api/llm/chat/index.post.ts` | 同步 `resolveModel` 和 tools 逻辑 | |
|||
| `server/service/agent/title.ts` | 同步 `resolveModel` | |
|||
|
|||
### 服务端 - Service 层 |
|||
|
|||
| 文件 | 改动 | |
|||
|------|------| |
|||
| `server/service/llm/index.ts` | `LlmModelRow` 接口加 `supportsTools`;`listSystemModels`、`listAllEnabledModelsForUser` 查询加 `supportsTools`;`createModel`、`createSystemModel`、`updateModel` 加 `supportsTools` 字段 | |
|||
|
|||
### 服务端 - API 接口 |
|||
|
|||
| 文件 | 改动 | |
|||
|------|------| |
|||
| `server/api/admin/llm/providers/index.post.ts` | `parseMode` 校验更新为 `["openai", "openai-compatible"]` | |
|||
| `server/api/admin/llm/models/index.post.ts` | 加 `supportsTools` 参数 | |
|||
| `server/api/llm/models/[providerId].post.ts` | 加 `supportsTools` 参数 | |
|||
| `server/api/llm/models/detail/[id].put.ts` | 加 `supportsTools` 参数 | |
|||
| `server/api/llm/models/index.get.ts` | 返回值包含 `supportsTools`(通过 service 层) | |
|||
| `server/api/llm/chat/models.get.ts` | 查询加 `supportsTools` 字段 | |
|||
| `server/api/agent/models/index.get.ts` | 返回值加 `supportsTools` | |
|||
|
|||
### 前端 |
|||
|
|||
| 文件 | 改动 | |
|||
|------|------| |
|||
| `app/pages/index.vue` | `ModelOption` 加 `supportsTools`;新增 `currentModelSupportsTools` computed;`enableTools` getter 不支持时返回 false;传 `tools-disabled` prop | |
|||
| `app/components/agent/AgentChatArea.vue` | 加 `toolsDisabled` prop,传给 `AgentInput` | |
|||
| `app/components/agent/AgentInput.vue` | 加 `toolsDisabled` prop;工具按钮禁用逻辑和样式 | |
|||
| `app/composables/useAgentChat.ts` | `validateAssistantContent` 增加 `hasReasoning` 检查 | |
|||
| `app/composables/useLlmChat.ts` | `validateAssistantContent` 增加 `hasReasoning` 检查 | |
|||
| `app/pages/settings/llm-config/index.vue` | provider 编辑页面 `parseMode` 选项更新;模型编辑表单加 `supportsTools` 下拉选项 | |
|||
| `app/pages/settings/llm-test/index.vue` | `ModelOption` 加 `supportsTools`;工具开关不支持时禁用 | |
|||
|
|||
## 数据库现状 |
|||
|
|||
- 数据库路径:`packages/drizzle-pkg/db.sqlite` |
|||
- provider 配置: |
|||
- deepseek(id=2, parseMode=`openai-compatible`) |
|||
- siliconflow(id=3, parseMode=`openai-compatible`) |
|||
- 模型配置: |
|||
- deepseek-v4-flash(id=2, supportsTools=1) |
|||
- Qwen3-VL-8B-Instruct(id=4, supportsTools=0) |
|||
|
|||
## 关键技术决策 |
|||
|
|||
1. **`createOpenAI` 返回类型与 `LanguageModel` 不完全兼容**:需用 `as unknown as LanguageModel` 转换 |
|||
2. **`enableThinking`/`enableTools` 改为请求体参数优先于 session 配置**:更灵活的控制方式 |
|||
3. **`openai-compatible` 作为默认 parseMode**:大多数第三方 API 都是 OpenAI 兼容协议 |
|||
|
|||
## 测试验证 |
|||
|
|||
- [x] Qwen3-VL-8B-Instruct 发送消息正常返回内容(不再只有思考过程) |
|||
- [x] Qwen3-VL-8B-Instruct 工具按钮禁用,tooltip 显示"当前模型不支持工具调用" |
|||
- [x] deepseek-v4-flash 工具按钮正常启用,可开关工具 |
|||
- [x] deepseek-v4-flash 工具列表正常显示(fetch_html、calculator、uuid 等) |
|||
|
|||
## 后续注意事项 |
|||
|
|||
- `server/api/llm/providers/[id].models.get.ts` 中仍有 `anthropic` 分支代码,但不会命中(parseMode 不再有 "anthropic"),走 else 分支 |
|||
- `app/pages/index.vue` 第 72 行硬编码 `enableThinking: () => false` |
|||
- 新增模型时默认 `supportsTools=1`,需在管理后台手动改为 0 如果模型不支持工具 |
|||
Binary file not shown.
@ -0,0 +1 @@ |
|||
ALTER TABLE `llm_models` ADD `supports_tools` integer DEFAULT 1 NOT NULL; |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue