この記事は、社内のAI運用ルールを 公開できるテンプレート としてGitHubに置くための実装メモです。
AI APIの呼び出しや、自動返信の実装は扱いません。先に、README、設定ファイル、サンプルCSV、ローカルチェック、Google Apps Scriptの取り込み口を用意し、個別顧客データを入れずに再利用できる形を作ります。
作るもの
小さなテンプレートリポジトリを作ります。
ai-ops-template/
README.md
config/
ai-ops-policy.yml
samples/
inquiry-log.sample.csv
review-rules.sample.csv
scripts/
check-template.js
gas/
importReviewRules.gs
package.json
目的は、AI導入の成果物を「個別案件のログ」ではなく「別チームでも使える運用テンプレート」に分けることです。
公開してよいもの、公開しないもの
最初に、公開テンプレートと非公開ログを分けます。
| 種類 | GitHub公開 | 理由 |
|---|---|---|
| READMEの運用手順 | 可 | 汎用ルールとして共有できる |
| サンプルCSV | 可 | 架空データだけなら再利用できる |
| review_requiredの判定条件 | 可 | 判断基準の型として使える |
| 顧客の問い合わせ本文 | 不可 | 個人情報や非公開情報を含む可能性がある |
| 実際の判断ログ | 原則不可 | 案件名、顧客名、内部判断が残る |
| APIキーや認証情報 | 不可 | 秘密情報 |
この線引きがないままテンプレートを作ると、あとから「便利なので実データも入れておこう」となりやすいです。
README.md
READMEは、使い方より先に境界を書きます。
# AI Ops Template
問い合わせ要約、FAQ候補作成、返信下書きなどでAIを使う前に、
人間確認と判断ログのルールを揃えるためのテンプレートです。
## このリポジトリに入れるもの
- 汎用的な確認ルール
- 架空データのサンプル
- ローカルチェック用スクリプト
- Google Apps Scriptの雛形
## このリポジトリに入れないもの
- 実際の顧客名、会社名、メールアドレス、電話番号
- 問い合わせ本文の原文
- 契約、請求、返金、法務判断の具体内容
- APIキー、Cookie、トークン、秘密鍵
- 社内だけで使う判断ログ
## AIへ送る前の確認
- 個人情報を含まない
- 秘密情報を含まない
- 契約、返金、法務判断をAIだけで決めない
- 外部送信前に人間が確認する
- 判断理由をログに残す
READMEの役割は、開発者だけでなく、運用担当者が見ても「ここには実データを入れない」と分かる入口にすることです。
config/ai-ops-policy.yml
次に、ルールを設定ファイルにします。
version: 1
public_repository:
allow_real_customer_data: false
allow_credentials: false
allow_internal_decision_logs: false
allowed_files:
- README.md
- config/ai-ops-policy.yml
- samples/*.sample.csv
- scripts/check-template.js
- gas/*.gs
blocked_terms:
- APIキー
- パスワード
- Cookie
- トークン
- 秘密鍵
- 顧客名
- 電話番号
- メールアドレス
review_rules:
- use_case: inquiry_summary
review_required_when:
- includes_personal_data
- includes_contract_or_refund
- customer_visible_output
- use_case: faq_candidate
review_required_when:
- includes_unverified_claim
- includes_private_customer_context
- use_case: reply_draft
review_required_when:
- always
required_log_fields:
- request_id
- source_type
- ai_use_case
- input_summary
- review_required
- reviewer
- decision
- decision_reason
- decided_at
ここでも実データは入れません。設定ファイルに入れるのは「運用の型」だけです。
samples/inquiry-log.sample.csv
サンプルCSVは、架空データだけで作ります。
request_id,source_type,ai_use_case,input_summary,review_required,reviewer,decision,decision_reason,decided_at
REQ-001,form,inquiry_summary,料金プランの違いについての質問,true,cs_owner,approved,公開情報だけで回答できるため,2026-06-30
REQ-002,email,reply_draft,返金条件に関する相談,true,business_owner,hold,契約条件の確認が必要,2026-06-30
REQ-003,form,faq_candidate,営業時間に関する質問,false,,approved,既存FAQと一致,2026-06-30
実際の問い合わせ原文ではなく、要約済みの架空例にします。
scripts/check-template.js
公開前に、テンプレートへ入れてはいけない語や不足ファイルを確認します。
const fs = require('fs');
const path = require('path');
const requiredFiles = [
'README.md',
'config/ai-ops-policy.yml',
'samples/inquiry-log.sample.csv',
'samples/review-rules.sample.csv',
'gas/importReviewRules.gs',
];
const blockedPatterns = [
/APIキー\s*[:=]/,
/password\s*[:=]/i,
/cookie\s*[:=]/i,
/token\s*[:=]/i,
/secret\s*[:=]/i,
/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,
/0\d{1,4}-\d{1,4}-\d{3,4}/,
];
function walk(dir) {
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const full = path.join(dir, entry.name);
if (entry.name === 'node_modules' || entry.name === '.git') return [];
return entry.isDirectory() ? walk(full) : [full];
});
}
let failed = false;
for (const file of requiredFiles) {
if (!fs.existsSync(file)) {
console.error(`missing required file: ${file}`);
failed = true;
}
}
for (const file of walk(process.cwd())) {
if (!/\.(md|yml|yaml|csv|js|gs)$/.test(file)) continue;
const body = fs.readFileSync(file, 'utf8');
for (const pattern of blockedPatterns) {
if (pattern.test(body)) {
console.error(`possible private data in ${file}: ${pattern}`);
failed = true;
}
}
}
if (failed) process.exit(1);
console.log('template check passed');
正規表現だけで完全に秘密情報を検出できるわけではありません。それでも、公開テンプレートに明らかな認証情報や個人情報が混ざる事故を減らせます。
package.json
チェックはnpm scriptにしておきます。
{
"name": "ai-ops-template",
"private": true,
"scripts": {
"check": "node scripts/check-template.js"
}
}
GitHub Actionsを使う場合も、この npm run check をそのまま呼べます。
gas/importReviewRules.gs
Googleスプレッドシートへ判定ルールを取り込む最小例です。
const REVIEW_RULES = [
{
useCase: 'inquiry_summary',
reviewRequiredWhen: [
'includes_personal_data',
'includes_contract_or_refund',
'customer_visible_output',
],
},
{
useCase: 'faq_candidate',
reviewRequiredWhen: [
'includes_unverified_claim',
'includes_private_customer_context',
],
},
{
useCase: 'reply_draft',
reviewRequiredWhen: ['always'],
},
];
function importReviewRules() {
const sheet = SpreadsheetApp.getActive().getSheetByName('review_rules')
|| SpreadsheetApp.getActive().insertSheet('review_rules');
sheet.clearContents();
sheet.appendRow(['use_case', 'condition']);
REVIEW_RULES.forEach((rule) => {
rule.reviewRequiredWhen.forEach((condition) => {
sheet.appendRow([rule.useCase, condition]);
});
});
}
ここでも、実際の顧客データや問い合わせ本文は扱いません。テンプレートから取り込むのは確認ルールだけです。
GitHub Actionsに載せる
公開リポジトリにするなら、チェックをPull Requestで動かします。
name: check
on:
pull_request:
push:
branches: [main]
jobs:
template-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci || npm install
- run: npm run check
テンプレートを配布する時は、READMEだけでなく「公開前チェックが通る状態」を成果物にします。
運用での使い分け
公開リポジトリと社内リポジトリは分けます。
| 置き場所 | 入れるもの |
|---|---|
| public template repo | 汎用ルール、架空サンプル、チェックツール |
| private ops repo | 実際の判断ログ、社内担当者、顧客別メモ |
| CRM/Sheets | 問い合わせごとのステータス、承認結果 |
公開テンプレートは、会社の運用を外に出すためのものではありません。社内で育った良い型だけを、個別情報を取り除いて再利用可能にするための置き場所です。
まとめ
GitHubでAI運用テンプレートを公開する時は、README、設定ファイル、架空サンプル、チェックスクリプト、GAS取り込み口を分けて作ると扱いやすくなります。
大切なのは、便利なテンプレートを作ることだけではなく、実データや判断ログを混ぜない境界を先に固定することです。
Miraigentでは、AI導入の前に、公開できる型と社内に残すべき判断ログを分けて整理します。テンプレート化は、その運用をチーム内で再現しやすくするための小さな土台です。
