関数型プログラミングからAIエージェント関数型プログラミング

# 何を言いたい

```Hugging Face```が開発されたAIエージェント```smolagents```の説明資料に、関数をツールと定義する使い方がこのように書いています。

https://github.com/huggingface/agents-course/blob/main/units/en/unit2/smolagents/code_agents.mdx

```python
from smolagents import CodeAgent, tool, HfApiModel

# Tool to suggest a menu based on the occasion
@tool
def suggest_menu(occasion: str) -> str:
    """
    Suggests a menu based on the occasion.
    Args:
        occasion: The type of occasion for the party.
    """
    if occasion == "casual":
        return "Pizza, snacks, and drinks."
    elif occasion == "formal":
        return "3-course dinner with wine and dessert."
    elif occasion == "superhero":
        return "Buffet with high-energy and healthy food."
    else:
        return "Custom menu for the butler."

# Alfred, the butler, preparing the menu for the party
agent = CodeAgent(tools=[suggest_menu], model=HfApiModel())

# Preparing the menu for the party
agent.run("Prepare a formal menu for the party.")
```

このような書き方は、ユーザープロンプトをAIで解析して、ほしい部分を抽出して、そのあとにソースコードを実行して結果を返します。

もっと抽象的に言いますと、このような感じです。

```python
def 何らかの処理をしたい(ユーザープロンプトから関数のインプットを抽出):
    """
    処理の説明文
    """
    
    実際の処理コード
    
    return 結果
```

# もう1ステップ行けたら

上記のロジックは普通のAIエージェントだと思うけど、それもあくまでプロンプトの解析だけなので、**実際の処理コード**も開発者が書かないといけないです。

でしたら、AIの方でソースコードを生成するのは無理ですか？

## 自動化じゃだめなんですか

```python
def 何らかの処理をしたい(ユーザープロンプトから関数のインプットを抽出):
    """
    処理の説明文
    """
    
    実際の処理コード　←　つまり、ここもAIに任せる
    
    return 結果
```

## 1個の例をやってみましょう

こちらは説明資料に別のページで、同じくツールの定義だけど、実際の処理コードが長くて、人間で書くより、AIの方が早くて書けるかどうかを検証したいです。

https://github.com/huggingface/agents-course/blob/main/units/en/unit2/smolagents/multi_agent_systems.mdx

```python
import math
from typing import Optional, Tuple

from smolagents import tool


@tool
def calculate_cargo_travel_time(
    origin_coords: Tuple[float, float],
    destination_coords: Tuple[float, float],
    cruising_speed_kmh: Optional[float] = 750.0,  # Average speed for cargo planes
) -> float:
    """
    Calculate the travel time for a cargo plane between two points on Earth using great-circle distance.

    Args:
        origin_coords: Tuple of (latitude, longitude) for the starting point
        destination_coords: Tuple of (latitude, longitude) for the destination
        cruising_speed_kmh: Optional cruising speed in km/h (defaults to 750 km/h for typical cargo planes)

    Returns:
        float: The estimated travel time in hours

    Example:
        >>> # Chicago (41.8781° N, 87.6298° W) to Sydney (33.8688° S, 151.2093° E)
        >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))
    """

    def to_radians(degrees: float) -> float:
        return degrees * (math.pi / 180)

    # Extract coordinates
    lat1, lon1 = map(to_radians, origin_coords)
    lat2, lon2 = map(to_radians, destination_coords)

    # Earth's radius in kilometers
    EARTH_RADIUS_KM = 6371.0

    # Calculate great-circle distance using the haversine formula
    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = (
        math.sin(dlat / 2) ** 2
        + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
    )
    c = 2 * math.asin(math.sqrt(a))
    distance = EARTH_RADIUS_KM * c

    # Add 10% to account for non-direct routes and air traffic controls
    actual_distance = distance * 1.1

    # Calculate flight time
    # Add 1 hour for takeoff and landing procedures
    flight_time = (actual_distance / cruising_speed_kmh) + 1.0

    # Format the results
    return round(flight_time, 2)


print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)))
```

### インプットプロンプト

インプットプロンプトには、処理のコードを削除して、要件だけ残します。

一番最後にソースコード生成を指示しました。

```python
import math
from typing import Optional, Tuple

from smolagents import tool

@tool
def calculate_cargo_travel_time(
    origin_coords: Tuple[float, float],
    destination_coords: Tuple[float, float],
    cruising_speed_kmh: Optional[float] = 750.0,  # Average speed for cargo planes
) -> float:
    """
    Calculate the travel time for a cargo plane between two points on Earth using great-circle distance.

    Args:
        origin_coords: Tuple of (latitude, longitude) for the starting point
        destination_coords: Tuple of (latitude, longitude) for the destination
        cruising_speed_kmh: Optional cruising speed in km/h (defaults to 750 km/h for typical cargo planes)

    Returns:
        float: The estimated travel time in hours

    Example:
        >>> # Chicago (41.8781° N, 87.6298° W) to Sydney (33.8688° S, 151.2093° E)
        >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))
    """

    ** GENERATE CODE HERE BASED ON THE FOLLOWING REQUIREMENTS **
    # Extract coordinates
    # Earth's radius in kilometers
    # Calculate great-circle distance using the haversine formula
    # Add 10% to account for non-direct routes and air traffic controls
    # Calculate flight time
    # Format the results

print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)))

Above is the function calculate_cargo_travel_time, please follow the requirements inside the function to fill in the code.
```

### 生成結果

Gemini 2.0 Proを使って、生成結果はこちらになります。

```python
import math
from typing import Optional, Tuple

from smolagents import tool

@tool
def calculate_cargo_travel_time(
    origin_coords: Tuple[float, float],
    destination_coords: Tuple[float, float],
    cruising_speed_kmh: Optional[float] = 750.0,  # Average speed for cargo planes
) -> float:
    """
    Calculate the travel time for a cargo plane between two points on Earth using great-circle distance.

    Args:
        origin_coords: Tuple of (latitude, longitude) for the starting point
        destination_coords: Tuple of (latitude, longitude) for the destination
        cruising_speed_kmh: Optional cruising speed in km/h (defaults to 750 km/h for typical cargo planes)

    Returns:
        float: The estimated travel time in hours

    Example:
        >>> # Chicago (41.8781° N, 87.6298° W) to Sydney (33.8688° S, 151.2093° E)
        >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))
    """

    # Extract coordinates
    lat1, lon1 = origin_coords
    lat2, lon2 = destination_coords

    # Earth's radius in kilometers
    R = 6371.0

    # Calculate great-circle distance using the haversine formula
    lat1_rad = math.radians(lat1)
    lon1_rad = math.radians(lon1)
    lat2_rad = math.radians(lat2)
    lon2_rad = math.radians(lon2)

    dlon = lon2_rad - lon1_rad
    dlat = lat2_rad - lat1_rad

    a = math.sin(dlat / 2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon / 2)**2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))

    distance_km = R * c

    # Add 10% to account for non-direct routes and air traffic controls
    distance_km *= 1.10

    # Calculate flight time
    flight_time_hours = distance_km / cruising_speed_kmh

    # Format the results
    return flight_time_hours

print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)))
```

計算結果は完璧だけど、最後の出力は要件定義が甘かったので、切り上げの処理はなかったですね。

# 結論

今まで関数型プログラミングの概念だったけど、生成AIによって、関数の中に要件定義をしっかりできたら、ソースコードを書くこともいらなくて、AIに任せればできってしまいますね。