AIに手順を考えさせるデモが動いても、そのまま仕事を任せられるとは限りません。途中で止まった処理を再開したら、同じメールを二通送った。古い資料の指示を信じて、予定にない操作を始めた。開発では、回答の出来と同じくらい、行動できる範囲と止まる条件が重要です。
この記事は、最初のAIエージェントを設計する開発担当者向けです。Pythonの関数と辞書、APIの基本を前提に、LangChainを例として入力・ツール・承認・状態・運用をつなぎます。基礎の位置づけはAI・LLMの学び方から確認できます。
30秒で要点
- エージェントは、モデルが次の処理やツールを選ぶ仕組み。決められた手順で足りるなら、固定したワークフローも選択肢です。
- 実行する側で入力、権限、承認、重複、上限を確認します。プロンプトに「安全に」と書くだけでは境界になりません。
- 下のコードは固定応答による動作確認です。実モデルの品質、外部APIとの接続、本番の復旧は別に検証します。
どこから読むか — 自分の状況から選ぶ
この記事はツール・承認・状態・停止の設計を扱います。選定、事故の読み方、権限の線引きはそれぞれ別の記事にあります。
まず何を選ぶかで迷っている。 基盤の比較はAntigravity・Cowork・Codex比較ガイド、選定の軸がモデルから移った話は「何に繋がっているか」へ、ベンチマークをどこまで信じるかはスコアをどこまで信じるかと「最強のモデル」は「最良のアシスタント」ではない。
本番で期待どおり動かない。 乖離の構造はベンチマーク9割、本番6割、効果が出ないときの型は3つの失敗パターン、並列化しても分散しない理由は30体中18体が同じ判断をした理由、再現性の定義はtemperatureを0にしても出力は一致しない。
権限と承認の線を引きたい。 権限の外側に近道を見つけた事件は導入判断に足すべき確認軸、承認をどこに置くかは承認ポイントの設計、資格情報から身元への転換はOkta Agent SSOが示した設計変更。
セキュリティの優先順位を決めたい。 事故記録の分布から順番を考えるなら入力ではなく権限だった、経営と実装の境界はIPAとOWASP、2つの脅威指標、言説の出どころの確かめ方はExcessive Agencyは本当に3位なのか。
人の判断への影響が気になる。 偏りの引き継ぎは人間の認知バイアスを引き継いでいないか、開発者側の歪みは認知バイアス15分類の実態調査。
実装の入口を探している。 フレームワークはLangChain入門、対話設計はAIチャットボットの設計思想、ベンダー発表の扱いはどこまでを契約判断に使えるか。
チャット、ワークフロー、エージェントを分ける
チャットは、対話する画面や入出力の形です。その裏では、単発のモデル呼び出し、決まった処理順、モデルが次の行動を選ぶループのいずれも使えます。「チャットボットだから質問にしか答えない」「エージェントだから人の介入がない」という区別はできません。
例えば、決まったCSVの合計を毎日集計する処理は、通常のプログラムで十分かもしれません。一方、調査中に不足を見つけて検索語を変える処理には、モデルが次の手順を選ぶ余地があります。ただし、その自由度は入力の揺れへの対応と引き換えに、実行経路の確認を難しくします。LangChainのAgents仕様は、モデルと実行を支える仕組みを組み合わせる構造を示しています。
表が収まらない場合は、横にスクロールできます
| 構成 | 手順を決める主体 | 最初に確認すること |
|---|---|---|
| 固定ワークフロー | 開発者が決めた分岐や順序 | 入力の形式と例外処理で足りるか |
| ツールを使うエージェント | 許可された範囲でモデルが選択 | 道具を誤選択しても影響を抑えられるか |
| 複数エージェント | 役割別のモデルと制御処理 | 引継ぎで何が失われ、責任がどこに残るか |
複数に分けること自体が品質向上の証拠にはなりません。まず一つのタスクで失敗を観察し、分離する理由が具体的になってから構成を増やします。
タスクを、入力と受入条件まで分解する
「記事を作成して公開する」は広すぎます。本記事で提案する分け方は、資料の収集、根拠の抽出、下書き、検証、公開という工程ごとに、受け取るものと完了条件を書くことです。検索結果の取得と本文の読了、下書きの生成と内容の確認、公開候補の準備と公開の実行は、それぞれ別の状態にします。
表が収まらない場合は、横にスクロールできます
| 設計欄 | 調査レポートを作る場合の記入例 |
|---|---|
| 入力 | 対象の問い、対象期間、参照を許可する資料 |
| 出力 | 主張、根拠URL、読んだ範囲、未確認事項を持つ下書き |
| 完了 | 指定した問いに答え、根拠に戻って確認できる |
| 保留 | 一次資料へ到達できない、資料間に矛盾がある |
| 実行権限 | 許可した資料を読む。公開や外部送信は別の実行経路 |
完了を「文章が返った」と定義すると、誤りのある下書きまで成功に数えます。利用者が何を受け入れるかを先に決めると、モデルの評価も運用の指標もそろえられます。
ツールの入口で、実行できることを狭める
ツールは、モデルの外にある処理を呼ぶ窓口です。検索、計算、ファイル操作、データベースの参照などを関数として渡します。公式Toolsガイドでは、型と説明を持つ関数や入力schemaを登録できます。
ただし、型が合うことと、実行してよいことは別です。注文番号が文字列でも、別の顧客の注文を読んでよいとは限りません。モデルが生成した値も、取得したページ中の文章も、実行側が検証する入力として扱います。
- 引数:型、長さ、数値の範囲、許可対象を確認する。
- 権限:ログイン中の利用者や案件に対して、その対象を扱えるか照合する。
- 作用:読む道具と、更新・送信する道具を分ける。
- 失敗:未実行、失敗、結果不明を区別する。例外を隠して成功と返さない。
計算のために、モデルの出した文字列をそのまま eval() へ渡す必要はありません。数値二つの掛け算なら、二つの整数だけを受け取る方が、許可した操作を確認しやすくなります。式を自由に受け取る設計では、許可する構文に加えて入力長・深さ・計算量も別に制限します。
固定した環境で、一本の流れを動かす
以下は2026年10月4日に確認した配布版で動かす、外部通信のない検査例です。Python 3.10以上4未満が必要で、実検証にはPython 3.12.14の隔離環境を使いました。新しい作業用フォルダで仮想環境を作り、その環境のPythonで次を実行します。ほかのアプリの依存関係と混ぜないでください。
python -m pip install "langchain==1.4.3" "langchain-core==1.6.6" "langgraph==1.2.12"
python -m pip check
python -m pip freeze > tested-requirements.txt
配布版はlangchain、langchain-core、langgraphのmetadataと照合しました。上の指定は主要依存の固定です。再現するには、実際に解決された推移依存も pip freeze の結果とPythonの版で保存します。
次を agent_demo.py として保存し、同じ環境で python agent_demo.py を実行します。APIキーは使いません。説明のために、モデルの返答を二つ先に決めています。
from pydantic import BaseModel, Field
from langchain.agents import create_agent
from langchain.tools import tool
from langchain.messages import AIMessage
from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
from langgraph.checkpoint.memory import InMemorySaver
class MultiplyInput(BaseModel):
a: int = Field(strict=True, ge=-10000, le=10000)
b: int = Field(strict=True, ge=-10000, le=10000)
@tool(args_schema=MultiplyInput)
def multiply(a: int, b: int) -> str:
"""範囲内の整数二つを掛け算する。外部への書き込みはしない。"""
return str(a * b)
class DemoModel(GenericFakeChatModel):
def bind_tools(self, tools, **kwargs):
# テスト専用。道具を選ぶ推論はせず、下の固定応答を返す。
return self
model = DemoModel(messages=iter([
AIMessage(content="", tool_calls=[{
"name": "multiply", "args": {"a": 6, "b": 7}, "id": "demo-call-1"
}]),
AIMessage(content="計算結果は42です。"),
]))
agent = create_agent(
model=model,
tools=[multiply],
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "demo-1"}, "recursion_limit": 10}
result = agent.invoke(
{"messages": [{"role": "user", "content": "6と7を掛けてください。"}]},
config=config,
)
tool_results = [m.content for m in result["messages"] if m.type == "tool"]
assert tool_results == ["42"]
print(tool_results[0])
確認できるのは、入力の messages からツール呼び出しに進み、実際の計算結果が履歴に入り、応答で終わる経路です。最後の回答文も固定されているため、この例は「AIが掛け算を理解した」という検証ではありません。道具の選択と文章の推論を調べるときは、模擬モデルを実モデルに置き換えた別の評価が必要です。公式の単体テスト方針も、この区別を前提にしています。
新しいコードでは from langchain.agents import create_agent を使い、入力は状態の辞書で渡します。古い記事の initialize_agent、AgentExecutor、{"input": ...} と、現行の create_agent の使い方を一つの例に混ぜないでください。公式移行ガイドで、使用中のAPIと依存を対応付けます。レガシーコードを維持する判断と、新規コードの入口を選ぶ判断は分けます。
実モデルに接続する前にそろえるもの
例えばOpenAI連携では、別パッケージの langchain-openai と langchain_openai.ChatOpenAI を使います。確認した配布版は1.6.7です。公式連携ガイドに従い、利用可能なtool calling対応モデルのID、APIキー、課金上限、タイムアウト、再試行回数を設定します。キーはコードや実行ログへ書かず、実行環境から渡します。
本記事の確認は、固定版のimportと構築、模擬応答でのツール経路までです。実モデルのAPI呼び出しは行っていません。モデル側の引数制限やアクセス権、料金、応答品質は、導入する環境で確かめます。同じ質問でも応答が変わる可能性を含め、通常例と例外例を残して評価してください。
会話の記憶、承認、再実行を別々に設計する
状態の保存は、何を覚えるかから決める
例の thread_id は、会話や実行を区別するIDです。保存機構であるcheckpointerが、そのthreadの状態を記録します。別threadを混ぜないため、利用者が他人のIDを指定して読めないよう、アプリ側で対応付けと権限を確認します。
InMemorySaver は試作向けのメモリ上の保存です。プロセスを再起動すると状態は失われます。Persistence仕様は、threadごとのcheckpointerと、threadをまたいで情報を持つstoreを区別しています。会話の保存期間、削除、アクセス制御、機微なデータの扱いも、永続保存先を選ぶ際の条件です。
承認は、実行する内容に結び付ける
Human-in-the-loopの仕組みを使うと、指定したツールを実行前に止め、承認や拒否を受けて再開できます。本記事では、操作名だけでなく対象・引数・依頼IDを表示し、その組み合わせへの承認として記録する設計を勧めます。承認後に送信先や金額が変われば、同じ承認を使い回しません。承認待ちが長くなれば、参照した在庫や権限が変わることもあります。再開時に期限と対象の状態を再確認し、拒否や期限切れを「完了」に数えないようにします。承認者を認証する画面や、承認の保存は、ミドルウェアを追加するだけで完成するものではありません。
再開しても、外部操作を二重にしない
Interrupts仕様では、中断から再開すると、そのnodeの先頭から処理が再実行されます。中断前にメールを送る実装なら、再開で送信処理が繰り返され得ます。外部操作は承認の確認後に置き、業務上の一つの依頼を識別するキーを使って実行結果を照合します。送信先APIに重複排除の機能があるか、結果不明時に照会できるかも確認します。「会話を保存したから一回だけ実行される」とは考えません。結果が不明な操作を、成功か失敗か決めずに自動再送することが、二重処理の入口になります。
止まる理由を記録してから、運用へ進む
例の recursion_limit はグラフのステップ上限です。実時間、請求額、ツール回数の上限と同じではありません。運用では、モデル呼び出し回数、ツールごとの待ち時間、全体の期限、予算を別に管理します。上限で止めた処理は成功扱いにせず、利用者へ未完了の範囲を示します。停止しても、すでに起きた外部作用が取り消されるわけではありません。
リサーチ、タスク管理、データ分析への応用では、境界を次のように具体化できます。
表が収まらない場合は、横にスクロールできます
| 用途 | 許可する作業の例 | 人へ戻す条件の例 |
|---|---|---|
| リサーチ | 許可した情報源を読み、出典付き下書きを作る | 根拠不足、資料の矛盾、公開判断 |
| タスク管理 | 対象案件の一覧を読み、更新案を作る | 担当者変更、期限変更、重複依頼 |
| データ分析 | 読取専用の集計、定義済み指標の計算 | 個人情報、因果の解釈、元データの更新 |
参照型の仕組みはRAGの設計、人への引継ぎはAIと人間の分担につながります。
指標の分母を固定する
仮想の検査20件で、受入条件を満たしたものが16件なら成功割合は16÷20=80%です。この数値は例であり、普遍的な目標値ではありません。残り4件を保留・失敗・結果不明に分け、失敗の重大さも記録します。
ツールが合計50回呼ばれたなら、20件あたりの平均は50÷20=2.5回/件です。「使用率250%」という名前より、回数と単位を明示する方が誤解を減らせます。費用も全試行の総額と、受入件数あたりの額を分け、やり直しを計上します。
最小の検証は、掲載例を一度動かした後に、整数の範囲外、文字列、未登録ツールを入れることです。次に承認拒否、同じ依頼の再送、途中停止からの再開を試し、「動く」だけでなく「実行しないはずの操作が実行されない」を確認します。模擬テストを通した段階と実モデルの評価を通した段階を分ければ、次に何が未確認なのかを判断できます。
参考資料・引用元
本記事は2026年10月8日に以下の一次資料を再読し、記述を確認しています。
- LangChain Agents / Tools / Human-in-the-loop — 型ヒントがツールの入力スキーマを作り、HITL middleware は実行前に割り込む
- LangGraph Persistence — 再開にはチェックポイントが必要。チェックポイントには保持期間と削除方針を設ける
- OpenAI 評価のベストプラクティス — 実業務の分布に合わせたタスク固有評価、ログ、人の採点との調整、継続評価を勧めている。複数エージェント化は評価で必要性を確認してから進める
- NIST AI 600-1. https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.600-1.pdf