LangChainとNovita AIのLLM APIを使ったディープサーチエージェントワークフローの開発方法

LangChainとNovita AIのLLM APIを使ったディープサーチエージェントワークフローの開発方法

さまざまなAI企業が、リクエストされたトピックについて詳細な調査を実行し、包括的なレポートを作成できるエージェント型AIシステムを導入しています。たとえば、OpenAIのDeep Researchなどです。

OpenAIのDeep Researchのようなエージェント型AIシステムは、マルチステップ検索や統合といった複雑なタスクのための自動化パイプラインを提供します。しかし、既存のソリューションのほとんどはクローズドソースであり、カスタマイズが難しく、モデルの動作やデータ処理に対する制御が制限されます。

たとえば、異なるLLMを使用したり、カスタム検索プロバイダーを統合したり、エージェントの計画や動作を調整して特定の出力を生成したい場合があるでしょう。

そこで興味深い疑問が生まれます。自分の好みのAIモデルを使い、好みの検索エンジンを統合し、エージェントの動作を自由にカスタマイズできる、完全に柔軟なディープサーチエージェントを作成できるでしょうか? 答えは 「はい」 です。

この記事では、Novita AILangChainTavily を使用して、独自のディープリサーチエージェントを構築する方法を学びます。

ディープサーチエージェントワークフローとは?

従来の検索は、オンラインで入手可能な大量の情報をふるいにかける作業が多く、時間がかかることがよくあります。そして最終的には洞察が得られないこともあります。ディープサーチエージェントワークフロー は、自律的に推論し、意思決定を行い、ワークフローの一部として外部ツールを調整できるAIエージェントを通じて、これらの問題を解決します。

このワークフローは通常、次のステップで構成されます。

  1. タスク構造化:AIエージェントがトピックを小さなタスクに分割します。
  2. 計画:エージェントが各タスクに対処するための戦略を作成し、ワークフローがタスク実行の順序を決定するのに役立ちます。
  3. ツール統合:情報を収集するために、エージェントはデータベースやWeb検索エンジンなどのさまざまなツールを使用します。これらのツールがなければ、エージェントはワークフロー内で主要なアクションを実行できません。
  4. 統合:エージェントが収集した情報を分析し、一貫性のあるデータに結合します。
  5. レポート生成:データを統合した後、エージェントは要約や引用を含む構造化されたレポートを作成します。

必要なツール

この記事の構築部分に入る前に、必要なツールを設定しましょう。

Novita AI

エージェントワークフローを構築するにはLLMが必要です。Novita AIは、手頃な価格で高性能なAPIを提供しており、最新のLLMや画像生成モデルなどにアクセスできます。

Novita AIにログイン して始めましょう。ログインしたら、Settings > Key Management に移動し、プロンプトに従ってAPIキーを生成します。

サインアップすると、Novita AIが無料クレジットを提供するので、構築や実験を始める前にクレジットを購入する必要はありません。

Novita AIのログインページ

Tavily

Tavilyは、AIアプリケーション向けに最適化された高度なWeb検索APIです。Tavilyの検索エンジンツールを使用することで、エージェントにインターネットへのアクセスを提供し、正確で偏りのない情報を収集できるようにします。TavilyにアクセスしてAPIキーを生成してください。

Tavilyのホームページ

Langchain

LangChain は、LLMを使用したアプリケーションを構築するために設計されたオープンソースフレームワークです。LangChainを使用すると、ステップバイステップで推論し、ツールを使用し、APIと対話するエージェントワークフローを作成できます。ディープリサーチエージェントでは、LangChainを使用してリサーチプロセスを構造化し、Web検索などのツールを使用し、すべてを構造化レポートに統合します。

langchain

Google Colab

このチュートリアルでは、Google Colab を使用してディープサーチエージェントを構築およびテストします。Colabを使用すると、セットアップ不要でブラウザ上でPythonコードを記述および実行できるため、チュートリアルを簡単に進めることができます。

ワークフローの概要

ディープエージェント検索は、検索タスクの計画から最終的な検索レポートの提供まで、さまざまなワークフローステージの組み合わせです。ワークフローの各ステップを見て、アプリがどのように機能するかを理解しましょう。

deepseekエージェントワークフロー

リサーチ計画

これはワークフローの最初のステップです。ここでエージェントはトピックを分析し、トピックのコンテキストに基づいて構造化されたリサーチ計画を作成します。広範な主題を、歴史、技術的詳細、長所と短所、ユースケースなどのターゲットを絞ったサブトピックに分割します。
これはワークフローの最も重要な部分と考えられます。これがないと、エージェントは一般的な検索を実行し、無関係な結果を返す可能性があるからです。

詳細検索

LLMはトレーニングデータに制限されており、現在のトレンドにアクセスできません。たとえば、検索機能なしのエージェントに現在のサッカーチームの選手をリストアップするよう指示した場合、トレーニングされたデータに基づいた結果を返します。しかし、それらの結果には最新の更新が含まれていないため、事実上正しくない可能性があります。
Tavilyを使用して高度なWeb検索を実行することで、エージェントは最新かつ関連性の高いWebソースにアクセスできるようになります。

ソース管理

エージェントが生成するすべての情報が信頼できるソースにリンクできるようにするために、すべてのソースを追跡することが重要です。ワークフローのこの部分は、最終レポート内の主張やデータを検証したいユーザーとの信頼を構築します。

統合

収集されたすべての情報の関連性を結びつけるために、エージェントは調査されたすべての側面からの洞察をまとめて、一貫性のあるレポートを形成します。ワークフローのこのフェーズがなければ、検索出力はまとまりのないレポートになる可能性があります。

最終フォーマット

レポートが事実に基づいて正確で、十分に調査されていたとしても、フォーマットが不十分だと読みにくくなります。クリーンな構造、一貫した見出し、箇条書き、スペーシングなどを確保するために、追加のステップが必要です。

ディープサーチエージェントの実装

これまでに、ディープサーチエージェントワークフローとは何かについて理解しました。次は、Google Colabで実装する時です。

開始するには、いくつかの主要な手順を実行します。

ステップ1:依存関係のインストール

 -q langchain langchain-openai tavily-python

ステップ2:必要なライブラリのインポート

# 標準Pythonライブラリのインポート
import os   # 環境変数を操作するため
import re   # 正規表現のため
import ast  # 文字列からPython式を安全に解析するため

# LangChainのモデルとツール
from langchain_openai import ChatOpenAI # OpenAIのチャットモデルと対話するためのインターフェース

from langchain_community.utilities.tavily_search import TavilySearchAPIWrapper  # Tavily APIによる検索を有効化

# LangChainのメッセージスキーマ
from langchain.schema import SystemMessage, HumanMessage  # 会話で使用されるメッセージタイプを定義

# LangChainのエージェントコンポーネント
from langchain.agents import Tool, AgentExecutor, create_react_agent  # ツールを使用したエージェントワークフローの構築と実行のため

# LangChainのプロンプトテンプレート
from langchain.prompts import PromptTemplate  # 再利用可能なプロンプトテンプレートの作成を可能にする

# LangChainのメモリ
from langchain.memory import ConversationBufferMemory  # 会話の状態をターン間で維持するのに役立つ

ステップ3:環境変数の設定

# 環境変数の設定と取得
os.environ["NOVITA_API_KEY"] = ""      # 実際のNovita APIキーに置き換えてください
os.environ["TAVILY_API_KEY"] = ""      # 実際のTavily APIキーに置き換えてください

# APIキーを変数にロード
novita_api_key = os.getenv("NOVITA_API_KEY")
tavily_api_key = os.getenv("TAVILY_API_KEY")

ステップ4:LLMヘルパー関数の定義

Novita AIはOpenAIと互換性があるため、LangChainの ChatOpenAI モジュールを使用してNovita AIとLangChainを統合します。つまり、OpenAIモデルと同じ方法でNovitaと通信できます。

ただし、注意すべき重要な点として、base_url をNovitaのAPIエンドポイント https://api.novita.ai/v3/openai に設定する必要があります。

このワークフローでは、命令追従タスク用にファインチューニングされた強力なLLaMA 4バリアントであるモデル llama-4-maverick-17b-128e-instruct-fp8 を使用します。

# LLMヘルパー関数
def llm(api_key,
        model="meta-llama/llama-4-maverick-17b-128e-instruct-fp8",
        temperature=0.7):
    """指定されたパラメータでChatOpenAI LLMインスタンスを作成します。"""    
    return ChatOpenAI(
        model=model,
        openai_api_key=api_key,
        base_url="https://api.novita.ai/v3/openai",
        temperature=temperature,
    )

エージェント型リサーチャーの構築

ディープリサーチワークフロー全体は、AgenticResearcher というモジュール式のクラスにカプセル化されます。このクラスは、リサーチ計画の生成、Web検索の実行、結果の統合、最終レポートのフォーマット、および完全なリサーチループの実行を管理します。

Novita APIを介したLLMへのアクセスと、Tavily APIを介したWeb検索ツールを使用して、リサーチエージェントを初期化します。次に、指定されたクエリに対してTavilyを使用して高度なWeb検索を実行するメソッドを定義します。結果は可読性のためにフォーマットされ、未加工のデータは後で使用するために保存されます。

class AgenticResearcher:
    def __init__(self, novita_api_key, tavily_api_key, num_researchers=3, temperature=0.3):
        """必要なAPIキーとパラメータでリサーチエージェントを初期化します。"""
        self.llm = llm(api_key=novita_api_key, temperature=temperature)
        self.tavily_search = 
TavilySearchAPIWrapper(tavily_api_key=tavily_api_key)
        self.num_researchers = num_researchers
        self.raw_search_results = []
    def search(self, query):
        """指定されたクエリについてWebを検索します。"""
        try:
            results = self.tavily_search.results(
                query, max_results=7,
                search_depth="advanced"
            )
            # 引用処理のために未加工の結果を保存
            self.raw_search_results.extend(results)
            formatted = []
            for r in results:
                formatted += [
                    f"TITLE: {r.get('title','')}",
                    f"URL: {r.get('url','')}",
                    f"CONTENT:\
{r.get('content','')}",
                    "---"
                ]
            return "\
".join(formatted) if formatted else "No results found"
        except Exception as e:
            return f"Search error: {str(e)}"

マルチアスペクトリサーチ計画の作成

引き続き AgenticResearcher クラスの一部として、LLMを使用してトピックを複数の異なる側面に分割し、構造化されたリサーチ計画を生成するメソッドを作成しましょう。各側面にはタイトルと特定の検索クエリが含まれます。目的は、トピックを複数の角度から調査し、深さと広さの両方を確保することです。

def create_research_plan(self, topic):
"""調査する複数の側面を持つ構造化されたリサーチ計画を作成します。"""
sys = "You are a planner that outputs Python lists of dicts."
hum = f"""

Create a comprehensive research plan for: {topic}
Identify {self.num_researchers} distinct aspects to investigate thoroughly.
Analyze the topic and determine the most relevant aspects to research based on its nature and domain.
Output exactly:
ASPECT {{'title': '...', 'search_query': '...'}}
"""
try:
resp = self.llm.invoke([SystemMessage(content=sys), HumanMessage(content=hum)])
aspects = []
for line in resp.content.splitlines():
if line.strip().startswith("ASPECT"):
m = re.search(r"\{.*\}", line)
if m:
try:
aspects.append(ast.literal_eval(m.group(0)))
except Exception as e:
print(f"Error parsing aspect: {e}")
if not aspects:
# さまざまなドメインで機能する汎用的なデフォルトの側面
default_aspects = [
{"title": "Overview and Key Information", "search_query": f"{topic} overview key facts"},
{"title": "Background and Context", "search_query": f"{topic} background history context"},
{"title": "Details and Specifications", "search_query": f"{topic} details specifics data"},
{"title": "Analysis and Significance", "search_query": f"{topic} analysis importance implications"}
]
aspects = default_aspects[:self.num_researchers]
return aspects
except Exception as e:
print(f"Error creating research plan: {e}")
return [{"title": f"{topic} research", "search_query": topic}]

ソース管理と引用

次に、ワークフローが信頼できるレポートを生成する方法を処理する必要があります。未加工の検索結果から一意のソースを抽出し、各ソースが引用されるようにするメソッドを作成します。

def extract_sources(self):
"""引用のために未加工の検索結果から一意のソースを抽出します。"""
unique_sources = {}
for result in self.raw_search_results:
url = result.get('url', '')
if url and 'http' in url:
domain = url.split('/')[2] if len(url.split('/')) > 2 else url
if domain not in unique_sources:
unique_sources[domain] = url
return unique_sources

レポート統合

複数のソースから未加工の情報を収集したので、次のステップはその乱雑な入力を詳細なリサーチレポートに変換することです。未加工のテキストを、見出し、小見出し、主要な発見、ソース引用を含む読みやすい整理されたレポートに統合するメソッドを記述します。

def synthesize(self, text):
"""未加工のテキストを詳細で構造化された発見事項と引用に統合します。"""
sources = self.extract_sources()
sources_list = list(sources.keys())
sys = """You are an expert research synthesizer that creates detailed, structured reports.
For each claim or fact you include, add a citation to the source domain.
Use the exact domain names provided without modification.
Adapt your report structure to the topic's domain and nature."""
hum = f"""
INFORMATION TO SYNTHESIZE:
{text}
AVAILABLE SOURCE DOMAINS (use these exact names for citations):
{sources_list}
Create a comprehensive, detailed research report with:
1. Main findings with specific facts and figures
2. Structured information with clear headings and subheadings appropriate to the topic
3. Citations using the exact source domain names in square brackets [like.this]
4. Relevant data presented clearly and professionally
5. Format adapted to the specific nature of the topic (technical, historical, news event, etc.)
FORMAT THE REPORT PROFESSIONALLY AND THOROUGHLY WITHOUT ASSUMING ANY SPECIFIC DOMAIN.
"""
try:
return self.llm.invoke([SystemMessage(content=sys), HumanMessage(content=hum)]).content
except Exception as e:
return f"Synthesis error: {str(e)}"

エージェント用ツールの作成

ディープサーチエージェントワークフローを機能させるには、ツールを定義する必要があります。ツールはエージェントに特定のアクションを実行する能力を与えます。

このワークフローに必要なコアツールは、エージェントがトピックを分解して構造化されたリサーチ計画を作成するのに役立つ “plan”、エージェントが詳細なWeb検索を実行できるようにする “search”、そしてエージェントが未加工の発見事項をすべて整理されたレポートに変換できるようにする “synthesize” です。

def get_tools(self):
"""エージェントが使用できるツールのリストを作成して返します。"""
return [
Tool(
name="plan",
func=lambda t: str(self.create_research_plan(t)),
description="Create a detailed research plan with multiple aspects to investigate."
),
Tool(
name="search",
func=self.search,
description="Search the web thoroughly for a query and return comprehensive results."
),
Tool(
name="synthesize",
func=self.synthesize,
description="Transform raw text into detailed, structured findings with citations."
),
]

エージェントエグゼキュータの構築

ツールの準備ができたので、ReActスタイルのプロンプトを使用してすべてをAIエージェントに統合する必要があります。これにより、エージェントは計画を立て、定義されたツールを使用してアクションを実行し、結果を観察し、最終的なリサーチレポートを生成するのに十分なデータが得られるまでループを繰り返すことができます。

def get_agent_executor(self):
"""ツールとメモリを使用してエージェントエグゼキュータを作成して返します。"""
tools = self.get_tools()
template = """You are an autonomous research agent specialized in producing comprehensive, detailed reports on any topic.
{tool_names}
TOOLS:
{tools}
PREVIOUS CONVERSATIONS:
{chat_history}
When given a research topic (as {input}), follow this process:
1. Analyze the type of topic and create a research plan tailored to its domain
2. Search for comprehensive information on each aspect of the topic
3. Collect detailed, relevant information with sources
4. Synthesize everything into a professional, detailed report formatted appropriately for the topic
Follow exactly this format:
Question: {input}
Thought: (your reasoning here)
Action: the name of the tool to call, must be one of [{tool_names}]
Action Input: the input to the tool
Observation: (the tool's output)
... (repeat Thought/Action/Action Input/Observation as needed)
When you have gathered comprehensive information, output:
Final Answer: (your final, detailed research report with structured sections, appropriate formatting, specific details, and citations)
BEGIN WITH A THOROUGH PLAN!
{agent_scratchpad}
"""
prompt = PromptTemplate(
template=template,
input_variables=["input", "agent_scratchpad", "tools", "tool_names", "chat_history"]
)
# 低レベルエージェントを作成
agent = create_react_agent(
llm=self.llm,
tools=tools,
prompt=prompt
)
# メモリ付きのエグゼキュータでラップ
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
verbose=True,
memory=memory,
max_iterations=18,
early_stopping_method="generate",
handle_parsing_errors=True
)
return agent_executor

最終レポートのフォーマット

リサーチエージェントがディープサーチを完了した後、出力は情報豊富かもしれませんが、見栄えが良くない場合があります。この追加ステップは、最終レポートをより洗練されたものにするのに役立ちます。これを実現するために、LLMに専門の編集者として作業を依頼し、最終レポートを改善します。

def format_final_report(self, raw_report):
"""レポートに最終的なフォーマットを追加して、よりプロフェッショナルにします。"""
sys = """You are an expert editor that improves research reports.
Keep all the factual content, citations, and structure intact.
Just improve the formatting, organization, and readability."""
hum = f"""
Here is a research report that needs final formatting improvements:
{raw_report}
Please improve the formatting and presentation while preserving all:
1. Facts and figures
2. Citations
3. Content organization
4. Statistical data
Make it look professional with proper headings, spacing, and layout.
"""
try:
improved = self.llm.invoke([SystemMessage(content=sys), HumanMessage(content=hum)]).content
return improved
except Exception as e:
# フォーマットに失敗した場合、元のレポートを返す
return raw_report

すべてを統合する

ワークフロー全体を、リサーチフロー全体を調整する単一のパイプラインにまとめましょう。これは、エージェントが完全なリサーチプロセスを実行し、最終レポートをフォーマットできるようにするエントリポイントとして機能します。

def run(self, topic):
"""指定されたトピックに対してリサーチプロセスを実行します。"""
try:
# 保存された検索結果をリセット
self.raw_search_results = []
# エージェントを実行
executor = self.get_agent_executor()
raw_report = executor.invoke({"input": topic})["output"]
# 最終レポートをフォーマット
final_report = self.format_final_report(raw_report)
return final_report
except Exception as e:
return f"Research failed: {str(e)}"

リサーチエージェントの実行

ディープサーチエージェントワークフローが構築されたので、実際のリサーチタスクでどれだけうまく機能するかをテストしてみましょう。

リサーチエージェントのインスタンスを作成し、現在のトピックに関する詳細なレポートを生成するよう指示します。

# リサーチャーオブジェクトを作成
researcher = AgenticResearcher(novita_api_key, tavily_api_key, num_researchers=3)

# テストリサーチを実行
topic = "What are the most promising climate tech startups in 2025?"
report = researcher.run(topic)

# リサーチレポートを表示
print("\
" + "="*60)
print(f"📝 DETAILED RESEARCH REPORT: {topic}")
print("="*60)
print(report)
print("="*60 + "\
")

結果:

ディープエージェントワークフローはトピックを分解してリサーチ計画を作成し、インターネット検索を実行して関連情報を取得し、収集したデータを統合し、最後に検索クエリに基づいた構造化されたレポートを返しました。

結論

独自のディープサーチエージェントワークフローを構築できました! これで、あらゆるトピックをリサーチし、クエリに関する詳細なレポートを取得できます。

達成したことを簡単に振り返りましょう。

この記事では、複雑なトピックを分解し、リサーチ計画を生成し、インターネット検索を実行し、すべての発見事項を構造化されたレポートに統合できるディープサーチエージェントを構築する方法を学びました。

このワークフロー全体は、以下のものによって支えられていました。

  • LLMプロバイダーとしてのNovita AI
  • エージェントフレームワークとしてのLangChain
  • リアルタイム検索エンジンとしてのTavily

さまざまなトピックでエージェントを試して、その能力をテストしてみてください!

これは、今日の強力なモデルで実現可能な、数多くのエキサイティングなAIアプリケーションの1つにすぎません。Novita LLM Playground にアクセスして、他の最高の最新AIモデルを試してみてください。あなたの次の素晴らしいAIアイデアが、そこから始まるかもしれません。

Colabでコードを確認する

Novita AI は、開発者がシンプルなAPIを使用してAIモデルを簡単にデプロイできるようにするとともに、アプリケーションの構築とスケーリングのための手頃な価格で信頼性の高いGPUクラウドを提供するAIクラウドプラットフォームです。