mh-gateway — 编排网关
核心网关服务,依赖 minimal-harness SDK。负责场景加载、用户权限校验、事件流归集,协调前端与各 worker 服务的通信。
-
版本:0.1.1
-
端口:
8005 -
Swagger:
http://localhost:8005/docs
开发者指南:docs/dev-guide.md(中文) · docs/dev-guide.agent.md(英文,面向 Coding Agent)
企业适配指导:docs/customer-adaptation-guide.md(中文) · docs/customer-adaptation-guide.agent.md(英文,面向 Coding Agent)
构建分发:docs/build-guide.md
在 mh 生态中的位置
| 包 | 角色 | 仓库 |
|---|---|---|
| minimal-harness | 核心 SDK(类型、协议、Agent 运行时、LLM 抽象、Memory/Session)。本服务依赖它。 | J0ey1iu/minimal-harness |
| mh-service-kit | FastAPI 服务工具包。本服务使用 ServiceApp 来托管 in-cluster Agent(如 dev-mode 下的 triage),并通过它提供的 SSE 客户端调用远程 Agent。 |
J0ey1iu/mh-service-kit |
| mh-tui | 本地 Textual TUI。本服务是它的云端多租户对等形态;二者共享 minimal-harness 的 Agent / Tool / Memory 抽象。 |
J0ey1iu/mh-tui |
| agent-tool-service | 内置于 umbrella 仓的示例 Agent & Tool 服务,可被本服务通过 M2M 端点调用。 | J0ey1iu/mh-incubator |
| mh-incubator | umbrella 工作区,串联本服务、agent-tool-service、web-frontend、minimal-harness 一起做端到端演示。 |
J0ey1iu/mh-incubator |
适配层架构
orchestration 通过 LifespanHook 接口与外部系统解耦。所有适配器通过 create_app() 参数注入:
| 接口 | 默认实现 | 企业部署替换 |
|---|---|---|
UserAuthProvider |
_DefaultAuthProvider — 提取 X-User-Id header/cookie |
实现 verify(request) → UserIdentity |
PermissionChecker |
_DefaultAuthProvider — 内置权限表 |
实现 check/get_permissions |
MetadataManager |
InMemoryManagementProvider — 内存数据(受 dev_mode 控制) |
实现读 (get_agent/list_agents/...) + CRUD (create_agent/update_agent/...) |
OutboundAuthProvider |
_DefaultOutboundAuthProvider — 透传请求 header |
实现 get_headers(request, url, type) → dict |
M2MAuthProvider |
_DefaultM2MAuthProvider — 允许所有请求 |
实现 authenticate(request) → str|None(Chat/Sessions 端点也支持 M2M 鉴权回退) |
ToolScriptStore |
orch-app: LocalFileScriptStore — 保存到 ./data/scripts/;mh-local: LocalScriptStore — 保存到 ~/.config/mh-local/scripts/ |
实现 save/read/delete/exists/close 定义 .py 工具脚本落盘位置;不启用文件型工具可传 None |
ConfigProvider |
无(仅环境变量) | 实现 get(key) → str 对接 Apollo/Nacos/Vault 等 |
LLMProvider |
通过 LLMProviderRegistry + 环境变量 ORCH_PROVIDER_* 配置 |
注入自定义 llm_provider_factory 或 llm_provider_registry LifespanHook |
UserAuthProvider、PermissionChecker、MetadataManager Protocol 定义在 mh_gateway 内。OutboundAuthProvider、M2MAuthProvider、ConfigProvider Protocol 也定义在 mh_gateway 内。
create_app() 工厂函数(客户部署入口)
create_app() 是 mh-gateway 的唯一入口,所有适配器通过 LifespanHook 参数注入:
import asyncio
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from mh_gateway import (
ConfigManager, ConfigSchema, create_app,
)
from my_adapters import (
CorpUserAuthProvider, CorpPermissionChecker, CorpRegistry,
)
# 1. 解析配置(env → 可选配置中心 → 报错)
config_mgr = ConfigManager()
settings = asyncio.run(config_mgr.resolve(ConfigSchema, prefix="ORCH"))
# 2. 配置 root logger(可选,不配置则使用 SDK 内置默认日志)
root = logging.getLogger()
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(name)s: %(message)s"
))
root.addHandler(handler)
root.setLevel(logging.DEBUG)
# 3. 定义 Adapter LifespanHook(应用启动时注入)
@asynccontextmanager
async def token_verifier(app: FastAPI):
app.state.adapters.token_verifier = CorpUserAuthProvider()
yield
@asynccontextmanager
async def permission_checker(app: FastAPI):
app.state.adapters.permission_checker = CorpPermissionChecker()
yield
@asynccontextmanager
async def management_provider(app: FastAPI):
app.state.adapters.management_provider = CorpRegistry()
yield
# 4. 注入你的企业适配器
app = create_app(
settings=settings,
token_verifier=token_verifier,
permission_checker=permission_checker,
management_provider=management_provider,
)
省略的适配器参数会使用内置默认实现,适合开发和演示。
部署后以 uvicorn my_app:app 启动。
AppState — 运行时可访问适配器
所有注入的适配器实例通过 request.app.state.adapters 访问:
from mh_gateway import AppState
adapters: AppState = request.app.state.adapters
identity = await adapters.token_verifier.verify(request)
perms = await adapters.permission_checker.get_permissions(user_id)
agents = await adapters.management_provider.list_agents()
API
用户面 API
| 端点 | 方法 | 说明 |
|---|---|---|
/api/v1/auth/me |
GET | 当前用户信息(含权限列表) |
/api/v1/scenarios |
GET | 场景列表(按权限过滤) |
/api/v1/scenarios/{id} |
GET | 场景详情(含 Agent/Tool) |
/api/v1/chat/{memory_id} |
POST | SSE 流式聊天(支持 session_id 续传)支持用户 Token 或 M2M 鉴权 |
/api/v1/sessions |
GET | 当前用户的 Session 列表(支持 ?scenario_id= 过滤)支持用户 Token 或 M2M 鉴权 |
/api/v1/sessions |
POST | 创建 Session 支持用户 Token 或 M2M 鉴权 |
/api/v1/sessions/{id} |
GET | Session 详情(含消息数) 支持用户 Token 或 M2M 鉴权 |
/api/v1/sessions/{id}/messages |
GET | Session 消息历史 支持用户 Token 或 M2M 鉴权 |
/api/v1/sessions/{id} |
DELETE | 删除 Session 支持用户 Token 或 M2M 鉴权 |
/api/v1/agents |
GET | Agent 列表(按权限过滤,支持 ?scenario= 过滤) |
/api/v1/tools |
GET | Tool 列表(按权限过滤) |
/api/v1/auth/logout |
POST | 用户登出(清除认证态) |
/api/v1/feedback |
GET/POST | 反馈列表(按 session 过滤)/ 提交用户反馈(自动关联 session/target 消息) |
/api/v1/feedback/{id} |
PUT/DELETE | 更新/删除反馈内容 |
/api/v1/health |
GET | 健康检查(始终返回 {"status":"ok"}) |
/ready |
GET | 就绪检查(检查数据库连接) |
/api/v1/metrics |
GET | 运行时指标快照(仅 metrics_enabled=true 时可用) |
管理面 API(需 MetadataManager + 对应资源管理权限:manage:scene:* / manage:agent:* / manage:tool:*)
| 端点 | 方法 | 说明 |
|---|---|---|
/api/v1/management/scenarios |
GET/POST | 场景列表/创建 |
/api/v1/management/scenarios/{id} |
GET/PUT/DELETE | 场景详情/更新/删除 |
/api/v1/management/scenarios/{id}/agents |
POST/DELETE | 场景-Agent 关系管理 |
/api/v1/management/scenarios/{id}/agents/{name}/tools |
POST/DELETE | Agent-Tool 关系管理 |
/api/v1/management/agents |
GET/POST | Agent 列表/创建 |
/api/v1/management/agents/{name} |
GET/PUT/DELETE | Agent 详情/更新/删除 |
/api/v1/management/tools |
GET/POST | Tool 列表/创建 |
/api/v1/management/tools/{name} |
GET/PUT/DELETE | Tool 详情/更新/删除 支持 ?force=true 强制删除(自动解除被 scenario 引用) |
/api/v1/management/tools/upload |
POST | 上传单个 .py 工具脚本(multipart file),自动解析 TOOL_NAME / TOOL_PARAMETERS / locale 元数据并校验 shebang 解释器存在性 |
/api/v1/management/tools/upload-batch |
POST | 批量上传多个 .py 工具脚本,单文件错误不影响其他文件 |
/api/v1/management/providers |
GET | LLM Provider 列表 |
/api/v1/management/controllers |
GET | Controller 目录(default / goal / timer,供前端渲染) |
/api/v1/management/metrics |
GET | 数据概览聚合指标(需 manage:metrics:* 权限,支持 ?date_from=&date_to= 日期区间,精确到日) |
M2M 端点
| 端点 | 方法 | 说明 |
|---|---|---|
/api/v1/agents/{name}/run |
POST | 运行 Agent(M2M 鉴权) |
AI 生成端点
| 端点 | 方法 | 说明 |
|---|
开发模式端点(仅 dev_mode=true)
| 端点 | 方法 | 说明 |
|---|
文件型 Tool(ToolScriptStore + 脚本上传)
除了在 UI 中以表单方式逐字段创建 tool,平台还支持把 Python 文件上传后自动解析为 tool:
- 用户在管理 UI 拖拽
.py文件 →POST /api/v1/management/tools/upload - 服务端用 AST 解析脚本顶部变量,校验必填字段(
TOOL_NAME、TOOL_DESCRIPTION、TOOL_DISPLAY_NAME_LOCALE、TOOL_DESCRIPTION_LOCALE、TOOL_PARAMETERS、async def execute())和 shebang 解释器是否可执行 - 通过后把脚本文件保存到
ToolScriptStore(每个 app 实现各自的存储位置),并写入ToolCreate.script_path创建ExternalScriptToolBinding - 运行时由
ExternalToolWrapper在子进程中执行execute(),每次yield序列化为 JSON 推到前端作为ToolProgress事件,支持取消和异常传播
每个 .py 文件对应一个 tool,禁止在文件里定义 register() 函数。最简模板:
TOOL_NAME = "greeter"
TOOL_DESCRIPTION = "Greet a user."
TOOL_DISPLAY_NAME_LOCALE = {"zh": "问候", "en": "Greeter"}
TOOL_DESCRIPTION_LOCALE = {"zh": "问候用户", "en": "Greet a user."}
TOOL_PARAMETERS = {
"type": "object",
"properties": {"name": {"type": "string"}},
"required": ["name"],
}
async def execute(name: str):
yield {"result": f"Hello, {name}!"}
AuditMiddleware
每个 Agent 执行周期自动记录审计日志(包括 agent_start/end、llm_start/end、tool_start/end/error、token 用量)。
日志级别为 INFO,可通过 orchestration.audit logger 配置。
AccessLogMiddleware
每个 HTTP 请求自动输出一条结构化 JSON 访问日志,包含 method、path、status、duration_ms、trace_id、user_id 等字段。
日志级别为 INFO,可通过 orchestration.access logger 配置。
监控指标
当 metrics_enabled=true 时,服务会自动注册 MetricsCollector,在内存中采集如下指标并通过后台定时任务推送到日志:
| 指标 | 类型 | 标签 |
|---|---|---|
http_requests_total |
Counter | method, path, status |
http_request_duration_ms |
Histogram | method, path |
llm_requests_total |
Counter | provider, model, status |
llm_tokens_total |
Counter | provider, model, type (prompt/completion) |
llm_request_duration_ms |
Histogram | provider, model |
agent_runs_total |
Counter | agent_id, status |
tool_calls_total |
Counter | tool_name, status |
sessions_active |
Gauge | — |
指标通过 AuditMiddleware 的生命周期钩子自动采集。可通过 /api/v1/metrics 获取实时快照。
指标持久化(MetricsRepository)
管理面数据概览(/api/v1/management/metrics)基于 可选 的持久化指标仓库,采用与
MetricsCollector 相同的单例注入模式,不修改 GatewayAdapters:
from mh_gateway.metrics_repo import MetricsRepository, LLMCallRecord, set_metrics_repo
class MyMetricsRepository(MetricsRepository):
async def record_llm_call(self, record: LLMCallRecord) -> None: ...
async def record_tool_call(self, record: ToolCallRecord) -> None: ...
async def query_summary(self, date_from=None, date_to=None) -> MetricsSummary: ...
async def close(self) -> None: ...
# 部署方在 lifespan hook 中注册(create_app 已支持 lifespan_hooks 参数)
set_metrics_repo(MyMetricsRepository())
- 记录写入:由独立的
MetricsPersistenceMiddleware(单一职责,区别于审计)在on_llm_end/on_tool_end钩子中写入,每条 LLM 调用记录一次(含 user/session/agent/scenario/provider/model/token/耗时)。 - 查询聚合:
query_summary按日期区间(YYYY-MM-DD)聚合调用次数、Token、Top N、模型性能。 - 存储介质:协议对后端完全中立 —— 单实例可用 SQLite/JSONL 文件,水平扩展时部署方可换共享数据库实现。
- 权限:端点需要
manage:metrics:*权限(require_permission)。 - 未注册仓库时端点返回
503;中间件在未注册时完全静默。
PermissionMiddleware
每个 Agent 运行时自动校验工具调用权限。可通过 check(user_id, perm) 返回 bool 实现自定义逻辑。
环境变量
所有环境变量以 ORCH_ 为前缀:
| 变量 | 默认值 | 说明 |
|---|---|---|
ORCH_DB_PATH |
./sessions.db |
SQLite 数据库文件路径 |
ORCH_DB_AUTO_SCHEMA |
false |
启动时自动建表(生产环境建议设为 false) |
ORCH_CORS_ORIGINS |
[] |
跨域源(逗号分隔,如 http://localhost:5173,http://localhost:3000) |
ORCH_DEV_MODE |
false |
开发模式开关,开启后暴露内置 agent、前端 SPA、开发调试工具及 SSO 登录页 |
ORCH_LOG_LEVEL |
INFO |
日志级别(ConfigSchema 字段,但日志通过 MH_LOG_LEVEL 环境变量或自行配置 root logger 控制) |
ORCH_ENABLE_EVAL |
true |
是否暴露评测接口 |
ORCH_EVAL_RESULTS_DIR |
./eval_results |
评测结果存储目录 |
ORCH_VERIFY_AGENT_TOOL_SSL |
false |
调用远程 agent/tool 时是否验证 SSL 证书 |
ORCH_METRICS_ENABLED |
false |
启用指标采集(计数器/直方图/仪表盘)及 /api/v1/metrics 端点 |
ORCH_METRICS_PUSH_INTERVAL |
60 |
指标推送间隔(秒),仅 ORCH_METRICS_ENABLED=true 时生效 |
LLM Provider 配置
LLM 配置通过 ORCH_PROVIDER_{NAME}__{KEY} 环境变量设置,不再使用旧的 ORCH_LLM_* 变量:
# 配置 OpenAI
export ORCH_PROVIDER_OPENAI__API_KEY=sk-xxx
export ORCH_PROVIDER_OPENAI__BASE_URL=https://api.openai.com/v1
# 配置 Anthropic
export ORCH_PROVIDER_ANTHROPIC__API_KEY=sk-ant-xxx
内置 provider:openai、anthropic、openai_viz(openai 的克隆)。
Agent 元数据的 provider 和 model 字段控制 per-agent 的 provider 选择。默认使用 openai。
外部配置对接
当客户有自己的配置中心(Apollo/Nacos/Consul)和密钥系统(HashiCorp Vault/AWS Secrets Manager)时,可通过 ConfigProvider 协议对接。
解析优先级
配置值按以下优先级解析(高 → 低):
- 环境变量(
ORCH_*)— 最高优先级,运维可临时覆盖 - 外接配置(
ConfigProvider实例,敏感与非敏感通过不同实例区分)— 来自配置中心 - 代码默认值 — 若以上均未设置,使用
ConfigSchema中的默认值
远程 key 重映射
ConfigManager.resolve() 支持 key_mapping 参数,将内部字段名重映射为客户配置中心的 key:
cfg = await config_mgr.resolve(
MyConfig,
prefix="my.registry",
key_mapping={
"db_path": "woa.orchestration.db.path",
},
sensitive_fields={"api_key"},
)
实现自定义 UserAuthProvider(对接企业 SSO)
verify() 收到的是完整的 FastAPI Request,可读 Cookie/Header/调外部 API:
from typing import Any
from mh_gateway.auth import UserAuthProvider, UserIdentity
class CorpSSOVerifier(UserAuthProvider):
async def verify(self, request: Any) -> UserIdentity | None:
# 1. 从 Cookie 中提取会话标识
session_id = request.cookies.get("sessionid")
if not session_id:
return None
# 2. 调用企业认证 API(request 还可读其他 header/query)
user_info = await self._call_auth_api(session_id)
if not user_info:
return None
# 3. 返回标准身份(extra_data 保留完整信息)
return UserIdentity(
user_id=user_info["employee_id"],
username=user_info["name"],
roles=user_info.get("roles", []),
extra_data=user_info,
)
HTTP Bearer token 由内置
_DefaultAuthProvider从request.headers["authorization"]提取,客户使用 Cookie 时直接在verify()中读取request.cookies即可。
实现其他 Provider
from mh_gateway import ConfigProvider
class ApolloConfigProvider(ConfigProvider):
async def get(self, key: str) -> str | None:
return await apollo_client.get_value(key)
class VaultSecretResolver(ConfigProvider):
async def get(self, key: str) -> str | None:
return await vault_client.read_secret(key)
内置 Agent 样例 & 开发模式
设置 ORCH_DEV_MODE=true 后,服务会暴露 3 个内置样例 agent 以及开发调试用工具端点:
| Agent | 英文名 | 中文名 | 说明 |
|---|---|---|---|
triage |
General Assistant | 通用助手 | 理解用户需求并路由到专业 agent(code-reviewer / writer)。本地执行。 |
code-reviewer |
Code Reviewer | 代码审查 | 分析代码变更中的缺陷、风格、安全和性能问题。通过 M2M 端点执行。 |
writer |
Writing Assistant | 写作助手 | 辅助撰写文章、邮件、报告等。通过 M2M 端点执行。 |
内置 Tool 包括 calculator、handoff、discover_agents、show_ui_meta、general_visualization、stop_agent。
triage agent 在进程内本地执行(无 endpoint_url),code-reviewer 和 writer 通过 M2M 端点执行。内置 agent 的 system_prompt 支持中英文,根据前端传来的 Accept-Language 自动适配。
生产环境请确保
ORCH_DEV_MODE为false(默认值),并通过management_providerLifespanHook 注入企业自己的注册中心实现。
内置前端 UI(一站式部署)
设置 ORCH_DEV_MODE=true 后,FastAPI 会在 / 直接 serve 编译后的 SPA(单页应用),前提是 static/ 目录存在。
# 构建前端(SPA + 组件 bundle → 复制到 static/)
bash scripts/build-frontend.sh
# 启动(前端在 http://localhost:8005)
ORCH_DEV_MODE=true uv run uvicorn mh_gateway.main:app --port 8005
注意:前端静态文件需预先构建并放入
static/目录。ORCH_DEV_MODE=true时服务会自动挂载前端并处理 SPA fallback 路由。
本地开发
# 带前端(先构建前端 SPA + 复制到 static/)
bash scripts/dev-standalone.sh
# 或仅后端(前端由 Vite 开发服务器提供热更新)
uv run uvicorn mh_gateway.main:app --port 8005
cd web-frontend && npm run dev
或使用项目根目录的 bash scripts/dev.sh 一键启动所有服务。
构建分发
cd packages/mh-gateway
uv build
# 产出 dist/mh_gateway-*.whl
客户 pip install 后,编写自己的启动文件注入适配器即可。
测试
uv run pytest packages/mh-gateway/tests -v
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mh_gateway-0.1.1.tar.gz.
File metadata
- Download URL: mh_gateway-0.1.1.tar.gz
- Upload date:
- Size: 270.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0259689267bd8e924f85ada415198422a724a71937b5741c497b98ab4ff96240
|
|
| MD5 |
44c55d2d80bb3d01e49f8c9f1c00fc5d
|
|
| BLAKE2b-256 |
7efc3d76bdc92f9601c6d09684752d856b75c7f4f36ce891d2f6ffbf83e05d24
|
File details
Details for the file mh_gateway-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mh_gateway-0.1.1-py3-none-any.whl
- Upload date:
- Size: 294.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
762ebea6d891c3b10028639008356379d7b76ca98fcef12f7e949f9bac9d973f
|
|
| MD5 |
f8e02d549d5f99c2aa0a77bb09364a4c
|
|
| BLAKE2b-256 |
516172ce8c88e97b3d691332e51f0225979ed561e9e8919ca832c0623cca41ff
|