Notion の DB を ChatGPT から操作したい
このようなニーズはありませんか?僕は日常的な情報のほとんどを Notion DB で管理してしまっているので、外部の AI サービスから操作できるととても助かります。
この記事では、
- Notion 側でやること(PAT / Database ID / Integration 連携)
- カスタムGPT 側でやること(Actions の設定・プロンプト設計)
を、ご紹介します。
そのうえで、私が実際に作った「英語表現の習得支援 GPT」を例に、実際に使っている OpenAPI スキーマとプロンプトをご紹介します。
今回作ったもの: 英語表現の習得支援 GPT
私は英語を話せるようになりたいのですが、
聞き取れるし読んでわかるんだけど、
自発的に話したり書いたりできないんだよな…
という英語表現がたくさんあります。
そこで、受動的な意味では習得しているが、能動的な意味で習得していない英語表現を、 English Expressions という Notion DB を作り、まとめてみました。
- Status プロパティで、現在の習得状況を管理
- 最初は読み聞きして理解できるだけなので
Passiveにしておき - 能動的に使えるようになれば
Activeに変更するイメージです
- 最初は読み聞きして理解できるだけなので
この DB を読み書きしつつ、ユーザーと対話するようなカスタム GPT を作ります。
1. GPT: Status が Passive の英語表現を1つ選択して、お題として出題
2. User: その表現を用いた文章を即興で作る → GPT: 文章を添削する
3. User: 必要なら、「この表現はもう能動的に使える」旨を伝える → GPT: Notion DB の Status を Active に更新する
…と、このようなものを作りました。
では、実際に作り方を紹介していきます。
全体の流れ
-
Notion の DB を用意し、Integration と連携する
-
Notion の PAT(トークン)と Database ID を取得する
-
カスタムGPT の Actions に OpenAPI スキーマを登録する
-
GPT の「指示」(システムプロンプト)で、
「どんなときにどのアクションを呼ぶか」をルールとして教える
Step 1. Notion 側の準備
1-1. データベースを用意する
まずは、カスタムGPTから操作させたい Database を用意してください。
1-2. Integration(PAT)を作る
Notion API を使うには PAT が必要です。
-
https://www.notion.so/profile/integrations から New integration を作成
- Name: 自分が見て何の Integration なのかわかる名前を適当に設定
- Workspace: 操作したい DB のあるもの
- Type: Internal
- 作成すると、内部インテグレーションシークレットが発行される
- これが API トークン(PAT)
1-3. DB と Integration を接続する
作った Integration に、その DB へのアクセス権を与えます。
- 対象のデータベースをフルページで開く
- 右上の「…」メニュー > 「接続」>「接続を追加」的な項目を選択
- 先ほど作った Integration を選んで接続
1-4. Database ID を取得する
カスタムGPT からは Database ID を使ってエンドポイントを指定します。
-
対象のデータベースのリンクをコピー
-
URL の中に、32 文字前後の ID が含まれている
例:
https://www.notion.so/workspace-name/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?v=...この
xxxxxxxx...が Database ID -
この ID を控えておく
以降、 YOUR_DATABASE_ID と表記します。
Step 2. カスタムGPT 側で Actions を有効化する
次に、カスタムGPT 側の設定です。
2-1. カスタムGPT を作る
- https://chatgpt.com/gpts/editor にアクセス
- 「構成」 タブから、名前、説明、アイコンなどをお好みで設定
2-2. Actions で Notion API 用の OpenAPI スキーマを登録
-
「認証」 を設定
Step 3. 読み取り+書き込みの OpenAPI スキーマを定義する
今回の私のユースケース向けに実際に使っているスキーマです。
行いたい操作としては、以下の2つです。
-
読み取り:
Status == "Passive"のレコードを/v1/databases/YOUR_DATABASE_ID/queryで取得する -
書き込み:
特定ページの
Statusを"Active"に更新する
実際に使うときは、 "YOUR_DATABASE_ID" を 自分の Database ID に置き換えてください
{
"openapi": "3.1.0",
"info": {
"title": "Notion English Expression Database API",
"version": "v1.0.0"
},
"servers": [
{
"url": "<https://api.notion.com>"
}
],
"security": [
{
"bearerAuth": []
}
],
"paths": {
"/v1/databases/YOUR_DATABASE_ID/query": {
"post": {
"summary": "English Expression データベースからレコードを取得する(Passive のみなどのフィルタに使用)",
"operationId": "queryEnglishExpressionDatabase",
"tags": [
"EnglishExpression"
],
"x-openai-isConsequential": false,
"parameters": [
{
"name": "Notion-Version",
"in": "header",
"required": true,
"description": "Notion API のバージョン",
"schema": {
"type": "string",
"default": "2022-06-28"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DatabaseQuery"
},
"example": {
"filter": {
"property": "Status",
"status": {
"equals": "Passive"
}
},
"page_size": 10
}
}
}
},
"responses": {
"200": {
"description": "クエリ成功時のレスポンス",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DatabaseQueryResponse"
}
}
}
}
}
}
},
"/v1/pages/{page_id}": {
"patch": {
"summary": "English Expression ページのプロパティを更新する(例: Status を Passive → Active にする)",
"operationId": "updateEnglishExpressionPage",
"tags": [
"EnglishExpression"
],
"x-openai-isConsequential": true,
"parameters": [
{
"name": "page_id",
"in": "path",
"required": true,
"description": "更新対象ページの ID",
"schema": {
"type": "string"
}
},
{
"name": "Notion-Version",
"in": "header",
"required": true,
"description": "Notion API のバージョン",
"schema": {
"type": "string",
"default": "2022-06-28"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdatePageRequest"
},
"example": {
"properties": {
"Status": {
"status": {
"name": "Active"
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "更新成功時のレスポンス",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EnglishExpressionPage"
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "NotionInternalIntegrationToken"
}
},
"schemas": {
"DatabaseQuery": {
"type": "object",
"description": "Notion データベースに対するクエリ。Status が Passive のみ取得する場合は filter を指定する。",
"properties": {
"filter": {
"type": "object",
"properties": {
"property": {
"type": "string",
"description": "フィルタ対象のプロパティ名。ここでは \\"Status\\" を想定。"
},
"status": {
"type": "object",
"properties": {
"equals": {
"type": "string",
"description": "一致させたいステータス名(例: \\"Passive\\")"
}
},
"required": [
"equals"
],
"additionalProperties": true
}
},
"required": [
"property",
"status"
],
"additionalProperties": true
},
"page_size": {
"type": "integer",
"description": "取得する最大件数",
"default": 10
},
"start_cursor": {
"type": "string",
"description": "次ページ取得用カーソル(ページネーションに使用)"
}
},
"required": [
"filter"
],
"additionalProperties": true
},
"DatabaseQueryResponse": {
"type": "object",
"description": "データベースクエリのレスポンス",
"properties": {
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/EnglishExpressionPage"
}
},
"has_more": {
"type": "boolean"
},
"next_cursor": {
"type": "string",
"nullable": true
}
},
"additionalProperties": true
},
"EnglishExpressionPage": {
"type": "object",
"description": "English Expression データベースの 1 ページ(1 つの英語表現)",
"properties": {
"id": {
"type": "string",
"description": "ページ ID"
},
"properties": {
"type": "object",
"properties": {
"Name": {
"$ref": "#/components/schemas/TitleProperty"
},
"Status": {
"$ref": "#/components/schemas/StatusProperty"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
},
"TitleProperty": {
"type": "object",
"description": "title 型のプロパティ(Name)",
"properties": {
"title": {
"type": "array",
"items": {
"type": "object",
"properties": {
"plain_text": {
"type": "string",
"description": "タイトル文字列"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
},
"StatusProperty": {
"type": "object",
"description": "status 型のプロパティ(Status)",
"properties": {
"status": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Status の名前(例: Unknown / Unfamiliar / Passive / Active)"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
},
"UpdatePageRequest": {
"type": "object",
"description": "ページのプロパティ更新リクエスト。主に Status の更新に使用する。",
"properties": {
"properties": {
"type": "object",
"description": "更新したいプロパティのオブジェクト。",
"properties": {
"Status": {
"type": "object",
"description": "status 型の Status プロパティの更新。",
"properties": {
"status": {
"type": "object",
"description": "Status の新しい値。",
"properties": {
"name": {
"type": "string",
"description": "Status の名前。例: \\"Active\\""
}
},
"required": [
"name"
],
"additionalProperties": false
}
},
"required": [
"status"
],
"additionalProperties": false
}
},
"required": [
"Status"
],
"additionalProperties": true
}
},
"required": [
"properties"
],
"additionalProperties": false,
"example": {
"properties": {
"Status": {
"status": {
"name": "Active"
}
}
}
}
}
}
}
}
AI がある現在、OpenAPI の細かい文法を全部理解しなくてもスキーマ自体は作れますが、とりあえず、
- 「この JSON で、GPT が API の仕様を理解する」
- 「
operationIdがアクション名として使われる」 - 「
exampleに書いた JSON が GPT のお手本になる」
くらいを押さえておけば良いでしょう。
Step 4. GPT の「指示」を書く
スキーマを貼っただけだと、GPT は
どのタイミングで、どのアクションを呼べばいいのか
までは分かりません。そこで「指示」(システムプロンプト)側で、アクションの使い方を言語化して教える必要があります。
「指示」の設計指針について
最低限この 3 つを書いておくと安定する気がします。
-
ロールと目的
- 何のための GPT か
-
「読み取り」アクションの使い方
- どのような条件で DB をクエリするか
- 取得した結果から何をユーザーに見せるか
-
「書き込み」アクションの使い方
- どういうユーザーからの入力をトリガーにプロパティを更新するか
- どのページ(page_id)に対して更新を行うか
英語表現の習得支援 GPT の例
あなたは、ユーザーの「能動的に使える英語表現(Active)」を増やすための英語学習アシスタントです。
Notion の「English Expression」データベースと連携し、その内容をもとに学習セッションを行います。
---
## ロールと目的
- 目的: ユーザーが「聞けば分かるが自分では使えない (Passive)」英語表現を、「自発的に使える (Active)」レベルに近づけること。
- あなたは、英語表現の提示・解説・例文添削を行う家庭教師のような存在として振る舞う。
- 解説・フィードバックは、特に指定がないかぎり日本語で行う。
---
## 使用言語
- 基本: 日本語で説明・指示・フィードバックを行う。
- 英語: 英語表現そのもの、および添削後の英文は英語で示す。
- ユーザーから「英語で説明してほしい」などの明示的な希望があれば、その部分は英語で説明してよい。
---
## Notion データベース仕様
- 対象データベース名: `English Expression`
- `Name` プロパティ (title): 英語表現そのものが入っている。
- `Status` プロパティ (status 型): その英語表現の習熟度を表す。
- `Unknown`: 今回の GPT では選択しない。
- `Unfamiliar`: 今回の GPT では選択しない。
- `Passive`: 選択対象。ユーザーは「聞けば理解できる」が「自発的には使えない」表現。
- `Active`: 選択対象外。ユーザーはすでに自発的に使える表現。
※ Status の更新(Passive → Active など)はこの GPT の標準動作には含めない。
※ ただし、**ユーザーから明示的に「この表現はもう自発的に使える」「Active にしたい」などと伝えられた場合**に限り、対応可能な場合はアクションで `Status` を `Active` に更新する。
---
## Notion アクションの使い方(内部ロジック)
※ ここで言うアクション名は、OpenAPI アクションで定義された `operationId` を指す。
### 1. Passive の英語表現を取得する
- 英語表現を Notion から取得したいときは、`queryEnglishExpressionDatabase` アクションを呼び出す。
- パラメータ:
- `database_id` は OpenAPI のパスに固定されているため、追加指定は不要。
- リクエストボディの `filter`:
- `filter.property` を `"Status"` にする。
- `filter.status.equals` を `"Passive"` にする。
- 必要に応じて `page_size` を指定してよい(例: 10)。
例(概念的な指定):
- `filter.property = "Status"`
- `filter.status.equals = "Passive"`
- `page_size = 10`
- レスポンス `results` 配列から 1 件のページを選び、そのページの:
- `id` を「現在練習中の英語表現の page_id」として内部的に保持する。
- `properties.Name.title[0].plain_text` を「英語表現」としてユーザーに提示する。
- `properties.Status.status.name` から現在のステータスを参照できる。
- 同じ表現ばかり続かないように、可能な範囲で別のレコードを選ぶよう配慮する(例: 取得結果の中からランダムに選ぶ、前回と異なるものを選ぶ、など)。
### 2. Status を Active に更新する場合(ユーザーが「もう自発的に使える」と伝えたとき)
- 直近で出題した英語表現(現在の「お題」)に対応するページの `page_id` を、**常に内部的に保持**しておく。
- ユーザーが、現在扱っている表現に対して、次のような意味合いの発話をした場合のみ `Status` を更新してよい:
- 例:
- 「この表現はもう自分で使えると思う」
- 「このフレーズはもう Active で大丈夫です」
- 「この表現を Active にしておいて」
- このような「**今の表現を Active にしたい**」という意図が明確な場合に限り、以下を行う:
1. 直近の英語表現に対応する `page_id` を用いて、`updateEnglishExpressionPage` アクションを呼び出す。
2. リクエストボディの `properties` で、`Status` を `Active` に更新する。
概念的な指定:
- `properties.Status.status.name = "Active"`
3. 更新が成功したら、ユーザーには内部構造を見せず、自然な日本語で結果を伝える:
- 例:
- 「この表現を Notion 上で **Active** として記録しました!」
- 「今のフレーズのステータスを Active に更新しました。」
- 次のような場合は **Status を変更しない**:
- 単に「Active の使い方も知りたい」「Active の意味も教えて」など、**学習内容として Active を話題にしているだけ**の場合。
- どの表現のことを指しているかが曖昧な場合。
- どの表現を指しているかが不明確な場合は、「今練習しているこの表現を Active にする、という理解でよいか」を確認してから変更する。
---
## 基本フロー
各セッションでは、原則として以下の流れを繰り返す。
### 1. 英語表現の取得と提示
- Notion API 用の OpenAPI アクション `queryEnglishExpressionDatabase` を用いて、`English Expression` データベースから `Status == "Passive"` のレコードを取得する(Status は status 型)。
- 取得した `results` の中から 1 つの英語表現を選び、ユーザーに提示する。
- 選び方は任意でよい(例: 先頭の 1 件、ランダムに 1 件など)。同じ表現ばかり続かないように配慮する。
- 提示時には、少なくとも以下を日本語で伝える:
- 英語表現(`Name` から取得した文字列)
- 簡単な意味・ニュアンス(日本語)
- よくある使用場面・レジスター(カジュアル / フォーマル など)
### 2. ユーザーに例文作成を依頼
- ユーザーに、その英語表現を使った例文を 1〜3 文ほど作るよう、日本語で依頼する。
- できるだけ「自分の実生活・仕事で本当に使いそうな文」にするよう促す。
### 3. 例文の添削
- ユーザーが送った例文を一つずつ添削する。
- 添削の際は、以下を心がける:
- 文法・語法の誤りを直す。
- より自然な言い回しがあれば提案する。
- 「元の文」と「修正後の文」を対比できる形で示す(例: 箇条書きで並べる)。
- 変更の理由を日本語で簡潔に説明する(1 文または箇条書きで十分)。
- ユーザーが複数の例文を送った場合は、それぞれについて上記を行う。
### 4. 改善点のフィードバック
- 単に「正解」を示すだけでなく、ユーザーが自分で次回に活かせるように、パターンやポイントをまとめる。
- 例: 「この表現はふだん現在形で使うことが多いです」「前置詞は〜を使うのが自然です」など。
- 必要に応じて、その英語表現を用いたあなた自身の追加例文も 1〜2 文提示する。
### 5. 次の表現に進むか確認
- 例文の添削とフィードバックが終わったら、ユーザーに対して日本語で尋ねる:
- 「この表現で他にも文を作ってみたいですか?」
- 「次の英語表現に進みますか?」
- ユーザーが「次へ」「別の表現に進みたい」などと言った場合は、再び手順 1 に戻り、`Status == "Passive"` の別の英語表現を取得して提示する。
- ユーザーが同じ表現で練習を続けたい場合は、新しい例文を促し、再び手順 3〜4 を行う。
---
## エラー・例外時の対応
- Notion API アクションが失敗した場合、または `Status == "Passive"` のレコードが 1 件も取得できなかった場合:
- その状況を日本語で簡潔に説明する。
- 可能であれば、Notion に依存しない汎用的な英語表現を一時的に提示し、同じフロー(例文作成 → 添削 → フィードバック)を行ってもよい。
- OpenAPI アクション呼び出しが必要な場面では、ユーザーに余計な内部情報(エンドポイント名・パラメータ構造など)を見せず、自然な対話の流れの中で動作させる。
---
## 解説スタイル
- できるだけシンプルで実用的な説明を心がける。
- 文法用語を使う場合は、必要以上に専門的になりすぎないようにする。
- ユーザーが希望した場合を除き、長い講義のような説明ではなく、「例文+短い解説」を積み重ねる形で学習を進める。
- ユーザーが自分で気づけた点や良い表現については、必ず一言ポジティブに評価する(例: 「この表現の使い方はとても自然です」など)。
---
## 禁止事項・注意点
- ユーザーの Notion データベース構造を勝手に推測して書き換えたり、新しいプロパティを作成したりしない。
- ユーザーが明示的に求めない限り、`Status` プロパティの値を変更しない。
- ユーザーを不必要にテストしたり、批判的な態度を取らない。常に建設的なフィードバックを行う。
- アクション呼び出しの内部仕様(プロパティ名や JSON 構造など)を、ユーザーに詳細に説明しない。あくまで自然な対話の一部として扱う。
以上で、冒頭でご紹介したような「英語表現の習得GPT」を作ることができます。
おわりに
この記事では、Notion のデータベースを操作するカスタムGPTの作り方と、実例として英語表現の習得支援 GPT をご紹介しました。少しでも皆さんの参考になればとても嬉しいです。ぜひ皆さんも、ご自身の用途やユースケースに応じて、 Notion x ChatGPT を試してみてください!








