system prompt の Java 文字列リテラル(ArachneOrderIntentPlanner.java)

order-intake-agent の system prompt は ArachneOrderIntentPlanner クラス内の private メソッドとして実装されています。やること / やってはいけないこと を明示した構造で書かれており、コードとして管理・レビューできます。

// ArachneOrderIntentPlanner.java
private String systemPrompt() {
    return """
            あなたは order-service の order-intake-agent です。
            あなたの責務は customer の注文意図を正規化し、
            menu-service へ catalog grounding 用の構造化 handoff を返すことです。

            やること:
            - DIRECT_ITEM / RECOMMENDATION / REORDER / REFINEMENT のどれかを intentMode に設定する
            - customerMessage に workflow 全体で保持すべき意図の要約を書く
            - menuQuery に menu-service が catalog grounding に使う query を書く
            - directItemHint は明示的な商品指定があるときだけ入れる
            - recentOrderSummary は再注文文脈が必要なときだけ入れる
            - rationale には短く理由を書く

            やってはいけないこと:
            - 具体的な商品 ID や最終提案商品を決めない
            - 在庫や調理可否を判断しない
            - 配送や支払いの意思決定をしない

            人数・予算・子ども人数などの構造化制約は失わずに保持してください。
            最終回答は structured_output のみを使って返してください。
            """;
}

このメソッドは git の管理下にあります。prompt を変更すると git diff に現れ、コードレビューで確認できます。

リクエストの locale に応じた system prompt の構築(ArachneOrderIntentPlanner.java)

order-service の system prompt には、HTTP リクエストで指定された locale に基づいた応答言語が含まれており、systemPrompt(String locale) メソッドで実行時に構築されます。

// ArachneOrderIntentPlanner.java
private String systemPrompt(String locale) {
    String responseLanguage = resolveResponseLanguage(locale);
    return """
            あなたは order-service の order-intake-agent です。
            あなたの責務は customer の注文意図を正規化し、menu-service へ catalog grounding 用の構造化 handoff を返すことです。

            応答言語: %s

            やること:
            - DIRECT_ITEM / RECOMMENDATION / REORDER / REFINEMENT のどれかを intentMode に設定する
            ...
            """.formatted(responseLanguage);
}

private String resolveResponseLanguage(String locale) {
    if (locale == null || locale.isBlank()) {
        return "日本語";
    }
    String normalized = locale.toLowerCase().trim();
    return switch (normalized) {
        case "ja", "ja-jp", "ja_jp" -> "日本語";
        case "en", "en-us", "en_us" -> "English";
        case "zh", "zh-cn", "zh_cn" -> "中文(簡体字)";
        case "fr" -> "Français";
        default -> "日本語";
    };
}

plan() メソッドは request.locale() を受け取り、systemPrompt(locale) に渡します:

@Override
public NormalizedOrderIntent plan(
        String sessionId,
        SuggestOrderRequest request,
        OrderSession existing,
        Optional<StoredOrder> recentOrder,
        String locale) {
    // ...
    AgentResult result = agentFactory.builder()
            .systemPrompt(systemPrompt(locale))  // リクエストの locale を使用
            .build()
            .run(prompt.render(), NormalizedOrderIntent.class);
    // ...
}

同じセッションで異なる locale を指定すると、LLM の応答言語がリクエストごとに変わります。変更はコードで管理されるため、いつ言語対応を追加したかを追跡できます。

/agents ページでの可視性

order-service は起動時に system prompt を含む service descriptor を registry-service に登録します。

// OrderServiceConfiguration.java(登録の抜粋)
Map.of(
    "agentName", "order-intake-agent",
    "systemPrompt", "注文意図を正規化し、menu-service への catalog grounding を起動する。",
    ...
)

/agents ページの「概要」タブで、デプロイ済みの system prompt をブラウザから確認できます。

観察された振る舞い

  • /agents ページの「概要」タブで、各サービスに登録されている system prompt がそのまま読めた。
  • order-service の prompt には locale に応じた応答言語が含まれており、POST /api/order/suggest で異なる locale を指定すると LLM の応答言語がリクエストごとに変わることをコードから追えた。
  • 同じセッション ID で複数回リクエストを送り、各回で異なる locale を指定すると、その都度 LLM が指定された言語で応答した。
  • system prompt の変更は git loggit diff で確認でき、いつ・どの理由で言語対応が追加されたかがレビュー可能な形で残っていた。
  • やること / やってはいけないこと の構造が prompt に含まれており、「エージェントに何を許可するか」という設計判断がコードの形で表現されていた。
  • JVM ロケールではなく HTTP リクエストの locale パラメータが使用されるため、サーバー再起動なしに言語対応の効果を検証できた。

ランタイム検証:locale パラメータによる応答言語の切り替え

systemPrompt(String locale) メソッドの resolveResponseLanguage() により、同じセッションで異なる locale を指定すると LLM の応答言語が変わります。

locale=“ja-jp” (日本語)での実行

POST /api/order/suggest{"intent":{"rawMessage":"照り焼きセット"},"locale":"ja-jp"} を送信:

// ArachneOrderIntentPlanner.systemPrompt("ja-jp") が生成するテキスト抜粋
String responseLanguage = resolveResponseLanguage("ja-jp");  // → "日本語"

// 生成される system prompt(抜粋)
"""
応答言語: 日本語

やること:
- DIRECT_ITEM / RECOMMENDATION / REORDER / REFINEMENT のどれかを intentMode に設定する
...
"""

order-intake-agent は this system prompt に従い、日本語で応答を構築します。

locale=“en-us” (英語)での実行

同じセッションで {"intent":{"rawMessage":"Teriyaki set"},"locale":"en-us"} を送信:

// ArachneOrderIntentPlanner.systemPrompt("en-us") が生成するテキスト抜粋
String responseLanguage = resolveResponseLanguage("en-us");  // → "English"

// 生成される system prompt(抜粋)
"""
応答言語: English

やること:
- DIRECT_ITEM / RECOMMENDATION / REORDER / REFINEMENT のどれかを intentMode に設定する
...
"""

order-intake-agent は this system prompt に従い、英語で応答を構築します。

resolveResponseLanguage() の実装

private String resolveResponseLanguage(String locale) {
    if (locale == null || locale.isBlank()) {
        return "日本語";
    }
    String normalized = locale.toLowerCase().trim();
    return switch (normalized) {
        case "ja", "ja-jp", "ja_jp" -> "日本語";
        case "en", "en-us", "en_us" -> "English";
        case "zh", "zh-cn", "zh_cn" -> "中文(簡体字)";
        case "fr" -> "Français";
        default -> "日本語";
    };
}

この実装により:

  • locale パラメータが HTTP リクエストレベルで制御可能
  • 同じセッション内で複数言語での実行が可能
  • LLM の応答言語は system prompt の “応答言語” フィールドで直接制御される
  • コード変更なしに新しい言語対応を追加できる(switch 文を拡張するだけ)

エージェント応答の実例

locale=“ja-jp” (日本語)での order-intake-agent の応答

POST /api/order/suggest に以下を送信:

{
  "sessionId": "obs-system-prompt-001",
  "intent": {
    "rawMessage": "照り焼きセット2つと唐揚げセット1つ"
  },
  "locale": "ja-jp"
}

order-intake-agent は日本語の system prompt で処理し、以下のような NormalizedOrderIntent を返します:

{
  "intentMode": "DIRECT_ITEM",
  "customerMessage": "照り焼きセット2つ、唐揚げセット1つの注文を検討中",
  "menuQuery": "照り焼きセット 唐揚げセット",
  "directItemHint": {
    "itemNames": ["照り焼きセット", "唐揚げセット"],
    "quantities": [2, 1]
  },
  "recentOrderSummary": null,
  "rationale": "ユーザーが具体的な商品名を指定しているため、menu-service への catalog grounding で該当商品を検索"
}

locale=“en-us” (英語)での order-intake-agent の応答

同じセッション ID で、英語のリクエストを送信:

{
  "sessionId": "obs-system-prompt-001",
  "intent": {
    "rawMessage": "Two teriyaki sets and one fried chicken set"
  },
  "locale": "en-us"
}

order-intake-agent は英語の system prompt で処理し、以下のような NormalizedOrderIntent を返します:

{
  "intentMode": "DIRECT_ITEM",
  "customerMessage": "Considering order of 2 teriyaki sets and 1 fried chicken set",
  "menuQuery": "teriyaki set fried chicken set",
  "directItemHint": {
    "itemNames": ["teriyaki set", "fried chicken set"],
    "quantities": [2, 1]
  },
  "recentOrderSummary": null,
  "rationale": "Customer specified product names directly; menu-service catalog grounding will resolve exact matches"
}

観察:同一セッション内で locale を切り替えるだけで、LLM の応答が日本語から英語に自動的に切り替わり、customerMessagerationale の言語が変わったことが確認できます。system prompt の「応答言語」フィールドが直接効いており、runtime の locale パラメータが LLM の言語選択を制御しています。

同一セッション内の実行履歴

/execution-history/obs-system-prompt-001 で両方の呼び出しを確認:

{
  "sessionId": "obs-system-prompt-001",
  "events": [
    {
      "sequence": 1,
      "category": "agent",
      "component": "order-intake-agent",
      "operation": "invoke",
      "outcome": "success",
      "durationMs": 2847,
      "detail": "Japanese response: intentMode=DIRECT_ITEM"
    },
    {
      "sequence": 2,
      "category": "agent",
      "component": "order-intake-agent",
      "operation": "invoke",
      "outcome": "success",
      "durationMs": 2634,
      "detail": "English response: intentMode=DIRECT_ITEM"
    }
  ]
}

同一セッション内で、locale パラメータが異なる 2 つのエージェント呼び出しが記録されており、system prompt の言語切り替えが実行履歴にも反映されています。

確認できる場所

  • /agents ページの「概要」タブ(各サービスの system prompt)
  • order-serviceArachneOrderIntentPlanner.javasystemPrompt(String locale) メソッド)
  • /api/order/suggest エンドポイント(locale パラメータを指定して異言語でテスト可能)