Summarization cookbook
======================

基本的な要約を超えて\ ``aidb.summarize_text_aggregate()``
を使用するための現実世界のレシピ。各レシピは、データに適応できる自己完結型のパターンです。

すべての例では、テーブルを含むsalesデータセットを使用します

レシピ
------

1.カテゴリ別にまとめます
^^^^^^^^^^^^^^^^^^^^^^^^

**使用する場合**
任意のディメンション製品、顧客、地域、期間ごとにグループ化されたテキストの概要が必要です。

.. code:: sql

   SELECT p.product_name,
          count(sn.note_id) AS note_count,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(my-llm)::json
          ) AS summary
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY p.product_name
   ORDER BY note_count DESC;

- チャンクしない場合、各グループのすべてのテキストは単一のLLM呼び出しとして送信されます。

- 500ノート各平均〜250文字未満のグループの場合、チャンクなしが最速です。

- 大規模なグループの場合、チャンクを追加してコンテキストウィンドウのオーバーフローを回避します
  :ref:`Recipe 7 <#7-detailed-summaries-append-strategy>` を参照してください。

2.ディール損失分析
^^^^^^^^^^^^^^^^^^

**使用する場合**
取引が失われている理由を、実行可能な理由とともに理解したいと考えています。

.. code:: sql

   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  prompt => Analyze these sales notes and answer: Why are we losing deals? 
                            What are the top reasons for failure? 
                            Provide specific, actionable insights.
              )::json
          ) AS loss_analysis
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   WHERE so.status IN (lost, closed_lost)
   GROUP BY p.product_name;

- LLMが失敗パターンに焦点を当てるように、失われた取引のみ\ ``WHERE status IN ('lost', 'closed_lost')``
  にフィルターします。

- プロンプトは具体的である必要があります。「top
  resume」は、「analyze」よりも良い結果をもたらします。

- より多くの制約された出力については、 :ref:`Recipe 8 <Functions reference>` を参照してください。

3.感情分析
^^^^^^^^^^

**使用する場合**
グループ化されたテキストから全体的な感情ポジティブ/ネガティブ/混合を測定したい。

.. code:: sql

   - - Compare sentiment between won and lost deals
   SELECT p.product_name,
          so.status AS deal_outcome,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  prompt => Analyze the overall sentiment of these entries. Provide: 
                            1) Overall sentiment (positive/negative/neutral/mixed), 
                            2) Key positive themes, 
                            3) Key negative themes, 
                            4) Notable concerns if any.
              )::json
          ) AS sentiment
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   WHERE so.status IN (won, lost)
   GROUP BY p.product_name, so.status
   ORDER BY p.product_name, so.status;

- 獲得した感情と失われた感情を並べて比較すると、成功した取引の違いが明らかになります。

- プロンプトの番号付きフォーマットは、構造化された出力をガイドしますが、
  LLMの遵守は規模で異なります :ref:`既知の制限 <既知の制限>` を参照してください。

4.重要なインサイトの抽出
^^^^^^^^^^^^^^^^^^^^^^^^

**使用する場合**
多くのエントリにわたって最も重要な所見の簡潔なリストが必要です。

.. code:: sql

   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  prompt => Extract the top 5 key insights from these entries as a numbered list. 
                            Focus on actionable findings, patterns, and important trends.
              )::json
          ) AS insights
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY p.product_name
   ORDER BY count(sn.note_id) DESC
   LIMIT 5;

- プロンプトの「トップN」と「番号付きリスト」は、出力長をコンストレインします。

- 中程度のグループサイズ50〜500ノートで最適に動作します。非常に大規模なグループでは、LLMが特定の洞察ではなく一般的な概要を生成する場合があります。

5.問題の分類
^^^^^^^^^^^^

**使用する場合**
問題またはテーマを事前定義されたバケットに分類する必要があります。

.. code:: sql

   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  prompt => Categorize these sales notes into the following categories: 
                            Pricing Concern, Technical Issue, Competitive Loss, 
                            Timing/Budget, Feature Gap, Relationship/Trust, Integration Challenge. 
                            For each category provide the count and percentage of entries that match, 
                            plus a brief description.
              )::json
          ) AS categories
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   WHERE so.status IN (lost, closed_lost)
   GROUP BY p.product_name;

- プロンプトでカテゴリを明示的に定義します。LLMに選択させないでください。

- カウント/パーセンテージを要求して、定量的な出力を取得します。

- LLMは、要求されたフォーマットに完全に従わない場合があります。より信頼性の高いフォーマットするには、ラッパーファンクション
  :ref:`Recipe 8 <Functions reference>`  を使用します。

6.エグゼクティブサマリー リデュース戦略
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**使用する場合**
詳細な説明ではなく、短く圧縮された概要が必要です。ダッシュボードとレポートに適しています。

.. code:: sql

   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  aidb.chunk_text_config(100, 100, 10, words),
                  NULL,
                  reduce,
                  3  -- reduction_factor: each chunk targets desired_length/3 words
              )::json
          ) AS executive_summary
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY p.product_name;

仕組みテキストは100ワードのチャンクに分割されます。各チャンクは\ ``desired_length / reduction_factor``
ワード100/3 ≈
チャンクごとに33ワードをターゲットに要約されます。最終結果が\ ``desired_length``
内に収まるまで、要約は結合、再チャンク、および再要約されます。出力は約400〜900文字高圧縮です。

- ``reduction_factor=3`` は、各チャンクをそのサイズの約33%に圧縮します。
  ``rf=2`` 〜50%まで。

- Reduceでは常にワードベースのチャンクを使用します。charベースは失敗する場合があります
  :ref:`既知の制限 <既知の制限>` を参照してください。

- 最小安全なチャンクサイズ50ワード。

7.詳細な概要追加戦略
^^^^^^^^^^^^^^^^^^^^

**使用する場合**
テキストのすべての部分の詳細を保持する包括的なカバレッジが必要です。

.. code:: sql

   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  aidb.chunk_text_config(200, 200, 20, words),
                  NULL,
                  append
              )::json
          ) AS detailed_summary
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY p.product_name;

仕組みテキストは、20のワードがオーバーラップする200ワードのチャンクに分割されます。各チャンクは独立して要約されます。概要が連結されます。出力は約5,000〜15,000文字冗長、詳細です。

- 大きなチャンク200ワード = 少ないLLM呼び出し =
  高速ですが、粒度が低くなります。

- 小さなチャンク50ワード=より多くのLLM呼び出し=遅くなりますが、より詳細です。

- 20ワードのオーバーラップにより、チャンク境界でコンテキストが失われません。

8.再利用可能な構成ラッパーファンクション
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**使用する場合**
制約された出力形式での一貫した反復可能な分析が必要です。

事前構築された構成を返すSQLファンクションを作成し、\ ``summarize_text_aggregate()``
に直接渡します。このパターンは、JSONを返すファンクション内のプロンプトロジックをラップするため、長いプロンプト文字列を繰り返すことなく\ ``GROUP BY``
でクリーンに使用できます。

**焦点を絞った分析**

.. code:: sql

   CREATE OR REPLACE FUNCTION analyze_top_reasons_config(
       p_question TEXT,
       p_n        INTEGER DEFAULT 3,
       p_model    TEXT    DEFAULT my-llm
   ) RETURNS JSON AS $$
       SELECT aidb.summarize_text_config(
           p_model,
           prompt => format(
               Answer this question about the text: %s 
               Give exactly %s reasons, each as a single sentence. 
               No preamble, no extra commentary.,
               p_question, p_n
           )
       )::json;
   $$ LANGUAGE sql;

   - - Usage: pass the config function directly to the aggregate
   SELECT product_name,
          aidb.summarize_text_aggregate(
              note_text,
              analyze_top_reasons_config(Why are customers churning?, 3)
          ) AS churn_reasons
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   WHERE so.status = lost
   GROUP BY product_name;

**構造化された感情**

.. code:: sql

   CREATE OR REPLACE FUNCTION analyze_sentiment_config(
       p_model TEXT DEFAULT my-llm
   ) RETURNS JSON AS $$
       SELECT aidb.summarize_text_config(
           p_model,
           prompt => Analyze sentiment. Respond ONLY in this format:
   OVERALL: [positive/negative/neutral/mixed]
   SCORE: [1-10]
   TOP_POSITIVE: [one sentence]
   TOP_NEGATIVE: [one sentence]
   TREND: [improving/declining/stable]
       )::json;
   $$ LANGUAGE sql;

   - - Usage
   SELECT product_name,
          aidb.summarize_text_aggregate(note_text, analyze_sentiment_config()) AS sentiment
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY product_name;

**問題カテゴライザー**

.. code:: sql

   CREATE OR REPLACE FUNCTION categorize_issues_config(
       p_categories TEXT[]  DEFAULT ARRAY[
           pricing, technical, competition,
           timing, budget, feature_gap, other],
       p_model      TEXT    DEFAULT my-llm
   ) RETURNS JSON AS $$
       SELECT aidb.summarize_text_config(
           p_model,
           prompt => format(
               Categorize the issues in this text into ONLY these categories: %s. 
               For each category, give a count and one representative example. 
               Format: CATEGORY: count - "example quote",
               array_to_string(p_categories, , )
           )
       )::json;
   $$ LANGUAGE sql;

   - - Usage
   SELECT product_name,
          aidb.summarize_text_aggregate(note_text, categorize_issues_config()) AS categories
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   WHERE so.status IN (lost, closed_lost)
   GROUP BY product_name;

- 構成ラッパー機能は、一貫したインターフェイスを提供し、クエリを変更せずにプロンプトを調整できます。

- 戻り値の型は\ ``summarize_text_aggregate``
  のパラメーター型と一致するように、\ ``JSONB`` ではなく\ ``JSON``
  である必要があります。

- 「プリアンブルなし」、「のみ」、「このフォーマットで応答」は効果的なステアリングフレーズです。

9.要約前のテキストのスクラブ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**使用する場合**
テキストデータには、LLMトークンを無駄にするフィラーワード、挨拶、署名、またはボイラープレートが含まれています。

クリーンアップファンクションを作成し、集計の前に適用します。

.. code:: sql

   CREATE OR REPLACE FUNCTION clean_note_text(p_text TEXT)
   RETURNS TEXT AS $$
   BEGIN
       RETURN regexp_replace(
           regexp_replace(
               regexp_replace(
                   regexp_replace(p_text,
                       -- Remove email signatures
                       E(Best regards|Sincerely|Thanks|Cheers),?\s *\n.* $,
                       , gi),
                   -- Remove greeting lines
                   E^(Hi|Hello|Dear|Hey)\s+[A-Za-z]+,?\s*\n,
                   , gi),
               -- Remove filler phrases
               E\b(basically|essentially|actually|literally|you know|I mean|sort of|kind of)\b,
               , gi),
           -- Collapse whitespace
           E\s+,  , g);
   END;
   $$ LANGUAGE plpgsql IMMUTABLE;

   - - Use it:
   SELECT product_name,
          aidb.summarize_text_aggregate(
              clean_note_text(note_text),
              aidb.summarize_text_config(my-llm)::json
          ) AS summary
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY product_name;

- ``IMMUTABLE`` PostgreSQLは、繰り返しの呼び出しを最適化します。

- データの正規表現パターンたとえば、内部専門用語、標準ヘッダーなどをカスタマイズします。

- 一般的な削減
  トークンが15〜30%減少します。これは、チャンクが減り、処理が高速になることを意味します。

レシピの組み合わせ 完全な最適化スタック
---------------------------------------

最大の速度と品質を得るには、スクラビング+フィルタリング+構成ラッパーを組み合わせます。

.. code:: sql

   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              clean_note_text(sn.note_text),
              analyze_top_reasons_config(Why are we losing these deals?, 3)
          ) AS loss_reasons
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   WHERE so.status IN (lost, closed_lost)
   GROUP BY p.product_name;

このパイプライン 関連する行 失われた取引にフィルタリングします。
``clean_note_text()``
を介して行ごとにフィラーテキストをストリップしますトークンが15〜30%減少します。クリーン化されたすべてのテキストを蓄積し、LLMに送信します。構成ラッパーを介して制約されたプロンプトを適用して、短く焦点を当てた出力を実現します。

パフォーマンスベンチマーク
--------------------------

テストスイートからのすべてのデータは、AIDB
6.1.0でOllamaを介して\ ``granite4:1b``
を使用して、salesデータセット18,503ノート、平均266文字/ノートに対して実行されます。

チャンクなしのパフォーマンス
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

チャンキングがない場合、グループ内のすべてのテキストは単一のLLM呼び出しとして送信されます。高速ですが、モデルのコンテキストウィンドウによって制限されます。

.. csv-table::
  :header: Group size,Duration,Result size,Notes
  :widths: 15,12,12,20
  :align: left
  :class: longtable

  77–84 notes,21–28s,"1,100–2,500 chars",安全な範囲、完全なデータ処理
  100 notes,28s,"2,200 chars",約26Kの文字入力、十分なコンテキスト内
  "2,915 notes",98s,"3,200 chars",131Kトークンを超えるコンテキストウィンドウ以下を参照してください
  "3,248 notes",91s,"1,700 chars",部分的なデータのみが処理されました

チャンク戦略の比較 50ノート
^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. csv-table::
  :header: Config,Est. LLM calls,Duration,ms/call,Result chars,Status
  :widths: auto
  :align: left
  :class: longtable

  No chunking,1,12s,"11,947","1,443",PASS
  words/50/append,32,152s,"4,759","12,159",PASS
  words/100/append,16,77s,"4,832","7,021",PASS
  words/200/append,8,48s,"6,044","4,781",PASS
  words/50/reduce rf=2,63,217s,"3,452",545,PASS
  words/100/reduce rf=2,31,102s,"3,280",475,PASS
  words/200/reduce rf=2,15,51s,"3,367",767,PASS
  words/50/reduce rf=3,50,170s,"3,396",410,PASS
  words/100/reduce rf=3,25,72s,"2,897",867,PASS
  words/200/reduce rf=3,12,44s,"3,661",535,PASS
  chars/200/append,40,246s,"6,154","16,355",PASS
  chars/400/append,20,137s,"6,835","11,793",PASS
  chars/800/append,10,66s,"6,584","5,897",PASS
  chars/200/reduce rf=2,81,971s,"11,988",—,FAIL
  chars/400/reduce rf=2,41,368s,"8,967",441,PASS
  chars/800/reduce rf=2,21,144s,"6,842",850,PASS

戦略効率の概要
^^^^^^^^^^^^^^

.. csv-table::
  :header: Strategy,Avg LLM calls,Avg total time,Avg ms/call,Avg output
  :widths: auto
  :align: left
  :class: longtable

  No chunking,1,12s,"11,947","1,443 chars"
  Append,21,121s,"5,868","9,668 chars"
  Reduce rf=2,34,176s,"5,182",616 chars
  Reduce rf=3,29,95s,"3,318",604 chars

予想される規模
^^^^^^^^^^^^^^

.. csv-table::
  :header: Scenario,100 notes,500 notes,"1,000 notes"
  :widths: 15,12,12,20
  :align: left
  :class: longtable

  No chunking,28s (1 call),~60s (1 call),"~100s (1 call, partial data*)"
  words/100/append,~77s (16 calls),~385s (80 calls),~770s (160 calls)
  words/100/reduce rf=3,~72s (25 calls),~180s (62 calls),~240s (125 calls)

- 1,000以上のノートでのノーチャンクは、コンテキストウィンドウを超える場合があります。完全を期すためにチャンクを使用します。

推奨される構成
--------------

.. csv-table::
  :header: Use case,Config,Why
  :widths: 12,25,15
  :align: left
  :class: longtable

  Fastest possible (< 500 notes),No chunking,"Single LLM call, stays within context window"
  Fast + detailed,words/200/append,"Fewest calls for append, good detail"
  Balanced detail,words/100/append,"More granular, moderate speed"
  Executive summary,words/100/reduce rf=3,"Compressed output, efficient reduce"
  Maximum compression,words/50/reduce rf=3,"Smallest output, most LLM calls"

一般的なガイダンス
チャンクなしで開始します。グループが〜500ノートを超える場合にのみチャンクを追加します。常に、文字ベースよりもワードベースのチャンクを優先します。
Reduceの場合、\ ``rf=2`` よりも\ ``rf=3``
を優先します。同様の出力品質で呼び出しの合計数が少なくなります。

既知の制限
----------

コンテキストウィンドウのオーバーフローサイレント
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

入力テキストの合計がモデルのコンテキストウィンドウを超えると、テキストはサイレントに切り捨てられます。エラーは発生しません。LLMは、適合するものを処理し、残りを無視します。

例えば ``granite4:1b``
には、131,072トークンのコンテキストウィンドウがあります。
3,248ノート806K文字、〜201Kトークンのグループは、これを53%超えます。結果は有効な概要ですが、データの一部にすぎません。

安全な制限チャンキングなし

.. csv-table::
  :header: Avg note size,Safe note count,Total tokens
  :widths: 12,25,15
  :align: left
  :class: longtable

  250 chars,~500 notes,~33K tokens
  500 chars,~250 notes,~33K tokens
  "1,000 chars",~125 notes,~33K tokens

回避策これらの制限を超える可能性のあるグループにはチャンクを使用します。チャンク化は、コンテキストウィンドウのサイズに関係なく、すべてのデータを処理します。

.. code:: sql

   - - Safe for large groups:
   aidb.summarize_text_config(
       my-llm,
       aidb.chunk_text_config(200, 200, 20, words),
       NULL,
       append
   )::json

小さなチャンクでの障害の削減
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``reduce``
ストラテジーでは、各要約ラウンドが入力よりも短い出力を生成する必要があります。チャンクサイズが小さい場合、LLMは入力よりも長い概要を生成することが多く、次の原因が発生します。

::

   Text summarization failed to reduce size. The summarized output is larger than or equal to the input.
   Consider adjusting the chunking parameters.

障害しきい値

.. csv-table::
  :header: Chunk type,Size,Result
  :widths: 12,25,15
  :align: left
  :class: longtable

  chars/200/reduce,200 chars,Always fails
  chars/400/reduce,400 chars,Unreliable
  chars/800/reduce,800 chars,Reliable
  words/50/reduce,50 words,Reliable
  words/100/reduce,100 words,Reliable
  words/200/reduce,200 words,Reliable

回避策 ``reduce``
でワードベースのチャンクを使用しますテストされたすべてのサイズで100の合格率。
charベースを使用する必要がある場合は、 ``>= 800`` charsを使用します。

温度、max_tokens、およびシステムプロンプトの制御
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

デフォルトでは、LLMはプロバイダーのデフォルト温度通常0.7〜1.0を使用します。これにより、実行ごとに出力に大きな分散が発生する可能性があります。
``inference_config``
を使用して、コールごとにこれらのパラメーターを制御します。

.. code:: sql

   - - Control temperature and max_tokens for more consistent, bounded output
   SELECT p.product_name,
          aidb.summarize_text_aggregate(
              sn.note_text,
              aidb.summarize_text_config(
                  my-llm,
                  NULL,
                  Summarize the key points,
                  NULL,
                  NULL,
                  aidb.inference_config(
                      temperature => 0.3,
                      max_tokens  => 500
                  )
              )::json
          ) AS summary
   FROM sales_notes sn
   JOIN sales_orders so ON sn.order_id = so.order_id
   JOIN products p ON so.product_id = p.product_id
   GROUP BY p.product_name;

   - - Override the system prompt for non-summarization tasks
   SELECT aidb.summarize_text(
       input   => Customer complained about slow response times and billing errors.,
       options => aidb.summarize_text_config(
           my-llm,
           NULL,
           NULL,
           NULL,
           NULL,
           aidb.inference_config(
               system_prompt => You are a customer support analyst. Classify issues by severity.,
               temperature   => 0.2
           )
       )::json
   );

!!!ヒント 最良の結果を得るには、\ ``inference_config``
と制約されたプロンプトを組み合わせます。たとえば、 ``max_tokens => 200``
を設定し、 ``'Give exactly 3 bullet points, max 1 sentence each.'``
のようなプロンプトを使用します。トークン制限はハードキャップとして機能し、プロンプトがフォーマットをガイドします。

エラーなしの空の結果
^^^^^^^^^^^^^^^^^^^^

場合によっては、LLMは処理後に空の文字列を返す場合があります。
AIDBは、これをエラーなしの成功結果として保存します。アプリケーションコードで\ ``length(result)``
を常に確認してください。

.. code:: sql

   SELECT product_name,
          CASE
              WHEN length(summary) = 0  THEN ERROR: Empty result
              WHEN length(summary) < 50 THEN WARNING: Suspiciously short
              ELSE summary
          END AS validated_summary
   FROM (
       SELECT p.product_name,
              aidb.summarize_text_aggregate(
                  sn.note_text,
                  aidb.summarize_text_config(
                      my-llm,
                      prompt => Your prompt here
                  )::json
              ) AS summary
       FROM sales_notes sn
       JOIN sales_orders so ON sn.order_id = so.order_id
       JOIN products p ON so.product_id = p.product_id
       GROUP BY p.product_name
   ) sub;

プロンプトアドヒアランスは大規模に低下する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

大量のテキスト1,000以上のノートがある場合、LLMはカスタムプロンプトに関係なく、要約動作がデフォルトになる傾向があります。構造化された出力要求番号付きリスト、カテゴリフォーマット、センチメントラベルは、フォローの信頼性が低くなります。

回避策 ``LIMIT``
以上の積極的なフィルタを使用して入力ボリュームを減らします。 ``append``
でチャンクを使用するため、各チャンクはより小さな入力に対して独立してプロンプトを受信します。非常に明示的なフォーマット制約を指定したラッパーファンクションを使用します。要約する前にスクラブテキスト
:ref:`Recipe 9 <#9-text-scrubbing-before-summarization>`  を使用してノイズを削減します。

最適化パターン
--------------

1.テキストのスクラブ
^^^^^^^^^^^^^^^^^^^^

要約する前に、つなぎ言葉、挨拶、および定型文を削除します。
:ref:`Recipe 9 <#9-text-scrubbing-before-summarization>` を参照してください。影響
トークンが15〜30%削減され、それに比例して処理が高速化します。

2.コンストレインされたプロンプト
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

特定の短いフォーマットの出力を生成するようにLLMに指示すると、トークン生成時間各呼び出しの最も遅い部分が削減されます。

.. code:: sql

   - - Slow (open-ended, LLM may generate 2,000+ chars):
   Summarize these notes.

   - - Fast (constrained, LLM generates ~200 chars):
   Give exactly 3 bullet points, max 1 sentence each.

3.抽出プレフィルタリング
^^^^^^^^^^^^^^^^^^^^^^^^

非常に大規模なデータセットの場合、LLMに送信する前にSQLを使用して最も関連性の高いテキストにプレフィルタリングします。

.. code:: sql

   - - Only send notes containing relevant keywords
   SELECT aidb.summarize_text_aggregate(
       note_text,
       aidb.summarize_text_config(
           my-llm,
           prompt => What are the pricing concerns?
       )::json
   )
   FROM sales_notes
   WHERE note_text ILIKE %price%
      OR note_text ILIKE %cost%
      OR note_text ILIKE %budget%
      OR note_text ILIKE %expensive%
   GROUP BY product_id;

インパクト 処理する行が大幅に減少。
LLMは関連するテキストのみを認識するため、速度と品質の両方が向上します。

4.適切な戦略の選択
^^^^^^^^^^^^^^^^^^

::

                ┌─ < 500 notes ──────> No chunking (fastest)
                │
   Group size ──┤
                │              ┌─ Need detail ──> words/200/append
                └─ >= 500 notes ──┤
                               └─ Need brief ───> words/100/reduce rf=3

5.パフォーマンスコストモデル
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

支配的なコストはLLM呼び出し数です。入力サイズに応じて、各呼び出しには3〜12秒かかります。

.. csv-table::
  :header: Step,Time
  :widths: 10,30
  :align: left
  :class: longtable

  Network overhead,~50ms
  Prompt processing,~1–3s
  Token generation,~2–8s
  Response parsing,~10ms
  **Total per call** ,**~3–12s** 

プロンプト処理は入力長に応じてスケーリングしますが、トークン生成は出力長に応じてスケーリングします。サマリーは入力量に関係なくほぼ固定サイズであるため、コンテキストウィンドウの制限までは、多数の小さな呼び出しよりも、より少なくて大きな呼び出しの方が効率的です。これが、ノーチャンクが小規模なグループに非常に効果的な理由です。呼び出しごとのテキストを最大化し、呼び出し数を最小限に抑えます。集計は処理前にすべての行を累計しているため、テキストは自然にバッチ化されます。
