🙆

人間の「曖昧な記憶」を技術でどう補完するか? 〜名刺検索AIエージェントにおける「翻訳」と「推論」のアプローチ〜

に公開

「名刺管理アプリ」と聞いて、どんな機能を思い浮かべますか?
おそらく、カメラで撮影してデータ化し、名前や会社名で検索する機能をイメージするでしょう。

しかし、現実のビジネスシーンで私たちが直面するのは、もっと曖昧な記憶との戦いです。

「先月会った営業の人、誰だっけ...? 確か東北出身って言ってたような...」

この「先月」や「東北」といった**人間の感覚的な言葉(フック)**は、これまでのデータベースシステムにとって「ノイズ」でしかありませんでした。「2024-10-01〜2024-10-31」や「青森県 OR 岩手県 OR ...」と入力しなければ、システムは答えてくれなかったのです。

今回、VoltAgentフレームワークを使用して開発したAIエージェントは、この**「人間の曖昧な記憶」と「データベースの厳密な条件」の間のギャップを、技術でどう埋めるか**というテーマに挑戦しました。

この記事では、単なるAIの実装だけでなく、**「曖昧さを補完するための技術的アプローチ」**に焦点を当てて解説します。

課題:記憶は「エピソード」、DBは「属性」

人間は情報を**エピソード(文脈)で記憶します。「暑い時期に会った」「出張のついでに会った」といった具合です。
一方、データベースは情報を
属性(値)**で管理します。「created_at: 2024-08-15」「address: 宮城県仙台市...」などです。

この「エピソード」から「属性」への変換をユーザーに強いるのが、従来の検索UIでした。
今回のシステムの目標は、この変換コストをシステム側が引き受けることです。

アプローチ:AIを「検索エンジン」ではなく「翻訳機」にする

LLM(大規模言語モデル)に名刺データを全部食わせて「探して」と頼むのは、コスト的にも精度的にも現実的ではありません(ハルシネーションのリスクもあります)。

そこで採用したのが、AIを「曖昧語 → クエリ言語」の翻訳機として配置し、確定的なロジック(ツール)で検索を実行するというアーキテクチャです。

全体像

ユーザーの曖昧な発話を受け取り、以下の3段階で「厳密化」していきます。

  1. 解釈(Interpretation): 「夏頃」とはいつか?「東北」とはどこか?
  2. 展開(Expansion): 検索可能なパラメータ(日付範囲、都道府県リスト)へ変換。
  3. 推論(Reasoning): 完全一致しなくても、「可能性が高い」候補を計算して提案。

技術実装1:「時間の感覚」をコードで定義する

「夏頃に会った」と言われたとき、システムはどう振る舞うべきでしょうか。
LLMに「夏っていつ?」と聞くと、毎回微妙に違う答えが返ってくる可能性があります。検索システムの再現性を保つため、ここはロジックとして定義しました。

src/utils/time-parser.ts
export function parseTimeExpression(expression: string): DateRange | null {
  const now = new Date();
  // ...

  // 「夏」という感覚を定義する
  // ここでは「6月1日から8月31日」と定義
  if (//.test(expression)) {
    const year = /去年|昨年/.test(expression) ? currentYear - 1 : currentYear;
    return {
      start: new Date(year, 5, 1), // 6月
      end: new Date(year, 7, 31, 23, 59, 59), // 8月
    };
  }

  // 「最近」という感覚を「直近1ヶ月」と定義
  if (/最近/.test(expression)) {
    // ...
  }
}

こうして**「曖昧な時間表現」を DateRange 型という「扱いやすい形」に変換**するツールを用意し、AIには「時間っぽい言葉が来たらこのツールを通せ」と指示します。これにより、ユーザーのふんわりした発言が、DBが理解できる厳密な Where 句に変わります。

技術実装2:「空間の概念」を展開する

「東北の人」という検索も同様です。DBには「住所」しか入っていないため、「東北」という文字列で検索してもヒットしません。
ここで必要なのは、「東北」という概念を、具体的な構成要素(県名)に展開する処理です。

src/utils/region-parser.ts
export const REGION_MAPPING: Record<string, string[]> = {
  // 人間のメンタルモデルに合わせた地域定義
  東北: ["青森", "岩手", "宮城", "秋田", "山形", "福島"],
  名古屋近辺: ["愛知", "岐阜", "三重"], // 「名古屋」と言いつつ三重を含む感覚をカバー
  // ...
};

このマッピングテーブルを持つツールをAIに持たせることで、
ユーザーの「東北」→ AI「parseRegion("東北")を実行」→ ツール「6県リストを返却」→ AI「6県リストでDB検索」
という連携が可能になります。

技術実装3:「うろ覚え」を許容するスコアリング

従来のDB検索は「0か1か(ヒットするかしないか)」の世界です。
しかし、人間の記憶は不確かです。「名前は違うけど、時期と場所は合ってる」というケースこそ、ユーザーが見つけたい情報だったりします。

そこで、単なるフィルタリングではなく、加点方式のスコアリングロジックを実装しました。

src/tools/business-card-search.ts
function calculateMatchScore(card, query, filters) {
  let score = 0;
  const matchedConditions = [];

  // 1. 名前・会社名のマッチング(完全一致じゃなくても部分一致で加点)
  if (card.name.includes(query)) {
    score += 100; // 強い確信
  }

  // 2. コンテキストのマッチング(「うろ覚え」を補完する要素)
  // 名前が違っても、場所が合っていれば加点
  if (filters.regions.includes(card.region)) {
    score += 20;
    matchedConditions.push("地域一致");
  }
  
  // 時期が合っていれば加点
  if (isInDateRange(card.createdAt, filters.dateRange)) {
    score += 20;
    matchedConditions.push("時期一致");
  }

  return { score, matchedConditions };
}

このロジックにより、以下のような**「気の利いた提案」**が可能になります。

ユーザー: 「宮城の田仲さん?」
AI: 「『田仲』さんという方は見つかりませんでしたが、宮城にいらっしゃる田中(たなか)さんなら見つかりました(地域一致)。こちらの方ではありませんか?」

これこそが、技術によって曖昧さを補完するという体験の核心です。

AIエージェントによるオーケストレーション

これらの「曖昧さ補完パーツ(ツール)」を統率するのが、VoltAgentで実装されたAIエージェントです。

エージェントのシステムプロンプト(Instructions)には、単なる役割だけでなく、**「思考の順序」**を教え込みます。

instructions: `
ユーザーの言葉には曖昧さが含まれます。以下の手順で具体化してから検索してください:

1. まず、ユーザーの発言から「いつ」「どこで」「どんな」の要素を抽出する。
2. 「いつ」が含まれていれば \`parseTimeRange\` で日付に変換する。
3. 「どこで」が含まれていれば \`parseRegion\` で地域リストに変換する。
4. それらの具体的な条件を使って \`searchBusinessCards\` を実行する。
5. 結果が0件でも、条件を緩和して再検索するか、類似の候補を提案する。
`

AIは、ユーザーの言葉という「非構造データ」を、ツールを使って「構造化データ」に変換し、その結果(JSON)を見て、最終的な回答を自然言語で生成します。

まとめ

「曖昧さを技術で補う」ために行ったアプローチをまとめると:

  1. 定義する: 「夏」「最近」などの感覚的な言葉をコードで定量化する。
  2. 展開する: 「東北」などの概念的な言葉を具体的な値の集合に分解する。
  3. 許容する: 完全一致だけでなく、スコアリングによって「惜しい」候補を拾い上げる。
  4. 翻訳する: AIエージェントを使って、自然言語をこれらのロジックへ繋ぎこむ。

技術(データベースやプログラム)は本来、曖昧なものを嫌います。
しかし、AIエージェントを中間に挟み、適切な「翻訳ツール」を持たせることで、システム側が人間に歩み寄るような、柔らかなインターフェースを作ることができます。

「名前を思い出せないから検索できない」という不条理をなくし、ビジネスの機会損失を防ぐ。
そんな「人間に優しいシステム」を作るためのヒントになれば幸いです。


使用した技術スタック

  • VoltAgent (AI Agent Framework)
  • AWS Lambda (Compute)
  • Amazon DynamoDB (Database)
  • Anthropic Claude 4.5 Haiku (LLM)
リバナレテックブログ

Discussion