如何监控运行状态?DeepSeek-R1日志分析教程
1. 为什么需要关注日志——不只是“跑起来”,更要“稳得住”
你刚把 DeepSeek-R1 (1.5B) 拉起来,输入“鸡兔同笼怎么解”,页面秒回一串清晰的分步推导——太棒了!但下一秒,你刷新页面发现卡在加载图标;或者连续问三个问题后,响应时间从800ms跳到4.2秒;又或者某天重启后,Web界面干脆打不开……这时候,光靠“试试看”和“重启大法”已经不够用了。
日志不是程序员的黑匣子,而是模型服务的“健康体检报告”。它不告诉你“答案对不对”,但它会如实记录:
- 模型加载时有没有缺文件、权限够不够、显存/内存是否告警;
- 每次请求进来,系统花了多少毫秒在加载tokenizer、多少毫秒在推理、哪一步悄悄超时了;
- 是用户同时发了10个请求压垮了CPU,还是某个长文本触发了未处理的异常中断;
- 甚至能帮你发现:原来你一直用的HTTP端口被另一个程序占用了,只是之前没报错,只默默降级成单线程响应。
本教程不讲抽象概念,只带你做三件事:
看懂默认日志里每一行在说什么(不用背术语)
快速定位最常见的5类运行异常(卡顿、崩溃、慢响应、启动失败、界面空白)
用3条命令+1个配置修改,让日志变成你的“运维小助手”
2. 日志从哪里来?先找到它的“出生地”
DeepSeek-R1-Distill-Qwen-1.5B 的日志输出路径,取决于你用哪种方式启动。别急着翻文档,我们按最常见场景直接定位:
2.1 如果你是用python app.py启动的(开发调试最常用)
日志默认直接打印在终端窗口里,像这样:
INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: 127.0.0.1:56789 - "POST /v1/chat/completions HTTP/1.1" 200 OK DEBUG: Input tokens: 42, Output tokens: 156, Inference time: 2842ms注意:关闭终端 = 日志消失。所以第一步,先把它存下来:
# 把实时日志保存到文件,后台运行(Linux/macOS) nohup python app.py > r1-runtime.log 2>&1 & # Windows 用户可用(在命令提示符中): python app.py > r1-runtime.log 2>&1小贴士:
2>&1的意思是“把错误信息也一起存进去”,否则你可能错过关键报错。
2.2 如果你是用 Docker 启动的(推荐生产环境)
日志就藏在容器内部,但不用进容器翻文件——直接用 Docker 命令实时查看:
# 查看最近100行(适合快速扫一眼) docker logs --tail 100 deepseek-r1 # 实时跟踪新日志(像看直播一样) docker logs -f deepseek-r1 # 查看某段时间的日志(比如今天上午9点后的) docker logs --since "2024-06-15T09:00:00" deepseek-r1验证技巧:在Web界面随便问一个问题,立刻执行
docker logs -f deepseek-r1 | grep "Inference",如果看到带毫秒数的那行,说明日志通路已确认打通。
2.3 如果你改过启动脚本或用了其他框架(如 Ollama、Text Generation WebUI)
别慌——所有主流方案都遵循一个铁律:日志一定输出到标准输出(stdout)或指定文件。
打开你的启动命令或配置文件,找这几个关键词:
--log-level、LOG_LEVEL→ 控制日志详细程度--log-file、LOG_FILE→ 明确指定了日志存哪>>或| tee→ 表示重定向到了文件或管道
找不到?那就用最笨也最可靠的办法:
# 找出进程ID ps aux | grep "deepseek\|app.py\|uvicorn" # 查看该进程打开了哪些文件(日志文件通常在这里) lsof -p <PID> | grep log3. 日志里到底在说啥?3分钟看懂核心字段
刚打开r1-runtime.log,满屏 INFO/DEBUG/WARNING,像天书?我们只盯最关键的5类信息,每类配真实例子:
3.1 启动阶段:它“醒没醒过来”?
INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000正常信号:看到这两行,说明服务已就绪,可以访问网页。
ERROR: Exception in 'startup' event handler ERROR: FileNotFoundError: [Errno 2] No such file or directory: 'models/qwen1.5b'危险信号:“FileNotFoundError”直指模型文件路径错误。检查app.py里model_path是否写错,或文件是否真在那个位置(注意大小写、斜杠方向)。
3.2 请求处理:每一次提问,它“干了什么”?
INFO: 127.0.0.1:43210 - "POST /v1/chat/completions HTTP/1.1" 200 OK DEBUG: Input tokens: 38, Output tokens: 142, Inference time: 2156ms解读:
127.0.0.1是你的本地访问;200 OK表示成功返回;Input tokens: 38= 你输入的问题被切成了38个词元(越长的问题数字越大);Inference time: 2156ms= 真正“思考”的时间是2.16秒(CPU上1.5B模型,2秒内属优秀水平)。
3.3 性能瓶颈:为什么突然变慢了?
WARNING: CPU usage > 95% for 30s. Consider reducing concurrent requests. DEBUG: Queue wait time: 4820ms before processing request #7这两行是黄金线索:
- 第一行警告CPU长期满载,说明不是模型慢,是你的CPU被榨干了;
- 第二行暴露真相:第7个请求在队列里等了近5秒才轮到它——你可能同时开了8个浏览器标签狂刷问题。
3.4 异常中断:它“倒下”前的最后一句话
ERROR: RuntimeError: expected scalar type BFloat16 but found Float32 CRITICAL: Process finished with exit code 1典型环境冲突:你装的PyTorch版本不支持BFloat16(常见于老款CPU),需降级PyTorch或加启动参数--dtype float32。
3.5 Web界面空白?先查这行
INFO: 127.0.0.1:56789 - "GET / HTTP/1.1" 404 Not Found404 不是前端问题!说明后端根本没把/路由注册好——大概率是app.py里漏写了@app.get("/"),或静态文件路径配置错了。
记住这个心法:日志里第一个 ERROR/WARNING 出现的位置,就是故障源头;后面跟着的 INFO/DEBUG,是它临终前的“遗言”。
4. 实战:5分钟搞定3类高频问题
现在,我们用真实操作代替理论。打开你的终端,照着做:
4.1 问题:Web界面打不开,浏览器显示“连接被拒绝”
排查步骤:
- 先确认服务是否在运行:
lsof -i :8000 # Linux/macOS,看8000端口有没有进程占用 netstat -ano | findstr :8000 # Windows - 如果没结果 → 服务根本没启动。执行:
看最后几行有没有python app.py 2>&1 | head -n 20Uvicorn running on...。如果没有,重点检查OSError: [Errno 98] Address already in use—— 端口被占,换端口启动:python app.py --port 8001
4.2 问题:提问后一直转圈,等1分钟才返回,或直接超时
排查步骤:
- 实时盯日志:
tail -f r1-runtime.log | grep -E "(Inference|Queue|ERROR)" - 发一个问题,观察:
- 如果
Inference time动辄5秒以上 → CPU确实吃紧,关掉其他程序,或限制并发(见下节); - 如果
Queue wait time很高但Inference time很低 → 你一次发太多请求,加限流:# 在 app.py 里找到 uvicorn.run(),加参数: uvicorn.run(app, host="0.0.0.0", port=8000, workers=1, limit_concurrency=3)
- 如果
4.3 问题:偶尔返回乱码、空回复,或数学题算错
这不是模型能力问题,是编码/截断陷阱:
- 查日志里是否有
UnicodeDecodeError→ 输入文本含不可见控制字符,复制时粘贴了隐藏符号; - 查是否有
max_new_tokens=16→ 这个值太小,数学证明被硬生生截断。在代码里搜max_new_tokens,改成256或512; - 查是否有
temperature=0.0→ 完全确定性输出,反而让逻辑链僵化。日常使用建议temperature=0.7。
5. 让日志更好用:3个立竿见影的优化
默认日志够用,但想省力,这3招马上提升效率:
5.1 开启详细日志(只需改1行代码)
打开app.py,找到类似logging.basicConfig()或logger.setLevel()的地方,改成:
import logging logging.basicConfig( level=logging.DEBUG, # 把 INFO 改成 DEBUG format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s", datefmt="%H:%M:%S" )效果:你会看到 tokenizer 加载耗时、KV Cache 内存占用、甚至每个 token 的生成概率——对调优极有用。
5.2 自动切割日志文件(防硬盘爆满)
用 Python 自带的RotatingFileHandler,替换原来的文件输出:
from logging.handlers import RotatingFileHandler handler = RotatingFileHandler( "r1-runtime.log", maxBytes=10*1024*1024, # 单个日志最大10MB backupCount=5 # 最多保留5个旧日志 )5.3 关键指标一键提取(告别手动翻)
写个3行脚本check_status.py,每次运行直接汇报健康度:
import re with open("r1-runtime.log") as f: log = f.read() print(f" 最近100次平均响应: {round(float(re.findall(r'Inference time: (\d+)ms', log)[-100:])[-1], 1)}ms") print(f" 错误次数: {len(re.findall(r'ERROR|CRITICAL', log))}") print(f" 当前负载: {len(re.findall(r'Queue wait time', log))} 个排队请求")6. 总结:日志不是终点,而是你掌控服务的起点
你不需要成为运维专家,也能用好日志:
🔹启动时看最后10行——确认Uvicorn running和端口正确;
🔹卡顿时tail -f | grep Queue——一眼识别是CPU瓶颈还是请求堆积;
🔹报错时找第一条ERROR——90%的问题根源就藏在它上面那行;
🔹日常加--log-level DEBUG——多出来的信息,远比你想象中更有价值;
🔹学会用grep和head/tail——这是比任何GUI工具都快的“日志显微镜”。
DeepSeek-R1 (1.5B) 的魅力,不仅在于它能在CPU上跑出逻辑链推理,更在于它足够透明——所有行为都诚实地写在日志里。你不需要猜,只需要读。
现在,打开你的终端,执行tail -f r1-runtime.log,再问它一个问题。这一次,你看到的不再是滚动的文字,而是服务的心跳。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。