feat: 升级至 v0.3.4 — 接入 Xiaomi MiMo Provider + 文档全量校准
新增 MiMo (小米) LLM Provider 适配器,支持 mimo-v2.5-pro 和 mimo-v2.5 两个文本模型,复用 OpenAI 兼容 SSE 流式解析,支持 Thinking 模式和 Function Calling。同步校准全量 docs 文档与 README 使其与实际代码一致。 主要变更: - 新增 mimo.adapter.ts 适配器(SSE + thinking.type + max_completion_tokens) - 修复 thinking 逻辑 bug:禁用思考时未传 temperature/top_p - 补全 sse-stream.ts 的 MiMo 缓存字段映射(prompt_tokens_details.cached_tokens) - 补全 sse-stream.ts 的 finish_reason 映射(repetition_truncation) - 注册 MiMo 适配器到 adapters/index.ts、main.ts 工厂 - handlers.ts 添加 mimo.contextWindow 热重载触发 - database.service.ts seed 添加 mimo 默认配置 - SettingsModal/OnboardingWizard/Header 添加 MiMo Provider UI - constants.ts PROVIDER_LABELS 添加 mimo - .env.example 添加 MIMO_API_KEY/MIMO_BASE_URL - 反向修改 4 个 docs HTML 设计文档(工具数量/版本日期/适配器列表/数据库表) - 反向修改 Agent网络工具通用设计-v2.md 附录 B 文件索引 - 完全重写 README.md(v0.3.4、27 工具、4 适配器、9 表)
This commit is contained in:
@@ -9,6 +9,10 @@ DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||||
AGNES_API_KEY=your_agnes_api_key_here
|
||||
AGNES_BASE_URL=https://apihub.agnes-ai.com/v1
|
||||
|
||||
# Xiaomi MiMo API
|
||||
MIMO_API_KEY=your_mimo_api_key_here
|
||||
MIMO_BASE_URL=https://api.xiaomimimo.com/v1
|
||||
|
||||
# Ollama API (local)
|
||||
OLLAMA_BASE_URL=http://localhost:11434
|
||||
|
||||
|
||||
@@ -1,80 +1,582 @@
|
||||
# MetonaAI Desktop
|
||||
|
||||
生产级通用 AI Agent 智能体桌面应用。
|
||||
> 生产级通用 AI Agent 智能体桌面应用
|
||||
|
||||
[](./package.json)
|
||||
[](./LICENSE)
|
||||
[](https://www.electronjs.org/)
|
||||
[](https://react.dev/)
|
||||
[](https://www.typescriptlang.org/)
|
||||
|
||||
Metona 是一款基于 Electron 的生产级 AI Agent 桌面应用,内置 ReAct 状态机驱动的智能体循环、27 个内置工具、三层记忆系统、四层安全防线与完整的可观测性链路。支持 DeepSeek、Agnes AI、MiMo(小米)、Ollama 四种 LLM Provider,兼容 MCP 协议扩展。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
- [技术栈](#技术栈)
|
||||
- [快速开始](#快速开始)
|
||||
- [核心特性](#核心特性)
|
||||
- [项目架构](#项目架构)
|
||||
- [内置工具](#内置工具)
|
||||
- [LLM 适配器](#llm-适配器)
|
||||
- [记忆系统](#记忆系统)
|
||||
- [安全机制](#安全机制)
|
||||
- [配置说明](#配置说明)
|
||||
- [项目结构](#项目结构)
|
||||
- [开发命令](#开发命令)
|
||||
- [许可证](#许可证)
|
||||
|
||||
---
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **运行时**: Electron 35 + React 19 + TypeScript 5.8
|
||||
- **状态管理**: Zustand 5
|
||||
- **数据库**: better-sqlite3
|
||||
- **LLM**: DeepSeek / Agnes AI / Ollama
|
||||
- **协议**: MCP (Model Context Protocol)
|
||||
- **构建**: electron-vite + Vite 6
|
||||
| 层级 | 技术 | 版本 |
|
||||
|------|------|------|
|
||||
| 运行时 | Electron | 35 |
|
||||
| 前端框架 | React | 19 |
|
||||
| 类型系统 | TypeScript | 5.8 |
|
||||
| UI 组件库 | Material UI (MUI) | 9 |
|
||||
| 状态管理 | Zustand | 5 |
|
||||
| 数据库 | better-sqlite3 | 11 |
|
||||
| 构建工具 | electron-vite + Vite | 3 / 6 |
|
||||
| LLM 协议 | MCP SDK | 1.12 |
|
||||
| 样式辅助 | Tailwind CSS | 4 |
|
||||
| Markdown | react-markdown + remark-gfm | 10 / 4 |
|
||||
| UUID | nanoid | 5 |
|
||||
| 校验 | Zod | 3 |
|
||||
| 缓存 | lru-cache | 11 |
|
||||
| 日志 | electron-log | 5 |
|
||||
| 配置存储 | electron-store | 10 |
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Node.js >= 18
|
||||
- npm >= 9
|
||||
- Windows / macOS / Linux
|
||||
|
||||
### 安装与运行
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 开发模式
|
||||
# 开发模式(启动 Electron + Vite 热重载)
|
||||
npm run dev
|
||||
|
||||
# 构建
|
||||
# 类型检查
|
||||
npm run typecheck
|
||||
|
||||
# 构建生产包(Windows 输出 NSIS 安装包 + 便携版)
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 配置
|
||||
### 配置 LLM Provider
|
||||
|
||||
复制 `.env.example` 为 `.env`,填入 API Key:
|
||||
1. 复制 `.env.example` 为 `.env`,填入 API Key:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
或在应用设置界面中配置 LLM Provider。
|
||||
```env
|
||||
# DeepSeek API
|
||||
DEEPSEEK_API_KEY=your_key
|
||||
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||||
|
||||
# Agnes AI API
|
||||
AGNES_API_KEY=your_key
|
||||
AGNES_BASE_URL=https://apihub.agnes-ai.com/v1
|
||||
|
||||
# Ollama(本地运行,无需 Key)
|
||||
OLLAMA_BASE_URL=http://localhost:11434
|
||||
```
|
||||
|
||||
2. 或在应用启动后,通过 **设置 → LLM 配置** 界面可视化配置 Provider、API Key、模型、上下文窗口等参数。
|
||||
|
||||
---
|
||||
|
||||
## 核心特性
|
||||
|
||||
### 智能体引擎
|
||||
|
||||
- **ReAct 状态机**:8 状态闭环(INIT → THINKING → PARSING → EXECUTING → OBSERVING → REFLECTING → COMPRESSING → TERMINATED)
|
||||
- **流式对话**:SSE(DeepSeek/Agnes)+ NDJSON(Ollama)双协议流式响应
|
||||
- **Thinking 模式**:支持 deepseek-v4-pro / agnes-2.0-flash / qwen3 等模型的推理模式
|
||||
- **死循环检测**:连续 3 轮相同工具调用签名自动终止
|
||||
- **上下文压缩**:80% 阈值触发 LLM 摘要压缩,保留最近 10 条消息
|
||||
- **错误重试**:指数退避(1s/2s/4s,上限 30s)+ ±20% jitter
|
||||
- **可配置迭代**:最大迭代次数(默认 20)、总超时(默认 600s)、工具执行超时(默认 120s)
|
||||
|
||||
### 工具与执行
|
||||
|
||||
- **27 个内置工具**:覆盖文件系统、代码搜索、网络搜索、浏览器自动化、Git、开发工具、记忆、任务管理等
|
||||
- **MCP 协议支持**:动态加载外部 MCP Server 工具
|
||||
- **子任务委派**:TaskOrchestrator 支持最大 3 层深度的 SubAgent 编排
|
||||
- **策略引擎**:三级权限(READ/WRITE/EXTERNAL_ACTION)+ 滑动窗口频率限制
|
||||
- **确认机制**:HIGH/CRITICAL 风险工具需用户确认,支持会话内同类免确认与持久化自动执行
|
||||
|
||||
### 记忆与上下文
|
||||
|
||||
- **三层记忆系统**:情节记忆(episodic)、语义记忆(semantic)、工作记忆(working)
|
||||
- **TF-IDF 语义检索**:中英文分词 + 时间衰减(30 天半衰期)+ IDF 缓存
|
||||
- **自动记忆固化**:会话结束时 LLM 提取重要信息写入 MEMORY.md
|
||||
- **System Prompt 分区构建**:SOUL.md + AGENTS.md + USERS.md + MEMORY.md + 安全准则
|
||||
|
||||
### 安全防线(四层纵深防御)
|
||||
|
||||
1. **路径安全**:工作空间边界校验 + realpathSync 符号链接逃逸检测 + 根目录 MEMORY.md 保护
|
||||
2. **命令安全**:SandboxManager 28 模式扫描 + shell-quote 双层防御 + 受保护文件检查
|
||||
3. **权限控制**:PolicyEngine 三级权限 + 频率限制(20 次/分钟)+ 用户确认钩子
|
||||
4. **内容安全**:PromptInjectionDefender(30+ 正则 + 语义检测)+ OutputValidator(幻觉检测)
|
||||
|
||||
### 可观测性
|
||||
|
||||
- **全链路追踪**:TraceViewer 可视化 ReAct 每轮迭代
|
||||
- **会话录制**:9 种事件录制到 JSONL 文件
|
||||
- **审计日志**:SQLite 链式哈希防篡改(INSERT-ONLY 触发器)
|
||||
- **Token 统计**:输入/输出/推理 Token 用量追踪
|
||||
|
||||
### 桌面体验
|
||||
|
||||
- **三栏布局**:Sidebar + Chat + DetailPanel,支持专注模式
|
||||
- **系统托盘**:4 状态指示(idle/thinking/executing/error)
|
||||
- **全局快捷键**:Cmd/Ctrl+Shift+M 唤起应用
|
||||
- **14 个应用内快捷键**:会话管理、布局切换、主题切换等
|
||||
- **暗色/亮色主题**:跟随系统 + 手动切换
|
||||
- **首次使用引导**:5 步 Onboarding 向导
|
||||
- **命令面板**:Cmd/Ctrl+K 快速搜索
|
||||
- **多平台构建**:Windows(NSIS + 便携版)、macOS(DMG + ZIP)、Linux(AppImage + DEB)
|
||||
|
||||
---
|
||||
|
||||
## 项目架构
|
||||
|
||||
### 四层 Harness 架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ L1 推理与编排层 │
|
||||
│ AgentLoopEngine (ReAct 状态机) · TaskOrchestrator (子任务) │
|
||||
│ MetonaRequest / MetonaResponse / MetonaStreamEvent │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ L2 上下文与记忆层 │
|
||||
│ ContextBuilder · MemoryManager · MemoryConsolidator │
|
||||
│ MetonaContext / MetonaMemoryItem │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ L3 工具与安全执行层 │
|
||||
│ ToolRegistry · SandboxManager · PolicyEngine · MCPAdapter │
|
||||
│ PromptInjectionDefender · OutputValidator · ConfirmationHook │
|
||||
│ MetonaToolDef / MetonaToolCall / MetonaToolResult │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ L4 支撑与基础架构层 │
|
||||
│ ConfigService · DatabaseService · AuditService │
|
||||
│ SessionService · SessionRecorder · WindowManager │
|
||||
│ TrayManager · MCPManager · WorkspaceService │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 进程模型
|
||||
|
||||
| 进程 | 运行时 | 职责 |
|
||||
|------|--------|------|
|
||||
| Main Process | Node.js | Agent 引擎、工具调度、数据库、MCP 管理、配置 |
|
||||
| Preload Script | 沙箱 | contextBridge 安全暴露 14 个 API 命名空间 |
|
||||
| Renderer | Chromium | React 19 + MUI 9 界面渲染 |
|
||||
|
||||
### 数据流
|
||||
|
||||
```
|
||||
用户输入 → ChatInput → agent-store.sendMessage
|
||||
→ IPC: agent:sendMessage → handlers.ts
|
||||
→ reloadAdapter (热重载,配置签名比对)
|
||||
→ 保存用户消息到 SQLite
|
||||
→ 加载历史消息 + 注入相关记忆
|
||||
→ ContextBuilder.buildSystemPrompt (SOUL+AGENTS+USERS+MEMORY+安全准则)
|
||||
→ PromptInjectionDefender.detect (riskScore>=7 阻断)
|
||||
→ AgentLoopEngine.runStream
|
||||
→ Adapter.sendStream (SSE/NDJSON 流式)
|
||||
→ 流式事件 → webContents.send('agent:streamEvent')
|
||||
→ 工具调用 → PreToolHooks (权限+频率+确认)
|
||||
→ ToolRegistry.execute → PostToolHooks (审计+记忆触发)
|
||||
→ 80% 阈值触发上下文压缩
|
||||
→ 死循环检测 (3 轮相同签名)
|
||||
→ OutputValidator.validate (幻觉检测)
|
||||
→ 保存 assistant 消息 + tool 结果消息
|
||||
→ MemoryConsolidator.consolidate (异步提取记忆)
|
||||
→ AuditService.logSessionEnd
|
||||
← useAgentStream Hook 监听事件 → Zustand Store → React 重渲染
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 内置工具
|
||||
|
||||
Metona 内置 27 个工具,按功能分类如下:
|
||||
|
||||
### 文件系统(5 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `read_file` | SAFE | 否 | 读取文本文件,二进制检测,offset/limit 分页 |
|
||||
| `write_file` | MEDIUM | 是 | 原子写入(tmp+rename),支持 overwrite/append |
|
||||
| `list_directory` | SAFE | 否 | 列出目录,depth(max 5)/glob/include_hidden |
|
||||
| `search_files` | SAFE | 否 | 按模式搜索,content/files 模式,context_lines |
|
||||
| `delete_file` | HIGH | 是 | 删除文件,禁止删除工作空间根目录和 MEMORY.md |
|
||||
|
||||
### 编辑与搜索(3 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `file_editor` | MEDIUM | 是 | 精准编辑,replace/insert/delete/regex + dry_run |
|
||||
| `code_search` | SAFE | 否 | 基于 ripgrep 高速搜索,回退 JS |
|
||||
| `diff_viewer` | SAFE | 否 | unified diff 格式,LCS 算法 |
|
||||
|
||||
### 网络与浏览器(4 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `web_search` | LOW | 否 | 双模式(SearXNG / 内置四引擎),智能排序,自动抓取 |
|
||||
| `web_fetch` | LOW | 否 | 三阶段回退(HTTP + 反爬 + 浏览器渲染),10MB 限制 |
|
||||
| `web_browser` | HIGH | 是 | 浏览器自动化,9 个 action(open/screenshot/extract 等) |
|
||||
| `http_request` | LOW | 否 | HTTP/REST API 请求,6 种 method |
|
||||
|
||||
### 记忆(2 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `memory_store` | MEDIUM | 否 | 存储记忆到三层(episodic/semantic/working) |
|
||||
| `memory_search` | SAFE | 否 | TF-IDF 检索记忆,时间衰减 |
|
||||
|
||||
### 命令与开发(5 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `run_command` | HIGH | 是 | 沙箱执行 Shell 命令,双重校验 + shell-quote 防御 |
|
||||
| `lint_code` | SAFE | 否 | TypeScript tsc 或 ESLint 检查 |
|
||||
| `run_tests` | LOW | 否 | 运行测试套件,filter 字符白名单防注入 |
|
||||
| `project_info` | SAFE | 否 | 项目结构分析,4 种 detail |
|
||||
| `delegate_task` | MEDIUM | 否 | 子任务委派给独立 SubAgent |
|
||||
|
||||
### Git(4 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `git_status` | SAFE | 否 | 工作树状态,porcelain v1 解析 |
|
||||
| `git_diff` | SAFE | 否 | diff 输出,50KB 截断,5MB maxBuffer |
|
||||
| `git_log` | SAFE | 否 | 提交历史,jest/vitest/mocha 格式解析 |
|
||||
| `git_commit` | MEDIUM | 是 | 暂存+提交,校验 file 在 workspace 内 |
|
||||
|
||||
### 任务与辅助(4 个)
|
||||
|
||||
| 工具 | 风险 | 需确认 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| `task_manager` | LOW | 否 | 持久化任务 CRUD,支持父子关系 |
|
||||
| `todo_write` | SAFE | 否 | 会话级 TODO,LRU 淘汰(max 50 sessions) |
|
||||
| `think` | SAFE | 否 | 结构化思考空间,无副作用 |
|
||||
| `view_image` | SAFE | 否 | 读取图片返回 base64,5MB 限制,7 种格式 |
|
||||
|
||||
---
|
||||
|
||||
## LLM 适配器
|
||||
|
||||
| 适配器 | Provider ID | 模型 | 上下文窗口 | 流式格式 | Thinking | 多模态 |
|
||||
|--------|-------------|------|-----------|----------|----------|--------|
|
||||
| DeepSeekAdapter | deepseek | deepseek-v4-pro / deepseek-v4-flash | 1M(可配) | SSE | thinking + reasoning_effort | 否 |
|
||||
| AgnesAdapter | agnes | agnes-2.0-flash | 1M(可配) | SSE | chat_template_kwargs | 是(URL) |
|
||||
| MimoAdapter | mimo | mimo-v2.5-pro / mimo-v2.5 | 131072(可配) | SSE | thinking.type | 是(URL) |
|
||||
| OllamaAdapter | ollama | qwen3 / gemma3 / deepseek-r1 | 4096(可配 num_ctx) | NDJSON | think 参数 | 是(Base64) |
|
||||
|
||||
### 上下文窗口配置
|
||||
|
||||
- **DeepSeek / Agnes / MiMo**:`contextWindow` 配置项影响本地压缩判断和 UI 显示(最小 4096)
|
||||
- **Ollama**:`num_ctx` 配置项直接影响 API 请求参数
|
||||
- 切换 Provider 时自动清空 API Key,防止使用不兼容的密钥
|
||||
- Engine 上下文窗口与 Adapter 配置值自动同步
|
||||
|
||||
---
|
||||
|
||||
## 记忆系统
|
||||
|
||||
### 三层记忆架构
|
||||
|
||||
| 层级 | 类型 | 存储表 | 用途 | 检索方式 |
|
||||
|------|------|--------|------|----------|
|
||||
| L2 | 情节记忆 (episodic) | episodic_memories | 会话事件、用户交互 | TF-IDF + 时间衰减 |
|
||||
| L3 | 语义记忆 (semantic) | semantic_memories | 知识、偏好、事实 | 精确 + 模糊匹配 |
|
||||
| L1 | 工作记忆 (working) | working_memories | 当前任务临时状态 | 精确键值查找 |
|
||||
|
||||
### 记忆生命周期
|
||||
|
||||
```
|
||||
新记忆写入 → 重要性评分 (0-1)
|
||||
├── 高 (>0.8) → 永久保存
|
||||
├── 中 (0.4-0.8) → 定期回顾,逐渐衰减
|
||||
└── 低 (<0.4) → 短期保留,自然遗忘
|
||||
会话结束 → MemoryConsolidator 提取重要信息 → 写入 MEMORY.md
|
||||
```
|
||||
|
||||
### 磁盘文件(工作空间)
|
||||
|
||||
| 文件 | 用途 | 是否必需 |
|
||||
|------|------|----------|
|
||||
| SOUL.md | AI 角色定义(灵魂) | 是 |
|
||||
| AGENTS.md | AI 行为规则 | 是 |
|
||||
| MEMORY.md | 动态记忆存储 | 是(仅根目录受保护) |
|
||||
| USERS.md | 用户信息画像 | 是 |
|
||||
|
||||
---
|
||||
|
||||
## 安全机制
|
||||
|
||||
### 四层纵深防御
|
||||
|
||||
```
|
||||
第 1 层:路径安全
|
||||
└─ isPathWithinWorkspace + realpathSync + MEMORY.md 保护
|
||||
|
||||
第 2 层:命令安全
|
||||
└─ SandboxManager (28 模式扫描) + shell-quote 双层防御
|
||||
|
||||
第 3 层:权限控制
|
||||
└─ PolicyEngine (三级权限) + 频率限制 (20/min) + ConfirmationHook
|
||||
|
||||
第 4 层:内容安全
|
||||
└─ PromptInjectionDefender (30+ 正则 + 语义检测) + OutputValidator (幻觉检测)
|
||||
```
|
||||
|
||||
### 风险分级
|
||||
|
||||
| 风险等级 | 示例工具 | 确认要求 |
|
||||
|----------|----------|----------|
|
||||
| SAFE | read_file, list_directory, code_search | 无需确认 |
|
||||
| LOW | web_search, web_fetch, http_request | 无需确认 |
|
||||
| MEDIUM | write_file, file_editor, memory_store | 可配置自动执行 |
|
||||
| HIGH | delete_file, run_command, web_browser, git_commit | 强制确认 |
|
||||
| CRITICAL | (预留) | 强制确认 + 双人复核 |
|
||||
|
||||
---
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 环境变量(.env)
|
||||
|
||||
```env
|
||||
# DeepSeek API
|
||||
DEEPSEEK_API_KEY=your_deepseek_api_key_here
|
||||
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||||
|
||||
# Agnes AI API
|
||||
AGNES_API_KEY=your_agnes_api_key_here
|
||||
AGNES_BASE_URL=https://apihub.agnes-ai.com/v1
|
||||
|
||||
# Xiaomi MiMo API
|
||||
MIMO_API_KEY=your_mimo_api_key_here
|
||||
MIMO_BASE_URL=https://api.xiaomimimo.com/v1
|
||||
|
||||
# Ollama API (local)
|
||||
OLLAMA_BASE_URL=http://localhost:11434
|
||||
|
||||
# App
|
||||
VITE_APP_TITLE=MetonaAI Desktop
|
||||
```
|
||||
|
||||
### 应用配置(app_config 表)
|
||||
|
||||
关键配置项及默认值:
|
||||
|
||||
| 配置项 | 默认值 | 说明 |
|
||||
|--------|--------|------|
|
||||
| `llm.provider` | deepseek | LLM Provider |
|
||||
| `llm.model` | deepseek-v4-pro | 模型名称 |
|
||||
| `agent.maxIterations` | 20 | 最大迭代次数 |
|
||||
| `agent.totalTimeoutMs` | 600000 | 总超时(ms) |
|
||||
| `agent.thinkingEnabled` | true | Thinking 模式 |
|
||||
| `agent.thinkingEffort` | high | 推理强度 |
|
||||
| `agent.confirmationTimeoutMs` | 120000 | 确认超时(30s~600s) |
|
||||
| `deepseek.contextWindow` | 1000000 | DeepSeek 上下文窗口 |
|
||||
| `agnes.contextWindow` | 1000000 | Agnes 上下文窗口 |
|
||||
| `mimo.contextWindow` | 131072 | MiMo 上下文窗口 |
|
||||
| `ollama.numCtx` | 4096 | Ollama 上下文窗口 |
|
||||
|
||||
### SearXNG 配置(可选)
|
||||
|
||||
启用 SearXNG 元搜索引擎替代内置四引擎搜索,支持 12 项配置(URL、引擎列表、认证方式等),详见设置界面。
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
MetonaAI-Desktop/
|
||||
├── electron/ # Electron 主进程
|
||||
│ ├── main.ts # 应用入口
|
||||
│ ├── preload.ts # 安全桥接脚本
|
||||
│ ├── ipc/ # IPC 通道处理
|
||||
│ ├── services/ # 业务服务(数据库、会话、记忆等)
|
||||
│ ├── main.ts # 应用入口(538 行)
|
||||
│ ├── preload.ts # 安全桥接(14 个 API 命名空间)
|
||||
│ ├── ipc/
|
||||
│ │ └── handlers.ts # IPC 通道处理(50+ 通道)
|
||||
│ ├── services/ # 业务服务层
|
||||
│ │ ├── audit.service.ts # 审计日志(链式哈希防篡改)
|
||||
│ │ ├── config.service.ts # 配置管理
|
||||
│ │ ├── database.service.ts # SQLite 数据库(9 张表)
|
||||
│ │ ├── mcp-manager.service.ts # MCP Server 管理
|
||||
│ │ ├── session-recorder.service.ts # 会话录制
|
||||
│ │ ├── session.service.ts # 会话 CRUD
|
||||
│ │ ├── tray-manager.service.ts # 系统托盘
|
||||
│ │ ├── update.service.ts # 自动更新
|
||||
│ │ ├── window-manager.service.ts # 窗口管理
|
||||
│ │ └── workspace.service.ts # 工作空间管理
|
||||
│ └── harness/ # Agent 核心引擎
|
||||
│ ├── agent-loop/ # ReAct 状态机
|
||||
│ │ ├── engine.ts # 循环引擎(8 状态)
|
||||
│ │ └── types.ts # 状态枚举
|
||||
│ ├── adapters/ # LLM Provider 适配器
|
||||
│ ├── tools/ # 工具注册与内置工具
|
||||
│ │ ├── base-adapter.ts # 抽象基类
|
||||
│ │ ├── deepseek.adapter.ts # DeepSeek(SSE)
|
||||
│ │ ├── agnes-ai.adapter.ts # Agnes AI(SSE)
|
||||
│ │ ├── mimo.adapter.ts # MiMo 小米(SSE)
|
||||
│ │ ├── ollama.adapter.ts # Ollama(NDJSON)
|
||||
│ │ └── shared/ # 共享模块
|
||||
│ │ ├── openai-format.ts # OpenAI 兼容格式
|
||||
│ │ └── sse-stream.ts # SSE 流解析
|
||||
│ ├── tools/ # 工具系统
|
||||
│ │ ├── registry.ts # 工具注册 + PolicyEngine
|
||||
│ │ └── built-in/ # 27 个内置工具
|
||||
│ │ ├── filesystem.ts # 文件系统(5 工具)
|
||||
│ │ ├── file-editor.ts # 编辑器
|
||||
│ │ ├── code-search.ts # 代码搜索
|
||||
│ │ ├── diff-viewer.ts # 差异查看
|
||||
│ │ ├── web-search.ts # 网络搜索
|
||||
│ │ ├── web-fetch.ts # 网页抓取
|
||||
│ │ ├── browser.ts # 浏览器工具
|
||||
│ │ ├── browser-window-manager.ts # 浏览器窗口管理
|
||||
│ │ ├── network.ts # 网络工具入口
|
||||
│ │ ├── network-utils.ts # 网络工具函数
|
||||
│ │ ├── http-request.ts # HTTP 请求
|
||||
│ │ ├── memory.ts # 记忆工具
|
||||
│ │ ├── command.ts # 命令执行
|
||||
│ │ ├── git.ts # Git 工具(4 个)
|
||||
│ │ ├── dev-tools.ts # 开发工具(3 个)
|
||||
│ │ ├── task-manager.ts # 任务管理
|
||||
│ │ ├── delegate-task.ts # 子任务委派
|
||||
│ │ ├── todo.ts # TODO 工具
|
||||
│ │ ├── think.ts # 思考工具
|
||||
│ │ ├── view-image.ts # 图片查看
|
||||
│ │ └── file-guard.ts # 文件保护
|
||||
│ ├── types/ # Metona IR 类型定义
|
||||
│ │ ├── metona-request.ts # 请求类型
|
||||
│ │ ├── metona-response.ts # 响应类型
|
||||
│ │ ├── metona-tool.ts # 工具类型
|
||||
│ │ ├── metona-context.ts # 上下文类型
|
||||
│ │ └── metona-adapter.ts # 适配器接口
|
||||
│ ├── sandbox/ # 沙箱安全
|
||||
│ │ ├── sandbox.ts # SandboxManager
|
||||
│ │ └── permissions.ts # PolicyEngine
|
||||
│ ├── security/ # 安全防御
|
||||
│ │ └── prompt-injection-defense.ts
|
||||
│ ├── memory/ # 记忆系统
|
||||
│ ├── prompts/ # System Prompt 构建
|
||||
│ └── types/ # Metona IR 类型定义
|
||||
│ │ ├── manager.ts # MemoryManager
|
||||
│ │ └── consolidator.ts # MemoryConsolidator
|
||||
│ ├── orchestration/ # 编排
|
||||
│ │ └── orchestrator.ts # TaskOrchestrator
|
||||
│ ├── prompts/ # 提示词构建
|
||||
│ │ └── context-builder.ts # ContextBuilder
|
||||
│ ├── hooks/ # 钩子
|
||||
│ │ ├── pre-tool.ts # 工具前钩子
|
||||
│ │ ├── post-tool.ts # 工具后钩子
|
||||
│ │ └── confirmation-hook.ts # 确认钩子
|
||||
│ ├── verification/ # 验证
|
||||
│ │ └── output-validator.ts # OutputValidator
|
||||
│ └── utils/ # 工具函数
|
||||
│ └── token-estimator.ts # Token 估算
|
||||
├── src/ # React 渲染进程
|
||||
│ ├── components/ # UI 组件
|
||||
│ ├── main.tsx # React 入口
|
||||
│ ├── App.tsx # 应用根组件
|
||||
│ ├── components/ # UI 组件(25 个)
|
||||
│ │ ├── chat/ # 聊天组件(11 个)
|
||||
│ │ ├── layout/ # 布局组件(5 个)
|
||||
│ │ ├── settings/ # 设置面板
|
||||
│ │ ├── memory/ # 记忆查看器
|
||||
│ │ ├── tasks/ # 任务列表
|
||||
│ │ ├── trace/ # 追踪查看器(3 个)
|
||||
│ │ ├── workspace/ # 工作空间查看器
|
||||
│ │ ├── onboarding/ # 引导向导
|
||||
│ │ └── common/ # 通用组件
|
||||
│ ├── hooks/ # React Hooks
|
||||
│ │ ├── useAgentStream.ts # Agent 流式事件
|
||||
│ │ ├── useKeyboardShortcuts.ts # 键盘快捷键
|
||||
│ │ └── useTheme.ts # 主题管理
|
||||
│ ├── stores/ # Zustand 状态管理
|
||||
│ ├── styles/ # 全局样式
|
||||
│ └── types/ # 类型声明
|
||||
│ │ ├── agent-store.ts # Agent 状态
|
||||
│ │ ├── session-store.ts # 会话状态
|
||||
│ │ └── ui-store.ts # UI 状态
|
||||
│ ├── lib/ # 工具库
|
||||
│ │ ├── constants.ts # 常量定义
|
||||
│ │ ├── formatters.ts # 格式化函数
|
||||
│ │ ├── theme.ts # MUI 主题
|
||||
│ │ └── cn.ts # className 合并
|
||||
│ ├── styles/
|
||||
│ │ └── globals.css # 全局样式
|
||||
│ └── types/
|
||||
│ └── global.d.ts # window.metona 类型声明
|
||||
├── docs/ # 设计文档
|
||||
├── standard/ # 开发规范
|
||||
└── apis/ # API 文档
|
||||
├── apis/ # LLM API 文档
|
||||
├── assets/ # 应用图标
|
||||
├── .env.example # 环境变量示例
|
||||
├── electron-builder.yml # 构建配置
|
||||
├── electron.vite.config.ts # Vite 配置
|
||||
├── package.json # 依赖与脚本
|
||||
├── tsconfig.json # TypeScript 配置
|
||||
├── tsconfig.node.json # Node 端配置
|
||||
├── tsconfig.web.json # Web 端配置
|
||||
└── LICENSE # MIT 许可证
|
||||
```
|
||||
|
||||
## 功能
|
||||
---
|
||||
|
||||
- ✅ 三栏布局(Sidebar + Chat + DetailPanel)
|
||||
- ✅ 流式对话(DeepSeek / Agnes / Ollama)
|
||||
- ✅ 9 个内置工具(文件系统、网络、记忆、命令行)
|
||||
- ✅ MCP 协议支持
|
||||
- ✅ 会话持久化(SQLite)
|
||||
- ✅ 三层记忆系统(情节/语义/工作)
|
||||
- ✅ 全链路追踪(Trace Viewer)
|
||||
- ✅ 审计日志(防篡改)
|
||||
- ✅ 系统托盘 + 全局快捷键
|
||||
- ✅ 暗色/亮色主题
|
||||
- ✅ 14 个键盘快捷键
|
||||
## 开发命令
|
||||
|
||||
```bash
|
||||
# 开发
|
||||
npm run dev # 启动开发模式
|
||||
npm run typecheck # 全量类型检查
|
||||
npm run typecheck:node # Node 端类型检查
|
||||
npm run lint # ESLint 检查
|
||||
npm run lint:fix # ESLint 自动修复
|
||||
npm run format # Prettier 格式化
|
||||
|
||||
# 测试
|
||||
npm test # 运行单元测试 (Vitest)
|
||||
npm run test:watch # 测试监听模式
|
||||
npm run test:e2e # E2E 测试 (Playwright)
|
||||
|
||||
# 构建
|
||||
npm run build # 构建生产包
|
||||
npm run build:renderer # 仅构建渲染进程
|
||||
npm run build:electron # 仅构建主进程
|
||||
npm run preview # 预览构建产物
|
||||
```
|
||||
|
||||
### 数据库 Schema(9 张表)
|
||||
|
||||
| 表名 | 用途 |
|
||||
|------|------|
|
||||
| sessions | 会话管理 |
|
||||
| messages | 消息持久化 |
|
||||
| app_config | 应用配置(键值对) |
|
||||
| audit_logs | 审计日志(链式哈希防篡改) |
|
||||
| mcp_servers | MCP Server 配置 |
|
||||
| episodic_memories | 情节记忆 |
|
||||
| semantic_memories | 语义记忆 |
|
||||
| working_memories | 工作记忆 |
|
||||
| tasks | 持久化任务 |
|
||||
|
||||
---
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT
|
||||
[MIT](./LICENSE)
|
||||
|
||||
@@ -0,0 +1,793 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MiMo Chat Completions API 接口文档</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary: #ff6900;
|
||||
--primary-light: #fff4eb;
|
||||
--text: #1a1a2e;
|
||||
--text-secondary: #555;
|
||||
--border: #e0e0e0;
|
||||
--bg: #ffffff;
|
||||
--code-bg: #f6f8fa;
|
||||
--accent-blue: #2563eb;
|
||||
--accent-green: #16a34a;
|
||||
--accent-red: #dc2626;
|
||||
--accent-purple: #7c3aed;
|
||||
--shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
--radius: 8px;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans SC', sans-serif; color: var(--text); line-height: 1.7; background: var(--bg); }
|
||||
|
||||
/* Header */
|
||||
.hero { background: linear-gradient(135deg, #ff6900 0%, #ff8533 50%, #ffa366 100%); color: #fff; padding: 48px 24px 40px; text-align: center; }
|
||||
.hero h1 { font-size: 2.2rem; font-weight: 800; letter-spacing: -0.5px; margin-bottom: 12px; }
|
||||
.hero p { opacity: 0.92; font-size: 1.05rem; max-width: 700px; margin: 0 auto; }
|
||||
.hero .badge { display: inline-block; background: rgba(255,255,255,0.22); padding: 4px 14px; border-radius: 20px; font-size: 0.82rem; margin-top: 16px; backdrop-filter: blur(4px); }
|
||||
|
||||
/* Container */
|
||||
.container { max-width: 960px; margin: 0 auto; padding: 0 24px; }
|
||||
|
||||
/* TOC */
|
||||
.toc { background: var(--primary-light); border: 1px solid #ffd9b3; border-radius: var(--radius); padding: 28px 32px; margin: -30px auto 36px; position: relative; z-index: 10; box-shadow: var(--shadow); }
|
||||
.toc h2 { font-size: 1.15rem; color: var(--primary); margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
|
||||
.toc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 6px 20px; }
|
||||
.toc a { color: var(--text); text-decoration: none; font-size: 0.92rem; padding: 3px 0; display: flex; align-items: center; gap: 6px; transition: color .15s; }
|
||||
.toc a:hover { color: var(--primary); }
|
||||
|
||||
/* Sections */
|
||||
section { margin-bottom: 48px; scroll-margin-top: 24px; }
|
||||
section h2 { font-size: 1.55rem; font-weight: 700; margin-bottom: 18px; padding-bottom: 10px; border-bottom: 2px solid var(--primary); display: flex; align-items: center; gap: 10px; }
|
||||
section h3 { font-size: 1.2rem; font-weight: 600; margin: 26px 0 12px; color: var(--text); }
|
||||
section h4 { font-size: 1.02rem; font-weight: 600; margin: 18px 0 8px; color: var(--text-secondary); }
|
||||
|
||||
/* Method badge */
|
||||
.method-badge { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 10px; }
|
||||
.method-tag { padding: 4px 12px; border-radius: 5px; font-size: 0.82rem; font-weight: 700; letter-spacing: 0.5px; color: #fff; }
|
||||
.method-post { background: var(--accent-green); }
|
||||
.url-box { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.88rem; background: var(--code-bg); padding: 10px 16px; border-radius: 6px; border: 1px solid var(--border); word-break: break-all; color: var(--accent-blue); }
|
||||
|
||||
/* Tables */
|
||||
table { width: 100%; border-collapse: collapse; margin: 14px 0 20px; font-size: 0.9rem; }
|
||||
th { background: #f0f0f0; text-align: left; padding: 10px 14px; font-weight: 600; border-bottom: 2px solid var(--border); white-space: nowrap; }
|
||||
td { padding: 9px 14px; border-bottom: 1px solid #eee; vertical-align: top; }
|
||||
tr:hover td { background: #fafafa; }
|
||||
.type-tag { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.83rem; color: var(--accent-purple); background: #f3effa; padding: 1px 7px; border-radius: 4px; }
|
||||
.required-tag { font-size: 0.78rem; font-weight: 600; padding: 1px 7px; border-radius: 4px; }
|
||||
.req-yes { background: #fef2f2; color: var(--accent-red); }
|
||||
.req-no { background: #f0fdf4; color: var(--accent-green); }
|
||||
.req-default { background: #eff6ff; color: var(--accent-blue); }
|
||||
|
||||
/* Code blocks */
|
||||
pre { background: #1e1e2e; color: #cdd6f4; padding: 20px 24px; border-radius: var(--radius); overflow-x: auto; font-size: 0.85rem; line-height: 1.6; margin: 14px 0 20px; position: relative; }
|
||||
pre code { font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; background: none; padding: 0; }
|
||||
.code-lang { position: absolute; top: 0; right: 12px; font-size: 0.72rem; color: rgba(255,255,255,0.35); text-transform: uppercase; letter-spacing: 1px; }
|
||||
|
||||
/* Inline code */
|
||||
code:not(pre code) { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.84em; background: var(--code-bg); padding: 2px 7px; border-radius: 4px; color: #d63384; }
|
||||
|
||||
/* Info / Warning boxes */
|
||||
.info-box { background: #eff6ff; border-left: 4px solid var(--accent-blue); padding: 14px 18px; border-radius: 0 var(--radius) var(--radius) 0; margin: 16px 0; font-size: 0.92rem; }
|
||||
.info-box strong { color: var(--accent-blue); }
|
||||
.warn-box { background: #fffbeb; border-left: 4px solid #d97706; padding: 14px 18px; border-radius: 0 var(--radius) var(--radius) 0; margin: 16px 0; font-size: 0.92rem; }
|
||||
.warn-box strong { color: #b45309; }
|
||||
.tip-box { background: #f0fdf4; border-left: 4px solid var(--accent-green); padding: 14px 18px; border-radius: 0 var(--radius) var(--radius) 0; margin: 16px 0; font-size: 0.92rem; }
|
||||
.tip-box strong { color: var(--accent-green); }
|
||||
|
||||
/* Tabs */
|
||||
.tabs { display: flex; gap: 0; margin: 16px 0 0; border-bottom: 2px solid var(--border); }
|
||||
.tab-btn { padding: 8px 18px; cursor: pointer; border: none; background: none; font-size: 0.88rem; font-weight: 500; color: var(--text-secondary); border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all .15s; }
|
||||
.tab-btn.active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; }
|
||||
.tab-content { display: none; }
|
||||
.tab-content.active { display: block; }
|
||||
|
||||
/* Feature cards */
|
||||
.feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; margin: 18px 0; }
|
||||
.feature-card { background: #fafafa; border: 1px solid var(--border); border-radius: var(--radius); padding: 18px; transition: box-shadow .15s; }
|
||||
.feature-card:hover { box-shadow: var(--shadow); }
|
||||
.feature-card .icon { font-size: 1.5rem; margin-bottom: 8px; }
|
||||
.feature-card h4 { margin: 0 0 6px; font-size: 0.95rem; }
|
||||
.feature-card p { font-size: 0.84rem; color: var(--text-secondary); margin: 0; }
|
||||
|
||||
/* Footer */
|
||||
footer { background: #1a1a2e; color: rgba(255,255,255,0.65); text-align: center; padding: 32px 24px; margin-top: 56px; font-size: 0.86rem; }
|
||||
footer a { color: var(--primary); text-decoration: none; }
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 640px) {
|
||||
.hero h1 { font-size: 1.6rem; }
|
||||
.toc { padding: 20px; margin-top: -20px; }
|
||||
table { font-size: 0.82rem; }
|
||||
th, td { padding: 7px 10px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ===== HERO ===== -->
|
||||
<div class="hero">
|
||||
<h1>🔮 MiMo Chat Completions API</h1>
|
||||
<p>Xiaomi MiMo V2.5 系列 OpenAI 兼容对话补全接口完整文档。支持多轮对话、深度思考、工具调用、联网搜索、语音合成、图像/视频输入等全功能。</p>
|
||||
<div class="badge">支持模型:mimo-v2.5-pro · mimo-v2.5 · mimo-v2.5-tts · mimo-v2.5-tts-voicedesign · mimo-v2.5-tts-voiceclone</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- ===== TOC ===== -->
|
||||
<nav class="toc">
|
||||
<h2>📋 目录导航</h2>
|
||||
<div class="toc-grid">
|
||||
<a href="#overview">📌 概述 & 基本信息</a>
|
||||
<a href="#quickstart">⚡ 快速开始</a>
|
||||
<a href="#models">💰 可用模型</a>
|
||||
<a href="#request-auth">🔐 认证方式</a>
|
||||
<a href="#request-body">📥 请求参数详解</a>
|
||||
<a href="#response">📤 响应对象(非流式)</a>
|
||||
<a href="#response-stream">📤 响应 Chunk(流式)</a>
|
||||
<a href="#thinking">🧠 深度思考模式</a>
|
||||
<a href="#tools">🔧 工具调用 (Function Calling)</a>
|
||||
<a href="#websearch">🌐 联网搜索</a>
|
||||
<a href="#tts">🎙️ 语音合成 (TTS)</a>
|
||||
<a href="#examples">💻 代码示例</a>
|
||||
<a href="#errors">⚠️ 错误码说明</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- ===== OVERVIEW ===== -->
|
||||
<section id="overview">
|
||||
<h2>📌 概述 & 基本信息</h2>
|
||||
<p>MiMo Chat Completions API 是小米大语言模型提供的 OpenAI 兼容对话补全接口,支持 RESTful HTTP 协议,所有请求与响应均使用 JSON 格式。流式响应采用 SSE(Server-Sent Events)。</p>
|
||||
|
||||
<div style="margin-top:18px;">
|
||||
<table>
|
||||
<tr><th width="140">项目</th><th>值</th></tr>
|
||||
<tr><td>Base URL</td><td><code>https://api.xiaomimimo.com/v1/chat/completions</code></td></tr>
|
||||
<tr><td>协议</td><td>HTTPS (POST)</td></tr>
|
||||
<tr><td>认证方式</td><td>api-key Header 或 Authorization Bearer</td></tr>
|
||||
<tr><td>内容类型</td><td>application/json</td></tr>
|
||||
<tr><td>SDK 兼容</td><td>OpenAI Python / Node.js SDK(修改 base_url 即可)</td></tr>
|
||||
<tr><td>文档日期</td><td>2026-07-15</td></tr>
|
||||
<tr><td>更新时间</td><td>2026-06-29(官方)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="info-box" style="margin-top:18px;">
|
||||
<strong>⚠️ 版本提醒:</strong>MiMo-V2 系列模型已于 <strong>2026.6.30 00:00</strong> 正式下线,原模型名称已失效。请使用 V2.5 系列模型。
|
||||
</div>
|
||||
|
||||
<h3>核心能力一览</h3>
|
||||
<div class="feature-grid">
|
||||
<div class="feature-card"><div class="icon">💬</div><h4>多轮对话</h4><p>支持 system/user/assistant/developer/tool 多角色消息</p></div>
|
||||
<div class="feature-card"><div class="icon">🧠</div><h4>深度思考</h4><p>思维链推理,返回 reasoning_content</p></div>
|
||||
<div class="feature-card"><div class="icon">🔧</div><h4>工具调用</h4><p>Function Calling + Web Search 工具</p></div>
|
||||
<div class="feature-card"><div class="icon">🌐</div><h4>联网搜索</h4><p>自动联网检索并返回引用注释</p></div>
|
||||
<div class="feature-card"><div class="icon">🖼️</div><h4>多模态输入</h4><p>支持图像、音频、视频输入</p></div>
|
||||
<div class="feature-card"><div class="icon">🎙️</div><h4>语音合成</h4><p>TTS / Voice Design / Voice Clone</p></div>
|
||||
<div class="feature-card"><div class="icon">📡</div><h4>SSE 流式</h4><p>流式输出,降低首字延迟</p></div>
|
||||
<div class="feature-card"><div class="icon">📊</div><h4>用量明细</h4><td>缓存命中/推理 token 等详细统计</td></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== QUICK START ===== -->
|
||||
<section id="quickstart">
|
||||
<h2>⚡ 快速开始</h2>
|
||||
<p>获取 API Key 后即可开始调用。支持 OpenAI SDK 兼容格式,也可直接使用 HTTP 请求。</p>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" onclick="switchTab(event,'tab-q-curl')">curl</button>
|
||||
<button class="tab-btn" onclick="switchTab(event,'tab-q-python')">Python (OpenAI SDK)</button>
|
||||
</div>
|
||||
|
||||
<div id="tab-q-curl" class="tab-content active">
|
||||
<pre><span class="code-lang">bash</span>curl --location --request POST 'https://api.xiaomimimo.com/v1/chat/completions' \
|
||||
--header "api-key: $MIMO_API_KEY" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data-raw '{
|
||||
"model": "mimo-v2.5-pro",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are MiMo, an AI assistant developed by Xiaomi."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "你好,请介绍一下自己"
|
||||
}
|
||||
],
|
||||
"max_completion_tokens": 1024,
|
||||
"temperature": 1.0,
|
||||
"top_p": 0.95,
|
||||
"stream": false,
|
||||
"thinking": {
|
||||
"type": "disabled"
|
||||
}
|
||||
}'</pre>
|
||||
</div>
|
||||
|
||||
<div id="tab-q-python" class="tab-content">
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
|
||||
client = OpenAI(
|
||||
api_key="$MIMO_API_KEY",
|
||||
base_url="https://api.xiaomimimo.com/v1"
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-pro",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are MiMo, an AI assistant developed by Xiaomi."},
|
||||
{"role": "user", "content": "你好,请介绍一下自己"}
|
||||
],
|
||||
max_completion_tokens=1024,
|
||||
temperature=1.0,
|
||||
thinking={"type": "disabled"}
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== MODELS ===== -->
|
||||
<section id="models">
|
||||
<h2>💰 可用模型</h2>
|
||||
<table>
|
||||
<tr><th>模型 ID</th><th>类型</th><th>默认 max_tokens</th><th>深度思考</th><th>工具调用</th><th>语音合成</th><th>联网搜索</th></tr>
|
||||
<tr><td><code>mimo-v2.5-pro</code></td><td>旗舰文本</td><td>131072</td><td>✅ 支持</td><td>✅ 支持</td><td>❌</td><td>✅ 支持</td></tr>
|
||||
<tr><td><code>mimo-v2.5</code></td><td>标准文本</td><td>32768</td><td>✅ 支持</td><td>✅ 支持</td><td>❌</td><td>✅ 支持</td></tr>
|
||||
<tr><td><code>mimo-v2.5-tts</code></td><td>语音合成</td><td>8192</td><td>❌</td><td>❌</td><td>✅ 预置音色</td><td>❌</td></tr>
|
||||
<tr><td><code>mimo-v2.5-tts-voicedesign</code></td><td>音色设计</td><td>8192</td><td>❌</td><td>❌</td><td>✅ 音色设计</td><td>❌</td></tr>
|
||||
<tr><td><code>mimo-v2.5-tts-voiceclone</code></td><td>声音克隆</td><td>8192</td><td>❌</td><td>❌</td><td>✅ 声音克隆</td><td>❌</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>💡 temperature 默认值:</strong>mimo-v2.5-pro / mimo-v2.5 默认 <code>1.0</code>;TTS 系列默认 <code>0.6</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== AUTH ===== -->
|
||||
<section id="request-auth">
|
||||
<h2>🔐 认证方式</h2>
|
||||
<p>接口支持以下两种认证方式,<strong>选择其中一种</strong>添加到请求头中:</p>
|
||||
|
||||
<h3>方式一:api-key 字段认证</h3>
|
||||
<pre><span class="code-lang">http</span>api-key: $MIMO_API_KEY
|
||||
Content-Type: application/json</pre>
|
||||
|
||||
<h3>方式二:Authorization Bearer 认证</h3>
|
||||
<pre><span class="code-lang">http</span>Authorization: Bearer $MIMO_API_KEY
|
||||
Content-Type: application/json</pre>
|
||||
</section>
|
||||
|
||||
<!-- ===== REQUEST BODY ===== -->
|
||||
<section id="request-body">
|
||||
<h2>📥 请求参数详解</h2>
|
||||
|
||||
<div class="method-badge">
|
||||
<span class="method-tag method-post">POST</span>
|
||||
<span class="url-box">https://api.xiaomimimo.com/v1/chat/completions</span>
|
||||
</div>
|
||||
|
||||
<h3>核心参数</h3>
|
||||
<table>
|
||||
<tr><th width="160">参数名</th><th width="90">类型</th><th width="70">必填</th><th>描述</th></tr>
|
||||
<tr><td><code>model</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-yes">必选</span></td><td>模型 ID。可选值:<code>mimo-v2.5-pro</code>, <code>mimo-v2.5</code>, <code>mimo-v2.5-tts</code>, <code>mimo-v2.5-tts-voicedesign</code>, <code>mimo-v2.5-tts-voiceclone</code></td></tr>
|
||||
<tr><td><code>messages</code></td><td><span class="type-tag">array</span></td><td><span class="required-tag req-yes">必选</span></td><td>对话消息列表。支持 role: system / user / assistant / developer / tool</td></tr>
|
||||
<tr><td><code>messages[].role</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-yes">必选</span></td><td>角色:<code>system</code> / <code>user</code> / <code>assistant</code> / <code>developer</code> / <code>tool</code></td></tr>
|
||||
<tr><td><code>messages[].content</code></td><td><span class="type-tag">string | array</span></td><td><span class="required-tag req-yes">必选</span></td><td>消息内容。支持纯文本或多模态 content parts 数组</td></tr>
|
||||
<tr><td><code>messages[].name</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-no">可选</span></td><td>参与者名称,用于区分相同角色的不同参与者</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>生成控制参数</h3>
|
||||
<table>
|
||||
<tr><th width="160">参数名</th><th width="90">类型</th><th width="70">必填</th><th>描述</th></tr>
|
||||
<tr><td><code>max_completion_tokens</code></td><td><span class="type-tag">integer | null</span></td><td><span class="required-tag req-default">可选</span></td><td>生成 token 上限(含推理 token)。pro 默认 131072;标准版 32768;TTS 系列 8192。范围 [1, 131072]</td></tr>
|
||||
<tr><td><code>temperature</code></td><td><span class="type-tag">number</span></td><td><span class="required-tag req-default">可选</span></td><td>采样温度 [0, 1.5]。pro/标准默认 1.0;TTS 默认 0.6。思考模式下不可自定义</td></tr>
|
||||
<tr><td><code>top_p</code></td><td><span class="type-tag">number</span></td><td><span class="required-tag req-default">可选</span></td><td>核采样概率 [0.01, 1.0],默认 0.95。建议仅与 temperature 二选一。思考模式下不可自定义</td></tr>
|
||||
<tr><td><code>frequency_penalty</code></td><td><span class="type-tag">number | null</span></td><td><span class="required-tag req-default">可选</span></td><td>频率惩罚 [-2.0, 2.0],默认 0</td></tr>
|
||||
<tr><td><code>presence_penalty</code></td><td><span class="type-tag">number | null</span></td><td><span class="required-tag req-default">可选</span></td><td>存在惩罚 [-2.0, 2.0],默认 0</td></tr>
|
||||
<tr><td><code>stop</code></td><td><span class="type-tag">string | array | null</span></td><td><span class="required-tag req-default">可选</span></td><td>停止序列(最多 4 个)。TTS 系列不支持</td></tr>
|
||||
<tr><td><code>stream</code></td><td><span class="type-tag">boolean | null</span></td><td><span class="required-tag req-default">可选</span></td><td>是否 SSE 流式传输,默认 false</td></tr>
|
||||
<tr><td><code>response_format</code></td><td><span class="type-tag">object</span></td><td><span class="required-tag req-default">可选</span></td><td>指定输出格式。TTS 系列不支持</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>深度思考参数</h3>
|
||||
<table>
|
||||
<tr><th width="160">参数名</th><th width="90">类型</th><th width="70">必填</th><th>描述</th></tr>
|
||||
<tr><td><code>thinking</code></td><td><span class="type-tag">object</span></td><td><span class="required-tag req-default">可选</span></td><td>思维链控制。TTS 系列不支持</td></tr>
|
||||
<tr><td><code>thinking.type</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-default">可选</span></td><td><code>"enabled"</code>(默认)或 <code>"disabled"</code></td></tr>
|
||||
</table>
|
||||
|
||||
<div class="warn-box">
|
||||
<strong>⚠️ 思考模式限制:</strong>在思考模式下,mimo-v2.5-pro / mimo-v2.5 不支持自定义 temperature 和 top_p,强制使用推荐默认值 1.0 和 0.95。多轮工具调用中建议保留历史 reasoning_content。
|
||||
</div>
|
||||
|
||||
<h3>工具调用参数</h3>
|
||||
<table>
|
||||
<tr><th width="160">参数名</th><th width="90">类型</th><th width="70">必填</th><th>描述</th></tr>
|
||||
<tr><td><code>tools</code></td><td><span class="type-tag">array</span></td><td><span class="required-tag req-default">可选</span></td><td>工具列表。支持 function 和 web_search 两种类型。TTS 系列不支持</td></tr>
|
||||
<tr><td><code>tools[].type</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-yes">必选</span></td><td>工具类型:<code>"function"</code> 或 <code>"web_search"</code></td></tr>
|
||||
<tr><td><code>tools[].function.name</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-yes">必选</span></td><td>函数名(a-z, A-Z, 0-9, _, -),最大 64 字符</td></tr>
|
||||
<tr><td><code>tools[].function.description</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-default">可选</span></td><td>功能描述</td></tr>
|
||||
<tr><td><code>tools[].function.parameters</code></td><td><span class="type-tag">object</span></td><td><span class="required-tag req-default">可选</span></td><td>JSON Schema 格式的参数定义</td></tr>
|
||||
<tr><td><code>tools[].function.strict</code></td><td><span class="type-tag">boolean</span></td><td><span class="required-tag req-default">可选</span></td><td>是否严格遵循 schema,默认 false</td></tr>
|
||||
<tr><td><code>tool_choice</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-default">可选</span></td><td>仅支持 <code>"auto"</code>。传入其他值会被后端移除。TTS 系列不支持</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>语音合成参数 (audio)</h3>
|
||||
<table>
|
||||
<tr><th width="160">参数名</th><th width="90">类型</th><th width="70">必填</th><th>描述</th></tr>
|
||||
<tr><td><code>audio</code></td><td><span class="type-tag">object</span></td><td><span class="required-tag req-default">可选</span></td><td>音频输出参数。仅 TTS 系列模型支持</td></tr>
|
||||
<tr><td><code>audio.format</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-default">可选</span></td><td>输出格式:<code>wav</code>(默认) / <code>mp3</code> / <code>pcm</code> / <code>pcm16</code>。stream:true 时默认 pcm</td></tr>
|
||||
<tr><td><code>audio.voice</code></td><td><span class="type-tag">string</span></td><td><span class="required-tag req-default">可选</span></td><td>预置音色 ID 或 base64 音频样本。TTS 预置:<code>mimo_default</code>, <code>冰糖</code>, <code>茉莉</code>, <code>苏打</code>, <code>白桦</code>, <code>Mia</code>, <code>Chloe</code>, <code>Milo</code>, <code>Dean</code></td></tr>
|
||||
<tr><td><code>audio.optimize_text_preview</code></td><td><span class="type-tag">boolean</span></td><td><span class="required-tag req-default">可选</span></td><td>智能润色播报文本,默认 false。仅 voicedesign 模型支持</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="tip-box">
|
||||
<strong>💡 TTS 提示:</strong>要生成音频时,必须添加一条 <code>role: "assistant"</code> 的消息指定合成文本。使用 voicedesign + optimize_text_preview=true 时可省略 assistant 消息。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== RESPONSE ===== -->
|
||||
<section id="response">
|
||||
<h2>📤 响应对象(非流式输出)</h2>
|
||||
<p>当 <code>stream: false</code> 时,API 返回完整的 <code>chat.completion</code> 对象。</p>
|
||||
|
||||
<h3>顶层字段</h3>
|
||||
<table>
|
||||
<tr><th width="180">字段名</th><th width="90">类型</th><th>描述</th></tr>
|
||||
<tr><td><code>id</code></td><td><span class="type-tag">string</span></td><td>响应的唯一标识符</td></tr>
|
||||
<tr><td><code>object</code></td><td><span class="type-tag">string</span></td><td>固定值 <code>"chat.completion"</code></td></tr>
|
||||
<tr><td><code>created</code></td><td><span class="type-tag">integer</span></td><td>Unix 时间戳(秒)</td></tr>
|
||||
<tr><td><code>model</code></td><td><span class="type-tag">string</span></td><td>实际使用的模型 ID</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>choices[] 字段</h3>
|
||||
<table>
|
||||
<tr><th width="200">字段名</th><th width="80">类型</th><th>描述</th></tr>
|
||||
<tr><td><code>choices[].index</code></td><td><span class="type-tag">integer</span></td><td>选项索引</td></tr>
|
||||
<tr><td><code>choices[].finish_reason</code></td><td><span class="type-tag">string</span></td><td>停止原因:<code>stop</code> / <code>length</code> / <code>tool_calls</code> / <code>content_filter</code> / <code>repetition_truncation</code></td></tr>
|
||||
<tr><td><code>choices[].message.content</code></td><td><span class="type-tag">string</span></td><td>回复内容</td></tr>
|
||||
<tr><td><code>choices[].message.reasoning_content</code></td><td><span class="type-tag">string</span></td><td>思维链推理内容(思考模式)</td></tr>
|
||||
<tr><td><code>choices[].message.role</code></td><td><span class="type-tag">string</span></td><td>固定为 <code>"assistant"</code></td></tr>
|
||||
<tr><td><code>choices[].message.tool_calls</code></td><td><span class="type-tag">array</span></td><td>工具调用列表(如有)</td></tr>
|
||||
<tr><td><code>choices[].message.tool_calls[].id</code></td><td><span class="type-tag">string</span></td><td>工具调用 ID</td></tr>
|
||||
<tr><td><code>choices[].message.tool_calls[].type</code></td><td><span class="type-tag">string</span></td><td>固定为 <code>"function"</code></td></tr>
|
||||
<tr><td><code>choices[].message.tool_calls[].function.name</code></td><td><span class="type-tag">string</span></td><td>被调用的函数名</td></tr>
|
||||
<tr><td><code>choices[].message.tool_calls[].function.arguments</code></td><td><span class="type-tag">string</span></td><td>JSON 格式的调用参数</td></tr>
|
||||
<tr><td><code>choices[].message.annotations</code></td><td><span class="type-tag">array</span></td><td>联网搜索引用注释(如有)</td></tr>
|
||||
<tr><td><code>choices[].message.audio</code></td><td><span class="type-tag">object</span></td><td>音频响应数据(TTS 请求时)</td></tr>
|
||||
<tr><td><code>choices[].message.audio.id</code></td><td><span class="type-tag">string</span></td><td>音频唯一标识</td></tr>
|
||||
<tr><td><code>choices[].message.audio.data</code></td><td><span class="type-tag">string</span></td><td>Base64 编码的音频数据</td></tr>
|
||||
<tr><td><code>choices[].final_text_preview</code></td><td><span class="type-tag">string</span></td><td>优化后的播报文本(optimize_text_preview 时返回)</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>usage 用量信息</h3>
|
||||
<table>
|
||||
<tr><th width="220">字段名</th><th width="80">类型</th><th>描述</th></tr>
|
||||
<tr><td><code>usage.prompt_tokens</code></td><td><span class="type-tag">integer</span></td><td>提示词 token 数</td></tr>
|
||||
<tr><td><code>usage.completion_tokens</code></td><td><span class="type-tag">integer</span></td><td>输出 token 数</td></tr>
|
||||
<tr><td><code>usage.total_tokens</code></td><td><span class="type-tag">integer</span></td><td>总 token 数</td></tr>
|
||||
<tr><td><code>usage.completion_tokens_details.reasoning_tokens</code></td><td><span class="type-tag">integer</span></td><td>推理 token 数</td></tr>
|
||||
<tr><td><code>usage.prompt_tokens_details.cached_tokens</code></td><td><span class="type-tag">integer</span></td><td>缓存命中的 token 数</td></tr>
|
||||
<tr><td><code>usage.prompt_tokens_details.audio_tokens</code></td><td><span class="type-tag">integer</span></td><td>音频输入 token 数</td></tr>
|
||||
<tr><td><code>usage.prompt_tokens_details.image_tokens</code></td><td><span class="type-tag">integer</span></td><td>图像输入 token 数</td></tr>
|
||||
<tr><td><code>usage.prompt_tokens_details.video_tokens</code></td><td><span class="type-tag">integer</span></td><td>视频输入 token 数</td></tr>
|
||||
<tr><td><code>usage.web_search_usage.tool_usage</code></td><td><span class="type-tag">integer</span></td><td>联网搜索 API 调用次数</td></tr>
|
||||
<tr><td><code>usage.web_search_usage.page_usage</code></td><td><span class="type-tag">integer</span></td><td>联网搜索返回网页数</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>响应示例</h3>
|
||||
<pre><span class="code-lang">json</span>{
|
||||
"id": "8b51f9e0515949cb8207fbd35ea6ea5c",
|
||||
"object": "chat.completion",
|
||||
"created": 1776848906,
|
||||
"model": "mimo-v2.5-pro",
|
||||
"choices": [
|
||||
{
|
||||
"finish_reason": "stop",
|
||||
"index": 0,
|
||||
"message": {
|
||||
"content": "Hello! I'm MiMo, Xiaomi's AI assistant created by the Xiaomi LLM-Core team...",
|
||||
"role": "assistant",
|
||||
"tool_calls": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"usage": {
|
||||
"completion_tokens": 72,
|
||||
"prompt_tokens": 57,
|
||||
"total_tokens": 129,
|
||||
"completion_tokens_details": {
|
||||
"reasoning_tokens": 0
|
||||
},
|
||||
"prompt_tokens_details": null
|
||||
}
|
||||
}</pre>
|
||||
</section>
|
||||
|
||||
<!-- ===== STREAM RESPONSE ===== -->
|
||||
<section id="response-stream">
|
||||
<h2>📤 响应 Chunk 对象(流式输出)</h2>
|
||||
<p>当 <code>stream: true</code> 时,API 通过 SSE 以 <code>chat.completion.chunk</code> 格式增量返回数据。</p>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>SSE 格式说明:</strong>每个 chunk 以 <code>data: {...}</code> 行发送,结束标记为 <code>data: [DONE]</code>。
|
||||
</div>
|
||||
|
||||
<h3>Chunk 特有字段(vs 非流式差异)</h3>
|
||||
<table>
|
||||
<tr><th width="220">字段名</th><th width="80">类型</th><th>描述</th></tr>
|
||||
<tr><td><code>object</code></td><td><span class="type-tag">string</span></td><td>固定值 <code>"chat.completion.chunk"</code></td></tr>
|
||||
<tr><td><code>choices[].delta</code></td><td><span class="type-tag">object</span></td><td>增量数据(替代 message)</td></tr>
|
||||
<tr><td><code>choices[].delta.content</code></td><td><span class="type-tag">string</span></td><td>本 chunk 的文本增量</td></tr>
|
||||
<tr><td><code>choices[].delta.reasoning_content</code></td><td><span class="type-tag">string</span></td><td>本 chunk 的推理增量</td></tr>
|
||||
<tr><td><code>choices[].delta.role</code></td><td><span class="type-tag">string</span></td><td>首个 chunk 中的角色(通常为 "assistant")</td></tr>
|
||||
<tr><td><code>choices[].delta.tool_calls</code></td><td><span class="type-tag">array</span></td><td>增量工具调用(含 index 定位)</td></tr>
|
||||
<tr><td><code>choices[].delta.tool_calls[].index</code></td><td><span class="type-tag">integer</span></td><td>工具调用在列表中的索引(从 0 开始)</td></tr>
|
||||
<tr><td><code>choices[].delta.audio</code></td><td><span class="type-tag">object | null</span></td><td>音频增量数据</td></tr>
|
||||
<tr><td><code>choices[].finish_reason</code></td><td><span class="type-tag">string | null</span></td><td>最后一个 chunk 的停止原因</td></tr>
|
||||
</table>
|
||||
|
||||
<p>其余字段(id, created, model, usage, annotations 等)与非流式相同,通常仅在最后一个 chunk 中返回 usage。</p>
|
||||
</section>
|
||||
|
||||
<!-- ===== THINKING ===== -->
|
||||
<section id="thinking">
|
||||
<h2>🧠 深度思考模式</h2>
|
||||
<p>MiMo V2.5 Pro 和标准版支持思维链(Chain-of-Thought)推理,让模型在回答前进行深度推理。适用于数学、逻辑、编程、复杂分析等场景。</p>
|
||||
|
||||
<h3>核心参数</h3>
|
||||
<table>
|
||||
<tr><th width="160">参数名</th><th width="90">类型</th><th>描述</th></tr>
|
||||
<tr><td><code>thinking.type</code></td><td><span class="type-tag">string</span></td><td><code>"enabled"</code>(默认)启用 / <code>"disabled"</code> 关闭</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>行为说明</h3>
|
||||
<ul style="padding-left:20px;margin:12px 0;font-size:0.93rem;">
|
||||
<li>启用后,响应中 <code>reasoning_content</code> 字段包含模型的推理过程,<code>content</code> 为最终回答</li>
|
||||
<li>思考模式下 <code>temperature</code> 强制为 <code>1.0</code>,<code>top_p</code> 强制为 <code>0.95</code>,自定义无效</li>
|
||||
<li>多轮工具调用中,模型同时返回 <code>tool_calls</code> 和 <code>reasoning_content</code></li>
|
||||
<li><strong>建议</strong>:后续每次请求的 messages 中保留所有历史 reasoning_content,以获得最佳表现</li>
|
||||
</ul>
|
||||
|
||||
<div class="warn-box">
|
||||
<strong>不支持范围:</strong>mimo-v2.5-tts / mimo-v2.5-tts-voicedesign / mimo-v2.5-tts-voiceclone 不支持思考模式。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== TOOLS ===== -->
|
||||
<section id="tools">
|
||||
<h2>🔧 工具调用 (Function Calling)</h2>
|
||||
<p>MiMo 支持 Function Calling,允许模型调用外部函数获取信息或执行操作。同时内置 <strong>Web Search</strong> 联网搜索工具。</p>
|
||||
|
||||
<h3>核心要点</h3>
|
||||
<table>
|
||||
<tr><th width="180">特性</th><th>描述</th></tr>
|
||||
<tr><td>工具类型</td><td><code>function</code>(函数工具)+ <code>web_search</code>(联网搜索)</td></tr>
|
||||
<tr><td>tool_choice</td><td>仅支持 <code>"auto"</code>。传入其他值会被后端移除</td></tr>
|
||||
<tr><td>strict 模式</td><td>支持 <code>strict: true</code>,严格遵循 JSON Schema(子集)</td></tr>
|
||||
<tr><td>思考模式兼容</td><td>V2.5 Pro/标准版支持思考模式下的工具调用</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Function Tool 结构</h3>
|
||||
<pre><span class="code-lang">json</span>{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"description": "获取指定城市的当前天气信息",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": { "type": "string", "description": "城市名称" }
|
||||
},
|
||||
"required": ["location"]
|
||||
},
|
||||
"strict": false
|
||||
}
|
||||
}</pre>
|
||||
|
||||
<div class="tip-box">
|
||||
<strong>💡 多轮工具调用提示:</strong>思考模式下工具调用会同时返回 reasoning_content,务必在后续轮次中保留以维持上下文连贯性。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== WEB SEARCH ===== -->
|
||||
<section id="websearch">
|
||||
<h2>🌐 联网搜索</h2>
|
||||
<p>MiMo 内置 Web Search 工具,模型可自动联网检索最新信息并在回答中引用来源。</p>
|
||||
|
||||
<h3>启用方式</h3>
|
||||
<p>在 <code>tools</code> 数组中添加 web search 类型的工具:</p>
|
||||
<pre><span class="code-lang">json</span>{
|
||||
"tools": [
|
||||
{ "type": "web_search" }
|
||||
]
|
||||
}</pre>
|
||||
|
||||
<h3>返回的引用注释 (annotations)</h3>
|
||||
<table>
|
||||
<tr><th width="200">字段名</th><th width="80">类型</th><th>描述</th></tr>
|
||||
<tr><td><code>annotations[].title</code></td><td><span class="type-tag">string</span></td><td>引用页面标题</td></tr>
|
||||
<tr><td><code>annotations[].url</code></td><td><span class="type-tag">string</span></td><td>引用网址</td></tr>
|
||||
<tr><td><code>annotations[].site_name</code></td><td><span class="type-tag">string</span></td><td>网站名称</td></tr>
|
||||
<tr><td><code>annotations[].summary</code></td><td><span class="type-tag">string</span></td><td>内容摘要</td></tr>
|
||||
<tr><td><code>annotations[].publish_time</code></td><td><span class="type-tag">string</span></td><td>发布时间</td></tr>
|
||||
<tr><td><code>annotations[].logo_url</code></td><td><span class="type-tag">string</span></td><td>网站 Logo 地址</td></tr>
|
||||
<tr><td><code>annotations[].type</code></td><td><span class="type-tag">string</span></td><td>类型</td></tr>
|
||||
<tr><td><code>error_message</code></td><td><span class="type-tag">string</span></td><td>联网搜索错误信息(如有)</td></tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- ===== TTS ===== -->
|
||||
<section id="tts">
|
||||
<h2>🎙️ 语音合成 (TTS)</h2>
|
||||
<p>MiMo 提供三种 TTS 能力,通过不同的模型和 audio 参数组合实现。</p>
|
||||
|
||||
<h3>三种模式对比</h3>
|
||||
<table>
|
||||
<tr><th>能力</th><th>模型</th><th>audio.voice</th><th>特点</th></tr>
|
||||
<tr><td>预置音色 TTS</td><td><code>mimo-v2.5-tts</code></td><td>可选,预置音色名</td><td>9 种预置音色,默认 mimo_default</td></tr>
|
||||
<tr><td>音色设计</td><td><code>mimo-v2.5-tts-voicedesign</code></td><td>不支持</td><td>通过文字描述设计音色</td></tr>
|
||||
<tr><td>声音克隆</td><td><code>mimo-v2.5-tts-voiceclone</code></td><td>必填,base64 音频</td><td>上传 3~10 秒音频样本克隆声音</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>预置音色列表 (mimo-v2.5-tts)</h3>
|
||||
<table>
|
||||
<tr><th>音色 ID</th><th>说明</th></tr>
|
||||
<tr><td><code>mimo_default</code></td><td>默认音色</td></tr>
|
||||
<tr><td><code>冰糖</code></td><td>甜美女声</td></tr>
|
||||
<tr><td><code>茉莉</code></td><td>温柔女声</td></tr>
|
||||
<tr><td><code>苏打</code></td><td>清爽男声</td></tr>
|
||||
<tr><td><code>白桦</code></td><td>沉稳男声</td></tr>
|
||||
<tr><td><code>Mia</code></td><td>英文女声</td></tr>
|
||||
<tr><td><code>Chloe</code></td><td>英文女声</td></tr>
|
||||
<tr><td><code>Milo</code></td><td>英文男声</td></tr>
|
||||
<tr><td><code>Dean</code></td><td>英文男声</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>音频格式</h3>
|
||||
<table>
|
||||
<tr><th>format 值</th><th>说明</th></tr>
|
||||
<tr><td><code>wav</code></td><td>WAV 格式(默认)</td></tr>
|
||||
<tr><td><code>mp3</code></td><td>MP3 格式</td></tr>
|
||||
<tr><td><code>pcm</code> / <code>pcm16</code></td><td>PCM16 格式(stream 模式下默认)</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="warn-box">
|
||||
<strong>⚠️ TTS 限制:</strong>TTS 系列模型 max_completion_tokens 范围为 [1, 8192];不支持 thinking、tools、response_format、stop 参数。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== EXAMPLES ===== -->
|
||||
<section id="examples">
|
||||
<h2>💻 代码示例</h2>
|
||||
|
||||
<h3>基础调用(非流式)</h3>
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" onclick="switchTab(event,'tab-ex1-py')">Python SDK</button>
|
||||
<button class="tab-btn" onclick="switchTab(event,'tab-ex1-curl')">curl</button>
|
||||
</div>
|
||||
<div id="tab-ex1-py" class="tab-content active">
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-pro",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are MiMo, an AI assistant developed by Xiaomi."},
|
||||
{"role": "user", "content": "你好,请介绍一下自己"}
|
||||
],
|
||||
max_completion_tokens=1024,
|
||||
temperature=1.0,
|
||||
thinking={"type": "disabled"}
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)
|
||||
print(f"输入: {response.usage.prompt_tokens}, 输出: {response.usage.completion_tokens}")</pre>
|
||||
</div>
|
||||
<div id="tab-ex1-curl" class="tab-content">
|
||||
<pre><span class="code-lang">bash</span>curl --location --request POST 'https://api.xiaomimimo.com/v1/chat/completions' \
|
||||
--header "api-key: $MIMO_API_KEY" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data-raw '{"model":"mimo-v2.5-pro","messages":[{"role":"system","content":"You are MiMo."},{"role":"user","content":"你好"}],"max_completion_tokens":1024,"thinking":{"type":"disabled"}}'</pre>
|
||||
</div>
|
||||
|
||||
<h3>流式响应</h3>
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" onclick="switchTab(event,'tab-ex2-py')">Python SDK</button>
|
||||
<button class="tab-btn" onclick="switchTab(event,'tab-ex2-js')">JavaScript</button>
|
||||
</div>
|
||||
<div id="tab-ex2-py" class="tab-content active">
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-pro",
|
||||
messages=[
|
||||
{"role": "system", "content": "你是一个专业的编程助手。"},
|
||||
{"role": "user", "content": "解释 JavaScript 的事件循环机制"}
|
||||
],
|
||||
stream=True
|
||||
)
|
||||
|
||||
full_reply = ""
|
||||
for chunk in response:
|
||||
content = chunk.choices[0].delta.content
|
||||
if content:
|
||||
full_reply += content
|
||||
print(content, end="", flush=True)
|
||||
|
||||
# 继续对话
|
||||
messages.append({"role": "assistant", "content": full_reply})
|
||||
messages.append({"role": "user", "content": "能给一个 async/await 的代码示例吗?"})</pre>
|
||||
</div>
|
||||
<div id="tab-ex2-js" class="tab-content">
|
||||
<pre><span class="code-lang">javascript</span>const response = await fetch('https://api.xiaomimimo.com/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'api-key': MIMO_API_KEY,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'mimo-v2.5-pro',
|
||||
messages: [
|
||||
{ role: 'system', content: '你是一个专业的编程助手。' },
|
||||
{ role: 'user', content: '解释 JavaScript 的事件循环机制' }
|
||||
],
|
||||
stream: true
|
||||
})
|
||||
});
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const lines = buffer.split('\n');
|
||||
buffer = lines.pop();
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('data: ') || line === 'data: [DONE]') continue;
|
||||
const chunk = JSON.parse(line.slice(6));
|
||||
const content = chunk.choices[0]?.delta?.content;
|
||||
if (content) process.stdout.write(content);
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<h3>深度思考模式</h3>
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-pro",
|
||||
messages=[{"role": "user", "content": "9.11 和 9.8 哪个更大?"}],
|
||||
extra_body={"thinking": {"type": "enabled"}}
|
||||
)
|
||||
|
||||
msg = response.choices[0].message
|
||||
print(f"[思考过程]\n{msg.reasoning_content}")
|
||||
print(f"\n[最终回答]\n{msg.content}")</pre>
|
||||
|
||||
<h3>函数调用 (Function Calling)</h3>
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-pro",
|
||||
messages=[{"role": "user", "content": "杭州今天天气怎么样?"}],
|
||||
tools=[{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"description": "获取指定城市的当前天气信息",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {"type": "string", "description": "城市名称"}
|
||||
},
|
||||
"required": ["location"]
|
||||
}
|
||||
}
|
||||
}]
|
||||
)
|
||||
|
||||
tool_calls = response.choices[0].message.tool_calls
|
||||
print("工具调用:", tool_calls)</pre>
|
||||
|
||||
<h3>联网搜索</h3>
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-pro",
|
||||
messages=[{"role": "user", "content": "今天有什么科技新闻?"}],
|
||||
tools=[{"type": "web_search"}]
|
||||
)
|
||||
|
||||
msg = response.choices[0].message
|
||||
print("回答:", msg.content)
|
||||
if msg.annotations:
|
||||
print("\n引用来源:")
|
||||
for ann in msg.annotations:
|
||||
print(f" - [{ann.title}]({ann.url})")</pre>
|
||||
|
||||
<h3>语音合成 (TTS)</h3>
|
||||
<pre><span class="code-lang">python</span>from openai import OpenAI
|
||||
import base64
|
||||
|
||||
client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="mimo-v2.5-tts",
|
||||
messages=[
|
||||
{"role": "user", "content": "用甜美的声音为大家念一首诗"},
|
||||
{"role": "assistant", "content": "床前明月光,疑是地上霜。举头望明月,低头思故乡。"}
|
||||
],
|
||||
audio={
|
||||
"format": "wav",
|
||||
"voice": "茉莉"
|
||||
}
|
||||
)
|
||||
|
||||
audio_data = response.choices[0].message.audio.data
|
||||
audio_bytes = base64.b64decode(audio_data)
|
||||
with output("output.wav", "wb") as f:
|
||||
f.write(audio_bytes)
|
||||
print("音频已保存到 output.wav")</pre>
|
||||
</section>
|
||||
|
||||
<!-- ===== ERRORS ===== -->
|
||||
<section id="errors">
|
||||
<h2>⚠️ 错误码说明</h2>
|
||||
<table>
|
||||
<tr><th width="120">错误码</th><th>HTTP 状态</th><th>描述</th></tr>
|
||||
<tr><td><code>invalid_api_key</code></td><td>401</td><td>API Key 无效或未提供</td></tr>
|
||||
<tr><td><code>rate_limit_exceeded</code></td><td>429</td><td>请求频率超限,请稍后重试</td></tr>
|
||||
<tr><td><code>invalid_request</code></td><td>400</td><td>请求参数错误(如缺少必填字段、模型不存在等)</td></tr>
|
||||
<tr><td><code>context_length_exceeded</code></td><td>400</td><td>输入内容超出模型上下文长度限制</td></tr>
|
||||
<tr><td><code>content_filter</code></td><td>400</td><td>内容触发安全过滤策略</td></tr>
|
||||
<tr><td><code>server_error</code></td><td>500</td><td>服务器内部错误</td></tr>
|
||||
<tr><td><code>model_not_found</code></td><td>404</td><td>请求的模型不存在或已下线</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>📌 finish_reason 含义参考:</strong><br>
|
||||
• <code>stop</code> — 自然结束 · <code>length</code> — 达到最大 token · <code>tool_calls</code> — 模型调用了工具<br>
|
||||
• <code>content_filter</code> — 内容被过滤 · <code>repetition_truncation</code> — 检测到复读截断
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div><!-- /.container -->
|
||||
|
||||
<!-- ===== FOOTER ===== -->
|
||||
<footer>
|
||||
<p>本文档基于 <a href="https://mimo.mi.com/docs/zh-CN/api/chat/openai-api" target="_blank">MiMo 官方 API 文档</a> 整理</p>
|
||||
<p style="margin-top:8px;">支持模型:<strong>mimo-v2.5-pro · mimo-v2.5 · mimo-v2.5-tts · mimo-v2.5-tts-voicedesign · mimo-v2.5-tts-voiceclone</strong></p>
|
||||
<p style="margin-top:8px;opacity:0.5;">Generated with ❤️ · 文档日期 2026-07-15 · 参考 DeepSeek API 文档风格</p>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
function switchTab(evt, tabId) {
|
||||
const tabBtns = evt.target.parentElement.querySelectorAll('.tab-btn');
|
||||
tabBtns.forEach(b => b.classList.remove('active'));
|
||||
evt.target.classList.add('active');
|
||||
const parent = evt.target.parentElement.parentElement;
|
||||
parent.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||||
document.getElementById(tabId).classList.add('active');
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -920,15 +920,21 @@ web_search(query) → [SearXNG模式] → JSON结果 → 相关性过滤
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `src/main/browser.ts` | 浏览器控制核心(9 个函数) |
|
||||
| `src/main/tool-handlers-system.ts` | web_fetch + web_search + SearXNG(核心实现) |
|
||||
| `src/main/ipc.ts` | IPC 工具调度 |
|
||||
| `src/main/main.ts` | 应用生命周期(browserClose on quit) |
|
||||
| `src/renderer/components/searxng-modal.ts` | SearXNG 配置模态框 |
|
||||
| `src/renderer/index.html` | SearXNG 模态框 HTML |
|
||||
| `src/renderer/styles/style.css` | SearXNG 样式 |
|
||||
| `src/renderer/services/tool-registry.ts` | 工具定义和参数声明 |
|
||||
| `src/renderer/services/agent-engine.ts` | 工具超时配置、并行/串行调度 |
|
||||
| `electron/harness/tools/built-in/browser.ts` | 浏览器控制核心(9 个 action 路由) |
|
||||
| `electron/harness/tools/built-in/browser-window-manager.ts` | 浏览器窗口状态管理 + 页面操作(单例 + 隔离会话) |
|
||||
| `electron/harness/tools/built-in/web-search.ts` | web_search 工具(SearXNG / 内置四引擎双模式) |
|
||||
| `electron/harness/tools/built-in/web-fetch.ts` | web_fetch 工具(三阶段回退抓取) |
|
||||
| `electron/harness/tools/built-in/network-utils.ts` | 网络工具函数(LRU 缓存、UA 轮换、反爬请求头、拦截检测、HTML 转文本、SearXNG 认证) |
|
||||
| `electron/harness/tools/built-in/http-request.ts` | HTTP/REST API 请求工具 |
|
||||
| `electron/harness/tools/built-in/file-guard.ts` | 文件保护(工作空间边界 + MEMORY.md 保护) |
|
||||
| `electron/harness/tools/registry.ts` | 工具注册表 + PolicyEngine 策略引擎 + truncateResult |
|
||||
| `electron/harness/sandbox/permissions.ts` | PolicyEngine(三级权限 + 频率限制 + 通配符策略) |
|
||||
| `electron/harness/agent-loop/engine.ts` | Agent Loop 引擎(ReAct 状态机 + 工具超时配置) |
|
||||
| `electron/ipc/handlers.ts` | IPC 通道处理(50+ 通道,含 `searxng:testConnection`) |
|
||||
| `electron/main.ts` | 应用生命周期(启动流程 + browserClose on quit) |
|
||||
| `src/components/settings/SettingsModal.tsx` | 设置面板(含 SearXNG 配置 Tab) |
|
||||
| `src/stores/agent-store.ts` | Agent 状态管理(Zustand) |
|
||||
| `src/hooks/useAgentStream.ts` | 流式事件监听 Hook |
|
||||
|
||||
## 附录 C:第三方库速查表
|
||||
|
||||
|
||||
@@ -480,7 +480,7 @@ MeToast.<span class="hl-fn">warning</span>(<span class="hl-str">'操作已取消
|
||||
<tr><th>Tab</th><th>内容</th></tr>
|
||||
<tr><td class="f1">LLM 配置</td><td class="f2">Provider 选择、API Key、模型名称、参数滑块(temperature/maxTokens/contextWindow)</td></tr>
|
||||
<tr><td class="f1">Agent 配置</td><td class="f2">最大迭代次数、超时、Thinking 开关、反思模式、压缩阈值</td></tr>
|
||||
<tr><td class="f1">工具管理</td><td class="f2">9 个基础工具开关、风险级别配置、路径白名单、命令黑名单</td></tr>
|
||||
<tr><td class="f1">工具管理</td><td class="f2">27 个内置工具开关、风险级别配置、路径白名单、命令黑名单</td></tr>
|
||||
<tr><td class="f1">MCP 服务</td><td class="f2">Server 列表、添加/删除/启停、连接状态指示灯</td></tr>
|
||||
<tr><td class="f1">外观</td><td class="f2">主题(light/dark/auto)、字体大小、消息密度、动画开关</td></tr>
|
||||
<tr><td class="f1">日志与数据</td><td class="f2">日志级别、数据库位置、数据导出/清理、使用统计</td></tr>
|
||||
@@ -718,7 +718,7 @@ MeToast.<span class="hl-fn">warning</span>(<span class="hl-str">'操作已取消
|
||||
<div style="text-align:center;padding:40px 0 20px;color:var(--text-dim);font-size:13px;border-top:1px solid var(--border)">
|
||||
<p>🎨 MetonaAI Desktop UI/UX 设计集成方案</p>
|
||||
<p>研究来源: <strong style="color:var(--accent)">Fuselab Creative · Ant Design X · Google A2UI · Hermes Agent · Siyu's Newsletter</strong></p>
|
||||
<p style="margin-top:6px">集成组件: <strong style="color:var(--purple)">MetonaToast v2.0.0</strong> · 版本 <strong style="color:var(--accent2)">v1.0.0</strong> · 2026-06-26</p>
|
||||
<p style="margin-top:6px">集成组件: <strong style="color:var(--purple)">MetonaToast v2.0.0</strong> · 版本 <strong style="color:var(--accent2)">v1.0.0</strong> · 2026-07-15</p>
|
||||
</div>
|
||||
|
||||
<!-- Back to Top Button -->
|
||||
|
||||
@@ -280,7 +280,7 @@
|
||||
<div class="hero-meta">
|
||||
<span><span class="dot dot-accent"></span> 版本: <strong>v1.0.0</strong></span>
|
||||
<span><span class="dot dot-green"></span> 适用范围: <strong>Electron 主进程 / IPC / 渲染进程</strong></span>
|
||||
<span><span class="dot dot-orange"></span> 更新日期: <strong>2026-06-26</strong></span>
|
||||
<span><span class="dot dot-orange"></span> 更新日期: <strong>2026-07-15</strong></span>
|
||||
</div>
|
||||
<div class="note-box" style="margin-top:16px">
|
||||
<strong>📋 文档层级:</strong>本文档是 <strong>类型系统与数据格式的权威定义</strong>,与《构建指南》第四章(ReAct)、第五章(Harness)对应。冲突时以本文档为准。
|
||||
@@ -309,11 +309,11 @@
|
||||
<span class="hl-box">│ Metona IR Standard │</span> ← 项目内唯一标准
|
||||
<span class="hl-box">└────────────┬─────────────┘</span>
|
||||
│
|
||||
┌────────┼────────┬────────┐
|
||||
│ │ │ │
|
||||
<span class="hl-box">┌───▼──┐ ┌──▼───┐ ┌─▼───┐ ┌─▼─────┐</span>
|
||||
<span class="hl-box">│DeepSeek│ │Agnes│ │Ollama│ │Anthropic│</span> ← Adapter 层
|
||||
<span class="hl-box">└───────┘ └─────┘ └──────┘ └────────┘</span>
|
||||
┌────────┼────────┐
|
||||
│ │ │
|
||||
<span class="hl-box">┌───▼──┐ ┌──▼───┐ ┌─▼───┐</span>
|
||||
<span class="hl-box">│DeepSeek│ │Agnes│ │Ollama│</span> ← Adapter 层
|
||||
<span class="hl-box">└───────┘ └─────┘ └──────┘</span>
|
||||
</pre>
|
||||
</div>
|
||||
<p class="desc">
|
||||
@@ -1000,13 +1000,13 @@
|
||||
<td>Ollama 原生 JSON / NDJSON</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="field-name">AnthropicAdapter</td>
|
||||
<td class="field-name">AnthropicAdapter(未来计划,未实现)</td>
|
||||
<td class="field-type">anthropic</td>
|
||||
<td>https://api.anthropic.com/v1/messages</td>
|
||||
<td>Anthropic 原生 JSON</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="field-name">OpenAIAdapter</td>
|
||||
<td class="field-name">OpenAIAdapter(未来计划,未实现)</td>
|
||||
<td class="field-type">openai</td>
|
||||
<td>https://api.openai.com/v1/chat/completions</td>
|
||||
<td>OpenAI 原生 JSON</td>
|
||||
@@ -1177,8 +1177,8 @@ electron/harness/adapters/
|
||||
├── deepseek.adapter.ts
|
||||
├── agnes-ai.adapter.ts
|
||||
├── ollama.adapter.ts
|
||||
├── anthropic.adapter.ts
|
||||
└── openai.adapter.ts</pre>
|
||||
# ├── anthropic.adapter.ts # 未来计划
|
||||
# └── openai.adapter.ts # 未来计划</pre>
|
||||
</div>
|
||||
|
||||
<h3>迁移检查清单</h3>
|
||||
@@ -1204,7 +1204,7 @@ electron/harness/adapters/
|
||||
<!-- FOOTER -->
|
||||
<div style="text-align:center; padding: 40px 0 20px; color: var(--text-dim); font-size: 13px; border-top: 1px solid var(--border);">
|
||||
<p>📜 Metona 内部 API 请求与响应标准 —— 项目端到端类型安全的基础</p>
|
||||
<p>版本: <strong style="color:var(--accent)">v1.0.0</strong> · 生效日期: <strong style="color:var(--accent)">2026-06-25</strong></p>
|
||||
<p>版本: <strong style="color:var(--accent)">v1.0.0</strong> · 生效日期: <strong style="color:var(--accent)">2026-07-15</strong></p>
|
||||
<p style="margin-top:8px;">所属项目: Metona (AI Agent Desktop) · 技术栈: TypeScript + React + SQLite + Electron</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MetonaAI-Desktop 架构与交互设计文档 | v1.0</title>
|
||||
<title>MetonaAI-Desktop 架构与交互设计文档 | v1.1</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0f1117;
|
||||
@@ -141,7 +141,7 @@
|
||||
<a href="#workspace">📁 工作空间</a>
|
||||
<a href="#db-config">💾 数据库配置</a>
|
||||
|
||||
<div class="sidebar-section">9 个基础工具</div>
|
||||
<div class="sidebar-section">27 个内置工具</div>
|
||||
<a href="#tools-overview">📊 工具总表</a>
|
||||
<a href="#tool-filesystem">📄 文件系统工具</a>
|
||||
<a href="#tool-web">🌐 网络搜索与抓取</a>
|
||||
@@ -165,14 +165,14 @@
|
||||
|
||||
<div class="hero">
|
||||
<h1>MetonaAI-Desktop 架构与交互设计</h1>
|
||||
<p>基于「生产级通用 AI Agent 桌面应用构建指南」+「Metona 内部 IR 标准」,定义完整的系统架构、9 个基础工具、4 个用户级磁盘文件、工作空间机制、数据库配置规范及全链路可追踪日志体系。</p>
|
||||
<p>基于「生产级通用 AI Agent 桌面应用构建指南」+「Metona 内部 IR 标准」,定义完整的系统架构、27 个内置工具、4 个用户级磁盘文件、工作空间机制、数据库配置规范及全链路可追踪日志体系。</p>
|
||||
<div class="hero-meta">
|
||||
<span><span class="dot dot-cyan"></span> 版本: <strong>v1.0.0</strong></span>
|
||||
<span><span class="dot dot-cyan"></span> 版本: <strong>v1.1.0</strong></span>
|
||||
<span><span class="dot dot-green"></span> 技术栈: <strong>React + Material UI (MUI) + Electron + SQLite</strong></span>
|
||||
<span><span class="dot dot-amber"></span> 日期: <strong>2026-06-26</strong></span>
|
||||
<span><span class="dot dot-amber"></span> 日期: <strong>2026-07-15</strong></span>
|
||||
</div>
|
||||
<div class="note-box" style="margin-top:16px">
|
||||
<strong>📋 文档层级:</strong>本文档是 <strong>工作空间、9 个基础工具、4 个磁盘文件、数据库配置的权威定义</strong>,与《构建指南》第三、五、六章对应。冲突时以本文档为准。
|
||||
<strong>📋 文档层级:</strong>本文档是 <strong>工作空间、27 个内置工具、4 个磁盘文件、数据库配置的权威定义</strong>,与《构建指南》第三、五、六章对应。冲突时以本文档为准。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
<p class="desc">
|
||||
MetonaAI-Desktop 是一个运行在用户本地桌面上的通用 AI Agent 应用。它以<strong>工作空间(Workspace)</strong>为基本组织单元,
|
||||
通过 <strong>4 个 Markdown 磁盘文件</strong> 定义 Agent 的灵魂、行为、记忆和用户画像,
|
||||
提供 <strong>9 个基础工具</strong> 赋予 Agent 操作文件系统、网络、记忆和命令行的能力。
|
||||
提供 <strong>27 个内置工具</strong> 赋予 Agent 操作文件系统、网络、记忆和命令行的能力。
|
||||
全链路操作<strong>透明可追踪</strong>,所有决策过程、工具调用、LLM 推理记录在本地 SQLite 日志中。
|
||||
</p>
|
||||
|
||||
@@ -203,11 +203,11 @@
|
||||
<span class="hl-box">│ └────┬──────────────────────────────────────────────┘ │</span>
|
||||
<span class="hl-box">│ │ │</span>
|
||||
<span class="hl-box">│ ┌────▼──────────────────────────────────────────────┐ │</span>
|
||||
<span class="hl-box">│ │ 9 Base Tools (统一 IR) │ │</span>
|
||||
<span class="hl-box">│ │ read_file | write_file | list_dir | search_files │ │</span>
|
||||
<span class="hl-box">│ │ web_search | web_extract │ │</span>
|
||||
<span class="hl-box">│ │ memory_store | memory_search │ │</span>
|
||||
<span class="hl-box">│ │ run_command │ │</span>
|
||||
<span class="hl-box">│ │ 27 Base Tools (统一 IR) │ │</span>
|
||||
<span class="hl-box">│ │ filesystem(5) | editor | code_search | diff │ │</span>
|
||||
<span class="hl-box">│ │ web_search | web_fetch | web_browser | http │ │</span>
|
||||
<span class="hl-box">│ │ memory(2) | run_command | delegate_task │ │</span>
|
||||
<span class="hl-box">│ │ git(4) | dev_tools(3) | task_mgr | todo | think │ │</span>
|
||||
<span class="hl-box">│ └────┬──────────────────────────────────────────────┘ │</span>
|
||||
<span class="hl-box">│ │ │</span>
|
||||
<span class="hl-box">│ ┌────▼──────────────────────────────────────────────┐ │</span>
|
||||
@@ -388,9 +388,9 @@
|
||||
|
||||
<hr class="section-divider">
|
||||
|
||||
<!-- ====== 9 个基础工具 ====== -->
|
||||
<!-- ====== 27 个内置工具 ====== -->
|
||||
<section class="api-section" id="tools-overview">
|
||||
<h2>📊 9 个基础工具 — 总表</h2>
|
||||
<h2>📊 27 个内置工具 — 总表</h2>
|
||||
<p class="desc">所有工具使用 <strong>Metona IR 的 MetonaToolDef / MetonaToolCall / MetonaToolResult</strong> 结构。内置在 Tool Registry 中,Adaper 为 LLM 生成 JSON Schema 格式的描述。</p>
|
||||
|
||||
<table class="spec">
|
||||
@@ -400,16 +400,17 @@
|
||||
<tr><td class="f-name">3</td><td class="f-name">list_directory</td><td class="f-type">filesystem</td><td class="f-risk risk-safe">SAFE</td><td>否</td><td>列出目录内容</td></tr>
|
||||
<tr><td class="f-name">4</td><td class="f-name">search_files</td><td class="f-type">filesystem</td><td class="f-risk risk-safe">SAFE</td><td>否</td><td>按模式搜索文件(名称/内容)</td></tr>
|
||||
<tr><td class="f-name">5</td><td class="f-name">web_search</td><td class="f-type">network</td><td class="f-risk risk-medium">LOW</td><td>否</td><td>网络搜索,返回结果列表</td></tr>
|
||||
<tr><td class="f-name">6</td><td class="f-name">web_extract</td><td class="f-type">network</td><td class="f-risk risk-medium">LOW</td><td>否</td><td>抓取网页内容转 Markdown</td></tr>
|
||||
<tr><td class="f-name">6</td><td class="f-name">web_fetch</td><td class="f-type">network</td><td class="f-risk risk-medium">LOW</td><td>否</td><td>抓取网页内容转 Markdown</td></tr>
|
||||
<tr><td class="f-name">7</td><td class="f-name">memory_store</td><td class="f-type">database</td><td class="f-risk risk-medium">MEDIUM</td><td>否</td><td>存储一条记忆到 SQLite</td></tr>
|
||||
<tr><td class="f-name">8</td><td class="f-name">memory_search</td><td class="f-type">database</td><td class="f-risk risk-safe">SAFE</td><td>否</td><td>检索记忆(关键词匹配)</td></tr>
|
||||
<tr><td class="f-name">9</td><td class="f-name">run_command</td><td class="f-type">code_execution</td><td class="f-risk risk-high">HIGH</td><td>是</td><td>执行 Shell 命令,沙箱限制</td></tr>
|
||||
<tr><td colspan="6" style="padding:14px;color:var(--text-dim);font-size:13px;">完整 27 个工具列表详见 README.md「内置工具」章节。新增工具涵盖:file_editor、code_search、diff_viewer、web_browser、http_request、git_status/git_diff/git_log/git_commit、lint_code、run_tests、project_info、delegate_task、task_manager、todo_write、think、view_image。</td></tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- --- 文件系统工具 --- -->
|
||||
<section class="api-section" id="tool-filesystem">
|
||||
<h2>📄 类别一:文件系统工具(4个)</h2>
|
||||
<h2>📄 类别一:文件系统工具(5个)</h2>
|
||||
|
||||
<h3>1. read_file</h3>
|
||||
<p class="desc">读取文件完整内容。支持行偏移和行数限制,自动检测二进制文件。文件超过 100K 字符时返回截断提示。</p>
|
||||
@@ -453,7 +454,7 @@
|
||||
|
||||
<!-- --- 网络工具 --- -->
|
||||
<section class="api-section" id="tool-web">
|
||||
<h2>🌐 类别二:网络搜索与抓取(2个)</h2>
|
||||
<h2>🌐 类别二:网络搜索与抓取(2个)(另有 18 个工具见 README.md)</h2>
|
||||
|
||||
<h3>5. web_search</h3>
|
||||
<p class="desc">执行网络搜索,返回标题、摘要和 URL。支持搜索运算符(site:、filetype: 等)。</p>
|
||||
@@ -463,8 +464,8 @@
|
||||
<tr><td class="f-name">limit</td><td class="f-type">number</td><td class="f-opt">可选</td><td>结果数(默认 5,最大 100)</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>6. web_extract</h3>
|
||||
<p class="desc">抓取网页内容并转换为 Markdown。支持 HTML 页面和 PDF 链接。超过 5000 字符自动摘要。</p>
|
||||
<h3>6. web_fetch</h3>
|
||||
<p class="desc">抓取网页内容,三阶段回退(HTTP + 反爬 + 浏览器渲染),10MB 限制</p>
|
||||
<table class="spec">
|
||||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||||
<tr><td class="f-name">urls</td><td class="f-type">string[]</td><td class="f-req">必填</td><td>待抓取的 URL 列表(最多 5 个)</td></tr>
|
||||
@@ -473,7 +474,7 @@
|
||||
|
||||
<!-- --- 记忆工具 --- -->
|
||||
<section class="api-section" id="tool-memory">
|
||||
<h2>🧠 类别三:记忆工具(2个)</h2>
|
||||
<h2>🧠 类别三:记忆工具(2个)(另有 18 个工具见 README.md)</h2>
|
||||
|
||||
<h3>7. memory_store</h3>
|
||||
<p class="desc">将一条内容存入持久记忆。写入 SQLite,支持关键词检索。Agent 可在对话中保存重要信息。</p>
|
||||
@@ -499,7 +500,7 @@
|
||||
|
||||
<!-- --- 命令工具 --- -->
|
||||
<section class="api-section" id="tool-command">
|
||||
<h2>⚒️ 类别四:命令工具(1个)</h2>
|
||||
<h2>⚒️ 类别四:命令工具(1个)(另有 18 个工具见 README.md)</h2>
|
||||
|
||||
<h3>9. run_command</h3>
|
||||
<p class="desc">在沙箱环境中执行 Shell 命令。命令在工作空间目录下运行,有超时限制和输出截断。高危命令需用户确认。</p>
|
||||
@@ -962,7 +963,7 @@
|
||||
<div style="text-align:center; padding: 40px 0 20px; color: var(--text-dim); font-size: 13px; border-top: 1px solid var(--border);">
|
||||
<p>🏗️ MetonaAI-Desktop 架构与交互设计文档</p>
|
||||
<p>基于: <strong style="color:var(--accent)">生产级通用 AI Agent 构建指南</strong> + <strong style="color:var(--accent)">Metona 内部 IR 标准</strong></p>
|
||||
<p style="margin-top:6px;">版本 <strong style="color:var(--accent)">v1.1.0</strong> · 2026-06-26</p>
|
||||
<p style="margin-top:6px;">版本 <strong style="color:var(--accent)">v1.1.0</strong> · 2026-07-15</p>
|
||||
</div>
|
||||
|
||||
<!-- Back to Top Button -->
|
||||
|
||||
@@ -591,7 +591,7 @@
|
||||
<div class="hero-meta">
|
||||
<span><span class="dot dot-blue"></span> 技术栈: <strong>TypeScript + React + SQLite + Electron</strong></span>
|
||||
<span><span class="dot dot-green"></span> 版本: <strong>v1.0.0</strong></span>
|
||||
<span><span class="dot dot-amber"></span> 更新日期: <strong>2026-06-26</strong></span>
|
||||
<span><span class="dot dot-amber"></span> 更新日期: <strong>2026-07-15</strong></span>
|
||||
</div>
|
||||
<div class="note-box" style="margin-top:16px">
|
||||
<strong>📋 文档层级:</strong>本文档是 <strong>理论基础与全景概述</strong>。各子领域的权威定义见以下文档(冲突时以子文档为准):<br>• 类型系统与数据格式 → <strong>《Metona 内部 API 请求与响应标准》</strong><br>• 工作空间/工具/磁盘文件 → <strong>《MetonaAI-Desktop 架构与交互设计》</strong><br>• 用户界面与交互 → <strong>《MetonaAI-Desktop UI/UX 设计集成方案》</strong>
|
||||
@@ -601,7 +601,7 @@
|
||||
<div class="content">
|
||||
<h1>生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南</h1>
|
||||
<blockquote>
|
||||
<p><strong>技术栈</strong>:TypeScript + React + SQLite + Electron<br><strong>版本</strong>:v1.0.0 | <strong>更新日期</strong>:2026-06-24<br><strong>定位</strong>:从架构设计到代码实现的全链路生产级工程指南</p>
|
||||
<p><strong>技术栈</strong>:TypeScript + React + SQLite + Electron<br><strong>版本</strong>:v1.0.0 | <strong>更新日期</strong>:2026-07-15<br><strong>定位</strong>:从架构设计到代码实现的全链路生产级工程指南</p>
|
||||
</blockquote>
|
||||
<hr>
|
||||
<h2>目录</h2>
|
||||
@@ -1092,12 +1092,28 @@
|
||||
│ │ ├── tools/ # 工具注册与管理
|
||||
│ │ │ ├── registry.ts # 工具注册表
|
||||
│ │ │ ├── base-tool.ts # 工具基类/接口
|
||||
│ │ │ └── built-in/ # 内置工具集
|
||||
│ │ │ ├── filesystem.ts # 文件系统工具
|
||||
│ │ │ ├── web-search.ts # 网络搜索工具
|
||||
│ │ │ ├── calculator.ts # 计算器工具
|
||||
│ │ │ ├── code-executor.ts # 代码执行工具
|
||||
│ │ │ └── index.ts
|
||||
│ │ │ └── built-in/ # 内置工具集(21 个文件,27 个工具)
|
||||
│ │ │ ├── filesystem.ts # 文件系统(5 工具)
|
||||
│ │ │ ├── file-editor.ts # 编辑器
|
||||
│ │ │ ├── code-search.ts # 代码搜索
|
||||
│ │ │ ├── diff-viewer.ts # 差异查看
|
||||
│ │ │ ├── web-search.ts # 网络搜索
|
||||
│ │ │ ├── web-fetch.ts # 网页抓取
|
||||
│ │ │ ├── browser.ts # 浏览器工具
|
||||
│ │ │ ├── browser-window-manager.ts
|
||||
│ │ │ ├── network.ts # 网络工具入口
|
||||
│ │ │ ├── network-utils.ts # 网络工具函数
|
||||
│ │ │ ├── http-request.ts # HTTP 请求
|
||||
│ │ │ ├── memory.ts # 记忆工具
|
||||
│ │ │ ├── command.ts # 命令执行
|
||||
│ │ │ ├── git.ts # Git 工具(4 个)
|
||||
│ │ │ ├── dev-tools.ts # 开发工具(3 个)
|
||||
│ │ │ ├── task-manager.ts # 任务管理
|
||||
│ │ │ ├── delegate-task.ts # 子任务委派
|
||||
│ │ │ ├── todo.ts # TODO 工具
|
||||
│ │ │ ├── think.ts # 思考工具
|
||||
│ │ │ ├── view-image.ts # 图片查看
|
||||
│ │ │ └── file-guard.ts # 文件保护
|
||||
│ │ ├── prompts/ # Prompt 模板管理
|
||||
│ │ │ ├── system-prompt.ts # 系统 Prompt 构建
|
||||
│ │ │ ├── templates/ # Prompt 模板文件
|
||||
@@ -2661,6 +2677,7 @@ export class ToolRegistry {
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p><strong>🔧 备注</strong>:v0.3.3 当前已实现 <strong>27 个内置工具</strong>,完整列表详见 <code>README.md</code>「内置工具」章节。下方仅以文件系统工具为示例展示实现规范。</p>
|
||||
<p><strong>内置工具示例——文件系统工具</strong>:</p>
|
||||
<pre><code class="language-typescript">// ====== electron/harness/tools/built-in/filesystem.ts ======
|
||||
|
||||
@@ -3298,6 +3315,7 @@ export interface ValidationIssue {
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>6.2 SQLite 存储方案设计</h3>
|
||||
<p><strong>📁 实际表结构</strong>:v0.3.3 实际共 <strong>9 张表</strong>,包含:<code>sessions</code>、<code>messages</code>、<code>app_config</code>、<code>audit_logs</code>、<code>mcp_servers</code>、<code>episodic_memories</code>、<code>semantic_memories</code>、<code>working_memories</code>、<code>tasks</code>(新增任务表,用于 Agent 子任务管理)。</p>
|
||||
<pre><code class="language-sql">-- ====== database/schema.sql ======
|
||||
|
||||
-- ============================================
|
||||
@@ -4345,6 +4363,7 @@ declare global {
|
||||
}
|
||||
</code></pre>
|
||||
<h3>8.3 IPC 通道设计规范</h3>
|
||||
<p><strong>🔗 实际规模</strong>:v0.3.3 实际已注册 <strong>50+ 个 IPC 通道</strong>,覆盖 agent、sessions、db、mcp、config、app、tasks 等多个 domain。下方代码为注册规范的代表性示例。</p>
|
||||
<pre><code class="language-typescript">// ====== electron/ipc/index.ts ======
|
||||
|
||||
/**
|
||||
@@ -6548,7 +6567,7 @@ ENABLE_TELEMETRY=true
|
||||
<!-- FOOTER -->
|
||||
<div style="text-align:center;padding:40px 0 20px;color:var(--text-dim);font-size:13px;border-top:1px solid var(--border)">
|
||||
<p>🤖 生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南</p>
|
||||
<p>版本: <strong style="color:var(--accent)">v1.0.0</strong> · 最后更新: <strong style="color:var(--accent)">2026-06-24</strong></p>
|
||||
<p>版本: <strong style="color:var(--accent)">v1.0.0</strong> · 最后更新: <strong style="color:var(--accent)">2026-07-15</strong></p>
|
||||
<p style="margin-top:8px">作者: <strong style="color:var(--accent2)">AI Agent Engineering Team</strong> · 许可协议: <strong style="color:var(--green)">CC BY-SA 4.0</strong></p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
* Provider Adapter 导出
|
||||
*
|
||||
* 三种 Provider 各自独立继承 BaseAdapter,无耦合关系:
|
||||
* 四种 Provider 各自独立继承 BaseAdapter,无耦合关系:
|
||||
* - DeepSeekAdapter — OpenAI 兼容 + DeepSeek 特有参数
|
||||
* - AgnesAdapter — OpenAI 兼容 + Agnes 特有参数
|
||||
* - MimoAdapter — OpenAI 兼容 + MiMo 特有参数
|
||||
* - OllamaAdapter — Ollama 原生 API
|
||||
*
|
||||
* 共享工具(仅供 OpenAI 兼容 Adapter 使用):
|
||||
@@ -14,4 +15,5 @@
|
||||
export { BaseAdapter } from './base-adapter';
|
||||
export { DeepSeekAdapter } from './deepseek.adapter';
|
||||
export { AgnesAdapter } from './agnes-ai.adapter';
|
||||
export { MimoAdapter } from './mimo.adapter';
|
||||
export { OllamaAdapter } from './ollama.adapter';
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* MiMo (Xiaomi) Provider Adapter
|
||||
*
|
||||
* 基于 OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、流式输出。
|
||||
* 模型: mimo-v2.5-pro(131072 max_tokens)/ mimo-v2.5(32768 max_tokens)
|
||||
*
|
||||
* 独立继承 BaseAdapter,通过 shared/openai-format 和 shared/sse-stream 复用
|
||||
* OpenAI 兼容格式构建和 SSE 流式解析逻辑。不与其他 Provider Adapter 耦合。
|
||||
*
|
||||
* 与 DeepSeek 适配器的关键差异:
|
||||
* - 使用 max_completion_tokens(非 max_tokens)
|
||||
* - thinking 参数结构与 DeepSeek 一致(thinking.type: "enabled"/"disabled")
|
||||
* - 不提供 /models 端点(listModels 回退到本地元数据)
|
||||
* - 不提供 /user/balance 端点
|
||||
* - tool_choice 仅支持 "auto"
|
||||
*
|
||||
* @see apis/mimo-api-docs-20260715.html
|
||||
*/
|
||||
|
||||
import { BaseAdapter } from './base-adapter';
|
||||
import type { MetonaRequest, MetonaResponse, MetonaStreamEvent } from '../types';
|
||||
import { MetonaFinishReason } from '../types';
|
||||
import type { MetonaModelInfo } from '../types/metona-adapter';
|
||||
import { buildOpenAICompatibleMessages, buildOpenAICompatibleTools } from './shared/openai-format';
|
||||
import { parseSSEStream, parseOpenAICompatibleResponse } from './shared/sse-stream';
|
||||
|
||||
export class MimoAdapter extends BaseAdapter {
|
||||
override readonly providerId: string = 'mimo';
|
||||
readonly supportedModels = ['mimo-v2.5-pro', 'mimo-v2.5'];
|
||||
readonly supportsToolCalling = true;
|
||||
readonly supportsThinking = true;
|
||||
|
||||
// MiMo 模型元信息
|
||||
// mimo-v2.5-pro: 131072 max_completion_tokens;mimo-v2.5: 32768
|
||||
// 官方未公布上下文窗口大小,保守设为 131072(与 pro 的 max_output 一致)
|
||||
private static readonly MODEL_INFO: Record<string, MetonaModelInfo> = {
|
||||
'mimo-v2.5-pro': {
|
||||
id: 'mimo-v2.5-pro',
|
||||
name: 'MiMo V2.5 Pro',
|
||||
contextWindow: 131_072,
|
||||
maxOutputTokens: 131_072,
|
||||
supportsToolCalling: true,
|
||||
supportsThinking: true,
|
||||
description: '小米 MiMo 旗舰模型,支持深度思考与工具调用',
|
||||
},
|
||||
'mimo-v2.5': {
|
||||
id: 'mimo-v2.5',
|
||||
name: 'MiMo V2.5',
|
||||
contextWindow: 131_072,
|
||||
maxOutputTokens: 32_768,
|
||||
supportsToolCalling: true,
|
||||
supportsThinking: true,
|
||||
description: '小米 MiMo 标准模型,低延迟推理',
|
||||
},
|
||||
};
|
||||
|
||||
// ===== POST /chat/completions (非流式) =====
|
||||
|
||||
async send(request: MetonaRequest): Promise<MetonaResponse> {
|
||||
const body = this.toNativeRequest(request, false);
|
||||
|
||||
const response = await fetch(`${this.config.baseURL}/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${this.config.apiKey}`,
|
||||
...this.config.headers,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: this.getFetchSignal(this.config.timeoutMs ?? 120_000),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text().catch(() => '');
|
||||
throw new Error(`MiMo API error: ${response.status} ${response.statusText} - ${errorBody}`);
|
||||
}
|
||||
|
||||
const data = await response.json() as Record<string, unknown>;
|
||||
const parsed = parseOpenAICompatibleResponse(data, request.meta.requestId, this.providerId, this.config.defaultModel);
|
||||
|
||||
return {
|
||||
meta: {
|
||||
requestId: request.meta.requestId,
|
||||
provider: this.providerId,
|
||||
model: (data.model as string) ?? this.config.defaultModel,
|
||||
latencyMs: 0,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
content: parsed.content,
|
||||
reasoningContent: parsed.reasoningContent,
|
||||
toolCalls: parsed.toolCalls,
|
||||
usage: parsed.usage,
|
||||
finishReason: parsed.finishReason as MetonaFinishReason,
|
||||
};
|
||||
}
|
||||
|
||||
// ===== POST /chat/completions (流式) =====
|
||||
|
||||
async *sendStream(request: MetonaRequest): AsyncIterable<MetonaStreamEvent> {
|
||||
const body = this.toNativeRequest(request, true);
|
||||
|
||||
const response = await fetch(`${this.config.baseURL}/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${this.config.apiKey}`,
|
||||
...this.config.headers,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: this.getFetchSignal(this.config.timeoutMs ?? 300_000),
|
||||
});
|
||||
|
||||
if (!response.ok || !response.body) {
|
||||
throw new Error(`MiMo stream error: ${response.status}`);
|
||||
}
|
||||
|
||||
yield* parseSSEStream(
|
||||
response.body,
|
||||
request.meta.requestId,
|
||||
request.meta.sessionId,
|
||||
request.meta.iteration,
|
||||
);
|
||||
}
|
||||
|
||||
// ===== 模型列表 =====
|
||||
|
||||
/**
|
||||
* MiMo 官方未提供 /models 端点,直接返回本地元数据。
|
||||
*/
|
||||
override async listModels(): Promise<MetonaModelInfo[]> {
|
||||
return this.supportedModels.map((id) => MimoAdapter.MODEL_INFO[id] ?? { id });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上下文窗口大小
|
||||
*
|
||||
* v0.3.1: 优先使用配置注入的 contextWindow,回退到 MODEL_INFO 默认值。
|
||||
* MiMo OpenAI 兼容 API 不支持 context_window 参数,此值仅用于
|
||||
* Engine 压缩判断和前端 UI 显示。
|
||||
*/
|
||||
override getContextWindow(): number {
|
||||
if (typeof this.config.contextWindow === 'number' && this.config.contextWindow > 0) {
|
||||
return this.config.contextWindow;
|
||||
}
|
||||
const modelInfo = MimoAdapter.MODEL_INFO[this.config.defaultModel];
|
||||
return modelInfo?.contextWindow ?? 131_072;
|
||||
}
|
||||
|
||||
// ========== 私有方法 ==========
|
||||
|
||||
/**
|
||||
* 构建 MiMo 原生请求体
|
||||
*
|
||||
* MiMo 特有参数:
|
||||
* - thinking: { type: "enabled" / "disabled" } — 与 DeepSeek 一致
|
||||
* - max_completion_tokens — 非 max_tokens(MiMo 使用新字段名)
|
||||
* - stream_options: { include_usage: true } — 流式返回 usage
|
||||
* - tool_choice: "auto" — MiMo 仅支持 auto
|
||||
*
|
||||
* 思考模式下 temperature/top_p 会被 API 强制覆盖,因此不传这两个参数。
|
||||
*/
|
||||
private toNativeRequest(request: MetonaRequest, stream: boolean): Record<string, unknown> {
|
||||
const messages = buildOpenAICompatibleMessages(request);
|
||||
const tools = buildOpenAICompatibleTools(request.tools);
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
model: this.config.defaultModel,
|
||||
messages,
|
||||
// MiMo 使用 max_completion_tokens(非 max_tokens)
|
||||
max_completion_tokens: request.params.maxTokens,
|
||||
stream,
|
||||
};
|
||||
|
||||
if (stream) {
|
||||
body.stream_options = { include_usage: true };
|
||||
}
|
||||
|
||||
if (tools) {
|
||||
body.tools = tools;
|
||||
// MiMo 仅支持 tool_choice: "auto"
|
||||
body.tool_choice = 'auto';
|
||||
}
|
||||
|
||||
// Thinking 模式(与 DeepSeek 参数结构一致)
|
||||
// MiMo API 默认 thinking.type = "enabled",必须显式发送 disabled 才能关闭
|
||||
if (request.params.thinkingEnabled === false) {
|
||||
// 显式禁用思考:传 disabled + temperature/top_p(非思考模式下这两个参数有效)
|
||||
body.thinking = { type: 'disabled' };
|
||||
body.temperature = request.params.temperature;
|
||||
body.top_p = request.params.topP;
|
||||
} else {
|
||||
// 启用思考(包括 undefined,因为 MiMo 默认 enabled)
|
||||
// 思考模式下 temperature/top_p 被 API 强制覆盖为 1.0/0.95,不传
|
||||
body.thinking = { type: 'enabled' };
|
||||
}
|
||||
|
||||
// 停止序列
|
||||
if (request.params.stopSequences?.length) {
|
||||
body.stop = request.params.stopSequences;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
* OpenAI 兼容 API 格式构建工具
|
||||
*
|
||||
* 将 MetonaRequest 转换为 OpenAI /chat/completions 兼容的原生请求格式。
|
||||
* DeepSeek 和 Agnes AI 共享此工具,各自 Adapter 只需处理 Provider 特有的差异参数。
|
||||
* DeepSeek、Agnes AI 和 MiMo 共享此工具,各自 Adapter 只需处理 Provider 特有的差异参数。
|
||||
*
|
||||
* @see electron/harness/types/metona-request.ts — MetonaRequest 定义
|
||||
* @see apis/deepseek-api-docs-20260518.html
|
||||
* @see apis/agnes-ai-api-docs-20260625.html
|
||||
* @see apis/mimo-api-docs-20260715.html
|
||||
*/
|
||||
|
||||
import type { MetonaRequest, MetonaToolDef } from '../../types';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* SSE 流式解析工具
|
||||
*
|
||||
* 解析 OpenAI 兼容的 Server-Sent Events (SSE) 流式响应,
|
||||
* 产出 MetonaStreamEvent。DeepSeek 和 Agnes AI 共享此工具。
|
||||
* 产出 MetonaStreamEvent。DeepSeek、Agnes AI 和 MiMo 共享此工具。
|
||||
*
|
||||
* SSE 格式:data: {json}\n\n
|
||||
* 结束标记:data: [DONE]
|
||||
@@ -174,7 +174,10 @@ export async function* parseSSEStream(
|
||||
outputTokens: chunk.usage.completion_tokens ?? 0,
|
||||
totalTokens: chunk.usage.total_tokens ?? 0,
|
||||
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens,
|
||||
cacheHitTokens: chunk.usage.prompt_cache_hit_tokens,
|
||||
// DeepSeek: prompt_cache_hit_tokens / prompt_cache_miss_tokens
|
||||
// MiMo: prompt_tokens_details.cached_tokens
|
||||
cacheHitTokens: chunk.usage.prompt_cache_hit_tokens
|
||||
?? chunk.usage.prompt_tokens_details?.cached_tokens,
|
||||
cacheMissTokens: chunk.usage.prompt_cache_miss_tokens,
|
||||
};
|
||||
|
||||
@@ -252,7 +255,9 @@ export function parseOpenAICompatibleResponse(
|
||||
outputTokens: (usage?.completion_tokens as number) ?? 0,
|
||||
totalTokens: (usage?.total_tokens as number) ?? 0,
|
||||
reasoningTokens: (usage?.completion_tokens_details as Record<string, unknown>)?.reasoning_tokens as number | undefined,
|
||||
cacheHitTokens: usage?.prompt_cache_hit_tokens as number | undefined,
|
||||
// DeepSeek: prompt_cache_hit_tokens / MiMo: prompt_tokens_details.cached_tokens
|
||||
cacheHitTokens: (usage?.prompt_cache_hit_tokens as number | undefined)
|
||||
?? (usage?.prompt_tokens_details as Record<string, unknown> | undefined)?.cached_tokens as number | undefined,
|
||||
cacheMissTokens: usage?.prompt_cache_miss_tokens as number | undefined,
|
||||
},
|
||||
};
|
||||
@@ -264,6 +269,8 @@ function mapOpenAIFinishReason(reason: string): string {
|
||||
case 'length': return 'length';
|
||||
case 'tool_calls': return 'tool_calls';
|
||||
case 'content_filter': return 'content_filter';
|
||||
// MiMo 特有:检测到复读截断
|
||||
case 'repetition_truncation': return 'stop';
|
||||
default: return 'stop';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export interface MetonaModelInfo {
|
||||
* Provider 适配器配置
|
||||
*/
|
||||
export interface AdapterConfig {
|
||||
/** Provider 标识(如 'deepseek'、'agnes'、'ollama') */
|
||||
/** Provider 标识(如 'deepseek'、'agnes'、'mimo'、'ollama') */
|
||||
provider: string;
|
||||
/** API 基础 URL */
|
||||
baseURL: string;
|
||||
|
||||
@@ -667,9 +667,9 @@ export function registerAllIPCHandlers(
|
||||
});
|
||||
|
||||
// LLM 相关配置变更时热重载 Adapter
|
||||
// v0.3.1: 加入 deepseek.contextWindow / agnes.contextWindow,使上下文窗口配置变化也触发热重载
|
||||
// v0.3.1: 加入 deepseek.contextWindow / agnes.contextWindow / mimo.contextWindow,使上下文窗口配置变化也触发热重载
|
||||
if (['llm.provider', 'llm.model', 'llm.apiKey', 'llm.baseURL', 'ollama.numCtx',
|
||||
'deepseek.contextWindow', 'agnes.contextWindow'].includes(key)) {
|
||||
'deepseek.contextWindow', 'agnes.contextWindow', 'mimo.contextWindow'].includes(key)) {
|
||||
// C-1 修复: reloadAdapter 返回 false 时表示加载失败,需要通知前端
|
||||
const reloadSuccess = reloadAdapter();
|
||||
if (!reloadSuccess) {
|
||||
@@ -700,8 +700,8 @@ export function registerAllIPCHandlers(
|
||||
agentLoop.updateConfig({ contextLength: (value as number) || undefined });
|
||||
orchestrator.updateDefaultConfig({ contextLength: (value as number) || undefined });
|
||||
log.info(`[CONFIG] Agent contextLength updated to ${value}`);
|
||||
} else if (key === 'deepseek.contextWindow' || key === 'agnes.contextWindow') {
|
||||
// v0.3.1: DeepSeek/Agnes contextWindow 变更,同步到 Engine 和 Orchestrator
|
||||
} else if (key === 'deepseek.contextWindow' || key === 'agnes.contextWindow' || key === 'mimo.contextWindow') {
|
||||
// v0.3.1: DeepSeek/Agnes/MiMo contextWindow 变更,同步到 Engine 和 Orchestrator
|
||||
// reloadAdapter 已重建 adapter,此处确保 Engine contextWindow 同步(兜底)
|
||||
const ctxWindow = (value as number) || undefined;
|
||||
agentLoop.updateConfig({ contextWindow: ctxWindow });
|
||||
|
||||
@@ -36,6 +36,7 @@ import { AgentLoopEngine } from './harness/agent-loop';
|
||||
import { ToolRegistry } from './harness/tools/registry';
|
||||
import { DeepSeekAdapter } from './harness/adapters/deepseek.adapter';
|
||||
import { AgnesAdapter } from './harness/adapters/agnes-ai.adapter';
|
||||
import { MimoAdapter } from './harness/adapters/mimo.adapter';
|
||||
import { OllamaAdapter } from './harness/adapters/ollama.adapter';
|
||||
import {
|
||||
ReadFileTool, WriteFileTool, ListDirectoryTool, SearchFilesTool,
|
||||
@@ -161,6 +162,7 @@ async function initialize(): Promise<void> {
|
||||
const adapterConfig = { provider, baseURL, apiKey, defaultModel: model, contextWindow };
|
||||
switch (provider) {
|
||||
case 'agnes': return new AgnesAdapter(adapterConfig);
|
||||
case 'mimo': return new MimoAdapter(adapterConfig);
|
||||
case 'ollama': return new OllamaAdapter(adapterConfig);
|
||||
default: return new DeepSeekAdapter(adapterConfig);
|
||||
}
|
||||
|
||||
@@ -378,6 +378,8 @@ export class DatabaseService {
|
||||
// v0.3.1: DeepSeek/Agnes 改为可配置,不再写死 1M
|
||||
{ key: 'deepseek.contextWindow', value: '1000000', category: 'deepseek' },
|
||||
{ key: 'agnes.contextWindow', value: '1000000', category: 'agnes' },
|
||||
// v0.3.4: MiMo 上下文窗口(官方未公布,保守设为 131072)
|
||||
{ key: 'mimo.contextWindow', value: '131072', category: 'mimo' },
|
||||
|
||||
// Onboarding
|
||||
{ key: 'onboarding.completed', value: 'false', category: 'general' },
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "metona-ai-desktop",
|
||||
"version": "0.3.3",
|
||||
"version": "0.3.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "metona-ai-desktop",
|
||||
"version": "0.3.3",
|
||||
"version": "0.3.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "metona-ai-desktop",
|
||||
"version": "0.3.3",
|
||||
"version": "0.3.4",
|
||||
"description": "MetonaAI Desktop — 生产级通用 AI Agent 智能体桌面应用",
|
||||
"main": "dist-electron/main/main.js",
|
||||
"author": "Metona Team",
|
||||
|
||||
@@ -30,6 +30,7 @@ import { useAgentStore } from '@renderer/stores/agent-store';
|
||||
const PROVIDER_LABELS: Record<string, string> = {
|
||||
deepseek: 'DeepSeek',
|
||||
agnes: 'Agnes',
|
||||
mimo: 'MiMo',
|
||||
ollama: 'Ollama',
|
||||
};
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ export function OnboardingWizard(): React.JSX.Element | null {
|
||||
<Select value={provider} label="Provider" onChange={(e) => setProvider(e.target.value)}>
|
||||
<MenuItem value="deepseek">DeepSeek</MenuItem>
|
||||
<MenuItem value="agnes">Agnes AI</MenuItem>
|
||||
<MenuItem value="mimo">MiMo (小米)</MenuItem>
|
||||
<MenuItem value="ollama">Ollama (本地)</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
@@ -86,7 +86,7 @@ function useConfig<T>(key: string, defaultValue: T): [T, (v: T) => void] {
|
||||
return [value, set];
|
||||
}
|
||||
|
||||
const PROVIDER_URLS: Record<string, string> = { deepseek: 'https://api.deepseek.com', agnes: 'https://apihub.agnes-ai.com/v1', ollama: 'http://localhost:11434' };
|
||||
const PROVIDER_URLS: Record<string, string> = { deepseek: 'https://api.deepseek.com', agnes: 'https://apihub.agnes-ai.com/v1', mimo: 'https://api.xiaomimimo.com/v1', ollama: 'http://localhost:11434' };
|
||||
|
||||
function WorkspaceSettings() {
|
||||
const [workspacePath, setWorkspacePath] = useConfig('workspace.path', '');
|
||||
@@ -290,9 +290,10 @@ function LLMSettings() {
|
||||
const [apiKey, setApiKey] = useConfig('llm.apiKey', '');
|
||||
const [baseURL, setBaseURL] = useConfig('llm.baseURL', '');
|
||||
const [numCtx, setNumCtx] = useConfig('ollama.numCtx', null as number | null);
|
||||
// v0.3.1: DeepSeek/Agnes contextWindow 可配置(不再写死 1M)
|
||||
// v0.3.1: DeepSeek/Agnes/MiMo contextWindow 可配置(不再写死)
|
||||
const [dsCtxWindow, setDsCtxWindow] = useConfig('deepseek.contextWindow', 1000000);
|
||||
const [agnesCtxWindow, setAgnesCtxWindow] = useConfig('agnes.contextWindow', 1000000);
|
||||
const [mimoCtxWindow, setMimoCtxWindow] = useConfig('mimo.contextWindow', 131072);
|
||||
const [showKey, setShowKey] = useState(false);
|
||||
|
||||
// 同步 Provider/Model 到 Agent Store(含 contextWindow)
|
||||
@@ -308,8 +309,10 @@ function LLMSettings() {
|
||||
if (dsCtxWindow != null && dsCtxWindow > 0) useAgentStore.setState({ contextWindow: dsCtxWindow });
|
||||
} else if (provider === 'agnes') {
|
||||
if (agnesCtxWindow != null && agnesCtxWindow > 0) useAgentStore.setState({ contextWindow: agnesCtxWindow });
|
||||
} else if (provider === 'mimo') {
|
||||
if (mimoCtxWindow != null && mimoCtxWindow > 0) useAgentStore.setState({ contextWindow: mimoCtxWindow });
|
||||
}
|
||||
}, [provider, numCtx, dsCtxWindow, agnesCtxWindow]);
|
||||
}, [provider, numCtx, dsCtxWindow, agnesCtxWindow, mimoCtxWindow]);
|
||||
|
||||
// 切换 Provider 时自动填充默认 URL + 清空 apiKey(不同 Provider 的 key 不通用)
|
||||
const handleProviderChange = (newProvider: string) => {
|
||||
@@ -335,6 +338,7 @@ function LLMSettings() {
|
||||
<Select value={provider} label="Provider" onChange={(e) => handleProviderChange(e.target.value)}>
|
||||
<MenuItem value="deepseek">DeepSeek</MenuItem>
|
||||
<MenuItem value="agnes">Agnes AI</MenuItem>
|
||||
<MenuItem value="mimo">MiMo (小米)</MenuItem>
|
||||
<MenuItem value="ollama">Ollama (本地)</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
@@ -391,6 +395,18 @@ function LLMSettings() {
|
||||
helperText="用于上下文压缩判断,不传给 API"
|
||||
/>
|
||||
)}
|
||||
{provider === 'mimo' && (
|
||||
<TextField
|
||||
size="small"
|
||||
label="上下文窗口 (contextWindow)"
|
||||
type="number"
|
||||
value={mimoCtxWindow ?? 131072}
|
||||
onChange={(e) => setMimoCtxWindow(Number(e.target.value) || 131072)}
|
||||
placeholder="如 32768、65536、131072"
|
||||
slotProps={{ htmlInput: { min: 4096, step: 4096 } }}
|
||||
helperText="官方未公布具体值,默认 131072,用于压缩判断"
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,5 +90,6 @@ export const SHORTCUTS = {
|
||||
export const PROVIDER_LABELS: Record<string, string> = {
|
||||
deepseek: 'DeepSeek',
|
||||
agnes: 'Agnes AI',
|
||||
mimo: 'MiMo (小米)',
|
||||
ollama: 'Ollama',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user