Googleスプレッドシート×Python連携実装:ナレッジをリアルタイムに読み込むバックエンド構築

,
【連載】中小企業のための「AI社長」実践導入ガイド(全12回) | 今回は 第12回 です | 前の記事:第11回

第11回で設計したGoogleスプレッドシートを、AI社長のプログラムに直結させます。

ハードコード(プログラム内に直接記述)されたナレッジは、修正するたびにプログラムの再起動やサーバーへのデプロイが必要になります。しかし、Google Sheets APIを使って毎回リアルタイムにスプレッドシートからデータを取得する構成にすれば、シートを1行書き換えるだけで、次の瞬間のLINE返信から新しい判断基準が自動適用されます。

本記事では、GoogleスプレッドシートとPythonを連携させる実装コードと、社員からの相談ログをシートへ自動蓄積する改善ループの全貌を解説し、全12回の連載を総括します。

スプレッドシート連携のシステム処理フロー

社員からLINEで相談が届いたとき、サーバー内部では以下のステップで処理が進行します。

リアルタイム連携の4ステップ

  1. LINEメッセージ受信:社員から相談内容とUser IDを受信。
  2. スプレッドシートから動的取得:「社員権限」「最新KPI」「社長判断基準」をSheets APIで即座に取得。
  3. 動的プロンプトの組み立て:取得した最新データと社員の相談を組み合わせてOpenAI APIへ送信。
  4. 相談ログの自動追記:社員の相談とAI社長の回答を、スプレッドシートの「相談ログ」シートに自動で1行追記。

準備:Google Sheets APIのサービスアカウント設定

PythonからGoogleスプレッドシートを安全に読み書きするために、「Google Cloud Console」でサービスアカウントを作成し、JSON鍵ファイル(credentials.json)をダウンロードします。

手順の概要

  1. Google Cloud Consoleでプロジェクトを作成し、「Google Sheets API」を有効化する。
  2. 「サービスアカウント」を作成し、キー(JSON)をダウンロードしてサーバーに配置する。
  3. 作成したGoogleスプレッドシートの「共有」ボタンを押し、サービスアカウントのメールアドレス(xxxx@xxxx.iam.gserviceaccount.com)に「編集者」権限を付与する。

必要なライブラリのインストール

pip install fastapi uvicorn line-bot-sdk openai gspread oauth2client

完成版:スプレッドシート連携AI社長バックエンドコード

スプレッドシートからナレッジを取得し、相談ログを自動記録する完全な実装例です。

import os
from datetime import datetime
from fastapi import FastAPI, Request, Header, HTTPException
from linebot.v3.webhook import WebhookParser
from linebot.v3.messaging import (
    AsyncApiClient,
    AsyncMessagingApi,
    Configuration,
    ReplyMessageRequest,
    TextMessage
)
from linebot.v3.exceptions import InvalidSignatureError
from openai import OpenAI
import gspread
from oauth2client.service_account import ServiceAccountCredentials

app = FastAPI()

# 1. 認証情報
CHANNEL_SECRET = os.getenv("LINE_CHANNEL_SECRET", "your_channel_secret")
CHANNEL_ACCESS_TOKEN = os.getenv("LINE_CHANNEL_ACCESS_TOKEN", "your_access_token")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "your_openai_api_key")
SPREADSHEET_KEY = os.getenv("SPREADSHEET_KEY", "your_google_spreadsheet_id")

line_config = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
parser = WebhookParser(CHANNEL_SECRET)
client_ai = OpenAI(api_key=OPENAI_API_KEY)

# 2. Googleスプレッドシート接続クライアント
scope = [
    "https://spreadsheets.google.com/feeds",
    "https://www.googleapis.com/auth/drive"
]
creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
gc = gspread.authorize(creds)
doc = gc.open_by_key(SPREADSHEET_KEY)

def get_authorized_users():
    sheet = doc.worksheet("LINE_Users")
    records = sheet.get_all_records()
    users = {}
    for r in records:
        uid = str(r.get("LINE_User_ID", "")).strip()
        if uid:
            users[uid] = {
                "name": r.get("氏名", "社員"),
                "role": r.get("役職", "一般"),
                "dept": r.get("担当部署", "全社")
            }
    return users

def get_latest_knowledge():
    rules_sheet = doc.worksheet("Decision_Rules")
    rules = rules_sheet.get_all_records()
    rules_text = "\n".join([
        f"・【{r.get('カテゴリ')}】{r.get('相談内容')} → 判断:{r.get('社長の判断')}(理由:{r.get('確認ステップ・例外')})"
        for r in rules
    ])

    kpi_sheet = doc.worksheet("Daily_KPI")
    kpis = kpi_sheet.get_all_records()
    latest_kpi = kpis[-1] if kpis else {}
    kpi_text = f"売上:{latest_kpi.get('今月売上')}、粗利率:{latest_kpi.get('粗利益率')}、空室数:{latest_kpi.get('空室数')}"

    return rules_text, kpi_text

def append_consultation_log(user_id, name, msg, answer):
    try:
        log_sheet = doc.worksheet("Consultation_Logs")
        now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_sheet.append_row([now_str, user_id, name, msg, answer])
    except Exception as e:
        print(f"Log append error: {e}")

@app.post("/webhook")
async def handle_webhook(request: Request, x_line_signature: str = Header(None)):
    if not x_line_signature:
        raise HTTPException(status_code=400, detail="Missing Signature")

    body = await request.body()
    body_str = body.decode("utf-8")

    try:
        events = parser.parse(body_str, x_line_signature)
    except InvalidSignatureError:
        raise HTTPException(status_code=400, detail="Invalid Signature")

    auth_users = get_authorized_users()

    async with AsyncApiClient(line_config) as api_client:
        line_api = AsyncMessagingApi(api_client)

        for event in events:
            if event.type != "message" or event.message.type != "text":
                continue

            user_id = event.source.user_id
            user_msg = event.message.text
            reply_token = event.reply_token

            # A. 認証チェック
            if user_id not in auth_users:
                await line_api.reply_message(
                    ReplyMessageRequest(
                        reply_token=reply_token,
                        messages=[TextMessage(text="社内専用アカウントです。利用権限がありません。")]
                    )
                )
                continue

            emp = auth_users[user_id]
            emp_name = emp["name"]
            emp_role = emp["role"]

            # B. 最新ナレッジと数字の動的取得
            rules_text, kpi_text = get_latest_knowledge()

            system_prompt = f"""
あなたは「○○不動産株式会社」のAI社長(山田社長の分身)です。
以下の最新判断基準と現在の数字を厳格に踏まえて回答してください。

【現在の経営数字】
{kpi_text}

【社長の最新判断基準】
{rules_text}

【行動原則】
1. 安易な値引きは原則禁止。「価値・広告・見せ方・競合・営業」を先に確認させる。
2. 100万円以上の支出や正式な契約判断は人間(社長)の決裁を必須とする。
3. 担当部署(営業部・管理部・経理)を明確に案内する。
"""

            try:
                res = client_ai.chat.completions.create(
                    model="gpt-4o-mini",
                    messages=[
                        {"role": "system", "content": system_prompt},
                        {"role": "user", "content": f"相談者:{emp_name}({emp_role})\n相談内容:{user_msg}"}
                    ],
                    temperature=0.3
                )
                ai_answer = res.choices[0].message.content
            except Exception as e:
                ai_answer = "回答生成中にエラーが発生しました。"

            # C. 相談ログをスプレッドシートへ自動追記
            append_consultation_log(user_id, emp_name, user_msg, ai_answer)

            # D. LINE返信
            await line_api.reply_message(
                ReplyMessageRequest(
                    reply_token=reply_token,
                    messages=[TextMessage(text=ai_answer)]
                )
            )

    return "OK"

自動蓄積された「相談ログ」から組織の課題が見える

このシステムを稼働させると、スプレッドシートの「Consultation_Logs」シートに現場のリアルな相談が自動で蓄積されていきます。

週末にこのログを眺めるだけで、社長は以下のような重要な発見を得られます。

相談ログから得られる経営の気付き

  • 現場が迷っているルールの空白:「リフォームの値引き相談が週に3件も来ている。基準を明文化してシートに足しておこう。」
  • マニュアルの不備:「鍵交換の手順について複数人が質問している。管理部マニュアルを改善しよう。」
  • 社員の積極的な挑戦:「若手社員が新規提案について自発的にAI社長へ相談している。」

全12回連載の総括:自走する組織の完成へ

全12回にわたり、構想・情報設計・セキュリティ・LINE実装・データ管理・運用自動化まで、中小企業が「AI社長」を真に使いこなすための全プロセスを解説してきました。

AI社長の導入とは、単に便利なツールをひとつ増やすことではありません。

「社長の頭の中にある判断基準や経営哲学を言語化し、Googleスプレッドシートという身近な資産に落とし込み、現場社員がスマホから毎日参照できるようにする」という、究極の経営承継・組織自走化プロジェクトです。

ぜひ、まずは1枚のスプレッドシートと最小限のナレッジから、貴社専属のAI社長を育て始めてみてください。

【全12回連載目次】中小企業のための「AI社長」実践導入ガイド

  1. 第1回:なぜ会社の情報を全部入れてはいけないのか?4つの情報分類と成功の骨格
  2. 第2回:普通のAIと「AI社長」を分けるもの:最重要ナレッジ「社長の判断基準」の言語化
  3. 第3回:思考と価値観を抽出する「社長への100問」:判断基準ファイルの作り方と実践質問集
  4. 第4回:組織図と役割分担の設計:AI社長が「誰に頼めばよいか」を迷わず案内する仕組み
  5. 第5回:失敗事例の蓄積と「禁止事項」:AI社長の経験値と絶対に譲れない境界線
  6. 第6回:プロンプトをパンクさせない3層システム設計:System Prompt・RAG・リアルタイムAPIの住み分け
  7. 第7回:なぜ「個人LINE+公式アカウント」なのか?中小企業の導入ハードルを下げる構成論
  8. 第8回:社内限定運用のセキュリティ設計:LINE User ID制限と社員認証コードによるアクセス制御
  9. 第9回:Pythonで作るLINE AI社長:Messaging APIとLLMをつなぐバックエンド実装
  10. 第10回:現場に定着するリッチメニューUIと、会社と共に育つナレッジ更新サイクル
  11. 第11回:ナレッジの保管場所とデータ管理術:GoogleスプレッドシートとGoogleドライブをAI社長の「記憶庫」にする方法
  12. 第12回:Googleスプレッドシート×Python連携実装:ナレッジをリアルタイムに読み込むバックエンド構築 現在の記事

eguchi.netをもっと見る

購読すると最新の投稿がメールで送信されます。