In financial services, portfolio managers and research analysts diligently sift through vast amounts of data to gain a competitive edge in investments. Making informed decisions requires access to the most pertinent data and the ability to quickly synthesize and interpret that data.
Traditionally, sell-side analysts and fundamental portfolio managers have focused on a small subset of companies, meticulously examining financial statements, earning calls, and corporate filings. Systematically analyzing financial documents across a larger trading universe can uncover additional insights. Due to the technical and algorithmic difficulty of such tasks, systematic analysis of transcripts over a wide trading universe was, until recently, only accessible to sophisticated quant-trading firms.
The performance achieved on these tasks using traditional
natural language processing (NLP)
methods such as bag-of-words, sentiment dictionaries, and word statistics, often falls short when compared to the capabilities of
large language models (LLMs)
in financial NLP tasks. Besides financial applications, LLMs have demonstrated superior performance in domains like medical document understanding, news article summarization, and legal document retrieval.
By leveraging AI and NVIDIA technology, sell-side analysts, fundamental traders, and retail traders can significantly accelerate their research workflow, extract more nuanced insights from financial documents, and cover more companies and industries. By adopting these advanced AI tools, the financial services sector can enhance its data analysis capabilities, saving time and improving the accuracy of investment decisions. According to the NVIDIA
2024 State of AI in Financial Services
survey report, 37% of respondents are exploring generative AI and LLMs for report generation, synthesis, and investment research to reduce repetitive manual work.
In this post, we’ll walk you through an end-to-end demo on how to build an AI assistant to extract insights from earnings call transcripts using
NVIDIA NIM
inference microservices to implement a
retrieval-augmented generation (RAG)
system. We’ll highlight how leveraging advanced AI technologies can accelerate workflows, uncover hidden insights, and ultimately enhance decision-making processes in the financial services industry.
Analyzing earnings call transcripts with NIM microservices
Earnings calls in particular are a vital source for investors and analysts, providing a platform for companies to communicate important financial and business information. These calls offer insights into the industry, the company’s products, competitors, and most importantly, its business prospects.
By analyzing earnings call transcripts, investors can glean valuable information about a company’s future earnings and valuation. Earnings call transcripts have successfully been used to generate alpha for over two decades. For more details, see
Natural Language Processing – Part I: Primer
and
Natural Language Processing – Part II: Stock Selection
.
Step 1: The data
In this demo, we use transcripts from NASDAQ earnings calls from 2016 to 2020 for our analysis. This
Earnings Call Transcripts dataset
can be downloaded from Kaggle.
For our evaluation, we used a subset of 10 companies from which we then randomly selected 63 transcripts for manual annotation. For all transcripts, we answered the following set of questions:
What are the company’s primary revenue streams and how have they changed over the past year?
What are the company’s major cost components and how have they fluctuated in the reporting period?
What capital expenditures were made and how are these supporting the company’s growth?
What dividends or stock buybacks were executed?
What significant risks are mentioned in the transcript?
This makes for a total of 315 question-answer pairs. All questions are answered using a structured
JSON format
. For example:
Question: What are the company’s primary revenue streams and how have they changed over the past year?
Answer:
{ 
  "Google Search and Other advertising": { 
	"year_on_year_change": "-10%", 
	"absolute_revenue": "21.3 billion", 
	"currency": "USD" 
  }, 
  "YouTube advertising": { 
	"year_on_year_change": "6%", 
	"absolute_revenue": "3.8 billion", 
	"currency": "USD" 
  }, 
  "Network advertising": { 
	"year_on_year_change": "-10%", 
	"absolute_revenue": "4.7 billion", 
	"currency": "USD" 
  }, 
  "Google Cloud": { 
	"year_on_year_change": "43%", 
	"absolute_revenue": "3 billion", 
	"currency": "USD" 
  }, 
  "Other revenues": { 
	"year_on_year_change": "26%", 
	"absolute_revenue": "5.1 billion", 
	"currency": "USD" 
  } 
}
Using JSON enables evaluating model performance in a manner that does not rely on subjective language understanding methods, such as
LLM-as-a-judge
, which might introduce unwanted biases into the evaluation.
Step 2: NVIDIA NIM
This demo uses
NVIDIA NIM
, a set of microservices designed to speed up enterprise
generative AI
deployment. For more details, see
NVIDIA NIM Offers Optimized Inference Microservices for Deploying AI Models at Scale
. Supporting a wide range of AI models, including NVIDIA-optimized community and commercial partner models, NIM ensures seamless, scalable AI inferencing, on-premises or in the cloud, leveraging industry-standard APIs.
When ready for production, NIM microservices are deployed with a single command for easy integration into enterprise-grade AI applications using standard APIs and just a few lines of code. Built on robust foundations including inference engines like
NVIDIA TensorRT
, TensorRT-LLM, and PyTorch, NIM is engineered to facilitate seamless AI inferencing with best performance out-of-the-box based on the underlying hardware. Self-hosting models with NIM supports the protection of customer and enterprise data, which is a common requirement in RAG applications.
Step 3: Setting up on NVIDIA API catalog
NIM microservices can be accessed using the NVIDIA API catalog. All it takes to set up is registering an NVIDIA API key (From the
API catalog
, click Get API Key.) For the purposes of this post, we’ll store it in an environment variable:
export NVIDIA_API_KEY=YOUR_KEY
LangChain provides a package for
convenient NGC integration
. This tutorial will use endpoints to run embedding, reranking, and chat models with NIM microservices. To reproduce the code, you’ll need to install the following Python dependencies:
langchain-nvidia-ai-endpoints==0.1.2 
faiss-cpu==1.7.4 
langchain==0.2.5 
unstructured[all-docs]==0.11.2
Step 4: Building a RAG pipeline with NIM microservices
RAG is a method that enhances language models by combining retrieval of relevant documents from a large corpus with text generation.
The first step of RAG is to vectorize your collection of documents. This involves taking a series of documents, splitting them into smaller chunks, using an embedder model to turn each of these chunks into a neural network embedding (a vector), and storing them in a
vector database
.
We’ll do this for each of the earning calls transcripts:
import os 
from langchain.text_splitter import RecursiveCharacterTextSplitter 
from langchain.document_loaders import TextLoader 
from langchain.vectorstores import FAISS 
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings 
 
# Initialise the embedder that converts text to vectors 
transcript_embedder = NVIDIAEmbeddings(model='nvidia/nv-embed-v1', 
                                       truncate='END' 
                                       ) 
 
# The document we will be chunking and vectorizing 
transcript_fp = "Transcripts/GOOGL/2020-Feb-03-GOOGL.txt" 
raw_document = TextLoader(transcript_fp).load() 
# Split the document into chunks of 1500 characters each 
text_splitter = RecursiveCharacterTextSplitter(chunk_size=3000, 
                                               chunk_overlap=200) 
documents = text_splitter.split_documents(raw_document) 
# Vectorise each chunk into a separate entry in the database 
vectorstore = FAISS.from_documents(documents, transcript_embedder) 
vector_store_path = "vector_db/google_transcript_2020_feb.pkl" 
try: 
    os.remove(vector_store_path) 
except OSError: 
    pass 
vectorstore.save_local(vector_store_path)
Once the vectorized database is built, the simplest RAG flow for the earning calls transcripts is as follows:
A user inputs a
query.
For example, “What are the company’s main revenue sources?”
The
embedder
model embeds the query into a vector and then searches through the vectorized database of the documents for the Top-K (Top-30, for example) most relevant chunks.
A
reranker
model, also known as a cross-encoder, then outputs a similarity score for each query-document pair. Additionally, metadata can also be used to help improve the accuracy of the reranking step. This score is used to reorder the Top-K documents retrieved by the embedder by relevance to the user query. Further filtering can then be applied, retaining only the Top-N (Top-10, for example) documents.
The Top-N most relevant documents are then passed onto an
LLM
alongside the user query. The retrieved documents are used as context to ground the model’s answer.
Figure 2. A simplified RAG workflow that involves three main steps: embedding and retrieval, reranking, and context-grounded LLM answer generation
Note that modifications can be made to improve a model’s answer accuracy, but for now we’ll continue with the simplest robust approach.
Consider the following user query and desired JSON format:
question = "What are the company’s primary revenue streams and how have they changed over the past year?" 
 
json_template = """ 
{"revenue_streams": [ 
    { 
        "name": "<Revenue Stream Name 1>", 
        "amount": <Current Year Revenue Amount 1>, 
        "currency": "<Currency 1>", 
        "percentage_change": <Change in Revenue Percentage 1> 
    }, 
    { 
        "name": "<Revenue Stream Name 2>", 
        "amount": <Current Year Revenue Amount 2>, 
        "currency": "<Currency 2>", 
        "percentage_change": <Change in Revenue Percentage 2> 
    }, 
    // Add more revenue streams as needed 
] 
} 
""" 
 
user_query = question + json_template
The JSON template will be used so that, further down the pipeline, the LLM knows to output its answer in valid JSON, rather than in plain text. As mentioned in Step 1, using JSON enables the automated evaluation of model answers in an objective manner. Note that this could be removed if a more conversational style is preferred.
To contextualize the user query, initialize the Embedder and the Reranker for the retrieval and ordering of the relevant documents:
from langchain_nvidia_ai_endpoints import NVIDIARerank 
from langchain.retrievers.contextual_compression import ContextualCompressionRetriever 
 
# How many retrieved documents to keep at each step 
top_k_documents_retriever = 30 
top_n_documents_reranker = 5 
# Initialie retriever for vector database 
retriever = vectorstore.as_retriever(search_type='similarity', 
                                     search_kwargs={'k': top_k_documents_retriever}) 
# Add a reranker to reorder documents by relevance to user query 
reranker = NVIDIARerank(model="ai-rerank-qa-mistral-4b", 
                         top_n=top_n_documents_reranker) 
retriever = ContextualCompressionRetriever(base_compressor=reranker, 
                                           base_retriever=retriever) 
# Retrieve documents, rerank them and pick top-N 
retrieved_docs = retriever.invoke(user_query) 
# Join all retrieved documents into a single string 
context = "" 
for doc in retrieved_docs: 
    context += doc.page_content + "\n\n"
Then, when the relevant documents are retrieved, they can be passed onto the LLM alongside the user query. We are using the
Llama 3 70B
NIM:
from langchain_nvidia_ai_endpoints import ChatNVIDIA 
 
PROMPT_FORMAT = """" 
Given the following context: 
 
#################### 
{context} 
#################### 
 
Answer the following question: 
{question} 
 
using the following JSON structure: 
 
{json_template} 
 
For amounts don't forget to always state if it's in billions or millions and "N/A" if not present. 
Only use information and JSON keys that are explicitly mentioned in the transcript. 
If you don't have information for any of the keys use "N/A" as a value.  
Answer only with JSON. Every key and value in the JSON should be a string. 
""" 
 
llm = ChatNVIDIA(model="ai-llama3-70b", 
                 max_tokens=600, 
                 temperature=0
                ) 
 
llm_input = PROMPT_FORMAT.format(**{"context": context, 
                                    "question": question, 
                                    "json_template": json_template 
                                   }) 
answer = llm.invoke(llm_input) 
print(answer.content)
Running this code will produce a JSON-structured answer to the user query. The code can now be easily modified to read in multiple transcripts and answer varying user queries.
Step 5: Evaluation
To evaluate the performance of the retrieval step, use the annotated question-answer pairs previously described to compare the ground-truth JSON with the predicted JSON, key-by-key. Consider the following ground-truth example:
"Google Cloud": { 
    "year_on_year_change": "43%", 
    "absolute_revenue": "3 billion", 
    "currency": "N/A" 
}
The prediction looks like this:
"Google Cloud": { 
	"year_on_year_change": "43%", 
	"absolute_revenue": "N/A", 
	"currency": "USD" 
}
The three possible outcomes are:
True positive (TP)
: There is no value to extract, and the ground truth and the prediction match. For the previous example, the prediction for
year_on_year_change
is TP.
False Positive (FP)
: The ground truth value is
“N/A”
. In other words, there is no value to extract, but the prediction hallucinates a value. For the previous example, the prediction for
currency
is FP.
False Negative (FN)
: There is a ground truth value to extract, however, the prediction fails to capture that value. For the previous example, the prediction for
absolute_revenue
is FP.
With these outcomes measured, next calculate the following three main metrics:
Recall
= TP/ (TP + FN): Higher recall implies our model is returning more and more of the relevant results.
Precision
= TP / (TP + FP): Higher precision implies our model returns a higher ratio of relevant results versus irrelevant ones.
F1-score
= (2 * Precision * Recall) / (Precision + Recall): The F1-score is a harmonic mean of precision and recall.
A user might want to be partially flexible with the matching of non-numeric values when doing string comparisons for some of the attributes. For example, consider a question about revenue sources, where one of the ground-truth answers is “Data Centers” and the model outputs “Data Center”. An exact match evaluation would treat this as a mismatch. To achieve more robust evaluation in such cases, use fuzzy matching with the Python default
difflib
:
import difflib


def get_ratio_match(gt_string, pred_string):
   if len(gt_string) < len(pred_string):
       min_len = len(gt_string)
   else:
       min_len = len(pred_string)
   matcher = difflib.SequenceMatcher(None, gt_string, pred_string, autojunk=False)
   _, _, longest_match = matcher.find_longest_match(0, min_len, 0, min_len)
   # Return the ratio of match with ground truth
   return longest_match / min_len
For evaluation, consider any string attributes to be a match if their similarity ratio is above 90%.
Table 1 presents results for two of the most-used open-source model families (Mistral AI Mixtral models and Meta Llama 3 models) on our manually annotated data. For both model families, there is noticeable performance deterioration when lowering the number of parameters. Visit the
NVIDIA API catalog
to experience these NIM microservices.
Method
F1
Precision
Recall
Llama 3 70B
84.4%
91.3%
78.5%
Llama 3 8B
75.8%
85.2%
68.2%
Mixtral 8x22B
84.4%
91.9%
78.0%
Mixtral 8x7B
62.2%
80.2%
50.7%
Table 1. Performance of Llama and Mixtral models on JSON-structured information extraction and question-answering from earning call transcripts
Mixtral-8x22B seems to have roughly equivalent performance to Llama 3 70B. However, for both model families, reducing the number of parameters does result in a significant decrease in performance. A decrease is most accentuated for Recall. This presents a frequent trade-off between choosing to have better accuracy at the cost of larger hardware requirements.
In most cases, model accuracy can be improved without increasing the number of parameters, by fine-tuning either the Embedder, Reranker, or the LLM using domain-specific data (in this case, earning call transcripts).
The Embedder is the smallest and therefore the quickest and most cost-effective to fine-tune. For detailed instructions, refer to the
NVIDIA NeMo documentation
. Additionally,
NVIDIA NeMo
simplifies and enhances the efficiency of fine-tuning an effective version of the LLM.
Key implications for users
This demo is designed to extract insights from earnings call transcripts. By leveraging advanced AI technologies like NIM, it’s now possible to quickly and accurately retrieve information from earnings call transcripts. The AI product assists multiple categories of financial researchers, analysts, advisors, and fundamental portfolio managers during the most intensive processes of documentation and data analysis, enabling financial professionals to spend more time on strategic decision-making or with clients.
In the asset management sector, for example, portfolio managers can use the assistant to quickly synthesize insights from a vast number of earnings calls, improving investment strategies and outcomes. In the insurance industry, the AI assistant can analyze financial health and risk factors from company reports, enhancing underwriting and risk assessment processes. In fundamental and retail trading, the assistant can help with systematic information extraction to identify market trends and sentiment shifts, enabling the use of more detailed information for future trades.
Even in banking, it can be used to assess the financial stability of potential loan recipients by analyzing their earnings calls. Ultimately, this technology enhances efficiency, accuracy, and the ability to make data-driven decisions, giving users a competitive edge in their respective markets.
Visit the
NVIDIA API catalog
to see all the available NIM microservices and experiment with
LangChain’s convenient integration
to see what works best for your own data.
Reading Time:
4
minutes
金融サービスでは、ポートフォリオ マネージャーやリサーチ アナリストが膨大な量のデータを丹念に精査し、投資で競争力を高めています。情報に基づいた意思決定を行うには、最も関連性の高いデータにアクセスし、そのデータを迅速に統合して解釈する能力が必要です。
従来、セルサイド アナリストやファンダメンタル ポートフォリオ マネージャーは、財務諸表、収益報告、企業提出書類を綿密に調べ、一部の企業に焦点を当ててきました。より広範な取引対象範囲にわたって財務文書を体系的に分析することで、さらなる洞察を得ることができます。このようなタスクは技術的およびアルゴリズム的に難しいため、広範な取引対象範囲にわたるトランスクリプトの体系的な分析は、最近まで、高度なクオンツ トレーディング (quant-trading) 会社にしかできませんでした。
これらのタスクで、バッグオブワード、感情辞書、単語統計などの従来の
自然言語処理 (NLP)
手法を使用して達成されるパフォーマンスは、金融 NLP タスクにおける
大規模言語モデル (LLM)
の機能と比較すると、しばしば不十分です。金融アプリケーション以外にも、LLM は医療文書の理解、ニュース記事の要約、法的文書の検索などの分野で優れたパフォーマンスを発揮しています。
AI と NVIDIA のテクノロジを活用することで、セルサイド アナリスト、ファンダメンタル トレーダー、リテール トレーダーはリサーチ ワークフローを大幅に加速し、金融文書からより微妙な洞察を抽出し、より多くの企業や業界をカバーできます。これらの高度な AI ツールを導入することで、金融サービス部門はデータ分析機能を強化し、時間を節約し、投資決定の精度を向上させることができます。
NVIDIA の 2024 年金融サービス
における AI の現状調査レポートによると、回答者の 37% (中国を除く) が、反復的な手作業を減らすために、レポート生成、統合合成、投資調査のための生成 AI と LLM を検討しています。
この記事では、
NVIDIA NIM
推論マイクロサービスを使用して収益報告のトランスクリプトから洞察を抽出する AI アシスタントを構築し、
検索拡張生成 (RAG)
システムを実装する方法について、エンドツーエンドのデモで説明します。高度な AI テクノロジを活用することで、ワークフローを加速し、隠れた洞察を明らかにし、最終的に金融サービス業界の意思決定プロセスを強化する方法を紹介します。
NIM による収益報告の記録の分析
特に、決算発表の電話会議は投資家やアナリストにとって重要な情報源であり、企業が重要な財務情報や事業情報を伝達するプラットフォームを提供します。これらの電話会議は、業界、企業の製品、競合他社、そして最も重要な事業見通しについての洞察を提供します。
決算発表の電話会議の記録を分析することで、投資家は企業の将来の収益と評価に関する貴重な情報を収集できます。決算発表の電話会議の記録は、20 年以上にわたってアルファを生み出すために効果的に使用されてきました。詳細については、
「自然言語処理 – パート I: 入門」
(2017 年 9 月) および
「自然言語処理 – パート II: 銘柄選択」
(2018 年 9 月)を参照してください。
ステップ 1: データ
このデモでは、2016 年から 2020 年までの NASDAQ の収益報告のトランスクリプトを分析に使用します。この
収益報告のトランスクリプト データセット
は、Kaggle からダウンロードできます。
評価では、10 社のサブセットを使用し、そこから 63 件のトランスクリプトをランダムに選択して手動で注釈を付けました。すべてのトランスクリプトについて、次の一連の質問に答えました:
会社の主な収益源は何ですか。過去 1 年間でどのように変化しましたか?
会社の主なコスト要素は何ですか。報告期間中にどのように変動しましたか?
どのような設備投資が行われ、それがどのように会社の成長を支えていますか?
どのような配当または株式買い戻しが実行されましたか?
トランスクリプトで言及されている重要なリスクは何ですか?
これにより、合計 315 の質問と回答のペアが作成されます。すべての質問への回答は、構造化された
JSON フォーマット
を使用して行われます。
たとえば:
質問: 会社の主な収入源は何ですか? また、過去 1 年間でどのように変化しましたか? (What are the company’s primary revenue streams and how have they changed over the past year?)
回答:
{ 
  "Google Search and Other advertising": { 
    "year_on_year_change": "-10%", 
    "absolute_revenue": "21.3 billion", 
    "currency": "USD"
  }, 
  "YouTube advertising": { 
    "year_on_year_change": "6%", 
    "absolute_revenue": "3.8 billion", 
    "currency": "USD"
  }, 
  "Network advertising": { 
    "year_on_year_change": "-10%", 
    "absolute_revenue": "4.7 billion", 
    "currency": "USD"
  }, 
  "Google Cloud": { 
    "year_on_year_change": "43%", 
    "absolute_revenue": "3 billion", 
    "currency": "USD"
  }, 
  "Other revenues": { 
    "year_on_year_change": "26%", 
    "absolute_revenue": "5.1 billion", 
    "currency": "USD"
  } 
}
JSON を使用すると、評価に望ましくないバイアスを導入する可能性のある「
LLM 断言
」などの主観的な言語理解方法に依存せずにモデルのパフォーマンスを評価できます。
ステップ 2: NVIDIA NIM
このデモでは、エンタープライズ生成 AI の導入を高速化するために設計されたマイクロサービス セットである
NVIDIA NIM
を使用します。詳細については、
「NVIDIA NIM は AI モデルの大規模な導入向けに最適化された推論マイクロサービスを提供します」
を参照してください。
NVIDIA 向けに最適化されたコミュニティ モデルや商用パートナー モデルなど、幅広い AI モデルをサポートする NIM は、業界標準の API を活用して、オンプレミスまたはクラウドでシームレスでスケーラブルな AI 推論を実現します。実稼働の準備ができたら、NIM は 1 つのコマンドで導入され、標準 API とわずか数行のコードを使用してエンタープライズ グレードの AI アプリケーションに簡単に統合できます。
NVIDIA TensorRT
、TensorRT-LLM、PyTorch などの推論エンジンを含む堅牢な基盤上に構築された NIM は、基盤となるハードウェアに基づいてすぐに最高のパフォーマンスでシームレスな AI 推論を実現するように設計されています。NIM を使用したセルフホスティング (self-hosting) モデルは、RAG アプリケーションで一般的な要件である顧客データと企業データの保護をサポートします。
ステップ 3: NVIDIA API カタログでの設定
NIM には、
NVIDIA API カタログ
を使用してアクセスできます。設定に必要なのは、NVIDIA API キーを登録することだけです (API カタログから、[API キーの取得] をクリックします)。この記事では、これを環境変数に保存します。
export NVIDIA_API_KEY=YOUR_KEY
LangChain は、
便利な NGC 統合
用のパッケージを提供しています。このチュートリアルでは、エンドポイントを使用して、NIM で埋め込み、リランキング、チャット モデルを実行します。コードを再現するには、次の Python 依存関係をインストールする必要があります。
langchain-nvidia-ai-endpoints==0.1.2
faiss-cpu==1.7.4
langchain==0.2.5
unstructured[all-docs]==0.11.2
ステップ 4: NIM を使用した RAG パイプラインの構築
RAG は、大規模なコーパスからの関連文書の取得とテキスト生成を組み合わせることで言語モデルを強化する方法です。
RAG の最初のステップは、文書のコレクションをベクトル化することです。これには、一連の文書を取得し、それらを小さなチャンクに分割し、埋め込みモデルを使用してこれらの各チャンクをニューラル ネットワーク埋め込み (ベクトル) に変換し、
ベクトル データベース
に保存することが含まれます。各収益報告通話のトランスクリプトに対してこれらの操作を実行します。
import os 
from langchain.text_splitter import RecursiveCharacterTextSplitter 
from langchain.document_loaders import TextLoader 
from langchain.vectorstores import FAISS 
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings 
  
# Initialise the embedder that converts text to vectors 
transcript_embedder = NVIDIAEmbeddings(model='nvidia/nv-embed-v1', 
                                       truncate='END'
                                       ) 
  
# The document we will be chunking and vectorizing 
transcript_fp = "Transcripts/GOOGL/2020-Feb-03-GOOGL.txt"
raw_document = TextLoader(transcript_fp).load() 
# Split the document into chunks of 1500 characters each 
text_splitter = RecursiveCharacterTextSplitter(chunk_size=3000, 
                                               chunk_overlap=200) 
documents = text_splitter.split_documents(raw_document) 
# Vectorise each chunk into a separate entry in the database 
vectorstore = FAISS.from_documents(documents, transcript_embedder) 
vector_store_path = "vector_db/google_transcript_2020_feb.pkl"
try: 
    os.remove(vector_store_path) 
except OSError: 
    pass
vectorstore.save_local(vector_store_path)
ベクトル化されたデータベースが構築されると、収益報告の記録の最も単純な RAG フローは次のようになります。
ユーザーが
クエリ (query)
を入力します。たとえば、「会社の主な収益源は何ですか?」(What are the company’s main revenue sources?)
埋め込みモデル (embedder)
はクエリをベクトルに埋め込み、ドキュメントのベクトル化されたデータベースを検索して、最も関連性の高い上位 K (例えば、上位 30 など) のチャンクを探します。
次に、クロスエンコーダーとも呼ばれる
リランキング (reranker)
モデルが、クエリとドキュメントの各ペアの類似性スコアを出力します。さらに、メタデータを使用して、再ランク付けステップの精度を向上させることもできます。このスコアは、埋め込みによって取得された上位 K のドキュメントを、ユーザー クエリとの関連性で並べ替えるために使用されます。その後、さらにフィルタリングを適用して、上位 N (例えば、上位 10 など) のドキュメントのみを保持できます。
次に、最も関連性の高い上位 N のドキュメントが、ユーザークエリとともに
LLM
に渡されます。取得されたドキュメントは、モデルの回答を基盤付けるコンテキストとして使用されます。
図1. 埋め込みと検索、リランキング、コンテキストに基づいた LLM 回答生成という 3 つの主要なステップを含む簡略化された RAG ワークフロー
モデルの回答精度を向上させるために変更を加えることもできますが、今のところは最もシンプルで堅牢なアプローチを続けます。
次のユーザー クエリと必要な JSON フォーマットを検討してください。
question = "What are the company’s primary revenue streams and how have they changed over the past year?"

# 会社の主な収入源は何ですか? また、過去 1 年間でどのように変化しましたか?
  
json_template = """ 
{"revenue_streams": [ 
    { 
        "name": "<Revenue Stream Name 1>", 
        "amount": <Current Year Revenue Amount 1>, 
        "currency": "<Currency 1>", 
        "percentage_change": <Change in Revenue Percentage 1> 
    }, 
    { 
        "name": "<Revenue Stream Name 2>", 
        "amount": <Current Year Revenue Amount 2>, 
        "currency": "<Currency 2>", 
        "percentage_change": <Change in Revenue Percentage 2> 
    }, 
    // Add more revenue streams as needed 
] 
} 
"""
  
user_query = question + json_template
JSON テンプレートは、パイプラインのさらに先で、LLM がプレーン テキストではなく有効な JSON フォーマットで回答を出力することを認識できるように使用されます。ステップ 1 で述べたように、JSON を使用すると、客観的な方法でモデル回答を自動的に評価できます。より「会話的なスタイル」が望ましい場合は、これを削除できることに注意してください。
ユーザー クエリをコンテキスト化するには、関連するドキュメントを取得して順序付けするために、Embedder (埋め込みモデル) と Reranker (リランキングモデル) を初期化します:
from langchain_nvidia_ai_endpoints import NVIDIARerank
from langchain.retrievers.contextual_compression import ContextualCompressionRetriever
  
# 1 How many retrieved documents to keep at each step, 各ステップで取得されたドキュメントをいくつ保存するかの設定：
top_k_documents_retriever = 30
top_n_documents_reranker = 5
# 2 Initialize retriever for vector database, ベクトルデータベースの取得を初期化する:
retriever = vectorstore.as_retriever(search_type='similarity',
                                     search_kwargs={'k': top_k_documents_retriever})
# 3 Add a reranker to reorder documents by relevance to user query, ユーザークエリとの関連性に基づいてドキュメントを並べ替えるリランキング機能を追加する:
reranker = NVIDIARerank(model="ai-rerank-qa-mistral-4b",
                         top_n=top_n_documents_reranker)
retriever = ContextualCompressionRetriever(base_compressor=reranker,
                                           base_retriever=retriever)
# 4 Retrieve documents, rerank them and pick top-N, ドキュメントを取得し、リランキングして上位Nを選択する:
retrieved_docs = retriever.invoke(user_query)
# 5 Join all retrieved documents into a single string, 取得したすべてのドキュメントを1つの文字列に結合する:
context = ""
for doc in retrieved_docs:
    context += doc.page_content + "\n\n"
次に、関連するドキュメントが取得されると、ユーザー クエリとともに LLM に渡されます。ここでは、
Llama 3 70B
NIM を使用しています。
from langchain_nvidia_ai_endpoints import ChatNVIDIA
  
PROMPT_FORMAT = """"
Given the following context:
  
####################
{context}
####################
  
Answer the following question:
{question}
  
using the following JSON structure:
  
{json_template}
  
For amounts don't forget to always state if it's in billions or millions and "N/A" if not present.
Only use information and JSON keys that are explicitly mentioned in the transcript.
If you don't have information for any of the keys use "N/A" as a value. 
Answer only with JSON. Every key and value in the JSON should be a string.
"""
  
llm = ChatNVIDIA(model="ai-llama3-70b",
                 max_tokens=600,
                 temperature=0
                )
  
llm_input = PROMPT_FORMAT.format(**{"context": context,
                                    "question": question,
                                    "json_template": json_template
                                   })
answer = llm.invoke(llm_input)
print(answer.content)
このコードを実行すると、ユーザー クエリに対する JSON 構造の回答が生成されます。コードを簡単に変更して、複数のトランスクリプトを読み込んでさまざまなユーザー クエリに回答できるようになりました。
ステップ 5: 評価
検索ステップのパフォーマンスを評価するには、前述の注釈付きの質問と回答のペアを使用して、真実の JSON と予測された JSON をキーごとに比較します。次の真実の例を考えてみましょう。
"Google Cloud": {
    "year_on_year_change": "43%",
    "absolute_revenue": "3 billion",
    "currency": "N/A"
}
予測の出力は次のようになります:
"Google Cloud": { 
    "year_on_year_change": "43%", 
    "absolute_revenue": "N/A", 
    "currency": "USD"
}
考えられる出力の評価結果は 3 つあります。
真陽性 (TP, True Positive)
: 参考の答えと予測が一致しています。前の例では、
year_on_year_change
の予測 (“43%”) は TP です。
偽陽性 (FP, False Positive)
: 参考の答えの値は
"N/A"
です。つまり、抽出する値はありませんが、予測では値が幻覚的に表示されます。前の例では、
currency
の予測 (“USD”) は FP です。
偽陰性 (FN, False Negative)
: 抽出する参考の答えの値がありますが、予測ではその値を取得できませんでした。前の例では、
absolute_revenue
の予測 (“N/A”) は FP です。
これらの結果を測定したら、次に、次の 3 つの主要なメトリックを計算します。
再現率 (Recall)
= TP/ (TP + FN): 再現率が高いほど、モデルが関連する結果をより多く返していることを意味します。
精度 (Precision)
= TP / (TP + FP): 精度が高いほど、モデルが関連する結果と無関係な結果の比率が高くなっていることを意味します。
F1 スコア (F1-score)
= (2 * 適合率 * 再現率) / (適合率 + 再現率): F1 スコアは、適合率と再現率の調和平均です。
ユーザーは、一部の属性について文字列比較を行う際に、数値以外の値のマッチングを部分的に柔軟にしたい場合があります。たとえば、収益源に関する質問を考えてみましょう。ここで、参考の回答の 1 つが複数形の「データ センター」(“Data Centers”) で、モデルが単数形の「データ センター」(“Data Center”)を出力します。完全一致評価では、これは「不一致」として扱われます。このような場合に、より堅牢な評価を実現するには、Python のデフォルトの
difflib
でファジー マッチング (fuzzy matching) を使用します。
import difflib
 
 
def get_ratio_match(gt_string, pred_string):
   if len(gt_string) < len(pred_string):
       min_len = len(gt_string)
   else:
       min_len = len(pred_string)
   matcher = difflib.SequenceMatcher(None, gt_string, pred_string, autojunk=False)
   _, _, longest_match = matcher.find_longest_match(0, min_len, 0, min_len)
   # Return the ratio of match with ground truth
   return longest_match / min_len
評価では、類似度が 90% を超える文字列属性は一致していると見なします。
表 1 は、手動で注釈を付けたデータに対する、最もよく使用される 2 つのオープンソース モデル ファミリ (
Mistral AI Mixtral モデル
と
Meta Llama 3 モデル
) の結果を示しています。どちらのモデル ファミリでも、パラメーターの数を減らすとパフォーマンスが著しく低下します。これらの NIM を体験するには、
NVIDIA API カタログ
にアクセスしてください。
Method
F1
Precision
Recall
Llama 3 70B
84.4%
91.3%
78.5%
Llama 3 8B
75.8%
85.2%
68.2%
Mixtral 8x22B
84.4%
91.9%
78.0%
Mixtral 8x7B
62.2%
80.2%
50.7%
表1. 収益報告電話会議の記録からのJSON構造化情報抽出と質問応答におけるLlamaおよびMixtralモデルのパフォーマンス
Mixtral-8x22B は、Llama 3 70B とほぼ同等のパフォーマンスを持っているようです。ただし、どちらのモデル ファミリでも、パラメーターの数を減らすとパフォーマンスが大幅に低下します。低下は Recall で最も顕著です。これは、ハードウェア要件の増加を犠牲にして精度を向上させることを選択するというトレードオフを頻繁に示しています。
ほとんどの場合、ドメイン固有のデータ (この場合は、収益通話のトランスクリプト) を使用して、Embedder、Reranker、または LLM のいずれかを微調整することで、パラメーターの数を増やすことなくモデルの精度を向上させることができます。
Embedder は最も小さいため、微調整が最も迅速かつコスト効率に優れています。詳細な手順については、
NVIDIA NeMo のドキュメント
を参照してください。さらに、
NVIDIA NeMo
は、LLM の有効なバージョンを微調整する効率を簡素化し、強化します。
ユーザー向け重要な意味合い
このデモは、収益報告の記録から洞察を抽出するように設計されています。NIM などの高度な AI テクノロジを活用することで、収益報告の記録から情報を迅速かつ正確に取得できるようになりました。AI 製品は、文書化とデータ分析の最も集中的なプロセス中に、複数のカテゴリの金融研究者、アナリスト、アドバイザー、ファンダメンタル ポートフォリオ マネージャーを支援し、金融専門家が戦略的な意思決定や顧客対応に多くの時間を費やせるようにします。
たとえば、資産管理セクターでは、ポートフォリオ マネージャーはアシスタントを使用して、膨大な数の収益報告から洞察をすばやく統合し、投資戦略と結果を改善できます。保険業界では、AI アシスタントが企業レポートから財務の健全性とリスク要因を分析し、引受とリスク評価のプロセスを強化できます。ファンダメンタル トレーディングと小売取引では、アシスタントが体系的な情報抽出を支援して市場のトレンドと感情の変化を特定し、将来の取引でより詳細な情報を使用できるようにします。
銀行でも、収益報告を分析することで、潜在的なローン受領者の財務安定性を評価するために使用できます。最終的に、このテクノロジーは効率、精度、データに基づく意思決定能力を高め、ユーザーにそれぞれの市場での競争上の優位性をもたらします。
NVIDIA API カタログ
にアクセスして、利用可能なすべての NIM を確認し、
LangChain の便利な統合
を試して、自分のデータに最適なものを味見してください。
関連情報
GTC セッション:
SQL からチャットへ: NVIDIA でエンタープライズ データ分析を変革する方法
NGC コンテナー:
DiffDock
NGC コンテナー:
NMT Megatron Riva 1b
ウェビナー:
資本市場における次世代分析: 取引実行とリスク管理
ウェビナー:
金融サービス向けの大規模な AI モデル推論の加速