1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

前回の記事では、ai-digest v1.1 で追加した Anthropic 互換 API の調整項目、OpenAI 互換経路、外部 URL や画像の検証についてまとめました[1]。その後、2026 年 8 月 4 日に v1.1.1、8 月 5 日に v1.2 をリリースしました。

今回の更新で最初に確認すべき点は、v1.1 で使用していた API 接続用の環境変数が、そのままでは使えなくなったことです。ANTHROPIC_*OPENAI_*SUMMARIZER_* へ統一され、SUMMARIZER_BACKEND の値も claudeopenai から anthropic-compatibleopenai-compatible へ変わりました。旧設定は自動変換されず、変数が存在するだけで起動を拒否します[2]

v1.1 から v1.2 までには、設定移行以外にも、収集期間が Asia/Tokyo で 9 時間短くなる不具合の修正、空の収集結果の原因表示、全設定のコマンドライン上書き、API 要約専用タイムアウト、既定ポートの変更、Debian と nginx の配備手順追加が含まれています。

ai-digest は、arXiv とニュースフィードを収集し、内容を日本語で要約・分類し、HTML と画像として日次保存するアプリケーションです[3]。この記事では、v1.1 を運用している環境を v1.2 へ更新し、API を消費しない確認を済ませた後、さくらの AI Engine で 1 回だけ本番実行するところまでを扱います。

v1.1 から v1.2 までに変わったこと

変更は v1.1.1 と v1.2 の 2 段階に分かれています。v1.1.1 は日次処理の正確性と診断性を直し、v1.2 は API 接続設定と配備方法を整理したリリースです[2]

v1.1.1 で修正したこと

分類 変更内容 実務上の影響
収集期間 feedparser が返す日時を UTC として処理 Asia/Tokyo で過去 24 時間を指定しても実質 15 時間しか取得していなかった問題を修正
表示期間 LOOKBACK_HOURS をプロンプト、要約画像、保存統計へ反映 72 時間収集したレポートが 24 時間と表示される不一致を解消
空の収集結果 接続失敗、期間内の記事なし、情報源未設定を区別 no entry collected の原因をログから判断可能
一時設定 認証情報を除く設定を cli.py のオプションとして追加 .env を書き換えず、1 回だけ --lookback-hours 72 などを指定可能
要約画像 重要度の高い話題のカテゴリーを凡例に残す 長いカテゴリー名で先頭の凡例が消える問題を修正
画像処理 decompression bomb と判定された画像を生成カードへ置換 画像 1 件の拒否で日次バッチ全体が停止しない
再描画 収集時の期間を report.json に保存 後日の render でも元の収集期間を維持
HTTP ヘッダー 空の USER_AGENT を既定値として扱う USER_AGENT= による空ヘッダー送信を回避
文字描画 明示的な改行も行数上限へ含める カード内の文字が画像領域をはみ出す可能性を除去

前回の記事では v1.1 の API 互換性と外部入力の扱いまでを説明しています。今回の差分は、その後の日次運用で見つかった時刻、診断、描画、再実行の問題です。

v1.2 で変更したこと

分類 変更内容 実務上の影響
環境変数 ANTHROPIC_*OPENAI_*SUMMARIZER_* へ統一 v1.1 の .env は書き換えが必要
バックエンド名 claudeopenai をプロトコル名へ変更 anthropic-compatible または openai-compatible を指定
旧設定の扱い 廃止した変数が存在すると起動を拒否 .env だけでなくシェル、systemd、cron も確認が必要
API タイムアウト SUMMARIZER_TIMEOUT を追加 応答しない API が日次処理を長時間保持する状態を制限
既定値 MAX_OUTPUT_TOKENS=8000HTTP_TIMEOUT=60PORT=3000 値を固定していない環境では更新後の動作が変化
設定例 .env.exampleUSER_AGENT と 2 種類の互換 API 設定を追加 コピー元だけで必要な設定を確認可能
配備 doc/DEPLOYMENT.mddeploy/ を追加 Debian、cron、systemd、nginx、TLS、保守手順を一続きで確認可能
障害対応 終了コード、ログ、典型的な原因を README に追加 cron の失敗をログから切り分け可能
拡張 コレクター追加手順を文書化 新しい情報源を追加するときの変更箇所を明示

更新前に v1.1 の設定を退避する

以下は Debian 上の /opt/ai-digest に配備している例です。作業ディレクトリが異なる場合は読み替えます。

最初に、未コミットの変更と現在のバージョンを確認します。

cd /opt/ai-digest

git status --short
.venv/bin/python cli.py --version
git describe --tags --always

.env を退避します。

cp -p .env .env.before-v1.2
chmod 600 .env.before-v1.2

退避ファイルにも API トークンが含まれます。リポジトリへ追加せず、不要になった時点で削除します。

コードと依存関係を更新します。

git pull --ff-only
.venv/bin/pip install -r requirements.txt
.venv/bin/python cli.py --version

OpenAI 互換経路を使う場合は、openai パッケージも確認します。これは既定の requirements.txt には含まれていません。

.venv/bin/pip install openai

更新後のバージョン表示が 1.2 であることを確認します。

旧環境変数が残っている場所を確認する

v1.2 は旧変数の値を読み替えません。空文字列であっても、変数名が存在した時点で次のように停止します。

ANTHROPIC_API_KEY is no longer read by ai-digest; use SUMMARIZER_API_KEY.

この検査はバッチだけでなく viewer の設定読み込みでも行われます。日次実行だけを直して systemd 側へ旧変数を残すと、viewer も起動できません。

.env を確認する

値を表示せず、旧変数名だけを抽出します。

sed -nE \
  's/^(ANTHROPIC_[A-Z0-9_]+|OPENAI_[A-Z0-9_]+)=.*/\1/p' \
  .env \
  | sort

何も表示されなければ、.env 内には旧変数がありません。

現在のプロセス環境を確認する

env \
  | sed -nE \
      's/^(ANTHROPIC_[A-Z0-9_]+|OPENAI_[A-Z0-9_]+)=.*/\1/p' \
  | sort

表示された変数は、現在のシェルから解除します。

unset ANTHROPIC_API_KEY
unset ANTHROPIC_AUTH_TOKEN
unset ANTHROPIC_BASE_URL
unset ANTHROPIC_MODEL
unset ANTHROPIC_THINKING_MODE
unset ANTHROPIC_TOOL_CHOICE_MODE
unset ANTHROPIC_TEXT_JSON_FALLBACK
unset ANTHROPIC_MAX_RETRIES
unset OPENAI_API_KEY
unset OPENAI_BASE_URL
unset OPENAI_MODEL

unset は現在のシェルにしか効きません。ログインし直すと復活する場合は、.profile.bashrc.zshrc などの定義元も削除します。

grep -nE \
  '(ANTHROPIC_|OPENAI_)' \
  "$HOME/.profile" "$HOME/.bashrc" "$HOME/.zshrc" \
  2>/dev/null \
  || true

systemd と cron を確認する

標準の systemd ユニットは /opt/ai-digest/.envEnvironmentFile として読みます。独自の Environment= や別の設定ファイルを追加している場合は、そこにも旧変数が残っていないか確認します。

systemctl cat ai-digest
sudo -u ai-digest crontab -l

表示内容に認証情報が含まれる構成では、出力を端末外へ貼り付けません。

API 接続設定を SUMMARIZER_* へ移行する

v1.2 の接続設定は、利用する会社ではなく、要約処理が接続する 1 つのエンドポイントを表します。Anthropic 互換と OpenAI 互換を同時に設定して自動切り替えする設計ではありません。

旧変数と新変数の対応は次のとおりです[4]

v1.1 v1.2
ANTHROPIC_API_KEY SUMMARIZER_API_KEY
ANTHROPIC_AUTH_TOKEN SUMMARIZER_AUTH_TOKEN
ANTHROPIC_BASE_URL SUMMARIZER_BASE_URL
ANTHROPIC_MODEL SUMMARIZER_MODEL
ANTHROPIC_MAX_RETRIES SUMMARIZER_MAX_RETRIES
ANTHROPIC_THINKING_MODE SUMMARIZER_THINKING_MODE
ANTHROPIC_TOOL_CHOICE_MODE SUMMARIZER_TOOL_CHOICE_MODE
ANTHROPIC_TEXT_JSON_FALLBACK SUMMARIZER_TEXT_JSON_FALLBACK
OPENAI_API_KEY SUMMARIZER_API_KEY
OPENAI_BASE_URL SUMMARIZER_BASE_URL
OPENAI_MODEL SUMMARIZER_MODEL
SUMMARIZER_BACKEND=claude SUMMARIZER_BACKEND=anthropic-compatible
SUMMARIZER_BACKEND=openai SUMMARIZER_BACKEND=openai-compatible

Anthropic 互換 Messages API を使う

さくらの AI Engine を Anthropic 互換経路で利用する場合は、次のように設定します。

SUMMARIZER_BACKEND=anthropic-compatible
SUMMARIZER_API_KEY=
SUMMARIZER_AUTH_TOKEN=<UUID>:<シークレット>
SUMMARIZER_BASE_URL=https://api.ai.sakura.ad.jp
SUMMARIZER_MODEL=preview/Kimi-K2.6
SUMMARIZER_MAX_RETRIES=0
SUMMARIZER_THINKING_MODE=disabled
SUMMARIZER_TOOL_CHOICE_MODE=auto
SUMMARIZER_TEXT_JSON_FALLBACK=disabled
SUMMARIZER_TIMEOUT=180

SUMMARIZER_BASE_URL/v1/messages は付けません。Anthropic SDK が必要なパスを組み立てます。

SUMMARIZER_MAX_RETRIES=0 は、1 回の cli.py run を 1 回の API 要求に固定する設定です。通常運用で再試行が必要なら増やせますが、API 設定の確認中は 0 のほうが消費量と失敗回数を追跡しやすくなります。

OpenAI 互換 Chat Completions API を使う

OpenAI 互換経路では次のように設定します。

SUMMARIZER_BACKEND=openai-compatible
SUMMARIZER_API_KEY=<UUID>:<シークレット>
SUMMARIZER_AUTH_TOKEN=
SUMMARIZER_BASE_URL=https://api.ai.sakura.ad.jp/v1
SUMMARIZER_MODEL=<コントロールパネルで確認したモデル名>
SUMMARIZER_MAX_RETRIES=0
SUMMARIZER_TIMEOUT=180

こちらの SUMMARIZER_BASE_URL には /v1 が必要です。Anthropic 互換経路から切り替えるときは、SUMMARIZER_BACKEND だけでなく URL と認証変数も同時に変更します。

SUMMARIZER_API_KEYSUMMARIZER_AUTH_TOKEN は同時に設定できません。使用しない側は空にするか、行自体を削除します。

v1.1 から変わった既定値を確認する

値を .env で固定している環境では、その値が引き続き優先されます。既定値へ任せていた環境だけが更新後の値へ変わります。

設定 v1.1 v1.2 確認点
MAX_OUTPUT_TOKENS 4,000 8,000 出力上限を固定していない場合だけ増加
HTTP_TIMEOUT 15 秒 60 秒 feed、記事ページ、画像取得の待機時間が増加
SUMMARIZER_TIMEOUT なし 180 秒 要約 API だけを別枠で制限
PORT 5000 3000 viewer、gunicorn、nginx の接続先を確認

前回の記事に合わせて MAX_OUTPUT_TOKENS=16000 を設定していた場合、その値は v1.2 でも維持されます。今回 8,000 へ下げる必要はありません。

要約 API の最大待機時間を計算する

SUMMARIZER_TIMEOUT は API 要求 1 回ごとの上限です。再試行を含めた最悪待機時間は次の式になります。

最大待機時間 = SUMMARIZER_TIMEOUT × (SUMMARIZER_MAX_RETRIES + 1)

既定値では次のとおりです。

180 × (2 + 1) = 540 秒

9 分は日次 cron の間隔より十分短い一方、手動確認には長い場合があります。最初の確認では SUMMARIZER_MAX_RETRIES=0 とし、最大 180 秒に固定します。

viewer の接続先を 3000 番へ合わせる

v1.2 で追加された配備例は、gunicorn を 127.0.0.1:3000 で起動し、nginx から接続する構成です[5]

既存環境が 5000 番を明示している場合は、次のどちらかへ統一します。

  • .envPORT=5000 を維持し、既存の systemd と nginx を変えない
  • PORT=3000 へ変更し、gunicorn と nginx の接続先も 3000 番へ変える

設定を混在させると、gunicorn は起動しているのに nginx からは 502 Bad Gateway になります。

API を使わずに更新を確認する

本番の API 要求を送る前に、設定読み込み、単体テスト、保存、HTML、画像、viewer を確認します。

単体テストを実行する

cd /opt/ai-digest
.venv/bin/python -m unittest discover -s tests

このテストは API トークンもネットワーク接続も必要としません。旧変数が残っている場合は、設定読み込みの段階で失敗するため、移行漏れもここで検出できます。

一時ディレクトリで demo を実行する

demo は収集と API 要約を行わず、同梱サンプルから通常形式のレポートを生成します[6]。本番の DATA_DIR を汚さないよう、一時ディレクトリを指定します。

tmpdir=$(mktemp -d)

.venv/bin/python cli.py demo \
  --date 2000-01-01 \
  --data-dir "$tmpdir"

.venv/bin/python cli.py list \
  --data-dir "$tmpdir"

find "$tmpdir/2000-01-01" \
  -maxdepth 1 \
  -type f \
  -printf '%f\n' \
  | sort

rm -rf "$tmpdir"

少なくとも report.jsonindex.htmlsummary.png、話題ごとの画像が生成されれば、API より後ろの処理は動いています。

viewer のヘルスチェックを確認する

systemd の設定を更新した場合は再読込と再起動を行います。

sudo systemctl daemon-reload
sudo systemctl restart ai-digest
sudo systemctl status ai-digest
curl --fail --silent http://127.0.0.1:3000/healthz

期待する応答は次です。

ok

nginx の接続先も変更した場合は、設定検査後に再読込します。

sudo nginx -t
sudo systemctl reload nginx

さくらの AI Engine で 1 回だけ実行する

さくらの AI Engine を使うには、さくらインターネットの会員 ID と、さくらのクラウドのプロジェクトが必要です。さくらのクラウドは、会員登録だけでは料金が発生せず、サーバーやストレージなどのリソースを追加した時点から利用料金が発生するサービスです[7]

さくらの AI Engine は、GPU 基盤を自分で構築せずに複数のモデルを API から利用でき、OpenAI 互換 API と Anthropic 互換 API を提供しています。基盤モデル無償プランと従量課金プランがあり、利用中のプランが自動で別のプランへ切り替わることはありません[8]

基盤モデル無償プランでは、Chat Completions を毎月 3,000 回まで利用できます。上限を超えると従量課金へ自動移行するのではなく、レート制限がかかります。アカウントトークンは <UUID>:<シークレット> 形式で、作成後に再表示されません[9]

日次で 1 回実行し、再試行を 0 にした場合の月間要求数は次のとおりです。

1 要求 × 31 日 = 31 要求

既定の再試行 2 回が毎回すべて発生する最悪条件でも 93 要求です。ほかのアプリケーションと無償枠を共有していなければ、個人用の日次処理では回数を過度に気にせず試せます。

利用可能なモデルは固定ではありません。実行時点のモデル名は、さくらの AI Engine コントロールパネルの 利用可能なモデル で確認します[10]

バッチを手動実行する

サービスユーザーで 1 回だけ実行します。

sudo -u ai-digest sh -c '
  cd /opt/ai-digest &&
  .venv/bin/python cli.py run \
    --summarizer-max-retries 0 \
    --verbose
'

認証情報はコマンドラインへ書きません。ps から読めるため、.env またはプロセス環境だけに置きます。

成果物を確認する

sudo -u ai-digest sh -c '
  cd /opt/ai-digest &&
  .venv/bin/python cli.py list
'

当日分の保存先を確認します。

report_date=$(date -u +%F)
ls -1 "data/reports/${report_date}"

標準の保存先では、次のファイルが生成されます。

index.html
report.json
style.css
summary.png
topic-1.png

話題数や画像取得結果により、topic-2.png 以降や別の画像拡張子も追加されます。

cron、nginx、バックアップまで文書化した

v1.2 では、README に断片的に書いていた配備例を doc/DEPLOYMENT.md へまとめました[5]

標準構成では、処理を次のように分離します。

cron
  └─ cli.py run
       └─ DATA_DIR へ書き込み

nginx
  └─ gunicorn
       └─ app.py
            └─ DATA_DIR を読み取り

cli.py run は 1 日分を書いて終了します。viewer は保存済みファイルだけを読み、API を呼びません。そのため、当日のバッチが失敗しても前日のレポートは表示し続けます。

配備文書には次の作業も追加しています。

  • 非特権の専用ユーザー作成
  • .env の権限を 600 に設定
  • 06:30 に実行する cron 例
  • nginx と TLS の設定
  • Basic 認証、IP 制限、VPN による閲覧制限
  • API トークンの交換
  • バッチログの logrotate
  • DATA_DIR のバックアップ
  • Git の以前の版へ戻すロールバック
  • 失敗時の終了コードとログの読み方

日次レポートは、後から同じ内容を完全に再生成できません。feed の掲載内容は変化し、モデルの回答も同一とは限らないため、保存したい履歴は DATA_DIR 自体をバックアップします。

ai-digest の後に sizu-writer も作った

同じくさくらの AI Engine を使う小規模なアプリケーションとして、sizu-writer も作りました[11]

sizu-writer は短いメモを受け取り、しずかなインターネットへ貼り付けられる本文とタイトル候補を生成します。投稿先への自動送信は行わず、生成結果を人間が確認してコピーする設計です。投稿用の認証情報をアプリケーションへ渡す経路もありません。

API 接続は OpenAI 互換 Chat Completions を使い、接続先を明示し、1 操作を 1 要求に固定できます。ai-digest とは用途もリポジトリも別ですが、無償枠のある互換 API を、小さな個人用アプリケーションへ安全に組み込むという点は共通しています。

まとめ

v1.1 から v1.2 への更新では、次の順番で作業します。

  1. v1.1 の .env を安全な場所へ退避する。
  2. .env、シェル、systemd、cron から ANTHROPIC_*OPENAI_* を削除する。
  3. API 接続設定を SUMMARIZER_* へ移し、バックエンド名をプロトコル名へ変更する。
  4. MAX_OUTPUT_TOKENSHTTP_TIMEOUTSUMMARIZER_TIMEOUTPORT を確認する。
  5. 単体テストと一時 DATA_DIRdemo で、API を使わずに更新結果を確認する。
  6. SUMMARIZER_MAX_RETRIES=0 で 1 回だけ本番実行する。
  7. systemd、nginx、cron、ログ、バックアップの設定を確認する。

v1.1.1 では、Asia/Tokyo で収集期間が短くなる問題を直し、収集失敗の理由、一時的な設定変更、描画時の境界条件を確認できるようにしました。v1.2 では、API の接続先をベンダー名ではなく要約処理の設定として整理し、古い環境変数が別用途の認証情報を拾う余地をなくしました。

さくらの AI Engine の毎月 3,000 回の無償枠に対し、1 日 1 回の ai-digest は月 31 回です。本家 OpenAI や Anthropic の API キーを個人用アプリケーションへ追加せず、日次処理や文章生成を互換 API で試す用途には十分な余裕があります。

参考文献

公開日または更新日が表示されないサービスページは、2026-08-05 の参照日を記載しています。

  1. id774, ai-digest v1.1 をリリースして Anthropic 互換 API と外部入力の扱いを改善した(2026-08-03). https://qiita.com/ynakayama/items/beadd112dbf4788daa20
  2. id774, ai-digest Repository Version History(2026-08-05). https://github.com/id774/ai-digest/blob/master/doc/VERSIONS
  3. id774, AI 論文とニュースを日次でまとめる ai-digest を作った(2026-07-31). https://blog.id774.net/entry/2026/07/31/5164/
  4. id774, ai-digest .env.example(2026-08-05). https://github.com/id774/ai-digest/blob/master/.env.example
  5. id774, Debian Deployment(2026-08-05). https://github.com/id774/ai-digest/blob/master/doc/DEPLOYMENT.md
  6. id774, Demo mode(2026-08-05). https://github.com/id774/ai-digest/blob/master/doc/DEMO.md
  7. さくらインターネット, クラウドサーバーはさくらのクラウド(2026-08-05). https://cloud.sakura.ad.jp/
  8. さくらインターネット, さくらのAI Engine(2026-08-05). https://ai.sakura.ad.jp/sakura-ai/ai-engine/
  9. さくらインターネット, 利用手順(2026-05-20). https://manual.sakura.ad.jp/cloud/ai-engine/02-howto.html
  10. さくらインターネット, 操作ガイド(2026-07-15). https://manual.sakura.ad.jp/cloud/ai-engine/03-operation-guide.html
  11. id774, sizu-writer(2026-08-04). https://github.com/id774/sizu-writer
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?