Implementing a retrospective agent: how it works

Alex O'Callaghan

ふりかえりエージェントの実装 — 仕組みの解説

前の記事では、なぜエンジニアリングの時間がどこに使われているかを計測しようとしているのか、そして小さなLLMエージェントがその計測をチームのスプリントレトロスペクティブにどう組み込めるかについて書きました。数か月が経ち、エージェントを各チームに展開したところ、これまで起きていなかった議論を生み出すきっかけになっています。

今回は、エージェントがどのように動き、どのようにデータを受け取り、プロンプトがどう進化してきたかに焦点を当てます。その土台となるデータプラットフォームや、DORAメトリクスの導出方法については、次回の記事で詳しく取り上げます。

概要

エージェントは、生産性メトリクスのデータプラットフォームからメトリクスとアクティビティデータを取得し、スプリントを要約して議論のたたき台を提示する、事前共有用のふりかえりレポートを生成します。

すべての生データをそのままモデルに流し込むのではなく、3スプリント分のメトリクス要約と、特定のチケットやマージリクエスト、失敗したリリースの詳細を調べるためのツールだけをエージェントに渡しています。

Metrics summary(sprint + 2 previous)AgentDetail: tickets, MRs,failed releasesRetro report(3-section markdown)always in the promptasks via 3 lookup tools

エージェントの設計

初期プロンプト

初期プロンプトでは、3スプリント分のメトリクスを要約し、それぞれに[BASELINE]または[LATEST - FOCUS SPRINT]というタグを付けて区別しています。メトリクスはJiraのデリバリーとDORAメトリクスで構成されています。

DORAメトリクスJiraメトリクス
デプロイ頻度課題およびストーリーポイントの完了率
変更のリードタイム(コーディング+レビュー+デプロイ)コミットしたスコープとスプリント途中で追加されたスコープ
変更失敗率キャリーオーバー
サービス復旧時間サイクルタイム

すべてのメトリクスはデータプラットフォーム側で決定的なコードによって算出しており、モデルに生データから計算させようとはしていません。プロンプトでもこの点は明示しています。「メトリクスの要約が正とします。再計算したり疑ったりしないでください」と。

要約には、サイクルタイムやリードタイムが75パーセンタイルを超えるなどの外れ値となったチケットやマージリクエストの一覧、そして注目スプリントで発生した失敗リリースの一覧も含まれています。エージェントには、これらのリストを分析の起点として使うよう指示しています。チケットは文中でKEY (16.8d, 3.0SP)のように、マージリクエストはproject!iid (308.7h: coding 116.3h, review 170.0h, deploy 22.4h)のように表記されます。

参照ツール

PydanticAIエージェントには、詳細を参照するための3つのツールが登録されています。

@agent.tool
def lookup_jira_ticket(ctx: RunContext[AgentDeps], ticket_key: str) -> str:
    """Look up a Jira ticket by its key (e.g. PROJ-1363).

    Returns summary, status, assignee, story points, sprint, dates, cycle time,
    and full status transition history.
    """

@agent.tool
def lookup_merge_request(ctx: RunContext[AgentDeps], query: str) -> str:
    """Search merge requests by title substring, Jira key, or MR reference (e.g. !1049).

    Returns up to 10 matching MRs with title, author, dates, lead time, and release info.
    """

@agent.tool
def lookup_failure(ctx: RunContext[AgentDeps], query: str) -> str:
    """Search detected failed releases by tag, project name, evidence, or alert tiny id.

    Returns up to 10 matching failures with signal (alert/revert), evidence,
    resolution time, and correlated alert detail where available.
    """

docstringはモデルが推論する際のスキーマを兼ねており、返されるペイロードがエージェントが物語を組み立て始める材料になります。チケットはstatus_history全体が読みやすいチェーンとして返されるため(例:「In Progress → Code Review → Awaiting Release → Done」)、「Blocked」に出入りを繰り返したチケットなどを特定しやすくなります。マージリクエストはコーディング/レビュー/デプロイの時間内訳と、それをリリースしたリリース情報とともに返されるため、マージリクエスト間の共通パターンやリリースサイクルへの影響を把握するのに役立ちます。

システムプロンプトでは、エージェントにこれらのツールを積極的に使うよう促しています。「これらのツールは積極的に使ってください……結論を出す前に調べてください」と。

出力の構造

エージェントの出力タイプはプレーンな文字列で、構造化された出力スキーマも後処理もありません。レポートの形を決めているのは、プロンプトのタスク定義だけです。すなわち、最新スプリントの簡潔な要約、ベースラインと比較した2〜4つの注目すべきトレンド(「良い点も悪い点も」)、そして3〜5つの具体的な話し合いの叩き台やディスカッション用の問いを、Sprint Summary、Notable Trends、Retrospective Talking Pointsという3つの必須見出しのもとにまとめる、という定義です。

トレンドを2〜4つ、話し合いの叩き台を3〜5つと数を絞らせることで選択を促し、第3セクションを結論ではなく問いとして構成することで、レポートが判定ではなく事前共有資料であり続けるようにしています。トレンドをどう解釈し、どう対応するかは、文脈をすべて持つチームに委ねられています。

典型的な実行例

典型的な実行例を紹介します。要約では11件のチケットとマージリクエストが挙げられ、エージェントは必要な詳細を得るために11回の参照を並列で実行しました。レポートは1回のLLM呼び出しで生成され、出力は3セクション構成のMarkdownレポートでした。

Metrics summaryAgentLookup tools3 sprints of metrics - 11 tickets & MRs namedlookup_jira_ticket ×8 (outliers, carry-overs, addition)lookup_merge_request ×3 (the p75 MRs)status histories, lead-time legswrites the three-section reportMetrics summaryAgentLookup tools

参照によってレポートにはより深い詳細が加わりました。サイクルタイムが最悪だった外れ値(16.8日)は、2スプリントにまたがっていたことが分かり、そのマージリクエストは最初のコミットからリリースまで308.7時間(内訳はコーディング116.3時間、レビュー170.0時間、デプロイ22.4時間)を要していました。別のマージリクエストは99.7時間のうち99.5時間をレビューに費やしていました。

レポートでは、ボトルネックはデプロイではなくレビューの遅延(中央値58時間で、前スプリントの約3倍)であると特定し、議論すべき具体的なチケットやマージリクエストを指摘できました。また、リリース数が23から6に減る一方で変更失敗率が8.7%から0%に改善したことも取り上げ、流れの鈍化が意図的なリスク管理によるものなのか、それとも単に変更がレビュー待ちで滞留しているだけなのか、という問いを投げかけました。

実行全体ではLLMの呼び出しは2回で、入力トークンは約11,400(2回目の呼び出しの3分の1はキャッシュ読み取り)、出力は2,200トークンでした。執筆時点のGPT-5.4のAPI価格では、およそ0.05ドルで、その大半は出力トークンによるものです。

実践におけるプロンプトエンジニアリング

エンジニアの名前は出さない

初期のプロトタイプでは、エージェントが進行の遅いチケットについて語る際に、しばしばエンジニアを名指ししていました。非難のないふりかえりの場を保つため、これを避けるガードレールをプロンプトに追加しました。エージェントには、個人のパフォーマンスではなく、チーム全体のトレンドや作業そのものに焦点を当てるよう指示しています。

これは決定的な評価処理でも担保しています。評価では入力からすべての担当者とマージリクエストの作成者を抽出し、出力にそれらが含まれていれば失敗とします。プロンプトと評価を組み合わせることで、このルールを徹底しています。

スキーマもプロンプトの一部

エージェントはフィールド名をもとに推論するため、命名は重要です。初期バージョンでは、Jiraのstatus_categoryフィールドに基づいてチケットのステータスや完了したかどうかを誤判定していました。チケットのスキーマにis_doneという真偽値を追加することでこの問題を解消しました。曖昧なフィールド名や値をモデルに解釈させるのではなく、決定的なロジックとデータ構造で意味をエンコードしたのです。

指示よりも構造

プロンプトでは「hypothesis」という言葉を一度も使っていませんが、実際のアウトプットは仮説そのものです。第3セクションは結論ではなく、話し合いの叩き台と問いかけで構成されています。ふりかえりは人が主導すべきものであり、そのことをモデルに覚えさせようとするのではなく、レポートのフォーマット自体にその思想を埋め込んでいます。

当初のプロンプトでは主要メトリクスを一目で分かる要約テーブルとしても求めていましたが、モデルは毎回異なる形式の要約を生成していました。エージェントを囲むWeb UIを構築することで、この要約テーブルは生成された文章の横に並ぶ決定的なコンポーネントになりました。毎回同じであるべき出力があるなら、LLMに生成させてはいけません。

おわりに

ふりかえりエージェントは、私たちのチームにとって小さくても有用なツールであり、エンジニアリングのふりかえりで議論や内省を促すきっかけになっています。プロンプトエンジニアリングと参照ツールの活用によって、チームのダイナミクスを尊重し、実行可能な洞察に焦点を当てた価値あるAIアシスタントを作れることを示す例でもあります。

その有用性の大きな部分は、土台となるメトリクスのデータプラットフォームが担っており、エージェントが推論の拠り所とする信頼できるデータを提供しています。そこでは、どのメトリクスを追うか、開発ワークフローからどう算出するかについて、慎重な選択が求められます。次回の記事では、そのプラットフォームがどのように動いているのか、DORAメトリクスをどう導出しているのか、そしてそれらがどのように連携してエンジニアリングチームを支えているのかを掘り下げます。

原文は Alex O'Callaghan により に公開されました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。