🤖

Cline の動作原理を追う

2025/01/02に公開

はじめに

Cline を使う機会が多くなってきたため、理解促進のために主要な部分の説明やプロンプトの翻訳を試みました。一度でも Cline を利用したことがある方を読者として想定しています。v3.0.0 を対象として説明します。

https://github.com/cline/cline

1. Cline の概要

Cline は、エンジニア的な知識をもったエージェントとして、ユーザーのワークスペース(現在のディレクトリやエディタの状態など)を確認しながら、各種ツールをユーザー承認ベースで順次呼び出します。ユーザー(ヒューマン)とのやり取りを大切にしつつ、自動化できる部分はエージェントが担う “human in the loop” 方式が特徴です。

2. Cline の処理の流れ

Cline は以下のような流れで実行されます。
Flow chart は 説明のために簡易に書いており、厳密ではありません。

各ノードの説明

  • インスタンス生成: new Cline(…)
    • Cline クラスのコンストラクタが呼ばれ、必要な下準備を行います。
  • 履歴がある?
    • 過去のタスク履歴 ( historyItem ) が存在するかを判定します。
  • タスク再開: Cline.resumeTaskFromHistory
    • 既存の履歴がある場合は、前回の状態からタスクを再開します。
  • タスク開始: Cline.startTask
    • 新規タスクの場合はここから開始します。
  • タスクループ開始: Cline.initiateTaskLoop
    • タスク処理を継続的に進めるための主ループです。
  • APIリクエストとツール実行のループ: Cline.recursivelyMakeClineRequests
    • タスクの実行サイクル:モデルへの問い合わせ、ツール呼び出し、結果確認、次ステップへの進行などを再帰的に行います。
  • ユーザー入力や履歴の前処理&エディタの環境取得: Cline.loadContext
    • ユーザーからの入力テキストなどを解析し、VSCode の環境情報を取得します。
  • API呼び出し: Cline.attemptApiRequest
    • 実際に LLM などのモデルに対して問い合わせを行い、ストリーミングの形で応答を受け取ります。
  • アシスタント応答の処理: Cline.presentAssistantMessage
    • モデルからの応答を段階的にパースし、ツール呼び出しや出力テキストを可視化・実行します。
  • ツール呼び出し?
    • 応答にツール呼び出しが含まれているかどうかを判定します。
  • 各ツールの実行 (Cline.executeCommandTool, browserSession など)
    • 応答に含まれたツールを実際に実行し、その結果を取得します。
  • ユーザーとやり取り: Cline.say / Cline.ask
    • 実行結果をユーザーに表示したり、ユーザーの承認やフィードバックを求めるフェーズです。
  • タスク継続 or 完了判断
    • タスクをさらに続行すべきか、それとも完了するかを判断します。
  • 終了
    • タスクを終了します。

提供される各ツール

“各ツールの実行“の中では以下のツールが提供されています。

  1. execute_command
    CLI コマンドを実行します。

    • <command>: 実際に実行するコマンド文字列
    • <requires_approval>: “true” or “false” で、ユーザーの承認が必要かどうかを指定します。
  2. read_file
    指定したファイルの内容を読み取るツールです。

    • <path>: ファイルパス
  3. write_to_file
    ファイルに新規作成または上書きで内容を書き込みます。

    • <path>: ファイルパス
    • <content>: 書き込む内容 (ファイル全体)
  4. replace_in_file
    既存ファイルの一部を差し替えるツールです。

    • <path>: ファイルパス
    • <diff>: 検索文字列と置換文字列のペアを、特定のフォーマットで記述したブロック
  5. search_files
    指定フォルダ以下のファイルに対して正規表現検索を行います。

    • <path>: ディレクトリパス
    • <regex>: 検索に使う正規表現
    • <file_pattern>: 検索対象ファイルを絞るための glob パターン (省略可)
  6. list_files
    指定したディレクトリの内容を一覧表示します。

    • <path>: ディレクトリパス
    • <recursive>: 再帰的にリストするかどうか (省略時はトップレベルのみ)
  7. list_code_definition_names
    指定ディレクトリ内のトップレベルにあるソースコードの定義(関数やクラス等)を一覧表示します。

    • <path>: 対象ディレクトリパス
  8. browser_action (ブラウザ操作がサポートされている場合)
    Puppeteer を使ってブラウザを操作します。

    • <action>: (launch, click, type, scroll_down, scroll_up, close) いずれか
    • <url>: launch 時に開く URL
    • <coordinate>: click で指定する座標
    • <text>: type で入力するテキスト
  9. use_mcp_tool
    外部 MCP サーバーが提供するツールを呼び出します。

    • <server_name>: MCP サーバー名
    • <tool_name>: ツール名
    • <arguments>: JSON 形式で引数を指定
  10. access_mcp_resource
    外部 MCP サーバーで管理されているリソースを取得します。

    • <server_name>: MCP サーバー名
    • <uri>: リソースの URI
  11. ask_followup_question
    不明点や追加情報が必要な場合に、ユーザーへ質問を行います。

    • <question>: 聞きたい質問内容
  12. attempt_completion
    タスクが完了したときに最終的な結果を提示するためのツールです。

    • <result>: タスクの最終結果を説明する文字列
    • <command>: (オプション) 結果を確認するためのコマンド

Cline.say と Cline.ask の違い

Cline.say
Cline 側からユーザーに「情報を提示する」ためのメソッドです。ユーザーの承認を必要としない単純な出力や通知に使います。
「ツールの実行結果をユーザーに見せるだけ」の場合に利用します。

Cline.ask
Cline 側からユーザーに「確認や選択を求める」ためのメソッドです。承認ボタンなどが含まれる UI が提示され、ユーザーに Approve/Reject またはメッセージの入力などを促せます。

3. prompt の日本語訳

以下は、Cline が参照する SYSTEM_PROMPT の大まかな日本語訳です。
SYSTEM_PROMPT の主要部分をChatGPTで翻訳しています。

あなたは Cline という、高度なソフトウェアエンジニアです。プログラミング言語、フレームワーク、デザインパターン、ベストプラクティスに精通しており、多彩なタスクに対応できます。

ツールの使用 (TOOL USE)
ツールをユーザー承認のもとで 1 度のメッセージにつき 1 つだけ呼び出すことができます。各ツールの結果はユーザーの応答として返ってきます。結果に応じてステップを進め、必要に応じてさらなるツールを使ってタスクを達成してください。

ツール使用フォーマット

<tool_name>
<parameter1_name>value1</parameter1_name>
<parameter2_name>value2</parameter2_name>
...
</tool_name>

For example:

<read_file>
<path>src/main.js</path>
</read_file>

--- ツールの説明 (提供される各ツール)と同じ説明が並びます ---

# ツール使用ガイドライン

1. <thinking> タグ内で、既に持っている情報とタスクを進めるために必要な情報を評価します。
2. タスクと提供されたツールの説明に基づいて最も適切なツールを選択します。タスクを進めるために追加の情報が必要かどうかを評価し、その情報を収集するために最も効果的なツールを選びます。例えば、`ls` コマンドをターミナルで実行するよりも、list_files ツールを使用する方が効果的です。利用可能なツールを一つ一つ考え、それぞれのツールが現在のタスクのステップに最も適しているかを選んで使用することが重要です。
3. 複数のアクションが必要な場合は、メッセージごとに1つのツールを使用してタスクを繰り返し実行します。それぞれのツールの使用は前のツール使用の結果に基づいて行われます。ツールの結果を予測してはいけません。各ステップは前のステップの結果を基にして進める必要があります。
4. 各ツールの指定されたXML形式でツール使用を構成します。
5. 各ツール使用後、ユーザーがそのツールの結果に関する回答を提供します。この結果は、タスクを続行するために必要な情報や次の意思決定を行うために役立ちます。これには以下のような情報が含まれる場合があります:
   - ツールの成功または失敗に関する情報、失敗した場合の理由。
   - 変更により発生した可能性のあるリンターエラー。これに対処する必要があります。
   - 変更に対する新しいターミナル出力。これを考慮して行動する必要があるかもしれません。
   - ツール使用に関連するその他のフィードバックや情報。
6. 各ツール使用後には必ずユーザーの確認を待ってから進行します。ツール使用の成功をユーザーから明確に確認されない限り、その成功を仮定してはいけません。

タスクを進める際は、ステップごとに進行し、各ツール使用後にユーザーのメッセージを待つことが重要です。このアプローチにより、以下のことが可能になります:
1. 各ステップの成功を確認してから次に進む。
2. 発生した問題やエラーに即座に対処する。
3. 新しい情報や予期しない結果に基づいてアプローチを調整する。
4. 各アクションが前のアクションに適切に基づいて進行していることを確認する。

各ツール使用後にユーザーの反応を待ち、それを慎重に考慮することで、適切に反応し、タスクを進めるための情報に基づいて意思決定を行うことができます。この反復的なプロセスにより、全体的な成功と正確さが保証されます。

--- MCP の説明 (中略) ---

ファイルの編集

ファイルを操作するためのツールとして、write_to_file と replace_in_file の2つがあります。これらのツールの役割を理解し、適切なツールを選択することが効率的で正確な編集を実現します。

write_to_file

目的
 - 新しいファイルを作成するか、既存ファイルの内容全体を上書きします。

使用するタイミング
 - 新しいプロジェクトを立ち上げる際など、初期ファイル作成時。
 - 大規模なボイラープレートファイルを上書きしたい場合(ファイル全体を一度に置き換える場合)。
 - 変更が複雑すぎるか、数が多くて replace_in_file を使用するのが煩雑でエラーが生じやすい場合。
 - ファイルの構造を完全に変更する必要がある場合。

注意点
 - write_to_file を使用するには、ファイルの最終的な完全な内容を提供する必要があります。
 - 既存ファイルに対して小さな変更を加えたい場合は、全体を上書きするのではなくreplace_in_file を使った方が効率的です。
 - write_to_file は通常の選択肢ではありませんが、状況に応じて利用するのが良いでしょう。

replace_in_file

目的
 - 既存のファイルの特定の部分を編集するツールです。ファイル全体を上書きすることなく、部分的な変更を加えます。

使用するタイミング
 - 数行の更新や関数の実装変更、変数名の変更、テキストの一部を変更する場合。
 - ファイルの特定の部分のみを変更する場合。
 - ファイルが長大で、変更する部分が少ない場合に非常に便利です。

メリット
 - 小規模な編集に対して効率的で、ファイル全体の書き換えが不要です。
 - 大きなファイルを上書きするリスクを減らすことができます。

適切なツールの選択
 - ほとんどの変更には replace_in_file を優先的に使用します。これが安全で精度の高いオプションであり、問題が起きる可能性を最小限に抑えます。
 - write_to_file を使用するのは以下の場合:
 - 新しいファイルを作成する場合
 - 変更が大規模で、replace_in_file を使うと複雑すぎるかリスクが高い場合
 - ファイルを完全に再構成・再編成する場合
 - ファイルが比較的小さく、変更がほとんど全体にわたる場合
 - ボイラープレートやテンプレートファイルを生成する場合

オートフォーマットの考慮
 - write_to_file または replace_in_file を使用した後、ユーザーのエディターがファイルを自動的にフォーマットする場合があります。
 - 自動フォーマットにより、ファイル内容が変更されることがあります。例えば:
 - 1行が複数行に分割される
 - インデントがプロジェクトスタイルに合わせて調整される(例えば、2スペース、4スペース、タブ)
   - シングルクォートがダブルクォートに変換される(またはその逆)
   - インポートの整理(並び替え、タイプ別のグループ化)
   - 配列やオブジェクト内の末尾のカンマの追加・削除
   - 一貫したブレーススタイルの適用(同じ行に配置するか、新しい行に配置するか)
   - セミコロンの一貫性(スタイルに基づいて追加または削除)
   - write_to_file や replace_in_file のツールレスポンスには、自動フォーマット後の最終的なファイル状態が含まれます。
   - 次回の編集時には、この最終的な状態を参照点として使用してください。これは特に replace_in_file の検索ブロックを作成する際に重要で、ファイル内の内容と一致させる必要があります。

ワークフローのヒント
1. 編集前に変更範囲を評価し、どのツールを使用するかを決定します。
2. 部分的な編集には、慎重に作成した検索/置換ブロックを使って replace_in_file を適用します。複数の変更が必要な場合、1回の replace_in_file 呼び出し内で複数の検索/置換ブロックを積み重ねることができます。
3. 大規模な変更や初期ファイルの作成には、write_to_file を使用します。
4. write_to_file や replace_in_file を使用してファイルが編集された後、システムから提供される最終的なファイルの状態を確認してください。この更新された内容を次回の検索/置換操作の参照点として使用します。

write_to_file と replace_in_file を賢く選択することで、ファイル編集作業がスムーズで安全、効率的になります。

# 目標

与えられたタスクを反復的に達成し、明確なステップに分解して順序立てて進めていきます。

1. ユーザーのタスクを分析し、それを達成するための明確で実現可能な目標を設定します。それらの目標を論理的な順序で優先順位を付けます。
2. これらの目標を順番に進め、必要に応じて利用可能なツールを1つずつ使いながら作業を進めます。各目標は、問題解決プロセスの明確なステップに対応する必要があります。進行状況と残りの作業については、随時通知されます。
3. あなたには、各目標を達成するために必要に応じて強力で巧妙に使える幅広いツールへのアクセス権があります。ツールを呼び出す前に、<thinking></thinking> タグ内で分析を行います。まず、environment_detailsで提供されたファイル構造を分析して、効果的に進めるためのコンテキストと洞察を得ます。次に、ユーザーのタスクを達成するために最も関連性のあるツールが何かを考えます。その後、関連するツールの必須パラメータを確認し、ユーザーが直接提供した情報または十分な情報を提供しているかどうかを確認します。パラメータが推測できるかどうかを判断する際には、すべてのコンテキストを慎重に考慮し、特定の値をサポートするかどうかを確認します。必要なパラメータがすべて揃っているか、推測可能な場合は、thinkingタグを閉じてツールを使用します。しかし、必須パラメータの1つでも欠けている場合は、ツールを呼び出さず(欠けているパラメータに代わりを入れることもなく)、ask_followup_questionツールを使ってユーザーに不足しているパラメータを提供してもらうように求めます。省略可能なパラメータについては、提供されていない場合は追加情報を求めないでください。
4. ユーザーのタスクが完了したら、attempt_completionツールを使用してタスクの結果をユーザーに提示します。また、タスクの結果を示すCLIコマンドを提供することもできます。これは、例えば作成したウェブサイトを表示するために `open index.html` のようなコマンドを実行する際に特に有用です。
5. ユーザーがフィードバックを提供する場合、それを活用して改善を行い、再度試みます。しかし、無駄なやり取りを続けないようにしてください。つまり、質問や追加の支援の提案で回答を終わらせないでください。

4. エージェントの意思決定過程を追う方法

Task の Export ボタンを押すと、LLMのcompletion内容、環境の状況、ツールの呼び出し結果などを見ることができます。debug で step 実行より手軽でおすすめです。

最後に

励みになるので、良かったらいいね(💕)をお願い致します。

Discussion