Function CallingでSQLiteデータベースを操作する実装例

## はじめに
Function Callingを使用してSQLiteデータベースを操作する実装方法を紹介します。AIが直接データベースとやり取りすることで、効率的なデータ管理が可能になります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/8c181090-9be8-e6eb-a4ff-79e5083a7c5b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/a0cd52f4-9c06-90f1-867c-422f29728425.png)


## 環境要件
- Python 3.10以上
- openaiライブラリ
- sqlite3（標準ライブラリ）

```bash
pip install openai
```

## データベースのセットアップ

```python
import sqlite3

def setup_database():
    conn = sqlite3.connect('sample.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS users (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    name TEXT NOT NULL,
                    email TEXT NOT NULL
                 )''')
    conn.commit()
    conn.close()

setup_database()
```

## Function Callingの実装

```mermaid
sequenceDiagram
    autonumber
    actor User
    participant Client
    participant OpenAI
    participant Function
    participant SQLite

    User->>Client: 自然言語による要求
    Note right of User: "田中さんを追加して"

    Client->>OpenAI: chat.completions.create()
    Note over Client,OpenAI: モデル: GPT-4<br/>functions定義を含む

    OpenAI-->>Client: function_call応答
    Note over OpenAI,Client: {name: "insert_user",<br/>arguments: {<br/>  name: "田中さん",<br/>  email: "tanaka@example.com"<br/>}}

    Client->>Function: insert_user()実行
    Note over Client,Function: 引数の型チェック<br/>バリデーション

    Function->>SQLite: SQLクエリ実行
    Note over Function,SQLite: プリペアドステートメント使用

    SQLite-->>Function: クエリ結果
    Function-->>Client: 実行結果
    Client-->>User: 処理完了通知

    Note over User,SQLite: エラーハンドリング<br/>- 不正な入力値<br/>- DB接続エラー<br/>- クエリ実行エラー
```

```python
from openai import OpenAI
import json

client = OpenAI(api_key='YOUR_OPENAI_API_KEY')

def insert_user(name: str, email: str):
    conn = sqlite3.connect('sample.db')
    c = conn.cursor()
    c.execute('INSERT INTO users (name, email) VALUES (?, ?)', (name, email))
    conn.commit()
    conn.close()
    return {"status": "success", "message": f"User {name} inserted."}

functions = [
    {
        "name": "insert_user",
        "description": "Add a new user to the database.",
        "parameters": {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "email": {"type": "string"}
            },
            "required": ["name", "email"]
        }
    }
]

response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "You are an assistant that can add users to a database."},
        {"role": "user", "content": "新しいユーザーとして田中さん (tanaka@example.com) を追加して"}
    ],
    functions=functions
)

function_call = response.choices[0].message.function_call
if function_call:
    function_name = function_call.name
    args = json.loads(function_call.arguments)
    if function_name == 'insert_user':
        result = insert_user(args['name'], args['email'])
        print(result)
```

## データの確認

```python
def fetch_users():
    conn = sqlite3.connect('sample.db')
    c = conn.cursor()
    c.execute('SELECT * FROM users')
    users = c.fetchall()
    conn.close()
    return users

print(fetch_users())
```

実行結果：
```python
{'status': 'success', 'message': 'User 田中さん inserted.'}
[(1, '田中さん', 'tanaka@example.com')]
```

## 実装のポイント

1. セキュリティ対策としてプリペアドステートメントを使用
2. 関数の引数と返り値の型を明確に定義
3. データベース接続の適切なクローズ処理

## 発展的な活用方法

- CRUD操作の完全実装
- WebアプリケーションやChatbotとの統合
- バッチ処理への応用

## まとめ
Function Callingを活用することで、自然言語でのデータベース操作が実現可能になります。本実装例をベースに、より高度なデータベース操作システムを構築できます。