跳到主要内容

ジャクソン 3 の使用LangChain4j は、交換するリクエストとレスポンスなど、さまざまな場所で JSON を読み書きします。

LLM プロバイダー、AI サービスが解析する構造化された出力、保持するチャット メモリなど。によって デフォルトでは Jackson 2 でこれを行います。 LangChain4j の使用方法 JSON と独自のマッパーをプラグインする方法については、JSON で説明されています。 アプリケーションが Jackson 3 上にある場合は、代わりに LangChain4j にそれを使用させることができます。

オンにする依存関係を 1 つ追加します。​

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-jackson3</artifactId>
<version>1.23.0-beta33</version>
</dependency>

langchain4j-agentic を含むすべてのモジュールについて、これがすべてです。 LangChain4j は、 モジュールを ServiceLoader 経由で接続し、その JSON を Jackson 3 経由でルーティングします。 設定しても呼び出す API がなく、依存関係を削除するとすべてが Jackson 2 に戻ります。 サポートは 2 つのアーティファクトに分割されており、上記の langchain4j-jackson3 は両方を取り込むので、 追加しない理由がない限り、追加するものです。

アーティファクトカバーによって異なります
langchain4j-core-jackson3langchain4j-core のすべて: プロバイダーの要求と応答、構造化された出力、チャット メモリのシリアル化、エージェントの状態langchain4j-core
langchain4j-jackson3上記に加えて、langchain4j モジュールに存在する InMemoryEmbeddingStore 永続性。 langchain4j-core-jackson3 と langchain4j
アプリケーションが langchain4j-core と
langchain4j モジュールのないプロバイダー - たとえば、モデルを構築するフレームワーク統合
直接的に。 langchain4j-jackson3 と一緒に追加することは不要ですが、害はありません。

変わらないものJSON ライブラリを切り替えることは、誤って動作を変更する良い方法であるため、モジュールはハードウェア的に動作します。​

に。 Jackson 3 はいくつかのデフォルトを変更し、LangChain4j の読み取り内容を変更するほぼすべてのデフォルトを変更しました。 write は、Jackson 2 が行ったことに戻ります。意図的に保持されているいくつかのものが以下にリストされています What is deliberately different。

設定ジャクソン3のデフォルトこのモジュールの機能
ALLOW_FINAL_FIELDS_AS_MUTATORS無効有効
USE_GETTERS_AS_SETTERS無効有効
SORT_PROPERTIES_ALPHABETICALLY有効無効
FAIL_ON_TRAILING_TOKENS有効無効
FAIL_ON_NULL_FOR_PRIMITIVES有効無効
READ_ENUMS_USING_TO_STRING有効無効: enum は name() によって読み取られます
WRITE_ENUMS_USING_TO_STRING有効無効: 列挙型は name()
DETECT_PARAMETER_NAMES有効構造化出力とツール引数を除き、無効になります (以下を参照)。
FAIL_ON_UNKNOWN_PROPERTIES無効有効: ターゲット タイプにないフィールドは、構造化出力、ツール引数、チャット メモリ、エージェント状態、および保存された埋め込みストアで失敗します。プロバイダーの応答は依然として不明なフィールドを無視します。
FAIL_ON_EMPTY_BEANS無効有効: 書き込むものが何もないオブジェクト (たとえば、フィールドがプライベートでゲッターを持たないオブジェクト) は、{}
最初の項目が最も重要です。これがないと、最終的なコレクション フィールドは空のままになります。
人口が多くても何もわかりません。
DETECT_PARAMETER_NAMES は、コードが Spring Boot として -parameters でコンパイルされている場合にのみ問題になります。
Quarkus プロジェクトは通常そうです。構造化された出力およびツール引数の場合、コンストラクター パラメーター
jackson-module-parameter-names がクラスパス上にある場合に Jackson 2 コーデックが行うように、名前が使用されます。
これは Spring Boot と Quarkus にあります。引数を持つコンストラクターのみを持つクラスです。
ロンボク島@AllArgsConstructorクラス、読めます。チャット メモリ、エージェントの状態、その他のコーデックは影響を受けません。
Jackson 2 と同様にパラメータ名を使用します。
コンパイラの設定に関係なく、コンストラクターを明示的に選択するには、それにアノテーションを付けます。
  • @JsonCreator(mode = JsonCreator.Mode.DELEGATING) を使用すると、"abc" などのプレーンな値を読み取ることができます。 引数が 1 つのコンストラクター。
  • @JsonCreator を使用し、@JsonProperty("name") を使用して各パラメータを使用すると、オブジェクトを介してオブジェクトを読み取ります。 引数付きのコンストラクター。 どちらもジャクソンのバージョンで動作します。

意図的に異なるものは何ですかいくつかの違いは、復元すると予想よりもコストがかかるため、意図的に残されています。​

  • 日付と時刻は ISO-8601 文字列として書き込まれます。 java.util.Date と Calendar は次のようになります。 エポックミリ秒の代わりに "1970-01-01T00:00:00.000Z"。 jackson-datatype-jsr310 を搭載 Spring Boot や Quarkus アプリケーションと同様に、Jackson 2 もクラスパスを Instant と書きます。 OffsetDateTime および Duration は数値として表されます。このモジュールはそれらを ISO-8601 文字列として書き込みます。 LLM ははるかに信頼性の高い読み取りを行います。 Date、Instant、Duration の数字は引き続き読み取られます。
  • java.time.Month は 1 から始まる数字として記述されます (1 月の場合は 1)。と jackson-datatype-jsr310、ジャクソン 2 は "JANUARY" を書き込み、開始位置として数値を読み取ります。 0 の場合、1 は FEBRUARY になります。どちらのバージョンも名前を読みます。
  • "" は、列挙型の場合は null として読み取られます。これは欠損値と同じです。これは必須に適用されます enum も同様です。欠落フィールドと同様に、"" はエラーではなく null を返します。代わりにジャクソン2は失敗しますが、 しかしプロバイダーはそれを送信します - ツール呼び出しに対して "type": "" を返す OpenAI 互換サーバーとは何ですか これが見つかりました - そして、LLM はオプションの列挙型に対して "" と応答する可能性があります。 "" (オブジェクト、マップ、またはリスト) Jackson 2 と同様に、やはり失敗します。
  • private 1 引数コンストラクターは、プレーンな値の読み取りには使用されません。 Jackson 2 はこれを使用します。 Jackson 3 の場合は、@JsonCreator(mode = JsonCreator.Mode.DELEGATING) という注釈を付けます。
  • 構造化出力およびツール引数の場合、引数のないコンストラクターと 引数付きコンストラクターは、コンパイル時に引数付きコンストラクター を介して作成されます。 -parameters。 Jackson 2 は引数なしのコンストラクターを使用してフィールドを設定します。これだけ そのコンストラクターがフィールドを割り当てる以上のことを行うかどうかが重要です。
  • ゲッター getXValue() を含む xValue などのフィールドは、"xValue" と記述されます。 Jackson 2 の導出 ゲッターからの "xvalue": 構造化出力、ツールの結果、およびエージェントの状態の両方を書き込みます。 "xValue" および "xvalue"、プロバイダー要求の場合のみ "xvalue"。エージェント状態の書き込み者 このような重複キーを持つ Jackson 2 は、このモジュールでの読み取りに失敗します。
  • 失敗すると LangChain4j タイプが取得されます。* デフォルトでは、JSON エラーは、Jackson 2 独自の例外をラップする RuntimeException として表面化します。 つまり、それに反応するコードは Jackson 2 を認識している必要があります。このモジュールを使用すると、JSON の読み取りまたは書き込みが可能になります。 失敗した場合は、代わりに JsonReadException または JsonWriteException (両方とも LangChain4jException) がスローされます。 ライブラリの例外が原因として保持されます。 これは矛盾ではなく意図的なステップです。型指定された例外は、LangChain4j の場所にあります。 は次のメジャー バージョンで導入される予定ですが、Jackson 2 コーデックはそれまでそのままのままです。 既存のコードは引き続き機能します。 JSON エラーをその Jackson タイプで検出できれば、それが 1 つのことです このモジュールを追加するときに再度アクセスしてください:
- } catch (JsonParseException e) {
+ } catch (JsonReadException e) {

RuntimeException をキャッチすることはどちらの方法でも機能します。 2 か所は、catch ブロックが関与せずにアプリケーション コードに到達するため、価値があります。 切り替える前に確認してください:

  • ツール引数エラー ハンドラー。* モデルが有効な JSON ではないツール引数を生成すると、 LangChain4j は、登録したハンドラーに失敗を渡します。 AiServices.toolArgumentsErrorHandler(...)。ジャクソン2では、失敗はジャクソン自身の責任である JsonParseException;このモジュールでは JsonReadException になります。上で分岐するハンドラ type はマッチングを停止し、ハンドラーはまだ呼び出され、単純に そのもう一方のブランチ:
AiServices.builder(Assistant.class)
.toolArgumentsErrorHandler((error, context) -> {
- if (error instanceof JsonParseException) {
+ if (error instanceof JsonReadException) {
return ToolErrorHandlerResult.text("Please return valid JSON.");
}
throw error;
})

両方の下で動作するハンドラーが必要な場合は、メッセージまたは RuntimeException に一致します。

  • OutputParsingException の原因* 構造化された出力を解析できない場合、LangChain4j どちらの場合でも OutputParsingException をスローします - その型は変更されません。何が変わるかというと、 その下の例外、Jackson 2 の JsonProcessingException から Jackson 3 まで StreamReadException。 getRootCause() を検査するコードも同じ処理が必要です。
  • すでに保存されているデータは引き続き読み取り可能です。* チャット メモリと InMemoryEmbeddingStore ファイル Jackson 2 によって書き込まれた内容は Jackson 3 によって正しく読み取られ、Jackson 3 が書き込む内容はバイト単位で行われます。 ジャクソン2が書いたであろうもの。それはテストでカバーされているため、真実のままです。

Jackson 2 の削除モジュールを追加しても、それ自体では Jackson 2 は削除されません。通常の推移的なものとして到着します。​

依存関係があり、この 2 つは無期限に共存できます。それをなくしたければ、通常はそうすることができますが、 このモジュールが存在すると、LangChain4j は Jackson 2 クラスをロードしなくなるためです。 実際に終了できるかどうかは、使用するモジュールによって異なります。

モジュールジャクソン2は除外できるのか?
langchain4j-core、langchain4jはい - Jackson 2 コーデックが同梱されていますが、これらはフォールバックであり、このモジュールがクラスパス上にある間はロードされません。
プロバイダー モジュール — OpenAI、Anthropic、Mistral、Ollama、Gemini、その他はい
埋め込みストア、Web 検索、コード実行はい
langchain4j-agenticはい
langchain4j-mcpはい、1.23.0 以降
langchain4j-mcp-dockerいいえ、Docker と通信するために使用される docker-java は Jackson 2 に依存しています。
langchain4j-guardrailsいいえ - JsonExtractorOutputGuardrail は、ガードレールが以前と同じように厳格であるように、意図的に通常の Jackson 2 ObjectMapper で解析します。
langchain4j-vespaいいえ - HTTP クライアントは Retrofit 独自の Jackson 2 コンバータを使用します。
ベンダー SDK を使用するものすべて — AWS、Azure、Googleいいえ、SDK は Jackson 2 自体に依存しています。
Maven の除外は、記述されている依存関係に適用されるため、すべての LangChain4j に適用されます。
最初の依存関係だけでなく、宣言した依存関係:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.23.0</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- and the same on langchain4j-open-ai, and on any other LangChain4j module you use -->

com.fasterxml.jackson.core:jackson-annotations を除外しないでください。 2.x 座標を保持します しかし、共有されています。Jackson 3 はそれに依存しており、それらの注釈を読み取ります。 この構成は機能すると考えられているだけでなく、すべてのプル リクエストで構築され、実行されます。 integration-tests/integration-tests-jackson3 はまさにこのように組み立てられたアプリケーションです - コア、 メイン モジュール、3 つのプロバイダー (OpenAI、Anthropic、Mistral AI)、エージェント、MCP、およびこのモジュール、 Jackson 2 はグラフ全体から除外されており、そのテストは AI Services の構造化された出力をカバーしています。 ツール呼び出し、チャットメモリの永続性、埋め込みストアの永続性、エージェント状態の永続性、 プロバイダー ワイヤ形式、MCP クライアントのリスト表示と呼び出しツール、およびレジストリ メタデータの読み取りです。 そのいずれかが Jackson 2 を必要とし始めた場合、それらのテストはクラスを見つけることができません。 langchain4j-guardrails、langchain4j-mcp-docker、Vespa、またはクラウド SDK を使用している場合は、Jackson 2 のままです。オプトインすると、引き続き Jackson 3 が 1 つ提供されます LangChain4j 自体がシリアル化するすべてのコード パス。

プロバイダーまたは DTO を作成する場合ワイヤータイプを提供する場合に知っておくべき 2 つのこと。​

  • 名前はタイプではなくコーデックに属します。* @JsonNaming は Jackson 2 の databind にあります。 パッケージなので、Jackson 3 はそれをまったく認識しません。フィールド名は黙ってキャメルケースで表示されます。を設定します。 代わりにコーデックに名前を付けます。
ProviderJson.codec(ProviderJsonSpec.builder()
.propertyNaming(ProviderJsonSpec.PropertyNaming.SNAKE_CASE)
.build());

単一のフィールドに別の名前が必要な場合、@JsonProperty("...") は両方のフィールドで機能します。 jackson-annotations から、2 つのバージョンが共有するアーティファクト。

  • ビルダーベースの DTO には、@JsonCreator とビルダーのフィールドの可視性が必要です。* @JsonDeserialize(builder = ...) は databind アノテーションでもあるため、Jackson 3 では DTO は次のようになります。 代わりに、ビルダーを受け取るコンストラクターの @JsonCreator を通じてビルドされます。ジャクソン3のフィル ビルダーはそのプライベート フィールドを書き込むことで、ビルダーも必要とする @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)。それがないと応答は解析されます エラーは発生しませんでしたが、フィールドは null のままです。 3 つすべてが存在する必要があります。
  • ビルダー メソッドが実行されるかどうかは、そのメソッドのアノテーションによって異なります。* これは、実行する部分です。 なぜなら、それは沈黙していて、ルールはあなたが推測するものではないからです。ジャクソン 2 が満たす ビルダーのセッターを呼び出してから build() を呼び出します。ジャクソン 3 は、セッターを運ぶ場合にのみセッターを呼び出します。 それ以外の場合はフィールドを直接書き込み、build() をまったく呼び出しません。 |ビルダーセッターについて |ジャクソン2 |ジャクソン3 | |---|---|---| | @JsonSetter("odd-name")、@JsonProperty、ベア @JsonSetter | |と呼ばれる|と呼ばれる | @JsonAlias 単体 | |と呼ばれる呼び出されません - エイリアスは無視されます。 |注釈なし | |と呼ばれる呼び出されません - フィールドは直接書き込まれます。 | build() | |と呼ばれる電話は一度もありません | したがって、2 つのコーデックは 1 つのタイプ内でプロパティごとに分岐する可能性があるため、これには価値があるのです。 警戒ではなく規則:
  • 両方のルートが通過する場所にその型が保証するものを入力します。* デフォルトはビルダーのものに属します。 build() ではなくフィールドです。防御的なコピーや正規化は、コンストラクター内に属し、コンストラクター内に属します。 セッター。エイリアスには、ビルダーの フィールド とそのセッターに @JsonAlias が必要です。 ここでは、それらのそれぞれが間違っていました。build() にデフォルト設定されていた型は、すべての mistral-ai ツール呼び出しをドロップしました。 セッターの @JsonAlias は、vLLM、OpenRouter、および Groq から推論コンテンツを削除しました。そして 注釈のないセッターの unmodifiableList(...) は、同じ応答が 1 つの下で変更可能に返されることを意味します。 他のコーデックではありません。誰も投げませんでした。 オプトインをサポートするモジュールは、jackson3 Maven プロファイルを宣言します。 そのモジュールのテスト クラスパス上に langchain4j-jackson3 があるため、その既存のテストが実行されます Jackson 3. CI はプル リクエストごとにすべてのモジュールを実行します。同じ方法で 1 つのモジュールを実行できます。
mvn test -Pjackson3 -pl langchain4j-your-module

結果を信頼する前に、モジュールの pom.xml が実際にそのプロファイルを宣言していることを確認してください。 Maven は、選択したモジュールが宣言していないプロファイルを無視するため、上記のコマンドはレポートします。 Jackson 2 ですべてを実行して成功しました。プロファイルの追加は、モジュールの移行の一部です。 プロファイルは、テスト クラスパスに langchain4j-jackson3 ではなく langchain4j-core-jackson3 を置きます。 後者は langchain4j モジュールに依存しており、グラフを周期的にするためです。 モジュール自体が構築されているモジュール。 InMemoryEmbeddingStore 持続性、これがその部分です 完全なアーティファクトが必要ですが、langchain4j-jackson3 独自のテストと integration-tests/integration-tests-jackson3。 langchain4j-open-ai には OpenAiBuilderCreatorParityTest も含まれており、すべてを比較します。 {} から解析された同じ DTO に対してビルダーを通じて構築されたビルダーベースの DTO。それが、 上記の欠落している build() 呼び出しによって生じる違いなので、テストではその違いが全体にわたって検出されます。 一度に 1 つのフィールドではなく、一度に OpenAI ワイヤー モデルを作成します。同じテストは次の場合にも失敗します。 ビルダーベースの DTO に @JsonCreator がないか、そのビルダーに @JsonAutoDetect がありません。

独自の JSON をプラグインする場合Jackson 3 を使用する場合、このセクションは必要ありません。依存関係を追加するだけで十分です。それはのためです​

LangChain4j に選択させるのではなく、独自に構成された JSON マッパーを LangChain4j に提供するフレームワーク 1 つは、langchain4j-jackson3 自体が行うことです。 LangChain4j には単一の JSON エントリ ポイントがありません。それぞれのコーデックを ServiceLoader に要求します。 それぞれ個別に回答できるように、以下の場所を選択します。 |サービスインターフェース | LangChain4j がどのように読み書きするかを決定します。|---|---| | dev.langchain4j.spi.json.JsonCodecFactory |汎用 JSON — AI サービスの構造化出力、モデルのツール引数 | | dev.langchain4j.spi.json.ProviderJsonCodecFactory | LLM プロバイダーと交換されるリクエストとレスポンス | | dev.langchain4j.spi.json.StateJsonCodecFactory |タイプが事前に知られていないため、タイプ名が付けられる状態 — エージェント状態 | | dev.langchain4j.spi.data.message.ChatMessageJsonCodecFactory |あなたが保持するチャットの記憶 | | dev.langchain4j.spi.agent.tool.ToolSpecificationJsonCodecFactory | ToolSpecification.toJson() と ToolSpecification.fromJson(String) | | dev.langchain4j.spi.prompt.structured.StructuredPromptFactory | @StructuredPrompt テンプレート | | dev.langchain4j.spi.store.embedding.inmemory.InMemoryEmbeddingStoreJsonCodecFactory | InMemoryEmbeddingStore.serializeToJson() | 最後の 1 つは langchain4j に住んでいます。残りは langchain4j-core に住んでいます。すべて @Internal です。 ここでは、アプリケーションではなく統合を目的としており、マイナー間で変更される可能性があることを意味します。 バージョン。

  • フレームワーク独自の実装が優先されます。* 何かがこれらのいずれかを既に提供している場合 - Quarkus 4 つあります。このモジュールを追加しても、それがなくなるわけではありません。ジャクソン 3 工場は、より低い水準を宣言 他のものよりも優先されるため、他に要求されていないサービスにのみ適用されます。これ サイレントに発生します。優先順位によってどの実装が使用されるかが決まるため、警告はログに記録されません。 つまり、このようなフレームワークでは、プロバイダーのトラフィックとエージェントの状態など、オプトインが部分的な設計になっています。 フレームワークが所有するサービスは独自のコーデックに残りますが、Jackson 3 に移行します。全部欲しいなら Jackson 3 上のアプリケーションでは、フレームワークの登録を削除します。
  • すべてを実装するか、どれを省略するかを把握してください。* それぞれは個別に解決されます。 実装が登録されていないものは、Jackson 2 にフォールバックします。一部には回答するが、他には回答しないということはできません。 エラーが発生し、警告は生成されません。たとえば、チャット メモリが書き込まれるアプリケーションが生成されます。 マッパーとエージェントの状態は別のライブラリによって異なります。意図的に 1 つを省略すると、フォールバックが発生します。 得られるものです。 すでに古いバージョンと統合している場合は、このうち 2 つをもう一度検討する価値があります。 ProviderJsonCodecFactory と StateJsonCodecFactory は新しいものなので、既存の統合 それらについては知りませんが、プロバイダー トラフィックとエージェントに Jackson 2 を静かに使用しながら動作し続けます 状態。