AstaBrief 8Bは検索エンジンではありません。研究上の問いと、あらかじめ渡した科学文献の抜粋をもとに、引用付きのレポートを生成するモデルです。この役割分担を明確にすることが、非公開環境で運用する際の出発点になります。生成モデルはファイアウォールの内側で動かし、文書解析と検索もローカルで完結させる。そのうえで、安定した出典IDを付けたランキング済みの根拠だけをモデルに渡します。
AstaBrief 8Bに必要なものを整理する
AstaBrief 8BはAi2が開発した80億パラメーターのテキスト生成モデルで、Qwen3-8BをベースにApache 2.0で公開されています。公式モデルカードが想定している入力は、研究上の問いと検索済みの科学文献抜粋です。モデル自身が質問に応じて検索する構成ではありません。また、ファインチューニング時のプロンプトや対話形式を変更すると、挙動が劣化したり不安定になったりする可能性があると注意されています。
このガイドでは、最終版のallenai/AstaBrief_8Bチェックポイントを使います。モデルカードのサンプルにはallenai/AstaBrief_8B_SFTが登場しますが、こちらは教師ありファインチューニング前段階のモデルです。ダウンロードするチェックポイントと名前が一致しない場合は、両者を互換モデルだと決めつけず、実際に取得するモデルを確認してください。
Ai2が公開しているScholarQAリポジトリは、基準となる構成を理解するうえで役立ちます。検索、必要に応じた再ランキング、論文単位での集約、引用文の抽出、レポート生成が、それぞれ独立したコンポーネントとして構成されています。Semantic Scholarを社内インデックスに置き換える場合でも、非公開環境ではこの分離を維持するのが得策です。
再現性のあるローカル構成を作る
非公開の検索パイプラインは、次の6段階に分けておくと扱いやすくなります。
- 取り込み:PDFを解析し、スキャンページにはOCRを適用する。文書ID、タイトル、ページ、セクション、文字オフセットも保持する。
- チャンク分割:テキストを適度なサイズの抜粋に分ける。ページ境界や見出しは失わない。
- 検索:用語、識別子、完全一致フレーズが重要な場合は、字句検索と埋め込み検索を組み合わせる。
- 再ランキング:最初の検索結果を質問全体と照合してスコアリングし、根拠候補を絞り込む。
- 組み立て:変更不可能な引用IDを割り当て、AstaBriefが想定する参照形式で抜粋を整形する。
- 生成:組み立てたプロンプトをローカルのvLLMエンドポイントに送る。
重要なのは、特定のベクトルデータベースを選ぶことではありません。モデルに渡すすべての抜粋に、文書とページへ確実にたどり戻れる安定したIDを持たせることです。ここが、検索結果と生成レポートをつなぐ「根拠の契約」になります。
引用IDは変わらない設計にする
引用IDには、配列の位置ではなくDOC_014_P07_Aのような値を使います。検索条件を変えると配列の位置は簡単に変わりますが、文書・ページ・範囲を組み合わせたIDなら、後から監査できます。
対応表はプロンプトの外側に保存します。
{
"DOC_014_P07_A": {
"document": "internal_protocol.pdf",
"page": 7,
"section": "Methods",
"char_start": 18420,
"char_end": 19210
}
}
プロンプト内では、抜粋の横に同じIDを表示します。生成後は、渡したIDの集合に存在しない引用を拒否するか、要確認として扱いましょう。これだけで、引用された箇所がすべての主張を裏付けていると証明できるわけではありません。ただし、存在しない出典をもっとも単純な形で捏造することは防げます。
コンテキストを組む前に検索範囲を決める
ヒットしたチャンクをすべてコンテキストに詰め込むのは避けます。まず再現率を確保できる広さで検索し、再ランキングを行ったうえで、モデルのプロンプト予算に収まり、質問に直接答える抜粋だけを詰め込みます。同じページにある隣接チャンクを結合すると議論の流れを保てる場合もありますが、最終レポートでページ単位の追跡性が必要なら、IDは分けたままにします。
Ai2のScholarQAリポジトリでは、256件の候補を検索し、再ランキング後に論文単位で50件を残す基準構成が説明されています。ただし、これらは公開パイプラインの設定であって、AstaBriefに普遍的な必須値ではありません。まずは小規模な非公開コレクションから始め、取りこぼした根拠を確認しながら、自分たちの質問に合わせて検索範囲とコンテキスト上限を調整してください。
AstaBrief 8BをvLLMで配信する
公式資料では、データ型、コンテキスト長、同時実行数の組み合わせごとに必要なVRAMを一律には示していません。まずは、チェックポイントをそのまま読み込めるハードウェアで非量子化版を動かします。量子化版を検討する前に、同時実行数やコンテキスト長を下げてみるのが安全です。量子化しても引用性能が維持されるとは限らないため、自分のコーパスで必ず検証してください。
CUDAとPyTorchの構成に合ったクリーンな環境へvLLMをインストールし、最終チェックポイントでOpenAI互換サーバーを起動します。
pip install -U vllm openai
vllm serve allenai/AstaBrief_8B \
--host 127.0.0.1 \
--port 8000 \
--dtype auto \
--max-model-len 16000
--max-model-lenは運用上の上限であり、すべてのリクエストに16,000トークンを詰め込むことを意味しません。モデルカードでは学習時の最大長を16,000トークンとしつつ、生成例ではmax_tokens=4096を使っています。
ローカルエンドポイントを確認する
curl http://127.0.0.1:8000/v1/models
次に、ファインチューニング用データで使われたものと同じ形式のプロンプトを送ります。公式サンプルでは、temperatureが0.7、top-pが0.95、生成トークン数の上限が4,096で、停止条件にはトークナイザーのEOSトークンを使っています。
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:8000/v1",
api_key="local-only",
)
response = client.chat.completions.create(
model="allenai/AstaBrief_8B",
temperature=0.7,
top_p=0.95,
max_tokens=4096,
messages=[
{"role": "user", "content": assembled_prompt},
],
)
print(response.choices[0].message.content)
非公開サーバーでは、ループバックまたは内部インターフェースにバインドし、認証とTLSはゲートウェイで処理します。外部からの接続も遮断してください。モデルをローカルで動かしただけでは、ログ、PDFの一時ファイル、トレースまで自動的に非公開になるわけではありません。
非公開検索のリクエストを組み立てる
次のコードは、インデックスの実装をあえて限定していません。重要なのは、ランキング済みの根拠リスト、変更不可能なID、そしてプロンプトの境界です。
from dataclasses import dataclass
from openai import OpenAI
@dataclass
class Evidence:
ref_id: str
text: str
title: str
page: int
def build_prompt(question: str, evidence: list[Evidence]) -> str:
references = "\n\n".join(
f"[{item.ref_id}] {item.title} (page {item.page})\n{item.text}"
for item in evidence
)
return f"""Research question:
{question}
Retrieved references:
{references}
Write a cited research report answering the question. Use only the supplied
references for factual support. Attach the supplied reference IDs to claims.
If the references do not establish a point, say that the evidence is
insufficient instead of inventing a source.
"""
def answer(question: str, evidence: list[Evidence]) -> str:
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="local-only")
prompt = build_prompt(question, evidence)
result = client.chat.completions.create(
model="allenai/AstaBrief_8B",
temperature=0.7,
top_p=0.95,
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
)
return result.choices[0].message.content
本番環境では、公式のAstaBriefプロンプトテンプレートを使い、参照IDを維持したまま検索結果の抜粋を差し込んでください。上の短い指示文はvLLMとの接続方法を示すためのもので、ファインチューニング時の形式を置き換えるものではありません。
非公開インデックスには、BM25、密ベクトル検索、ハイブリッド検索のいずれも使えます。ただし、すべての段階でメタデータを引き継いでください。文書IDやページ番号を失った抜粋は、生成された文章が正しそうに見えても、説明責任のある研究レポートには不十分です。
本番投入前に引用とプライバシーのゲートを設ける
AstaBriefがScholarQA-CS2で報告した結果は、自分のコーパスに対する保証ではなく、あくまで参考値です。モデルカードの100問テストセットでは、AstaBrief 8Bの引用精度は90.5、引用再現率は78.2、回答精度は89.0と報告されています。引用再現率が引用精度を下回っている点には、実務上の意味があります。レポートが提示された資料を正確に引用していても、関連する根拠を取りこぼす可能性があるということです。
本番前には、少なくとも次の4項目を確認するゲートを設けます。
- 参照の妥当性:生成された引用IDがすべて、リクエストで許可したIDリストに存在する。
- メタデータの解決:各IDから文書、ページ、保存済みのテキスト範囲を引ける。
- 根拠の裏付け:その抜粋が近くにある主張を実際に支えているか、レビュアーまたは別の検証器が確認する。
- 検索再現率:想定文書とページを含む小規模なラベル付き質問セットを用意し、チャンク分割、埋め込み、再ランキングを変更した後の取りこぼしを測定する。
モデルサーバー、インデックス、オブジェクトストレージ、ログ、監視基盤は、社内ポリシーで外部サービスが明示的に許可されていない限り、同じ信頼境界の内側に置きます。機密文書を含むリクエスト本文のログは無効にし、可能な範囲でトレースから質問内容を削除します。アップロードされたPDFと生成レポートの保持期間も決めておきましょう。
Ai2が報告したFastモードの51.1秒という値を、ローカル環境のベンチマークとしてそのまま使ってはいけません。この数値はエンドツーエンドのAstaパイプラインを対象にしたもので、自己ホスト環境ではGPU、検索システム、バッチ処理、プロンプト長、ネットワーク経路が変わります。検索、再ランキング、初回トークンまでの時間、生成時間、リクエスト全体の時間を分けて計測してください。
層ごとにデプロイを切り分ける
| 症状 | 疑う層 | 最初に確認すること |
|---|---|---|
| サーバーは起動するが引用の質が低い | プロンプトまたは根拠の契約 | 公式形式とプロンプトを比較し、参照IDが安定しているか確認する |
| 引用先が存在しない | アプリケーションの検証 | リクエストの許可リストにないIDを拒否する |
| 関連論文が検索結果から抜ける | 検索 | モデルを変更する前に、チャンク分割、ハイブリッド検索、再ランキングの再現率を評価する |
| リクエストがメモリ不足になる | サービングまたはコンテキスト構成 | 同時実行数、出力予算、詰め込むコンテキストを減らし、その後で量子化を再検討する |
| ローカルでのレイテンシーが想定より高い | パイプライン全体 | 検索、再ランキング、キュー待ち、生成を個別に計測する |
| 非公開データがログに現れる | 運用 | ゲートウェイ、vLLM、トレース、キャッシュ、オブジェクトストレージの保持設定を確認する |
このように層を分けて診断すれば、検索の取りこぼしをモデルの失敗と誤認したり、プロンプト形式の不一致を「文書をもっと追加する」ことで解決しようとしたりせずに済みます。
AstaBrief 8Bは、専門性のあるローカルレポート生成器を求め、検索品質、出典の対応付け、検証まで自分たちで管理できる場合に向いています。vLLMが解決するのはモデルのサービングです。文書検索、引用の来歴管理、プライバシー制御まで提供してくれるわけではありません。