# 07 · LLM 对话 本节讲怎么接 LLM、两条协议(OpenAI 兼容 / Anthropic)的差别、常见错误码、长什么样。 ## 1. 配置文件在哪里 存在 `~/.live2D/live2d.conf.json` 里,但**改完必须重启**(见 §5.1)。 ```jsonc { "llm_provider": "openai", // "openai" 或 "anthropic" "llm_model": "gpt-4o-mini", "llm_api_key": "sk-...", "llm_base_url": "https://api.openai.com" } ``` **修改入口**:桌宠 → 工具栏 ⚙ → 配置中心 → 「🤖 LLM 对话设置」区。 ## 2. 两条协议对照 | 项 | OpenAI 兼容 | Anthropic | |---|---|---| | **端点** | `POST {base_url}/v1/chat/completions` | `POST {base_url}/v1/messages` | | **鉴权 Header** | `Authorization: Bearer ` | `x-api-key: ` + `anthropic-version: 2023-06-01` | | **system 消息位置** | `messages: [{role:"system", content:...}]` | 提到顶层 `system: "..."` 字段 | | **messages[0] 限制** | 无 | 必须是 `user`(后端有兜底,强制补一条) | | **max_tokens** | 可选(默认 1024) | **必填**(默认 1024) | | **响应** | `choices[0].message.content` | `content[*].text`(按 type 过滤) | | **多模态** | `content: [{type:"text"}, {type:"image_url", image_url:{url:"data:..."}}]` | `content: [{type:"text"}, {type:"image", source:{type:"base64", media_type, data}}]` | | **请求超时** | 180 秒 | 180 秒 | | **代理** | `no_proxy()`(不走 HTTP_PROXY) | `no_proxy()`(不走 HTTP_PROXY) | > 💡 **OpenAI 兼容** = 任何实现同一协议的服务:OpenAI 官方、Azure OpenAI、OpenRouter、DeepSeek、Moonshot、智谱 GLM(兼容端点)、自部署 vLLM / Ollama(`/v1` 端点)、LM Studio 等。 ## 3. 常用 Base URL + Model 速查 | 服务 | Provider 选项 | Base URL | 常用 Model | |---|---|---|---| | OpenAI 官方 | `openai` | `https://api.openai.com` | `gpt-4o-mini`, `gpt-4o`, `o1-mini` | | Anthropic Claude | `anthropic` | `https://api.anthropic.com` | `claude-3-5-sonnet-20241022`, `claude-3-5-haiku-20241022` | | DeepSeek | `openai` | `https://api.deepseek.com/v1` | `deepseek-chat` | | Moonshot | `openai` | `https://api.moonshot.cn/v1` | `moonshot-v1-8k`, `moonshot-v1-32k` | | 智谱 GLM | `openai` | `https://open.bigmodel.cn/api/paas/v4` | `glm-4-flash`, `glm-4` | | Ollama(本地) | `openai` | `http://localhost:11434/v1` | 任何已 pull 的模型 | | LM Studio(本地) | `openai` | `http://localhost:1234/v1` | 加载的模型 | | 自部署 vLLM | `openai` | 你的 URL | 部署时定的名字 | > ⚠️ **如果你在走代理(clash-verge / sing-box 等),且 LLM 端点是内网 / Tailscale IP**,注意 `no_proxy()` 已在代码里强制加上,但**你自己的系统环境变量**如果有错可能让请求出问题。详细见 [09-常见问题FAQ.md](09-常见问题FAQ.md)。 ## 4. 错误码 LLM 返回非 2xx 时,会在气泡里显示一条 `system` 错误,格式:`[<状态码>] <友好前缀>: `。 ### 4.1 OpenAI 兼容 | 状态码 | 含义 | |---|---| | 401 | API key 无效或未授权 | | 403 | API key 权限不足 | | 404 | API 端点或模型不存在(检查 base_url 和 model 名) | | 429 | 请求频率超限或余额不足 | | 5xx | API 服务异常 | | 60s | "请求超时"(注意:实际超时是 180s,错误文案是历史遗留) | | connect | "无法连接到 API 服务" | ### 4.2 Anthropic | 状态码 | 含义 | |---|---| | 401 | API key 无效或未授权 | | 403 | API key 权限不足 | | 404 | 模型不存在 | | 429 | 请求频率超限 | | 529 | 服务过载(Overloaded) | | 5xx | 服务异常 | ## 5. 关键限制 ### 5.1 改完配置必须重启 ⚠️ LLM 客户端(`OpenAiProvider` / `AnthropicProvider`)在 `main()` 里**一次性创建**: ```rust let llm_provider: Arc = match provider_kind.as_str() { "anthropic" => Arc::new(AnthropicProvider::new(...)), _ => Arc::new(OpenAiProvider::new(...)), }; ``` 这个 `Arc` 整个进程生命周期里都是同一个对象。`get_llm_status` 读到的是**磁盘最新配置**,但实际请求的还是启动时的 provider。 **所以**: - 改了 provider / model / api_key / base_url **任何一项** → 重启软件 - 在配置中心保存时按钮会变绿显示「✅ 已保存」,但**状态点变色**和**实际能用**是**两回事** ### 5.2 流式输出不支持 ❌ 当前是**整段返回**:等 LLM 全推完才一次性显示。 - 小模型(< 3B)体验还行 - 大模型(7B+、Claude Sonnet 等)会有一段"静默"等待期 - 输入框会一直 disabled,底部出现"桌宠正在思考…" ### 5.3 max_tokens 硬编码 = 1024 对话回复超过 1024 token 会被截断。**当前版本没有 UI 让你改这个**。 ### 5.4 多模态(图片)支持 - **支持**:发截图给 LLM 看 → 见 [04-桌宠窗口使用.md §4](04-桌宠窗口使用.md) - **JPEG 预览优先**(不是 PNG 原图,节省 10× 体积) - **只支持 image_url 形式**(OpenAI)/ **image base64 形式**(Anthropic),不支持音频/视频 ### 5.5 思考块(DeepSeek / QwQ / o1) LLM 回复里含 `...` 时**自动折叠**为可点开的小标签。详细见 [05-聊天功能.md §3.2](05-聊天功能.md)。 ### 5.6 动作标签(`[MOTION: xxx]`) **当前版本不再注入**动作标签指令进 system prompt。 - 历史:2026-06-12 曾经让 LLM 在回复末尾附 `[MOTION: idle]` 等 - 当前:脑里不再加这个 prompt,LLM 不会主动回动作标签 - 情绪仍然通过**事件注入**(interact / praise 等)驱动模型动作 ### 5.7 RAG 记忆的真相 - 架构上**有** RAG(SQLite + 向量索引) - 实际 **embedder 是 `DummyEmbedder`**(基于 hash 的伪 384 维向量)— **不是真实语义嵌入** - 所以"长期记忆"功能**当前没意义**:检索结果随机性强,不实用 - 状态:架构已就位,等接入真实 embedder 才能用 > 💡 如果你接的是 OpenAI 兼容服务,**可以让你的 LLM 端点自带 embedding 能力**(如支持 `/v1/embeddings`),把 `dummy` 换成真实调用即可——但这是改源码的事,本手册不展开。 ### 5.8 base_url 末尾 `/v1` 处理 - OpenAI 兼容:自动剥末尾的 `/` 和 `/v1`,请求时统一拼 `{base}/v1/chat/completions` - Anthropic:只剥末尾 `/` - 举例:填 `https://api.deepseek.com/v1` 和 `https://api.deepseek.com` 都对 ## 6. 多模态请求超时 = 180 秒 - 普通对话:理论几秒-几十秒 - 多模态(截图)请求:图片 base64 上传 + 视觉编码 + 文本生成,**实测 30-90 秒很常见** - 如果 LLM 端点很慢,可以把图片压得更小([04-桌宠窗口使用.md §4.3](04-桌宠窗口使用.md)),但不能改超时 ## 7. 自部署网关的兼容性提示 某些自部署 OpenAI 兼容网关**严格校验 `detail` 字段**。代码**已主动不传** `detail` 字段(默认行为是 OpenAI 官方默认 `auto`),所以兼容性好。 如果你的网关还报 `invalid image detail: auto (2013)`,**前端清缓存**(关掉重开),确认版本是 **2026-06-14 之后**。 --- 下一步:[08-数据存储与备份.md](08-数据存储与备份.md)。