Files
DevFlow/docs/09-问题排查/aichat-apikey-401排查-2026-06-15.md
绝尘 04032a2a8d 重构: 文档汇总+进度看板+孤儿任务清理脚本+gitignore 噪音排除
- docs/02 架构设计: 新增 aichat审查/异步审批构想/流式渲染调研/generating状态机/密钥迁移健壮性/工作流脚本执行边界/条件表达式引擎/F-07 trait下沉/Agent架构说明/任务推进构想/功能创意池;更新功能决策记录+归档/对抗论证/文档记录规范/经验记录
- docs/03 模块文档: 新增 AI对话引擎/DAG引擎详解;更新 df-knowledge/df-nodes/df-storage/df-workflow/df-ai
- docs/05 代码审查: 新增 全栈审查/全局review/架构审查/近期改动审查/工作区多角度走查/自研memo流式渲染审查
- docs/09 问题排查: 新增 aichat-apikey-401
- docs/INDEX+README 索引同步;docs/todo 待办看板(2026-06-15 汇总)
- PROGRESS.md Sprint 22-25;URGENT.md 加急清单快照(5 项 P0 已全修)
- scripts/cleanup_orphan_tasks.{py,sh} 孤儿任务清理工具
- .gitignore 补 *.broken.bak + tmp/ 噪音排除
2026-06-15 05:14:21 +08:00

126 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# aichat API Key 鉴权失败排查
> 2026-06-15 排查 | 看板索引:`docs/todo.md`「🔴 aichat API Key 401 排查」区块
## 现象
- aichat 对话失败,提示「调用失败: API Key 无效或无权限」
- 重新设置 apikey 后仍无效
## 错误来源
- `stream_recv.rs:107-113``provider.stream(request)` 直接返回 `Err` 分支
- 错误文本:`format!("AI 调用失败: {}", e)``e` 为服务端返回的 401/403
- 即:请求发出去了,被服务端以鉴权/权限为由拒绝。**非流式中断、非网络断连。**
## 排查结论:代码链路全对(排除代码 bug
### 保存链路(正确)
- `commands.rs ai_save_provider:329-333``api_key` 非空 → `set_provider_secret` 写 OS keyring
- 写失败会返回「密钥保存到系统钥匙串失败」(用户未报此错 → **写入成功**
- `:334`DB `api_key` 列恒空FR-S1 设计,真实密钥唯一源 = OS keyring
### 读取链路(正确)
所有 `build_provider` 调用点均经 `resolve_provider_secret`keyring 优先fallback DB
| 调用点 | 行号 | 状态 |
|--------|------|------|
| agentic.rs对话主循环 | :50 | ✓ |
| project.rs技术栈扫描 | :378 | ✓ |
| knowledge_inject.rs知识提炼/嵌入) | :33, :323 | ✓ |
| title.rs标题生成 | :63 | ✓ |
- 例外:`df-nodes/ai_node.rs:118``p.api_key`(工作流 AI 节点独立配置,不经 keyring与本问题无关
### 鉴权头(正确)
- `openai_compat``Authorization: Bearer {api_key}`
- `anthropic_compat``x-api-key: {api_key}` + `anthropic-version`
### URL 智能拼接(正确,三规则容错)
- `openai_compat.chat_url`openai_compat.rs:253-262
- 已含 `/chat/completions` → 直接用
-`/v<数字>` 结尾(如 `/v1` `/v4`GLM 的 `/api/paas/v4`)→ 补 `/chat/completions`
- 仅域名(`api.openai.com` / `api.deepseek.com`)→ 补 `/v1/chat/completions`
- `anthropic_compat.messages_url`anthropic_compat.rs:255-264
- 已含 `/v1/messages` → 直接用
-`/v1` 结尾 → 补 `/messages`
- 否则(`.../api/anthropic``api.anthropic.com`)→ 补 `/v1/messages`
**链路已全部验证无误。401 来自服务端,根因不在 devflow 代码。**
## 根因方向(服务端 401按概率排序
### 1. API Key 本身无效(最常见)
- 过期 / 欠费 / 额度用尽
- 粘贴时带空格、引号、回车或多余字符
- 中转 key 与官方 key 混淆(不同渠道 key 不通用)
### 2. provider_type 与端点不匹配
- `openai_compat``Bearer``anthropic_compat``x-api-key`,两者鉴权头互斥
- 若实际是 OpenAI 兼容端点却选 `anthropic_compat`(或反之)→ 鉴权头不被识别 → 401
- 典型:
- GLM 官方 chat 端点(`open.bigmodel.cn/api/paas`)→ `openai_compat`
- GLM 的 Anthropic 兼容端点(`open.bigmodel.cn/api/anthropic`)→ `anthropic_compat`
- Claude 官方(`api.anthropic.com`)→ `anthropic_compat`
- 各类中转/聚合站one-api/new-api→ 一般 `openai_compat`
### 3. base_url 填错
- 多/少 `/v1` 段(智能拼接已容错多数情况,但中转站路径各异仍可能错)
- 协议错(`http` vs `https`
- 域名拼写错误
### 4. model 名错/无权限
- 部分 API 网关对无效 model 返回 401 而非 404
- model 名大小写、版本号、前缀错(如 `glm-4` vs `glm-4-flash``claude-3-5-sonnet` vs `claude-3-5-sonnet-20241022`
## 验证步骤(直连测试,区分 key / 配置)
在终端用 curl 直连,绕开 devflow精准定位是 key 还是配置问题:
### A. provider_type = openai_compatBearer 鉴权)
```bash
curl -s "{base_url}/v1/chat/completions" \
-H "Authorization: Bearer {KEY}" \
-H "Content-Type: application/json" \
-d '{"model":"{MODEL}","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'
```
### B. provider_type = anthropic_compatx-api-key 鉴权)
```bash
curl -s "{base_url}/v1/messages" \
-H "x-api-key: {KEY}" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model":"{MODEL}","max_tokens":5,"messages":[{"role":"user","content":"hi"}]}'
```
> `{base_url}` `{KEY}` `{MODEL}` 替换为设置页实际填的值base_url 按拼接规则:不带末尾的 `/v1/...`,但带了也兼容)。
### 结果判断
| 返回 | 含义 |
|------|------|
| 正常 completion JSON | key+url+type+model 全对 → 问题在 devflow 内部(概率极低,链路已验证;此时查 Rust 日志看实际请求) |
| `401` / `authentication_error` | key 无效,**或** provider_type 选错(鉴权头不匹配) |
| `404` | base_url 拼接错,端点不存在 |
| `400` model 相关 | model 名错/无权限 |
| 连接失败/超时 | base_url 域名或网络问题 |
## TODO
- [ ] S-260615-01 用户执行直连测试A 或 B确认是 key、provider_type、base_url、model 哪一项的问题
- [ ] 用户:核对 provider_type 与实际端点匹配(见「根因方向 2」的典型对照
- [ ] 用户:核对 model 名拼写(对照 API 提供商文档)
- [ ] 若直连测试通过、devflow 内仍 401开 Rust tracing 日志,查实际发出的 url + header 是否与直连一致(排除 body 字段触发的鉴权问题)
- [ ] **B-260615-01可选增强** `stream_recv.rs:107` Err 分支增加诊断信息:把 provider_type + 实际请求 url + HTTP 状态码记入日志/错误返回,便于 401 快速定位(当前错误只透传服务端文本,看不出打了哪个 url