このページでは、LlamaIndex Query Pipelines テンプレート(Vertex AI SDK for Python の LlamaIndexQueryPipelineAgent
クラス)を使用してエージェントを開発する方法について説明します。このエージェントは、検索拡張生成(RAG)を使用して質問に回答するように設計されています。たとえば、「ポール グラハムの大学生活は?」などのクエリに回答します。
LlamaIndex クエリ パイプラインを使用してエージェントを開発する手順は次のとおりです。
- モデルを定義して構成する
- 取得ツールを定義して使用する
- レスポンス シンセサイザーを定義して使用する
- (省略可)プロンプト テンプレートをカスタマイズする
- (省略可)オーケストレーションをカスタマイズする
始める前に
環境の設定の手順に沿って環境が設定されていることを確認します。
モデルを定義して構成する
LlamaIndex Query Pipeline エージェントが使用するモデルを定義して構成します。
モデル バージョンを定義します。
model = "gemini-2.0-flash"
(省略可)モデル パラメータを指定します。
model_kwargs = { # vertexai_config (dict): By providing the region and project_id parameters, # you can enable model usage through Vertex AI. "vertexai_config": { "project": "PROJECT_ID", "location": "LOCATION" }, # temperature (float): The sampling temperature controls the degree of # randomness in token selection. "temperature": 0.28, # context_window (int): The context window of the model. # If not provided, the default context window is 200000. "context_window": 200000, # max_tokens (int): Token limit determines the maximum # amount of text output from one prompt. If not provided, # the default max_tokens is 256. "max_tokens": 256, }
次のモデル構成を使用して
LlamaIndexQueryPipelineAgent
を作成します。from vertexai.preview import reasoning_engines agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model=model, # Required. model_kwargs=model_kwargs, # Optional. )
インタラクティブな環境(ターミナルや Colab ノートブックなど)で実行している場合は、エージェントにクエリを実行できます。
response = agent.query(input="What is Paul Graham's life in college?") print(response)
次のようなレスポンスが返されます。
{'message': {'role': 'assistant', 'additional_kwargs': {}, 'blocks': [{'block_type': 'text', 'text': "Unfortunately, there's not a lot of publicly available information about Paul Graham's personal life in college. ..."}]}, 'raw': {'content': {'parts': [{'video_metadata': None, 'thought': None, 'code_execution_result': None, 'executable_code': None, 'file_data': None, 'function_call': None, 'function_response': None, 'inline_data': None, 'text': "Unfortunately, there's not a lot of publicly available information about Paul Graham's personal life in college. ..."}], 'role': 'model'}, 'citation_metadata': None, 'finish_message': None, 'token_count': None, 'avg_logprobs': -0.1468650027438327, 'finish_reason': 'STOP', 'grounding_metadata': None, 'index': None, 'logprobs_result': None, 'safety_ratings': [{'blocked': None, 'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'probability_score': 0.022949219, 'severity': 'HARM_SEVERITY_NEGLIGIBLE', 'severity_score': 0.014038086}, {'blocked': None, 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'probability_score': 0.056640625, 'severity': 'HARM_SEVERITY_NEGLIGIBLE', 'severity_score': 0.029296875}, {'blocked': None, 'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'probability_score': 0.071777344, 'severity': 'HARM_SEVERITY_NEGLIGIBLE', 'severity_score': 0.024047852}, {'blocked': None, 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'probability_score': 0.103515625, 'severity': 'HARM_SEVERITY_NEGLIGIBLE', 'severity_score': 0.05102539}], 'usage_metadata': {'cached_content_token_count': None, 'candidates_token_count': 222, 'prompt_token_count': 10, 'total_token_count': 232}}, 'delta': None, 'logprobs': None, 'additional_kwargs': {}}
(省略可)モデルをカスタマイズする
LlamaIndexQueryPipelineAgent
テンプレートは、 Google Cloudで利用可能なすべての基盤モデルにアクセスできるため、デフォルトで Google GenAI
を使用します。Google GenAI
で使用できないモデルを使用するには、次のように model_builder=
を定義します。
from typing import Optional
def model_builder(
*,
model_name: str, # Required. The name of the model
model_kwargs: Optional[dict] = None, # Optional. The model keyword arguments.
**kwargs, # Optional. The remaining keyword arguments to be ignored.
):
LlamaIndexQueryPipeline
でサポートされているチャットモデルとその機能の一覧については、使用可能な LLM 統合をご覧ください。各チャットモデルは、model=
と model_kwargs=
に独自のサポート対象値セットを使用します。
Google GenAI
Google GenAI は、環境を設定するとデフォルトでインストールされ、model_builder
を省略すると LlamaIndexQueryPipelineAgent
テンプレートで自動的に使用されます。
from vertexai.preview import reasoning_engines
agent = reasoning_engines.LlamaIndexQueryPipelineAgent(
model=model, # Required.
model_kwargs=model_kwargs, # Optional.
)
Anthropic
Anthropic のドキュメントに沿ってアカウントを設定し、
llama-index-llms-anthropic
パッケージをインストールします。Anthropic
モデルを返すmodel_builder
を定義します。def model_builder(*, model_name: str, model_kwargs = None, **kwargs): from llama_index.llms.anthropic import Anthropic return Anthropic(model=model_name, **model_kwargs)
LlamaIndexQueryPipelineAgent
テンプレートで Anthropic モデルを使用します。from vertexai.preview import reasoning_engines agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model="claude-3-opus-20240229", # Required. model_builder=model_builder, # Required. model_kwargs={ "api_key": "ANTHROPIC_API_KEY", # Required. "temperature": 0.28, # Optional. }, )
OpenAILike
OpenAILike
は、Gemini の ChatCompletions
API で使用できます。
OpenAILike
のドキュメントに沿ってパッケージをインストールします。pip install llama-index-llms-openai-like
OpenAILike
モデルを返すmodel_builder
を定義します。def model_builder( *, model_name: str, model_kwargs = None, project: str, # Specified via vertexai.init location: str, # Specified via vertexai.init **kwargs, ): import google.auth from llama_index.llms.openai_like import OpenAILike # Note: the credential lives for 1 hour by default. # After expiration, it must be refreshed. creds, _ = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform"]) auth_req = google.auth.transport.requests.Request() creds.refresh(auth_req) if model_kwargs is None: model_kwargs = {} endpoint = f"https://{location}-aiplatform.googleapis.com" api_base = f'{endpoint}/v1beta1/projects/{project}/locations/{location}/endpoints/openapi' return OpenAILike( model=model_name, api_base=api_base, api_key=creds.token, **model_kwargs, )
LlamaIndexQueryPipelineAgent
テンプレートでモデルを使用します。from vertexai.preview import reasoning_engines agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model="google/gemini-2.0-flash", # Or "meta/llama3-405b-instruct-maas" model_builder=model_builder, # Required. model_kwargs={ "temperature": 0, # Optional. "max_retries": 2, # Optional. }, )
取得ツールを定義して使用する
モデルを定義したら、モデルが推論に使用する Retriever を定義します。取得ツールはインデックス上に構築できますが、包括的に定義することもできます。ローカルで Retriever をテストする必要があります。
関連するドキュメントと類似性スコアを返すリトリーバーを定義します。
def retriever_builder(model, retriever_kwargs=None): import os import requests from llama_index.core import ( StorageContext, VectorStoreIndex, load_index_from_storage, ) from llama_index.core import SimpleDirectoryReader from llama_index.embeddings.vertex import VertexTextEmbedding import google.auth credentials, _ = google.auth.default() embed_model = VertexTextEmbedding( model_name="textembedding-gecko@003", project="PROJECT_ID", credentials=credentials ) data_dir = "data/paul_graham" essay_file = os.path.join(data_dir, "paul_graham_essay.txt") storage_dir = "storage" # --- Simple Download (if needed) --- if not os.path.exists(essay_file): os.makedirs(data_dir, exist_ok=True) # Make sure the directory exists essay_url = "https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt" try: response = requests.get(essay_url) response.raise_for_status() # Check for download errors with open(essay_file, "wb") as f: f.write(response.content) print("Essay downloaded.") except requests.exceptions.RequestException as e: print(f"Download failed: {e}") # --- Build/Load Index --- if not os.path.exists(storage_dir): print("Creating new index...") # --- Load Data --- reader = SimpleDirectoryReader(data_dir) docs = reader.load_data() index = VectorStoreIndex.from_documents(docs, model=model, embed_model=embed_model) index.storage_context.persist(persist_dir=storage_dir) else: print("Loading existing index...") storage_context = StorageContext.from_defaults(persist_dir=storage_dir) index = load_index_from_storage(storage_context, embed_model=embed_model) return index.as_retriever()
取得ツールをテストします。
from llama_index.llms.google_genai import GoogleGenAI model = GoogleGenAI( model=model, **model_kwargs ) retriever = retriever_builder(model) retrieved_response = retriever.retrieve("What is Paul Graham's life in College?")
取得されたレスポンスは次のようになります。
[ NodeWithScore( node=TextNode( id_='692a5d5c-cd56-4ed0-8e29-ecadf6eb9933', embedding=None, metadata={'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-24', 'last_modified_date': '2025-03-24'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={ <NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='3e1c4d73-1e1d-4e83-bd16-2dae24abb231', node_type='4', metadata={'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-24', 'last_modified_date': '2025-03-24'}, hash='0c3c3f46cac874b495d944dfc4b920f6b68817dbbb1699ecc955d1fafb2bf87b'), <NodeRelationship.PREVIOUS: '2'>: RelatedNodeInfo(node_id='782c5787-8753-4f65-85ed-c2833ea6d4d8', node_type='1', metadata={'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-24', 'last_modified_date': '2025-03-24'}, hash='b8e6463833887a8a2b13f1b5a623672819faedc1b725d9565ba003223628db0e'), <NodeRelationship.NEXT: '3'>: RelatedNodeInfo(node_id='f7d2cb7e-fa0c-40bf-b8e7-b888e36b87f9', node_type='1', metadata={}, hash='db7cc1a67fa3afd1e5f24c8c61583781ce6a00c444da8f25a5374468c17b7de0') }, metadata_template='{key}: {value}', metadata_separator='\n', text='So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp...', mimetype='text/plain', start_char_idx=7166, end_char_idx=11549, metadata_separator='\n', text_template='{metadata_str}\n\n{content}' ), score=0.7403571819090398 ) ]
LlamaIndexQueryPipelineAgent
テンプレートで Retriever を使用するには、retriever_builder=
引数の下に追加します。from vertexai.preview import reasoning_engines agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model=model, # Required. model_kwargs=model_kwargs, # Optional. retriever_builder=retriever_builder, # Optional. )
テストクエリを実行して、エージェントをローカルでテストします。
response = agent.query( input="What is Paul Graham's life in College?" )
レスポンスは、スコアを含むノードの JSON シリアル化可能なリストです。
[{'node': {'id_': '692a5d5c-cd56-4ed0-8e29-ecadf6eb9933', 'embedding': None, 'metadata': {'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-12', 'last_modified_date': '2025-03-12'}, 'excluded_embed_metadata_keys': ['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], 'excluded_llm_metadata_keys': ['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], 'relationships': {'1': {'node_id': '07ee9574-04c8-46c7-b023-b22ba9558a1f', 'node_type': '1', 'metadata': {}, 'hash': '44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a', 'class_name': 'RelatedNodeInfo'}, '2': {'node_id': 'ac7e54aa-6fff-40b5-a15e-89c5eb234936', 'node_type': '1', 'metadata': {'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-12', 'last_modified_date': '2025-03-12'}, 'hash': '755327a01efe7104db771e4e6f9683417884ea6895d878da882d2b21a6b66442', 'class_name': 'RelatedNodeInfo'}, '3': {'node_id': '3a04be27-ac46-4acd-a8c6-031689508982', 'node_type': '1', 'metadata': {}, 'hash': 'db7cc1a67fa3afd1e5f24c8c61583781ce6a00c444da8f25a5374468c17b7de0', 'class_name': 'RelatedNodeInfo'}}, 'metadata_template': '{key}: {value}', 'metadata_separator': '\n', 'text': 'So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp...', 'mimetype': 'text/plain', 'start_char_idx': 7164, 'end_char_idx': 11547, 'metadata_separator': '\n', 'text_template': '{metadata_str}\n\n{content}', 'class_name': 'TextNode'}, 'score': 0.25325886336265013, 'class_name': 'NodeWithScore'} ]
レスポンス シンセサイザーを定義して使用する
モデルと Retriever を定義したら、ユーザークエリと特定のテキスト チャンクのセットを使用して LLM からレスポンスを生成するレスポンス シンセサイザーを定義します。デフォルトの get_response_synthesizer を使用するか、レスポンス モードを構成できます。
回答を返すレスポンス シンセサイザーを定義します。
def response_synthesizer_builder(model, response_synthesizer_kwargs=None): from llama_index.core.response_synthesizers import SimpleSummarize return SimpleSummarize(llm=model)
関数をテストします。
response_synthesizer = response_synthesizer_builder(model=model) response = response_synthesizer.get_response( "What is Paul Graham's life in College?", [node.model_dump_json() for node in retrieved_response], )
レスポンスの例を以下に示します。
"While in a PhD program for computer science, he took art classes and worked on a book about Lisp hacking. He applied to art schools, got accepted to RISD, and later got an invitation to take the entrance exam at the Accademia di Belli Arti in Florence. He was accepted to both. He attended the Accademia, but was disappointed by the lack of instruction."
LlamaIndexQueryPipeline
テンプレートでレスポンス シンセサイザーを使用するには、response_synthesizer_builder=
引数の下に追加します。from vertexai.preview import reasoning_engines agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model=model, # Required. model_kwargs=model_kwargs, # Optional. retriever_builder=retriever_builder, # Optional. response_synthesizer_builder=response_synthesizer_builder, # Optional. )
テストクエリを実行して、RAG クエリ パイプライン全体をローカルでテストします。
response = agent.query( input="What is Paul Graham's life in College?" )
レスポンスは、次のような辞書形式になります。
{ 'response': "While in college, he was drawn to McCarthy's 1960 Lisp, although he didn't fully grasp the reasons for his interest at the time. He also had a brief encounter with surplus Xerox Dandelions in the computer lab but found them too slow for his liking. \n", 'source_nodes': [ '{"node":{"id_":"95889c30-53c7-43d0-bf91-930dbb23bde6"...,"score":0.7077213268404997,"class_name":"NodeWithScore"}' ], 'metadata': { '95889c30-53c7-43d0-bf91-930dbb23bde6': { 'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-25', 'last_modified_date': '2025-03-25' } } }
(省略可)プロンプト テンプレートをカスタマイズする
プロンプト テンプレートは、ユーザー入力をモデルの指示に変換し、コンテキストに応じて関連性と一貫性のある出力のレスポンスをガイドします。詳しくは、プロンプトをご覧ください。
デフォルトのプロンプト テンプレートは、次のセクションに順番に編成されています。
セクション | 説明 |
---|---|
(省略可)システム指示 | すべてのクエリに適用されるエージェント向けの手順。 |
ユーザー入力 | ユーザーからのエージェントに渡すクエリ。 |
独自のプロンプト テンプレートを指定せずにエージェントを作成すると、デフォルトのプロンプト テンプレートが生成されます。このテンプレートは次のようになります。
from llama_index.core import prompts
from llama_index.core.base.llms import types
message_templates = [
types.ChatMessage(role=types.MessageRole.SYSTEM, content=system_instruction),
types.ChatMessage(role=types.MessageRole.USER, content="{input}"),
]
prompts.ChatPromptTemplate(message_templates=message_templates)
次の例では、エージェントをインスタンス化すると、プロンプト テンプレートの全体を使用できます。
from vertexai.preview import reasoning_engines
system_instruction = "I help to find what is Paul Graham's life in College"
agent = reasoning_engines.LlamaIndexQueryPipelineAgent(
model=model,
system_instruction=system_instruction,
)
デフォルトのプロンプト テンプレートを独自のプロンプト テンプレートでオーバーライドし、エージェントの作成時に使用できます。
prompt_str = "Please answer {question} about {name}"
prompt_tmpl = PromptTemplate(prompt_str)
from vertexai.preview import reasoning_engines
agent = reasoning_engines.LlamaIndexQueryPipelineAgent(
model = model,
prompt = prompt_tmpl,
)
agent.query(
input={
"name": "Paul Graham",
"question": "What is the life in college?",
}
)
(省略可)オーケストレーションをカスタマイズする
すべての LlamaIndexQueryPipeline
コンポーネントは、オーケストレーション用の入力スキーマと出力スキーマを提供する Query Component インターフェースを実装します。LlamaIndexQueryPipelineAgent
では、クエリに応答するために実行可能ファイルをビルドする必要があります。デフォルトでは、LlamaIndexQueryPipelineAgent
は Query Pipeline
を使用して順次チェーンまたは有向非巡回グラフ(DAG)を構築します。
次のいずれかを行う場合は、オーケストレーションをカスタマイズすることをおすすめします。
RAG パイプラインを拡張するエージェントを実装します(既存のプロンプト、モデル、取得ツール、レスポンス シンセサイザー モジュールを クエリエンジン、クエリ トランスフォーマー、出力パーサー、ポストプロセッサ/再ランク、カスタム クエリ コンポーネントに拡張するなど)。
ReAct を使用してエージェントにプロンプトを送り、ツールを実行し、各ステップにそのステップを実行した理由をコメントでアノテーションします。そのためには、
LlamaIndexQueryPipelineAgent
を作成するときにrunnable_builder=
引数を指定して、デフォルトの実行可能ファイルをオーバーライドします。from typing import Optional from llama_index.core.llms import function_calling def runnable_builder( model: function_calling.FunctionCallingLLM, *, system_instruction: Optional[str] = None, prompt: Optional[query.QUERY_COMPONENT_TYPE] = None, retriever: Optional[query.QUERY_COMPONENT_TYPE] = None, response_synthesizer: Optional[query.QUERY_COMPONENT_TYPE] = None, runnable_kwargs: Optional[Mapping[str, Any]] = None, ):
ここで
model
は、model_builder
から返されるチャットモデルに対応します(モデルを定義して構成するをご覧ください)。retriever
とretriever_kwargs
は、使用する Retriever と構成に対応します(Retriever を定義するをご覧ください)。response_synthesizer
とresponse_synthesizer_kwargs
は、使用するレスポンス シンセサイザーと構成に対応します(レスポンス シンセサイザーを定義するをご覧ください)。system_instruction
とprompt
は、プロンプト構成に対応しています(プロンプト テンプレートをカスタマイズするをご覧ください)。agent_executor_kwargs
とrunnable_kwargs
は、実行可能ファイルのカスタマイズに使用できるキーワード引数です。
カスタム パイプラインまたは ReAct を使用して、オーケストレーション ロジックをカスタマイズできます。
カスタム パイプライン
エージェントに追加のモジュール(Postprocessor など)を提供する場合は、LlamaIndexQueryPipelineAgent
の runnable_builder
をオーバーライドします。
ポストプロセッサを定義します。
def post_processor_builder(): from llama_index.core.postprocessor import SimilarityPostprocessor # similarity postprocessor: filter nodes below 0.7 similarity score return SimilarityPostprocessor(similarity_cutoff=0.7) def runnable_with_postprocessor_builder( model, runnable_kwargs, **kwargs ): from llama_index.core.query_pipeline import QueryPipeline pipeline = QueryPipeline(**runnable_kwargs) pipeline_modules = { "retriever": retriever_builder(model), "postprocessor": post_processor_builder(), } pipeline.add_modules(pipeline_modules) pipeline.add_link("retriever", "postprocessor") return pipeline agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model=model, runnable_builder=runnable_with_postprocessor_builder, )
エージェントにクエリを実行します。
result = agent.query(input="What is Paul Graham's life in College?")
出力例を以下に示します。
[ { 'node': {'id_': 'bb7d2942-213d-4fb3-a7cb-1a664642a7ff', 'embedding': None, 'metadata': { 'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-25', 'last_modified_date': '2025-03-25' }, 'excluded_embed_metadata_keys': [ 'file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date' ], 'excluded_llm_metadata_keys': [ 'file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date' ], 'relationships': {'1': {'node_id': 'c508cee5-5ef2-4fdf-a33d-0427dcb78b5c', 'node_type': '4', 'metadata': {'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-25', 'last_modified_date': '2025-03-25'}, 'hash': '0c3c3f46cac874b495d944dfc4b920f6b68817dbbb1699ecc955d1fafb2bf87b', 'class_name': 'RelatedNodeInfo'}, '2': {'node_id': '97a84b41-62bf-4959-acae-cfd4bdfbd4d9', 'node_type': '1', 'metadata': {'file_path': '/content/data/paul_graham/paul_graham_essay.txt', 'file_name': 'paul_graham_essay.txt', 'file_type': 'text/plain', 'file_size': 75042, 'creation_date': '2025-03-25', 'last_modified_date': '2025-03-25'}, 'hash': 'a7dd352be97e47e8e553ceda3d2d2c9e9d5c54adb298063c94da06167938d583', 'class_name': 'RelatedNodeInfo'}, '3': {'node_id': 'b984eea1-f0bc-4880-812e-3f49f1e304b8', 'node_type': '1', 'metadata': {}, 'hash': 'db7cc1a67fa3afd1e5f24c8c61583781ce6a00c444da8f25a5374468c17b7de0', 'class_name': 'RelatedNodeInfo'}}, 'metadata_template': '{key}: {value}', 'metadata_separator': '\n', 'text': 'So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp...', 'mimetype': 'text/plain', 'start_char_idx': 7166, 'end_char_idx': 11549, 'metadata_separator': '\n', 'text_template': '{metadata_str}\n\n{content}', 'class_name': 'TextNode'}, 'score': 0.7403571819090398, 'class_name': 'NodeWithScore' }, { 'node': {'id_': 'b984eea1-f0bc-4880-812e-3f49f1e304b8...'} 'score': 0.7297395567513889, 'class_name': 'NodeWithScore' } ]
ReAct エージェント
独自の ReAct エージェントでツール呼び出し動作を提供するには、LlamaIndexQueryPipelineAgent
の runnable_builder
をオーバーライドします。
為替レートを返す関数の例を定義します。
def get_exchange_rate( currency_from: str = "USD", currency_to: str = "EUR", currency_date: str = "latest", ): """Retrieves the exchange rate between two currencies on a specified date. Uses the Frankfurter API (https://api.frankfurter.app/) to obtain exchange rate data. Args: currency_from: The base currency (3-letter currency code). Defaults to "USD" (US Dollar). currency_to: The target currency (3-letter currency code). Defaults to "EUR" (Euro). currency_date: The date for which to retrieve the exchange rate. Defaults to "latest" for the most recent exchange rate data. Can be specified in YYYY-MM-DD format for historical rates. Returns: dict: A dictionary containing the exchange rate information. Example: {"amount": 1.0, "base": "USD", "date": "2023-11-24", "rates": {"EUR": 0.95534}} """ import requests response = requests.get( f"https://api.frankfurter.app/{currency_date}", params={"from": currency_from, "to": currency_to}, ) return response.json()
ツールを使用してカスタム ReAct エージェントを作成する。
def runnable_with_tools_builder(model, runnable_kwargs=None, **kwargs): from llama_index.core.query_pipeline import QueryPipeline from llama_index.core.tools import FunctionTool from llama_index.core.agent import ReActAgent llama_index_tools = [] for tool in runnable_kwargs.get("tools"): llama_index_tools.append(FunctionTool.from_defaults(tool)) agent = ReActAgent.from_tools(llama_index_tools, llm=model, verbose=True) return QueryPipeline(modules = {"agent": agent}) agent = reasoning_engines.LlamaIndexQueryPipelineAgent( model="gemini-2.0-flash", runnable_kwargs={"tools": [get_exchange_rate]}, runnable_builder=runnable_with_tools_builder, )
エージェントにクエリを実行します。
result = agent.query(input="What is the exchange rate between US and EURO today?")
出力は次のようになります。
{ 'response': 'The exchange rate between US and EURO today, 2025-03-19, is 1 USD to 0.91768 EUR.', 'source_nodes': [], 'metadata': None }