1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

生成しないAI「Jev」とは? IBM BobでJavaアプリの検索リランキングに組み込んでみた

1
Posted at

はじめに

「AIの機能が進化したら、ビジネスルールのテキストとAIだけでアプリケーションを置き換えられるのではないか?」
そんなふうに考えていた時期が私にもありました。
AIがアプリケーションの挙動を代替できたら「アプリケーション開発」という業務がほぼ不要になるという未来予想図です。

LLMとMCPなどの周辺技術が進化した現在、技術的にはAIへ多くの判断を委ねられるようになりました。
ただ、実際にAIを中核にビジネスロジックを置き換えた場合、性能面とランニングコストは通常のアプリケーションに劣るため現実的な実装になりにくい、という感触もつかめてきました。また、AI特有の出力のゆらぎもビジネスにとって不安要素ともなりえます。

この状況下で、フロンティアAIとは別の切り口で「Jev」というAIがリリースされました。「判断特化型AI」「性能とランニングコストが効率的」という触れ込みで上に挙げた課題を解決してくれるかもしれません。

この記事ではJevのユースケースの想定と実装にを考えていきます。
前半ではJevの基本概念とアプリケーションへの組み込み方を整理し、後半ではIBM Bobを使って既存Javaアプリケーションへ導入します。

ユースケースに焦点を当てた記事のため、Jevが提供する機能の詳細については深掘りしていません。

TL;DR

概要一枚図

アプリケーション全体をAIに置き換えるのではなく、従来コードでは扱いにくい判断だけをJevで補完します。この記事では、IBM Bobを使って既存Javaアプリへの適用箇所を検討し、検索リランキングを題材に設計・実装します。

Jev概説

テキストを入力とし、判断結果を定量的に出力する」モデル。その特性からアプリケーションとの連携に強みがあります。

マルチモーダルなAIと異なり、入力はテキストですが、出力は質問の判定結果を数値化して返却します。
目的特化型にしたことによる高速処理・低コストでの運用が特徴となっています。
特に出力はプログラム処理に適した形となるため、プログラムとの連携が主な利用形態になるでしょう。

入力はテキストのみがカバーされていますが、
 Images, audio, and video are not supported (yet).
ドキュメントに記載されていますので、将来的に拡張される可能性はありそうです。

構成要素

Jevへの問合せに必要な情報は QuestionsState の2つです。

構成要素 解説
Questions AIに対する固定的なプロンプト
State リクエスト毎に可変となる情報

Questionsには、次の3つの項目を指定します。

構成要素 解説
type 質問・回答の形式を Choice、Score、Noul の3タイプから指定します
instructions プロンプトの本体です
criteria Jevが回答を準備する際の選択肢、およびその意味を定義します

また、Questionsは複数の質問をまとめておくことができ、Stateに記載した内容を一括で確認することができます。

3タイプの入力と出力

type 入力 出力
Choice criteriaに、順序を持たない候補とその意味を定義する 選択結果、各候補の予測確率、確信度
Score criteriaに、順序を持つ評価レベルを定義する 加重スコア、各レベルの予測確率、確信度
Noul Yes/Noで評価できる指示をinstructionsに指定する。criteriaは任意 Yesである確率。独立したconfidenceはない

確信度(confidence)は、各選択肢の予測確率のバラつきを示します。特定の選択肢に予測確率が集中するほど高くなります。
例えば、5つの選択肢への予測確率が、0%・10%・80%・10%・0% のようなケースでは確信度は高めになります。これが 20%・20%・20%・20%・20% のような結果であれば、確信度は低くなります。

アプリケーション上の判断では、各選択肢の予測確率および確信度の両方を参照することになるでしょう。
例えば、ラベリング処理で1つの選択肢を選択するケースでは基本的に「予測確率が最高の選択肢を選ぶ」ことになりますが、「ただし確信度が低ければ、選択を保留する」といった取り扱い方も考えられます。

Scoreでは、総合的な評価を数値として出力します。そのままビジネスロジックの判定に使いやすいですが、こちらも場合により確信度を併用して、結果の採否を検討すべきでしょう。

Noulは、質問の真偽を問うシンプルな質問パターンです。これには確信度は付帯しません。

JevによるアプリケーションとAIの統合

Jevは「AI-powered software」の構築向けにデザインされています。

上のドキュメントに、Jevが想定している実装パターンが記載されています。
判断特化AIではあるものの、従来のアプリケーションで記載できる決定論的なロジックはコードで実現し、これでカバーできない領域(常識に基づく判断非構造化データの対応)にJevを適用することが推奨されています。
AIに全てを任せるよりは、アプリケーションとAIのハイブリッドが現時点の最適解ということなのだと思います。

Jevに対する質問はクローズドクエスチョンに限定されます。開発者側が回答の選択肢を把握しているため、Jevの判断をコードに接続する箇所も問題なく実装できるでしょう。この仕様からも、Jevとアプリケーションの親和性は高いといえます。

Jevのユースケース

判断を伴う多様なユースケースに対応します。

上のドキュメントでは、Typesafe AIの提示するユースケース案がリストされています。
この記事では、事務アプリで想像できそうな例をQuestionのTypeを意識して挙げてみます。

ユースケース 主なType 解説
入力フォームのチェック Noul / Score 論理矛盾だけでなく、妥当性、十分性、リスクなどを評価する
事務ワークフローの事前処理 Choice / Score / Noul 非構造化テキストを分類・数値化し、処理ルートを決定する
自然言語によるオペレーション Choice 公式サイトのスマートホームデモにあるような、定義済みの操作候補からユーザーの意図に合う操作の選択

事務ワークフローは、クレーム対応処理であれば質問内容から深刻度を数値化・ラベリングすることでフロー遷移の制御条件にする、という使われ方になります。
自然言語によるシステム操作は現在のLLMでも実現可能ですが、より低コストで実現できるという点でユーザーインターフェースへの採用に向いているでしょう。

いずれのケースも、これまでは開発者が実現不可能として向き合うことを避けてきた領域といえるでしょう。
おそらくJevを使いこなすための最大のポイントは、開発者の意識改革にありそうです。

IBM Bobと実現するAI駆動アプリケーション

この章では、IBMが提供するソフトウェア開発を支援するAIパートナーである IBM Bob(以下 Bob)を使って、実際にアプリケーションにJevの機能を導入するタスクを体験します。

今回利用するアプリケーション

別の記事で取り上げた RealWorld というJavaアプリケーションを使用します。
これはQiitaのような記事投稿サイトの機能を提供するバックエンドアプリです。この記事では、既存のアプリにJevを使ってAI駆動の機能を追加する、という試みです。

導入箇所を検討する

TypesafeAIから、AIがJevの理解を深めるためのスキルが提供されています。これを使って、Bobと導入箇所のディスカッションを行います。

まずはスキルをインストールします。

npx skills add typesafe-ai/skills --skill typesafe-ai

インストール後、Bobでプロジェクトを開いて次のように質問します。

TypeSafeスキルを使って、このプロジェクトのコードを解析したうえで、Jevで知的な判断を活用できるポイントを見つけてください。

この質問に対し、Bobからの回答を整理すると次のようになりました。

  • 記事作成時の「タグ自動推薦・カテゴリ分類」
分野 解説
課題 ユーザーが手動でタグを入力しない場合や、タグの表記揺れ・不整合が発生する。
Jevのプリミティブ Choice または Noul(各候補タグへの適合判定)
設計 ・state: 記事の title, description, body, 既存の人気タグリスト
・記事投稿時に本文・要約を評価し、既存の候補タグセットから適切なタグを選択、またはタグ未指定時に自動付与。
・確信度(Confidence)が一定値以上のタグのみを自動採用。
  • コメント・記事の「モデレーションと有害性判定(Verify & Escalate)」
分野 解説
課題 スパム、誹謗中傷、利用規約違反のコメント・記事の検知。
Jevのプリミティブ Noul(違反判定) + Score(違反重大度スコア)
設計 ・state: comment.body または article.body, 作成者の過去のステータス
・is_toxic(Noul)の確率を判定。
・確率・重大度スコアに応じてワークフローを分岐:
 ・安全圏(低スコア): そのまま公開
 ・グレーゾーン(中スコア): フラグを立てて管理者レビュー待ち(Escalate)
 ・明白な違反(高スコア): 自動却下・非公開化
  • 記事フィード・検索の「セマンティック・リランキング(Reranking)」
分野 解説
課題 現在は作成日時(created_at)順や単純なタグ一致によるフィード表示のみで、ユーザーの関心度や文脈に沿った並び順になっていない。
Jevのプリミティブ Score(適合度スコア)
設計 ・DBから候補記事をフェッチ後、ユーザーの閲覧・お気に入り傾向や検索クエリに対する適合度を各記事について判定。
・得られた確率加重スコアを用いて複合スコアリング(Composite Scoring)を行い、リランキングして返す。

各々、「投稿ユーザー向け」「運営者向け」「閲覧ユーザー向け」の機能改善となっており、さまざまな局面でJevを適用できる期待感があります。

この記事では、価値の分かりやすさなどを考慮して、3つめの「セマンティック・リランキング」をターゲットに深掘りしていきます。

設計を詳細化する

Bobと会話しながら、実装を意識したレベルの設計情報をつくります。
最終的に次のように整理しました。

Step 処理 説明
1 投稿時の静的評価 記事単体をJevで評価し、複数次元のスコアをarticle_scoresへ保存する。
2 候補抽出 従来の検索処理(タグ一致、全文検索など)により候補記事を絞る。
3 一次ランキング 静的評価(ユーザーの嗜好で重みづけ)、ソーシャル&鮮度シグナル、パーソナライズ・ブースト の要素を合成して表示順を決める。
4 Jevによる動的リランキング 上位N件について、検索クエリと各記事の関連度をJevで評価する。
5 最終順位決定とページング 一次スコアと動的関連度を合成した後、ページ単位に分割して返す。

よりユーザーにマッチした記事を上位に表示するため、検索クエリと記事本文の関連度をJevで評価してソート条件に組み込みます。
ただ抽出対象の全件についてこの評価を行うと、処理が重くなりすぎます。そのため、注目されやすい上位N件に絞って追加評価を行う仕様としています。

スコア算定における要素選定や段階的なスコアリングという考え方は、Bobが把握している検索エンジンロジックのベストプラクティスが検討のベースになっています。
Jevを使ったアプリでは最終的に「出力された数値の加工や閾値をどのように利用するか」を具体化する必要がありますが、決定論的なロジックに慣れている設計者には経験が薄い部分です。
BobなどのAIを使って設計を進めることで、これらの経験を補完することができました。

実装する

対象のアプリケーションはQuarkus上で動かすJavaアプリケーションです(詳細はこちらの記事を参照してください)。
公式サイトのクライアントSDKはPython、TypeScript向けに提供されていますが、HTTPベースのAPIも提供されているため、Javaからの呼び出しも可能です。

この記事では、PythonのSDKに寄せる形でライブラリをまず作成し、これを業務ロジックから呼ぶ形で作成しています。
投稿処理のタイミングでJev評価を行っているコードは次のようになります。Jevに関係する部分を抜粋していますので、プログラム上での組み込み方法の参考にしてください。

ArticleStaticScoringService.java (新設、抜粋)

  // Stateのテキストを作成する。
  Map<String, Object> state = new LinkedHashMap<>();
  Map<String, String> articleState = new LinkedHashMap<>();
  articleState.put("title", article.getTitle());
  articleState.put("description", article.getDescription());
  articleState.put("body", article.getBody());
  state.put("article", articleState);

  Map<String, Question> questions = new LinkedHashMap<>();

  // Questionsのテキストを作成する。
  questions.put("technical_depth", ScoreQuestion.builder()
      .instructions("Evaluate the technical depth of the article.")
      .criteria(List.of(
          "Surface level introduction or brief concept overview without technical details",
          "Standard technical explanation with basic code snippets and common patterns",
          "In-depth architectural analysis, internal mechanics, performance trade-offs, and robust design"
      ))
      .build());

  questions.put("practicality", ScoreQuestion.builder()
      .instructions("...")
        
        

  // API呼び出し
  SystemOneResponse response = typeSafeClient.systemOne(state, questions);

  // Score output is 0.0, 1.0, 2.0 (normalized to 0.0 - 1.0 by dividing by max level 2.0)
  double technicalDepth = extractNormalizedScore(response.getScore("technical_depth"), 2.0);
  double practicality = extractNormalizedScore(response.getScore("practicality"), 2.0);

おまけ:複数次元評価のQuestions

あなたの記事をJevに評価してもらいましょう。

上記のロジックで使用しているQuestionは次のとおりです。Qiita記事を書かれている皆さまは、ぜひ自分の記事で評価してみるのはいかがでしょうか。
かかるコストは自分で試したところ、1記事分の評価で $0.0005(0.08円) でした。

questions
{
  "technical_depth": {
    "type": "score",
    "instructions": "Evaluate the technical depth of the article.",
    "criteria": [
      "表面的な紹介や概念の概要のみで、技術的な掘り下げがない",
      "基本的な仕組みには触れているが、説明が浅く一般論の域を出ない",
      "一般的なコード例と基本構成の説明があり、標準的な理解が得られる",
      "内部挙動や設計背景にある程度踏み込み、実装上の注意点にも言及している",
      "内部挙動やトレードオフに深く踏み込み、設計判断の理由まで解説されている"
    ]
  },
  "practicality": {
    "type": "score",
    "instructions": "Rate how practically applicable and actionable the article is.",
    "criteria": [
      "抽象的な概念のみで実践例がない",
      "実践例はあるが断片的で、実際に手を動かすには情報が不足している",
      "基本的なサンプルコードが付属しており、最小限の実践は可能",
      "実務を想定した手順とコードがあり、多少の応用で現場に適用できる",
      "そのまま現場で応用できる実践的な手順とコードが網羅され、再現性が高い"
    ]
  },
  "beginner_friendly": {
    "type": "score",
    "instructions": "Rate how suitable this article is for beginners.",
    "criteria": [
      "高度な前提知識が必要で初学者には難解",
      "前提知識の説明が乏しく、初学者にはやや厳しい",
      "ある程度の予備知識があれば追える",
      "専門用語には簡単な補足があり、予備知識が少なくても大筋は理解できる",
      "前提知識が丁寧に説明されており初学者でも再現可能"
    ]
  },
  "originality": {
    "type": "score",
    "instructions": "Evaluate the uniqueness and original insight provided by the author.",
    "criteria": [
      "ドキュメントや他記事の単なる転載・まとめ",
      "既存情報の再構成が中心で、著者独自の視点はほぼ見られない",
      "一般的な解説に著者の視点が少し加わっている",
      "著者自身の検証や工夫が部分的に含まれ、一定のオリジナリティがある",
      "実体験に基づく深い考察や独自の検証結果が含まれている"
    ]
  },
  "clarity": {
    "type": "score",
    "instructions": "Rate the structural clarity and readability of the article.",
    "criteria": [
      "構成が乱れており要点が分かりにくい",
      "構成に一貫性がなく、読み進めるのにやや苦労する",
      "標準的な構成で問題なく読める",
      "見出しや図表が適切に使われ、要点が把握しやすい",
      "見出し、コード、解説のバランスが優れ極めて明快"
    ]
  },
  "completeness": {
    "type": "score",
    "instructions": "Rate the self-contained completeness of the topic covered.",
    "criteria": [
      "メモ程度で途中で途切れている",
      "概要の一部しか触れられておらず、話が完結していない",
      "一通りの概要は網羅されている",
      "実装や検証にも触れているが、一部を他記事や外部情報に依存している",
      "前提から実装・検証まで記事単体で完全に完結している"
    ]
  }
}

state
"article": {
  "title": "<タイトル>",
  "body": "<マークダウン形式の投稿データ>"
}

上の内容は、TypeSafe.aiのコンソールで実際に試すことができます。

コンソール

同様の評価結果はフロンティアモデルでも可能なのですが、上で紹介したQuestionsを同一記事で処理・比較したところの応答時間では
 Jev:0.4秒
 Haiku 4.5:約6秒
となりました(各1回計測の実測値)。Jevの処理が圧倒的に速いことが分かります。

おわりに

これまでアプリケーション開発の分野に登場するAIといえば、「AI駆動開発」など開発作業そのものにフォーカスされることが多く、その他はMCPサーバーによるAIエージェントへの機能提供などでした。

Jevが示しているのは、それとは異なる方向性です。アプリケーション全体をAIへ置き換えるのではなく、従来のコードだけでは扱いにくかった意味的な判断を、型付きの小さな部品としてアプリケーションへ組み込みます。

今回、Jevを既存のアプリケーションへ導入する一連のプロセスを通じて、AIによる判断をアプリケーションの処理へ組み込むことの有用性と、現実的に実装できることを確認できました。

「AIがアプリケーションの挙動をすべて代替する」世界は、まだ先かもしれません。一方で、決定論的な処理はコードに残し、意味的な判断だけをJevに任せるアプローチは、現在のアプリケーションへAIを取り入れるための、現実的で有力な選択肢だと感じました。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?