# Kimi-Agent 与 RAG 问题排查及修复总结

> 排查时间：2026-04-24
> 涉及服务：`baizor-app`、`kimi-agent`

---

## 一、问题现象

1. `docker exec baizor-app curl -s http://kimi-agent:8088/health` 返回 **502 Bad Gateway**
2. 前端调用 `POST /api/v1/documents/kimi` 返回 **502**
3. 修复 502 后，前端调用返回 **400 Bad Request**
4. RAG 检索知识库（等级语法例句详情）时，明明有原句却查不出来，同步向量后检索结果为空 `[[]]`
5. 前端"查看 Chunks"功能永远显示空列表

---

## 二、排查过程与根因分析

### 2.1 第一阶段：502 排查

**测试命令：**
```bash
docker exec baizor-app curl -v http://kimi-agent:8088/health
```

**发现：**
- `baizor-app` 容器内设置了 `http_proxy=http://192.168.99.195:7890`
- `no_proxy=localhost,127.0.0.1` **没有排除 `kimi-agent`**
- 请求被转发到外部代理服务器，代理无法访问 Docker 内网域名，返回 502
- 绕过代理后直连测试成功：`{"status":"ok"}`

**根因：** 代理配置错误，`kimi-agent` 内网域名被强制走外部代理。

---

### 2.2 第二阶段：400 排查

修复代理后，容器内 `curl` 已能连通 `kimi-agent`，但前端请求仍返回 400。

**查看 `baizor-app` 代码 `/app/backend/open_webui/routers/documents.py`：**
- `kimi_in_docs` 使用 `aiohttp` 向 `kimi-agent` 发送 `POST /run` 请求
- 检查发现 `baizor-app` 环境变量中**没有 `KIMI_AGENT_URL`**
- 代码回退到 `.env` 默认值：`KIMI_AGENT_URL=http://localhost:8088`
- `baizor-app` 自己并不监听 8088，连接被拒绝 → `aiohttp.ClientError` → 捕获后返回 502

**查看 `kimi-agent` 代码 `/app/app.py`：**
- `ALLOWED_ROOT = /app/backend/data`（由 `KIMI_SHARED_ROOT` 环境变量控制）
- `baizor-app` 代码中 `AGENT_DATA_ROOT = /data/shared`（默认）
- 发给 `kimi-agent` 的 `workdir` 是 `/data/shared/...`，不在白名单内 → 返回 400

**根因：**
1. `baizor-app` 缺少 `KIMI_AGENT_URL` 环境变量，回退到 `.env` 默认值 `http://localhost:8088`，导致连错地址
2. `baizor-app` 缺少 `KIMI_AGENT_SHARED_ROOT`，使用默认 `/data/shared`，导致 `workdir` 路径不匹配

---

### 2.3 第三阶段：RAG 检索不到数据排查

**直接查看向量数据库：**
```bash
# ChromaDB 中 note-3452292a-2249-4b6c-a288-b953ad153d92 collection
Document count: 180
```

**找到目标句子所在 chunk（doc[175]）：**
```
七—九145 | 句群:带关联词语 | 除了记忆能力差之外，我还有其他的缺点...
```

**Embedding 相似度实测：**

| Chunk 内容 | 与查询句 Cosine 相似度 |
|---|---|
| 当前大 chunk（709字符，含6条无关语法记录） | **0.3704** |
| 仅保留目标句子的 focused chunk | **0.8563** |

**根因：**
- `CHUNK_SIZE = 1000`（默认值）
- `ExcelChunker.batch_size = CHUNK_SIZE // 200 = 5`（每 5 行为一个 chunk）
- 每个 chunk 约 1000 字符，包含多条语法记录
- 目标句子被大量无关内容稀释，语义相似度从 0.85 暴跌到 0.37
- `RAG_TOP_K = 3`，目标 chunk barely 挤进前 3，很容易被裁剪掉

---

### 2.4 第四阶段：`get_note_rag_chunks` Bug 排查

**日志报错：**
```
WARNING | open_webui.routers.notes:get_note_rag_chunks:592 -
get_note_rag_chunks: 'GetResult' object has no attribute 'get'
```

**查看代码：**
```python
result = VECTOR_DB_CLIENT.get(collection_name=collection_name)
docs = result.get("documents", [[]])  # ← 这里报错
```

**根因：** `VECTOR_DB_CLIENT.get()` 返回 `GetResult` dataclass，不是 Python `dict`，没有 `.get()` 方法。导致每次请求都抛异常，前端永远看不到 chunks。

---

## 三、修改内容汇总

### 3.1 `/lucky/docker-compose.yml`（`baizor-app` 环境变量）

```yaml
# 修改 1（由我修改）：修复代理导致的 502
- NO_PROXY=localhost,127.0.0.1,kimi-agent
- no_proxy=localhost,127.0.0.1,kimi-agent

# 修改 2（排查时已存在于配置中，可能由用户之前添加）：修复连错地址导致的 502
- KIMI_AGENT_URL=http://kimi-agent:8088

# 修改 3（排查时已存在于配置中，可能由用户之前添加）：修复 token 缺失
- KIMI_AGENT_TOKEN=lucky-token-mq123456

# 修改 4（由我修改）：修复 workdir 路径不匹配导致的 400
- KIMI_AGENT_SHARED_ROOT=/app/backend/data
```

**需要重启 `baizor-app` 生效：**
```bash
cd /lucky && docker compose up -d baizor-app
```

---

### 3.2 `/home/lucky/.docker/config.json`（Docker 客户端全局代理）

```json
"proxies": {
    "default": {
        "httpProxy": "http://192.168.99.195:7890",
        "httpsProxy": "http://192.168.99.195:7890",
        "noProxy": "localhost,127.0.0.1,kimi-agent"
    }
}
```

**作用：** 以后通过 Docker 客户端新建的容器，访问 `kimi-agent` 时会自动绕过代理。

---

### 3.3 `/app/backend/open_webui/routers/notes.py`（容器内代码，第 582 行）

**修改前：**
```python
docs = result.get("documents", [[]])
```

**修改后：**
```python
docs = result.documents if result.documents else [[]]
```

**作用：** 修复 `GetResult` dataclass 没有 `.get()` 方法的 Bug，前端"查看 Chunks"功能恢复正常。

---

## 四、后续建议（未执行）

### 4.1 优化 RAG Chunk 策略

当前 `CHUNK_SIZE = 1000` 导致每 5 行 Excel 数据塞进一个 chunk，语义严重稀释。

**建议修改：**
```yaml
# 在 docker-compose.yml 的 baizor-app 环境变量中追加
- CHUNK_SIZE=200
- CHUNK_OVERLAP=20
- RAG_TOP_K=20
- RAG_TOP_K_RERANKER=20
```

- `CHUNK_SIZE=200` → `batch_size = 1`，每行语法记录独立成 chunk
- `RAG_TOP_K=20` → 让更多候选进入重排序，避免正确结果被裁剪

**修改后必须重新同步向量库**，前端进入知识库 → 点击"同步向量"即可。

### 4.2 其他潜在问题

- `annesc-installer` 服务也配置了 `NO_PROXY=localhost,127.0.0.1`，如果它以后需要访问内网 HTTP 服务，同样会遇到代理问题
- `baizor-app` 使用的 `aiohttp` 默认不读取系统代理环境变量（`trust_env=False`），当前代理修复依赖的是 `no_proxy` 让系统 curl/requests 绕过代理。如果 `aiohttp` 以后需要走代理，需要显式配置

---

## 五、验证命令

```bash
# 验证 kimi-agent 连通性
docker exec baizor-app curl -s http://kimi-agent:8088/health
# 期望输出：{"status":"ok"}

# 验证 baizor-app 环境变量
docker exec baizor-app env | grep -i KIMI
# 期望看到 KIMI_AGENT_URL、KIMI_AGENT_TOKEN、KIMI_AGENT_SHARED_ROOT

# 验证 vector DB 数据
docker exec baizor-app python3 -c "
import chromadb
client = chromadb.PersistentClient(path='/app/backend/data/vector_db')
coll = client.get_collection('note-3452292a-2249-4b6c-a288-b953ad153d92')
print('Documents:', coll.count())
"
```

---

## 六、补充排查（2026-04-25 00:30）

### 6.1 用户反馈

用户反馈：已将 chunk 改为按行切割、更新了 RAG、降低了阈值，但检索仍然返回 `[[]] [[]]`。

### 6.2 验证用户修改是否生效

直接检查向量数据库中的实际数据：

```bash
# ChromaDB collection: note-3452292a-2249-4b6c-a288-b953ad153d92
Document count: 180
Doc[0] len=1000: ## Sheet: Sheet1  
序号 | 名称 | 例句 | 定义 | 特征
一01 | 方位名词 | 桌子上 | ...
```

**结论：用户的"按行切割"修改没有生效到向量库。**

如果按行切割生效了，预期应该是：
- Document count: **~360+**（每行一个 chunk）
- 每个 doc 长度: **~100-150 字符**

当前仍然是 180 个文档、每个约 1000 字符，说明 chunk 策略**完全没有变化**。

### 6.3 为什么修改没有生效？

`PersistentConfig` 的优先级逻辑：
```python
if self.config_value is not None and ENABLE_PERSISTENT_CONFIG:
    self.value = self.config_value  # 数据库配置优先
else:
    self.value = env_value  # 环境变量作为默认值
```

这意味着：
1. **如果数据库中已有配置值，环境变量会被覆盖**
2. 用户在前端修改配置后，配置被保存到数据库
3. 如果用户只在前端改了"阈值"等参数，但没有改 `CHUNK_SIZE`，那 `CHUNK_SIZE` 仍然是默认值 1000
4. 即使改了 `docker-compose.yml` 的环境变量，也必须重启容器才能生效

### 6.4 检索返回 `[[]] [[]]` 的排查

直接调用 `query_doc_with_hybrid_search` 测试（使用实际环境和数据）：
```
Result docs: 3
Result distances: [0.399, 0.376, 0.370]
```

**结论：`query_doc_with_hybrid_search` 本身是工作的。**

但日志显示 3 个子查询都返回 `[[]] [[]]`。实际运行和测试的差异在于：
1. 实际运行使用了查询扩展（query expansion），长句被拆分成 3 个短子查询
2. 短子查询的向量检索**无法匹配到目标 chunk**（目标 chunk 在大查询下排第 3，在短查询下完全消失）
3. 如果子查询非常短甚至为空，BM25 和向量检索都可能返回空

**根本问题仍然是 chunk 太大：** 目标句子和大量无关内容混在一起，短查询无法精准定位。

### 6.5 额外发现：`lanhc-webui` 配置笔误

`/lucky/docker-compose.yml` 第 494 行：
```yaml
- KIMI_AGENT_TOKEN=KIMI_AGENT_TOKEN=lucky-token-mq123456
```
变量名重复了，实际 token 值变成了 `KIMI_AGENT_TOKEN=lucky-token-mq123456`，可能导致 `kimi-agent` 的 token 验证失败。

---

## 七、下一步建议

### 7.1 让 chunk 修改真正生效

**方式一（推荐）：通过环境变量**

在 `/lucky/docker-compose.yml` 的 `baizor-app` 环境变量中追加：
```yaml
- CHUNK_SIZE=200
- CHUNK_OVERLAP=20
```

然后重启容器：
```bash
cd /lucky && docker compose up -d baizor-app
```

**方式二：清空数据库中的旧配置**

如果数据库中已保存了旧的 `CHUNK_SIZE=1000`，需要清空配置数据库让环境变量生效。

### 7.2 修复 `lanhc-webui` 的 token 笔误

修改 `/lucky/docker-compose.yml` 第 494 行：
```yaml
# 修改前
- KIMI_AGENT_TOKEN=KIMI_AGENT_TOKEN=lucky-token-mq123456
# 修改后
- KIMI_AGENT_TOKEN=lucky-token-mq123456
```

### 7.3 重新同步向量库

修改生效后，在前端进入知识库 → 点击"同步向量"。

### 7.4 验证 chunk 是否生效

同步后检查向量库：
```bash
docker exec baizor-app python3 -c "
import chromadb
client = chromadb.PersistentClient(path='/app/backend/data/vector_db')
coll = client.get_collection('note-3452292a-2249-4b6c-a288-b953ad153d92')
print('Documents:', coll.count())
peek = coll.peek(limit=2)
for i, doc in enumerate(peek['documents']):
    print(f'Doc[{i}] len={len(doc)}: {doc[:100]}...')
"
```

预期输出：
- Documents: **360+**
- 每个 doc 长度: **~100-150 字符**
