中国語の企業ドキュメントを対象とした検索拡張生成(RAG)パイプラインを構築する際、バックエンドエンジニアは欧米言語中心の標準スタックでは解決が難しい課題に直面します。中国語の文章には単語間の空白区切りがなく、契約書や業務マニュアル、技術仕様書には特有の専門用語や条文番号が頻出します。汎用の多言語 Embedding モデルではトークン分割の断片化が生じやすく、検索の再現率や意味理解の精度が低下する原因となります。
百川智能(Baichuan AI)は、膨大な中国語コーパスで事前学習された基盤モデルを提供しています。推論・回答生成に優れた Baichuan4 や Baichuan3-Turbo、そして 1024 次元の高密度ベクトルを出力する中国語特化型エンベディングモデル Baichuan-Text-Embedding が代表例です。百川 API は https://api.baichuan-ai.com/v1 で OpenAI 互換の REST インターフェースを提供しているため、LangChain および LlamaIndex の双方からコミュニティプラグインや互換コネクタを通じて容易に統合できます。
本記事では、中国語企業ナレッジベースに適したチャンキング戦略、設計パターン、本番環境向けの Python 実装コードを解説します。
1. 前提条件と API エンドポイント仕様
パイプラインの実装を始める前に、百川智能の開発者プラットフォームで API キーを取得し、環境変数に設定します。
export BAICHUAN_API_KEY="your-baichuan-api-key"
必要な Python ライブラリとベクトルデータベースをインストールします。
pip install langchain-community langchain-core langchain-openai \
llama-index-core llama-index-llms-openai-like llama-index-embeddings-openai \
chromadb pydantic
百川 API の主要エンドポイント仕様:
- Base URL:
https://api.baichuan-ai.com/v1 - チャット生成:
POST /v1/chat/completions(モデル:Baichuan4,Baichuan4-Air,Baichuan3-Turbo) - ベクトル化:
POST /v1/embeddings(モデル:Baichuan-Text-Embedding)
2. 中国語企業ドキュメントのチャンキング戦略とトークン上限
英語圏で一般的な空白基準のテキスト分割を中国語に適用すると、文の途中で意味単位が不自然に切断され、契約条文や業務規定の文脈が破壊されます。中国語文書のチャンキングでは、段落の改行や中国語の句読点(。, !, ?, ;)を優先する再帰的分割が不可欠です。
特に注意すべき点として、Baichuan-Text-Embedding は 1 リクエストあたりの入力上限が 512 トークンに制限されています。バッチ処理時の 400 Bad Request エラーを防ぐため、1 チャンクの文字数は 350〜400 文字程度、オーバーラップは 40〜50 文字に設定するのが安全です。
from langchain_text_splitters import RecursiveCharacterTextSplitter
def create_chinese_document_splitter(chunk_size: int = 400, chunk_overlap: int = 50):
"""
中国語の契約書や社内規定に特化した再帰的テキストスプリッター
"""
return RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=[
"\n\n", # 段落の区切り
"\n", # 改行
"。", # 句点
"!", # 感嘆符
"?", # 疑問符
";", # セミコロン(箇条書き条文で多用)
" ", # 空白
"" # 文字単位フォールバック
]
)
3. LangChain による統合実装(LCEL + 高密度ベクトル検索)
LangChain では、langchain_community の ChatBaichuan や BaichuanTextEmbeddings を使用することも、langchain_openai をベースに百川の openai_api_base を指定することも可能です。本番環境では、ストリーミングや非同期処理、LCEL(LangChain Expression Language)の記法に完全対応した互換アダプタ方式が推奨されます。
LangChain RAG 実装コード
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.documents import Document
# 1. 百川 LLM およびエンベディングの初期化
BAICHUAN_BASE_URL = "https://api.baichuan-ai.com/v1"
api_key = os.environ.get("BAICHUAN_API_KEY")
embeddings = OpenAIEmbeddings(
model="Baichuan-Text-Embedding",
openai_api_base=BAICHUAN_BASE_URL,
openai_api_key=api_key,
check_embedding_ctx_length=False # OpenAI 固有のコンテキスト検証をスキップ
)
llm = ChatOpenAI(
model="Baichuan4",
openai_api_base=BAICHUAN_BASE_URL,
openai_api_key=api_key,
temperature=0.1, # 社内規定の回答における正確性を重視
streaming=True
)
# 2. 社内規定サンプルの投入
raw_docs = [
Document(
page_content="第十三条 采购付款管理规范:对于超过人民币50万元的设备采购合同,供应商必须提供全额增值税专用发票后,财务部方可安排第二笔30%的进度款支付。项目初验合格前,累计付款比例不得超过合同总额的80%。",
metadata={"source": "采购管理制度2024.pdf", "department": "Finance"}
),
Document(
page_content="第二十四条 差旅报销标准:研发部门员工赴一类城市(北京、上海、广州、深圳)出差,住宿费上限为每人每天550元,餐饮补贴为每人每天120元,按实际出差自然天数核算。",
metadata={"source": "员工差旅规范v3.pdf", "department": "HR"}
)
]
splitter = create_chinese_document_splitter(chunk_size=400, chunk_overlap=40)
chunked_docs = splitter.split_documents(raw_docs)
# 3. Chroma によるベクトルストア作成
vectorstore = Chroma.from_documents(
documents=chunked_docs,
embedding=embeddings,
collection_name="enterprise_knowledge"
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 4. コンプライアンスを意識したプロンプト設計
system_prompt = (
"你是一个严谨的企业知识库助手。请严格根据以下检索到的参考文档回答用户的问题。\n"
"如果参考文档中没有提供明确信息,请直接回答'依据现有内部制度未查到相关说明',严禁虚构或主观臆测。\n\n"
"【参考文档】:\n{context}"
)
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", "{question}")
])
def format_docs(docs):
return "\n\n".join(f"[{doc.metadata.get('source', '未知')}] {doc.page_content}" for doc in docs)
# 5. LCEL パイプラインの構築
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# 6. クエリの実行
if __name__ == "__main__":
query = "50万元以上の設備調達契約において、第2回進捗支払いの前提条件は何ですか?"
response = rag_chain.invoke(query)
print("回答結果:\n", response)
4. LlamaIndex による統合実装(OpenAILike とカスタム分割)
LlamaIndex(v0.10+)ではモジュール構成が細分化されており、標準の OpenAI クラスは公式モデル名の検証を行います。そのため、百川 API を呼び出す際は llama-index-llms-openai-like の OpenAILike を使用し、エンベディングには api_base を設定した OpenAIEmbedding を用います。
LlamaIndex RAG 実装コード
import os
from llama_index.core import Settings, VectorStoreIndex, Document
from llama_index.core.node_parser import SentenceSplitter
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.openai import OpenAIEmbedding
# 1. グローバル設定の構成
BAICHUAN_BASE_URL = "https://api.baichuan-ai.com/v1"
api_key = os.environ.get("BAICHUAN_API_KEY")
Settings.llm = OpenAILike(
model="Baichuan4",
api_base=BAICHUAN_BASE_URL,
api_key=api_key,
is_chat_model=True,
temperature=0.1
)
Settings.embed_model = OpenAIEmbedding(
model="Baichuan-Text-Embedding",
api_base=BAICHUAN_BASE_URL,
api_key=api_key
)
# 2. 中国語の句点に基づくノードパーサー
Settings.node_parser = SentenceSplitter(
chunk_size=400,
chunk_overlap=40,
separator="。"
)
# 3. インデックスの構築
documents = [
Document(
text="第七章 核心数据安全防护要求:涉及生产数据库导出操作必须提前48小时提交工单,经信息安全负责人与业务分管领导双重审批后方可在堡垒机中执行。导出文件须启用国密SM4算法加密并在3天内自动销毁。",
metadata={"category": "SecOps", "author": "Security Committee"}
)
]
index = VectorStoreIndex.from_documents(documents)
# 4. クエリエンジンの生成
query_engine = index.as_query_engine(
similarity_top_k=2,
system_prompt=(
"你代表企业信息化与安全管理委员会回答技术咨询。"
"请严格根据检索到的规范作答,列出具体审核流程及技术加密要求。"
)
)
if __name__ == "__main__":
response = query_engine.query("本番環境データベースのエクスポートに必要な承認とセキュリティ条件は何ですか?")
print("レスポンス:\n", str(response))
5. 本番運用のためのバックエンド設計要件
企業向けシステムで安定した運用を実現するためには、以下の技術的配慮が不可欠です。
1. ハイブリッド検索(ベクトル + BM25)の併用
密なベクトル検索は意味の類似性を捉えるのに優れていますが、特定の条文番号(例:「第13条第2項」)や型番、製品コードの検索では精度が落ちる場合があります。LangChain の EnsembleRetriever や LlamaIndex のハイブリッド検索機能を活用し、BM25 などのキーワード検索と重み付け統合することが推奨されます。
2. ベクトル化前のトークン長検証ガード
Baichuan-Text-Embedding は 512 トークンを超過するとエラーを返します。OCR のノイズやフォーマット崩れによる長大なテキストが混入した場合に備え、ベクトル化 API を呼び出す直前にトークン数を検証し、必要に応じて再分割する安全機構を設けてください。
3. レート制限とリトライ処理
大規模な文書群を一括インデックス化する際は、百川プラットフォームの RPM(1分間あたりのリクエスト数)制限に達するリスクがあります。tenacity による指数バックオフ付きリトライや、非同期ワーカーでの同時実行数制限(セマフォ制御)を組み込むことが重要です。
4. ハルシネーション抑制と出典メタデータ管理
社内規程やコンプライアンスに関する回答では、不正確な推測を防ぐことが最優先です。プロンプト内で根拠のない回答を禁止するだけでなく、検索されたドキュメントのメタデータ(ファイル名、章節、部署名)をレスポンスに含め、ユーザーが原文を確認できる設計にしてください。