document-chat-interface について
自然言語で文書を検索・質問できる会話型インターフェースの開発ガイドです。文書の取り込み、検索、会話コンテキスト、引用を扱い、LangChain、LlamaIndex、RAGの実装例を紹介します。
主な機能
- 01PDF、リポジトリ、メール、ウェブページの処理
- 02テキストの抽出、整形、分割、メタデータ付与
- 03会話コンテキストの維持
- 04出典を示した回答の生成
- 05質問の明確化と追加質問への対応
活用シーン
- 01レポートや研究論文の質問応答を構築
- 02メールアーカイブの会話型検索
- 03質問を通じたコードリポジトリの調査
- 04社内文書のインタラクティブな参照環境の構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ qodex-ai/ ai-agent-skills --skill document-chat-interfaceインストール後、Claude Code で/document-chat-interfaceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/conversation_manager.pydocument_processors.pytext_processor.py詳細
ドキュメントチャットインターフェース
自然言語を使ってユーザーがドキュメントに質問したり、やり取りしたりできる、インテリジェントなチャットインターフェースを構築します。静的なドキュメントを、対話可能なナレッジソースに変換できます。
概要
ドキュメントチャットインターフェースは、次の3つの機能を組み合わせたものです。
- ドキュメント処理 - ドキュメントを抽出して準備します
- 意味理解 - 質問を理解し、関連するコンテンツを見つけます
- 会話型インターフェース - コンテキストを維持し、自然な応答を返します
主な用途
- PDF の質疑応答:研究論文、レポート、書籍に関する質問に回答します
- メール検索:メールアーカイブから会話形式で情報を見つけます
- GitHub エクスプローラー:コードリポジトリについて質問します
- ナレッジベース:社内ドキュメントに対話形式でアクセスします
- 契約書レビュー:自然言語で法的文書に質問します
- リサーチアシスタント:学術論文を対話形式で調べます
アーキテクチャ
Document Source
↓
Document Processor
├→ Extract text
├→ Process content
└→ Generate embeddings
↓
Vector Database
↓
Chat Interface ← User Question
├→ Retrieve relevant content
├→ Maintain conversation history
└→ Generate response
主なコンポーネント
1. ドキュメントソース
実装例については、examples/document_processors.py を参照してください。
PDF ドキュメント
- PDF ページからテキストを抽出します
- ドキュメントの構造とメタデータを保持します
- OCR(pytesseract)を使用してスキャンされた PDF を処理します
- 表を抽出します(pdfplumber)
GitHub リポジトリ
- リポジトリからコードファイルを抽出します
- リポジトリの構造を解析します
- 複数のファイル形式を処理します
メールアーカイブ
- メールのメタデータ(差出人、宛先、件名、日付)を抽出します
- メール本文の内容を解析します
- 複数のメールボックス形式に対応します
ウェブページ
- ページのテキストと構造を抽出します
- 見出しの階層を保持します
- リンクとナビゲーションを抽出します
YouTube/音声
- YouTube 動画からトランスクリプトを取得します
- 音声ファイルを文字起こしします
- 複数の形式に対応します
2. ドキュメント処理
実装例については、examples/text_processor.py を参照してください。
テキストの抽出とクリーニング
- 余分な空白や特殊文字を削除します
- 重複部分を含むスマートなテキスト分割を行います
- 文の境界をインテリジェントに検出します
メタデータの抽出
- タイトル、著者、日付、言語を抽出します
- 単語数とドキュメント統計を計算します
- ドキュメントのソースと形式を記録します
構造の保持
- 分割したテキスト内で見出しの階層を保持します
- セクションのコンテキストを維持します
- 階層的な検索を可能にします
3. チャットインターフェースの設計
実装例については、examples/conversation_manager.py を参照してください。
会話の管理
- サイズ制限を設けて会話履歴を維持します
- メッセージのメタデータ(タイムスタンプ、ロール)を記録します
- LLM 連携に必要なコンテキストを提供します
- 必要に応じて履歴を消去します
質問の調整
- 質問に含まれる暗黙的な参照を補足します
- 代名詞やコンテキストへの参照を処理します
- 以前のコンテキストを使って質問を明確にします
応答の生成
- 回答にドキュメントのコンテキストを使用します
- プロンプト内で会話履歴を維持します
- 出典を提示します
- 対象範囲外の質問に対応します
4. ユーザーエクスペリエンス機能
引用と出典
def format_response_with_citations(response: str, sources: List[Dict]) -> str:
"""Add source citations to response"""
formatted = response + "\n\n**Sources:**\n"
for i, source in enumerate(sources, 1):
formatted += f"[{i}] Page {source['page']} of {source['source']}\n"
if 'excerpt' in source:
formatted += f" \"{source['excerpt'][:100]}...\"\n"
return formatted
確認の質問
def generate_follow_up_questions(context: str, response: str) -> List[str]:
"""Suggest follow-up questions to user"""
prompt = f"""
Based on this Q&A, generate 3 relevant follow-up questions:
Context: {context[:500]}
Response: {response[:500]}
"""
follow_ups = llm.generate(prompt)
return follow_ups
エラー処理
def handle_query_failure(question: str, error: Exception) -> str:
"""Handle when no relevant documents found"""
if isinstance(error, NoRelevantDocuments):
return (
"I couldn't find information about that in the documents. "
"Try asking about different topics like: "
+ ", ".join(get_main_topics())
)
elif isinstance(error, ContextTooLarge):
return (
"The answer requires too much context. "
"Can you be more specific about what you'd like to know?"
)
else:
return f"I encountered an issue: {str(error)[:100]}"
実装フレームワーク
LangChain を使用する
from langchain.document_loaders import PDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain
# Load document
loader = PDFLoader("document.pdf")
documents = loader.load()
# Split into chunks
splitter = CharacterTextSplitter(chunk_size=1000)
chunks = splitter.split_documents(documents)
# Create embeddings
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(chunks, embeddings)
# Create chat chain
llm = ChatOpenAI(model="gpt-4")
qa = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=vectorstore.as_retriever(),
return_source_documents=True
)
# Chat interface
chat_history = []
while True:
question = input("You: ")
result = qa({"question": question, "chat_history": chat_history})
print(f"Assistant: {result['answer']}")
chat_history.append((question, result['answer']))
LlamaIndex を使用する
from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader, ChatMemoryBuffer
from llama_index.llms import ChatMessage, MessageRole
# Load documents
documents = SimpleDirectoryReader("./docs").load_data()
# Create index
index = GPTVectorStoreIndex.from_documents(documents)
# Create chat engine with memory
chat_engine = index.as_chat_engine(
memory=ChatMemoryBuffer.from_defaults(token_limit=3900),
llm="gpt-4"
)
# Chat loop
while True:
question = input("You: ")
response = chat_engine.chat(question)
print(f"Assistant: {response}")
RAG ベースのアプローチを使用する
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# Load and embed documents
model = SentenceTransformer('all-MiniLM-L6-v2')
documents = load_documents("document.pdf")
embeddings = model.encode(documents)
# Create FAISS index
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(np.array(embeddings).astype('float32'))
# Chat function
def chat(question):
# Embed question
q_embedding = model.encode(question)
# Retrieve documents
k = 5
distances, indices = index.search(
np.array([q_embedding]).astype('float32'), k
)
# Get relevant documents
context = " ".join([documents[i] for i in indices[0]])
# Generate response
response = llm.generate(
f"Context: {context}\nQuestion: {question}\nAnswer:"
)
return response
ベストプラクティス
ドキュメントの処理
- ✓ 複数の形式に対応します(PDF、TXT、docx など)
- ✓ 大きなドキュメントを効率的に処理します
- ✓ ドキュメントの構造を保持します
- ✓ メタデータを抽出します
- ✓ 複数の言語に対応します
- ✓ スキャンされた PDF 向けに OCR を実装します
会話の品質
- ✓ 会話のコンテキストを維持します
- ✓ 確認の質問をします
- ✓ 出典を引用します
- ✓ 曖昧さに対応します
- ✓ 追加の質問を提案します
- ✓ 対象範囲外の質問に対応します
パフォーマンス
- ✓ 検索速度を最適化します
- ✓ キャッシュを実装します
- ✓ 大規模なドキュメントセットを処理します
- ✓ ドキュメントをバッチ処理します
- ✓ レイテンシを監視します
- ✓ ページネーションを実装します
ユーザーエクスペリエンス
- ✓ 応答を分かりやすく整形します
- ✓ 出典を引用できるようにします
- ✓ ドキュメントブラウザー/エクスプローラーを用意します
- ✓ 検索候補を表示します
- ✓ クエリ履歴を表示します
- ✓ 会話をエクスポートできるようにします
よくある課題と解決策
課題:無関係な回答
解決策:
- 検索を改善する(コンテキストを増やす、より優れた埋め込みを使用する)
- 回答をコンテキストと照合する
- 明確化の質問をする
- 信頼度スコアリングを実装する
- ハイブリッド検索を使用する
課題:ターンをまたいだコンテキストの喪失
解決策:
- 会話のメモリを保持する
- 履歴に基づいて検索を更新する
- 長い会話を要約する
- 過去のクエリの重みを再調整する
課題:長いドキュメントの処理
解決策:
- 階層的なチャンク分割
- まず要約する
- 質問を洗練する
- マルチホップ検索
- ドキュメントのナビゲーション
課題:コンテキストウィンドウの制限
解決策:
- 検索したコンテキストを圧縮する
- ドキュメントの要約を使用する
- 階層的な検索
- 最も関連性の高いセクションに絞る
- 反復的に洗練する
高度な機能
複数ドキュメントの分析
def compare_documents(question: str, documents: List[str]):
"""Analyze and compare across multiple documents"""
results = []
for doc in documents:
response = query_document(doc, question)
results.append({
"document": doc.name,
"answer": response
})
# Compare and synthesize
comparison = llm.generate(
f"Compare these answers: {results}"
)
return comparison
インタラクティブなドキュメント探索
class DocumentExplorer:
def __init__(self, documents):
self.documents = documents
def browse_by_topic(self, topic):
"""Find documents by topic"""
pass
def get_related_documents(self, doc_id):
"""Find similar documents"""
pass
def get_key_terms(self, document):
"""Extract key terms and concepts"""
pass
リソース
ドキュメント処理ライブラリ
- PyPDF:PDF の処理
- python-docx:Word ドキュメントの処理
- BeautifulSoup:ウェブスクレイピング
- youtube-transcript-api:YouTube の文字起こし
チャットフレームワーク
- LangChain:包括的なフレームワーク
- LlamaIndex:ドキュメントに特化
- RAG ライブラリ:ベクトル DB との統合
実装チェックリスト
- サポートするドキュメントソースを選択する
- ドキュメントの読み込みと処理を実装する
- ベクトルデータベース/埋め込みをセットアップする
- チャットインターフェースを構築する
- 会話管理を実装する
- ソースの引用を追加する
- エッジケース(大きなドキュメント、OCR など)に対応する
- エラー処理を実装する
- パフォーマンス監視を追加する
- 実際のドキュメントでテストする
- デプロイして監視する
はじめに
- シンプルに始める:単一の PDF、基本的なチャット
- 機能を追加する:複数ドキュメント、会話履歴
- 品質を向上させる:より優れたチャンク分割と検索
- スケールする:より多くの形式と、より大きなドキュメントをサポートする
- 仕上げる:UX の改善、エラー処理
コメント
Markdown 対応