> ## Documentation Index
> Fetch the complete documentation index at: https://twenty-claude-cool-pascal-5ay683.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 技能与智能体

> 为你的应用定义 AI 技能和智能体。

<Warning>
  技能和智能体目前处于 Alpha 阶段。 该功能可用，但仍在演进中。
</Warning>

应用可以定义存在于工作区内的 AI 能力——可复用的技能指令以及具有自定义系统提示词的智能体。

<AccordionGroup>
  <Accordion title="defineSkill" description="定义 AI 智能体技能">
    技能定义了可复用的指令和能力，AI 智能体可在你的工作区中使用。 使用 `defineSkill()` 定义带内置校验的技能：

    ```ts src/skills/example-skill.ts theme={null}
    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`（可选）提供有关技能用途的更多上下文。
  </Accordion>

  <Accordion title="defineAgent" description="使用自定义提示词定义 AI 智能体">
    智能体是在你的工作区内驻留的 AI 助手。 使用 `defineAgent()` 来创建带有自定义系统提示词的智能体：

    ```ts src/agents/example-agent.ts theme={null}
    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' }`。 使用 `{ type: 'json', schema }` 来强制生成结构化 JSON 输出。

    默认情况下，代理返回自由格式文本。 要获取结构化输出，将 `responseFormat` 设置为 `{ type: 'json' }`，并提供一个 `schema`：

    ```ts src/agents/structured-agent.ts theme={null}
    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` 中声明的属性。
  </Accordion>

  <Accordion title="runAgent" description="从逻辑函数中运行代理">
    `runAgent()` 允许逻辑函数运行你的应用的某个代理（及其技能和工具）。 通过你传递给 `defineAgent()` 的 `universalIdentifier` 来标识该代理。 只传入 `prompt` 字符串或 `messages` 会话历史其中之一，不要同时传入两者：

    ```ts src/logic-functions/run-enricher.ts theme={null}
    import { runAgent } from 'twenty-sdk/logic-function';

    const { result, error, success } = await runAgent({
      agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123',
      prompt: 'Enrich House Ad <recordId>: fill empty fields from its listing URL.',
    });
    ```

    对于多轮对话机器人（Slack、Discord、Teams 等），将线程历史作为 `messages` 传入，而不是单个 `prompt`：

    ```ts src/logic-functions/reply-in-thread.ts theme={null}
    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`（字符串）或 `messages`（1 到 100 个 `{ role: 'user' | 'assistant', content: string }` 条目）中的 **恰好一个**。
    * 代理以**同步**方式运行，并且可以通过其自身的工具读取/更新记录 —— `runAgent()` 会在运行完成后才 resolve。
    * 一个应用只能运行它自己的代理。
    * 应用的[默认角色](/l/zh/developers/extend/apps/config/roles)必须授予 `AI` 权限标记 —— 在其 `permissionFlagUniversalIdentifiers` 中添加 `SystemPermissionFlag.AI`（或设置 `canAccessAllTools: true`）。
      否则，`runAgent()` 会因权限错误而失败。
    * 在逻辑函数上设置较大的 `timeoutSeconds` 值 —— 代理运行可能需要数秒时间。
    * 当运行完成时，`success` 为 `true` 且 `result` 为非空；失败时，`success` 为 `false`，`result` 为 `null`，并且 `error` 保存失败原因（例如，当工作区在运行过程中耗尽 AI 额度时）。

    ```ts src/roles/default-role.ts theme={null}
    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],
    });
    ```

    <Warning>
      \*\*避免循环：\*\*如果你从 `*.updated` 数据库事件触发器中调用 `runAgent()`，而代理又会更新同一条记录，请将触发器的 `updatedFields` 限定为代理永远不会写入的字段（例如来源 URL），或者在调用 `runAgent()` 之前检查任何目标字段是否仍为空。
    </Warning>

    ### 以工作区成员身份运行

    当运行是由某个用户触发时（例如，一个聊天机器人在回复消息），传入 `runAsWorkspaceMemberId`，这样智能体就会以该成员的身份而不是以应用自身的身份执行：

    ```ts src/logic-functions/answer-question.ts theme={null}
    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 密钥——都不能为任何成员命名。

    <Warning>
      当工作区成员无法解析时——例如未知或已移除的成员，或者没有角色的成员——`runAgent()` 会抛出异常。 它绝不会回退到代理自身的角色，因为那样会授予比调用方请求更多的访问权限。
    </Warning>
  </Accordion>
</AccordionGroup>
