内容
<p align="center">
<img src="./examples/images/logo-formio-uag.png" alt="Form.io 通用代理网关(UAG)" width="40%">
</p>
通用代理网关(UAG)利用 [模型上下文协议(MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) ,通过 Form.io 实现进程内代理自动化。它为 AI 代理提供与我们的 [JavaScript 渲染器](https://github.com/formio/formio.js) 为人类提供的相同功能;将 Form JSON 模式解释为可理解的格式。在 UAG 的情况下,它将 Form JSON 模型转换为 AI 可读的 Markdown 格式,以便代理可以轻松理解需要收集的数据的目的和结构。

--------------------------
UAG 启用了两种主要场景:
- **非结构化 '聊天' 输入到确定性表单提交**:此功能使用 Form.io 表单的 JSON 模式生成确定性结构化数据对象,提供自然语言对话输入。

有关此流程的示例,请尝试 [对话表单示例](./examples/conversation-form)。
- **代理 Form.io 工作流**:UAG 为 AI 代理提供能力,以现有提交数据和“上下文”标准为基础,提示 AI 代理在工作流场景中提供自己的数据和分析。以下示例显示了使用 Form.io 应用程序表单的大学申请流程,演示了此主要场景的工作原理。

有关代理工作流的更多信息,请查看专用的 [代理工作流](#agentic-workflows) 部分。有关此流程的示例,请尝试 [代理工作流示例](./examples/agentic-workflow)。
---
UAG 提供的众多好处之一是能够将 **动态上下文** 注入 AI 处理周期。这是通过 Form JSON 模式的动态性质实现的,可以在无需更新应用程序或重新训练过程中的代理的情况下轻松修改和部署到任何环境。因此,动态上下文更改可以无缝地注入到现有的运行过程中,自动更新使用 UAG 的代理的行为。
## 试试吧!
此存储库中有三个示例,每个示例都使用 Docker Compose 启动 Form.io 服务器和 UAG。请选择与您正在构建的内容相匹配的示例。
| 示例 | 模式 | 许可 |
|---------|---------|-----------|
| **[自定义模块](examples/custom-module)** | **对话式,现有客户端。** 将 Claude Desktop 连接到您的表单并与它们交谈:“我想添加一个新客户。” 构建为自定义模块,因此角色和权限决定代理可以执行的操作。 | 开源 - 免费 |
| **[对话表单](examples/conversation-form)** | **对话式,您自己的 UI。** 聊天应用程序,其问题完全来自表单。约 200 行代码,代码中没有字段名称 - 编辑表单,转换更改。 | 开源 - 免费 |
| **[代理工作流](examples/agentic-workflow)** | **自主。** 提交触发代理,根据评分标准评估它并写回其决定,这反过来触发第二个代理。无需人工,无需聊天窗口。 | 企业 |
还有一个 [流程查看器](examples/flow-viewer) - 一个小型代理,实时显示代理运行的每个环节,这是最快查看代理实际执行的操作的方法。
## 存储库中的文档
此文件是主要参考资料:UAG 是什么,如何配置表单,如何部署,以及如何排除故障。其他文档位于其描述的代码旁边。
| 文档 | 内容 |
|----------|----------------|
| **README.md**(此文件) | 概念,[代理工作流设置](#agentic-workflows),[MCP 工具](#pre-defined-mcp-tools-providing-dynamic-context),[部署](#deploying-uag),[环境变量](#environment-variables)和[故障排除](#troubleshooting)。 |
| [module/Readme.md](./module/Readme.md) | 构建 **自定义模块** - 添加自己的 MCP 工具,表单操作,预定义表单和资源,以及配置覆盖,然后将其挂载到 Docker 容器中。 |
| [integrations/claude/Readme.md](./integrations/claude/Readme.md) | **Claude 集成**:其 API 端点和命令,如何使用 Node 或 Docker 运行它,其环境变量,以及如何从 Form.io Webhook 操作中触发它。 |
| [examples/custom-module/Readme.md](./examples/custom-module/Readme.md) | 示例 - 一个自定义模块,由 **Claude Desktop** 对话驱动,其中角色和权限控制代理可以执行的操作。 |
| [examples/conversation-form/Readme.md](./examples/conversation-form/Readme.md) | 示例 - 一个 **您自己的聊天应用程序**,其问题完全来自表单。 |
| [examples/agentic-workflow/Readme.md](./examples/agentic-workflow/Readme.md) | 示例 - 一个 **自主,Webhook 触发的工作流**,具有两个链接的代理角色。 |
| [examples/flow-viewer/Readme.md](./examples/flow-viewer/Readme.md) | 一个小型代理,实时显示 **代理运行的每个环节** - token 请求,每个工具调用和写回。最快查看代理执行的操作的方法。 |
| [examples/custom-module/module/templates/Readme.md](./examples/custom-module/module/templates/Readme.md) | 重写 UAG 返回给代理的 **响应模板**,使用 Lodash 模板。 |
| [test/e2e/Readme.md](./test/e2e/Readme.md) | **端到端测试套件** - 其三个层,每个层涵盖的内容,以及如何运行它。 |
---
## 代理工作流
UAG 最强大的功能之一是 `agent_provide_data` 工具。此工具提供能力,指示通用训练的代理如何分析现有的提交数据,然后通过遵循可配置的 **标准** 生成自己的数据。此行为历史上只能通过专门训练的代理实现,这并不提供 Form.io 平台提供的动态可配置性的任何好处。此工具能够通过为通用训练的代理提供必要的“上下文”来实现此目标,以便在自动化工作流中准确生成自己的数据。此功能在您希望在代理工作流中使用 UAG 时特别有用,其中 AI 代理能够理解结构化数据,然后通过 UAG 提供的配置 **标准** “上下文”贡献自己的数据。
例如,假设您希望自动化大学申请流程的后端管理。在此示例中,潜在学生提交的申请包括许多不同的数据字段,例如学术,课外活动,荣誉,志愿者工作以及可能的书面论文。历史上,这些申请将由管理员审查,以评估候选人的资格是否符合录取标准。使用 `agent_provide_data` 工具,现在可以自动化此过程,如下图所示。

要实现此目标,`agent_provide_data` 工具使用以下信息,然后将其提供给通用训练的代理,以生成自己的提交数据。
- **现有提交数据**:为了使代理能够贡献自己的数据,它必须首先有一个现有的提交数据,根据配置的 **标准** 进行分析。
- **标准**:这是一个内容,提供代理在分析数据时要遵循的 **标准**,还提供有关代理如何应填充 **必填字段** 的说明。
- **必填字段**:这些是表单字段,代理需要填充作为 `agent_provide_data` 过程的一部分。
### 设置
要配置表单使用 `agent_provide_data` 工具,您必须首先指定表单的一部分将被 AI 代理读取和使用。类似于表单中“仅限办公室使用”的内容,但不是人类贡献值,而是自动化 AI 代理。 有两种类型的字段可以添加到表单中,以配置其用于 `agent_provide_data` 工具: **标准** 和 **代理字段**
完整的设置分为四个步骤,所有四个步骤都是必需的:
1. **标记表单 `uag`** (下面描述)- 如果没有,UAG 将不会注册表单。
2. 添加 **标准** 内容组件,教导代理执行操作。
3. 添加 **代理字段** 代理可以填充的字段。
4. 添加 **Webhook 操作** 以在提交时触发代理 - 请参阅 [Claude 集成](./integrations/claude/Readme.md#formio-webhook-setup)。此步骤需要企业服务器,因为操作必须设置请求头并转换其有效载荷;在社区版上,请在创建提交后从自己的代码中触发集成。
有关包含所有四个步骤的工作参考,请参阅 [代理工作流示例](./examples/agentic-workflow)。
#### 标记表单 `uag`
UAG 仅注册带有 `uag` 标签的表单。任何没有它的表单对每个代理和每个工具都是不可见的,包括 `get_forms`。在表单生成器中,此设置在 **表单设置 → 标签** 下; 在表单的 JSON 中,它如下所示:
```json
"tags": ["uag"]
```
每当代理坚持认为表单不存在时,都值得首先检查这一点,因为缺少标签不会在任何地方产生错误 - 就代理而言,表单根本不存在。还要注意,新标记的表单将在下一次项目缓存过期时被拾取,因此允许最多 `PROJECT_TTL` 秒(请参阅 [项目缓存和 TTL](#project-cache-and-ttl))。
#### 代理“标准”组件
需要配置的第一件事是一个特殊的 **内容组件** ,它指示 AI 代理如何解释数据。例如,以下是一个标准内容块,旨在指示 AI 代理如何评估大学申请论文的提交。

此内容的目标是像为新员工编写操作手册一样编写。请确保它是您希望代理理解和遵循的内容。它还用于指示 AI 代理如何填充为该标准配置的表单值。一旦编写了此标准,就需要用 `uag` 属性和该属性的值标记为代理的 **角色** 。这提供了具有多个代理的功能,可以承担不同的角色来分析提交的数据并提供自己的值。此外,“标准”内容还需要提供 `uagField` 属性,其值等于 `criteria`。 下面是一个正确配置的 `uag` 标准内容组件:

一旦您将此 **标准** 内容组件添加到表单中,接下来的对象是添加您希望代理填充的字段。这些称为 **代理字段**。
#### 代理字段
在表单的任何位置,您都可以拖放可以标记为代理字段的字段。使用上面的示例,假设您的表单有一个“仅限办公室使用”的部分(可能是面板)。在此面板中,首先看到的是一个内容组件,其中包含有关如何填写以下字段的说明。这是我们刚刚描述的 **标准**。接下来是代理需要填充的字段。任何具有与 **标准** 内容组件相同的 `uag` 属性值的字段将被用作代理字段。
例如,假设我们为大学申请论文创建了一个表单。在 **标准** 下面可能有一些字段,代理需要根据提供的 **标准** 对论文进行“评分”。这可能如下所示...

要将这些字段标记为代理字段,您只需添加 `uag` 属性,其值与 **标准** 内容组件给出的角色标志相同。

**嵌套组件**
还可以将 `uag` 属性标记为一组字段。这可以通过将所有这些字段包装在 **嵌套组件** (例如面板,容器,字段集等)中实现,然后该嵌套组件内的所有字段都将被添加到具有该角色的代理的上下文中。
### 每表单多个角色
还可以实现每表单多个角色。这在过程中需要发生多个隔离的评估时非常有用。例如,如果我们查看上面显示的流程图,可以看到大学申请表。在申请人提交申请时,会进行第一次代理评估,以决定是否接受或拒绝。从那时起,如果申请人被接受,则需要进行完全不同的评估,以授予经济援助或奖学金。这些评估将需要完全不同的标准来评估提交的数据。
要实现此目的,您只需将组件的 `uag` 属性值标记为适用于该字段的角色。对于上面的示例,您将添加一个内容组件来评估申请人是否应被接受,然后为该内容提供以下 `uag` 属性:`uag="application"`。 任何需要由 AI 代理填充以批准申请的字段也将使用属性 `uag="application"` 标记。然后,在表单的不同部分,您将创建一个单独的内容组件,其中包含财务管理员 AI 代理的标准。此内容将使用属性 `uag="finance"` 标记。财务管理员 AI 代理需要填充的任何字段也将使用 `uag="finance"` 标记。这提供了一个真正灵活和动态的 AI 参与,其中多个通用训练的代理可以被动态“教导”如何读取和解释仅与该部分代理过程相关的数据。
代理字段不必与其标准相邻。`status` 字段在一个面板中可以标记为 `uag="application"`,而旁边的字段可以标记为 `uag="finance"`,这就是一个工作流字段可以由负责该阶段的角色所有。
#### 将角色链接到工作流中
如果表单上的多个角色只有在其他角色触发后才有用。因为每个角色都写入提交内容,所以第二个角色的自然触发器是第一个角色的写入。
这是使用第二个 Webhook 操作配置的,该操作在 `update` 上触发,而不是 `create`,并在字段上有限制条件,该字段由第一个角色设置:
```json
{
"name": "webhook", "handler": ["after"], "method": ["update"], "priority": 0,
"condition": {
"conjunction": "all",
"conditions": [
{ "component": "status", "operator": "isEqual", "value": "scholarshipEvaluation" }
]
},
"settings": {
"method": "post",
"url": "http://formio-uag-claude:3300/agent/claude/agent_provide_data",
"headers": [{ "header": "x-token", "value": "<your project API key>" }],
"transform": "payload = {formName: 'application', submissionId: payload.submission._id, persona: 'finance'};",
"block": false
}
}
```
在大学申请工作流中,招生角色将 `status` 设置为 `scholarshipEvaluation`,仅适用于奖学金轨道的申请人,因此只有这些提交内容才能唤醒财务角色。未被简单接受或拒绝的申请人永远不会触发它。
> **避免循环。** 第二个角色也写入提交内容,这会再次触发相同的 `update` Webhook。确保角色自己的写入内容不能重新匹配触发它的条件 - 在上面的示例中,财务角色将 `status` 设置为 `scholarshipGranted`,这不再满足条件,因此工作流终止。条件在角色运行后保持不变,将无限循环并消耗 API 积分,直到您停止容器。
一个完整的可运行的两个角色工作流示例在 [代理工作流示例](./examples/agentic-workflow) 中。
## 集成
为了帮助实现 UAG 的"智能代理化",我们还提供了一些"集成",可以直接与通用训练的 AI 代理通信,以利用 UAG 实现自动化的 AI 代理行为。这涉及提供一个单一的 API 端点,可以触发 AI 代理流程,以及与已部署的 UAG 的连接。然后,可以使用表单中的简单 Webhook 操作来触发这些 API 端点,以启动 Agentic 流程作为表单提交的结果。下面是特定集成如何用于实现单个 API 调用以完成 Agentic 任务的示意图。

每个集成都运行自己的 MCP 客户端,并连接到 UAG,因此 UAG 不需要公开访问即可工作 - 它只需要可以从集成访问,例如通过私有 Docker 网络或在 `localhost` 上。
这些集成可以在 **integrations** 文件夹中找到。提供了以下 **集成** 以启用自动化的 Agentic 工作流。
- [Claude 集成](./integrations/claude)
请点击其中一个集成链接以了解它们的工作原理。
---
## 技术概述
UAG 可以被视为由许多功能层组成。每个层大致负责获取动态上下文或提交确定性数据结构。UAG 中使用了以下层。
1. **MCP 接口**:UAG 的入口点是 MCP 接口,位于 AI 代理和在服务器上执行的工具之间。
2. **授权**:作为 MCP 规范的一部分,AI 代理和后端服务之间的每个交互都必须经过身份验证过程,利用 OIDC(PKCE)身份验证。UAG 在此基础上更进一步,通过在 Form.io 已提供的身份验证灵活性的基础上添加 OIDC(PKCE)身份验证层。因此,如果使用 SAML、Form.io 身份验证、OIDC 或甚至通过 Form.io 平台的自定义身份验证过程,就有可能对 UAG 进行身份验证。
3. [**预定义的 MCP 工具提供动态上下文**](#预定义的-mcp-工具提供动态上下文):UAG 利用 MCP 提供了一系列预定义的工具,根据 Form.io 平台中标记为兼容的表单和资源,为 AI 代理提供动态上下文。这些工具在下面的章节中更详细地描述。
4. **自定义工具**(由 [自定义模块](#自定义模块) 提供):这使开发人员能够引入新的工具,利用 Form.io 表单和提交数据结构,为 AI 代理提供额外的功能。这将允许自定义代理交互以实现特定用例的目标。
5. **自定义操作**(由 [自定义模块](#自定义模块) 提供):使开发人员能够创建可组合的中间件,在 AI 代理提供的数据经过验证和净化后执行。这提供了将 AI 代理收集的数据与任何后端系统或工作流接口的能力。
6. **内置操作**:除了通过模块引入的自定义操作外,UAG 还支持少数现有的操作,可以分配给任何表单或资源。诸如 **Webhook** 之类的操作将在 AI 代理提交后向任何端点发送 REST API 调用。这可以用于指向任何无服务器函数,以启动由 AI 代理交互触发的后端工作流。
7. **预定义表单和资源**(由 [自定义模块](#自定义模块) 提供):允许开发人员发布一个提供默认数据结构的模块给 AI 代理。如果开发人员希望创建一个实现特定目标的模块,这将非常有用,其中该目标所需的数据结构需要遵循表单或资源提供的预定义字段集。例如,如果开发人员希望为 UAG 发布一个 CRM 模块,那么该模块还将提供通常伴随大多数 CRM 实现的 **客户** 和 **公司** 资源。
8. **自定义数据库**(由 [自定义模块](#自定义模块) 提供):默认情况下,UAG 通过“提交代理”执行数据收集和检索,而数据则通过 REST API 提交到企业服务器项目或开源服务器。但是,可以修改此设置,以便将数据直接发送到和从数据库中。这可以通过 UAG 提供的数据库接口实现。有关更多信息,请参见 **模块** 文档。此功能需要 UAG 连接到企业服务器。
下面是一个示意图,展示了这些层如何组织以构成 UAG。

### 预定义的 MCP 工具提供动态上下文
UAG 提供的以下工具可以描述如下:
| 工具名称 | 工具描述 |
|-----------------|----------------------|
| get_forms | 为 AI 代理提供可用表单的列表。<br/>它只会返回标记为 `uag` 的表单。 |
| get_form_fields | 当 AI 代理推断用户意图使用特定表单时,此工具为代理提供提交该表单所需的所有字段的高级概述(以及字段数据路径)。 |
| get_field_info | 一旦使用 `get_form_fields` 确定了字段,此工具就会提供有关请求字段的特定信息,例如验证、条件、输入格式等。<br/>此工具指示 AI 代理如何格式化和构造发送到 MCP 服务器的数据。 |
| collect_field_data | 为 AI 代理提供一种机制,以动态收集用户所需的信息。它可以一次解析用户的输入到多个字段,并会在需要时识别其他输入。<br/>此工具支持复杂和结构化的数据收集,并与嵌套或多值字段(如嵌套表单、数据网格等)兼容。 |
| confirm_form_submission | 此工具用于在向表单提交之前提供收集的所有数据的摘要。 |
| submit_completed_form | 使 AI 代理能够提交从用户收集的所有数据,以创建表单提交。 |
| find_submissions | 使代理能够将用户的自然语言请求解析为查询或特定提交的特定字段。 |
| submission_update | 使 AI 代理能够更新现有的提交,可以通过提供未填充的字段或更新现有的字段(如果允许)。提供现有字段值的上下文,允许内联更改或编辑。 |
| agent_provide_data | 使 AI 代理能够根据用可配置的 **标准** 定义的规则分析现有的提交数据。然后指示代理使用 `submission_update` 工具为特定 **角色** 配置的字段提供生成的数据。请阅读 [**Agentic 工作流**](#agentic-workflows) 部分以获取有关此工具集的更多信息。 |
| fetch_external_data | 此工具使 AI 代理能够通过资源组件、选择 URL 或数据源组件将外部数据拉入表单工作流。 |
### 自定义模块
虽然 UAG 可以作为一个独立系统使用,以实现 AI 代理和动态 JSON 表单之间的交互,但该平台的真正强大之处在于,开发人员可以通过使用自定义模块和工具扩展该平台的功能,以解决行业特定的用例。开发人员可以创建一个 **模块**,引入自定义工具、操作和预定义资源和表单,以实现与行业特定技术的交互。他们可以通过以下机制实现此自定义集成能力:
1. **预定义表单和资源**:使用 Form.io 模板系统,自定义模块可以包含 Form.io 项目的模板导出,其中包括多个表单、资源、操作(以及与它们关联的任何角色和权限)。使用模块时,这将自动“注册”这些资产,以便 AI 代理立即了解这些资产。
例如,想象一个模块包含一个具有“名字”、“姓氏”和“电子邮件”字段的客户资源。如果您然后简单地要求 AI 代理“我想要添加一个新客户”,代理将自动了解客户数据结构的内容,并知道您在提出此请求时的确切意图。
2. **自定义操作**:操作可以被视为可组合的中间件函数,允许为任何表单和资源附加可配置的 Express.js 中间件函数,然后在 AI 代理提交的数据经过适当的数据验证和净化后执行。这些可用于提供与后端流程和工作流的自定义集成。
3. **自定义工具**:除了提供自定义操作外,模块还可以引入自定义 MCP 工具,为任何行业特定的目的提供 AI 代理和 UAG 之间的定制交互能力。
4. **自定义身份验证**:模块还可以修改“身份验证”登录页面,以协助任何自定义身份验证要求。
5. **行为覆盖**:模块还可以“覆盖”UAG 的任何默认行为。这确保了使用特定模块的人员可以“调整”某些工具和响应,以实现更好的结果,以满足其行业特定的需求。
Form.io 旨在通过 GitHub 和 NPM 使开发人员能够构建和贡献自己的自定义模块到更广泛的社区。
#### 使用自定义模块
一旦开发了自定义模块,任何人都可以安装该模块(通过 NPM),然后通过以下方式轻松使用您的模块...
<sub>这只是一个例子。</sub>
```js
import { UAGServer } from '@formio/uag';
import { ExampleUAG } from '@example/uag';
import Express from 'express';
try {
(async function () {
const server = new UAGServer();
server.use(ExampleUAG);
const app = Express();
app.use(await server.router());
const port = process.env.PORT || 3200;
app.listen(port, () => {
console.log(`Form.io UAG 服务器运行在端口 ${port}`);
console.log(`访问 http://localhost:${port} 以访问应用程序`);
});
})();
} catch (error) {
console.error('启动服务器失败:', error);
process.exit(1);
}
```
要开始构建自己的自定义模块,请访问 [模块自述文件](./module/Readme.md) 获取帮助文档。
## 部署 UAG
以下部分描述了创建运行中的 UAG 实例、将其连接到 Form.io 平台以及配置 AI 代理使用它的过程。
本文档重点介绍使用 Form.io 开源版的 UAG。如需有关在 Form.io 企业版中使用 UAG 的文档,请参阅 [https://help.form.io/uag](https://help.form.io/uag)。
### 代理如何连接
在部署之前,值得决定 **哪一方打开到 UAG 的 `/mcp` 端点的连接**,因为这一决定决定了 UAG 是否需要可公开访问。
| 连接模型 | 谁运行 MCP 客户端 | UAG 是否需要公共域名? |
|------------------|-------------------------|------------------------------------|
| **本地 MCP 客户端** | 您的应用程序或集成,运行在 UAG 旁边 | **否。** UAG 只需要可以从该进程访问 — `http://localhost:3200` 或私有 Docker 网络地址就足够了。 |
| **远程 MCP 客户端** | 一个托管代理,拨入您的 UAG(Claude.ai 和 Claude Desktop 连接器,Anthropic MCP 连接器,或任何其他远程 MCP 主机) | **是。** 代理必须能够通过公共互联网访问 `/mcp` 和 OAuth 发现端点。 |
使用 **本地 MCP 客户端**,您的应用程序连接到 UAG,调用工具本身,并将结果传递给正在使用的模型。没有任何东西拨回连接,因此 UAG 可以完全位于您的网络内部。这就是 [Claude 集成](./integrations/claude) 的工作方式,也是推荐的服务器到服务器和 Webhook 触发的自动化模型 — 包括在开发人员机器上运行整个堆栈。
> 如果您正在使用已发布的 Claude 集成镜像,则需要 **`formio/uag-claude:1.3.0` 或更高版本**。早期镜像将 MCP 服务器 URL 作为远程连接器传递给 Anthropic API,这意味着 API 拨入您的 UAG,并且需要公共 URL。较旧的镜像指向私有地址,将与 Anthropic API 的 `400` 错误一起失败,读取 `MCP 服务器通信过程中的连接错误`,这看起来像是 UAG 故障,但并非如此。
使用 **远程 MCP 客户端**,代理位于您的网络外部并连接进来,因此 `/mcp` 和 `.well-known` OAuth 发现端点必须通过 HTTPS 公开访问,并且 `BASE_URL` 必须是公共 URL。参见 [域名和 URL 配置](#域名和-url-配置)。
两种模型可以同时用于同一个 UAG 部署。
#### 本地 MCP 客户端的身份验证
远程代理通过基于浏览器的 OAuth(PKCE)流程进行身份验证。本地客户端没有浏览器,因此它使用 `client_credentials` 授权与 `{{ BASE_URL }}/auth/token` 交换服务器端密钥以获取访问令牌,然后在 `/mcp` 请求上将该令牌作为 `Bearer` 令牌发送。
`client_id` 必须以项目名称为前缀 — 对于开源部署,默认为 `formio-oss`:
```
POST /auth/token
Content-Type: application/json
{
"grant_type": "client_credentials",
"client_id": "formio-oss-x-admin-key",
"client_secret": "{{ ADMIN_KEY }}"
}
```
对于企业版,请使用您的项目端点中的项目名称和项目 API 密钥 — 例如 `"client_id": "myproject-x-token"` 和 `"client_secret": "{{ PROJECT_KEY }}"`。
响应中包含一个 `access_token`,该令牌被传递给 UAG 作为 `Authorization: Bearer {{ access_token }}`。令牌根据 `JWT_EXPIRE_TIME` 过期,因此长期运行的客户端应缓存令牌并在令牌过期之前刷新。有关工作实现,请参见 [`integrations/claude/auth.js`](./integrations/claude/auth.js)。
### 运行时环境
目前有两种运行时环境与 UAG 配合使用:
- [**Docker**](#docker)
- [**Node.js (Express)**](#nodejs-express)
### Docker
在 Docker 中运行 UAG 启用了各种部署选项到常见的托管环境中,例如 AWS 和 Azure。此外,它还允许使用诸如 Kubernetes 和 Docker Compose 等常见的编排运行时。您可以运行 UAG 的容器如下:
```
formio/uag
```
该容器可以通过两种方式运行:
- [**Docker-Compose.yml**](#docker-compose-recommended) - 推荐的方法,将部署为多容器 Docker Compose 堆栈。
- [**Docker 运行**](#docker-run) - 使用常见的 `docker run` 命令作为独立容器。
#### Docker Compose(推荐)
启动 UAG 的推荐方法是使用 Docker Compose。这使您可以编排多个容器在单个实例中运行,以提供一种更无缝、更简单的部署管理方式。以下是运行 Form.io UAG 和 Form.io OSS 服务器在同一实例上的简单示例。
docker-compose.yml
```
services:
mongo:
image: mongo
restart: always
volumes:
- ./data/db:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME
- MONGO_INITDB_ROOT_PASSWORD
formio:
image: formio/formio:rc
restart: always
links:
- mongo
depends_on:
- mongo
environment:
PORT: 3000
DEBUG: formio.*
NODE_CONFIG: '{"mongo": "mongodb://mongo:27017/formio-oss", "jwt": {"secret": "CHANGEME"}, "mongoSecret": "CHANGEME"}'
ROOT_EMAIL: admin@example.com
ROOT_PASSWORD: CHANGEME
ADMIN_KEY: CHANGEME
ports:
- "3000:3000"
formio-uag:
image: formio/uag
restart: always
links:
- formio
depends_on:
- formio
environment:
PORT: 3200
DEBUG: formio.*
PROJECT: http://formio:3000
ADMIN_KEY: CHANGEME
JWT_SECRET: CHANGEME
JWT_EXPIRE_TIME: 525600
LOGIN_FORM: http://localhost:3000/user/login
# 客户端访问 UAG 的地址 — 这是 UAG 自己的端口,
# 而不是 Form.io 服务器的端口。参见下面的 BASE_URL 部分。
BASE_URL: http://localhost:3200
ports:
- "3200:3200"
```
可以通过输入以下命令运行:
```
docker compose up -d
```
#### Docker 运行
以下是使用 `docker run` 命令运行 UAG 的一些示例。
**UAG 指向开源服务器**
```bash
docker run -d \
-e "PROJECT=https://forms.mysite.com" \
-e "ADMIN_KEY=CHANGEME" \
-e "JWT_SECRET=CHANGEME" \
-e "BASE_URL=https://forms.mysite.com" \
-e "LOGIN_FORM=https://forms.mysite.com/user/login" \
-e "PORT=3200" \
--restart unless-stopped \
--network formio \
--name formio-uag \
-p 3200:3200 \
formio/uag
```
**UAG 指向 Form.io 企业服务器**
```bash
docker run -d \
-e "PROJECT=https://forms.mysite.com/myproject" \
-e "PROJECT_KEY=CHANGEME" \
-e "UAG_LICENSE=YOUR-LICENSE" \
-e "JWT_SECRET=CHANGEME" \
-e "PORTAL_SECRET=CHANGEME" \
-e "BASE_URL=https://forms.mysite.com" \
-e "LOGIN_FORM=https://forms.mysite.com/myproject/user/login" \
-e "PORT=3200" \
--restart unless-stopped \
--network formio \
--name formio-uag \
-p 3200:3200 \
formio/uag
```
一旦运行成功,您可以通过以下地址访问开源部署和 UAG 服务器:
- http://localhost:3000:Form.io 开源服务器
- http://localhost:3200:UAG 服务器
在 Node.js 运行时环境和 Docker 中,通过使用**环境变量**和**模块**来控制 UAG。
### 环境变量
此模块可以通过多种方式配置。其中一种方式是通过环境变量来实现,相关文档如下:
| 变量 | 描述 | 示例 |
|----------|-------------|---------|
| PROJECT | API 端点,指向企业项目端点或开源服务器 URL。 | http://localhost:3000 |
| PROJECT_KEY | (仅限企业)此 UAG 绑定的项目的 API 密钥,在**项目设置 → API 密钥**中找到。开源部署使用 `ADMIN_KEY` 代替。 | CHANGEME |
| ADMIN_KEY | (仅限开源)允许您提供 ADMIN_KEY 以安装和连接到开源服务器。 | CHANGEME |
| UAG_LICENSE | 运行 UAG 针对 Form.io 企业部署的许可证。 | |
| PROJECT_TTL | 项目缓存 TTL(秒)。控制检查项目是否有任何“更改”的时间,以刷新 UAG 中的表单和资源。 | 900 |
| PORT | 运行服务器的端口。 | 3200 |
| DEBUG | 用于执行服务器活动调试日志的变量 | formio.* |
| PORTAL_SECRET | 企业专用:允许您从 Form.io 企业门户连接到 UAG。 | CHANGEME |
| JWT_SECRET | 用于生成和验证 UAG 身份验证过程中生成的 JWT 令牌的密钥。不需要与连接到的企业服务器的 JWT_SECRET 匹配。 | CHANGEME |
| JWT_EXPIRE_TIME | jwt 密钥的过期时间。 | 3600 |
| MONGO | (仅限企业)允许您将 UAG 直接连接到 mongo 数据库,而不是必须将提交重定向到 Form.io 提交 API。 | |
| MONGO_CONFIG | Node.js Mongo 驱动程序的 JSON 配置。 | |
| BASE_URL | **必填。** UAG 可以在其客户端访问的 URL。它发布在 `.well-known` OIDC(PKCE)定义中,并用于身份验证回调。对于远程代理连接,必须是公共 URL;对于本地 MCP 客户端,私有或 localhost URL 即可。 | https://forms.yoursite.com |
| LOGIN_FORM | 加载 `/auth/authorize` 页面的登录表单 JSON 端点的 URL。仅浏览器登录流程使用,因此必须能被该浏览器访问。 | https://mysite.com/project/user/login |
| CORS | 允许跨域资源共享的域名或 JSON 配置。 | *.* |
| NODE_TLS_REJECT_UNAUTHORIZED | 标准 Node.js 变量。当 `PROJECT` 是自签名或不受信任证书保护的 `https` URL 时,设置为 `0`,在本地和内部部署中很常见;如果不设置此项,UAG 无法连接到服务器,所有工具调用都会失败。永远不要在可从网络外部访问的部署上设置此项,因为它会禁用所有出站请求的证书验证。 | 0 |
### 项目缓存和 TTL
默认情况下,UAG 使用 TTL(生存时间)来“获取”项目资产并将它们注册和缓存到 UAG 中。这意味着,如果您对底层项目表单和资源进行任何更改(直接或通过部署),您需要等待最多 TTL 设置(秒)才能看到已进行的任何更新。例如,如果 TTL 设置为 900(或 15 分钟),并且您对任何表单和资源进行更改,则必须等待最多 15 分钟才能看到这些更改在 UAG 中生效。应该注意的是,当发生“刷新”时,将调用底层项目端点的“导出”方法。这是一个处理器密集型 API 调用,因此不建议将 TTL 设置为小于 60 的任何值。TTL 设置为 0 表示“无 TTL”,这意味着刷新项目表单和资源的唯一方法是重启 UAG 服务器。
以下是解释此参数用法的表格:
| 环境变量 | 值 | 结果 |
|----------|-------------|---------|
| PROJECT_TTL | 0 | 不会发生 TTL(刷新)。这可以用于“禁用”任何刷新,并确保唯一刷新和更新表单和资源的方法是重启 UAG 服务器。 |
| PROJECT_TTL | 60 | 每分钟检查一次更改 |
| PROJECT_TTL | 3600 | 每小时检查一次更改 |
此缓存是表单编辑似乎不会立即生效的原因。任何更改代理所知道的内容 - 添加 `uag` 标签,重写 **条件** 内容组件,添加或删除 **代理字段** - 只有在下一次到期后才会到达代理。 当您积极迭代条件时,重启 UAG 会立即重新注册项目:
```bash
docker restart formio-uag
```
### 域名和 URL 配置
有 3 个不同的“域名”环境变量非常重要,了解如何根据您的用例配置它们非常重要。无论它们是否需要是**公共的**,都取决于代理的连接方式 - 请参阅 [代理如何连接](#如何连接代理)。
如果远程代理连接到您的 UAG,必须正确配置这些变量,否则代理将无法身份验证。如果您只使用本地 MCP 客户端,所有三个变量都可以指向私有或 localhost 地址。
#### 项目
`PROJECT` 环境变量用于建立 UAG 服务器与项目端点(用于企业)或开源服务器 URL 的连接。这**不需要**是公共 DNS 条目,而是 UAG 容器可以连接到服务器容器的 URL。以下示例说明了如何配置此变量。
##### 本地连接到开源服务器
如果您使用本地连接,例如在 Docker Compose 文件中,您可以将 `PROJECT` 环境变量配置为直接指向本地 URL,如下所示。
docker-compose.yml
```yml
services:
formio:
image: formio/formio:rc
restart: always
environment:
PORT: 3000
ADMIN_KEY: CHANGEME
formio-uag:
image: formio/uag
restart: always
links:
- formio
depends_on:
- formio
environment:
PROJECT: http://formio:3000
ADMIN_KEY: CHANGEME
```
在此示例中,我们使用 Docker Compose 启动开源 Form.io 容器,并设置此部署的 ADMIN_KEY,UAG 使用 `http://formio:3000` 连接,这是本地 Docker 网络名称(使用 Docker Compose 文件中的“links”属性提供)。
##### 本地连接到企业服务器项目
如果您在本地环境中使用企业 Form.io 服务器和 UAG,则需要确保 UAG 使用 PROJECT_KEY 连接到独立项目,如下所示。
docker-compose.yml
```yml
services:
formio-enterprise:
image: formio/formio-enterprise
restart: always
environment:
PORT: 3000
formio-uag:
image: formio/uag
restart: always
links:
- formio-enterprise
depends_on:
- formio-enterprise
environment:
PROJECT: http://formio-enterprise:3000/myproject
PROJECT_KEY: CHANGEME
```
##### 公共 DNS
如果您的项目不位于与 UAG 相同的网络上,您可以提供域名作为 PROJECT,如下所示。
docker-compose.yml:连接到企业(formio/formio-enterprise)
```yml
services:
formio-uag:
image: formio/uag
restart: always
environment:
PROJECT: https://forms.mydomain.com/myproject
PROJECT_KEY: CHANGEME
```
docker-compose.yml:连接到开源(formio/formio)
```yml
services:
formio-uag:
image: formio/uag
restart: always
environment:
PROJECT: https://forms.mydomain.com
ADMIN_KEY: CHANGEME
```
#### BASE_URL
`BASE_URL` 告诉 UAG 它可以访问的 URL。该值发布在 OIDC(PKCE)身份验证的 `.well-known` 定义中,并用于身份验证回调。
**`BASE_URL` 始终是必需的**,包括用于本地客户端。UAG 的身份验证提供程序仅在设置时启用,因此如果省略它,`/mcp` 对每个请求返回 401,并且 `/auth/token` 和 `/.well-known/*` 端点根本不存在(404)。`/auth/token` 的 404 是 `BASE_URL` 缺失的最明确信号。
它需要设置为什么取决于代理的连接方式:
- **远程代理连接**:这必须是托管 UAG 的公开可访问域,因为这是代理被告知要验证的地址。例如,`BASE_URL: https://forms.mysite.com`。
- **仅限本地 MCP 客户端**:将其设置为客户端用于访问 UAG 的地址。私有或 localhost URL 即可 - 例如,在 Docker 网络中,`BASE_URL: http://localhost:3200` 或 `BASE_URL: http://formio-uag:3200`。
如果远程代理无法身份验证,则 `BASE_URL` 不匹配是最常见的原因:代理从发现文档中读取此值并遵循它,因此如果它指向代理无法访问的位置,则身份验证失败,即使 UAG 本身运行正确。
#### LOGIN_FORM
这是您的项目或开源部署的登录表单的 URL。它提供在用户导航到 `{{ BASE_URL }}/auth/authorize` 时加载的表单。如果您导航到此 URL,并且页面显示无法加载表单,则是因为您的 LOGIN_FORM 环境变量未指向项目的正确表单 JSON 端点。
仅浏览器登录流程使用此变量,因此它需要能被执行登录的浏览器访问。对于示例:
- 企业示例:`LOGIN_FORM: https://forms.mysite.com/myproject/user/login`
- 开源示例:`LOGIN_FORM: https://forms.mysite.com/user/login`
### Node.js(Express):
在 Node.js 环境中,您可以将 UAG 导入本地运行的 Node.js 和 Express.js 环境中。首先,通过以下方式在 Node.js Express 应用程序中安装 UAG:
```bash
npm install --save @formio/uag
```
或
```bash
yarn add @formio/uag
```
然后,您可以在 Express 应用程序中挂载 UAG,如下例所示:
```javascript
import 'dotenv/config';
import Express from 'express';
import { UAGServer } from '@formio/uag';
try {
(async function () {
const server = new UAGServer();
const app = Express();
app.use(await server.router());
const port = process.env.PORT || 3200;
app.listen(port, () => {
console.log(`Form.io UAG server running on port ${port}`);
console.log(`Visit http://localhost:${port} to access the application`);
});
})();
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
```
还可以通过模块扩展 UAG 的功能,详见 [模块自述文件](./module/Readme.md)
## 与 Form.io 企业服务器结合使用
当与 Form.io 企业服务器结合使用 UAG 时,您将解锁有关在 UAG 中管理表单和资源的多个好处。使用我们的企业服务器,您可以获得的一些功能包括:
- **表单修订** - 我们的表单修订系统提供了一种跟踪对任何表单所做的任何更改的方法,并将这些更改与针对这些修订提交的提交数据关联起来。此功能使您能够确保如果表单架构发生任何更改,则提交的该表单的数据与提交时表单的修订相关联。除了此强大的功能外,您还可以使用表单修订作为一种“回滚”由于表单更改引起的任何错误或回归的方法。您只需恢复到以前的修订,AI 代理将相应地进行调整,而无需重新训练或卸载具有任何架构的 AI 代理。
- **提交修订** - 提交修订提供了一种跟踪对提交数据所做的任何更改的方法,并提供有关谁更改了数据的信息。这与 UAG 的强大功能相结合,为任何系统提供了跟踪由 AI 代理和工作流过程中的人为因素所做的任何数据更改的能力。
- **阶段版本和部署** - 阶段版本提供了一种在项目中的所有表单和资源上创建“标签”版本的方法。这确保您可以确定 AI 代理(可能使用许多不同的表单和资源)与整个项目交互的某个时间点。它还提供了一种更优雅的“回滚”机制,可以对整个项目进行版本控制和独立部署。
### 在企业服务器上运行 UAG
要在企业项目上运行 UAG,您需要提供几个与此模块的开源运行时不同的环境变量。以下是在企业项目上运行 UAG 所需的环境变量。
| 变量 | 描述 | 示例 |
|----------|-------------|---------|
| PROJECT | 对于企业服务器,这指向您要绑定 UAG 的项目端点。 | https://mydeployment.com/myproject |
| PROJECT_KEY | 该项目的 API 密钥,在项目设置中提供 | CHANGEME |
| UAG_LICENSE | Form.io 许可团队为您提供的许可证。联系 support@form.io 获取“临时”或完整许可证。 | |
一旦您拥有这些环境变量,您应该能够将 UAG 指向您的企业项目。
## 故障排除
大多数 UAG 问题是配置问题,而不是代码问题,而且它们往往在距离问题原因很远的地方表现出来——缺少一个标签看起来像缺少一个表单,而缺少 `BASE_URL` 看起来像权限错误。下表将您可能看到的症状映射到实际导致这些症状的原因。
| 症状 | 可能的原因 |
|---------|--------------|
| 代理说一个表单不存在,或者 `get_forms` 不列出它 | 表单没有标记 `uag`,或者更改尚未生效。请参阅 [标记表单 `uag`](#tagging-the-form-uag) 和 [项目缓存和 TTL](#project-cache-and-ttl)。 |
| `/auth/token` 返回 `404`,并且 `/.well-known/*` 也缺失 | `BASE_URL` 未设置。身份验证提供程序仅在存在时才启用,因此这些端点根本不存在。请参阅 [BASE_URL](#base_url)。 |
| 每个 `/mcp` 请求都返回 `401` | Either `BASE_URL` 未设置(如下所述),或者客户端未发送 `Authorization: Bearer <token>`。对于服务器端客户端,请参阅 [身份验证本地 MCP 客户端](#authenticating-a-local-mcp-client)。 |
| 远程代理(claude.ai,Claude Desktop 连接器)无法身份验证 | `BASE_URL` 不指向公开可达的 HTTPS URL。代理从发现文档中读取该值并遵循它,因此它必须从代理的角度正确,而不是从服务器的角度。 |
| 克劳德集成返回 `400 ... 与 MCP 服务器通信时连接错误` | `formio/uag-claude` 镜像早于 `1.3.0`,并且正在将 UAG 视为*远程* MCP 服务器,因此 Anthropic API 试图连接到私有地址。升级到 `1.3.0` 或更新版本。请参阅 [代理如何连接](#how-agents-connect)。 |
| UAG 根本无法访问服务器,并且每个工具都失败 | 如果 `PROJECT` 是具有自签名证书的 `https` URL,请设置 `NODE_TLS_REJECT_UNAUTHORIZED=0`。否则,请检查 `PROJECT` 是否可以从 UAG 容器*内部*解析 — 它是容器到容器的地址,而不是浏览器地址。请参阅 [PROJECT](#project)。 |
| 创建提交时没有任何反应 | Webhook 操作未触发。确认其 `handler` 为 `after`,`method` 包含 `create`,并且 API 密钥标头与集成中的 `PROJECT_KEY`(企业)或 `ADMIN_KEY`(OSS)匹配。 |
| 创建提交但响应长时间挂起 | Webhook 操作具有 `block: true`。代理运行需要数十秒;设置 `block: false` 以便提交者不必等待。 |
| 代理连续运行并消耗 API 积分 | 链接的角色正在重新触发自身。其自身的写入仍然满足 `update` Webhook 启动时的条件。请参阅 [将角色链接到工作流中](#chaining-personas-into-a-workflow)。 |
| 代理填充某些字段但不是其他字段 | 这些字段缺少 `uag` 属性,或者其值与 **条件** 组件上的角色不完全匹配。代理可能写入的每个字段都必须携带相同的角色,直接或间接继承自父组件。 |
| 代理写入的值表单拒绝 | **条件** 对格式和允许的值不够具体。声明单位、舍入和确切选项值,并逐字命名字段键。 |
| 运行失败,并且日志中没有足够的信息 | 将 [流程查看器](./examples/flow-viewer) 放在 UAG 前面。它显示令牌请求、`tools/list`、每个工具调用及其参数,以及写回顺序。 |
如果以上情况都不适用,请运行其中一个[示例](#try-it-out) 以确认环境本身正常,然后将环境配置与您的配置进行比较。
连接信息
猜你喜欢
暂无推荐服务器