Dify x AIエージェントで不動産エリア分析

# 1. はじめに：
こんにちは、技術愛好家の皆さん！年末が近づく中、新しい技術の組み合わせで何か面白いことができないかと考えていませんか？  
今回は、不動産情報ライブラリAPIと生成AIプラットフォームを組み合わせた興味深い技術検証についてお話しします。

不動産情報ライブラリは、実に多様なデータの宝庫です。位置情報、物件詳細、周辺環境など、様々な情報が含まれています。これらの情報をAIで分析することで、どのような新しい洞察が得られるでしょうか？

本ブログでは、不動産情報ライブラリAPIとDifyというAIプラットフォームを組み合わせて、エリア分析を行うAIエージェントを作成する方法を紹介します。このプロジェクトは、APIとAIの統合による新しい可能性を探る試みです。

具体的には、以下のような技術的チャレンジに取り組みます：

1. 不動産情報ライブラリAPIを活用した効率的な情報取得方法
2. Difyを使用したノーコードでのAIエージェント構築プロセス
3. APIから取得した情報をAIモデルで処理し、有用な洞察を得る手法

# 2. 不動産情報ライブラリAPIとDifyの概要
## 2.1 不動産情報ライブラリAPIの特徴
不動産情報ライブラリAPIは、豊富な不動産関連データへのアクセスを国土交通省が提供する強力なツールです。  
このAPIの主な特徴は以下の通りです：

- 不動産価格情報：取引価格・成約価格データ
- 地理情報：都道府県内市区町村一覧、都市計画区域、用途地域など
- 教育施設情報：小学校区、中学校区、学校、保育園・幼稚園等
- 医療・福祉情報：医療機関、福祉施設
- 人口統計：将来推計人口（500mメッシュ）
- 交通情報：駅別乗降客数
- 防災情報：災害危険区域、大規模盛土造成地、地すべり防止地区など
- 公共施設：図書館、市区町村役場、集会施設等
- 自然環境：自然公園地域
- 都市計画：地区計画、高度利用地区など

不動産情報ライブラリAPIを活用することで、豊富な不動産データにアクセスし、それを基にした高度な分析や多様なアプリケーション開発が可能になります。  
次のセクションでは、このAPIのデータを活用するためのツールであるDifyについて見ていきます。

## 2.2 Difyの特徴
Difyは、AI応用プログラムの開発を支援するオープンソースのプラットフォームです。  
特にLLM（大規模言語モデル）を活用したアプリケーションの構築に焦点を当てています。

### Difyの主な特徴
Difyは、ノーコードインターフェース、多様なAIモデルとの連携、プロンプトエンジニアリングのサポート、カスタマイズ可能なデータセット、APIエンドポイントの自動生成などの機能を提供します。

Difyを活用することで、不動産情報ライブラリAPIから取得したデータを効果的に処理し、ユーザーフレンドリーなAIアシスタントを構築することができます。  

次のセクションでは、これらのツールを組み合わせて具体的にどのようなエージェントを設計できるか、考えていきましょう。


# 3. AIエージェントの設計：何ができる子にする？
## 3.1 ユーザーのニーズを考える
不動産情報ライブラリAPIとDifyを組み合わせたAIエージェントを設計する際、まずユーザーのニーズを深く理解することが重要です。  
既存の不動産サービスでは得られない、より深い洞察や専門的な分析を提供することに焦点を当てます。

一般的な物件検索はSUUMOなどの既存サービスで十分にカバーされています。そのため、AIエージェントは、これらのサービスでは得られない、周辺エリアの洞察や専門的な分析を提供することに焦点を当てます。

### ユーザーの主な課題とニーズ
1. エリア分析: 特定のエリアの不動産取引の特徴を深く理解したい。
2. 立地評価: 過去の取引データに基づいて、エリアの立地条件を客観的に評価したい。
3. 価格動向の把握: エリアや物件タイプごとの過去の価格動向を理解したい。

### AIエージェントに求められる実現可能な機能
1. 詳細なエリア取引プロファイリング: 選択されたエリアの過去の取引情報を分析し、地域の特徴を説明。
2. 立地特性の分析: 主要施設へのアクセスを考慮し、立地の特徴を説明。
3. 類似取引エリア推奨: 指定されたエリアと類似した特徴を持つ他のエリアを提案。
4. 過去の価格トレンド分析: エリアや物件タイプごとの価格トレンドを分析・説明。
5. 物件タイプ別エリア特性分析: 特定の物件タイプの過去の取引傾向をエリアごとに分析。
6. カスタマイズ可能な取引分析レポート生成: ユーザーの関心事項に基づいたレポートを自動生成。
7. 主要施設アクセス分析: エリア内の主要施設への距離や数を分析し、生活利便性を説明。

AIエージェントは、不動産情報ライブラリAPIから得られるデータを活用し、ユーザーに価値ある分析と洞察を提供し、より良い住居選択の意思決定をサポートします。全ての情報と分析結果は、テキストベースのレポートで提供します。

## 3.2 エージェントの機能を決める

今回の検証では、ユーザーのニーズと不動産情報ライブラリAPIから実際に取得可能な情報を考慮し、AIエージェントが提供する具体的な機能を2つピックアップしました。この機能について実際に実装していきます。

1. 将来の人口動態分析

- 指定されたエリアの将来の人口推移予測を分析します。
- 年齢層別の人口構成の変化を予測し、その影響を解説します。
- 世帯数の変化傾向を分析し、地域の発展性や需要の変化を推測します。

2. 駅別乗降者数トレンド分析

- 特定の駅や路線の乗降者数の推移を分析します。
- 乗降者数の変化から、エリアの発展性や人気度の変化を考察します。

これらの機能を通じて、AIエージェントは利用可能なデータに基づいた深い分析と洞察を提供します。ユーザーは、これらの情報を基に、より長期的な視点で住居選択や不動産に関する意思決定を行うことができます。

次のセクションでは、これらの機能をどのように実装していくか、具体的な方法を探っていきましょう。


# 4. 不動産情報ライブラリAPIとDifyの統合
## 4.1 OpenAPIフォーマットでの不動産情報ライブラリAPIの定義

Difyのカスタムツールは、外部APIやサービスをDifyに組み込み、AIエージェントが特定のタスクを実行したり外部データにアクセスしたりするための機能です。  
Difyのカスタムツールを活用するためには、不動産情報ライブラリAPIをOpenAPIの仕様で定義する必要があります。  

以下に、主要なエンドポイントを例にとってOpenAPI定義の作成方法を説明します。

1. OpenAPI仕様の基本構造
まず、OpenAPI 3.0の基本構造を設定します：
    ```
    openapi: 3.0.0
    info:
      title: 不動産情報ライブラリAPI
      version: 1.0.0
      description: |
      # 不動産情報ライブラリAPI

      このAPIは、不動産取引価格情報や地価公示・地価調査、国土数値情報等のデータを提供します。

      servers:
        - url: https://www.reinfolib.mlit.go.jp/ex-api/external
    ```

2. APIの定義
主要なエンドポイントを定義します。  
例として、人口統計データと過去の売買情報のエンドポイントを示します：
    ```
    paths:
      /XKT013:
        get:
          summary: 国土数値情報（将来推計人口500mメッシュ）API
          description: 指定された地理的範囲内の将来推計人口（500mメッシュ）情報を取得します。
          tags:
            - 国土数値情報
          parameters:
            - name: response_format
              in: query
              required: true
              schema:
                type: string
                enum: [geojson, pbf]
              description: |
                応答形式
                geojson…GeoJSON応答
                pbf…バイナリベクトルタイル応答
            - name: z
              in: query
              required: true
              schema:
                type: integer
                minimum: 11
                maximum: 15
              description: |
                ズームレベル（縮尺）
                11（市）～15（詳細）で指定可能
            - name: x
              in: query
              required: true
              schema:
                type: integer
              description: XYZ方式におけるタイル座標のX値
            - name: y
              in: query
              required: true
              schema:
                type: integer
              description: XYZ方式におけるタイル座標のY値
          responses:
            '200':
              description: 成功
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      type:
                        type: string
                        description: GeoJSONのタイプ（"FeatureCollection"）
                      features:
                        type: array
                        items:
                          type: object
                          properties:
                            type:
                              type: string
                              description: GeoJSONのタイプ（"Feature"）
                            geometry:
                              type: object
                              description: 500mメッシュの境界を表すポリゴン
                              properties:
                                type:
                                  type: string
                                  enum: ["Polygon"]
                                coordinates:
                                  type: array
                                  items:
                                    type: array
                                    items:
                                      type: array
                                      items:
                                        type: number
                                      minItems: 2
                            properties:
                              type: object
                              properties:
                                MESH_ID:
                                  type: string
                                  description: 分割地域メッシュコード
                                SHICODE:
                                  type: string
                                  description: 行政区域コード
                                PTN_20XX:
                                  type: integer
                                  description: 20XX年男女計総数人口（秘匿なし）
                                HITOKU_20XX:
                                  type: string
                                  description: 20XX年秘匿記号
                                GASSAN_20XX:
                                  type: string
                                  description: 20XX年合算先メッシュ
                                PT0_20XX:
                                  type: integer
                                  description: 20XX年男女計総数人口
                                PT1_20XX:
                                  type: integer
                                  description: 20XX年男女計0～4歳人口
                                PT2_20XX:
                                  type: integer
                                  description: 20XX年男女計5～9歳人口
                                PT3_20XX:
                                  type: integer
                                  description: 20XX年男女計10～14歳人口
                                PT4_20XX:
                                  type: integer
                                  description: 20XX年男女計15～19歳人口
                                PT5_20XX:
                                  type: integer
                                  description: 20XX年男女計20～24歳人口
                                PT6_20XX:
                                  type: integer
                                  description: 20XX年男女計25～29歳人口
                                PT7_20XX:
                                  type: integer
                                  description: 20XX年男女計30～34歳人口
                                PT8_20XX:
                                  type: integer
                                  description: 20XX年男女計35～39歳人口
                                PT9_20XX:
                                  type: integer
                                  description: 20XX年男女計40～44歳人口
                                PT10_20XX:
                                  type: integer
                                  description: 20XX年男女計45～49歳人口
                                PT11_20XX:
                                  type: integer
                                  description: 20XX年男女計50～54歳人口
                                PT12_20XX:
                                  type: integer
                                  description: 20XX年男女計55～59歳人口
                                PT13_20XX:
                                  type: integer
                                  description: 20XX年男女計60～64歳人口
                                PT14_20XX:
                                  type: integer
                                  description: 20XX年男女計65～69歳人口
                                PT15_20XX:
                                  type: integer
                                  description: 20XX年男女計70～74歳人口
                                PT16_20XX:
                                  type: integer
                                  description: 20XX年男女計75～79歳人口
                                PT17_20XX:
                                  type: integer
                                  description: 20XX年男女計80～84歳人口
                                PT18_20XX:
                                  type: integer
                                  description: 20XX年男女計85～89歳人口
                                PT19_20XX:
                                  type: integer
                                  description: 20XX年男女計90歳以上人口
                                PTA_20XX:
                                  type: integer
                                  description: 20XX年男女計0～14歳人口
                                PTB_20XX:
                                  type: integer
                                  description: 20XX年男女計15～64歳人口
                                PTC_20XX:
                                  type: integer
                                  description: 20XX年男女計65歳以上人口
                                PTD_20XX:
                                  type: integer
                                  description: 20XX年男女計75歳以上人口
                                PTE_20XX:
                                  type: integer
                                  description: 20XX年男女計80歳以上人口
                                RTA_20XX:
                                  type: number
                                  format: float
                                  description: 20XX年男女計0～14歳人口比率
                                RTB_20XX:
                                  type: number
                                  format: float
                                  description: 20XX年男女計15～64歳人口比率
                                RTC_20XX:
                                  type: number
                                  format: float
                                  description: 20XX年男女計65歳以上人口比率
                                RTD_20XX:
                                  type: number
                                  format: float
                                  description: 20XX年男女計75歳以上人口比率
                                RTE_20XX:
                                  type: number
                                  format: float
                                  description: 20XX年男女計80歳以上人口比率
                application/x-protobuf:
                  schema:
                    type: string
                    format: binary
            '400':
              description: リクエストパラメータが不正
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
            '401':
              description: 認証エラー
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
            '404':
              description: リソースが見つかりません
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
            '429':
              description: リクエスト回数制限超過
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
          security:
            - ApiKeyAuth: []

      /XKT015:
        get:
          summary: 国土数値情報（駅別乗降客数）API
          description: 指定された地理的範囲内の駅別乗降客数情報を取得します。
          tags:
            - 国土数値情報
          parameters:
            - name: response_format
              in: query
              required: true
              schema:
                type: string
                enum: [geojson, pbf]
              description: |
                応答形式
                geojson…GeoJSON応答
                pbf…バイナリベクトルタイル応答
            - name: z
              in: query
              required: true
              schema:
                type: integer
                minimum: 11
                maximum: 15
              description: |
                ズームレベル（縮尺）
                11（市）～15（詳細）で指定可能
            - name: x
              in: query
              required: true
              schema:
                type: integer
              description: XYZ方式におけるタイル座標のX値
            - name: y
              in: query
              required: true
              schema:
                type: integer
              description: XYZ方式におけるタイル座標のY値
          responses:
            '200':
              description: 成功
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      type:
                        type: string
                        description: GeoJSONのタイプ（"FeatureCollection"）
                      features:
                        type: array
                        items:
                          type: object
                          properties:
                            type:
                              type: string
                              description: GeoJSONのタイプ（"Feature"）
                            geometry:
                              type: object
                              properties:
                                type:
                                  type: string
                                  description: ジオメトリタイプ（"Point"）
                                coordinates:
                                  type: array
                                  items:
                                    type: number
                                  description: 経度、緯度の順で表される座標
                            properties:
                              type: object
                              properties:
                                S12_001_ja:
                                  type: string
                                  description: 駅名
                                S12_001c:
                                  type: string
                                  description: 駅コード
                                S12_001g:
                                  type: string
                                  description: グループコード
                                S12_002_ja:
                                  type: string
                                  description: 運営会社
                                S12_003_ja:
                                  type: string
                                  description: 路線名
                                S12_004:
                                  type: string
                                  description: 鉄道区分
                                S12_005:
                                  type: string
                                  description: 事業者種別
                                S12_006:
                                  type: string
                                  description: 重複コード2011
                                S12_007:
                                  type: string
                                  description: データ有無コード2011
                                S12_008:
                                  type: string
                                  description: 備考2011
                                S12_009:
                                  type: integer
                                  description: 乗降客数2011
                                S12_010:
                                  type: string
                                  description: 重複コード2012
                                S12_011:
                                  type: string
                                  description: データ有無コード2012
                                S12_012:
                                  type: string
                                  description: 備考2012
                                S12_013:
                                  type: integer
                                  description: 乗降客数2012
                                S12_014:
                                  type: string
                                  description: 重複コード2013
                                S12_015:
                                  type: string
                                  description: データ有無コード2013
                                S12_016:
                                  type: string
                                  description: 備考2013
                                S12_017:
                                  type: integer
                                  description: 乗降客数2013
                                S12_018:
                                  type: string
                                  description: 重複コード2014
                                S12_019:
                                  type: string
                                  description: データ有無コード2014
                                S12_020:
                                  type: string
                                  description: 備考2014
                                S12_021:
                                  type: integer
                                  description: 乗降客数2014
                                S12_022:
                                  type: string
                                  description: 重複コード2015
                                S12_023:
                                  type: string
                                  description: データ有無コード2015
                                S12_024:
                                  type: string
                                  description: 備考2015
                                S12_025:
                                  type: integer
                                  description: 乗降客数2015
                                S12_026:
                                  type: string
                                  description: 重複コード2016
                                S12_027:
                                  type: string
                                  description: データ有無コード2016
                                S12_028:
                                  type: string
                                  description: 備考2016
                                S12_029:
                                  type: integer
                                  description: 乗降客数2016
                                S12_030:
                                  type: string
                                  description: 重複コード2017
                                S12_031:
                                  type: string
                                  description: データ有無コード2017
                                S12_032:
                                  type: string
                                  description: 備考2017
                                S12_033:
                                  type: integer
                                  description: 乗降客数2017
                                S12_034:
                                  type: string
                                  description: 重複コード2018
                                S12_035:
                                  type: string
                                  description: データ有無コード2018
                                S12_036:
                                  type: string
                                  description: 備考2018
                                S12_037:
                                  type: integer
                                  description: 乗降客数2018
                                S12_038:
                                  type: string
                                  description: 重複コード2019
                                S12_039:
                                  type: string
                                  description: データ有無コード2019
                                S12_040:
                                  type: string
                                  description: 備考2019
                                S12_041:
                                  type: integer
                                  description: 乗降客数2019
                                S12_042:
                                  type: string
                                  description: 重複コード2020
                                S12_043:
                                  type: string
                                  description: データ有無コード2020
                                S12_044:
                                  type: string
                                  description: 備考2020
                                S12_045:
                                  type: integer
                                  description: 乗降客数2020
                                S12_046:
                                  type: string
                                  description: 重複コード2021
                                S12_047:
                                  type: string
                                  description: データ有無コード2021
                                S12_048:
                                  type: string
                                  description: 備考2021
                                S12_049:
                                  type: integer
                                  description: 乗降客数2021
                                S12_050:
                                  type: string
                                  description: 重複コード2022
                                S12_051:
                                  type: string
                                  description: データ有無コード2022
                                S12_052:
                                  type: string
                                  description: 備考2022
                                S12_053:
                                  type: integer
                                  description: 乗降客数2022
                application/x-protobuf:
                  schema:
                    type: string
                    format: binary
            '400':
              description: リクエストパラメータが不正
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
            '401':
              description: 認証エラー
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
            '404':
              description: リソースが見つかりません
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
            '429':
              description: リクエスト回数制限超過
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
          security:
            - ApiKeyAuth: []
    ```

この OpenAPI 定義を使用することで、Dify のカスタムツール機能で不動産情報ライブラリ API を簡単に統合できます。API の詳細な仕様や利用可能なすべてのエンドポイントに合わせて、この定義をさらに拡張することができます。

多くのOpenAPIの定義ファイルを人力で作成するのは骨が折れる作業なので、不動産情報ライブラリのAPI操作説明のドキュメントをAnthropicのClaude3.5 Sonnetに与えて作ってもらいました。  
他のAPIの定義ファイルも同様にClaude3.5 Sonnetに作ってもらいましょう。

この定義をもとに、Dify上でAPIを呼び出し、取得したデータをAIエージェントの入力として使用することが可能になります。  
次のステップでは、このAPIをAIエージェントの機能として活用する方法を説明します。

## 4.2 Difyワークフローでの不動産情報ライブラリAPIの統合と座標変換

不動産情報ライブラリAPIを利用するためには、世界測地系とタイル座標系を理解し、それらの間で変換を行う必要があります。  
不動産情報ライブラリAPIでは、機能によって世界測地系座標とタイル座標の両方が使用される可能性があります。そのため、これらの座標系間の変換が必要になります。

### 世界測地系（WGS84）
世界測地系（WGS84）は、地球上の位置を緯度と経度で表す国際的な標準座標系です。

### タイル座標系
タイル座標系は、地球の表面を正方形のタイルに分割し、ズームレベル（Z）と X、Y 座標で位置を表現する Web 地図サービスで使用される座標系です。

### 座標変換の仕組み
1. ユーザー入力（住所）→ 世界測地系座標:
    - ユーザーが入力した住所を、緯度経度の形式に変換
    - Amazon Location Serviceなどのジオコーディングサービスを使用する

2. 世界測地系座標 → タイル座標:
    - 緯度経度をZ/X/Y形式のタイル座標に変換
    - ズームレベルの選択が重要（一般的に13-15が都市レベルの分析に適している）


### Amazon Location Serviceを使った住所から世界測地系の座標への変換

住所から世界測地系座標を取得するために、Amazon Location Serviceを利用します。  
これをDifyワークフローに組み込むために、AWS Lambda関数を作成し、Amazon API Gatewayで公開した後、Difyのカスタムツールとして設定します。

- Lambda関数の作成:

  ```python
  import boto3
  import json
  import os
  import time
  import math
  from aws_lambda_powertools import Logger

  logger = Logger()

  PLACE_INDEX = os.environ['PLACE_INDEX']

  def fetchWGS(address: str):
      client = boto3.client('location')
      response = client.search_place_index_for_text(
        IndexName=PLACE_INDEX,
        Text=address
      )
      if response['Results']:
          geometry = response['Results'][0]['Place']['Geometry']
          x = geometry['Point'][0]
          y = geometry['Point'][1]
          return x, y
      else:
          return None, None

  def handler(event, context):
      try:
          body = json.loads(event['body'])
          logger.info(body)
          query = body.get('query')
          logger.info(f"query is {query}")

          address = body['address']
          longitude, latitude = fetchWGS(address)

          return {'statusCode': 200, 'body': json.dumps(
              {
                  "longitude": longitude,
                  "latitude": latitude,
              })}
      except Exception as e:
          logger.error(str(e))
          return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}


  if __name__ == '__main__':
      address = '東京都千代田区丸の内1-1-1'
      x, y = fetchWGS(address)
      print(f'x: {x}, y: {y}')
  ```

- Difyでのカスタムツール設定:  
  Difyの「Tools」セクションで、新しいカスタムツールを追加します。  
  OpenAPI仕様で、API GatewayのエンドポインドとPOSTメソッドを定義します。 

  ```
  openapi: 3.0.0
  info:
    title: Address to Coordinates API
    version: 1.0.0
    description: An API to convert an address to WGS84 coordinates using Amazon Location Service
  servers:
  - url: "https://abcdefghij.execute-api.ap-northeast-1.amazonaws.com/prod/"

  paths:
    /geocode:
      post:
        summary: Convert address to coordinates
        description: Converts a given address to WGS84 coordinates using Amazon Location Service
        requestBody:
          required: true
          content:
            application/json:
              schema:
                type: object
                required:
                  - address
                properties:
                  address:
                    type: string
                    description: The address to geocode
        responses:
          '200':
            description: Successful conversion
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    x:
                      type: number
                      format: float
                      description: Longitude (WGS84)
                    y:
                      type: number
                      format: float
                      description: Latitude (WGS84)
          '500':
            description: Internal server error
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    error:
                      type: string
                      description: Error message
  ```


### 世界測地系の座標からタイル座標への変換

- Lambda関数の作成:
  ```
  import boto3
  import json
  import os
  import time
  import math
  from aws_lambda_powertools import Logger

  logger = Logger()

  def latlon_to_tile(lat, lon, zoom):
      lat_rad = math.radians(lat)
      n = 2.0 ** zoom
      xtile = int((lon + 180.0) / 360.0 * n)
      ytile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)
      return (xtile, ytile, zoom)


  def handler(event, context):
      try:
          body = json.loads(event['body'])
          logger.info(body)
          query = body.get('query')
          logger.info(f"query is {query}")

          lat = body['lat']
          lon = body['lon']

          x_13, y_13, z_13 = latlon_to_tile(lat, lon, 13)
          print(f"Tile coordinates: x={x_13}, y={y_13}, z={z_13}")

          x_14, y_14, z_14 = latlon_to_tile(lat, lon, 14)
          print(f"Tile coordinates: x={x_14}, y={y_14}, z={z_14}")

          x_15, y_15, z_15 = latlon_to_tile(lat, lon, 15)
          print(f"Tile coordinates: x={x_15}, y={y_15}, z={z_15}")

          return {'statusCode': 200, 'body': json.dumps(
              {
                  "x_13": x_13,
                  "y_13": y_13,
                  "z_13": z_13,
                  "x_14": x_14,
                  "y_14": y_14,
                  "z_14": z_14,
                  "x_15": x_15,
                  "y_15": y_15,
                  "z_15": z_15,
              })}
      except Exception as e:
          logger.error(str(e))
          return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}


  if __name__ == "__main__":
      event = {
          "body": json.dumps({
              "lat": 35.6895,
              "lon": 139.6917
          })
      }
      context = {}
      print(handler(event, context))
  ```


- Difyでのカスタムツール設定:  
  Difyの「Tools」セクションで、新しいカスタムツールを追加します。  
  OpenAPI仕様で、API GatewayのエンドポインドとPOSTメソッドを定義します。

    ```
    openapi: 3.0.0
    info:
      title: Tile Coordinate Converter API
      version: 1.0.0
      description: An API to convert latitude and longitude to tile coordinates

    servers:
    - url: "https://abcdefghij.execute-api.ap-northeast-1.amazonaws.com/prod/"

    paths:
      /latlon_to_tile:
        post:
          summary: Convert lat/lon to tile coordinates
          description: Converts given latitude and longitude to tile coordinates at zoom level 15
          requestBody:
            required: true
            content:
              application/json:
                schema:
                  type: object
                  required:
                    - lat
                    - lon
                  properties:
                    lat:
                      type: number
                      format: float
                      description: Latitude
                    lon:
                      type: number
                      format: float
                      description: Longitude
          responses:
            '200':
              description: Successful conversion
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      x_13:
                        type: integer
                      y_13:
                        type: integer
                      z_13:
                        type: integer
                      x_14:
                        type: integer
                      y_14:
                        type: integer
                      z_14:
                        type: integer
                      x_15:
                        type: integer
                      y_15:
                        type: integer
                      z_15:
                        type: integer
            '500':
              description: Internal server error
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      error:
                        type: string
    ```
  


### ワークフローの作成

Difyのワークフローに組み込んでみましょう。  
Difyの `スタジオ` から `ワークフロー` を作成します。先ほど作成したカスタムツールをブロックとして追加して、それらを繋いでいきます。
カスタムツールの出力は文字列型になるため、`コード`のブロックを使用してJSON型に変換(`json.loads()`)します。  
`報告書の作成`ブロックでは、不動産情報ライブラリから習得した情報を分析するように指示をします。  

![将来人口推定ワークフロー図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131124/a676b4e2-0894-5d4c-0868-dd5887221752.png)

![jsonloads.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131124/aa54cdca-22ac-213c-d932-133697fa57d3.png)

![報告書作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131124/78b5303c-40c6-7ead-bc02-5e49bb798db7.png)


次のセクションでは、このワークフローを使用して実際にどのような回答が生成されるか、具体的な例を示していきます。


## 4.3 ワークフローの実行

指定する住所で、将来の人口推定と周辺駅の乗降者数を不動産情報ライブラリを使って情報を取得し、AIエージェントに報告書をまとめてもらいます。  

### ワークフローの出力

以下の分析レポートはAIが不動産情報ライブラリの情報を読み取ってまとめたものです。  
json形式のデータを読み取り、指定した住所周辺の駅の乗降者数と将来の人口がどのように推移するかを分析しています。    
ハルシネーションが起きているかについては確認する必要ではありますが、いい感じにデータを読めているようです。  

```
# 大田区の駅と人口の分析レポート

## 1. 駅の概要
大田区内には以下の主要な駅が存在します：

### JR線
- 西大井駅: 1日平均約29,000人の乗降客
- 大森駅: 1日平均約183,000人の乗降客（区内最大規模）
### 京浜急行線
- 平和島駅: 1日平均約43,000人の乗降客
- 大森海岸駅: 1日平均約13,000人の乗降客
- 立会川駅: 1日平均約16,600人の乗降客
- 大森町駅: 1日平均約17,000人の乗降客
### 都営地下鉄
- 西馬込駅: 1日平均約38,500人の乗降客
- 馬込駅: 1日平均約22,900人の乗降客
### 東急線
- 池上駅: 1日平均約33,000人の乗降客

## 2. 将来人口推計の特徴
分析対象エリアの将来人口推計から以下の特徴が見られます：

1. 2020年から2050年にかけて、多くのメッシュで人口減少傾向
2. 特に高齢者人口の増加が顕著
3. 駅周辺部でも人口減少が予測される

## 3. 駅と人口分布の関係性
1. 大森駅周辺

- 現在最も乗降客が多い
- 将来的にも一定の人口密度を維持

2. 京急線沿線

- 比較的コンパクトな駅間距離
- 各駅で1万人以上の乗降客を維持

3. 都営地下鉄エリア

- 西馬込駅を中心に一定の利用者数を確保
- 馬込駅は比較的小規模ながら安定した利用者数

## 4. 今後の課題

1. 人口減少への対応

- 駅周辺の再開発検討
- 交通結節点としての機能強化
- 高齢化への対応

2. バリアフリー化の推進
- 駅周辺の生活利便施設の充実

3. 交通ネットワークの最適化
- 各路線間の連携強化
- フィーダーバスの充実

## まとめ
大田区の駅は、JR大森駅を中心に複数の鉄道路線が機能的なネットワークを形成しています。将来的な人口減少が予測される中、駅を中心としたコンパクトなまちづくりと、高齢化に対応した交通環境の整備が求められます。
```

> 技術検証を目的とする実験的な試みであるため、生成AIの出力内容の正しさは確認はしておりません。

# まとめ
今回のプロジェクトでは、不動産情報ライブラリAPIとDifyを組み合わせることで、従来にない深い不動産エリア分析が可能になることがわかりました。特筆すべきは、不動産情報ライブラリに含まれる将来人口推定データをAIが解釈し、わかりやすく提示できる点です。

この技術の組み合わせは、既存のデータをより効果的に活用し、ユーザーにとって理解しやすい形で提供することを可能にします。人口動態や駅の利用状況など、多角的な視点からエリアの特徴を浮き彫りにできるのは、大きな強みといえるでしょう。

他の不動産情報ライブラリのAPIを組み込むことで、次回の引越しの際に希望のエリアがどんな雰囲気なのか探ることができそうです。  



# Appendix: 他のワークフローの出力例

```
# 不動産に関する規制等の分析レポート

## 1. 防火・準防火地域の状況

### 防火地域
- 大田区と品川区の境界付近に複数の防火地域が指定されています
- 特に、品川区側の東西に広がる地域（139.70-139.74度付近）に集中して指定
- 大田区側にも小規模な防火地域が点在

### 準防火地域
- 両区とも広範囲に準防火地域が指定
- 大田区側は東西方向に広く分布
- 品川区側は南北方向に帯状に分布
- 防火地域を取り囲むように準防火地域が設定されている傾向

## 2. 土砂災害関連の状況

### 大規模盛土造成地
- 大田区内に5箇所の大規模盛土造成地が確認
  1. 大田区02-37（谷埋め型）
  2. 大田区02-55-a（谷埋め型）
  3. 大田区02-58（谷埋め型）
  4. 大田区02-66（谷埋め型）
  5. 大田区-R1-4（腹付け型）
- 4箇所が谷埋め型、1箇所が腹付け型
- 比較的小規模な区域に分散して存在

### その他の土砂災害関連区域
- 災害危険区域の指定なし
- 地すべり防止地区の指定なし
- 急傾斜地崩壊危険区域の指定なし

## 3. 総合的な評価

1. 火災対策
   - 両区とも火災対策は充実しており、特に重要な地域は防火地域に指定
   - 準防火地域による重層的な防火対策が実施

2. 土砂災害リスク
   - 大規模な土砂災害リスクは比較的低い
   - 局所的に盛土造成地があり、これらの地域では注意が必要
   - 特に谷埋め型盛土が多く、地震時等の安定性に留意が必要

3. 開発・建築時の留意点
   - 防火・準防火地域での建築には、それぞれの基準に適合した防火性能が必要
   - 盛土造成地での開発には、地盤調査や適切な対策工事が重要

以上の分析から、当該地域は火災対策が充実している一方で、一部地域で盛土に関する注意が必要な地域であることが分かります。
```

```
# 都市計画決定GISデータ 総合分析レポート
作成日: 2024年11月12日

## 1. データ概要

分析対象データ:
- 都市計画区域/区域区分データ
- 用途地域データ
- 立地適正化計画データ
- 地区計画データ
- 高度利用地区データ

対象地域: 東京都品川区・大田区

## 2. 主要な発見事項

### 2.1 都市計画区域の特徴
- 両区とも全域が都市計画区域かつ市街化区域に指定
- 市街化調整区域の設定なし
- 東京湾沿岸部を含む都市的土地利用が進んだ地域

### 2.2 用途地域の分布
主な用途地域:
- 第一種住居地域（28件）
- 準工業地域（25件）
- 近隣商業地域（24件）
- その他、住居系・商業系・工業系の用途がバランスよく配置

建ぺい率/容積率:
- 建ぺい率: 50%〜80%
- 容積率: 100%〜600%

### 2.3 その他の計画データ
以下のデータについては記録なし:
- 立地適正化計画
- 地区計画
- 高度利用地区

## 3. 地域特性の分析

### 品川区
- 商業・工業機能が充実
- 準工業地域と近隣商業地域が多い
- 高い容積率設定（200%〜400%）

### 大田区
- 住居系用途地域が中心
- 工業系用途地域も点在
- 比較的低めの容積率設定（100%〜300%）

## 4. 課題と提言

### データ整備に関する課題
1. 立地適正化計画等のデータが未整備
2. 地区計画情報の欠如
3. 高度利用地区の情報不足

### 提言
1. データ整備の推進
   - 未整備データの収集・登録
   - 定期的な更新体制の構築

2. 情報管理の改善
   - 統一的なデータ管理システムの導入
   - データ品質管理プロセスの確立

3. 都市計画の方向性
   - 用途地域の細分化による効率的な土地利用
   - 地域特性に応じた建ぺい率・容積率の最適化

## 5. まとめ

本データセットは、東京都心部における典型的な都市計画の特徴を示しています。特に用途地域データは詳細な土地利用計画を反映していますが、その他の計画データについては整備が必要な状況です。今後の都市計画においては、データの充実とともに、地域特性を活かした計画的な都市開発の推進が望まれます。
```


```
2024年から2023年の品川区の不動産取引データを時系列で分析すると、以下のような傾向が見られます：

## 価格推移の傾向

### マンション
1. 価格帯の変動
- 2024年Q1では高額物件（1億円以上）が大崎・上大崎エリアに集中
- 2023年を通じて、大崎エリアの平均価格は8,000-9,000万円台を維持
- 投資用の小型物件（1K/1R）は2,000-3,500万円台で安定的に推移

2. 面積帯別の特徴
- 20-40㎡の物件が一貫して取引の30-40%を占める
- 大型物件（80㎡以上）は全期間を通じて10-15%程度で推移

### 戸建て
1. 価格変動
- 2024年Q1では2億円以上の高額物件が増加傾向
- 2023年を通じて一般的な価格帯は7,000-9,000万円で推移
- 土地面積50-100㎡の物件が中心的な取引層を形成

### アパート
- 投資用途が中心で、5-8%程度の利回りが一般的
- 築古物件の取引が多い傾向は期間を通じて継続

## 地域特性の変化

1. 大崎・五反田エリア
- 再開発の影響で高級マンションの供給が継続
- 平均価格は上昇傾向を維持

2. 品川・北品川エリア
- 中価格帯の安定した取引が継続
- 古い物件のリノベーション案件が増加

3. 大井エリア
- 比較的手頃な価格帯が中心
- 投資用物件の取引が活発

## 総合的な市場動向

1. 価格トレンド
- 高級物件の価格は堅調に推移
- 中小規模物件は安定的な取引が継続

2. 需要の特徴
- 単身・DINKS向けの小型物件需要が継続して強い
- 投資用物件への需要も安定的

3. 築年数による影響
- 新築・築浅物件は高額での取引が継続
- 築古物件も立地次第で一定の需要を維持

このように、品川区の不動産市場は、地域による二極化が進みながらも、全体として安定的な取引が継続していることが確認できます。
```