Reyn が止まる理由を理解する¶
Reyn が実行を中断するときは、必ず次の 3 つのいずれかが原因です:
- ループ検知 — 同じことを繰り返している
- タイムアウト — 時間がかかりすぎている
- 予算超過 — トークン / USD の上限に達した
各カテゴリは独自の設定名前空間を持ち、エラーメッセージには「このキーを上げれば 継続できる」というヒントが組み込まれています。本ページは、止まる理由と設定キーの 対応関係をまとめます。
TL;DR: 統一された名前空間は、ループ / タイムアウトが
safety.*、 財務的な上限はcost.*です。
① ループ検知 — safety.loop.*¶
ループ検知は暴走的な繰り返しを捕まえる仕組みです。フェーズが永遠に再入する、 ルーターが何度もルーティングし直す、委譲チェーンが青天井に伸びる、など。 開発中に到達するのは正常です。本当に必要な反復数なら上限を引き上げ、 そうでないなら原因を調査してください。
| 上限 | 検出対象 | 既定値 | 設定キー |
|---|---|---|---|
| フェーズ訪問回数 | 1 スキル実行内で同じフェーズに入りすぎた | 25 | safety.loop.max_phase_visits |
| フェーズ内 act ターン数 | 1 フェーズ訪問内の LLM ↔ op の往復 | 10 | safety.loop.max_act_turns_per_phase (skill / phase frontmatter が優先) |
| 1 ターンあたりの router 呼び出し | 1 ユーザーターン内のルーター起動回数 | 3 | safety.loop.max_router_calls_per_turn (0 = 無制限) |
| エージェント委譲の深さ | user → A → B → C のチェーンが深すぎる |
3 | safety.loop.max_agent_hops |
| チェーン内スキル起動回数 | 同一スキルが同一チェーンで起動しすぎた | 無制限 | safety.loop.skill_calls_per_chain.hard_limit |
| チェーン内スキルトークン数 | 同一スキルが同一チェーンでトークンを使いすぎた | 無制限 | safety.loop.skill_tokens_per_chain.hard_limit |
エラーの例¶
Phase 'revise' reached max_phase_visits=25.
→ Raise safety.loop.max_phase_visits to allow more iterations.
修正の例¶
# reyn.local.yaml
safety:
loop:
max_phase_visits: 50 # フェーズあたり 50 回まで許可
max_router_calls_per_turn: 5
② タイムアウト — safety.timeout.*¶
タイムアウトは時間がかかりすぎているものを捕まえます。LLM 呼び出しが遅い、 委譲先が応答しない、フェーズが 1 時間動き続けている、など。本当に時間が 必要なら上限を引き上げ、そうでないなら原因を調査してください。
| 上限 | 検出対象 | 既定値 | 設定キー |
|---|---|---|---|
| LLM 1 呼び出し | 1 回の litellm.acompletion がタイムアウトを超えた | 60 秒 | safety.timeout.llm_call_seconds |
| LLM リトライ | 一時エラー時のリトライ上限 | 3 | safety.timeout.llm_max_retries |
| フェーズ wall-clock | 1 フェーズ訪問が時間予算を超えた | 無制限 (0) |
safety.timeout.phase_seconds |
| Chain 待機 | マルチエージェントの pending chain が委譲応答を待ちすぎた | 60 秒 | safety.timeout.chain_seconds (0 = タイムアウトなし) |
エラーの例¶
chain timeout: 1 delegate(s) (writer) did not respond within 60s.
→ Raise safety.timeout.chain_seconds to wait longer (0 = no timeout).
修正の例¶
③ 予算超過 — cost.*¶
予算上限は財務的なキャップ(トークン数、USD 額、日次 / 月次クォータ) です。
意図的に cost: 配下に残し、safety: には統合しません。運用者の感覚として、
ループ / タイムアウトは「上げるべき」ことが多いのに対し、予算は「調査するか
明示的に承認する」ことが多いためです。
| 上限 | 検出対象 | 設定キー |
|---|---|---|
| エージェントごとのトークン | 1 エージェントがトークン上限に達した | cost.per_agent_tokens.hard_limit |
| エージェントごとの USD | 1 エージェントが USD 上限に達した | cost.per_agent_cost_usd.hard_limit |
| 日次クォータ | 当日の合計が daily_tokens / daily_cost_usd を超えた |
cost.daily_tokens.hard_limit, cost.daily_cost_usd.hard_limit |
| 月次クォータ | 当月の合計が monthly_tokens / monthly_cost_usd を超えた |
cost.monthly_tokens.hard_limit, cost.monthly_cost_usd.hard_limit |
| レートリミット | モデルごとの requests-per-minute 上限 | cost.rate_limit_per_minute.<model> |
((chain, skill) ごとの起動回数 / トークン上限はループ検知側にあり、
safety.loop.skill_calls_per_chain / safety.loop.skill_tokens_per_chain
を参照してください — 上記 §① 参照。)
上限到達時のユーザー承認フロー (FP-0003)¶
(chain, skill) ごとの起動回数キャップは、即時拒否ではなく対話的な承認に 切り替えできます:
# reyn.local.yaml
safety:
loop:
skill_calls_per_chain:
hard_limit: 5
ask_on_exceed: true # ask_user 経由で問い合わせる
extension_calls: 3 # 承認時に +3 回付与
上限到達時に Reyn が 「Skill X が上限 5 回に達しました。+3 回追加で
継続しますか?」 と問います。承認は何度でも可能で、毎回 extension_calls
分だけキャップが拡張されます。
limit 到達時の挙動 (safety.on_limit)¶
既定の挙動: limit 到達時、 ask_user で user に延長を確認します
(= mode: interactive / ask_timeout_seconds: 0 — 無制限待機)。
拒否 / timeout / intervention surface 不在の場合は abort、 Reyn は
RunResult を返し、 status を loop_limit_exceeded /
phase_budget_exceeded / budget_exceeded のいずれかに設定し、
partial_data には最後に完了したフェーズの artifact (= 「今ここまでの
成果物」) を入れます。ヘッドレス path (= bus=None / 非 TTY stdin) は
intervention 不要に自動的に abort 経路へ短絡するので、 interactive
既定はどの環境でも安全です。
挙動は safety.on_limit.mode で変更できます:
# reyn.local.yaml
safety:
on_limit:
mode: interactive # 既定 — ask_user で user に確認、 承認時に limit 延長して継続
# mode: unattended # 到達時に abort (= CI / cron / スクリプト実行向けのオプトイン)
# mode: auto_extend # N 回まで自動延長、 それ以降は abort
auto_extend_times: 1 # auto_extend 時のみ参照
ask_timeout_seconds: 0 # interactive 時のみ参照; 0 = 無制限待機
| モード | 用途 |
|---|---|
interactive (既定) |
reyn chat / TUI / a2a session — user が到達可能で延長判断を返せる |
unattended |
CI / cron / スクリプト実行で human を待てない用途のオプトイン、 fail fast |
auto_extend |
信頼済みの長時間タスクで「N 回までは自動延長して良い」と分かっているとき |
各 limit がどの site で wiring されているか (FP-0005 Phase 2 — landing 完了):
| Limit | Site | モード挙動 |
|---|---|---|
safety.loop.max_phase_visits |
OSRuntime._enter_phase |
interactive / auto_extend |
safety.timeout.phase_seconds |
OSRuntime._check_phase_budget |
interactive / auto_extend |
safety.loop.max_act_turns_per_phase |
OSRuntime act-loop | interactive / auto_extend |
safety.loop.max_router_calls_per_turn |
ChatSession._check_and_increment_router_cap |
interactive / auto_extend |
safety.loop.max_agent_hops |
ChatSession._send_to_agent |
interactive / auto_extend |
safety.timeout.chain_seconds |
chain timeout watchdog | interactive / auto_extend (再 arm) |
safety.loop.skill_calls_per_chain |
spawn budget gate | interactive (= FP-0003 ask_on_exceed) |
safety.timeout.llm_call_seconds は設計上対象外です — litellm が
safety.timeout.llm_max_retries 内で自動再試行するため、 追加の
ask_user 層はレイテンシを増やすだけになります。