返回资料库
A2A

在 Hermes Agent 上部署 A2A:Docker 网关参考栈

最后更新:2026年7月23日

在生产环境中运行 A2A 意味着桥接两个从未被设计为相互通信的协议——并在一个网关后面完成认证、租户隔离和流式传输而不丢失 token。这个参考栈解决了阻止 A2A 部署的三个问题:协议转换(JSON-RPC 2.0 到 OpenAI 兼容的 chat completions)、流式协调(A2A 工件 SSE 到 Hermes 运行事件 SSE)以及多租户安全(每次查询的 PostgreSQL 行级安全)。如果你需要不同框架上的代理相互委托工作,这里的模式就是部署路径。

关键要点

  • 3 层架构,1 个 Docker Compose 栈 — SilvaEngine Gateway 负责传输与鉴权,A2A Daemon Engine 负责协议逻辑,HermesAgentHandler 桥接到 Hermes Agent 的 OpenAI 兼容 API。docker-a2a-hermes-agent-gateway 仓库将三者打包在一起。
  • 单端口 5 个协议面 — JSON-RPC 2.0、GraphQL、SSE 流、SSE 推送和 Agent Card 发现,全部位于端口 8765 上单个网关之后,采用 JWT 或 AWS Cognito 鉴权。
  • PostgreSQL 行级安全强制租户隔离 — 复合键 partition_key = "{endpoint_id}#{Part-Id}" 通过四张 A2A 表上的 RLS 策略在数据库层面强制执行,而非仅依赖应用代码。
  • A2A SDK v2 的单消息约束塑造了流式架构 — 桥接将 token 分块实时发送到 SSE,并在流完成后将单个累积 Message 发送到 SDK EventQueue,避免 InvalidAgentResponseError
  • 跨 5 个脚本的 15 项端到端测试检查 — 从非流式冒烟测试到完整的 SSE 流式管线并验证 HTTP 回退,全部可用 pip install requests 运行。

Agent2Agent Protocol(A2A)定义了 AI 智能体如何通过 JSON-RPC 2.0 互相发现、委派和流式传输任务。Hermes Agent(由 Nous Research 开发)在 /v1/chat/completions 暴露 OpenAI 兼容的 API Server,并在 /v1/runs/v1/runs/{id}/events 提供基于 runs 的 SSE 流式接口。两者并不使用同一种语言。A2A 发送带有结构化 parts 的 message/send;Hermes 接收的是聊天补全负载。A2A 通过 SSE 流式传输任务制品;Hermes 通过 run 事件流式传输 token 增量。

docker-a2a-hermes-agent-gateway 仓库以单一容器镜像和 docker compose 栈弥合了这一鸿沟。它运行 SilvaEngine Gateway,仅注册 a2a_daemon_engine 模块,暴露完整的 A2A 协议面,并通过 HTTP + SSE 将 A2A 任务桥接到一个 Hermes Agent API Server 实例。状态持久化到内置的 PostgreSQL 后端,并通过行级安全实现租户隔离。

本文梳理了三层架构、从 A2A 客户端到 Hermes 再返回的请求生命周期、配置与部署模式,以及在生产环境中于 Hermes Agent 上运行 A2A 的运维关注点。这是一份参考部署指南——通用模式(网关介导的、桥接到任意智能体框架的 A2A)才是主题;Docker 栈是具体的实现范例。

三层架构

该栈将关注点分离为三层,每层由一个独立组件负责:

Hermes Agent 上的 A2A — 三层栈 docker-a2a-hermes-agent-gateway 参考部署 1 A2A 客户端 任何使用 JSON-RPC 2.0 的智能体或应用 message/send · tasks/get · SSE 2 SilvaEngine Gateway 传输 · 鉴权 · 路由 · SSE 客户端生命周期 JWT / Cognito 鉴权 Part-Id 租户路由 SSE 客户端注册表 速率限制 3 A2A Daemon Engine 协议逻辑 · 任务状态机 · 处理器分发 Agent Card 服务 任务生命周期 HermesAgentHandler 双路流式 Hermes Agent API Server OpenAI 兼容 · SSE runs /v1/chat/completions /v1/runs + /events PostgreSQL 持久化 · RLS 租户隔离 a2a_agents / tasks messages / settings 网关是唯一常驻服务 — Hermes 和 PostgreSQL 是按需启用的兄弟服务 — ideabosque.com/library

网关是唯一常驻服务。Hermes 和 PostgreSQL 都是按需启用的兄弟服务——将它们打包即可获得自包含栈,或者关闭这些 profile,将 HERMES_API_URLPG_HOST 指向外部实例。这对生产环境很重要:你可以在自己的 VPC 中运行网关,并将其指向托管的 Postgres(RDS、Cloud SQL)以及运行在别处 GPU 节点上的 Hermes 实例。

第 1 层:SilvaEngine Gateway — 传输与鉴权

SilvaEngine Gateway 是一个 FastAPI 网关,用于对已安装模块进行经过鉴权的进程内访问。它通过可配置的 YAML 路由清单暴露模块的 GraphQL 和 REST 路由——添加新模块只需修改清单,无需编写任何网关 Python 代码。在本栈中,仅注册了 A2A Daemon Engine。

网关负责:

  • 鉴权 — 本地 JWT(HS256)或 AWS Cognito(RS256 + JWKS),由 GATEWAY_AUTH_PROVIDER 选择
  • 路由 — YAML 清单将 URL 路径映射到模块分发函数
  • SSE 客户端生命周期sse_manager 按模块解析并管理长生命周期客户端连接
  • 速率限制 — 基于 IP 的内存速率限制(GATEWAY_RATE_LIMIT 请求 / GATEWAY_RATE_WINDOW 秒)
  • 线程池分发 — 同步模块分发函数在可配置线程池中运行(GATEWAY_DISPATCH_WORKERS,Docker 镜像默认 32)

网关根据 URL 路径段和 Part-Id 请求头构建 partition_key = "{endpoint_id}#{Part-Id}"。每个租户范围的请求都需要该头。位于 /{ep}/.well-known/agent-card.json 的 Agent Card 端点按 A2A 规范是公开的(无需鉴权),但仍需要 Part-Id,因为卡片是按分区解析的。

第 2 层:A2A Daemon Engine — 协议逻辑

a2a_daemon_engine 不是一个独立服务。它通过 main.py 中的 deploy() 作为已注册的网关模块加载,声明了三个面向网关的入口点:

入口点 网关路由 方法 用途
a2a_core_graphql POST /{ep}/a2a_core_graphql POST 针对智能体、任务、消息、设置的 GraphQL CRUD
a2a POST /{ep}/a2a POST A2A JSON-RPC 协议(message/sendtasks/gettasks/canceltasks/list
sse_message POST /{ep}/a2a_sse POST A2A JSON-RPC 消息 + 推送到 SSE 客户端

网关额外暴露 GET /{ep}/a2a_sse 用于 SSE 流。在生产环境中,守护进程不监听自己的端口,也不运行自己的 HTTP 服务器。所有传输、鉴权和 SSE 客户端生命周期均由网关负责。

守护进程提供:

  • A2A SDK v1.0 — 基于 HTTP 的 JSON-RPC,构建于官方 A2A SDK 服务端模式
  • 公开 Agent Card 位于 /.well-known/agent-card.json,支持 ETag 和 Last-Modified
  • 任务状态机submittedworkinginput-required | completed | failed | canceled
  • 双后端持久化 — DynamoDB(PynamoDB)或 PostgreSQL(SQLAlchemy + Alembic)。Docker 镜像强制使用 PostgreSQL。
  • 多租户隔离 — 复合分区键({endpoint_id}#{part_id})配合 PostgreSQL 行级安全
  • 可插拔 LLM 处理器 — 在智能体注册表中按智能体选择 module_name / class_name

第 3 层:HermesAgentHandler — 桥接

Hermes 桥接处理器(a2a_daemon_engine/handlers/a2a_hermes_handler.py)是唯一框架特定的代码。它实现了 ask_model() 接口:接受 A2A 消息 parts 和上下文,调用 Hermes Agent API Server,将响应转换回 A2A 消息 parts,对于流式情况,将 token 增量转发到 SSE 通道。

该处理器支持两种执行模式:

非流式映射到 Hermes API Server 的 POST /v1/chat/completions — 即 OpenAI 兼容端点。请求将转换后的 A2A 消息 parts 作为聊天补全负载携带。Hermes 处理请求并返回单个响应。处理器将响应转换为带 ROLE_AGENT 的 A2A Message 并发送到 SDK EventQueue。客户端收到一个包含完整智能体文本的 JSON-RPC 响应。

流式映射到 POST /v1/runs 以创建 run,然后打开到 GET /v1/runs/{id}/events 的 SSE 连接。Hermes 在事件发生时流式传输:token 增量(message.delta)、推理元数据(reasoning.available)、工具调用/结果通知、审批请求(approval.required)以及生命周期事件(run.createdrun.completedrun.failed)。处理器在后台线程中运行排空循环。每个 message.delta 事件被推送到网关的 SSE 管理器,实时投递给已连接的客户端。当 run.completed 到达时,累积文本作为单个 A2A Message 发送到 SDK EventQueue。

请求生命周期

一个带 stream=truemessage/send 需经过八个步骤:

1. Client         POST /{ep}/a2a  {jsonrpc, method:"message/send", params}
                  Headers: Authorization: Bearer *** Part-Id: 
2. Gateway        auth (local JWT / Cognito) → route match from routes.yaml
                  → partition_key = "{ep}#{Part-Id}"
3. a2a_daemon     dispatch_a2a → A2ADaemonExecutor
                  → resolve_agent(): agent metadata (DB) > setting dict > Config (env)
4. Handler        HermesAgentHandler (A2A_AI_AGENT_MODULE / _CLASS)
5. Hermes         POST {HERMES_API_URL}/v1/runs   (Bearer HERMES_API_KEY)
                  GET  {HERMES_API_URL}/v1/runs/{id}/events   (SSE)
6. Broadcast      token chunks → subscribers on GET /{ep}/a2a_sse
7. Persist        task + messages written to PostgreSQL (a2a_* tables, RLS-scoped)
8. Response       accumulated reply also returned in the HTTP JSON-RPC result

第 8 步很关键:即使在流式情况下,HTTP 响应也携带完整回复。错过 SSE 帧的客户端仍可回退到 HTTP 响应。端到端测试套件(test_hermes_sse_live.py)在其第 06 步中显式验证了这一回退。

智能体解析优先级

配置解析遵循优先级链:智能体元数据(DB)→ setting dict → Config 默认值(环境变量)。按智能体的覆盖优先于全局默认值。两个智能体可以指向不同框架——一个指向 Hermes 处理推理密集型任务,另一个指向不同处理器处理工作流编排任务——而 A2A 协议面对调用方智能体时看起来完全相同。

对于由 Hermes 支持的智能体,存储在 a2a_agents 表中的元数据如下:

{
  "module_name": "a2a_daemon_engine.handlers.a2a_hermes_handler",
  "class_name": "HermesAgentHandler",
  "hermes_api_url": "http://127.0.0.1:8642",
  "hermes_api_key": "hermes-local-key",
  "hermes_model": "hermes-agent",
  "hermes_timeout": 300.0
}

环境变量默认值(HERMES_API_URLHERMES_API_KEYHERMES_MODEL)让桥接在没有数据库智能体记录时也能到达 Hermes——当不存在智能体记录时,a2a_ai_agent_utility.py 中的 resolve_agent() 函数回退到环境变量。这意味着你可以启动栈并直接发送 message/send 而无需注册任何智能体,它将使用环境默认值路由到 Hermes。

A2A 状态映射

桥接将 Hermes SSE 事件映射到 A2A 任务状态。这张表是桥接的核心——每个框架集成都会产生一张等价表:

Hermes SSE 事件 A2A 任务状态 桥接动作
run.created(返回 run_id) WORKING 注册 run_id 以支持取消
message.delta WORKING 累积 token;按分块发送到 SSE
reasoning.available WORKING 推理元数据 — 不发送 token
tool.call / tool.result WORKING 仅工具执行元数据
approval.required INPUT_REQUIRED 发送审批分块;存储 pending_approval
run.completed COMPLETED 设置流事件;累积最终文本
run.failed FAILED 发送错误分块;设置 FAILED 状态
POST /v1/runs/{id}/stop CANCELED 通过 tasks/cancel 外部取消
POST /v1/runs/{id}/approval (继续 run) 通过 operation="approval_response" 解决

a2a_daemon_engine 仓库中的 HERMES_INTEGRATION.md 文档记录了确切的 Hermes 事件格式、配置键和端到端流程细节。

跨智能体边界的人在回路审批

Hermes 支持人在回路审批门控——当智能体需要执行敏感操作的许可时,它会暂停并发出审批请求。桥接将其转换为 A2A INPUT_REQUIRED 状态,向调用方智能体(或人类操作员)发出需要输入的信号。响应通过 POST /v1/runs/{id}/approval 返回,run 随即继续。

这正是桥接模式体现价值之处。A2A 将 INPUT_REQUIRED 定义为一等任务状态。Hermes 有自己的审批机制。桥接将两者映射,而调用方智能体——它本身可能是运行在完全不同框架上的 A2A 客户端——看到的是标准协议状态转换,而非 Hermes 特有的细节。一条智能体委派链可以包含一个需要人工审批的步骤(采购授权、数据访问决策、报价审批),而 A2A 协议会透明地跨越框架边界传递该门控。

A2A SDK v2 约束与双路修复

A2A SDK v2(a2a-sdk==1.0.2)对 on_message_send 路径施加了两项约束,塑造了桥接实现:

  1. 仅单个 Message。 向 SDK EventQueue 发送多个 Message 对象会引发 InvalidAgentResponseError: Multiple Message objects received.
  2. 无 TaskStatusUpdateEvent。 状态事件会引发 InvalidAgentResponseError: Received TaskStatusUpdateEvent in message mode.

朴素的桥接会为每个 token 增量发送一个 Message——这是自然的流式模式。SDK 拒绝这样做,并拒绝在 message/send 路径上的状态事件(WORKING、COMPLETED)。

修复方案是双路输出通道:

  • SSE(网关管理): Token 分块实时推送到 SSE。已连接的客户端实时看到流式输出。状态事件(WORKING、COMPLETED、FAILED)也仅发送到 SSE。
  • SDK EventQueue: 流完成后,将一个包含完整响应文本的累积 Message 发送到 SDK EventQueue。这是 JSON-RPC message/send 响应所返回的内容。

客户端通过 SSE 获得实时流式输出,并通过 SDK 获得干净的单消息 JSON-RPC 响应。两个通道都能工作;都不违反 SDK 约束。

单端口上的协议面

网关在单个端口(默认 8765)上暴露五个协议面:

协议 路由 鉴权 用途
GraphQL POST /{ep}/a2a_core_graphql A2A 核心查询/变更(智能体、任务、消息、设置)
JSON-RPC 2.0 POST /{ep}/a2a A2A 协议:message/sendtasks/gettasks/canceltasks/list
SSE(流) GET /{ep}/a2a_sse 长生命周期的按分区 A2A 任务事件流
SSE(推送) POST /{ep}/a2a_sse JSON-RPC 消息 + 推送到已连接的 SSE 客户端
Agent Card GET /{ep}/.well-known/agent-card.json 公开 A2A 发现文档(仍需 Part-Id 头)

测试工具使用的 JSON-RPC message/send 参数结构:

{
  "message": {
    "role": "ROLE_USER",
    "parts": [{ "text": "Say hello from A2A" }]
  },
  "metadata": {
    "operation": "task_execution",
    "agent_uuid": "a2a-hermes-agent",
    "stream": true,
    "task_data": { "task_id": "my-task-001", "task_type": "hermes_test" },
    "system_prompt": "You are a concise assistant.",
    "conversation_history": []
  }
}

metadata.operation 字段选择执行路径:task_execution 用于支持流式的智能体 run,message_response 用于非流式聊天。agent_uuid 指向注册表中的特定智能体。stream 标志启用 SSE 广播。task_data.task_id 是调用方提供的 id,用于 tasks/gettasks/cancel

SSE 是按分区的,而非按任务的。{ep}#{Part-Id} 中的每个任务都广播给该分区的所有订阅者。操作顺序很关键:在发送消息之前先连接 SSE 监听器,否则会错过早期的 token 分块。

持久化与多租户

Docker 镜像强制 db_backend=postgresql — 不支持 DynamoDB。守护进程使用字面、无前缀的表名:

存储
a2a_agents 智能体记录 + 按智能体的处理器/模型元数据
a2a_tasks 任务生命周期 + 状态
a2a_messages 每个任务的消息轮次
a2a_settings 按分区的设置 dict

由于名称无前缀,请不要将 PG_DB 与使用相同名称的其他模块共享。

租户隔离使用 PostgreSQL 行级安全。会话变量 app.tenant_id 被设置为请求的 partition_key"{endpoint_id}#{Part-Id}"),RLS 策略将每个查询限定到该值。当 initialize_tables=1 时,表和策略在网关启动时自动创建。这意味着应用代码中遗漏的 partition_key 过滤器不会泄漏跨租户行——数据库强制了边界。

RLS 实现位于 a2a_daemon_engine/utils/rls.pyset_rls_contextcreate_rls_policies)以及迁移 0005_enable_rls_policies 中。set_rls_context 函数在连接上运行每请求的 SET app.tenant_idcreate_rls_policies 在全部四张 A2A 表上启用并强制 RLS 以及 tenant_isolation 策略。在 DynamoDB 模式下 RLS 不生效。

使用 Docker Compose 部署

该栈有一个常驻服务和两个可选的按需启用兄弟服务:

服务 容器名 是否常驻? Profile 用途
a2a-gateway a2a-hermes-gateway SilvaEngine Gateway(仅 A2A 路由)+ Hermes 桥接
postgres a2a-postgres 可选 postgres 内置 PostgreSQL 持久化后端
hermes container-hermes 可选 hermes 内置 Hermes Agent(OpenAI 兼容 API + 仪表盘)

COMPOSE_PROFILES 是控制两个兄弟服务的单一开关:

启动的服务
仅网关(外部 Postgres + 外部 Hermes)
postgres 网关 + 内置 Postgres
hermes 网关 + 内置 Hermes(外部 Postgres)
postgres,hermes 网关 + 内置 Postgres 和 Hermes(默认)

当兄弟服务被内置时,将其主机引用指向服务名:PG_HOST=postgresHERMES_API_URL=http://hermes:<API_SERVER_PORT>。当兄弟服务为外部时,将它们指向你自己的实例(例如 PG_HOST=host.docker.internalHERMES_API_URL=http://host.docker.internal:8642)。

快速开始

cp .env.example .env

# Fill in: JWT_SECRET_KEY, ADMIN_PASSWORD, API_SERVER_KEY,
# HERMES_API_KEY (= API_SERVER_KEY), HERMES_MODEL_PROVIDER + provider key, HERMES_MODEL

mkdir -p www/hermes www/projects

DOCKER_BUILDKIT=1 docker compose build
docker compose up -d           # COMPOSE_PROFILES=postgres,hermes is the default

docker compose ps              # wait for (healthy)
curl -f http://localhost:8765/health

pip install requests
python test_hermes_hello.py    # end-to-end smoke test

silvaengine_gatewaya2a_daemon_engine 均通过 pip 从 git 安装到镜像中(不挂载主机源码)。镜像是通用的、完全由环境变量驱动——不内嵌任何密钥。模块通过 git+httpsideabosque 下的公开 GitHub 仓库克隆——无需凭据或 SSH 部署密钥。

.env 行内注释陷阱

Docker Compose 的 env_file 解析器不会去除行内注释。像这样一行:

HERMES_API_KEY=hermes-local-key   # token for Hermes

会将 HERMES_API_KEY 设为字面字符串 hermes-local-key # token for Hermes(注释被包含在内),从而静默破坏鉴权。规则是:在任何 KEY=value 行的值之后不要放任何内容。将说明放在变量上方的独立 # 注释行中。

验证:跨 5 个脚本的 15 项端到端检查

该栈附带独立的 Python 测试工具(唯一依赖:requests)。它们加载 ./.env、解析或铸造网关 JWT,并与运行中的栈通信:

脚本 类型 功能
test_hermes_hello.py 冒烟 非流式 message/send,打印回复
test_hermes_hello_sse.py 冒烟 通过 SSE 流式回传一个提示
test_hermes_gateway_live.py E2E 套件 9 项检查:Hermes 健康、网关健康、agent card、GraphQL ping、message/sendtasks/gettasks/listtasks/cancel、失败路径
test_hermes_sse_live.py E2E 套件 6 项检查:健康 ×2、SSE 连接、实时 token 分块、COMPLETED 状态、HTTP 回退
test_hermes_chatbot.py 交互式 针对 A2A 界面的 REPL,带实时 SSE 流式

所有非交互式脚本按步骤打印 PASS/FAIL 并在失败时以非零退出,因此可用作 CI 门控。单元测试套件(test_hermes_handler.py)通过 httpx.MockTransport 模拟 HTTP 运行 24 项测试——无需任何服务。

运维模式

路由变更无需重新构建

routes.yaml 以只读方式绑定挂载到容器中。编辑主机文件并重启网关进程——无需重新构建:

make restart

上游变更之后

由于 silvaengine_gatewaya2a_daemon_engine 在构建时通过 pip 从 git 安装,上游变更需要使用 --no-cache 重新构建,以便 git 层重新克隆最新的 @main

DOCKER_BUILDKIT=1 docker compose build --no-cache
docker compose up -d --force-recreate

没有版本固定——@main 是一个移动目标。如需可复现性,请在 requirements-modules.txt 中固定标签或提交。

扩展到超过一个 worker

内存中的任务状态、速率限制计数器和 SSE 客户端注册表都是按进程的。当 GATEWAY_WORKERS > 1 时,切换到共享后端(GATEWAY_TASK_BACKEND=dynamodbGATEWAY_RATE_LIMIT_BACKEND=dynamodb,外加 region_nameaws_* 凭据),并为 SSE 使用粘性会话。默认配置启动一个 Uvicorn 进程。

需要更改的安全默认值

  • JWT_SECRET_KEY=change-me-in-production — 用 openssl rand -hex 32 替换
  • ADMIN_PASSWORD=change-me — 替换为真实密码
  • POSTGRES_PASSWORD=silvaengine — 替换为真实密码
  • GATEWAY_CORS_ORIGINS=* 允许任意无凭据来源。如需 cookie/凭据,请设置显式列表。
  • 内置 Hermes 挂载主机 Docker socket(/var/run/docker.sock)。这对该容器内的任何内容而言实际上等同于主机 root。仅在受你控制的主机上运行 hermes profile,如果智能体不需要启动容器,请移除该挂载。
  • Hermes 仪表盘默认在端口 9119 启用,且 basic-auth 凭据为空。在暴露主机之前设置 HERMES_DASHBOARD_BASIC_AUTH_* 或将端口绑定到 localhost。
  • RLS 是租户边界。能设置任意 Part-Id 的调用方可读取该分区数据——在你置于其前的任何前端中,将 Part-Id 视为与授权相关的输入。

这带来的能力

三层栈赋予你三项难以从零组装的能力:

1. 无需重写 Hermes 即可实现 A2A 协议合规。 任何 A2A 客户端都可以通过其 Agent Card 发现由 Hermes 支持的智能体,通过 message/send 发送任务,通过 SSE 流式接收响应,并通过标准 A2A 状态跟踪任务生命周期。客户端不知道远端智能体运行的是 Hermes——它看到的是一个带 JSON-RPC 接口的 A2A 端点。

2. 单网关多租户智能体服务。 Part-Id 头配合 PostgreSQL RLS 意味着单个网关实例以硬性的数据库级隔离服务多个租户。每个租户拥有自己的智能体注册表、任务历史和消息存储——全部位于相同的四张表中,由 partition_key 限定范围。

3. 跨智能体边界的人在回路审批。 Hermes 审批门控映射到 A2A INPUT_REQUIRED 状态。一条智能体委派链可以包含一个需要人工审批的步骤,而 A2A 协议将这一状态转换回传给发起智能体或操作员——无论链中每个智能体运行在哪个框架上。

该参考实现还支持用于无服务器 A2A 的 AWS Lambda 分发、带双向流式的实验性 gRPC 传输,以及双后端持久化(DynamoDB 或 PostgreSQL)。a2a_daemon_engine 仓库及其 Hermes 集成指南包含完整实现、配置参考和状态映射细节。SilvaEngine Gateway 仓库记录了路由清单系统、鉴权提供者和模块自动初始化。

相关阅读


一家中端分销商需要报价智能体与目录智能体对话,目录智能体再与库存智能体对话——每个智能体由不同框架支持,每个智能体由不同团队拥有。A2A 为这些智能体提供了共享协议。桥接层让 Hermes Agent 无需重写内部实现即可参与其中。docker-a2a-hermes-agent-gateway 将该桥接打包为单一容器镜像,具备 PostgreSQL 持久化、RLS 多租户和 15 项端到端测试检查。

申请范围明确的构建

一周的发现阶段。你将获得系统清单、工作流映射和固定范围——无论你是否选择与我们合作构建。

想为您的系统构建这个吗?

这里的每份文档都来自真实的生产工作。如果您有目标系统和工作流想法,我们可以在一周内确定范围。

申请定制开发

为期一周的发现阶段。您会拿到系统清单、工作流地图和固定范围——无论您最终是否与我们合作开发。