Files
DevFlow/docs/02-架构设计/已编号方案/F-01-模型能力系统与智能路由设计-2026-06-16.md
绝尘 998a2f243d 文档: 架构方案文档(意图识别论证+多主题愿景/论证+文档物理分类+边界清晰化)
squash合并:
- 意图识别层论证(8维度+10业界佐证)
- 多主题上下文管理愿景+并存论证+补充论证(多轮agentic)
- 架构设计文档物理分类(四子目录+INDEX+命名规范+引用同步+边界清晰化)
- 前端架构技术债清单归档
2026-06-19 15:04:04 +08:00

639 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# F-01 模型能力系统 Phase 1 — 模型配置与智能路由设计
> 状态:📐 设计定稿2026-06-16含多角度佐证 + 厂商适配 + 用户流程)
> 类型:架构设计文档(不碰任何 code
> 关联F-260614-05 多模态 Phase 2 / F-260614-04 多 Provider 负载均衡池
> 前置F-07 df-ai-core trait 下沉 ✅ 已完成batch61·2069f79
> 决策记录:见 [功能决策记录-2026-06-14.md](../滚动规范/功能决策记录-2026-06-14.md) §「模型能力系统」行
---
> ## ⚠️ 实施状态2026-06-18 核对:已落地,路由部分改方向)
>
> **阶段 1-6 全部落地**(数据模型 / 探测器 / 厂商拉取 / 路由器 / 7+ 调用点接入 / 前端):
> - 阶段 1 数据模型:`crates/df-ai-core/src/model.rs:106` `ModelConfig`、`:20/35/55/71` 四维度枚举Modality/Capability/CostTier/IntelligenceTier、`:211` `deserialize_model_configs` 向后兼容;`crates/df-storage/src/models.rs:159-160` `AiProviderRecord.model_configs` 字段(**注意:实际落地字段名 `model_configs` 而非本文档 §1.1/§2.3 描述的老 `models` JSON 字段扩展**,新字段经 V18 迁移幂等补列 `crates/df-storage/src/migrations.rs:317-325`)。
> - 阶段 2 探测器:`crates/df-ai/src/model_probe.rs`(已建)+ `crates/df-ai/presets/models.json`(已建)。注意预设表/PatternRule 未拆独立 `preset_table.rs`,合并在 model_probe 内。
> - 阶段 3 厂商拉取:`crates/df-ai/src/model_fetch.rs`已建fetch_models 分派)。
> - 阶段 4 路由器:`crates/df-ai/src/router.rs:40/56/76` `ModelRouter::select` / `select_model_id`。
> - 阶段 5 调用点:主对话 `src-tauri/src/commands/ai/agentic.rs:418/423`、标题 `title.rs:86/91`、知识提炼/嵌入 `knowledge_inject.rs:58-63/359-364`、压缩 `compress.rs:59-64`、项目扫描 `project.rs:533-538/627-632`、灵感评估 `crates/df-ideas/src/adversarial.rs:158-163`、AiNode `crates/df-nodes/src/ai_node.rs:221-226`。
>
> **§6.1 路由逻辑已改方向2026-06-18 决策 B-260618-03**:本文档 §6.1 描述的 `TaskRequirements` 含 `min_intelligence`/`max_cost` 两字段、`select` 含「智力达标」「成本可控」两过滤步、`max_by_key((weight, Reverse(cost_tier)))` 同权重选便宜——**均已删除**。
> - 实际形态:`crates/df-ai/src/router.rs:27-35` `TaskRequirements` 仅 3 字段(`modalities`/`needs_tool_use`/`estimated_context``min_intelligence`/`max_cost` 已删;`:56-63` `select` 过滤链仅 4 步enabled / 模态 / 能力 / 窗口),`:62` 排序纯 `max_by_key(m.weight)`,无 cost tie-break。
> - 根因provider `/v1/models` API 不返回 cost_tier/intelligence两维度 100% 靠预设表写死 + 模型名启发式猜数据无客观依据不可信不参与硬路由。枚举CostTier/IntelligenceTier保留在 `model.rs` 供未来出现真实判别源再接回。
>
> **§6.2 场景路由表 / §6.3 调用点表**:表中行号(如 `agentic.rs:50`/`title.rs:63`/`project.rs:378`)已漂移,实际调用点见上方阶段 5 行号清单。
---
## 0. 摘要
将当前「一个 Provider 一个 default_model 跑全场」升级为「多模型池 + 能力感知 + 智能路由」。
用户只需填 Provider 基本信息 → 自动拉取模型列表 → 自动探测每个模型的模态/能力/价格/智力 → 路由器按场景自动选最优模型。
**核心价值**:含图消息自动选 Vision 模型、标题生成自动选便宜模型、复杂推理自动选强模型、限流自动 fallback。
---
## 1. 现状盘点
### 1.1 数据模型AiProviderRecord
`crates/df-storage/src/models.rs:127-140`
```rust
pub struct AiProviderRecord {
pub provider_type: String, // "openai_compat" | "anthropic_compat"
pub base_url: String,
pub default_model: String, // 唯一实际使用的模型名
pub models: Option<String>, // JSON array of model names展示用未消费
pub config: Option<String>, // JSON extra config几乎没用
pub is_default: bool,
...
}
```
**问题**
1. `models` 存了模型列表但**没有能力标记**,不知道哪个支持 vision / tool use
2. **没有启用/禁用开关**,配了的模型无法控制哪些参与路由
3. **没有权重/优先级**,无法表达"优先用 AA 不可用时 fallback 到 B"
4. `default_model` 是唯一实际使用的模型名,`models` 列表形同虚设
### 1.2 模型选择机制(当前)
```
用户在 Settings 配置 Provider含 base_url + default_model
AiSession.active_provider_id ← 全局唯一活跃 Provider
get_active_provider() → 取 Provider 配置
CompletionRequest { model: provider.default_model } ← 直接用固定 model
```
- 一个时刻只有一个活跃 Provider
- 所有场景(对话/标题/知识提炼/项目扫描)共用同一个 model
- 无 ModelCapability / ModelRouter / 按场景路由机制
---
## 2. 模型配置数据模型
### 2.1 ModelConfig每个模型的完整描述
```rust
/// 单个模型的完整配置4 维度 + 路由控制)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelConfig {
// ── 基础 ──
/// 模型名(如 "glm-4v-flash"
pub model_id: String,
/// 启用/禁用false = 配了但不参与路由,相当于"备档"
#[serde(default = "default_true")]
pub enabled: bool,
/// 用户自定义别名(可选)
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
// ── 维度 1模态能接收什么输入──
pub modalities: Vec<Modality>,
// ── 维度 2能力能做什么──
pub capabilities: Vec<Capability>,
// ── 维度 3价格成本分级──
pub cost_tier: CostTier,
// ── 维度 4聪明程度智力分级──
pub intelligence: IntelligenceTier,
// ── 路由控制 ──
/// 权重0-100同能力候选中优先选权重高的
#[serde(default = "default_weight")]
pub weight: u32,
/// 上下文窗口大小tokens
#[serde(default = "default_context_window")]
pub context_window: usize,
// ── 探测元数据(只读,由 ModelProbe 填充)──
#[serde(skip_serializing_if = "Option::is_none")]
pub probe_source: Option<ProbeSource>,
}
fn default_true() -> bool { true }
fn default_weight() -> u32 { 50 }
fn default_context_window() -> usize { 8192 }
```
### 2.2 枚举定义
```rust
/// 模态(输入类型)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Modality {
Text,
Vision,
// 未来扩展Audio, Video
}
/// 能力
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Capability {
ToolUse, // function calling / tool use
Embedding, // 向量嵌入
CodeGen, // 代码生成强项
}
/// 价格分级
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum CostTier {
Free, // 免费
Low, // flash / mini 系列
Medium, // 标准定价
High, // 旗舰定价
}
/// 聪明程度(智力分级)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum IntelligenceTier {
Lite, // flash/mini/lite/nano — 快但简单任务
Standard, // air/standard — 日常够用
Plus, // plus/pro/max — 复杂推理
Ultra, // 最强模型 — 兜底用
}
```
### 2.3 存储方式:扩展 models JSON 字段(零迁移)
`AiProviderRecord.models``["glm-4-flash", "glm-4v"]` 升级为:
```json
[
{
"model_id": "glm-4-flash",
"enabled": true,
"modalities": ["text"],
"capabilities": ["tool_use"],
"cost_tier": "low",
"intelligence": "lite",
"weight": 90,
"context_window": 128000
},
{
"model_id": "glm-4v",
"enabled": true,
"modalities": ["text", "vision"],
"capabilities": ["tool_use"],
"cost_tier": "medium",
"intelligence": "plus",
"weight": 70,
"context_window": 128000
}
]
```
**向后兼容**:自定义反序列化器,老格式 `["model-a"]` → 自动转成默认配置列表。
```rust
fn deserialize_models<'de, D>(d: D) -> Result<Vec<ModelConfig>, D::Error>
where D: serde::Deserializer<'de> {
let v = serde_json::Value::deserialize(d)?;
match v {
// 老格式:字符串数组 → 每个转默认 ModelConfig
serde_json::Value::Array(arr) if arr.iter().all(|v| v.is_string()) => {
arr.into_iter()
.filter_map(|v| v.as_str().map(|s| ModelConfig::with_defaults(s)))
.collect::<Vec<_>>()
.pipe(Ok)
}
// 新格式ModelConfig 数组
serde_json::Value::Array(_) => {
serde_json::from_value::<Vec<ModelConfig>>(v).map_err(D::Error::custom)
}
_ => Ok(vec![]),
}
}
```
**否决方案**:新建 `ai_models` 独立表 — 增量复杂度高(迁移 + 新 Repo`models` JSON 字段已够用。
---
## 3. 多角度佐证
### 3.1 行业对标
| 产品 | 模型配置方式 | 对照 |
|------|------------|------|
| OpenRouter | 每个模型标 modality/pricing/context_length | 4 维度完全覆盖,且加了 intelligence 分级 |
| Cursor | 内置模型能力感知(自动判断图片/工具) | 预设表 + 启发式探测本质相同 |
| LangChain ModelRouter | 按 max_tokens/supports_tool_use 路由 | capabilities + modalities 路由一致 |
| One-API / New-API | 纯渠道管理,无能力感知 | 能力标记是显著增量 |
**结论**4 维度配置是行业标配的超集,非过度设计。
### 3.2 路由器实际需求倒推
| 路由决策 | 必须知道 | 对应维度 | 缺了会怎样 |
|---------|---------|---------|-----------|
| 含图消息选哪个 | 是否支持 Vision | 模态 | 发给纯文本模型 → 400 |
| Agentic loop 选哪个 | 是否支持 tool_use | 能力 | 发 tool 定义给不支持的 → 忽略/报错 |
| 标题生成选哪个 | 够便宜够快 | 价格+智力 | 用旗舰模型 → 烧钱 |
| 复杂推理选哪个 | 够聪明 | 智力 | 用 flash → 质量差 |
| 上下文超长选哪个 | 窗口够大 | context_window | 超窗口 → 截断 |
**结论**:每个维度直接对应路由器必须做的判断,缺一不可。
### 3.3 用户认知负担
| 信息 | 用户负担 | 说明 |
|------|---------|------|
| 模型名 | 零 | 从文档复制 |
| 模态 | 低 | 文档一眼可见,或名字带 v |
| 能力 | 低 | 文档明确标注 |
| 价格 | 中 | 查文档,但分级别直觉可判 |
| 智力 | 低 | flash < air < plus 是行业共识 |
**结论**4 个维度都是用户本来就知道的,加上自动填充,门槛极低。
### 3.4 可扩展性
| 未来需求 | 支持 | 扩展方式 |
|---------|------|---------|
| 音频输入 | ✅ | Modality 加 Audio |
| 视频输入 | ✅ | Modality 加 Video |
| 精确价格控制 | ✅ | cost_tier 升级为精确数值 |
| 流式支持差异 | ✅ | Capability 加 Streaming |
| 自定义能力标签 | ✅ | Capability 加 Custom(String) |
**结论**enum + Vec 开放式,未来加维度只需加变体。
### 3.5 数据兼容性
`models: ["model-a"]` → 自定义反序列化自动补默认值。`default_model` 字段保留向后兼容。零迁移脚本。
### 3.6 竞品缺陷反证
| 问题 | 竞品现状 | 我们的方案 |
|------|---------|-----------|
| 含图发给纯文本模型 | One-API 不感知能力 | 路由器自动选 Vision |
| 标题生成用旗舰模型 | 固定模型手动切 | 按 intelligence+cost 自动选 Lite |
| 新模型不知道能不能用 | 用户自己试 | 预设表 + 启发式自动推断 |
| 限流后无 fallback | 手动切换 | 按 weight 自动 fallback |
### 3.7 实施风险
| 风险 | 评估 | 缓解 |
|------|------|------|
| 预设表维护 | 低(主流 20-30 个,半年更新) | JSON 配置文件可热更新 |
| 启发式误判 | 低(命名是行业惯例) | 标注 Medium 可信度,用户可修正 |
| 路由器选错 | 低 | weight fallback + 降级兜底 |
**7 个角度一致指向:方案可行且合理。**
---
## 4. 模型探测器ModelProbe
### 4.1 多源探测
每个模型的信息从多个来源获取,交叉验证:
```rust
pub struct ModelProbe {
preset_table: ModelPresetTable,
}
impl ModelProbe {
pub async fn probe(&self, provider: &AiProviderRecord, model_id: &str) -> ModelProfile {
// 1. 启发式:从模型名推断
let heuristic = self.heuristic_infer(model_id);
// 2. 查预设表(精确匹配 > 模糊匹配)
let preset = self.preset_table.lookup(model_id);
// 3. 多源合并(预设表 > 启发式)
let merged = self.merge_sources(heuristic, preset);
// 4. 最终结果 + 标注每个维度的置信度
self.finalize(merged)
}
}
```
### 4.2 探测优先级链
```
用户手动设定 (UserSet) ← 最高优先,永不被覆盖
内置预设表精确匹配 (PresetTable) ← 高可信
模型名启发式 (Heuristic) ← 中可信,标注"建议确认"
默认值 (Default) ← 低可信
```
### 4.3 探测结果带置信度
```rust
pub struct ModelProfile {
pub model_id: String,
pub modalities: SourcedField<Vec<Modality>>,
pub capabilities: SourcedField<Vec<Capability>>,
pub cost_tier: SourcedField<CostTier>,
pub intelligence: SourcedField<IntelligenceTier>,
pub context_window: SourcedField<usize>,
}
pub struct SourcedField<T> {
pub value: T,
pub source: Source,
pub confidence: Confidence,
}
pub enum Source { PresetTable, Heuristic, UserSet }
pub enum Confidence { High, Medium, Low }
```
### 4.4 内置预设表
```rust
pub struct ModelPresetTable {
exact: HashMap<String, ModelPreset>, // 精确匹配
patterns: Vec<PatternRule>, // 模糊匹配
}
// 精确匹配示例
"glm-4-flash" => { modalities:[Text], capabilities:[ToolUse], cost:Low, intelligence:Lite, context:128K }
"glm-4-air" => { modalities:[Text], capabilities:[ToolUse], cost:Low, intelligence:Standard }
"glm-4-plus" => { modalities:[Text], capabilities:[ToolUse], cost:Medium, intelligence:Plus }
"glm-4v" => { modalities:[Text,Vision], capabilities:[ToolUse], cost:Medium, intelligence:Plus }
"glm-4v-flash" => { modalities:[Text,Vision], capabilities:[ToolUse], cost:Low, intelligence:Lite }
"deepseek-chat" => { modalities:[Text], capabilities:[ToolUse], cost:Low, intelligence:Standard }
"deepseek-coder"=> { modalities:[Text], capabilities:[ToolUse,CodeGen], cost:Low, intelligence:Plus }
"claude-3-5-sonnet-20241022" => { modalities:[Text,Vision], capabilities:[ToolUse], cost:High, intelligence:Ultra }
"claude-3-haiku-20240307" => { modalities:[Text,Vision], capabilities:[ToolUse], cost:Low, intelligence:Standard }
"gpt-4o" => { modalities:[Text,Vision], capabilities:[ToolUse], cost:High, intelligence:Ultra }
"gpt-4o-mini" => { modalities:[Text,Vision], capabilities:[ToolUse], cost:Low, intelligence:Standard }
"embedding-3" => { modalities:[], capabilities:[Embedding], cost:Low, intelligence:Lite }
// 模糊匹配规则
PatternRule { keyword: "flash|mini|lite|nano", Intelligence(Lite) }
PatternRule { keyword: "plus|pro|max|ultra", Intelligence(Plus) }
PatternRule { keyword: "v$|vl|vision|-v\\d", Modality(Vision) }
PatternRule { keyword: "embed", Capability(Embedding) }
PatternRule { keyword: "code|coder", Capability(CodeGen) }
```
预设表以 JSON 配置文件形式存储(`crates/df-ai/presets/models.json`),可热更新不随版本绑。
---
## 5. 厂商模型列表适配
### 5.1 差异盘点
| 厂商/协议 | 端点 | 鉴权 | 返回格式 |
|-----------|------|------|---------|
| OpenAI 兼容GLM/DeepSeek/Kimi/通义) | `GET /v1/models` | Bearer | `{data:[{id, owned_by}]}` |
| Anthropic | `GET /v1/models` | x-api-key + version | `{data:[{id, display_name}]}` |
| 中转站 | `GET /v1/models` | Bearer | 同 OpenAI但可能混入噪音或返回 404 |
| Ollama | `GET /api/tags` | 无 | `{models:[{name, size}]}` — 完全不同 |
### 5.2 统一拉取接口
```rust
/// 模型拉取结果(统一格式)
pub struct FetchedModel {
pub model_id: String,
pub display_name: Option<String>,
}
/// 按 provider_type 分派
pub async fn fetch_models(
provider_type: &str,
base_url: &str,
api_key: &str,
) -> Result<Vec<FetchedModel>, FetchError> {
match provider_type {
"openai_compat" => fetch_openai_compat(base_url, api_key).await,
"anthropic_compat" => fetch_anthropic_compat(base_url, api_key).await,
_ => Err(FetchError::Unsupported),
}
}
```
### 5.3 URL 智能拼接
```rust
fn build_models_url(base_url: &str) -> String {
let url = base_url.trim_end_matches('/');
if url.ends_with("/chat/completions") {
url.replace("/chat/completions", "/models")
} else if url.ends_with("/v1") || url.ends_with("/v4") {
format!("{}/models", url)
} else if url.ends_with("/models") {
url.to_string()
} else {
format!("{}/v1/models", url)
}
}
```
### 5.4 噪音过滤
```rust
fn is_non_chat_model(id: &str) -> bool {
let id = id.to_lowercase();
id.contains("dall-e") || id.contains("midjourney") // 图片生成
|| id.contains("tts") || id.contains("whisper") // 语音
|| id.contains("moderation") // 审查
// embedding 保留(知识库需要)
}
```
### 5.5 失败降级
| 错误 | 处理 |
|------|------|
| 404 / 不支持 | 静默降级到手动输入(批量文本) |
| 401 / 403 | 提示密钥问题 |
| 网络/超时 | 提示检查连接 |
| 解析失败 | 提示格式不兼容,降级手动 |
**核心原则:自动拉取是锦上添花,手动输入永远保底。**
---
## 6. 模型路由器ModelRouter
### 6.1 路由逻辑
```rust
pub struct TaskRequirements {
pub modalities: Vec<Modality>, // 任务需要什么模态
pub needs_tool_use: bool, // 是否需要工具调用
pub min_intelligence: IntelligenceTier, // 最低智力要求
pub max_cost: Option<CostTier>, // 成本上限(可选)
pub estimated_context: usize, // 预估上下文大小
}
impl ModelRouter {
pub fn select(&self, req: &TaskRequirements, pool: &[ModelConfig]) -> Option<&ModelConfig> {
pool.iter()
.filter(|m| m.enabled) // 1. 只选启用的
.filter(|m| req.modalities.iter().all(|r| m.modalities.contains(r))) // 2. 模态匹配
.filter(|m| !req.needs_tool_use || m.capabilities.contains(&Capability::ToolUse)) // 3. 能力匹配
.filter(|m| m.intelligence >= req.min_intelligence) // 4. 智力达标
.filter(|m| req.max_cost.map_or(true, |max| m.cost_tier <= max)) // 5. 成本可控
.filter(|m| m.context_window >= req.estimated_context) // 6. 窗口够大
.max_by_key(|m| (m.weight, -(m.cost_tier as i32))) // 7. 权重优先,同权重选便宜的
}
}
```
### 6.2 场景路由表
| 场景 | 路由偏好 | 典型选择 |
|------|---------|---------|
| 标题生成 | Lite + Low cost | glm-4-flash |
| 日常对话 | Standard | glm-4-air |
| 写代码 | Standard/Plus + CodeGen | deepseek-coder |
| 含图片 | Vision + Standard | glm-4v |
| 复杂推理 | Plus/Ultra | glm-4-plus |
| 知识嵌入 | Embedding | embedding-3 |
### 6.3 7 个调用点接入
| 调用点 | 当前代码位置 | TaskRequirements |
|--------|------------|-----------------|
| 主对话 stream_llm | agentic.rs:50 | 动态按消息内容含图→Vision |
| 标题生成 | title.rs:63 | Lite + Low省钱 |
| 知识提炼 | knowledge_inject.rs:33,323 | Standard |
| 知识嵌入 | knowledge_inject.rs embedding | Embedding |
| 项目扫描描述 | project.rs:378 | Standard含图→Vision |
| 灵感评估 | df-ideas adversarial.rs | Standard |
| AiNode 工作流 | df-nodes ai_node.rs:118 | 按节点配置 |
---
## 7. 用户配置与使用流程
### 7.1 配置流程(做一次)
```
Step 1: 填 Provider 基本信息(名称/类型/地址/密钥)
Step 2: 点「测试连接并拉取模型」
↓ 自动调 /v1/models按协议分派
↓ 自动过滤非 chat 模型
↓ 自动探测每个模型特征(预设表 + 启发式)
Step 3: 显示模型列表(已标注特征 + 可信度)
↓ 用户确认或微调(大多数不需要进这步)
Step 4: 完成
```
**拉取失败时降级**:手动输入模型名(批量文本,每行一个)→ 同样走探测。
### 7.2 日常使用(零配置)
```
用户发消息 → 路由器自动选模型 → 用户无感 → 出结果
```
**手动覆盖**AiChat 顶部下拉选「自动(推荐)」或指定具体模型。
**自动 fallback**:模型限流/失败 → 按 weight 选次高 → 自动重试。
### 7.3 简洁性指标
| 传统做法 | 我们的做法 | 省了什么 |
|---------|-----------|---------|
| 手动填每个模型能力 | 预设表自动填充 | 省 90% 配置 |
| 自己记哪个支持图片 | 路由器自动选 | 省记忆 |
| 每次对话手动切模型 | 自动路由 | 省操作 |
| 限流后手动换 | 自动 fallback | 省故障处理 |
**用户最小操作路径**:填 3 个字段 → 点 1 个按钮 → 完成。
---
## 8. 实施分阶段
### 阶段 1数据模型df-ai-core + df-storage
| 文件 | 改动 |
|------|------|
| `crates/df-ai-core/src/provider.rs` | 新增 ModelConfig / Modality / Capability / CostTier / IntelligenceTier |
| `crates/df-storage/src/models.rs` | AiProviderRecord.models 反序列化升级(兼容老格式) |
| `crates/df-ai/src/model_config.rs`(新建) | deserialize_models 兼容函数 + ModelConfig::with_defaults |
### 阶段 2预设表 + 探测器df-ai
| 文件 | 改动 |
|------|------|
| `crates/df-ai/presets/models.json`(新建) | 主流模型预设数据 |
| `crates/df-ai/src/model_probe.rs`(新建) | ModelProbe + 启发式 + 多源合并 |
| `crates/df-ai/src/preset_table.rs`(新建) | 预设表加载 + 精确/模糊匹配 |
### 阶段 3厂商模型列表拉取df-ai
| 文件 | 改动 |
|------|------|
| `crates/df-ai/src/model_fetch.rs`(新建) | fetch_models + openai_compat/anthropic_compat 分派 + URL 拼接 + 噪音过滤 |
### 阶段 4路由器df-ai
| 文件 | 改动 |
|------|------|
| `crates/df-ai/src/router.rs`(新建) | ModelRouter + TaskRequirements + select 逻辑 |
### 阶段 57 调用点接入src-tauri
| 文件 | 改动 |
|------|------|
| `src-tauri/src/commands/ai/agentic.rs` | 主对话路由(按 has_image 动态选) |
| `src-tauri/src/commands/ai/title.rs` | 标题生成路由Lite + Low |
| `src-tauri/src/commands/ai/knowledge_inject.rs` | 知识提炼/嵌入路由 |
| `src-tauri/src/commands/project.rs` | 项目扫描路由 |
| `src-tauri/src/commands/ai/commands.rs` | 新增 IPCai_fetch_models / ai_probe_model |
### 阶段 6前端src
| 文件 | 改动 |
|------|------|
| `src/api/types.ts` | ModelConfig 类型对齐 |
| `src/components/settings/` | Provider 配置页加模型列表 + 探测结果展示 + 启用/禁用/权重 |
| `src/components/AiChat.vue` | 顶部模型下拉(自动/指定) |
---
## 9. 与 F-05多模态的关系
| 子能力 | 依赖 F-01 | 说明 |
|--------|------------|------|
| ContentPart 数据模型 | ❌ | 纯类型升级,与 ModelConfig 解耦 |
| provider content 数组化 | ❌ | 协议层改造,与路由器无关 |
| 前端粘贴/拖拽/渲染 | ❌ | 纯前端 |
| **vision 模型自动路由** | ✅ | ModelRouter 按 modalities 含 Vision 筛选 |
F-05 可独立先做 80%(数据模型 + provider + 前端vision 路由留到 F-01 落地后接入。
过渡期靠 ModelConfig.modalities 手动标注 + 路由器筛选。
---
## 10. 不做的事(显式排除)
- 不做模型自动下载/安装(仅 API 模型,不含本地模型管理)
- 不做模型 benchmark 自动跑分(智力分级靠预设表 + 用户确认)
- 不做多 Provider 负载均衡(属 F-04本任务只做单 Provider 内多模型路由)
- 不做模型用量统计/成本告警(属运维增强,后续独立做)
- 不新建 ai_models 独立表(扩展 models JSON 字段够用)
- 本文档不实施任何 code纯设计