Skip to main content

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_factoryllm_provider_registry LifespanHook

UserAuthProviderPermissionCheckerMetadataManager Protocol 定义在 mh_gateway 内。OutboundAuthProviderM2MAuthProviderConfigProvider 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:

  1. 用户在管理 UI 拖拽 .py 文件 → POST /api/v1/management/tools/upload
  2. 服务端用 AST 解析脚本顶部变量,校验必填字段(TOOL_NAMETOOL_DESCRIPTIONTOOL_DISPLAY_NAME_LOCALETOOL_DESCRIPTION_LOCALETOOL_PARAMETERSasync def execute())和 shebang 解释器是否可执行
  3. 通过后把脚本文件保存到 ToolScriptStore(每个 app 实现各自的存储位置),并写入 ToolCreate.script_path 创建 ExternalScriptToolBinding
  4. 运行时由 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/endllm_start/endtool_start/end/error、token 用量)。 日志级别为 INFO,可通过 orchestration.audit logger 配置。

AccessLogMiddleware

每个 HTTP 请求自动输出一条结构化 JSON 访问日志,包含 methodpathstatusduration_mstrace_iduser_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:openaianthropicopenai_viz(openai 的克隆)。

Agent 元数据的 providermodel 字段控制 per-agent 的 provider 选择。默认使用 openai

外部配置对接

当客户有自己的配置中心(Apollo/Nacos/Consul)和密钥系统(HashiCorp Vault/AWS Secrets Manager)时,可通过 ConfigProvider 协议对接。

解析优先级

配置值按以下优先级解析(高 → 低):

  1. 环境变量ORCH_*)— 最高优先级,运维可临时覆盖
  2. 外接配置ConfigProvider 实例,敏感与非敏感通过不同实例区分)— 来自配置中心
  3. 代码默认值 — 若以上均未设置,使用 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 由内置 _DefaultAuthProviderrequest.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 包括 calculatorhandoffdiscover_agentsshow_ui_metageneral_visualizationstop_agent

triage agent 在进程内本地执行(无 endpoint_url),code-reviewerwriter 通过 M2M 端点执行。内置 agent 的 system_prompt 支持中英文,根据前端传来的 Accept-Language 自动适配。

生产环境请确保 ORCH_DEV_MODEfalse(默认值),并通过 management_provider LifespanHook 注入企业自己的注册中心实现。

内置前端 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

mh_gateway-0.1.1.tar.gz (270.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mh_gateway-0.1.1-py3-none-any.whl (294.2 kB view details)

Uploaded Python 3

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

Hashes for mh_gateway-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0259689267bd8e924f85ada415198422a724a71937b5741c497b98ab4ff96240
MD5 44c55d2d80bb3d01e49f8c9f1c00fc5d
BLAKE2b-256 7efc3d76bdc92f9601c6d09684752d856b75c7f4f36ce891d2f6ffbf83e05d24

See more details on using hashes here.

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

Hashes for mh_gateway-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 762ebea6d891c3b10028639008356379d7b76ca98fcef12f7e949f9bac9d973f
MD5 f8e02d549d5f99c2aa0a77bb09364a4c
BLAKE2b-256 516172ce8c88e97b3d691332e51f0225979ed561e9e8919ca832c0623cca41ff

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page