現場のシフト作成って、地味に時間が溶けます。
「希望は通したい」「でも上限回数は守らないといけない」「曜日や時間帯も人によって違う」——この調整を毎月手作業でやるのは、正直つらい。
そこで今回は、Difyのチャットフロー + Codeノード(Python)を使って、月間シフト表を自動生成するアプリを制作しました。
個別条件の多い現場でも回せるように、LLMだけに頼らず、“制約はコードで守る”設計にしています。
どんなシフトを作るアプリ?
シフトの前提
- 1か月単位で作成(例:2026-03)
- 1日の枠は short / long / stay(泊まり) の3種類
- 日ごとに「日タイプ」があり、タイプによって必要枠が変わる
- weekday(平日):short / long / stay
- sunday(日曜):short / long / stay
- holiday(祝日):short / long / stay
- saturday_p1(土曜P1):short / stay
- saturday_p2(土曜P2):short / long / stay
守るべき制約(ハード)
- 月上限:最大4回(個別上限があればそちら優先)
- 週上限:1人1回まで(week_id基準)
- 同日同職員の重複なし
- 「入れない(日付 / 曜日 / 日タイプ / stayのみ)」を厳守
- 「許可枠(allow_slots)」と「許可日タイプ(allow_types)」を厳守
(例:平日shortのみ、日祝longのみ…など)
希望の扱い(ソフトとハード)
- 希望は2段階にしました
- 希望(hard):できれば必ず入れたい(ただし固定枠や制約で不可能な場合は未達として出す)
- 希望(soft):入れられたら嬉しい
なぜLLMだけだと崩れるのか?
最初は「LLMに全部割り振らせる」方針も検討しましたが、実運用では以下が起きがちでした。
- 月上限4回が守られない
- 逆に怖がって全員0回みたいな結果が出る
- hard希望が入っているのに割り当てられない
- 途中の手順を説明する文章が長くなり、出力が読みづらい
つまり、LLMは“方針”は強いけど、厳密な回数制限や探索(入れ替え調整)が苦手です。
そこで、LLM=カレンダー生成 / コード=割当ロジックで役割分担する形に切り替えました。
仕組み:Difyチャットフローでの構成
今回のフローは大きく2段階です。
① LLM①:対象月のカレンダー(枠一覧)を作る
ユーザーが入力した対象月と「日別区分(weekday / holiday…)」をもとに、
- date(YYYY-MM-DD)
- slot(short/long/stay)
- day_type
- weekday(mon..sun)
- week_id
をTSVで出力します。
この段階では「割当」はしません。
**“候補となる枠一覧(カレンダー)を整形して作る”**のが役目です。
② Codeノード:固定枠の除外 → 割当 → 仕上げ調整(swap)
次に、Codeノード(Python)が以下を行います。
- 固定枠TSVの(date,slot)を候補から除外
(固定枠は既に確定している前提) - 希望(hard)を最優先で割当
ただし上限・週上限・禁止条件に反する場合は未達として記録 - 希望(soft)を割当
- 残り枠を公平に割当(0回救済を含む)
- それでも空欄が残る場合
swap(入れ替え)探索で空欄を減らす
→ “空欄を直接埋める”のではなく、
埋められる人を別枠から解放して埋める、という調整
入力はTSVで統一(現場運用しやすい)
入力はすべてTSVにしています。
Excelで管理している現場が多いので、TSVにすると運用が簡単です。
- 職員TSV(希望・NG・上限・許可枠など)
- 固定枠TSV(候補から除外する枠)
- カレンダーTSV(LLM①の出力)
出力は「TSVと回数だけ」に絞る
運用で欲しいのは結局ここだけです。
- シフト案TSV
日付 / 枠 / 担当者 - 職員ごとの割当回数(0回も含める)
- hard未達がある場合だけ、そのリスト(理由付き)
長い説明文は出さず、現場で使いやすい出力に寄せています。
使ってみて良かった点
- 制約(回数・週上限)が安定して守れる
- hard希望の扱いが明確(無理な場合は未達として出る)
- 0回が大量発生しにくく、分配が改善
- 固定枠を「候補から外す」運用が可能で、現場ルールに合わせやすい
今後の改善予定
現場運用を想定すると、次の改善が効きそうです。
- **枠別の上限(例:shortは月2回まで)**を列として追加
- hard希望未達の理由をもう少し具体化
(固定枠で消えている / allow_slotsで不可 / 週上限で不可 など) - 出力をそのまま貼れるように
**“日付×枠の表形式”**にも対応(必要なら)
まとめ:AI+ルールで「現実的に使える自動シフト」へ
今回のポイントは、「LLMに全部任せない」ことでした。
- LLM:カレンダー整形、入力の解釈
- コード:制約を厳密に守る割当、入れ替え調整
この役割分担にすることで、精度と再現性が一気に上がりました。
もし同じように、
「毎月の調整が大変」「人別の制約が多い」「手作業が限界」
という業務があれば、Dify+コードの組み合わせはかなり相性が良いと思います。
