--- title: スキルとエージェント description: アプリ向けの AI のスキルとエージェントを定義します。 icon: robot --- スキルとエージェントは現在アルファ版です。 この機能は動作しますが、まだ進化の途上です。 アプリは、ワークスペース内で動作する AI 機能 — 再利用可能なスキルの指示やカスタムのシステムプロンプトを持つエージェントを定義できます。 スキルは、ワークスペース内で AI エージェントが利用できる再利用可能な指示と機能を定義します。 組み込み検証付きでスキルを定義するには `defineSkill()` を使用します: ```ts src/skills/example-skill.ts import { defineSkill } from 'twenty-sdk/define'; export default defineSkill({ universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', name: 'sales-outreach', label: 'Sales Outreach', description: 'Guides the AI agent through a structured sales outreach process', icon: 'IconBrain', content: `You are a sales outreach assistant. When reaching out to a prospect: 1. Research the company and recent news 2. Identify the prospect's role and likely pain points 3. Draft a personalized message referencing specific details 4. Keep the tone professional but conversational`, }); ``` 主なポイント: * `name` はスキルの一意の識別子文字列です(kebab-case を推奨)。 * `label` は、UI に表示される人間が読める表示名です。 * `content` にはスキルの指示が含まれます — これは AI エージェントが使用するテキストです。 * `icon`(任意)は、UI に表示されるアイコンを設定します。 * `description`(任意)は、スキルの目的に関する追加のコンテキストを提供します。 エージェントは、ワークスペース内で動作する AI アシスタントです。 カスタムのシステムプロンプトでエージェントを作成するには `defineAgent()` を使用します: ```ts src/agents/example-agent.ts import { defineAgent } from 'twenty-sdk/define'; export default defineAgent({ universalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123', name: 'sales-assistant', label: 'Sales Assistant', description: 'Helps the sales team draft outreach emails and research prospects', icon: 'IconRobot', prompt: 'You are a helpful sales assistant. Help users with their questions and tasks.', }); ``` 主なポイント: * `name` はエージェントの一意の識別子文字列です(kebab-case を推奨)。 * `label` は UI に表示される表示名です。 * `prompt` はエージェントの動作を定義するシステムプロンプトです。 * `description`(任意)は、エージェントが何を行うかのコンテキストを提供します。 * `icon`(任意)は、UI に表示されるアイコンを設定します。 * `modelId`(任意)は、エージェントが使用するデフォルトの AI モデルを上書きします。 * `responseFormat`(オプション)は、エージェントの出力の形式を制御します。 自由形式テキストの場合、デフォルトは `{ type: 'text' }` です。 構造化された JSON 出力を強制するには、`{ type: 'json', schema }` を使用します。 デフォルトでは、エージェントは自由形式テキストを返します。 構造化された出力を取得するには、`responseFormat` を `{ type: 'json' }` に設定し、`schema` を指定します: ```ts src/agents/structured-agent.ts import { defineAgent } from 'twenty-sdk/define'; export default defineAgent({ universalIdentifier: 'c4d5e6f7-a8b9-0123-cdef-456789012345', name: 'lead-scorer', label: 'Lead Scorer', prompt: 'Score the lead and explain your reasoning.', responseFormat: { type: 'json', schema: { type: 'object', properties: { score: { type: 'number', description: 'Lead score from 0 to 100' }, summary: { type: 'string', description: 'Short reasoning for the score' }, }, required: ['score', 'summary'], additionalProperties: false, }, }, }); ``` スキーマに関する補足: * スキーマはフラットなオブジェクトであり、各プロパティの `type` はプリミティブ型(`string`、`number`、`boolean` のいずれか)でなければなりません。 ネストされたオブジェクトおよび配列はサポートされていません。 * 各プロパティの `description`(オプション)は、そのプロパティに何を入れるべきかをモデルに示します。 * `required`(オプション)は、モデルが常に返さなければならないプロパティを列挙します。 * `additionalProperties: false`(オプション)は、`properties` に宣言されていないプロパティを禁止します。 `runAgent()` を使用すると、ロジック関数からアプリのエージェント(そのスキルやツールを含む)を実行できます。 `defineAgent()` に渡した `universalIdentifier` でエージェントを識別します。 `prompt` 文字列または会話履歴である `messages` のいずれか一方のみを渡してください。両方は渡さないでください。 ```ts src/logic-functions/run-enricher.ts import { runAgent } from 'twenty-sdk/logic-function'; const { result, error, success } = await runAgent({ agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123', prompt: 'Enrich House Ad : fill empty fields from its listing URL.', }); ``` マルチターンのボット (Slack、Discord、Teams など) の場合は、単一の `prompt` ではなく、スレッド履歴を `messages` として渡してください。 ```ts src/logic-functions/reply-in-thread.ts import { runAgent } from 'twenty-sdk/logic-function'; const { result, error, success } = await runAgent({ agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123', messages: [ { role: 'user', content: 'Who owns Acme?' }, { role: 'assistant', content: 'Sarah owns the Acme account.' }, { role: 'user', content: 'What was the last touchpoint?' }, ], }); ``` 主なポイント: * `prompt` (string) または `messages`(1~100 個の `{ role: 'user' | 'assistant', content: string }` エントリ)のうち、**ちょうど一つだけ**を指定してください。 * エージェントは**同期的に**実行され、自身のツールを通じてレコードの読み取り/更新ができます。`runAgent()` は、実行が完了すると解決されます。 * アプリは自分自身のエージェントのみを実行できます。 * アプリの[デフォルトロール](/l/ja/developers/extend/apps/config/roles)には `AI` パーミッションフラグが付与されている必要があります — その `permissionFlagUniversalIdentifiers` に `SystemPermissionFlag.AI` を追加するか(または `canAccessAllTools: true` を設定します)。 これがない場合、`runAgent()` はパーミッションエラーで失敗します。 * ロジック関数には十分に長い `timeoutSeconds` を設定してください — エージェントの実行には数秒かかることがあります。 * 実行が完了すると `success` は `true` になり、`result` は null 以外になります。失敗時には `success` は `false`、`result` は `null` で、`error` に理由が入ります(たとえば、実行の途中でワークスペースの AI クレジットが不足した場合など)。 ```ts src/roles/default-role.ts import { defineApplicationRole, SystemPermissionFlag } from 'twenty-sdk/define'; export default defineApplicationRole({ universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061', label: 'Default function role', // runAgent() requires the AI permission flag on the app's default role. permissionFlagUniversalIdentifiers: [SystemPermissionFlag.AI], }); ``` **ループを避けてください:** `*.updated` データベースイベントトリガーから `runAgent()` を呼び出し、そのエージェントが同じレコードを更新する場合、`updatedFields` を使ってエージェントが決して書き込まないフィールド(例: ソース URL)にスコープするか、`runAgent()` を呼び出す前に、対象フィールドのいずれかがまだ空であるかどうかを判定してガードしてください。 ### ワークスペースメンバーを代理して実行する場合 実行が人によってトリガーされた場合 — たとえばメッセージに返信するチャットボットなど — には、`runAsWorkspaceMemberId` を渡して、そのエージェントがアプリとしてではなく、そのメンバーとして動作するようにします。 ```ts src/logic-functions/answer-question.ts const { result } = await runAgent({ agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123', prompt: 'How many open opportunities do we have?', runAsWorkspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', }); ``` この実行はその後、**メンバー自身のロール**で動作します。そのメンバーができることだけを実行でき、それ以上のことはできません。作成されたレコードはそのメンバーに帰属し、そのメンバーの行レベル権限が適用されます。 エージェントのロールは関与しません。これは、背後に誰もいない実行に対するアプリのデフォルトです。 自律的な実行(スケジュールされたジョブ、データベースイベントトリガー)の場合は、そのフィールドを省略します。この場合、エージェント自身のロールが維持されます。 動作中のアプリケーションは、メンバーの権限を狭めることなく、プロビナンスのために実行のコンテキストに紐づいたままになります。 実行をトリガーした人物を、どのワークスペースメンバーに対応付けるかは、あなたのアプリ側の責任です。 メンバーを指定するにはアプリアクセストークンが必要であり、トークンで指定できるメンバーは、そのトークンにユーザーが紐づいているかどうかに依存します。 * ユーザーが紐づいていないトークンは、任意のメンバーを指定できます。 ロジック関数はそのようなトークンで実行され、`client_credentials` を通じて、または API キーから発行されたトークンも同様です。 * フロントコンポーネントが受け取るような、ユーザーを代表して発行されたトークンは、そのユーザー自身のメンバーのみを指定できます。 それ以外、つまり通常のユーザーセッションやアプリアクセストークンを伴わない API キーは、メンバーをまったく指定できません。 `runAgent()` は、ワークスペースメンバーを解決できない場合(不明または削除されたメンバー、あるいはロールを持たないメンバー)に例外をスローします。 呼び出し元が要求した以上のアクセス権を与えてしまうことになるため、 エージェント自身のロールにフォールバックすることは決してありません。