InternAgentS 跑任务中途停下——先去哪一层看日志?

文章导读
任务跑到一半停下,界面通常只留下一个失败标记,不会说明原因。比较稳的排查顺序是三层递进:先用界面状态固定“停在哪一步”,再用进程输出判断“属于哪类错误”,最后回任务日志核对“输入和中间产物是否完整”。跳过前两层直接翻任务日志,容易在一堆字段里打转;只盯着界面提示重跑,则很可能原样再失败一次。
📋 目录
  1. Ⅰ 先记下中断前的最后一条界面状态
  2. Ⅱ 在进程输出里找第一条错误
  3. Ⅲ 到任务日志里核对输入和中间产物
  4. Ⅳ 按错误类型分开处理
  5. Ⅴ 修完后从最近一个检查点重跑
A A

任务跑到一半停下,界面通常只留下一个失败标记,不会说明原因。比较稳的排查顺序是三层递进:先用界面状态固定“停在哪一步”,再用进程输出判断“属于哪类错误”,最后回任务日志核对“输入和中间产物是否完整”。跳过前两层直接翻任务日志,容易在一堆字段里打转;只盯着界面提示重跑,则很可能原样再失败一次。

适用场景是任务中途中断、界面只显示失败。操作动作:先记录界面提示原文和步骤序号,再去进程输出找从末尾往前数的第一条异常栈,最后到任务日志核对输入路径与上一步输出是否存在。验证方式是每一项都能用日志行、文件列表或命令输出指认,不靠推测。风险边界:进程输出和任务日志未必完整保留,容器或调度器可能只留首尾片段,需要结合运行环境确认日志留存策略。

先记下中断前的最后一条界面状态

界面提示是唯一能直接确认“停在哪一步”的线索,但它往往只显示一两行。记录时不要转述,尽量复制原文,因为后面在进程输出和任务日志之间切换时,很容易忘记当时看到的是哪个步骤。建议固定记录这几项:

  • 任务名或任务 ID,以及这次运行的实例编号,同一任务可能同时跑多个实例。
  • 步骤序号或步骤名,例如界面上显示的“第 3 步:解析文档”。
  • 中断时间,界面时间、本机时间和日志时间可能不同时区,最好三个都记下来。
  • 界面提示原文,包括是否有“重试”“继续”按钮,以及进度条停在哪个位置。

可以先在记事本里放一个固定模板,后面每一步都往里面填:

任务名/ID:
实例:
步骤序号/名称:
界面时间:
界面提示原文:

这一步的目的不是解决问题,而是防止现场丢失。很多人直接跳到任务日志里逐字段核对,结果因为不知道停在第几步,把无关步骤的报错当成根因。

在进程输出里找第一条错误

进程输出回答的是“错误类型”。任务如果跑在容器或编排环境里,先拿到最近的输出片段,再看 systemd 或重定向文件里的原始日志。通用命令骨架如下,参数按实际环境替换:

InternAgentS 跑任务中途停下——先去哪一层看日志?
# 容器
docker logs `--tail`=300 `--timestamps` <container_id> 2>&1 | tail -n 300

# 编排环境
kubectl logs <pod_name> `--tail`=300 `--timestamps`

# systemd 托管
journalctl -u <service_name> `--since` "YYYY-MM-DD HH:MM" `--no-pager` | tail -n 300

# 前台运行或重定向到文件
tail -n 300 run.log

拿到输出之后不要从第一行读,从末尾往前扫,找第一条真正的异常栈:Python 找最近一个 Traceback 的最上面那行,Java 找 Caused by,Node 找 Error 后面第一段调用栈。末尾常见的 “task finished with status: failed” 属于收尾信息,不是根因。如果输出被截断,先用 `--since` 或时间戳把范围缩到中断前几分钟。

紧接着要区分依赖报错和业务报错。依赖报错通常出现在导入或初始化阶段,关键字是 ModuleNotFoundError、No module named、版本冲突、动态库找不到;业务报错则落在自己的模块名、步骤函数或文件读写上,栈里会出现业务路径和参数。前者先别改业务代码,后者再回任务日志核对输入。

到任务日志里核对输入和中间产物

任务是“材料问题”还是“步骤问题”,要到任务日志里比对。至少核对这几个字段:

  • 输入路径:日志里记录的路径和实际文件路径是否一致,相对路径要确认执行时的工作目录。
  • 读取状态:日志里是否有“已读取”“读取失败”“文件大小为 0”这类记录,0 字节文件有时会被当成空输入继续往下跑。
  • 上一步输出文件:是否存在,修改时间是否落在本次运行窗口内,避免读到上一次运行留下的旧产物。
  • 步骤参数:分片范围、批次大小、分页游标这类参数在两次运行之间是否变过。

可以用几条简单命令交叉验证,注意用执行任务的同一个用户、同一个工作目录:

InternAgentS 跑任务中途停下——先去哪一层看日志?
ls -l <上一步输出目录>
test -f <输入文件> && echo ok
grep -n "<step_id>" task.log | tail -n 20

如果任务日志显示读取成功,但进程输出报文件不存在,优先怀疑执行用户或工作目录不同,而不是文件真的丢了。

按错误类型分开处理

三类常见中断方向不能用同一种办法修,先归类再动手。

  • 输入缺失:确认路径是相对还是绝对、执行用户是否有读权限、上游产物是否真的生成。验证方式是切到执行用户和工作目录,用 test -f 与 ls -l 各跑一次;处理方向是补文件或修配置,不要先把代码里的默认路径改掉。
  • 依赖版本不符:用 pip show、conda list 或 npm ls 看实际安装版本,和报错里提到的包名、版本号对齐。验证方式是重跑一次导入或初始化步骤,看异常是否消失;版本先往日志里出现过成功记录的那一版靠,不要直接升到最新。
  • 外部调用超时:看日志里的超时值、重试次数和目标地址返回状态。验证方式是用 curl 或同款客户端单独请求同一个 endpoint,区分是网络链路慢还是对端处理慢;如果是对端慢,改超时和重试只在部分场景有效,需要确认对端的限流或排队策略。

修完后从最近一个检查点重跑

不要从头跑整个任务,缩短复现路径才能看出改动是否有效。部分任务框架提供从某一步开始或断点续跑的开关,参数名可能是 `--start-from`、`--resume` 一类,用之前先确认语义是“跳过已完成步骤”还是“只执行该步骤”。如果没有这类开关,就把上游产物路径显式指到已有输出,手动执行失败步骤。

要保留的中间产物有三类:失败步骤的上一步输出、失败步骤已经写出的部分文件,以及本次运行的任务日志和进程输出。前两类用于断点续跑,后两类用于两次对比。

# 只跑失败步骤(示意,按实际参数替换)
python run_task.py `--task` <task_name> `--start-from` <step_id> 2>&1 | tee rerun.log

# 对比两次运行的关键行
diff <(grep -E 'input|output|version|timeout' run1.log) \
     <(grep -E 'input|output|version|timeout' rerun.log)

对比时重点看三处是否发生变化:输入路径、依赖版本、外部调用的耗时与返回状态。如果这三处都相同而错误依旧,说明问题不在这三层能覆盖的范围,需要回到界面状态,确认是不是同一个步骤、同一份输入在复现。