セキュリティに関する最新トレンド情報を取得するlanggraphの取り組み

# はじめに
LangGraphを使って、セキュリティに関する最新トレンド情報を取得するエージェントを作成してみます。

# tavilyとは？
「Tavily」は、AIエージェント向けに特化して設計された検索エンジンです。このプラットフォームは、AIの性能を向上させ、リアルタイムで正確かつ信頼性の高い情報を迅速に提供します。「Search API」を活用することで、AIエージェントがリアルタイムで信頼性のある知識を取得でき、ハルシネーションや偏りを抑制し、より適切な意思決定を支援します。

### 実際にtavilyを使ってみよう
Tavilyに「2024年において、セキュリティ業界で流行しているトレンドは？」を聞くと、下記のようなレスポンスが返ってきます。
1000リクエストまで無料で使えます。
https://app.tavily.com/chat
![スクリーンショット 2024-12-12 7.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958389/c1848dff-1379-edc2-540c-91f679c56c6e.png)


# LangGraph
パッケージのバージョンは下記を使用します。
```py
langgraph==0.2.57
langchain-openai==0.2.12
langsmith==0.2.1
langchain-anthropic==0.3.0
langchain-community==0.3.11
```
必要な環境変数は以下です。
OPENAI_API_KEYは、OPENAIで、
それ以外は、下記の環境でログインすると取得できるかと思います。
https://smith.langchain.com/
```py
# .env
OPENAI_API_KEY=<OPENAI_API_KEY>
LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=<LANGCHAIN_API_KEY>
LANGCHAIN_PROJECT=test-20241211
TAVILY_API_KEY=<TAVILY_API_KEY>
```
以下、コードの全体像です。

```py
from dotenv import load_dotenv
from IPython.display import Image, display
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import create_react_agent
from pydantic import BaseModel, Field
from typing import List
from typing_extensions import TypedDict

load_dotenv("../docker/.env")

# トレンド情報からキーワードを抽出するLLMをこの形式で出力させる
class TrendKeywords(BaseModel):
    trend_keywords: List[str] = Field(
        description="流行における重要キーワード",
    )

# 抽出されたキーワードを下に広告文生成するLLMをこの形式で出力させる
class SecurityInfo(BaseModel):
    news_title  : str       = Field(description="ニュースのタイトル名")
    genre       : str       = Field(desciption="ニュースのジャンル")
    news_keyword: List[str] = Field(description="ニュース内のキーワード")

openai_model_version = "gpt-4o-mini"
llm                  = ChatOpenAI(model=openai_model_version)

# max_results: 何件分の検索結果を保持するか
tools = [TavilySearchResults(max_results=5)]

agent_executor = create_react_agent(llm, tools)

extract_prompt = ChatPromptTemplate.from_messages(
    [
        ("user", "以下で与えられるセキュリティ情報から重要なキーワードを5つ抽出してください。\n\n##トレンド情報\n{trend_text}"),
    ]
)
extract_trends  = llm.with_structured_output(TrendKeywords)
trend_extractor = extract_prompt | extract_trends
examples = [
    {"example": "news_title: 'オリオンホテル那覇が利用する宿泊施設予約管理システムに不正アクセス'  , genre: '不正アクセス', news_keyword: ['オリオンホテル那覇', '宿泊施設予約管理システム']"},
    {"example": "news_title: 'RIZAPの顧客情報含む一部ファイルが第三者に閲覧可能な状態に'           , genre: '不具合'      , news_keyword: ['RIZAP']"},
    {"example": "news_title: 'LINEアプリのアルバム機能に不具合、他のユーザーの画像のサムネイル表示', genre: '不具合'      , news_keyword: ['LINE', 'アルバム機能']"},
]
OPENAI_TEMPLATE = PromptTemplate(input_variables=["example"], template="{example}")

fewshot_template = FewShotPromptTemplate(
    prefix          = "以下はセキュリティニュースに関するサンプルデータです。",
    examples        = examples,
    suffix          = "これらの例を参考にセキュリティニュースを10文作成してください。ただし、作成するセキュリティニュースのジャンルは{genre}とし、以下に提示する2024年のトレンド情報を加味してください。\n\n##トレンド情報\n{trend_keywords}",
    input_variables = ["genre", "trend_keywords"],
    example_prompt  = OPENAI_TEMPLATE,
)

generate_title = llm.with_structured_output(SecurityInfo)
ads_generator  = fewshot_template | generate_title

class State(TypedDict):
    input         : str       # ユーザが入力する最初のクエリーを管理
    trend_text    : str       # 検索されたトレンド情報をLLMがまとめた結果を格納
    news_title    : str       # 生成される架空のニュースタイトル
    genre         : str       # 生成させたい広告のジャンル
    trend_keywords: List[str] # trend_textを下にLLMが抽出したキーワードを格納
    news_keyword  : List[str] # 生成されたニュース内のキーワード文を格納

def search_trend(state: State):
    response            = agent_executor.invoke({"messages": [("user", state["input"])]})
    state["trend_text"] = response["messages"][-1].content
    return state

def extract_keywords(state: State):
    response                = trend_extractor.invoke(state)
    state["trend_keywords"] = response.trend_keywords
    return state

def generate_title(state: State):
    response              = ads_generator.invoke(state)
    state["news_title"]   = response.news_title
    state["news_keyword"] = response.news_keyword
    return state

workflow = StateGraph(State)

workflow.add_node("search_trend"    , search_trend)
workflow.add_node("extract_keywords", extract_keywords)
workflow.add_node("generate_title"  , generate_title)

workflow.add_edge(START             , "search_trend")
workflow.add_edge("search_trend"    , "extract_keywords")
workflow.add_edge("extract_keywords", "generate_title")
workflow.add_edge("generate_title"  , END)

app = workflow.compile()

```
下記のようなグラフになります。
![スクリーンショット 2024-12-12 7.32.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958389/f6cfeb48-0584-b54f-8d6b-674992da2aca.png)

```py
display(Image(app.get_graph(xray=True).draw_mermaid_png()))

initial_state          = State()
initial_state["input"] = "2024年において、セキュリティ業界で流行しているトレンドは？"
initial_state["genre"] = "脆弱性"
for event in app.stream(initial_state):
    for k, v in event.items():
        if k != "__end__":
            print(v)
```

LangSmith上で閲覧すると、下記のようになります。　
エージェントの実行の流れやinput, output、さらにトークンの使用量や料金まで確認することが可能です。
![スクリーンショット 2024-12-12 7.36.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958389/bfb3943d-d592-dad6-2af4-1825085fb68f.png)

実際に取得したセキュリティトレンドをとると、下記のようになっていました。
```py
input: 2024年において、セキュリティ業界で流行しているトレンドは？
trend_text: |-
  2024年のセキュリティ業界では、以下のトレンドが注目されています。

  1. **AIと機械学習の進化**:
     - AIはサイバー攻撃の検出と防御に革命をもたらしています。特に、異常検知システムや脅威インテリジェンスの向上に寄与し、リアルタイムでの脅威の識別が可能になっています。攻撃者もAIを利用して巧妙な手法を駆使するため、対策が急務です。

  2. **ゼロトラスト戦略の採用**:
     - 従来の境界ベースのセキュリティモデルから脱却し、ネットワーク内外のアクセスを厳密に管理するゼロトラスト戦略が重要視されています。このアプローチは、リモートワークやクラウドサービスの普及に伴い、特に重要です。

  3. **サプライチェーン攻撃の増加**:
     - サプライチェーンを狙った攻撃が増加しており、企業はパートナーやベンダーのセキュリティ状況を把握し、適切な対策を講じる必要があります。特にオープンソースプロジェクトに対する攻撃が目立っています。

  4. **ランサムウェアの進化**:
     - ランサムウェア攻撃は依然として高い脅威であり、攻撃手法が多様化しています。組織はデータのバックアップや多要素認証（MFA）の導入を強化する必要があります。

  5. **第三者リスク管理（TPRM）の重要性**:
     - 外部ベンダーやパートナーとの関係から生じるリスクを管理するTPRMが重要視されています。企業は、ベンダーのセキュリティ評価や契約時のセキュリティ要件を明確にし、継続的な監視を行う必要があります。

  これらのトレンドに対する具体的な対策としては、脆弱性管理の強化、従業員教育の充実、インシデント対応計画の策定などが挙げられます。企業はこれらのトレンドを意識し、セキュリティ戦略を見直す必要があります。

  詳しい情報については、以下のリンクも参照してください：
  - [AIの台頭と進化する脅威の最前線](https://blog.cbsec.jp/entry/2024/11/25/060000)
  - [ゼロトラストからTPRMまでのサイバーセキュリティトレンド](https://reinforz.co.jp/bizmedia/49429/)
news_title: AIを利用した新たなランサムウェアが発覚、企業のデータを脅かす
genre: 脆弱性
trend_keywords:
  - AI
  - ゼロトラスト
  - サプライチェーン攻撃
  - ランサムウェア
  - 第三者リスク管理
```
今のセキュリティトレンドは、
- AI
- ゼロトラスト
- サプライチェーン攻撃
- ランサムウェア
- 第三者リスク管理
のようです。

# 最後に
今回はセキュリティに関するトレンド情報を取得してみました。tavilyを使うことで簡単にlangchainと連携して、LLMを使用することができます。