UiPath LangChainエージェントの基本的な実装手順と各LLM対応

# はじめに
- 本記事では **UiPath LangChain** の基本的な実装手順と各大規模言語モデル(LLM)のプラットフォームに対応させる方法について解説したいと思います。
- UiPath AIエージェントは [Studio Web](https://docs.uipath.com/ja/agents/automation-cloud/latest/user-guide/building-an-agent) を利用してノーコード・ローコードでも開発が可能ですが、LangChainなどのPythonライブラリーを利用し [Coded Agent (コード化されたエージェント)](https://docs.uipath.com/ja/agents/automation-cloud/latest/user-guide/about-coded-agents) として開発することも可能です。

## UiPath LangChain概要
- [UiPath LangChain Python SDK](https://github.com/UiPath/uipath-langchain-python) は、UiPath Automation CloudにLangChainやLangGraphライブラリーで実装されたエージェントを開発・デプロイするためのPython SDKです。このパッケージは、UiPath Automation Cloudサービスとの連携、Action Centerを利用したHuman-in-the-Loop(意思決定などに人間を介在させる処理)を提供します。
- 現時点では月間ダウンロードが11,000件ほどあり注目を集めています！
	
    ![01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/0623d128-86f5-47a0-a1f6-c8729f68fcd3.png)

- LangChainJP によるX投稿でも紹介されています。

https://x.com/LangChainJP/status/1918939403969290305
    
- 英語になりますが、UiPath Blog記事でも紹介されています。

https://www.uipath.com/blog/product-and-updates/langgraph-uipath-advancing-agentic-automation-together

- 具体的な使い方は [UiPath LangChain SDKマニュアル](https://uipath.github.io/uipath-python/) に記載がありますが、英文ということもあり少々ハードルが高いものになっています。またサンプルではOpenAIとAnthropicには対応していますが、それ以外のLLMには対応していません。
- そこで本記事では [UiPath LangChainクイックスタート](https://uipath.github.io/uipath-python/) を各LLMのプラットフォーム(Azure OpenAI Service, Amazon Bedrock, UiPath AI Trust Layer)にも対応させ、Automation Cloudにデプロイして実行する手順について説明したいと思います。

# 実装手順

## 前提
UiPath LangChainの開発・実行には次の環境が必要となります。
- UiPath Automation Cloud
    - 必要となるライセンスは [こちらのページ](https://docs.uipath.com/ja/agents/automation-cloud/latest/user-guide/coded-agents-licensing) をご参照ください。
- 下記いずれかのLLMプラットフォームおよびAPIキーが利用できること
	- OpenAI
	- Anthropic
	- Azure OpenAI Service
	- Amazon Bedrock
	- UiPath AI Trust Layer
- Python 3.10以降の開発環境 (本記事ではWindowsを利用)

## 実装の流れ
1. [LLMのAPIキー入手](#1-llm%E3%81%AE%E4%BA%8B%E5%89%8D%E6%A4%9C%E8%A8%8E%E3%81%A8api%E3%82%AD%E3%83%BC%E3%81%AE%E5%85%A5%E6%89%8B)
2. [Python環境作成とライブラリーインストール](#2-python%E7%92%B0%E5%A2%83%E4%BD%9C%E6%88%90%E3%81%A8%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%83%BC%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
3. [UiPath LangChainエージェント本体作成](#3-uipath-langchain%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E6%9C%AC%E4%BD%93%E4%BD%9C%E6%88%90)
4. [Automation Cloudへのパブリッシュと動作確認](#4-automation-cloud%E3%81%B8%E3%81%AE%E3%83%91%E3%83%96%E3%83%AA%E3%83%83%E3%82%B7%E3%83%A5%E3%81%A8%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D)

### 1. LLMの事前検討とAPIキーの入手
- 利用するLLMを事前に検討し、それぞれのLLMに応じてAPIキーを入手します。いずれでもそれぞれのLLM管理において適切な権限を保持していることが前提となります。

#### OpenAI
- https://platform.openai.com/api-keys よりAPIキーを入手します。
- API利用要件はOpenAIサイトをご確認ください。

#### Anthropic
- https://console.anthropic.com/settings/keys よりAPIキーを入手します。
- API利用要件はAnthropicサイトをご確認ください。

#### Azure OpenAI Service
- [Azureポータル](https://portal.azure.com) でAzure OpenAIのインスタンスを作成し、APIキーとエンドポイントをコピーします。
    ![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/3be84101-b0c0-4fe7-a5cc-a621cb2d3e47.png)

- [モデルデプロイ](https://oai.azure.com/resource/deployments) にてLLMをデプロイし、デプロイ名を確認します。
    ![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/7c48bac1-b010-47d6-8d00-6caabeee7b7f.png)

#### Amazon Bedrock
- AWSマネジメントコンソールにて適切なリージョンに切り替え、Bedrock > モデルアクセスに移動します。    
- 利用するモデルへのアクセスが有効化されていない場合には モデル > リクエスト可能 > アクセスリクエスト をクリックしてリクエストを送信して承認されるまでしばらく待ちます。
    ![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/5434bd06-989c-4732-bf2c-68a7ec718d32.png)

- IAMに移動し、適切なIAMロール(`AmazonBedrockFullAccess` または適切にスコープダウンした権限ポリシーを付与)を持つIAMユーザーを作成します。
- IAMユーザーにてアクセスキーを作成し、アクセスキーIDとシークレットアクセスキーを安全な場所に保存します。
    ![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/e09c8414-f0fd-4b3f-8f40-783eb39f126d.png)

#### UiPath AI Trust Layer
- 追加の作業は不要です。認証処理は後ほど `uipath auth` コマンドにて行います。

### 2. Python環境作成とライブラリーインストール
- Python開発環境を作成するために、任意の作業ディレクトリに移動し、コマンドプロンプトにて次のコマンドを順次実行します。

    ```powershell
    python -m venv .venv
    .venv\Scripts\activate
    pip install uipath-langchain langchain_anthropic langchain_aws
    uipath -lv
    ```

> uipath-langchain version 0.0.110

のようにバージョンが表示されることを確認します。

### 3. UiPath LangChainエージェント本体作成
- 次のコマンドを実行し、プロジェクトを作成します。

    ```powershell
    uipath new quickstart-agent
    uipath init
    ```

#### 環境変数設定
- 利用するLLMに応じて `.env` ファイルに環境変数をセットします。
    ```bash
    MODEL_TYPE=Azure
    MODEL_NAME=gpt-4o
    AZURE_OPENAI_API_KEY={AzureOpenAI-ApiKey}
    AZURE_OPENAI_ENDPOINT=https://{AzureOpenAI-Name}.openai.azure.com/
    OPENAI_API_VERSION=2025-01-01-preview
    AWS_ACCESS_KEY_ID={AWS-Access-Key}
    AWS_SECRET_ACCESS_KEY={AWS-Secret-Key}
    AWS_REGION=us-east-1
    TEMPERATURE=0
    MAX_TOKENS=4096
    ```
- まず `MODEL_TYPE` は利用するLLMのプラットフォームに応じて指定します。

|プラットフォーム|設定値|
|--|--|
|OpenAI|`OpenAI`|
|Anthropic|`Anthropic`|
|Azure OpenAI Service|`Azure`|
|Amazon Bedrock|`AWS`|
|UiPath AI Trust Layer|`UiPath`|

- 各プラットフォームに応じて環境変数を指定します。
	- **OpenAI**:
		- `OPENAI_API_KEY`: OpenAI APIキー
	- **Anthropic**:
		- `ANTHROPIC_API_KEY`: Anthropic APIキー
	- **Azure OpenAI Service**:
		- `AZURE_OPENAI_API_KEY`: Azure OpenAI APIキー
		- `AZURE_OPENAI_ENDPOINT`: エンドポイント (`https://{AzureOpenAIリソース名}.openai.azure.com/`)
		- `OPENAI_API_VERSION`: APIバージョン (例: `2025-01-01-preview`)
		- `MODEL_NAME`: モデルのデプロイ名を指定
	- **Amazon Bedrock**:
		- `AWS_ACCESS_KEY_ID`: AWSアクセスキーID
		- `AWS_SECRET_ACCESS_KEY`: AWSシークレットアクセスキー
		- `AWS_REGION`: Bedrockモデルのリージョン (例: `us-east-1`)
		- `MODEL_NAME`: BedrockモデルID
			- Claude 3.7 Sonnetを利用する場合には [推論プロファイルでサポートされているリージョンとモデル](https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/inference-profiles-support.html#inference-profiles-support-system) に記載のモデルIDを指定します。たとえばUSリージョンでは現在は `us.anthropic.claude-3-7-sonnet-20250219-v1:0` となります。
	- **UiPath AI Trust Layer**:
		- `MODEL_NAME`: [UiPathChat](https://uipath.github.io/uipath-python/langchain/chat_models/#uipathchat) でサポートされているいずれかのモデル (例: `gpt-4o-2024-11-20`) を指定します。
		- テナントのリージョンによって利用可能なモデルが異なる点にご注意ください。

#### LLMのパラメータ設定
- 環境変数で設定できる主要なLLMパラメータについて解説します。
    - **TEMPERATURE** (0～1.0): 生成される文章のランダム性を制御します。
        - 低い値 (0～0.3): より一貫性のある、予測可能な応答が生成されます。ビジネスロジックや正確さが求められる場合に適しています。
        - 高い値 (0.7～1.0): より創造的で多様な応答が生成されます。アイデア出しやブレインストーミングに適しています。
    - **MAX_TOKENS**: 生成される応答の最大トークン数を指定します。
        - 短い応答 (500以下): 簡潔な回答や選択肢の生成に適しています。
        - 中程度 (1000～2000): 詳細な説明や分析に適しています。
        - 長い応答 (4000以上): 詳細なレポートや長文の生成に適しています。
- 異なるLLMによって設定できるパラメータや値の範囲が異なるため、各プラットフォームのドキュメントを参照することをお勧めします。

#### Pythonコード実装
- これらのLLMプラットフォームに対応させるため `main.py` を次のように書き換えます。

    ```python
	from langchain_anthropic import ChatAnthropic
	from langchain_core.messages import HumanMessage, SystemMessage
	from langchain_openai import ChatOpenAI, AzureChatOpenAI
	from langchain_aws import ChatBedrock
	from uipath_langchain.chat.models import UiPathChat
	from langgraph.graph import START, StateGraph, END
	from pydantic import BaseModel
	import os
	import sys
	
	class GraphInput(BaseModel):
		topic: str
	
	class GraphOutput(BaseModel):
		report: str
	
	def get_llm():
		"""
		Initialize and return an LLM based on the MODEL_TYPE environment variable.
		
		Returns:
			A language model instance based on the specified MODEL_TYPE.
			
		Raises:
			ValueError: If MODEL_TYPE is not set, has an invalid value, or if required credentials are missing.
		"""
		# Get the model type from environment variable
		model_type = os.getenv("MODEL_TYPE")
		
		# Get temperature from environment variable or use default value of 0
		try:
			temperature = float(os.getenv("TEMPERATURE", "0"))
		except (ValueError, TypeError):
			print("Warning: Invalid TEMPERATURE value. Using default value of 0.", file=sys.stderr)
			temperature = 0
		
		# Validate MODEL_TYPE environment variable
		valid_model_types = ["OpenAI", "Anthropic", "Azure", "AWS", "UiPath"]
		if not model_type or model_type not in valid_model_types:
			error_msg = f"Error: MODEL_TYPE environment variable must be set to one of: {', '.join(valid_model_types)}"
			print(error_msg, file=sys.stderr)
			raise ValueError(error_msg)
		
		# Initialize LLM based on MODEL_TYPE
		if model_type == "Anthropic":
			if not os.getenv("ANTHROPIC_API_KEY"):
				raise ValueError("Error: ANTHROPIC_API_KEY environment variable is required when MODEL_TYPE is set to Anthropic")
			return ChatAnthropic(model=os.getenv("MODEL_NAME"), temperature=temperature)
		
		elif model_type == "OpenAI":
			if not os.getenv("OPENAI_API_KEY"):
				raise ValueError("Error: OPENAI_API_KEY environment variable is required when MODEL_TYPE is set to OpenAI")
			return ChatOpenAI(model=os.getenv("MODEL_NAME"), temperature=temperature)
		
		elif model_type == "Azure":
			if not (os.getenv("AZURE_OPENAI_API_KEY") and os.getenv("AZURE_OPENAI_ENDPOINT")):
				raise ValueError("Error: AZURE_OPENAI_API_KEY and AZURE_OPENAI_ENDPOINT environment variables are required when MODEL_TYPE is set to Azure")
			# For Azure OpenAI
			return AzureChatOpenAI(
				deployment_name=os.getenv("MODEL_NAME"),
				azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
				openai_api_key=os.getenv("AZURE_OPENAI_API_KEY"),
				temperature=temperature
			)
		
		elif model_type == "AWS":
			if not (os.getenv("AWS_ACCESS_KEY_ID") and os.getenv("AWS_SECRET_ACCESS_KEY") and os.getenv("AWS_REGION")):
				raise ValueError("Error: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION environment variables are required when MODEL_TYPE is set to AWS")
			# For Amazon Bedrock
			return ChatBedrock(
				model_id=os.getenv("MODEL_NAME"),
				region_name=os.getenv("AWS_REGION"),
				model_kwargs={"temperature": temperature}
			)
		
		elif model_type == "UiPath":
			# For UiPath AI Trust Layer
			return UiPathChat(
				model=os.getenv("MODEL_NAME"),
				temperature=temperature
			)
	
	async def generate_report(state: GraphInput) -> GraphOutput:
		# Get LLM from the provider module
		llm = get_llm()
	
		system_prompt = "You are a report generator. Please provide a brief report based on the given topic."
		output = await llm.ainvoke([SystemMessage(system_prompt), HumanMessage(state.topic)])
		return GraphOutput(report=output.content)
	
	builder = StateGraph(input=GraphInput, output=GraphOutput)
	
	builder.add_node("generate_report", generate_report)
	
	builder.add_edge(START, "generate_report")
	builder.add_edge("generate_report", END)
	
	graph = builder.compile()
    ```

上記のコードの主要な部分を解説します：

1. **GraphInput/GraphOutput クラス**: 
    - Pydanticを使用して入出力のデータ構造を定義しています。
    - `GraphInput`は入力パラメータの`topic`を定義し、`GraphOutput`はレポート生成結果を格納します。

2. **get_llm() 関数**:
    - 環境変数の`MODEL_TYPE`に基づいて適切なLLMインスタンスを初期化する関数です。
    - 各LLMプラットフォーム（OpenAI、Anthropic、Azure、AWS、UiPath）に対応しています。
    - 必要な環境変数がセットされているかを検証し、エラーメッセージを出力します。
    - `temperature`パラメータを環境変数から読み込み、設定します。

3. **generate_report() 関数**:
    - 実際にレポートを生成する非同期関数です。
    - `get_llm()`を使って設定されたLLMインスタンスを取得します。
    - システムプロンプトとユーザー入力（topic）をLLMに送信し、結果を`GraphOutput`として返します。

4. **LangGraph構造**:
    - `StateGraph`を使ってワークフロー構造を定義しています。
    - シンプルなフローとして`START`→`generate_report`→`END`の流れを作成しています。
    - `graph = builder.compile()`で実行可能なグラフを生成しています。

このコードは基本的なレポート生成のみですが、LangGraphを利用することで、より複雑なエージェントの振る舞いや多段階の処理フローを構築することができます。

#### ローカルでのエージェント実行
- 次のコマンドでUiPath Automation Cloudにブラウザーで認証します。複数テナント存在する場合にはテナントを選択します。

    ```powershell
    uipath auth
    ```

- 認証成功後 `.env` に次の環境変数が追加されます。
	- UIPATH_URL
	- UIPATH_TENANT_ID
	- UIPATH_ORGANIZATION_ID
	- UIPATH_ACCESS_TOKEN

- `input.json` ファイルを作成し、引数の値を指定します。

    ```json
    {
    	"topic": "UiPath"
    }
    ```

- 次のコマンドでエージェントを実行します。

    ```powershell
    uipath run agent --file input.json
    ```

- 実行結果が正常に表示されることを確認します。

    ![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/809f2b67-1a20-420c-a657-8b1b87bb4f74.png)

### 4. Automation Cloudへのパブリッシュと動作確認
- `pyproject.toml` を編集して、エージェントのバージョンと作成者を指定します。また依存関係のあるライブラリーを定義します。

    ```toml
    [project]
    name = "quickstart-agent"
    version = "0.0.1"
    description = "quickstart-agent"
    authors = [{ name = "Your Name", email = "your.name@example.com" }]
    dependencies = [
        "uipath-langchain>=0.0.106",
        "langchain-anthropic>=0.3.8",
        "langchain-aws>=0.2.23",
        "boto3>=1.38.14",
    ]
    requires-python = ">=3.10"
    ```

- パッケージを作成します。

    ```powershell
    uipath pack
    ```

- パッケージをパブリッシュします。

    ```powershell
    uipath publish -t
    ```

	- `-t` はテナントフィードにパブリッシュします。
	- `-w` は個人用ワークスペースにパブリッシュします。

- Automation Cloud上のOrchestratorでエージェントをプロセスとしてデプロイします。この時 `.env` に設定したLLM関連の環境変数をセットします。(`uipath auth` によって追加された UIPATH_URLなどは設定不要です)
    ![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/b1c28e43-32fd-4cf8-ae7f-e9426296b179.png)

- エージェントを実行します。
    ![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/a2b70520-eeff-4b3f-bc02-0ef13459faa8.png)

    - 実行時に引数を指定します。
        ![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/76befcb4-2e08-4089-a852-9cb359e6556a.png)

- 実行結果を確認します。
    ![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/eeb07e49-4b0b-40fc-9c4e-0dffe3971466.png)

- Traceをクリックすることによって、各ステップの処理内容を追跡することができます。Flow diagramをクリックすることによってLangGraphによって可視化された処理フローを表示することもできます。
    ![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/c681a50e-6e3c-47e3-a731-9a3a7bcd2f81.png)

### 【任意】Studio Webからのエージェント呼び出し
- パブリッシュしたエージェントはStudio Webでのエージェント構築からもツールとして呼び出すことが可能です。
    ![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178312/4cad3212-1b78-489c-bb19-6291c4e36836.png)

# おわりに
本記事ではUiPath LangChainエージェントのクイックスタートを様々なLLMに対応させる手順について説明しました。Pythonコードで開発したエージェントもStudio Webで構築したエージェントもAutomation Cloudにて一元管理し、連携や実行結果を追跡できることが大きなメリットだと思います。皆さまも是非お試しください！