内容
# 架构代理
用于软件架构规划的**多代理AI**系统。描述一个需求——_"实现SFTP解决方案"_——一个由专门的AI代理组成的管道协作生成解决方案架构和开发票据。审批循环图设计和审查计划;一个单独的工具调用代理通过MCP将其持久化为史诗和票据。审查计划,完善后续工作,或接受它以触发票据创建。








---
## 架构

该系统由十个服务组成,通过HTTP、WebSocket、RabbitMQ和Redis进行通信。所有外部和内部HTTP流量都通过**Kong API网关**。身份验证集中在**Keycloak**:服务间调用使用OAuth 2.0客户端凭证令牌;浏览器用户通过OpenID Connect(OIDC)授权码流与PKCE登录。Kong在转发请求之前验证所有JWT令牌——服务信任Kong传递的内容。
```
┌─────────────────────────────────────────────────────────────────────┐
│ 浏览器 │
│ Next.js 前端 (端口 3000) │
│ · 需求输入、实时思考日志、计划卡、最终回复 │
│ · "Looks good" 按钮 → 接受流程;自由文本 → 完善流程 │
│ · 侧边栏显示对话历史(按登录用户范围) │
│ · /epic/:id 和 /ticket/:id 详情页 │
│ · Keycloak 登录 — OIDC 授权码流 + PKCE │
└──────────────────────┬───────────────────────┬──────────────────────┘
│ HTTP /api/* │ WS /ws
│ (Next.js 代理) │ (直接 WebSocket)
┌──────────────────────▼───────────────────────▼──────────────────────┐
│ Kong API 网关 (端口 8888 外部 · 8000 内部) │
│ · JWT 插件 — 验证 kc_token cookie(浏览器用户)或 │
│ Authorization: Bearer(M2M 服务)对抗 Keycloak RS256 密钥 │
│ · 速率限制 — 每分钟 100 请求/每 IP(所有路由) │
│ · 路由(strip_path: true): │
│ /backend → backend:8000 │
│ /ticket-service → ticket-service:8000 │
│ /ticket-agent → ticket-agent:8000 │
│ /mcp-server → mcp-server:8000 │
└──────────────────────┬───────────────────────────────────────────────┘
│ 删除前缀,转发验证请求
┌──────────────────────▼──────────────────────────────────────────────┐
│ 后端 (NestJS · 端口 8000) │
│ · REST 聊天 API — 保存每对话的用户名 │
│ · 票据代理 — 通过 Kong 转发到 ticket-service │
│ · WebSocket 网关 — 轮询 Redis,推送聊天更新事件 │
│ · PostgreSQL — 对话(uuid,用户名,标题,消息) │
│ · Redis — 实时聊天状态在代理处理期间 │
│ · 向 RabbitMQ 发布 ChatEventInterface(fire-and-forget) │
│ · 解码 kc_token cookie(Kong 验证)以填充 req.user │
└────────────┬─────────────────────────────┬───────────────────────────┘
│ AMQP 发布 │ 读取 / 写入
│ architecture-agent.chat │
┌────────────▼──────────────────────┐ ┌──▼──────────────────────┐
│ RabbitMQ │ │ Redis │
│ 队列: │ │ 键: chat:{uuid} │
│ · architecture-agent.chat │ │ 键: mcp_tools │
│ · architecture-agent.accept │ └──────────────────────────┘
└────────────┬──────────────────────┘
│ AMQP 订阅(architecture-agent.chat)
┌────────────▼────────────────────────────────────────────────────────┐
│ 架构代理 (FastAPI + LangGraph · 端口 8001) │
│ │
│ START → intent_node │
│ │ │
│ ┌─[计划/完善]──────────────────────────────────┐ │
│ │ ▼ │
│ │ ┌─► solution_node │
│ │ │ │ │
│ │ │ ▼ │
│ │ [拒绝]│ solution_review_node │
│ │ └───┘ │ [批准] │
│ │ ▼ │
│ │ ┌─► plan_node │
│ │ │ │ │
│ │ [拒绝]│ plan_review_node │
│ │ └───┘ │ [批准] │
│ │ ▼ │
│ │ reply_node → 结束 │
│ │ │
│ └─[接受]──► 发布 AcceptEvent ──► 结束 │
│ │ │
└──────────────────────────┼──────────────────────────────────────────┘
│ AMQP 发布(architecture-agent.accept)
┌──────────────────────────▼──────────────────────────────────────────┐
│ 票据代理 (FastAPI + LangGraph · StateGraph · 端口 8004) │
│ │
│ START → create_node ◄──────────────┐ │
│ │ │ │
│ ┌─[工具调用]──► tools_node ────┘ │
│ │ │
│ └─[完成]──► extract_node → 结束 │
│ │
│ · 在 MCP 调用前获取 Keycloak 令牌(客户端凭证) │
│ · 通过 Kong 将 MCP 调用路由到 /mcp-server │
└────────────┬────────────────────────────────────────────────────────┘
│ 通过 Kong 的 MCP(http://kong:8000/mcp-server/mcp/)
│ Bearer <Keycloak M2M 令牌>
┌────────────▼──────────────────────────┐ ┌───────────────────────┐
│ MCP 服务器 (端口 8002) │ │ Keycloak (端口 8080) │
│ create_epic / create_ticket │ │ │
│ · 在调用 ticket-service 前获取 Keycloak 令牌 │ │ 领域: │
│ 调用 │ │ architect-multi-agent│
└────────────┬──────────────────────────┘ │ │
│ REST 通过 Kong │ M2M 客户端: │
│ (/ticket-service/api/*) │ · ticket-agent │
│ Bearer <Keycloak M2M 令牌> │ · mcp-server │
┌────────────▼──────────────────────────┐ │ · backend │
│ 票据服务 (端口 8003) │ │ │
│ NestJS — 史诗 + 票据 CRUD │ │ OIDC 客户端: │
│ · PostgreSQL │◄─┤ · 前端 │
│ · 信任 Kong JWT 验证 │ └───────────────────────┘
└───────────────────────────────────────┘
```
---
## 服务
| 服务 | 端口 | 目录 | 技术栈 |
|---------|------|-----------|-------|
| 前端 | 3000 | `frontend/` | Next.js 16 · React 19 · Tailwind CSS 4 · keycloak-js |
| 后端 | 8000 | `backend/` | NestJS 11 · TypeORM · PostgreSQL · Redis · RabbitMQ |
| 架构代理 | 8001 | `architect-agent/` | FastAPI · LangGraph · LangChain · Claude |
| MCP 服务器 | 8002 | `mcp-server/` | FastMCP · FastAPI |
| 票据服务 | 8003 | `ticket-service/` | NestJS 11 · TypeORM · PostgreSQL |
| 票据代理 | 8004 | `ticket-agent/` | FastAPI · LangGraph · StateGraph · Claude |
| Kong | 8888 | `kong/` | Kong 3.8 (无数据库) |
| RabbitMQ | 5672 / 15672 | — | RabbitMQ 3 |
| Redis | 6379 | — | Redis 7 |
| PostgreSQL 后端 | 5432 | — | PostgreSQL 17 |
| PostgreSQL 票据 | 5433 | — | PostgreSQL 17 |
| Keycloak | 8080 | `keycloak/` | Keycloak 26 |
| Prometheus | 9090 | `prometheus/` | Prometheus v2.53 |
| Grafana | 3001 | `grafana/` | Grafana 11.1 |
| Loki | 3100 | `loki/` | Grafana Loki 3.0 |
| Promtail | — | `promtail/` | Grafana Promtail 3.0 |
---
## Kong API 网关
Kong 以无数据库模式运行,启动时生成声明性配置。`kong/entrypoint.sh` 脚本在启动时获取一次 Keycloak 的 RSA 公钥,并将完整配置写入 `/tmp/kong.yml`,然后启动 Kong。
### 路由
所有四个应用程序服务都注册为 Kong 上游,`strip_path: true`:
| 外部路径 | 上游 |
|---|---|
| `http://localhost:8888/backend/*` | `backend:8000/*` |
| `http://kong:8000/ticket-service/*` | `ticket-service:8000/*` |
| `http://kong:8000/ticket-agent/*` | `ticket-agent:8000/*` |
| `http://kong:8000/mcp-server/*` | `mcp-server:8000/*` |
前端在端口 8888 访问 Kong。所有服务间(东西向)调用都使用内部 Docker 地址 `http://kong:8000`——没有服务硬编码另一个服务的 hostname。
### JWT 验证
Kong 使用嵌入的 Keycloak RS256 公钥本地验证每个请求——每个请求无需调用 Keycloak。两个消费者涵盖了两种令牌类型:
| 消费者 | `iss` 声明 | 令牌来源 |
|---|---|---|
| `browser-user` | `http://localhost:8080/realms/architect-multi-agent` | `kc_token` cookie(浏览器登录) |
| `service-account` | `http://keycloak:8080/realms/architect-multi-agent` | `Authorization: Bearer`(M2M) |
### 速率限制
全局速率限制插件将所有路由限制在 **每分钟 100 请求/每 IP** (`policy: local`)。每个响应都包含 `X-RateLimit-Limit-Minute` 和 `X-RateLimit-Remaining-Minute` 头。
---
## 身份验证
所有身份验证都由 **Keycloak** 处理(端口 8080,领域 `architect-multi-agent`),通过 `keycloak/realm.json` 配置,该配置在首次启动时自动导入。

### 服务间:OAuth 2.0 客户端凭证 + `private_key_jwt`
每个 M2M 服务(ticket-agent、mcp-server、backend)使用 **客户端凭证** 授权与 `private_key_jwt` 客户端身份验证(RFC 7523)向 Keycloak 进行身份验证。每个服务都使用其自己的 RSA-2048 私钥签署一个短期的 JWT 断言。Keycloak 获取服务的 JWKS 端点以验证断言,然后颁发一个 30 分钟的 RS256 访问令牌。
每个服务:
- 在 `.env` 中持有其 RSA-2048 私钥作为 `PRIVATE_KEY_PEM`
- 通过 `JwksService` 将相应的公钥作为 JWK 提供(`GET /api/.well-known/jwks`)
- 使用 RS256 签署客户端断言 JWT(`iss=clientId`、`sub=clientId`、`aud=tokenUrl`,唯一的 `jti`,30 分钟 `exp`)
- 将断言发布到 Keycloak 的令牌端点作为 `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer`
- 缓存生成的访问令牌(30 分钟 TTL);在过期前 30 秒刷新
Keycloak 客户端配置为 `"clientAuthenticatorType": "client-jwt"` 和 `"use.jwks.url": "true"`,指向每个服务的 `/api/.well-known/jwks` 端点。
**令牌验证由 Kong 处理**,而不是由接收服务处理。Kong 的 JWT 插件使用启动时获取的 Keycloak 公钥本地验证 RS256 签名。服务信任 Kong 转发请求携带有效令牌。
#### 身份验证映射
| 调用者 | Kong 路由 | 接收者 | 令牌来源 |
|--------|-----------|-----------|-------------|
| ticket-agent | `/mcp-server` | mcp-server | Keycloak — `ticket-agent` 客户端凭证 |
| mcp-server | `/ticket-service` | ticket-service | Keycloak — `mcp-server` 客户端凭证 |
| backend | `/ticket-service` | ticket-service | Keycloak — `backend` 客户端凭证 |
### 前端用户身份验证:OIDC 授权码流与 PKCE
前端使用 `keycloak-js`,`onLoad: 'login-required'` 和 `pkceMethod: 'S256'`。首次加载时,未身份验证的用户会自动重定向到 Keycloak 登录页面。成功登录后,访问令牌存储在 `kc_token` cookie 中。Kong 在 `/backend` 的每个请求中验证此 cookie。后端的 `KeycloakAuthMiddleware` 然后简单地解码已经验证的令牌(无需 JWKS 获取)以填充 `req.user`,包含用户名和电子邮件。
身份验证的用户名存储在创建新聊天时存储在 `conversations` 表中,并用于作用域聊天历史记录端点(`GET /api/chat/history`),以便每个用户仅查看自己的对话。
---
## 可观察性

Prometheus(端口 9090)每 15 秒抓取所有五个应用程序服务。Grafana(端口 3001,登录 `admin`/`admin`)预配置了一个 Prometheus 数据源和一个概览仪表盘。
### 每个服务的指标
| 服务 | 指标 | 描述 |
|---------|--------|-------------|
| backend | `backend_chat_requests_total{endpoint}` | `/api/chat/new` 和 `/api/chat/:id/cont` 请求 |
| backend | `backend_events_published_total` | 发布到 RabbitMQ 的事件 |
| architect-agent | `architect_agent_events_consumed_total` | RabbitMQ 消费的消息 |
| architect-agent | `architect_agent_llm_requests_total{node}` | 每个图节点的 LLM 调用 |
| ticket-agent | `ticket_agent_events_consumed_total` | RabbitMQ 消费的消息 |
| ticket-agent | `ticket_agent_llm_requests_total{node}` | 每个图节点的 LLM 调用 |
| mcp-server | `mcp_server_tool_requests_total{tool}` | MCP 工具调用(`create_epic`、`create_ticket`) |
| ticket-service | `ticket_service_requests_total{endpoint}` | 史诗和票据端点的请求 |
### 日志(Loki + Promtail)

**Promtail** (`promtail/`) 直接从 Docker 引擎 API (`docker_sd_configs` 针对 `/var/run/docker.sock`) 尾部容器日志,并将它们发送到 **Loki** (`loki/`,端口 3100),后者预配置为 Grafana 数据源以及 Prometheus。日志通过 Grafana 的 **Explore** 视图使用 LogQL 查询和实时尾部 - 没有单独的日志 UI。
只有带有 `logs.collect=true` 标签的容器被收集 - `architect-agent`、`backend`、`mcp-server`、`ticket-agent`、`ticket-service`(参见 `docker-compose.yml`)。这是硬性要求,而不仅仅是重新标记便利:使用 `relabel_configs` 和 `action: keep` 只会剥夺非匹配容器的标签 **之后** 它们已经被尾部,而 Loki 拒绝任何推送,其中一个流有零个标签,这会破坏整个批次(包括您想要的服务)。在发现时过滤可以完全避免空标签的情况。
要从附加服务收集日志,请在 `docker-compose.yml` 中为其添加 `labels: ["logs.collect=true"]` - 无需更改 Promtail 配置。 Loki 和 Promtail 都运行 `log_level: warn` 以保持其自己的容器输出静默。
---
## 前端(端口 3000)
- **Keycloak 登录** — OIDC 授权码流与 PKCE (`keycloak-js`);未经身份验证的用户自动重定向到 Keycloak
- 侧边栏显示用户名和电子邮件;注销按钮调用 `keycloak.logout()`
- 自由文本需求输入实时聊天日志通过 WebSocket 流出
- 聊天日志显示每个代理节点的进度:`Analyzing... → Intention: Plan`、`Designing... / Reviewing... → Result: Approved` 等。
- 批准的计划呈现为 `PlanCard` - 解决方案架构 + 组件列表 + 开发票据
- **"Looks good" 按钮发送接受信号;架构代理发布 `AcceptEvent` 到 RabbitMQ;ticket-agent 拾取它并调用 `create_epic` + `create_ticket` via MCP
- 自由文本后续工作通过新的代理循环完善计划
- `FinalReplyCard` 从 ticket-service 提取完整的史诗和票据数据并渲染它们并带有可点击的链接
- **`/epic/:id`** - 史诗详情页与解决方案架构和完整的票据列表
- **`/ticket/:id`** - 票据详情页与需求和验收标准
- 左侧边栏列出已保存的聊天记录作用域到登录用户
---
## 后端(端口 8000)
### 聊天 API
| 方法 | 路径 | 描述 |
|--------|------|-------------|
| `POST` | `/api/chat/new` | 在 PostgreSQL + Redis 中创建对话,发布 `ChatEvent` 到 RabbitMQ |
| `POST` | `/api/chat/:id/cont` | 追加用户消息,发布 `ChatEvent` 到 RabbitMQ |
| `GET` | `/api/chat/history` | 返回登录用户(id,title, `GET /api/chat/history` | 返回对话(id,标题,createdAt) |
| `GET` | `/api/chat/:id` | Redis 中的实时状态,或从 PostgreSQL 中持久化 |
| `POST` | `/api/chat/:id/stop` | 持久化消息到 PostgreSQL,删除 Redis 键 |
| `WS` | `/ws` | 轮询 Redis,推送 `chat-update` 事件,直到 `agentStatus === hasReplied` |
### 票务代理
通过Kong将浏览器代理到内部的票务服务。在转发之前,`KeycloakTokenService`通过`backend`客户端凭证获取Keycloak访问令牌,并将其附加为`Authorization: Bearer`。Kong在请求到达票务服务之前验证此M2M令牌。
| 方法 | 路径 | 代理到 |
|--------|------|------------|
| `GET` | `/api/epic/:id` | `kong:8000/ticket-service/api/epic/:id` |
| `GET` | `/api/epic/:epicId/tickets` | `kong:8000/ticket-service/api/epic/:epicId/tickets` |
| `GET` | `/api/ticket/:id` | `kong:8000/ticket-service/api/ticket/:id` |
---
## 架构代理(端口8001)

从`architecture-agent.chat` RabbitMQ队列中消费`ChatEvent`消息,并运行一个**LangGraph**状态图。每个节点都是一个Python类,带有注入的依赖项——一个共享的`ChatAnthropic` LLM实例和一个`RabbitMQPublisher`——在应用程序容器中连接在一起。
### 节点职责
| 节点 | 类 | 角色 |
|------|-------|------|
| `intent_node` | `IntentNode` | 将用户消息分类为`plan`、`refine`或`accept`;在接受时,发布`AcceptEvent`到RabbitMQ |
| `solution_node` | `SolutionNode` | 生成`SolutionInterface`(架构 + 组件) |
| `solution_review_node` | `SolutionReviewNode` | 批准/拒绝解决方案;将评论反馈给`solution_node` |
| `plan_node` | `PlanNode` | 将解决方案分解为`TicketInterface[]` |
| `plan_review_node` | `PlanReviewNode` | 批准/拒绝票务;将评论反馈给`plan_node` |
| `reply_node` | `ReplyNode` | 组装`ReplyInterface`(epic + 票务)并写入Redis |
### 代理内部
每个节点的关注点分为三个专用目录:
```
app/agent/
├── nodes/ — 节点类 (__call__ + 私有帮助函数)
├── schemas/ — Pydantic输出模型(每个节点一个文件)
│ ├── intent_schema.py 意图输出
│ ├── solution_schema.py 解决方案输出、组件输出、功能输出
│ ├── solution_review_schema.py 解决方案审查输出
│ ├── plan_schema.py 计划输出、票务输出、需求输出、验收标准输出
│ └── plan_review_schema.py 计划审查输出
├── personas/ — LLM角色/行为系统提示(每个节点一个文件)
│ ├── intent_persona.py
│ ├── solution_persona.py
│ ├── solution_review_persona.py
│ ├── plan_persona.py
│ └── plan_review_persona.py
├── templates/ — 参数化用户字符串(每个节点一个文件)
│ ├── intent_templates.py 意图用户
│ ├── solution_templates.py 解决方案用户新建 / _REFINE / _REVISE
│ ├── solution_review_templates.py 解决方案审查用户
│ ├── plan_templates.py 计划用户 / 计划用户修订
│ └── plan_review_templates.py 计划审查用户
└── contracts/ — 架构状态和共享接口
```
### 依赖注入
所有节点通过`__init__`接收它们的依赖项。应用程序容器(`container.py`)构造并连接所有内容:
```
Container
├── llm → ChatAnthropic (claude-sonnet-4-6, max_tokens=4096)
├── rabbitmq_publisher → RabbitMQPublisher(rabbitmq_url)
└── agent_graph → ArchitectGraph(llm, rabbitmq_publisher).build()
```
### 状态(`ArchitectState`)
```python
class ArchitectState(MessagesState):
conversation_id: str
requirement: str
raw_history: list[dict]
user_intent: str # "plan" | "accept" | "refine"
prior_solution: dict | None # 解决方案来自前一轮(细化上下文)
solution: dict | None
solution_review_comments: list[str]
solution_approved: bool
tickets: list[dict]
ticket_review_comments: list[str]
tickets_approved: bool
final_reply: dict | None
```
---
## 票务代理(端口8004)

订阅`architecture-agent.accept` RabbitMQ队列。当`AcceptEvent`到达时,它运行一个**LangGraph `StateGraph`**,有两个节点:`create_node`(工具调用循环)和`extract_node`(结构化输出提取)。
### 图
```
START → create_node ◄──────────┐
│ │
┌─[工具调用]──► 工具 ─────┘
│
└─[完成]──► extract_node → END
```
| 节点 | 类 | 角色 |
|------|-------|------|
| `create_node` | `CreateNode` | 按顺序调用`create_epic`和`create_ticket`工具 |
| `tools` | `ToolNode` | 通过MCP执行工具调用 |
| `extract_node` | `ExtractNode` | 从工具结果中提取`epicId`和`ticketIds`到`ExtractOut` |
### 状态(`TicketState`)
```python
class TicketState(MessagesState):
extract_out: ExtractOut | None = None
```
### 工具(动态 - 启动时从Redis构建)
启动时,`McpToolBuilder`从Redis读取`mcp_tools`并使用`pydantic.create_model`动态为每个条目创建`StructuredTool`,从存储的JSON模式派生输入模式。每个工具调用`McpClient`以`providerHost`为目标,该`providerHost`记录在规范中。
| 工具 | 从哪里发现 | 功能 |
|------|----------------|-------------|
| `create_epic` | `mcp_tools` Redis键 | 调用MCP `create_epic` → 票务服务 `POST /api/epic/` |
| `create_ticket` | `mcp_tools` Redis键 | 调用MCP `create_ticket` → 票务服务 `POST /api/ticket/` |
`McpClient`通过`KeycloakTokenService`(客户端凭证)获取Keycloak访问令牌,并通过`_BearerAuth`适配器传递它 - FastMCP的`Client`接受`httpx.Auth`实例,而不是原始标头。调用通过Kong路由(`http://kong:8000/mcp-server`),Kong在转发到MCP服务器之前验证M2M JWT。
在`extract_node`将`ExtractOut`写入状态后,`TicketService`直接读取它以构建`FinalReplyInterface`,将其写入Redis,并设置`agentStatus = hasReplied` - 后端WebSocket网关将其传递给浏览器。
---
## MCP服务器(端口8002)
通过MCP协议(`POST /mcp/`的可流式HTTP)公开两个工具。 通过Kong将AI工具调用转换为票务服务的REST调用。
传入的MCP请求在到达服务器之前由Kong验证 - 没有每项服务的JWT中间件。 发往票务服务的出站REST调用包括由`KeycloakTokenService`使用`mcp-server`客户端凭证获取的Keycloak访问令牌。
启动时,将完整的工具规范序列化到Redis下的`mcp_tools`键,格式如下:
```json
[
{
"providerName": "Ticket MCP Server",
"providerHost": "http://mcp-server:8000",
"tools": [
{ "name": "create_epic", "description": "...", "inputSchema": { ... } },
{ "name": "create_ticket", "description": "...", "inputSchema": { ... } }
]
}
]
```
这允许其他服务(票务代理)在启动时动态发现和构建工具,而无需硬编码工具定义。
| 工具 | 功能 |
|------|-------------|
| `create_epic` | 票务服务上的`POST /api/epic/` |
| `create_ticket` | 票务服务上的`POST /api/ticket/` |
---
## 票务服务(端口8003)
最小的NestJS CRUD服务,背后有自己的PostgreSQL实例。没有RabbitMQ,没有Redis,没有WebSocket,没有Keycloak依赖。JWT验证由Kong上游处理 - 所有到达此服务的请求都已验证。
| 方法 | 路径 | 描述 |
|--------|------|-------------|
| `POST` | `/api/epic/` | 创建epic |
| `GET` | `/api/epic/:id` | 按ID获取epic |
| `POST` | `/api/ticket/` | 创建票务 |
| `GET` | `/api/epic/:epicId/tickets` | 获取某个epic的所有票务 |
| `GET` | `/api/ticket/:id` | 按ID获取票务 |
| `GET` | `/api/health` | 健康检查 |
---
## 数据模型
```
SolutionInterface { architecture: string; components: ComponentInterface[] }
ComponentInterface { tech: string; features: FeatureInterface[] }
FeatureInterface { feature: string }
EpicInterface { id: uuid; name: string; requirements: RequirementInterface[]; solution: SolutionInterface }
TicketInterface { id: uuid; epicId: uuid; name: string; requirements: RequirementInterface[]; acceptance_criteria: AcceptanceCriterionInterface[] }
ReplyInterface { epic: EpicInterface; tickets: TicketInterface[] }
FinalReplyInterface { epicId: string; ticketIds: string[] }
MessageInterface {
actor: "User" | "Agent"
timestamp: datetime
content: string | ReplyInterface | FinalReplyInterface
agentStatus: "isThinking" | "hasReplied" | null
}
```
---
## 工作流程
```
用户输入"实施SFTP解决方案"
→ POST /api/chat/new (通过Kong /backend)
→ backend在PostgreSQL + Redis中创建对话
→ 发布ChatEvent到architecture-agent.chat
→ 前端打开WebSocket
架构代理处理ChatEvent:
intent_node → "plan"
solution_node → SolutionInterface
solution_review_node → 批准? 否 → solution_node (循环)
是 →
plan_node → TicketInterface[]
plan_review_node → 批准? 否 → plan_node (循环)
是 →
reply_node → ReplyInterface写入Redis → agentStatus=hasReplied
前端渲染PlanCard(架构 + 票务)
用户点击"看起来不错"
→ POST /api/chat/:id/cont (通过Kong /backend)
→ intent_node → "accept"
→ 发布AcceptEvent { conversationId, content }到architecture-agent.accept
→ 图结束(Redis保持isThinking)
票务代理处理AcceptEvent(StateGraph):
create_node调用工具按顺序:
→ create_epic → Kong /mcp-server → MCP create_epic → Kong /ticket-service → POST /api/epic/
→ create_ticket → Kong /mcp-server → MCP create_ticket → Kong /ticket-service → POST /api/ticket/ (× N)
extract_node读取工具结果 → ExtractOut { epicId, ticketIds }
→ FinalReplyInterface写入Redis → agentStatus=hasReplied
前端渲染FinalReplyCard:
· 通过Kong /backend → /api/epic/:id和/api/epic/:epicId/tickets获取完整的epic和票务
· epic名称链接到/epic/:id
· 每个票务名称链接到/ticket/:id
```
---
## 快速入门
```bash
# 1. 设置Anthropic API密钥
cp architect-agent/.env.example architect-agent/.env
# 编辑architect-agent/.env — 设置ANTHROPIC_API_KEY=sk-ant-...
# 2. 为三个M2M服务生成RSA-2048密钥对
for svc in ticket-agent mcp-server backend; do
key=$(openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 2>/dev/null)
echo "PRIVATE_KEY_PEM=\"$key\"" > $svc/.env
done
# 3. 启动所有服务
docker compose up --build
```
打开[http://localhost:3000](http://localhost:3000)。您将自动重定向到Keycloak登录页面。 使用`dev` / `dev`登录(`keycloak/realm.json`中预配置的测试用户)。
- Keycloak管理界面: [http://localhost:8080](http://localhost:8080) — `admin` / `admin`
- Kong代理: [http://localhost:8888](http://localhost:8888)
- Prometheus: [http://localhost:9090](http://localhost:9090)
- Grafana: [http://localhost:3001](http://localhost:3001) — `admin` / `admin` (探索 → Loki数据源获取日志)
- RabbitMQ管理: [http://localhost:15672](http://localhost:15672) — `guest` / `guest`
### 所需环境
| 键 | 文件 | 描述 |
|-----|------|-------------|
| `ANTHROPIC_API_KEY` | `architect-agent/.env` | [console.anthropic.com](https://console.anthropic.com) — 由架构代理和票务代理共享 |
| `PRIVATE_KEY_PEM` | `ticket-agent/.env` | 用于Keycloak `private_key_jwt`客户端身份验证的RSA-2048私钥(PEM) |
| `PRIVATE_KEY_PEM` | `mcp-server/.env` | 用于Keycloak `private_key_jwt`客户端身份验证的RSA-2048私钥(PEM) |
| `PRIVATE_KEY_PEM` | `backend/.env` | 用于Keycloak `private_key_jwt`客户端身份验证的RSA-2048私钥(PEM) |
所有其他凭证(数据库URL,RabbitMQ URL)都已在`docker-compose.yml`中预配置。Keycloak从`keycloak/realm.json`自动配置 - 只需生成上述RSA密钥即可,无需手动设置。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器