这是本节的多页打印视图。 .
部署运维
最近更新:
- 1: 单机与 Docker 部署
- 2: Control/Data Plane 分离部署
- 3: 配置与认证
- 4: 数据目录、备份与升级
- 5: 日志与常见问题
本章面向负责安装和维护 Server 的用户。首次部署可从单机开始;只有需要拆开管理与执行服务时,才需要阅读分离部署。
- 单机与 Docker 部署:启动服务、保存数据并挂载项目目录。
- 分离部署:准备共享服务,配置控制面、数据面和代理路由。
- 配置与认证:按用途查找配置项、默认值和生效方式。
- 备份与升级:保留数据库、密钥和文件,验证能否恢复。
- 日志与常见问题:按故障现象逐步排查。
1 - 单机与 Docker 部署
最近更新:
Standalone 在一个 Server 中提供管理页面、对话执行和定时任务,适合本机试用或单台主机部署。默认使用 SQLite 保存数据,由当前进程运行任务,无需另行部署数据库服务。
可以使用 Docker 镜像,或自行构建与操作系统及处理器架构匹配的 Portable Server。两种方式都包含 Web 界面;下面先完成本机访问,再说明目录挂载和远程访问。
Docker 本机试用
打开 http://localhost:30816/setup 完成初始化。通过 Docker 端口映射访问时,容器看到的请求来源不是回环地址,Setup 页面会要求填写一次性 Setup Code;用 docker logs agw 在启动日志中查找 “Agw remote setup code”。镜像包含静态 Web,浏览器直接访问 Server 即可。示例的 latest 适用于试用;持续运行的部署应换成 Releases 对应的固定版本标签。
要让 Agent 访问主机项目,额外添加显式 bind mount,再将容器内路径配置为 Project Workspace。不要将主机路径误填成容器可见路径。
Portable Server
Portable Server 不随 Release 提供,需要在仓库根目录构建,例如:
产物位于 artifacts/publish/portable/agw-server-<版本>-<RID>/,同时生成对应的压缩包。在产物目录中启动:
Windows 使用 agw-server.exe serve。默认监听 http://127.0.0.1:30816,需要调整时使用 ASPNETCORE_URLS。未设置 ASPNETCORE_URLS 且 30816 端口已被占用时,Server 会改用一个随机的本机空闲端口,并把实际地址记录在 <AgwDataDir>/runtime/server.json 中。先验证本机 Setup、Web 和一次对话,再配置远程访问。
持久化与网络
Docker 数据目录为 /data,日志默认独立写入工作目录下的 logs;持久化文件日志需要另外挂载配置的日志路径。Project Workspace 也独立于数据卷。
远程部署需要正确配置 AllowedHosts、受信代理、HTTPS 和 WebSocket 转发。仓库 Compose 是带域名与代理配置的示例,使用前替换成真实环境值。完整持久化范围见备份与升级。
实现与参考
2 - Control/Data Plane 分离部署
最近更新:
分离部署把管理和调度放在 Control Plane(控制面),把任务执行放在 Data Plane(数据面)。需要单独维护执行环境或增加执行节点时,可以采用这种方式;只在一台主机试用时,Standalone更容易配置。
本页面向熟悉容器、数据库和反向代理的部署者。开始前,准备共享 PostgreSQL、用于解密凭据的 Data Protection 密钥,以及各执行节点都能访问的工作目录。入口代理还需要支持 WebSocket,以便持续传输对话事件。
角色
| Host | 职责 |
|---|---|
| Control Plane | Setup、Web、管理 API、Jobs 调度 |
| Data Plane | SignalR Execution、A2A、持久化执行 workers |
| Standalone | 合并两种职责,适合单机 |
分离部署使用 Distributed 执行模式。在这种模式下,Chat 中直接运行 External Agent(Claude Code、Codex、Pi)的回合会报错 “Distributed execution currently supports System Agents only.”;需要直接使用这些外部 Agent 时,应选择 InProcess 执行的 Standalone。
分离部署要求两端使用 PostgreSQL 数据库、Distributed 执行和 PostgreSQL 锁。不能使用 SQLite 或内存锁替代跨节点协调。
这是注入两端的环境配置片段。连接字符串为空的锁配置复用数据库连接;实际数据库连接字符串通过 Secrets 提供。
启动与路由
- 按仓库 cluster Compose 配置数据库、两个 Host、共享密钥和目录。
- 先启动 Control Plane,完成初始化并确认就绪:
GET /api/health/ready在未初始化或数据库无法连接时返回 503,就绪后返回 200;GET /api/health/live只表示进程在运行。这两个地址不需要登录。 - 再启动 Data Plane,最后按需要增加副本。
- 将
/api/hubs/exec、/a2a/*和/.well-known/agents.json路由到 Data Plane,其余应用路径到 Control Plane。
保留 Host、认证头/Cookie 和 WebSocket Upgrade;执行 Hub 查询字符串不应写入代理访问日志。Control Plane 不提供 A2A。
如何阅读下面的示例
Docker Compose 部署从文末的 cluster Compose 文件开始,并按上一节验证启动顺序和路由。Kubernetes 部署可参考下面的本地 kind 示例;其中 kind 是在容器中运行本地 Kubernetes 集群的工具,Pod 是运行应用的单元,Service 提供访问地址,PV/PVC 用于声明和申请存储。
两种部署都需要统一的客户端入口。Nginx 一节说明哪些请求发送到控制面、哪些发送到数据面。先确保两个服务和数据库可用,再检查入口转发,便于区分服务自身与代理的问题。
Kubernetes YAML 示例
仓库的 deploy/k8s 提供一套本地单节点 kind 示例。它将 Control Plane 和 Data Plane 分成独立 Deployment,使用外部 PostgreSQL,并通过 NodePort 接入后文的 Nginx 配置。以下内容对应这些文件,不会额外创建 PostgreSQL 或 Ingress Controller。
| 文件 | 用途 |
|---|---|
| kind-agw-cluster.yaml | 创建本地 kind 集群,映射端口与宿主目录 |
| agw-data-pv-pvc.yaml | 提供共享给同一节点上各 Pod 的数据卷 |
| agw-control-plane-deployment.yaml | 1 个 Control Plane 副本和 NodePort Service |
| agw-data-plane-deployment.yaml | 2 个 Data Plane 副本和 NodePort Service |
集群入口与共享目录
kind-agw-cluster.yaml 将两个 NodePort 映射到宿主机的回环地址,同时将 /opt/agw 挂入 kind 节点:
创建集群前,在容器运行时所在主机准备 /opt/agw/agw-data。使用 Docker/Podman 虚拟机时,还需通过文件共享配置使该路径在虚拟机中可用。role: control-plane 指 Kubernetes 节点角色,与 AGW 的 Control Plane 服务不是同一概念。
数据的实际路径为:
下面是对应的 PV/PVC。Retain 保留回收后的卷数据,但不代替备份;PVC 的 1Gi 是请求容量,PV 声明的容量为 5Gi。
ReadWriteOnce 允许同一节点上的多个 Pod 挂载,因此本例两个角色及 Data Plane 副本可以共用该卷。hostPath 不提供跨节点共享存储;多节点部署需要替换成集群支持的共享存储,并保证密钥、凭据和 Project 工作目录在各执行节点一致。若项目目录位于 /data 之外,还需为这些目录添加相应挂载。
Data Plane Deployment 与 Service
以下是仓库中的完整 Data Plane 示例。它运行两个副本,监听容器端口 8080,读取 agw-database Secret,并将 Service 暴露为 30820。Control Plane 的对应文件使用同样的数据卷和数据库配置,副本数为 1、NodePort 为 30816,并额外读取 agw-admin 的 password 作为 Setup__AdminPassword。
使用前需要确认以下配置:
- 镜像:示例使用
localhost/agw-…:local和imagePullPolicy: Never,需要先构建镜像并加载到 kind 节点。使用镜像仓库时,替换为可拉取的地址和版本,并调整拉取策略及必要的凭据。 - 数据库:两个角色的 Secret 必须指向同一个可从 Pod 访问的 PostgreSQL。连接字符串中的
localhost指 Pod 自身,通常不是宿主机数据库。 - 权限:示例为了适配本地目录权限使用 root 身份运行。其他环境应按存储权限配置合适的 UID/GID,不应直接照搬这个本地设置。
- 连接保持:Service 使用
ClientIP会话亲和性,帮助 SignalR 请求落到同一 Pod。如果 Nginx 位于集群外,多个客户端可能都表现为同一个代理 IP,因此不能据此保证负载均匀。
部署顺序
先准备本地镜像、数据目录和两个 Secret 的内容文件,再从仓库根目录执行。Secret 文件只包含对应值,不要将真实凭据提交到仓库。以下命令使用当前 kubectl 上下文的默认 namespace;若选择其他 namespace,Deployment、Service、PVC 和 Secret 必须保持一致。
rollout status 表示 Deployment 已完成滚动更新,不能单独证明 AGW 已完成初始化。本例由 Control Plane 的 Setup__AdminPassword 触发首次初始化;应结合日志和登录页面确认成功后再启动 Data Plane。已有数据库的认证配置不会被该初始密码覆盖。
按上述 kind 端口映射运行时,后文 Nginx 示例中的 upstream 可直接使用 127.0.0.1:30816 和 127.0.0.1:30820。如果 Nginx 在集群内部,则使用相同 namespace 下的 Service 地址 agw-control-plane:30816 和 agw-data-plane:30820。检查 PVC 为 Bound、Pod 正常运行后,再验证登录、执行连接和各节点实际接收的请求。
不要执行 kubectl apply -f deploy/k8s/:目录中的 kind Cluster 文件是 kind 的输入,不是 Kubernetes API 资源。更改 kind 的端口或目录映射需要重建集群,操作前先备份数据。完整步骤见 本地 kind 部署说明。
Nginx 配置示例
下面的配置中,Nginx 提供统一入口,Control Plane 监听 30816,Data Plane 监听 30820,与前面的 kind 示例一致;仓库中的 deploy/nginx.split.conf.example 和 cluster Compose 示例则让 Data Plane 使用 30817。端口只是示例,需要与实际 Host 的监听地址一致;如果服务运行在不同主机或容器中,将 127.0.0.1 换成 Nginx 能访问的地址。
Control Plane 同时提供 Web
将以下内容保存为 Nginx 的站点配置文件,并确保它被 nginx.conf 的 http {} 引入。map、log_format 和 upstream 不能放进 server {}。日志路径相对于 Nginx prefix,使用前创建对应目录或替换为可写的绝对路径。
此示例使用 HTTP 便于本机验证。对外使用时,在该 server 中配置 listen 443 ssl;、ssl_certificate 和 ssl_certificate_key,使用自己的域名与有效证书,并将 HTTP 入口重定向到 HTTPS。
| 请求 | 转发目标 | 作用 |
|---|---|---|
/api/hubs/exec 及其子路径 | Data Plane | SignalR 协商与执行连接 |
/a2a/* | Data Plane | A2A 请求及流式响应 |
/.well-known/agents.json | Data Plane | Agent 发现 |
| 其余路径 | Control Plane | 初始化、管理 API、OpenAPI、Web 页面与静态资源 |
proxy_pass 不附加 URI,保留原始路径和查询参数。认证头和 Cookie 默认随请求转发;Upgrade、Connection 和 HTTP/1.1 用于 WebSocket。关闭执行与 A2A 路由的响应缓冲,避免流式内容被代理积攒后才返回。3600s 是代理读写超时设置,不保证任意时长的任务都不会断线。
多 Data Plane 实例时,ip_hash 让来自同一 IP 的连接尽量落到同一实例,避免 SignalR 协商和后续连接被分到不同节点;它不能替代共享数据库、执行状态和恢复配置。若 Nginx 前还有代理,需结合实际网络配置可信代理与客户端 IP;不要直接信任来自任意来源的 X-Forwarded-For。
示例访问日志使用 $uri,不记录查询参数;upstream 字段可帮助确认请求实际进入哪个节点。client_max_body_size 只控制 Nginx 请求体限制,不会提高 AGW 对图片等附件的限制。
Web 单独运行
如果 Web 在 3001 单独运行,保留上述 Data Plane 路由和公共代理设置,再添加 agw_web upstream,按下面的方式调整管理路由并替换原来的 location /。3001 是仓库 Web 开发端口,实际部署按 Web 服务端口填写。
这样 /setup 和 /setup/ 都会进入 Control Plane,普通 /api/ 不会误送到 Web;更长的 /api/hubs/exec 匹配仍进入 Data Plane。独立 Web 服务自身的后端地址也应指向 Control Plane。客户端统一使用 Nginx 的入口地址。
检查并加载配置
保存实际配置后,先检查,再重新加载:
重新加载需要在自己的部署环境执行。检查登录和页面资源是否正常;在浏览器网络面板检查执行连接是否成功升级为 WebSocket(101),并查看访问日志中的 upstream 是否为 Data Plane。普通管理 API 则应进入 Control Plane。登录失败先核对 Cookie、转发协议和应用的代理信任设置;执行连接失败先检查 Upgrade、路由及 Data Plane 端口。
验证
依次验证登录、一次 Chat、一次 Job,并观察实际执行节点。所有 Host 从同一数据库读取初始化和认证状态。重启恢复还依赖共享目录、密钥和运行时凭据一致,不能仅验证容器都已启动。
实现与参考
3 - 配置与认证
最近更新:
本页说明 AGW Server 的运行设置:服务地址、数据存放位置、任务执行方式、日志和登录认证。模型、Agent、Project 和集成账号则在管理界面中设置。修改本页配置后,请重启相应的 Server 程序。
初次在本机使用时,大多数设置可以保留默认值。需要远程访问时,重点检查服务地址、客户端来源和代理设置;需要分离部署时,再配置 PostgreSQL 和 Distributed 模式。分布式执行的轮询、批量写入等参数,通常可以先保持默认值。
先看与当前任务有关的设置
只在本机开始使用时,可以先保留默认配置并完成初始化。准备长期运行前,确认数据库和数据目录在哪里,按备份指南保存数据。
远程访问遇到问题时,优先检查“服务地址与数据目录”“初始化、来源与反向代理”和“认证与 API Key”。分离部署则先看两端的必需配置;后面的轮询和批量参数是调优参考,无需在首次部署时逐一修改。
配置方法与优先级
同一项设置可以写在配置文件、环境变量或启动命令中。如果多处都设置了它,后面的来源优先:
程序默认值 → appsettings.json → 环境专用 JSON → 开发环境的 Secrets(机密配置)→ 环境变量 → 命令行。
例如,文件中设置为 SQLite,启动命令中指定 PostgreSQL,最终会使用 PostgreSQL;但连接字符串不会随之自动更换,需要一起修改。配置文件位于 Server 程序目录。日志工具 Serilog 的读取方式有所不同,见下方日志配置。
本页用冒号表示配置的分组,例如 Database:Provider 表示 Database 分组中的 Provider。它在环境变量中写成 Database__Provider,在启动命令中写成 --Database:Provider postgres。开关使用 true(开启)或 false(关闭);需要从几个选项中选择时,请使用表格列出的名称。
表格中的“appsettings.json”指 Server 自带的 appsettings.json;“未设置时”指文件、环境变量和命令行中都没有这一项。两种情况下的默认值若有不同,会分别说明。
按部署方式选择配置
先选择部署方式,再查对应的配置组。部署方式决定启动哪些 Server 程序,执行模式决定任务如何运行,两者需要分别选择。
| 配置组 | 什么时候需要看 |
|---|---|
| 通用配置 | 所有部署都需要了解:服务地址、数据目录、数据库、认证和日志等 |
| Standalone 单机部署 | 一个 Server 同时负责管理、调度和执行;默认使用 SQLite 和 InProcess |
| Control/Data Plane 分离部署 | 控制面负责管理调度,数据面负责执行;必须使用 PostgreSQL 和 Distributed |
| Distributed 执行调优 | 使用 Distributed 时再看:包括分离部署,也包括主动启用 Distributed 的 Standalone |
Standalone 单机部署
本机试用或单台 Server 部署,可以先保留下面的默认组合,通常无需填写这些配置:
| 完整配置名 | 默认选择 | 含义 |
|---|---|---|
Database:Provider | sqlite | 使用本地数据库文件 |
Database:ConnectionString | Data Source=agw.db | SQLite 文件位置;相对路径以 <AgwDataDir>/database/ 为起点,默认文件为 <AgwDataDir>/database/agw.db |
Execution:Provider | InProcess | 由当前 Server 直接运行任务 |
DistributedLock:Provider | 未设置 | 随 SQLite 自动使用进程内锁 |
DistributedLock:ConnectionString | 空 | 进程内锁无需连接数据库 |
Standalone 也可以使用 PostgreSQL,而继续保留 InProcess。若选择 Distributed,则需要同时满足下一节的 PostgreSQL 数据库和锁要求,并按分布式执行方式配置。单机部署方法见单机与 Docker 部署。
Control/Data Plane 分离部署
两端必须使用同一套业务数据库,并采用下面的组合。先完成 Control Plane 初始化,再启动 Data Plane。
| 完整配置名 | 必需设置 | 配置在哪一端 |
|---|---|---|
Database:Provider | postgres | 两端 |
Database:ConnectionString | 指向同一个 PostgreSQL 数据库 | 两端 |
Execution:Provider | Distributed | 两端 |
DistributedLock:Provider | postgres,或不填以跟随数据库 | 两端 |
DistributedLock:ConnectionString | 留空复用数据库连接,或指向相同的锁服务 | 两端保持一致 |
通用配置也要按各自职责填写:
- Control Plane:配置初始化密码、管理页面使用的地址,以及集成 OAuth 的公开地址。
- Data Plane:准备 Agent 所需的 CLI、Shell、工作目录和文件。工作节点的并发数、检查间隔在这一端影响实际执行。
- 两端共同检查:各自的监听地址、客户端来源和代理、日志与监控;需要解密共享数据的节点应使用一致的加密密钥。所有执行节点都必须能访问任务使用的工作目录。
执行模式
下表配置项的完整名称都以 Execution: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Provider | InProcess | InProcess:由当前 Server 直接运行任务,适合简单的单机部署。Distributed:将执行状态保存到 PostgreSQL,由负责执行的 Server 领取并运行任务,支持多个执行节点协作。选择 Distributed 时,数据库和分布式锁都必须使用 PostgreSQL。 |
TurnBroadcastRetentionSeconds | 300 | 一个回合结束后,本 Server 在内存中保留该回合回放内容的秒数。在这段时间内重新连接,或重试已被接受的同一回合的客户端,可以收到完整回放。 |
InProcess 模式下,回合只存在于当前 Server 进程中。Server 重启时,上一个进程遗留的运行中回合会被结束为 Interrupted,不会继续执行;需要跨重启恢复时使用 Distributed。
这里的 Host 就是运行中的 Server 程序。启动 Standalone 时,一个程序同时负责管理、调度和执行;分离部署时,Control Plane 负责管理和调度,Data Plane 负责执行。分离部署的两端都需要设置 PostgreSQL 数据库、Distributed 执行模式和 PostgreSQL 锁。请按部署方式启动对应程序,Execution:Provider 只决定任务如何执行。
分布式锁
多台 Server 协作时,需要确认“这项工作现在由谁处理”。锁用来保证同一时刻只有一个执行者取得这项工作的处理权,避免相互冲突。
下表配置项的完整名称都以 DistributedLock: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Provider | 未指定,跟随数据库 | inmemory:在当前 Server 内记录谁正在执行,适合单节点。postgres:让多个 Server 通过 PostgreSQL 共同确认执行权。未设置或填 null 时会自动选择:SQLite 使用 inmemory,PostgreSQL 使用 postgres。 |
ConnectionString | 空 | postgres 锁使用的连接字符串;空值复用 Database:ConnectionString。inmemory 不使用连接字符串。 |
Distributed 执行调优
下面的设置用于 Distributed 执行模式。分离部署需要使用它;Standalone 只有启用 Distributed 后才需要关注。先保留默认值,出现明确的性能问题后再逐项调整。
分布式工作节点
工作节点是负责实际运行任务的 Server。下面这些设置决定它多久检查新任务、同时处理多少任务,以及执行租约的时长和续期间隔。
下表配置项的完整名称都以 Execution:Distributed: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
WorkerPollingMilliseconds | 250 | 每隔多久检查一次是否有新任务,单位毫秒。默认 250 毫秒,即每秒约检查 4 次。调小后可能更快开始任务,但数据库也会更忙。 |
MaxConcurrentExecutions | 4 | 每个执行 Server 最多同时处理多少次任务。默认 4,表示这一台 Server 最多同时运行 4 次任务;部署多台时,每台分别计算。 |
LeaseSeconds | 30 | 执行租约的时长,单位秒。领取任务的 Server 持有租约;租约到期而没有续期时,其他 Server 可以接手这次执行。正常运行的长任务会持续续期,不会仅因运行超过 30 秒就被接手。 |
LeaseRenewSeconds | 10 | 持有租约的 Server 每隔多久续期一次,单位秒,必须小于 LeaseSeconds。 |
只有选择 Distributed 模式时才需要关注这些设置。所有数值都必须是大于 0 的整数,且 LeaseSeconds 必须大于 LeaseRenewSeconds,否则 Server 启动时报错;没有明确的性能问题时,建议先使用默认值。
执行事件与回放
Agent 执行时会不断产生回复和状态消息。系统保存这些消息后,客户端重新连接时可以补读执行过程,这就是“回放”。这里设置消息保存在哪里,以及读写的频率。
下表配置项的完整名称都以 Execution:Distributed:EventStream: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Provider | Postgres | 执行过程中的消息总是先保存到 PostgreSQL。Postgres:只从 PostgreSQL 读取,无需额外安装 Redis。Redis:同时把已保存的消息复制一份到 Redis Stream,读取时优先使用 Redis,缺少的部分(包括已过期或 Redis 暂时不可用时)从 PostgreSQL 补齐。任务状态和分布式锁始终需要 PostgreSQL。 |
ReadPollingMilliseconds | 250 | 暂时没有新消息时,隔多久再检查一次,单位毫秒,必须大于 0。 |
ReadBatchSize | 100 | 一次最多读取多少条执行消息,必须大于 0。 |
WriteIntervalMilliseconds | 250 | 收到第一条待保存消息后,最多等待多久把消息一起写入,单位毫秒。默认 250;填 0 表示立即写入,不能为负数。 |
WriteBatchSize | 100 | 待保存消息达到多少条时,就触发一次批量写入,必须大于 0。默认积累到 100 条时写入。 |
Redis:ConnectionString | 空 | 选择 Redis 时必填,所有相关 Server 使用相同 Redis 服务,例如 redis:6379,password=...。 |
Redis:StreamTtlMinutes | 1440 | 执行消息在 Redis 中保留多久,单位分钟。默认 1440 分钟,即 24 小时;选择 Redis 时必须大于 0。过期的部分会改从 PostgreSQL 读取。 |
通用配置
以下设置适用于两种部署方式。分离部署时,根据每个 Server 承担的职责配置相应项目。
服务地址与数据目录
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
ASPNETCORE_URLS / --urls | 本地默认端口 30816;容器由运行配置指定 | Server 接收请求的地址。用 --urls http://127.0.0.1:30816 仅供本机访问,或按部署需要绑定其他地址。多个地址用分号分隔。 |
ASPNETCORE_ENVIRONMENT | Production | 选择环境专用 JSON,例如 appsettings.Production.json。常用名称为 Development(开发)、Staging(预发布)、Production(生产);这是环境名称,不是只接受三个值的枚举。 |
AgwDataDir | ~/agw | AGW 数据根目录,包含运行数据、Skills 和加密密钥等。支持 ~;相对路径以启动程序时的工作目录为起点。 |
AgwLogDir | ./logs | 独立的日志目录,不随数据目录移动;支持 ~,相对路径从工作目录解析。 |
AllowedHosts | * | 允许用哪些域名访问 Server。* 表示不限制;也可以填写 agw.example.com;localhost 这样的域名列表,用分号分隔。客户端从哪个页面连接,则由 AllowedOrigins 设置。 |
数据库
下表配置项的完整名称都以 Database: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Provider | sqlite | sqlite:本地 SQLite 文件,适合单机;postgres:PostgreSQL 服务,支持分离和分布式部署。只有这两种值。 |
ConnectionString | Data Source=agw.db | 所选数据库的连接字符串。SQLite 使用 Data Source=...,相对路径以 <AgwDataDir>/database/ 为起点;PostgreSQL 使用 Host=...;Port=5432;Database=...;Username=...;Password=...,Host 不能为空。切换 Provider 时必须一起修改。 |
初始化、来源与反向代理
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Setup:AdminPassword | 未设置 | 首次初始化的管理员密码,8–256 个字符。通过环境或 Secrets 注入可完成无人值守初始化;已有认证配置时不会覆盖密码。分离部署在 Control Plane 初始化。 |
Auth:AllowedOrigins | agw://app、http://localhost:3000、http://127.0.0.1:3000 | 允许哪些客户端地址连接 Server。Origin 是地址的“协议 + 主机名 + 端口”,例如 http://localhost:3000。请填写实际地址,协议和端口都要一致;完全未设置时列表为空。 |
ReverseProxy:TrustedProxies | appsettings.json含 127.0.0.1、172.16.0.0/12、10.0.0.0/8 | 如果请求经过反向代理,填写代理的实际 IP,让 Server 能识别原始访问地址和 HTTP/HTTPS 协议。当前只接受单个 IP;10.0.0.0/8 这样的网段写法不会生效。程序读取 X-Forwarded-For、X-Forwarded-Host、X-Forwarded-Proto,最多处理一层转发。 |
数组通过数字下标配置,例如 Auth__AllowedOrigins__0=agw://app。配置覆盖按下标合并;只覆盖第 0 项不会自动删除appsettings.json中的第 1、2 项,需要完整核对最终列表。
集成 OAuth 地址
下表配置项的完整名称都以 Integrations:OAuth: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
PublicBaseUrl | http://localhost:30816 | 用户在 GitHub 等服务中完成授权后,浏览器返回 AGW Server 时使用的地址。程序会在它后面加上 api/integrations/oauth/callback。远程部署时,请填写浏览器实际能访问的 Server 地址。 |
WebBaseUrl | http://localhost:3001 | 授权流程结束后,用户返回 AGW 页面时使用的地址。请填写实际打开 Web 界面的地址。 |
两项都填写以 http:// 或 https:// 开头的完整地址,不要附带用户名、密码、? 后的查询参数或 # 后的内容。未设置或留空时,使用当前请求的基础地址。
对话历史写入
下表配置项的完整名称都以 ConversationHistory: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Mode | Interval | Immediate:有需要保存的内容就立即写入数据库。Interval:先暂存在内存中,隔一段时间一起保存。TurnEnd:主要等这一回合结束后再保存。暂存内容达到大小上限时,也会提前保存。 |
FlushIntervalSeconds | 10 秒 | Server 自带的 appsettings.json 设为 10 秒;如果所有配置来源都没有设置这一项,程序使用 5 秒。Interval 模式下,隔多少秒把暂存内容保存到数据库。必须大于 0,且不能超过程序计时器支持的范围。 |
MaxBufferedBytes | 16777216(16 MiB) | 允许暂存在内存中的内容大小,单位字节。默认 16 MiB;达到上限会提前保存到数据库,必须大于 0。 |
这些设置决定聊天记录什么时候保存到数据库,页面仍可实时显示回复。先暂存、后保存可以减少数据库写入,但程序意外退出时,尚未保存的部分可能丢失。如果更看重记录及时保存,可以选择 Immediate。
Shell 工具
下表配置项的完整名称都以 Agents:Shell: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Backend | local | local:直接在运行 Agent 的主机上执行命令,使用项目工作目录。docker:在 Docker 容器中执行命令,需要主机已安装并能使用 Docker。容器中的项目目录为 /workspace,附加目录为 /project-directories/{id};当前容器禁用网络,命令超时为 30 秒。 |
此项只选择 AGW Shell 工具的执行后端,不改变整个 Server 的部署模式,也不为外部 Agent 安装 CLI。
OpenTelemetry
OpenTelemetry 用于把运行指标和调用追踪等信息发送到监控系统,帮助排查慢请求和错误。已有监控服务时,填写它的接收地址;刚开始使用时,先了解下面的默认行为即可。
下表配置项的完整名称都以 OpenTelemetry: 开头。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
ServiceName | appsettings.json Agw | 监控系统中显示的服务名称。分离 Host 遇到appsettings.json值 Agw 时会改为 Agw.ControlPlane 或 Agw.DataPlane;未设置时使用 Agw.{Host角色}。 |
ServiceVersion | 1.0.0 | 监控系统中显示的版本号,方便区分不同版本的运行情况。 |
OtlpEndpoint | appsettings.json空 | 接收运行指标、调用追踪等数据的监控服务地址。留空或不填时,不启用 OpenTelemetry 的追踪、指标和日志导出。 |
日志配置
日志记录 Server 运行中发生的事情。级别越详细,越有利于排查问题,但产生的日志也越多。下面保留完整配置名,日常调整通常只需关注日志级别和保存目录。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
Logging:LogLevel:Default | Information | Microsoft 日志默认记录到什么详细程度;可用 Logging:LogLevel:{类别} 单独调整某个模块。 |
Logging:LogLevel:Microsoft.AspNetCore | Warning | Web 请求处理相关日志的详细程度。 |
Logging:LogLevel:Microsoft.EntityFrameworkCore | Warning | 数据库访问相关日志的详细程度。 |
Serilog:Using | Console、File、Async sinks | 启用控制台、文件和异步输出功能所需的日志组件。一般无需修改。 |
Serilog:MinimumLevel:Default | Information;Development 为 Debug | Serilog 默认保留的最低日志级别。低于该级别的日志不会输出。 |
Serilog:MinimumLevel:Override:Microsoft.AspNetCore | Warning | 单独设置 Web 请求相关日志的最低级别。 |
Serilog:MinimumLevel:Override:Microsoft.EntityFrameworkCore | Warning | 单独设置数据库访问日志的最低级别。 |
Serilog:MinimumLevel:Override:System | Warning | 单独设置 System 系统组件日志的最低级别;其他类别可按同样方式设置。 |
Serilog:WriteTo:0:Name | Async | 让日志在后台输出,减少写日志对请求处理的影响。一般保留 Async。 |
Serilog:WriteTo:0:Args:configure:0:Name | Console | 将日志输出到运行 Server 的终端或容器日志中。 |
Serilog:WriteTo:0:Args:configure:0:Args:outputTemplate | 见下方 | 控制台行格式,包含时间、级别、来源、TraceId、SpanId、线程、消息与异常。 |
Serilog:Enrich | FromLogContext、WithMachineName、WithThreadId、WithOpenTelemetryTraceId、WithOpenTelemetrySpanId | 给日志补充主机名、线程和请求追踪信息,方便把同一次操作的记录联系起来。 |
当前 Host 的 Serilog 配置从 appsettings.json 及 appsettings.{ASPNETCORE_ENVIRONMENT}.json 单独读取;不能假设 Serilog__... 环境变量会覆盖这条管线。修改日志输出或级别时编辑相应 JSON 并重启。Logging 与 Serilog 是两套级别配置,当前主要输出使用 Serilog。
Microsoft 日志级别全部为:Trace(最细追踪)、Debug(调试)、Information(正常运行)、Warning(异常征兆)、Error(操作失败)、Critical(严重故障)、None(关闭)。Serilog 对应支持 Verbose、Debug、Information、Warning、Error、Fatal;其中 Verbose 对应最细追踪,Fatal 对应严重故障,Serilog 最小级别没有 None。
WriteTo 的 Name、Using 和 Enrich 是插件名称,不是固定枚举;上表列的是当前appsettings.json。Host 还额外写入 AgwLogDir/application-{角色}-.log,每小时生成一个新日志文件,保留 30 个文件,每秒将日志写入磁盘;这些规则由程序固定,不能通过本页配置修改。
认证与 API Key
在浏览器中使用远程 Web 时,用管理员密码登录,浏览器会通过 Cookie 记住登录状态。Desktop、Mobile 和自动化程序则使用 API Key(访问密钥),它相当于这些客户端连接 Server 的钥匙。请求格式为:
在 Server 所在主机上直接访问时,满足以下全部条件的请求会自动以管理员 1001 的身份通过认证,不需要密码或 API Key:来源是回环地址,没有任何转发请求头,访问的主机名是 localhost 或回环 IP,且请求不带认证请求头或登录 Cookie。经过反向代理或从其他主机访问的请求不满足这些条件。
创建 API Key 时为它起一个便于识别的名称,并保存当时显示的完整值;之后不会再次显示。自动化程序可以从环境变量或机密配置中读取它。不再使用时撤销该 API Key。Server 会按创建者的身份判断它能访问哪些资源。每个 Server 会把验证通过的 API Key 缓存 30 秒:处理撤销请求的 Server 立即清除缓存;分离部署且没有共享的分布式缓存时,其他副本最多 30 秒后停止接受该 API Key。多账号登录通过下一节的第三方登录配置;当前不提供角色、API Key 权限范围(scopes)或 JWT 的配置。
密码和 API Key 都以用于验证的哈希值保存在数据库中,不保存原文。管理员认证信息位于 setting 表的 auth 分组,API Key 信息位于 api_token 表,由管理功能自动维护,无需在 appsettings 中填写。修改管理员密码后,各 Server 会检查新的登录状态版本;检查每秒进行一次,读取失败时不再沿用缓存的认证信息。忘记密码可先停止 Server,再运行 agw-server auth reset-password;分离部署使用 agw-control-plane auth reset-password。新密码需要 12–256 个字符,重置后已有的 Web 登录会话全部失效。
第三方登录
启用第三方登录后,用户可以用组织账号进入 Web 和 Desktop。每个账号首次登录时创建一个独立的本地用户,编号从 10000 开始,管理员仍是 1001。未配置提供商时,管理员密码和 API Key 继续可用。行为说明见第三方账号登录。
在提供商侧把 AGW 登记为 Web 应用(保密客户端),回调地址按提供商 ID 组成。Desktop 用户同样使用这个地址,提供商把浏览器送回 Server,不直接送回桌面程序:
下表配置项的完整名称都以 Auth:Oidc: 开头,{id} 是你为提供商起的编号。
| 配置项 | 默认值 | 用途与可选值 |
|---|---|---|
PublicBaseUrl | 空 | 浏览器访问 Server 的地址,验证完成后返回这里。程序在它后面加上 api/auth/oidc/callback/{id}。必须是不带路径的完整地址,生产环境使用 HTTPS,开发环境允许本机 HTTP。启用任一提供商后必填。 |
WebBaseUrl | 空 | 登录结束后返回的 Web 界面地址。Web 与 Server 同源时留空;源码开发中 Web 在 3001、后端在 30816 时需要填写。 |
Providers:{id}:Enabled | false | 是否启用该提供商。 |
Providers:{id}:Type | Oidc | Oidc:按 Authority 自动读取端点,请求 openid profile email。OAuth2:逐项填写端点和字段名称。 |
Providers:{id}:DisplayName | 提供商 ID | 登录按钮上显示的名称。 |
Providers:{id}:ClientId | 空 | 在提供商侧登记 AGW 得到的客户端编号,必填。 |
Providers:{id}:ClientSecret | 空 | 对应的客户端密钥,必填,通过环境变量或机密配置注入。 |
Providers:{id}:Authority | 空 | Type 为 Oidc 时必填,例如 https://sso.example.com/realms/company。 |
Providers:{id}:AuthorizationEndpoint | 空 | Type 为 OAuth2 时必填,用户跳转到提供商的授权地址。 |
Providers:{id}:TokenEndpoint | 空 | Type 为 OAuth2 时必填,Server 换取访问令牌的地址。 |
Providers:{id}:Issuer | 空 | Type 为 OAuth2 时必填,用于标识账号来源,与账号编号一起确定用户身份。 |
Providers:{id}:IdentitySource | UserInfo | 仅用于 OAuth2。UserInfo:调用用户信息接口读取账号。AccessToken:从签名的 JWT 访问令牌读取账号。 |
Providers:{id}:UserInfoEndpoint | 空 | IdentitySource 为 UserInfo 时必填。 |
Providers:{id}:AccessTokenIssuer | 空 | IdentitySource 为 AccessToken 时必填,校验令牌的签发者。 |
Providers:{id}:AccessTokenAudience | 空 | IdentitySource 为 AccessToken 时必填,校验令牌的接收方。 |
Providers:{id}:AccessTokenJwksUri | 空 | IdentitySource 为 AccessToken 时必填,读取验签公钥的地址。 |
Providers:{id}:ClientAuthMethod | Post | OAuth2 换取令牌时提交客户端凭据的方式:Post 放在请求体,Basic 放在请求头。 |
Providers:{id}:UsePkce | false | OAuth2 是否启用 S256 校验。Type 为 Oidc 时固定启用。 |
Providers:{id}:Scopes | 空 | OAuth2 申请的权限范围,按数字下标配置,例如 Scopes__0=read:user。 |
Providers:{id}:SubjectClaim | sub | 仅用于 OAuth2,账号编号对应的字段名称,例如 GitHub 使用 id。Oidc 固定使用 sub。 |
Providers:{id}:DisplayNameClaim | name | 仅用于 OAuth2,显示名称对应的字段名称,例如 GitHub 使用 login。Oidc 固定使用 name。 |
Providers:{id}:EmailClaim | 仅用于 OAuth2,邮箱对应的字段名称;Oidc 固定使用 email。缺少显示名称或邮箱不影响登录。 |
提供商 ID 使用小写字母、数字和连字符,最长 64 个字符,例如 company、entra-id。每个 ID 对应各自的回调地址,登记后不要再修改。
不含密钥的配置示例:
对应的密钥通过 Auth__Oidc__Providers__company__ClientSecret 注入,不要写入 appsettings、前端环境文件或截图。GitHub 这类只提供 OAuth2 的服务改用下面的写法:
常见提供商的 Authority:
| 平台 | Authority |
|---|---|
https://accounts.google.com | |
| Microsoft Entra ID | https://login.microsoftonline.com/<租户 ID>/v2.0 |
| Keycloak | https://sso.example.com/realms/<realm> |
| Authentik | https://sso.example.com/application/o/<应用标识>/ |
修改这些配置后重启相应的 Server 程序。分离部署把登录相关请求指向 Control Plane,数据面使用由此得到的本地凭据;所有副本共用同一套数据库和数据保护密钥,Desktop 的一次性代码可以在不同副本上完成换取。停用某个提供商会阻止新的登录和尚未完成的 Desktop 换取,已经签发的 Cookie 和 API Key 需要单独撤销。
配置示例与验证
下面的示例只展示设置方式,连接字符串应通过环境或 Secrets 注入实际值:
分离部署将相同数据库和执行配置传给各 Host,先初始化 Control Plane,再启动 Data Plane。上面的 agw-server 是 Standalone 程序,分离部署使用相应 Host 程序。
重启后检查启动日志、访问地址、数据库连接和客户端登录。调整执行参数后,先运行一个小任务,观察开始速度、完成时间和资源占用。启动报错时,先检查选项名称是否拼写正确、数值是否在允许范围内、数据库地址和凭据是否正确,以及 Distributed 所需的数据库和锁是否已配置。排查日志时不要公开密码或 API Key。
实现与参考
4 - 数据目录、备份与升级
最近更新:
备份需要同时保留 AGW 的配置和记录、加密密钥,以及项目文件。只复制安装目录,或只保存代码仓库,都可能遗漏恢复服务所需的数据。
开始前,确认实际数据库、数据目录和各 Project 工作目录的位置;下面的默认路径仅用于帮助定位,以运行中的配置为准。
数据范围
AgwDataDir 默认 ~/agw,Docker 使用 /data。路径支持 ~,其他相对路径相对进程工作目录解析。默认的 SQLite 数据库文件是 <AgwDataDir>/database/agw.db,Docker 中为 /data/database/agw.db。
需要一起保存:
- 数据库,包括
setting、api_token、会话和执行记录。 - 数据目录中的
keys/和skills/。 - 部署配置及其秘密引用,实际秘密通过安全存储备份。
- 各 Project 主目录与附加目录中的业务文件,使用独立文件备份策略。
日志目录独立于数据目录;日志和临时文件不属于认证恢复必需数据。丢失 Data Protection 密钥可能使已保护凭据无法读取。
先列出备份清单
记录数据库位置、AgwDataDir 的实际值、各 Project 的目录及当前程序版本。项目使用文件型 Memory 时,还要包含主目录下的隐藏目录 .agw/memory/;数据库型 Memory 随数据库保存。表单默认的主目录 ~/.agw/<项目文件夹名> 和 Server 默认的 ~/.agw/projects/{projectId:N} 都位于运行 Server 的账号的主目录下,不在 AgwDataDir 中;Docker 中也不在 /data 卷内,需要另外挂载并备份。
备份数据库和文件前,先等待任务结束或中断任务,避免备份期间仍有写入。SQLite 的简单做法是停止 Server 后复制数据库及相关文件;PostgreSQL 使用自己的备份工具。数据目录和项目目录可能在不同位置,应逐项核对,不能假定它们都在 /data 内。
升级顺序
- 阅读目标 Release 说明,记录当前镜像或安装包版本。
- 停止全部旧版 Standalone、Control Plane 和 Data Plane 进程,取得一致性备份:SQLite 简单部署可在停止后复制文件;PostgreSQL 使用数据库自身的备份机制。
- 应用新版本对应数据库的迁移(SQLite 或 PostgreSQL 其中一套)。已初始化的 Server 正常启动时不会自动执行迁移,只有首次 Setup 会执行;源码部署可使用 Development Guide 中按数据库区分的命令。
- 更新 Server 与客户端,保留数据、Data Protection 密钥和目录挂载,再启动新版本。新版 Host 在接受请求和启动 Worker 之前,会检查并升级正在进行的执行记录;某条记录无法解密或验证失败时,Host 启动报错,需要修正数据后重新启动。
- 验证初始化状态、登录、Project 文件和一个小任务;分离部署还需验证 worker 与 Job。
AGW 在 1.0 前的升级可能包含 schema 变更。回滚时需要使用彼此兼容的程序版本、数据库备份和密钥备份。
恢复验证
优先在隔离环境验证备份能恢复,确认凭据可解密、文件路径可见。更改数据或日志根目录需要重启并自行迁移文件,不会自动搬运已有数据。
实现与参考
5 - 日志与常见问题
最近更新:
排查时先确定故障发生在哪一步:页面连接、登录、模型调用,还是文件和工具操作。用一个简单任务重现问题,通常比反复重启更容易找到原因。
记录出错的 Server、Project、会话和时间,再查看对应服务日志。分离部署的管理问题主要查控制面日志,任务执行问题主要查数据面日志。
排查顺序
| 现象 | 优先检查 |
|---|---|
| 无法打开界面 | 监听地址、端口、容器映射、代理目标 |
| Setup 无法完成 | 数据库连接、目录写权限、远程 Setup Code |
| 登录或 API Key 失败 | 实际 Server、API Key 撤销情况、数据库认证状态 |
| 第三方登录失败 | Auth:Oidc:PublicBaseUrl、提供商侧登记的回调地址、客户端凭据、Server 到提供商的网络 |
| Agent 不回复 | Model Provider、模型 ID、凭据、待审批/待输入状态 |
| CLI 无法启动 | 执行节点的可执行文件、账号与环境 |
| 文件找不到 | 当前目录选择、Server 路径、挂载和访问权限 |
| Job 没运行 | 启用状态、未来时间、UTC Cron、有效目标和日志 |
| 断线后状态不对 | 会话选择、WebSocket 代理、执行是否仍在后台运行;InProcess 模式下 Server 重启后,原来运行中的会话会显示为 Interrupted,不会继续执行 |
示例:页面能打开,但 Agent 不回复
- 查看 Chat 是否正在等待审批或补充信息。如果是,先处理请求。
- 使用同一个模型连接运行一条纯文字问题。如果仍失败,检查 API 地址、模型 ID 和凭据。
- 纯文字正常而工具任务失败时,检查工具绑定、工作目录和执行主机的访问权限。
- 分离部署中,若配置页面正常而对话连接失败,检查
/api/hubs/exec是否转发到数据面,以及代理是否支持 WebSocket。 - 根据出错时间查找服务日志中的具体错误,修改后重复同一个小任务验证。
这个顺序可以把模型、工具和连接问题分开,避免同时更改多项设置后无法判断原因。
第三方登录失败
第三方登录失败时,浏览器回到登录页,地址中带有 error=oidc-<类别>,Desktop 在 Server 配置处显示提示。用这个类别配合 Agw.Auth.Oidc 日志定位原因:日志记录提供商、客户端、失败所处的阶段、失败类别和 TraceId。
| 类别 | 通常的原因 |
|---|---|
provider-unavailable、provider-timeout | Server 访问不到提供商:网络、出站代理或防火墙 |
provider-rejected | 能访问提供商,但 OAuth2 的用户信息接口返回错误状态码:检查 UserInfoEndpoint、Scopes 和令牌权限 |
protocol-rejected | OIDC 提供商返回协议错误:客户端编号、密钥或已登记的回调地址不符 |
invalid-state、invalid-nonce | 回调校验未通过:浏览器访问的地址与 PublicBaseUrl 不一致,或校验用的 Cookie 被拦截 |
invalid-token | 令牌校验未通过:Authority、签发者、接收方或验签地址配置不符 |
protocol-validation-failed | 其他未归类的协议失败,包括 OAuth2 换取令牌被拒绝:先检查客户端编号、密钥和回调地址 |
provisioning-failed、grant-creation-failed、session-creation-failed | Server 本地处理失败:先检查数据库连接和迁移是否完成 |
authorization-denied | 用户在提供商页面取消了授权 |
排查时不要关闭签发者、接收方、签名、state、nonce 或 PKCE 校验。反向代理需要保留原始协议和主机名,否则回调会落在另一个来源上。报告问题时不要附带认证相关的查询参数和完整的提供商响应。
日志与遥测
AgwLogDir 默认 ./logs,不随 AgwDataDir 自动变化。分离部署要查看对应角色日志。需要集中遥测时配置 OpenTelemetry:OtlpEndpoint;空值或缺失时不启用 OpenTelemetry 的追踪、指标和日志导出。
历史采用 Interval 批量写入。Host 模板的 ConversationHistory:FlushIntervalSeconds 为 10 秒,省略时回退到 5 秒。即时输出与已落库历史存在时间差。
Web 开发代理
Web 开发运行在 3001,后端默认 30816。代理目标依次取 BACKEND_API_BASE_URL、NEXT_PUBLIC_API_BASE_URL、默认本机地址。静态 export 模式不使用 Next.js 代理,应由 Server 或外部入口提供同源路由。
修复后重复原来失败的小任务,确认界面状态和日志都恢复。报告问题时提供版本、部署方式、复现步骤和脱敏错误,不附带真实 API Key 或完整 OAuth 响应。