MonkeyCode故障排查手册:常见问题诊断与解决
引言
"系统不出问题的时候,运维的价值是隐性的;系统出问题的时候,运维的能力是显性的。"
在上一篇文章中,我们详细介绍了如何为MonkeyCode构建监控告警体系。但监控只是第一步——当告警真的触发时,你能否快速定位根因并恢复服务?
本文将作为MonkeyCode运维团队的实战故障排查手册,覆盖从安装部署到日常运行中最常见的30+个问题场景,每个问题都包含:症状描述→排查步骤→解决方案→预防措施。
一、快速诊断决策树
╔═══════════════════════════════════════════════════════════╗
║ MonkeyCode 故障快速诊断 ║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ 问题现象? ║
║ ║
│ ┌────────────────┐ │
│ │ 完全无法连接? │──是──→ 【第一节:连接问题】 │
│ └───────┬────────┘ │
│ │ 否 │
│ ┌───────▼────────┐ │
│ │ 连接但响应极慢? │──是──→ 【第二节:性能问题】 │
│ └───────┬────────┘ │
│ │ 否 │
│ ┌───────▼────────┐ │
│ │ 响应快但质量差? │──是──→ 【第三节:输出质量问题】 │
│ └───────┬────────┘ │
│ │ 否 │
│ ┌───────▼────────┐ │
│ │ IDE插件异常? │──是──→ 【第四节:插件问题】 │
│ └───────┬────────┘ │
│ │ 否 │
│ ┌───────▼────────┐ │
│ │ GPU/模型相关? │──是──→ 【第五节:GPU与模型问题】 │
│ └────────────────┘ │
║ ║
╚═══════════════════════════════════════════════════════════╝
二、连接问题(完全无法使用)
问题2.1:服务启动失败
症状:
$ monkeycode-server start
Error: Failed to bind to port 8080
Address already in use
排查步骤:
# Step 1: 检查端口占用
sudo lsof -i :8080
# 或
ss -tlnp | grep 8080
# Step 2: 如果被占用,查看是什么进程
ps aux | grep $(lsof -t -i:8080)
# Step 3: 常见原因及处理
# 情况A: 上次进程没有正常退出
kill -9 $(lsof -t -i:8080)
monkeycode-server start
# 情况B: 端口配置冲突
# 编辑 config/server.yaml
# 修改 port: 8080 → port: 8081
# 情况C: Docker端口映射冲突
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep 8080
# 修改 docker-compose.yml 中的端口映射
预防措施:
# 在 systemd service 文件中添加
[Service]
ExecStartPre=/bin/bash -c 'kill -9 $(lsof -t -i:%i 2>/dev/null) || true'
Restart=on-failure
RestartSec=5
StartLimitBurst=5
问题2.2:API返回502/504错误
症状:浏览器访问MonkeyCode Web界面显示 "502 Bad Gateway" 或 "504 Gateway Timeout"
排查步骤:
# Step 1: 检查各层状态
echo "=== Nginx/网关层 ==="
curl -s -o /dev/null -w "%{http_code}" http://localhost:80/health
# 期望: 200
echo "\n=== API服务层 ==="
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/api/v1/health
# 期望: 200
echo "\n=== 推理服务层 ==="
curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/health
# 期望: 200 (vLLM/TGI)
# Step 2: 查看网关日志
tail -100 /var/log/nginx/error.log | grep -i "upstream"
# Step 3: 检查上游超时设置
cat /etc/nginx/conf.d/monkeycode.conf
# 关键配置:
# proxy_connect_timeout 10s;
# proxy_read_timeout 300s; # AI推理可能需要较长时间!
# proxy_send_timeout 60s;
常见原因与修复:
| 原因 | 现象 | 修复 |
|---|---|---|
| 推理服务未启动 | 502 | 启动vLLM/TGI服务 |
| 推理服务启动中(加载模型) | 502持续数分钟 | 正常现象,等待模型加载完成 |
| 单次请求超时 | 504 | 增大proxy_read_timeout到300s+ |
| 上游崩溃 | 随机502/504 | 检查上游日志和OOM |
问题2.3:WebSocket连接断开
症状:IDE插件频繁断开重连,控制台报错 WebSocket closed with code 1006
排查步骤:
// 浏览器开发者工具 → Network → WS 过滤
// 检查:
// 1. 连接建立是否成功 (Status Code: 101 Switching Protocols)
// 2. 断开前的最后消息
// 3. 关闭代码含义:
// 1000: 正常关闭
// 1001: 客户端离开
// 1006: 异常关闭(网络中断/服务端崩溃)
// 1011: 服务端遇到错误
// 1013: 服务端重启
# Nginx WebSocket 配置检查
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 关键:WebSocket超时设置
proxy_read_timeout 86400s; # 24小时(流式生成可能很长)
proxy_send_timeout 86400s;
}
修复方案:
# monkeycode.yaml — WebSocket 配置优化
websocket:
heartbeat_interval: 30s # 心跳间隔
heartbeat_timeout: 90s # 超过3次心跳未响应则断开
max_message_size: "10MB" # 大代码文件传输
reconnect:
max_attempts: 10 # 最大重连次数
base_delay: "1s" # 初始延迟
max_delay: "30s" # 最大延迟
exponential_backoff: true # 指数退避
三、性能问题(响应慢)
问题3.1:首次响应极慢(冷启动)
症状:第一次请求需要等待30秒-几分钟,后续请求正常
原因分析:
┌─────────────────────────────────────────────────────────────┐
│ 冷启动链路分析 │
│ │
│ 用户请求 │
│ ↓ │
│ [API网关] ───── 1ms ────→ [API服务] │
│ ↓ │
│ [模型推理引擎] ←── 这里是瓶颈! │
│ ↓ │
│ ┌─────────────────────┐ │
│ │ 1. 加载模型权重到GPU │ ~30-120s │
│ │ 2. 编译计算图(Kernel) │ ~5-20s │
│ │ 3. 预热KV Cache │ ~1-5s │
│ │ 4. 初始化采样器等 │ ~1s │
│ └─────────────────────┘ │
│ ↓ │
│ 开始推理 │
└─────────────────────────────────────────────────────────────┘
解决方案:
# 方案1: 预热脚本(在服务启动后立即执行)
import requests
import time
def warmup_model(base_url="http://localhost:8080"):
"""发送预热请求,让模型完成初始化"""
warmup_prompts = [
"// Write a hello world function",
"def add(a, b):",
"public class Hello {",
"# TODO: implement",
]
print("开始模型预热...")
start = time.time()
for i, prompt in enumerate(warmup_prompts):
try:
resp = requests.post(
f"{base_url}/api/v1/generate",
json={
"prompt": prompt,
"max_tokens": 50,
"stream": False,
},
timeout=120,
)
print(f" 预热请求 {i+1}/{len(warmup_prompts)} 完成")
except Exception as e:
print(f" 预热请求 {i+1} 失败: {e}")
elapsed = time.time() - start
print(f"✅ 预热完成,耗时 {elapsed:.1f}s")
if __name__ == "__main__":
warmup_model()
# 方案2: vLLM 配置优化(减少冷启动时间)
server_args:
# 使用更快的模型加载方式
enable-prefix-caching: true # 开启前缀缓存
# 预分配显存(避免运行时分配导致抖动)
gpu-memory-utilization: 0.95
# 减少首次编译开销
enforce-eager: false # 使用CUDA graph加速
# 并行优化
tensor-parallel-size: 1 # 根据GPU数量调整
pipeline-parallel-size: 1
问题3.2:响应逐渐变慢(性能衰减)
症状:刚重启时很快(<2s),运行几小时后变慢(>10s)
排查清单:
#!/bin/bash
# MonkeyCode 性能衰减诊断脚本
echo "=========================================="
echo " MonkeyCode 性能衰减诊断"
echo "=========================================="
echo ""
echo "[1] GPU显存碎片化检查..."
nvidia-smi --query-gpu=memory.used,memory.total,memory.free --format=csv,noheader
echo "如果 used 接近 total 但实际推理需求不大,可能有内存泄漏/碎片"
echo ""
echo "[2] GPU温度降频检查..."
nvidia-smi --query-gpu=temperature.gpu,clocks.current.sm,clocks.max.sm --format=csv,noheader
echo "如果 current.sm << max.sm,说明因高温降频"
echo ""
echo "[3] 进程内存泄漏检查..."
pid=$(pgrep -f "monkeycode|vllm")
if [ -n "$pid" ]; then
echo "PID: $pid"
cat /proc/$pid/status | grep VmRSS
echo "观察该值是否持续增长"
fi
echo ""
echo "[4] KV Cache膨胀检查..."
# vLLM 的 KV Cache 会随着不同请求不断增长
curl -s http://localhost:8000/stats | python3 -m json.tool \
| grep -E "cache_num|gpu_cache"
echo ""
echo "[5] 文件描述符耗尽检查..."
ulimit -n
ls /proc/$pid/fd/ 2>/dev/null | wc -l
echo "如果接近ulimit限制,需要增大或排查泄露"
echo ""
echo "[6] 网络连接池耗尽..."
ss -s | grep "estab"
echo "大量 ESTAB 连接可能是连接未释放"
常见原因与修复:
| 原因 | 诊断命令 | 修复方案 |
|---|---|---|
| KV Cache无限增长 | /stats 中 cache_num 持续增 |
设置 max_num_seqs 和定期清理策略 |
| GPU显存碎片 | nvidia-smi 显示used高但利用率低 |
定期重启或启用显存整理 |
| 进程内存泄漏 | VmRSS 持续增长 |
升级版本(已知bug)或设置定期重启 |
| 连接池耗尽 | ss -s 显示大量ESTAB |
调整连接池大小和idle timeout |
| 日志文件过大 | du -sh /var/log/monkeycode/ |
配置logrotate |
问题3.3:偶发超时(P99 spikes)
症状:大部分请求正常,但偶尔出现超过30秒的超时
排查方法:
# analyze_latency_spikes.py
# 分析延迟尖峰的根因
import pandas as pd
import requests
# 从Prometheus获取延迟数据
query = """
histogram_quantile(0.99,
rate(monkeycode_request_duration_seconds_bucket[5m])
)
"""
resp = requests.get(
"http://prometheus:9090/api/v1/query",
params={"query": query}
)
data = resp.json()["data"]["result"]
# 找出尖峰时刻
df = pd.DataFrame([{
"timestamp": d["values"][i][0],
"value": float(d["values"][i][1])
} for d in data for i in range(len(d["values"]))])
spikes = df[df["value"] > df["value"].mean() + 3*df["value"].std()]
print(f"发现 {len(spikes)} 个延迟尖峰")
# 关联其他指标
for _, spike in spikes.iterrows():
ts = spike["timestamp"]
print(f"\n尖峰时刻: {ts}")
# 检查同时刻的并发量
concurrent = f'monkeycode_active_requests[{ts}]'
# 检查同时刻的队列深度
queue = f'monkeycode_queue_depth[{ts}]'
# 检查同时刻的GPU利用率
gpu_util = f'DCGM_FI_DEV_GPU_UTIL[{ts}]'
# 检查是否有长尾请求(输入token特别多)
input_tokens = f'rate(monkeycode_input_tokens_total[5m]) offset at {ts}'
典型场景与解决方案:
场景A: 长尾大请求阻塞
现象:某个用户粘贴了整个文件(5000+ tokens),导致后续所有请求排队
解决:
1. 设置最大输入长度限制(如 max_input_tokens=8192)
2. 实现请求优先级队列(短请求优先)
3. 对大请求自动拆分处理
场景B: GC停顿(Java服务)
现象:每隔几分钟出现一次规律性延迟尖峰
解决:
1. 使用G1GC替代CMS/ZGC
2. 调整GC参数: -XX:MaxGCPauseMillis=200
3. 监控GC日志确认
场景C: 模型重新加载
现象:某时刻所有请求同时变慢
解决:
1. 检查是否有定时任务触发模型切换
2. 使用蓝绿部署避免重启期间服务中断
3. 预加载下一版模型到备用GPU
四、输出质量问题(AI生成的代码不好用)
问题4.1:生成的代码风格不一致
症状:有时用驼峰命名,有时用下划线;有时用async/await,有时用回调
排查方向:
diagnosis_checklist:
system_prompt_check:
question: "系统提示词中是否明确指定了编码规范?"
fix: |
在MonkeyCode的系统提示词中添加:
"请严格遵循以下编码规范:
- 命名:驼峰命名法(camelCase)用于变量/函数,帕斯卡(PascalCase)用于类
- 缩进:4空格
- 异步:统一使用 async/await
- 注释:公共API必须有JSDoc"
model_temperature_check:
question: "temperature设置是否过高?"
detail: "temperature越高,输出的随机性越大,风格越不稳定"
recommended_values:
code_generation: "0.1 - 0.3" # 代码生成要低
creative_writing: "0.7 - 1.0" # 创意写作可以高
context_conflict_check:
question: "RAG检索到的上下文是否来自不同风格的代码?"
fix: |
1. 检索结果增加风格过滤
2. 只检索同一项目/团队的代码
3. 在提示词中明确"以第一个代码片段的风格为准"
finetune_check:
question: "是否使用了定制化微调模型?"
recommendation: |
如果团队有明确的编码规范,
强烈建议使用LoRA微调(参见《定制化训练》一文)
微调后的模型风格一致性可提升至85%+
问题4.2:生成代码存在安全漏洞
症状:AI生成的代码包含SQL注入、XSS、硬编码密码等问题
排查与修复:
# security_filter_example.py
# MonkeyCode 安全过滤中间件示例
import re
from dataclasses import dataclass
@dataclass
class SecurityIssue:
severity: str # critical/high/medium/low
category: str
description: str
line_number: int
pattern: str
SECURITY_PATTERNS = [
# SQL注入
(r'execute\(["\'].*\+.*["\']', "critical", "SQL Injection",
"字符串拼接构造SQL,应使用参数化查询"),
(r'f"\s*SELECT.*\{.*\}', "critical", "SQL Injection (f-string)",
"f-string直接拼接SQL变量"),
# XSS
(r'dangerouslySetInnerHTML', "high", "XSS",
"使用dangerouslySetInnerHTML可能导致XSS"),
(r'\.innerHTML\s*=', "high", "XSS",
"innerHTML赋值应先做转义"),
# 硬编码敏感信息
(r'password\s*=\s*["\'][^"\']+["\']', "critical", "Hardcoded Password",
"密码不应硬编码在源码中"),
(r'secret_key\s*=\s*["\'][^"\']+["\']', "critical", "Hardcoded Secret",
"密钥应从环境变量或密钥管理服务获取"),
(r'api_key\s*=\s*["\'][^"\']+["\']', "high", "Hardcoded API Key",
"API Key不应硬编码"),
# 不安全的随机数
(r'random\(\)', "medium", "Insecure Random",
"Math.random()不适用于安全场景,应使用crypto.randomBytes()"),
# 命令注入
(r'exec\(["\'].*\+.*["\']', "critical", "Command Injection",
"exec函数参数拼接用户输入可能导致命令注入"),
(r'os\.system\(.+\.)', "critical", "Command Injection",
"os.system参数含变量时有注入风险"),
# 弱加密
(r'md5\(', "low", "Weak Hash",
"MD5不适合密码存储,应使用bcrypt/scrypt/argon2"),
]
def scan_generated_code(code: str) -> list[SecurityIssue]:
"""扫描AI生成的代码中的安全问题"""
issues = []
lines = code.split('\n')
for pattern, severity, category, description in SECURITY_PATTERNS:
for i, line in enumerate(lines, 1):
if re.search(pattern, line):
issues.append(SecurityIssue(
severity=severity,
category=category,
description=description,
line_number=i,
pattern=pattern,
))
return issues
# 集成到MonkeyCode输出管道
def post_process_ai_output(generated_code: str) -> dict:
"""对AI输出进行安全扫描"""
issues = scan_generated_code(generated_code)
if not issues:
return {"safe": True, "code": generated_code}
critical_issues = [i for i in issues if i.severity == "critical"]
if critical_issues:
return {
"safe": False,
"code": None,
"issues": issues,
"action": "BLOCKED", # 阻止输出
"message": f"发现 {len(critical_issues)} 个严重安全问题,已阻止输出",
}
else:
return {
"safe": True, # 允许输出但附带警告
"code": generated_code,
"issues": issues,
"action": "WARNING",
"message": f"发现 {len(issues)} 个安全问题,建议审查",
}
问题4.3:模型出现幻觉(编造不存在的API/库)
症状:AI自信地使用了一个根本不存在的方法或库
缓解措施:
hallucination_mitigation:
strategy_1_context_grounding:
name: "上下文锚定"
method: |
在提示词中强制要求只使用项目中已有的依赖:
"本项目使用的库版本如下(只能使用以下库中的API):
- spring-boot: 3.2.0
- mybatis-plus: 3.5.5
- hutool: 5.8.25
不要使用任何不在上述列表中的库"
strategy_2_verification_layer:
name: "验证层"
implementation: |
AI输出后,通过以下验证:
1. import语句检查:引用的包是否在pom.xml/requirements.txt中
2. API签名检查:调用的方法是否存在于对应版本的SDK文档
3. 类型检查:变量类型和方法签名是否匹配
strategy_3_few_shot_with_examples:
name: "少样本示例约束"
method: |
在提示词中提供3-5个正确的代码示例,
让模型模仿这些示例的模式,
显著降低幻觉率(研究显示可降低40-60%)
strategy_4_temperature_control:
name: "低温度参数"
setting: "code_generation temperature = 0.1"
effect: "降低创造性输出,提高事实准确性"
五、IDE插件问题
问题5.1:VSCode插件无响应
症状:VSCode中MonkeyCode面板空白,或输入框无反应
排查步骤:
# Step 1: 检查插件进程
code --list-extensions | grep monkeycode
# Step 2: 查看插件日志
# VSCode → 输出(Ctrl+Shift+U) → 选择 "MonkeyCode"
# 或查看日志文件:
# macOS: ~/Library/Application Support/Code/logs/
# Linux: ~/.config/Code/logs/
# Windows: %APPDATA%/Code/logs/
# Step 3: 常见问题快速修复
# 问题A: Node.js版本不兼容
node --version
# 需要 >= 18.0.0
# 问题B: 扩展宿主崩溃
# Ctrl+Shift+P → "Developer: Restart Extension Host"
# 问题C: 代理设置问题
# 检查 VSCode 设置中的 proxy 配置
# MonkeyCode插件需要能访问API服务器
完整重装流程:
# 1. 卸载旧版本
code --uninstall-extension monkeycode.monkeyCode-vscode
# 2. 清理残留数据
rm -rf ~/.vscode/extensions/monkeycode.*
rm -rf ~/AppData/Roaming/Code/User/globalStorage/monkeycode.*
# 3. 重新安装
code --install-extension monkeycode-1.2.3.vsix
# 4. 重启VSCode
code --disable-extensions # 先以无扩展模式启动测试
# 确认基础功能OK后再启用扩展
问题5.2:JetBrains插件快捷键冲突
症状:MonkeyCode的快捷键触发了IDE的其他功能
解决方法:
<!-- IntelliJ IDEA keymap配置 -->
<!-- Settings → Keymap → 搜索 "monkeycode" -->
<!-- 推荐的快捷键映射 -->
<keymap version="1" name="MonkeyCode Custom" parent="Default">
<!-- 补全触发 -->
<action id="monkeycode.complete">
<keyboard-shortcut first-keystroke="ctrl space"/>
</action>
<!-- 内联补全接受 -->
<action id="monkeycode.accept-inline">
<keyboard-shortcut first-keystroke="tab"/>
</action>
<!-- 打开对话面板 -->
<action id="monkeycode.open-chat">
<keyboard-shortcut first-keystroke="ctrl shift m"/>
</action>
<!-- 解释选中代码 -->
<action id="monkeycode.explain">
<keyboard-shortcut first-keystroke="ctrl shift e"/>
</action>
</keymap>
问题5.3:插件与服务端认证失败
症状:插件界面显示 "Authentication failed" 或 "Token expired"
排查与修复:
# Step 1: 检查Token有效性
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://your-monkeyCode-server/api/v1/me
# Step 2: 常见原因
# A) Token过期(默认24小时有效期)
# 解决:插件设置 → Refresh Token
# B) 时钟偏差(服务端和客户端时间差>5分钟)
date # 检查系统时间
ntpdate pool.ntp.org # 同步时间
# C) SSO/LDAP集成问题
# 检查LDAP服务是否可用
ldapsearch -x -H ldap://corpdc.corp -b "DC=corp,DC=com" "(sAMAccountName=username)"
# Step 3: 重新获取Token
curl -X POST https://your-monkeyCode-server/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"your-user","password":"your-pass"}'
六、GPU与模型问题
问题6.1:CUDA Out of Memory (OOM)
症状:错误信息 RuntimeError: CUDA out of memory
紧急处理:
# oom_emergency_handler.py
# OOM发生时的应急处理脚本
import subprocess
import requests
def handle_oom():
"""OOM应急处理流程"""
print("🚨 检测到GPU OOM!执行应急处理...")
# 1. 立即记录现场
subprocess.run("nvidia-smi > /tmp/oom_nvidia_smi.log", shell=True)
subprocess.run("free -h > /tmp/oom_memory.log", shell=True)
# 2. 清理当前批次的挂起请求
requests.post("http://localhost:8080/admin/cancel-pending-requests")
# 3. 尝试释放显存
import torch
if torch.cuda.is_available():
torch.cuda.empty_cache()
print(f"✅ 已清理CUDA缓存,释放显存")
# 4. 降低batch size
requests.post("http://localhost:8080/admin/config", json={
"max_batch_size": 1, # 临时降到最低
"max_num_seqs": 16, # 减少并发序列
})
# 5. 切换到更小的模型(如果有配置)
requests.post("http://localhost:8080/admin/switch-model", json={
"model": "qwen2.5-coder-1.5b-instruct", # 备用小模型
"reason": "OOM emergency fallback"
})
print("✅ 应急处理完成,服务已降级运行")
print("📋 请查看日志排查OOM根因:/tmp/oom_*.log")
根因分析与长期解决:
oom_root_causes_and_fixes:
cause_1_large_batch:
symptom: "单次请求batch太大"
diagnosis: "检查请求的 max_tokens 和 n 参数"
fix: |
限制前端传入的最大值:
max_tokens: <= 2048 (默认)
n (并行生成): <= 1 (生产环境不建议并行)
cause_2_long_context:
symptom: "输入序列过长"
example: "用户粘贴了整个项目的代码"
fix: |
设置 max_model_len 限制
超长输入自动截断并提示用户
cause_3_memory_fragmentation:
symptom: "总显存够但连续块不够"
diagnosis: "nvidia-smi显示有free memory但仍OOM"
fix: |
启用显存整理(需要PyTorch 2.0+)
或定期重启服务(如每天凌晨)
cause_4_other_gpu_processes:
symptom: "其他程序占用了显存"
diagnosis: "nvidia-smi看到非MonkeyCode进程占用GPU"
fix: |
确保独占GPU使用(nvidia-smi -c 1)
或使用CUDA_VISIBLE_DEVICES隔离
cause_5_model_too_large_for_gpu:
symptom: "模型本身就需要比物理显存更多的空间"
example: "33B模型在24GB显卡上"
fix: |
使用量化模型(4bit/8bit量化可将显存需求降低2-4倍)
或使用CPU offload(速度会下降)
问题6.2:模型加载失败
症状:
FileNotFoundError: No such file or directory: 'models/qwen2.5-coder/pytorch_model.bin'
ValueError: Config file not found: config.json
排查与修复:
#!/bin/bash
# 模型加载问题诊断脚本
MODEL_DIR="/opt/models/qwen2.5-coder"
echo "[1] 检查模型目录是否存在..."
if [ ! -d "$MODEL_DIR" ]; then
echo "❌ 目录不存在: $MODEL_DIR"
echo "请检查模型下载是否完整"
exit 1
fi
echo "✅ 目录存在"
echo ""
echo "[2] 检查必需文件..."
REQUIRED_FILES=("config.json" "tokenizer.json" "tokenizer_config.json"
"special_tokens_map.json" "generation_config.json")
WEIGHT_FILES=("model.safetensors.index.json" "model-00001-of-0000X.safetensors")
for f in "${REQUIRED_FILES[@]}"; do
if [ -f "$MODEL_DIR/$f" ]; then
echo "✅ $f"
else
echo "❌ 缺少: $f"
fi
done
echo ""
echo "[3] 检查模型权重文件..."
if [ -f "$MODEL_DIR/model.safetensors.index.json" ]; then
echo "找到分片索引,检查分片完整性..."
cat "$MODEL_DIR/model.safetensors.index.json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
total = len(data['weight_map'])
print(f' 总共 {total} 个权重文件')
# 检查每个分片是否存在
from collections import Counter
files = Counter(data['weight_map'].values())
for fname, count in files.items():
import os
exists = os.path.exists(f'$MODEL_DIR/{fname}')
status = '✅' if exists else '❌ 缺失!'
print(f' {status} {fname} ({count} tensors)')
"
elif [ -f "$MODEL_DIR/pytorch_model.bin" ] || [ -f "$MODEL_DIR/model.safetensors" ]; then
echo "✅ 单文件权重存在"
else
echo "❌ 未找到任何权重文件!"
fi
echo ""
echo "[4] 检查文件完整性(SHA256)..."
if [ -f "$MODEL_DIR/checksum.sha256" ]; then
cd "$MODEL_DIR"
sha256sum -c checksum.sha256
else
echo "⚠️ 无校验文件,跳过完整性检查"
fi
echo ""
echo "[5] 检查权限..."
ls -la "$MODEL_DIR"/*.json "$MODEL_DIR"/*.safetensors 2>/dev/null | head -5
echo "确保运行用户至少有读权限(r--)"
问题6.3:多GPU环境下的NCCL通信错误
症状:
NCCL ERROR: Collective communication failed
RuntimeError: NCCL error: unhandled cuda error (either device-side error or synchronous error)
解决方案:
#!/bin/bash
# NCCL通信问题修复指南
echo "=========================================="
echo " MonkeyCode NCCL 问题诊断与修复"
echo "=========================================="
# 1. 检查GPU互联拓扑
echo ""
echo "[1] GPU拓扑结构..."
nvidia-smi topo -m
# 期望看到 NVLINK 或 PIX (PCIe) 连接
# NVLINK 通信效率 >> PCIe
# 2. 检查NCCL调试信息
echo ""
echo "[2] 启用NCCL调试模式..."
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=ALL
# 重现问题,观察详细日志
# 3. 常见NCCL问题修复
echo ""
echo "[3] 应用NCCL修复..."
# 修复A: 禁用P2P(某些虚拟化/云环境不支持)
export NCCL_P2P_DISABLE=1
export NCCL_IB_DISABLE=1 # 同时禁用InfiniBand(如果不使用)
# 修复B: 设置通信算法
export NCCL_ALGO=Ring # Ring算法兼容性最好
# 其他选项: Tree, CollnetDirect
# 修复C: 超时设置
export NCCL_TIMEOUT=600 # 10分钟超时(模型加载可能较慢)
# 修复D: 环境感知缓冲区大小
export NCCL_BUFFSIZE=8388608 # 8MB
# 4. 网络相关(多节点场景)
echo ""
echo "[4] 多节点网络检查..."
if [ -n "$MONKEYCODE_MULTI_NODE" ]; then
# 检查防火墙
nc -zv $(hostname) 29500 # NCCL默认端口范围起始
# 检查网卡绑定
ibdev2netdev # InfiniBand
ethtool -i eth0 # 以太网
fi
echo ""
echo "✅ NCCL配置建议已输出"
echo "将上述 export 命令加入启动脚本即可生效"
七、数据库与存储问题
问题7.1:向量数据库查询超时
症状:RAG检索阶段耗时超过10秒
诊断与优化:
# vector_db_tuning.py
# 向量数据库性能优化
# Milvus 优化配置
milvus_optimization = {
"index_type": "IVF_FLAT", # 精度最高
# 或 IVF_PQ (更快,精度略低)
# 或 HNSW (最佳平衡)
"index_params": {
"nlist": 1024, # IVF聚类数量
"M": 32, # HNSW每个节点连接数
"efConstruction": 200, # HNSW构建参数
},
"search_params": {
"nprobe": 32, # IVF搜索探测聚类数(越大越准但越慢)
"ef": 128, # HNSW搜索范围
},
"collection_settings": {
"segments_per_query": 1, # 减少段数提升查询速度
"consistency_level": "Bounded", # 牺牲一点一致性换取性能
},
}
# 性能对比参考
# IVF_FLAT, nlist=1024, nprobe=32: 召回率95%, QPS~500
# HNSW, M=32, ef=128: 召回率97%, QPS~800
# IVF_PQ, m=64, nbits=8: 召回率85%, QPS~2000
问题7.2:Redis连接池耗尽
症状:Cannot acquire connection from pool 或 Connection pool exhausted
修复:
# monkeycode redis 配置优化
redis:
host: "redis-cluster.internal"
port: 6379
mode: "cluster" # 或 standalone/sentinel
connection_pool:
max_connections: 50 # 最大连接数
min_idle: 10 # 最小空闲连接
max_idle: 30 # 最大空闲连接
retry_on_timeout: true # 超时自动重试
timeouts:
connect_timeout: 5s # 连接超时
socket_timeout: 10s # 读写超时
command_timeout: 5s # 命令超时
health_check:
interval: 10s # 健康检查间隔
failure_threshold: 3 # 连续失败多少次标记不可用
八、故障排查工具箱
8.1 一键诊断脚本
#!/bin/bash
# monkeycode_diagnosis.sh
# MonkeyCode 全方位一键诊断工具
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
PASS=0
WARN=0
FAIL=0
check() {
local label="$1"
local condition="$2"
local severity="${3:-FAIL}"
if eval "$condition" > /dev/null 2>&1; then
echo -e "${GREEN}✅ ${label}${NC}"
((PASS++))
else
if [ "$severity" = "WARN" ]; then
echo -e "${YELLOW}⚠️ ${label}${NC}"
((WARN++))
else
echo -e "${RED}❌ ${label}${NC}"
((FAIL++))
fi
fi
}
info() {
echo -e "${BLUE}ℹ️ $1${NC}"
}
echo "╔══════════════════════════════════════════════════╗"
echo "║ 🐒 MonkeyCode 全方位诊断 v2.0 ║"
echo "║ $(date '+%Y-%m-%d %H:%M:%S') ║"
echo "╚══════════════════════════════════════════════════╝"
echo ""
# ===== 系统资源 =====
echo "━━━ 系统资源 ━━━"
check "CPU核心数 >= 4" "$(nproc) >= 4"
check "内存 >= 16GB" "$(free -g | awk '/Mem:/ {print $2}') -ge 16"
check "磁盘剩余 >= 50GB" "$(df -BG / | awk 'NR==2 {print $4}' | tr -d 'G') -ge 50"
check "系统负载 < CPU核数*2" "$(awk '{printf "%.0f", $1/$2*100}' /proc/loadavg) -lt 200" WARN
# ===== GPU =====
echo ""
echo "━━━ GPU 状态 ━━━"
if command -v nvidia-smi &> /dev/null; then
GPU_COUNT=$(nvidia-smi --list-gpus | wc -l)
check "NVIDIA驱动已安装" "true"
check "检测到GPU ($GPU_COUNT 块)" "$GPU_COUNT -gt 0"
GPU_TEMP=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits | sort -rn | head -1)
check "GPU最高温度 < 85°C" "$GPU_TEMP -lt 85" WARN
GPU_MEM_USED=$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits | awk '{s+=$1} END {print s}')
GPU_MEM_TOTAL=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | awk '{s+=$1} END {print s}')
GPU_MEM_PCT=$((GPU_MEM_USED * 100 / GPU_MEM_TOTAL))
check "GPU显存使用 < 90%" "$GPU_MEM_PCT -lt 90" WARN
info "GPU显存: ${GPU_MEM_USED}MB / ${GPU_MEM_TOTAL}MB (${GPU_MEM_PCT}%)"
info "GPU最高温度: ${GPU_TEMP}°C"
else
echo -e "${YELLOW}⚠️ 未检测到nvidia-smi(可能无GPU或驱动未安装)${NC}"
((WARN++))
fi
# ===== Docker/K8s =====
echo ""
echo "━━━ 容器运行时 ━━━"
if command -v docker &> /dev/null; then
check "Docker服务运行中" "docker info > /dev/null 2>&1"
MC_CONTAINER=$(docker ps --filter "name=monkeycode" --format "{{.Names}}" | head -1)
if [ -n "$MC_CONTAINER" ]; then
info "容器名称: $MC_CONTAINER"
check "容器状态为running" "docker inspect -f '{{.State.Status}}' $MC_CONTAINER | grep -q running"
CONTAINER_UPTIME=$(docker inspect -f '{{.State.StartedAt}}' $MC_CONTAINER)
info "启动时间: $CONTAINER_UPTIME"
RESTART_COUNT=$(docker inspect -f '{{.RestartCount}}' $MC_CONTAINER)
check "容器重启次数 < 5" "$RESTART_COUNT -lt 5" WARN
if [ "$RESTART_COUNT" -gt 0 ]; then
info "⚠️ 容器已重启 $RESTART_COUNT 次"
info "最近退出码: $(docker inspect -f '{{.State.ExitCode}}' $MC_CONTAINER)"
fi
else
echo -e "${RED}❌ 未找到运行中的MonkeyCode容器${NC}"
((FAIL++))
fi
fi
# ===== 网络连通性 =====
echo ""
echo "━━━ 网络连通性 ━━━"
check "DNS解析正常" "nslookup github.com > /dev/null 2>&1"
check "API端口可达" "curl -sf --connect-timeout 3 http://localhost:8080/api/v1/health > /dev/null" WARN
check "外部网络可达" "curl -sf --connect-timeout 3 https://www.google.com > /dev/null 2>&1" WARN
# ===== 依赖服务 =====
echo ""
echo "━━━ 依赖服务 ━━━"
check "Redis可达" "redis-cli -h localhost -p 6379 ping 2>/dev/null | grep -q PONG" WARN
check "PostgreSQL可达" "pg_isready -h localhost -p 5432 2>/dev/null | grep -q accepting" WARN
check "Milvus可达" "curl -sf http://localhost:9091/healthz > /dev/null 2>&1" WARN
# ===== MonkeyCode服务健康 =====
echo ""
echo "━━━ MonkeyCode 服务 ━━━"
HEALTH_RESP=$(curl -sf http://localhost:8080/api/v1/health 2>/dev/null || echo "{}")
if [ -n "$HEALTH_RESP" ] && [ "$HEALTH_RESP" != "{}" ]; then
check "API服务健康端点正常" "true"
echo "$HEALTH_RESP" | python3 -m json.tool 2>/dev/null || echo "$HEALTH_RESP"
else
echo -e "${RED}❌ API服务健康检查失败${NC}"
((FAIL++))
fi
# ===== 总结 =====
echo ""
echo "╔══════════════════════════════════════════════════╗"
echo "║ 诊断总结 ║"
echo "╠══════════════════════════════════════════════════╣"
echo -e "║ ${GREEN}通过: ${PASS}${NC} ${YELLOW}警告: ${WARN}${NC} ${RED}失败: ${FAIL}${NC} ║"
echo "╚══════════════════════════════════════════════════╝"
if [ "$FAIL" -gt 0 ]; then
echo ""
echo -e "${RED}🔴 发现 ${FAIL} 个严重问题,请按上述提示逐一修复${NC}"
exit 1
elif [ "$WARN" -gt 0 ]; then
echo ""
echo -e "${YELLOW}🟡 发现 ${WARN} 个警告项,建议尽快处理${NC}"
exit 0
else
echo ""
echo -e "${GREEN}🟢 所有检查通过!MonkeyCode运行状态良好${NC}"
exit 0
fi
8.2 日志分析常用命令
# ===== 实时日志跟踪 =====
# 跟踪所有ERROR级别日志
tail -f /var/log/monkeycode/app.log | grep -i "error\|exception\|fatal"
# 跟踪特定用户的请求
tail -f /var/log/monkeycode/app.log | grep "user_id=abc123"
# 跟踪慢请求(>5秒)
tail -f /var/log/monkeycode/app.log | grep "duration=[5-9][0-9]\{3,\}\|duration=[1-9][0-9]\{4,\}"
# ===== 统计分析 =====
# 最近1小时的错误统计
grep "ERROR" /var/log/monkeycode/app.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# P99延迟趋势(每5分钟一个点)
awk '/duration=/{match($0, /duration=([0-9]+)/, a); print a[1]}' \
/var/log/monkeycode/app.log | sort -n | tail -n +$(($(wc -l < /dev/stdin)*99/100)) \
| awk 'NR%100==0'
# 各类型请求的分布
grep "endpoint=" /var/log/monkeycode/app.log \
| sed 's/.*endpoint=\([^ ]*\).*/\1/' | sort | uniq -c | sort -rn
# ===== GPU相关 =====
# GPU OOM历史
grep -i "oom\|cuda out of memory\|killed" /var/log/monkeycode/app.log \
| tail -20
# 模型加载记录
grep -i "loading model\|model loaded\|warmup" /var/log/monkeycode/app.log \
| tail -10
九、常见问题速查表
| # | 问题现象 | 可能原因 | 快速修复 | 详细章节 |
|---|---|---|---|---|
| 1 | 服务无法启动 | 端口占用 | lsof -i :port + kill |
§2.1 |
| 2 | 502 Bad Gateway | 上游未启动 | 检查vLLM/TGI进程 | §2.2 |
| 3 | WebSocket断开 | 超时配置太短 | 增大read_timeout | §2.3 |
| 4 | 首次请求很慢 | 冷启动 | 预热脚本 | §3.1 |
| 5 | 运行几小时后变慢 | 内存泄漏/GC | 检查VmRSS | §3.2 |
| 6 | 偶发超时 | 长尾请求阻塞 | 限流+队列 | §3.3 |
| 7 | 代码风格不一致 | 温度过高/无规范 | 降temp+加规范 | §4.1 |
| 8 | 生成代码有漏洞 | 无安全过滤 | 加安全扫描层 | §4.2 |
| 9 | AI编造API | 幻觉问题 | 低temp+上下文锚定 | §4.3 |
| 10 | VSCode插件无响应 | 扩展宿主崩溃 | 重启Extension Host | §5.1 |
| 11 | 快捷键冲突 | 与IDE内置冲突 | 自定义Keymap | §5.2 |
| 12 | 认证失败 | Token过期 | Refresh Token | §5.3 |
| 13 | CUDA OOM | 显存不足 | 降batch/切小模型 | §6.1 |
| 14 | 模型加载失败 | 文件缺失/损坏 | 运行诊断脚本 | §6.2 |
| 15 | NCCL通信错误 | 多GPU配置不当 | 设NCCL环境变量 | §6.3 |
| 16 | 向量库查询慢 | 索引未优化 | 调整index参数 | §7.1 |
| 17 | Redis连接池耗尽 | 连接未释放 | 调pool配置 | §7.2 |
十、何时该升级/寻求帮助
╔═══════════════════════════════════════════════════════════╗
║ 问题升级决策树 ║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ 自己能解决? ║
│ ├── 是 → 按照本文档操作 │
│ │ │
│ └── 否 ↓ │
║ ║
║ 社区有人遇到过? │
│ ├── 是 → GitHub Issues / Discord / 论坛搜索 │
│ │ │
│ └── 否 ↓ │
║ ║
║ 影响范围? │
│ ├── 个人使用 → 提GitHub Issue(附诊断日志) │
│ ├── 团队受影响 → 企业版支持工单 │
│ └── 生产事故 → 立即电话支持 + 启动应急预案 │
║ ║
║ 🔧 报问题时请务必包含: │
║ 1. monkeycode --version │
║ 2. 操作系统和GPU型号 │
║ 3. 完整的错误日志(不是截图!) │
║ 4. 复现步骤 │
║ 5. 已尝试过的解决方法 │
║ ║
╚═══════════════════════════════════════════════════════════╝
总结
好的故障排查能力 = 结构化的思维 + 丰富的经验 + 完善的工具链
本文覆盖的核心能力:
- 快速定位:决策树帮你第一时间缩小排查范围
- 系统化诊断:从连接→性能→质量→插件→GPU全面覆盖
- 即用脚本:一键诊断、OOM应急、日志分析——复制就能用
- 标本兼治:不仅告诉你怎么修,还告诉你怎么预防
- 知道何时求助:解决问题的成本 vs 寻求帮助的成本
一句话总结:收藏这篇手册,下次出问题时它能帮你节省数小时的排查时间。
下一篇预告:《MonkeyCode版本演进历程:从v1.0到v4.0的技术跨越》
浙公网安备 33010602011771号