AIHero
    3 min read · Updated Jan 22, 2026

    如何在 AFK Ralph 中流式查看 Claude Code 输出

    运行 AFK Ralph 时实时流式查看 Claude Code。学习使用 jq 获取 Claude 输出,而不是盯着空白屏幕。

    Matt Pocock
    Matt Pocock
    本页目录

    本指南面向已经尝试用 Claude Code 运行 Ralph、却遇到这一恼人问题的人:运行 AFK 脚本后,只能盯着空白屏幕。

    如果从未听说过 Ralph,请从这里开始:

    问题:空白屏幕

    如果希望离开键盘后 Ralph 继续运行,可能会使用下面这样的脚本:

    #!/bin/bash
    set -e
    if [ -z "$1" ]; then
    echo "Usage: $0 <iterations>"
    exit 1
    fi
    for ((i=1; i<=$1; i++)); do
    result=$(docker sandbox run --credentials host claude \
    --print \
    "<your prompt here>")
    if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
    echo "Ralph complete after $i iterations."
    exit 0
    fi
    done

    令人沮丧的问题是:使用 --print 标记运行 Claude 时,完全没有流式输出,终端一片空白。

    离开后,你完全不知道发生了什么:Claude 在工作吗?卡住了吗?是不是出了问题?只有结束时才会知道。

    AFK Ralph 的理想状态是兼得两者:既能实时看到 Claude 在做什么,又能在离开时让它继续运行。

    解决方案:使用 jq 流式输出

    Claude 可以输出 stream-json 格式,实时提供每一条消息,但输出极其冗长,难以阅读。

    通过组合 stream-json with jq 过滤,可以只提取有用信息并实时流式显示到终端,同时捕获最终结果,以检查 <promise>COMPLETE</promise> 标记。

    下面是完整脚本:

    #!/bin/bash
    set -e
    if [ -z "$1" ]; then
    echo "Usage: $0 <iterations>"
    exit 1
    fi
    # jq filter to extract streaming text from assistant messages
    stream_text='select(.type == "assistant").message.content[]? | select(.type == "text").text // empty | gsub("\n"; "\r\n") | . + "\r\n\n"'
    # jq filter to extract final result
    final_result='select(.type == "result").result // empty'
    for ((i=1; i<=$1; i++)); do
    tmpfile=$(mktemp)
    trap "rm -f $tmpfile" EXIT
    docker sandbox run --credentials host claude \
    --verbose \
    --print \
    --output-format stream-json \
    "<your prompt here>" \
    | grep --line-buffered '^{' \
    | tee "$tmpfile" \
    | jq --unbuffered -rj "$stream_text"
    result=$(jq -r "$final_result" "$tmpfile")
    if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
    echo "Ralph complete after $i iterations."
    exit 0
    fi
    done

    脚本接收一个参数:要运行的迭代次数。

    逐步解析脚本结构

    拆解流过滤器

    流过滤器会执行几项重要操作:

    1. 选择 assistant 消息: select(.type == "assistant") 只获取 Claude 的响应
    2. 提取文本内容: .message.content[]? | select(.type == "text").text 只取出文本部分
    3. 修复行尾: gsub("\n"; "\r\n") 把换行替换为回车加换行
    4. 添加间距: . + "\r\n\n" 在消息之间插入额外空白

    替换回车可以修复光标无法正确返回行首字符的问题。

    数据管道

    数据在脚本中的流动方式如下:

    Docker 会流式输出 stream-json 格式的数据,但其中还夹杂一些无意义的非 JSON 行。 grep --line-buffered '^{' 过滤器可以确保只处理有效 JSON 行。

    随后, tee "$tmpfile" 命令会在不中断数据流的情况下,把全部内容写入临时文件。稍后需要用该文件检查 Claude 是否完成。

    最后, jq --unbuffered -rj "$stream_text" 应用流过滤器,并在终端中实时显示文本。

    总结

    我希望不久后就能删除本文,因为 Claude Code 会推出一项功能,在流式显示响应的同时仍能捕获最终输出。

    OpenCode 已经支持这项能力,因此不需要为 OpenCode 写类似文章。在 Claude Code 支持之前,这仍是运行 AFK Ralph 时实时查看 Claude 流式输出的可行方案。