0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「ハーネス」とは何か: Claude Code の裏側で起きていることから理解する

0
Posted at

はじめに

AIエージェントの話をしていると、「ハーネス」という言葉を目にする機会が増えました。Claude Code の公式ドキュメントでも、「次のステップ」の欄で「すべてのタスクのためのハーネス」という題のブログ記事が紹介されています。

ただ、この言葉を聞いて中身を説明できる人は、まだ多くないと感じています。日本語でハーネスと聞いて思い浮かぶのは、馬具や安全帯、配線の束です。そこからAIの話にはつながりません。

この記事では、まず Claude Code に作業を頼んだときに裏で何が起きているかを見ます。そこからハーネスとは何かを説明し、最後に、誰がこの考え方を理解しておく必要があるのかを書きます。

Claude Code に作業を頼んだときに起きていること

Claude Code に「README.md を読んで、3行で要約して」と頼んだとします。画面上では、Claude Code がファイルを読んで要約を返してくれたように見えます。

裏では、次のやり取りが起きています。

harness_sequence.png

青い矢印が Claude Code の動き、オレンジの矢印がモデルの動きです。番号の順に見ていきます。

  1. Claude Code が、頼んだ文章をモデルに送る
  2. モデルは「README.md を読む」という指示を返す。モデル自身はファイルを開けないので、指示を返すところまでしかできない
  3. Claude Code がその指示を受け取り、README.md を開いて、依頼とファイルの中身をモデルに送る
  4. モデルは中身を読んで、要約の文章を返す
  5. モデルの返事にファイルを読む指示が含まれていないので、Claude Code はここで作業を終え、要約を画面に表示する

モデルがやっているのは、2と4の「文章を受け取って文章を返す」ことだけです。次の処理は、どれも Claude Code のプログラムがやっています。

  • README.md を開く
  • ファイルの中身をモデルに送る
  • 作業を終えると判断する

このように、モデルの外側でこうした処理を受け持っているプログラムを、ハーネスと呼びます。

ハーネスの部品

先ほどのやり取りで、ハーネスがやっていたことを整理します。

harness_overview.png

部品 役割 先ほどの例では
ループ モデルの返事を受けて、次の処理を行う 3でファイルを開き、モデルにもう一度送った
ツール モデルが使える機能を用意する ファイルを読む機能を用意していた
コンテキスト モデルに毎回送る内容を組み立てる 3で、最初の依頼とファイルの中身を一緒に送った
権限 確認なしで実行してよい操作かを判断する README.md を読むことを、利用者に確認せずに実行した
停止条件 作業を終えるタイミングを判断する 5で、ファイルを読む指示がなくなったので終えた

この例ではファイルを1回読んだだけで終わりましたが、実際の作業では、モデルがファイルを読む指示を返し、ハーネスがファイルを読んで送る、というやり取りが数十回続くこともあります。そのあいだ、ハーネスは作り手が設計したとおりに、この表の5つの役割を果たしています。

ハーネスの基本形は短いコードで書ける

ハーネスの基本形は、思ったより短いコードで書けます。先ほどのやり取りをそのままコードにすると、次のようになります。ファイルを読むツールを1つだけ持つハーネスを、OpenAI 互換のクライアントを使う形で書いています。実行するためではなく、構造を見るためのコードです。

import json

# client は OpenAI 互換のクライアント、MODEL はモデル名とします

def read_file(path: str) -> str:
    with open(path, encoding="utf-8") as f:
        return f.read()

# ツール: モデルに「使える道具」として見せる一覧と、実際に動かす関数の対応
TOOLS = [{
    "type": "function",
    "function": {
        "name": "read_file",
        "description": "指定したパスのテキストファイルを読む",
        "parameters": {
            "type": "object",
            "properties": {"path": {"type": "string"}},
            "required": ["path"],
        },
    },
}]
TOOL_IMPL = {"read_file": read_file}

def run(question: str, max_steps: int = 10) -> str:
    # コンテキスト: モデルに毎回渡す会話の履歴
    messages = [{"role": "user", "content": question}]
    # ループと停止条件: 最大 max_steps 回まで繰り返す
    for _ in range(max_steps):
        res = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
        msg = res.choices[0].message
        messages.append(msg.model_dump(exclude_none=True))
        # ツールを呼ぶ指示がなければ、その文章を最終回答として終える
        if not msg.tool_calls:
            return msg.content
        # モデルが返すのはツールを呼ぶ指示だけ。実際に実行するのはこのコード
        for call in msg.tool_calls:
            args = json.loads(call.function.arguments)
            result = TOOL_IMPL[call.function.name](**args)
            messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
    return "上限回数に達したので打ち切りました"

コメントに書いたとおり、このコードには表の5つの部品のうち4つが入っています。

  • for 文がループ
  • TOOLS と TOOL_IMPL がツール
  • messages がコンテキスト
  • max_steps と、ツール呼び出しがなければ終える判定が停止条件

権限だけは入っていません。このコードは、モデルが指定したパスのファイルを確認なしで読みます。実際の製品では、ここに「このファイルを読んでよいか」を利用者に確認する処理や、読めるフォルダを限定する処理が入ります。

Claude Code のような製品は、この基本形の各部品を作り込んだものです。

Claude Code の機能はハーネスの部品を調整するもの

ハーネスの部品が分かると、Claude Code の機能がそれぞれ何のためにあるのかを整理できます。

Claude Code の機能 調整しているハーネスの部品
CLAUDE.md、自動メモリ コンテキスト (毎回最初に読ませる指示や、セッションをまたいで残す内容)
MCP ツール (外部のデータやサービスを使えるようにする)
スキル ツールと手順 (繰り返す作業の手順をまとめて呼び出せるようにする)
フック 権限とループ (決まったタイミングで必ず実行する処理を差し込む)
権限の設定 権限 (確認なしで実行してよい操作の範囲)
サブエージェント ループ (仕事を分けて別のエージェントに任せる)

CLAUDE.md はモデルに毎回送られる指示なので、モデルが必ず従うとは限りません。フックは、決まったタイミングでハーネスが必ず実行する処理です。同じ「AIにルールを守らせたい」という目的でも、どの部品で実現するかによって確実さが変わります。

新しい機能が追加されたときも、どの部品を調整する機能なのかを考えると、役割を理解しやすくなります。

ハーネスの動き方は作り手が設計している

Claude Code や Codex のハーネスが表の各部品でどう動くかは、作り手が設計しています。多くの用途でうまく動くように考えられた設計です。

ただし、どんな設計も、すべての用途に合うわけではありません。

たとえば、問い合わせに答える業務で、社内のナレッジベースをもとに回答を作る場面を考えます。ナレッジベースには、依存関係が複雑に絡み合ったコードベースも含まれるとします。

Claude Code の情報の集め方は、ファイルを検索して、見つかったファイルを読み進めるやり方が基本です。コードを書き換える作業では、これは理にかなった設計です。一方、依存関係を何段もたどらないと答えが出ない問い合わせでは、必要な箇所にたどり着く前に、読んだ内容でコンテキストが埋まってしまうことがあります。

ここで重要なのは、モデルを新しいものに替えても、ハーネスの情報の集め方は変わらないことです。問題はモデルの性能ではなく、ハーネスの設計が用途に合っていないことにあります。

ハーネスエンジニアリングは、ハーネスを自分の用途に合わせて設計し直す作業だと私は理解しています。

ハーネスを用途に合わせる方法は1つではない

既製のハーネスが合わないとき、「既製品で我慢する」か「全部自作する」かの二択で考えてしまいがちです。実際には、その間にいくつかの段階があります。

  1. 既製品をそのまま使う
  2. 既製品の拡張の仕組み (CLAUDE.md、スキル、MCP、フックなど) で変える
  3. エージェントを作るためのフレームワークの上で、自分でハーネスを組む
  4. ゼロから書く

harness_stages.png

段階2では、ツールや指示を足すことはできます。しかし、ループの形や情報の集め方の基本は、製品の設計のままです。段階3以降では、それらも自分で設計できます。その代わりに、自分で設計するものと保守するものが増えます。

先ほどの例なら、コードの依存関係をたどるツールを MCP で追加すれば足りる場合は、段階2で済みます。次のような情報の集め方そのものを変える必要がある場合は、段階3が候補になります。

  • 依存関係を何段までたどるか
  • どこで打ち切るか
  • たどった結果のうち、何をコンテキストに残すか

どの段階で解決できるかは、どの部品が合っていないかによって決まります。合っていない部品を特定しないまま段階を選ぶと、拡張で済むものを自作したり、自作が必要なものを拡張で無理に済ませようとしたりします。

ハーネスを理解しておく必要がある人

Claude Code や Codex を使って自分の仕事を楽にしたい人は、ハーネスという言葉を知らなくても困りません。製品が用意した設定や拡張の範囲で、十分に成果を出せます。

ハーネスを理解しておく必要があるのは、エージェントで期待した結果が出ないときに、原因を探して手を打つ立場の人です。具体的には次の3つの立場です。

  • Claude Code や Codex では業務の要件を満たせず、どうするかを決めなければならない人
  • エージェントを社内に提供し、使えるツールや権限、実行の記録を管理する基盤チーム
  • 自分たちでエージェントを作る開発者

この立場の人がハーネスを意識していないと、原因の探し方が偏ります。

Claude Code や Codex を普段使っていると、モデルとハーネスが分かれていることは見えません。利用者から見えるのは、選んでいるモデルの名前と、自分が書いた指示だけです。そのため、期待した結果が出ないときに思い浮かぶ原因も、この2つになりがちです。モデルの性能が足りないと考えて次のモデルを待ったり、指示が足りないと考えてプロンプトや CLAUDE.md に指示を足し続けたりします。

harness_visibility.png

「ハーネスの動き方は作り手が設計している」の節で見たように、原因がハーネスの設計にある場合、これらの手を打っても結果は変わりません。

以下、それぞれの立場で押さえておきたいことを書きます。

Claude Code や Codex では足りない人

まず、ハーネスのどの部品の設計が自分の業務に合っていないかを特定します。たとえば次のどれが合っていないかによって、取るべき段階が変わります。

  • 情報の集め方
  • 使えるツール
  • 途中に人の確認を挟めるかどうか

「モデルが賢くなれば解決するか」と考えてみるのも有効です。解決しないと思える問題は、ハーネスの設計を疑ってみる価値があります。

エージェントを提供・管理する基盤チーム

管理したい点が、ハーネスのどの部品にあるかを把握します。次の点は、いずれもモデルではなくハーネス側の仕組みです。

  • 使えるツールの範囲
  • 確認なしで実行してよい操作
  • 実行の記録

製品ごとに、これらの設定の仕方は異なります。製品を比べるときは、使えるモデルだけでなく、管理したい点をどこまで制御できるかも比較の対象になります。

自分でエージェントを作る開発者

ハーネスも、モデルと同じく設計し、観察し、評価する対象です。工夫がプロンプトとモデル選びに偏ると、ループの形やコンテキストに何を入れるかが、設計の対象として意識されません。

評価で最終的な回答だけを見ていると、途中の処理に原因がある失敗に気づけません。どのツールをどの順番で呼び、何をコンテキストに入れたかを記録して確認する必要があります。

ハーネスを変えたときも、モデルを替えたときと同じように評価し直します。成果はモデルとハーネスの組み合わせで決まるからです。

まとめ

ハーネスについて整理したことをまとめます。

  • モデルは文章を受け取って文章を返すだけ。ファイルを開いて中身を送ることや、作業を終える判断は、モデルの外側のプログラムがやっている
  • モデルの外側でこうした処理を受け持つプログラムがハーネス 。ループ、ツール、コンテキスト、権限、停止条件といった部品でできている
  • ハーネスの基本形は数十行のコードで書ける。製品はそれを作り込んだもの
  • Claude Code の CLAUDE.md、MCP、スキル、フック、サブエージェントは、ハーネスの部品を調整するための機能
  • ハーネスの動き方は作り手が設計している 。用途に合わない設計は、モデルを替えても変わらない
  • ハーネスを用途に合わせる方法には、拡張の仕組みで変える、フレームワークの上で組む、ゼロから書く、という段階がある。どれを選ぶかは、合っていない部品で決まる

ハーネスという言葉が分かりにくいのは、多くの人が製品を通じてしかエージェントに触れておらず、モデルとハーネスを分けて見る機会がないからだと思います。既製品をそのまま使う人にはそれで問題ありません。ただ、エージェントを選ぶ人、作る人、管理する人にとっては、成果が出ないときにモデル以外を疑えるかどうかが判断の分かれ目になります。この記事が、その見方を持つきっかけになればうれしいです。

ハーネスの先にあるもの

この記事では、1つのハーネスがどのような部品でできていて、どう動いているかを見てきました。業務によっては、Claude Code や Codex のような複数のハーネスを使い分けたり、まとめて管理したりする必要が出てきます。こうした使い分けや管理を担う仕組みは、メタハーネスと呼ばれています。

メタハーネスの考え方と、OSS の Omnigent を使ってそれを実現する方法は、私も著者として参加した次の本にまとめています。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?