企业级 Agent Runtime SDK — 让 AI 工程师专注 Agent 能力开发,无需关心底层基础设施
Project description
wisruntime — 企业级 Agent Runtime SDK
版本: v0.1.0 (MVP) | 日期: 2026-07 | 团队: WIS Team
一、项目概述
1.1 定位
wisruntime 是一个企业级 Agent Runtime SDK(Python),以 pip install 方式提供给 AI 应用工程师使用。
它的核心使命:让 Agent 工程师专注 Agent 能力开发,无需关心底层基础设施。
1.2 一句话描述
为 Agent 开发者提供轻量、可扩展、多框架适配的统一运行时 SDK——用框架原生 API 构建 Agent 后,数行代码即可获得完整的生产级服务端点,并自动接入 WIS Hub 平台能力(MCP / Skill / Sandbox)。
1.3 核心价值
没有 wisruntime 有了 wisruntime
══════════════ ══════════════
AI 工程师 → 写 FastAPI 路由 AI 工程师 → 写 invoke_agent 函数
→ 处理 SSE 流式协议 → create_server(invoke_agent).start(8000)
→ 对接 MCP 协议 → ✅ Dify SSE 服务就绪
→ 对接 Skill API → ✅ 平台能力自动接入
→ 管理 Sandbox → ✅ API-KEY 统一鉴权
→ 对接鉴权系统 → ✅ 开箱即用
→ 每个应用都重复一遍
1.4 对标参考
本架构深度借鉴了阿里云 AgentRun Python SDK 的分层设计思想,在其基础上针对 WIS Hub 平台的差异化特点(统一 API-KEY 鉴权、Dify SSE 协议、DeepAgents 框架、平台能力托管)进行了重新设计。
二、整体架构
2.1 分层架构图
┌──────────────────────────────────────────────────────────────────────┐
│ WIS Hub 平台 (AI 中台) │
│ │
│ MCP 服务 │ Skill 服务 │ Sandbox 服务 │ Checkpoint 服务 │
│ (REST) │ (REST) │ (REST) │ (REST) │
│ │
│ 统一 API-KEY 鉴权: 创建应用 → 勾选能力 → 生成 Key │
└────────────────────────────┬─────────────────────────────────────────┘
│ HTTPS + Bearer <API-KEY>
│
┌────────────────────────────┴─────────────────────────────────────────┐
│ wisruntime SDK │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Infrastructure 层 │ │
│ │ Config (API-KEY / 端点 / 超时) │ │
│ │ CredentialContext (contextvars: 请求级 API-KEY 注入) │ │
│ │ BaseModel / 异常定义 / 日志 │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Platform Client 层 (框架无关,只写一次) │ │
│ │ │ │
│ │ mcp/MCPClient skill/SkillClient │ │
│ │ sandbox/SandboxClient memory/CheckpointClient │ │
│ │ │ │
│ │ 每个 Client: 自动读 API-KEY, 统一错误处理, 异步 HTTP (httpx) │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Capability Bridge 层 (每个框架一份) │ │
│ │ │ │
│ │ adapters/deepagents/ │ │
│ │ ├── mcp.py MCPClient → DeepAgents BaseTool │ │
│ │ ├── skill.py SkillClient → DeepAgents BaseTool │ │
│ │ └── sandbox.py SandboxClient → DeepAgents BaseTool │ │
│ │ │ │
│ │ adapters/agentscope/ (未来) │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Adapter 层 (用户可选工具: Agent 对象 → invoke_agent 函数) │ │
│ │ │ │
│ │ 提供两种使用方式: │ │
│ │ ① wrap_agent(agent) → invoke_agent 函数 (便捷包装) │ │
│ │ ② 用户在 invoke_agent 内部手动做事件转换 │ │
│ │ │ │
│ │ adapters/deepagents/ (DeepAgents 事件 → CanonicalEvent) │ │
│ │ adapters/agentscope/ (未来) │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Server 层 (框架无关,只认函数) │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────────┐ │ │
│ │ │ DifyHandler │ │AGUIHandler │ │ AgentInvoker │ │ │
│ │ │ SSE+Blocking │ │ (规划中) │ │ 函数归一化引擎 │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ └─────────┬─────────┘ │ │
│ │ └─────────────────┴────────────────────┘ │ │
│ │ │ │ │
│ │ CanonicalEvent │ │
│ │ ProtocolRegistry │ │
│ └────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
2.2 分层职责
| 层 | 职责 | 关键组件 |
|---|---|---|
| Infrastructure | 全局配置、凭证注入、基础模型 | Config, CredentialContext, BaseModel |
| Platform Client | 封装 WIS Hub REST API 调用,统一鉴权 | MCPClient, SkillClient, SandboxClient, CheckpointClient |
| Capability Bridge | 平台客户端 → 框架原生 Tool 对象转换 | DeepAgentsMCPTool, DeepAgentsSkillTool |
| Adapter | (用户可选) Agent 对象 → invoke_agent 函数包装,及框架事件 → CanonicalEvent 转换 | wrap_agent(), DeepAgentsAdapter |
| Server | HTTP 服务承载、协议路由、请求校验、响应序列化。只接收 invoke_agent 函数 | DifyHandler, AgentInvoker, ProtocolRegistry |
2.3 关键设计决策
| 决策 | 说明 | 参考来源 |
|---|---|---|
| API-KEY 唯一鉴权 | 不引入 AK/SK/STS 签名体系,整个应用只用一个 API-KEY | WIS Hub 平台特征 |
| SDK 不管理资源生命周期 | 资源由 WIS Hub 平台管理,SDK 只做运行时调用(零 CRUD) | 与 AgentRun 的核心差异 |
| Platform Client 框架无关 | MCP/Skill/Sandbox 客户端只写一次,所有框架共享 | AgentRun Resource 层思想 |
| Capability Bridge 每个框架一份 | 将平台客户端转为框架原生 Tool 对象 | AgentRun Integration 层思想 |
| CanonicalEvent 11 种类型 | 综合 LangChain v2/v3、Dify/Wisknow、AgentRun 四套事件体系 | 见第三节 |
| Server 只接收 invoke_agent 函数 | Server 不知道框架的存在,用户函数 = 唯一入口。与 AgentRun 完全一致 | AgentRun AgentRunServer |
| AgentInvoker 单层归一化 | 用户函数 yield 的 str/AgentEvent → CanonicalEvent 流 | AgentRun AgentInvoker 模式 |
| 协议处理器双向负责 | Handler 负责请求解析 + 响应序列化 | AgentRun Protocol Handler 模式 |
| contextvars 注入 API-KEY | Server 模式下从请求 Bearer 头提取 → 注入请求上下文 | AgentRun CredentialContext 模式 |
三、CanonicalEvent 设计
CanonicalEvent 是 wisruntime 的核心抽象——框架事件和协议事件之间唯一的稳定契约。所有 Adapter 产出 CanonicalEvent,所有 ProtocolHandler 消费 CanonicalEvent。
3.1 设计来源
综合分析了四套事件体系,取各自最佳实践:
| 事件体系 | 来源 | 特点 |
|---|---|---|
| LangChain v2 | astream_events(version="v2") |
Runnable 层级事件,on_*_start/stream/end 模式,支持自定义事件 |
| LangChain v3 | astream_events(version="v3") |
Content-block 协议层级,message-start → block-delta → message-finish,推理/文本/工具调用独立块 |
| Dify / Wisknow | event/ 目录中的实体定义 |
SSE 协议事件,agent_message、agent_thought、message_end、subagent_start/end |
| AgentRun | server/model.py 中的 EventType |
TEXT、REASONING、TOOL_CALL、TOOL_CALL_CHUNK、TOOL_RESULT、ERROR、CUSTOM |
3.2 11 种 CanonicalEvent 类型
┌──────────────────────────────────────────────────────────────────────┐
│ CanonicalEvent 类型体系 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 内容流事件 │ │
│ │ │ │
│ │ TextDelta 文本增量 │ │
│ │ ← v2 on_chat_model_stream(chunk.content) │ │
│ │ ← v3 content-block-delta(text-delta) │ │
│ │ ← Dify agent_message / text_chunk │ │
│ │ ← AgentRun TEXT │ │
│ │ │ │
│ │ ReasoningDelta 推理增量 (CoT 思维链) │ │
│ │ ← v2 additional_kwargs.reasoning_content │ │
│ │ ← v3 content-block-delta(reasoning-delta) │ │
│ │ ← Dify reasoning_chunk │ │
│ │ ← AgentRun REASONING │ │
│ │ │ │
│ │ FileOutput 文件输出 (图片/音频/视频/文件) │ │
│ │ ← v3 image/audio/video/file content blocks │ │
│ │ ← Dify message_file │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 工具调用生命周期 (借鉴 LangChain v3 的 block 模型) │ │
│ │ │ │
│ │ ToolCallStart 工具调用开始 │ │
│ │ ← v2 on_tool_start (data.input) │ │
│ │ ← v3 content-block-start(type=tool_call) │ │
│ │ ← Dify agent_thought (tool + tool_input 前半) │ │
│ │ ← AgentRun TOOL_CALL / TOOL_CALL_CHUNK │ │
│ │ data: { id, name, args_delta } (args 分块流式到达) │ │
│ │ │ │
│ │ ToolCallEnd 工具调用结束 (含执行结果) │ │
│ │ ← v2 on_tool_end (data.output) │ │
│ │ ← v3 content-block-finish(type=tool_call) │ │
│ │ ← Dify agent_thought (observation 后半) │ │
│ │ ← AgentRun TOOL_RESULT │ │
│ │ data: { id, result, error? } │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 子Agent生命周期 (灵知/Wisknow 自定义场景) │ │
│ │ │ │
│ │ SubAgentStart 子Agent开始运行 │ │
│ │ ← 灵知 subagent_start │ │
│ │ data: { agent_name, run_id, task_description } │ │
│ │ │ │
│ │ SubAgentEnd 子Agent运行结束 │ │
│ │ ← 灵知 subagent_end │ │
│ │ data: { agent_name, run_id, status } │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 元事件 │ │
│ │ │ │
│ │ Usage Token 用量统计 │ │
│ │ ← v2 usage_metadata (on_chat_model_end) │ │
│ │ ← v3 message-finish.usage │ │
│ │ ← Dify metadata.usage │ │
│ │ data: { prompt_tokens, completion_tokens, total_tokens } │ │
│ │ │ │
│ │ Error 错误事件 │ │
│ │ ← 所有体系都有 │ │
│ │ data: { message, code?, recoverable? } │ │
│ │ │ │
│ │ Custom 自定义事件 (扩展通道) │ │
│ │ ← v2 on_custom_event │ │
│ │ ← 灵知 todo_update / recommendation_card / next_step │ │
│ │ data: { name, payload } │ │
│ │ │ │
│ │ Done 流结束标记 │ │
│ │ ← v3 message-finish │ │
│ │ ← Dify message_end │ │
│ │ ← AgentRun 流自然结束 (隐式) │ │
│ │ data: { metadata? } │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
3.3 数据流
┌─── invoke_agent 函数 (用户编写) ───┐
│ │
│ 用户可以在函数内部: │
│ · 直接 yield str / CanonicalEvent │
│ · 使用框架 Agent + Adapter 转换 │
│ · 调用 MCPClient / SkillClient │
│ │
└────────────┬───────────────────────┘
│
▼
┌─────────────────────────┐
│ AgentInvoker │ ← 归一化: str → TextDelta
│ │ 异常 → Error
│ AsyncGenerator[ │ 透传 CanonicalEvent
│ CanonicalEvent] │
└────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ ProtocolHandler │ ← 序列化: CanonicalEvent → SSE/JSON
│ │
│ DifyHandler → Dify SSE │
│ AGUIHandler → AG-UI │
└─────────────────────────┘
Adapter 层 (用户可选工具): 框架 Agent + Adapter → CanonicalEvent 流 → 在 invoke_agent 中 yield
四、分层详解
4.1 Infrastructure 层
┌────────────────────────────────────────────────────┐
│ Config │
│ ├── api_key: str 统一 API-KEY │
│ ├── hub_endpoint: str WIS Hub 地址 │
│ ├── timeout: int = 600 请求超时(秒) │
│ └── 获取优先级: │
│ 1. 显式传入 Config(api_key="...") │
│ 2. 环境变量 WIS_HUB_API_KEY │
│ 3. 请求级 contextvars overlay (Server 模式) │
│ │
│ CredentialContext (contextvars) │
│ ├── get_request_api_key() → Optional[str] │
│ ├── set_request_api_key(key) 上下文管理器 │
│ └── 用途: Server 模式从 Bearer 头注入 → 全局可用 │
│ │
│ ApiKeyMiddleware (纯 ASGI) │
│ ├── 每次请求从 Authorization: Bearer <KEY> 解析 │
│ ├── 注入 contextvars overlay │
│ └── 请求结束时自动复位 │
└────────────────────────────────────────────────────┘
与 AgentRun 的差异: AgentRun 使用 AK/SK + STS + RAM 签名三级体系,wisruntime 只使用 API-KEY,结构大幅简化。但 contextvars 注入模式完全复用。
4.2 Platform Client 层
核心原则: 框架无关,只写一次。只做运行时调用,不做资源 CRUD。
WIS Hub 平台负责资源的创建和管理,SDK 不需要 create() / delete() 操作。每个 Client 只需要:
# 统一模式 (以 MCP 为例)
class MCPClient:
def __init__(self, base_url=None, api_key=None, timeout=600):
self._base_url = base_url or f"{Config.current().hub_endpoint}/mcp"
self._api_key = api_key
self._timeout = timeout
@property
def api_key(self) -> str:
"""三级获取: 显式传入 → contextvars → 环境变量"""
return self._api_key or CredentialContext.get_request_api_key()
async def call(self, method: str, params: dict) -> dict:
"""调用 MCP 工具"""
...
async def list_tools(self) -> list[dict]:
"""列出可用工具"""
...
各 Client 职责:
| Client | 职责 | 端点示例 |
|---|---|---|
MCPClient |
调用 WIS Hub 托管的 MCP 服务 | POST /mcp/invoke |
SkillClient |
调用 WIS Hub 托管的 Skill | POST /skill/{name}/invoke |
SandboxClient |
代码/浏览器沙箱执行 | POST /sandbox/execute |
CheckpointClient |
会话检查点读写 | GET/POST /checkpoint/{conversation_id} |
4.3 Capability Bridge 层
核心原则: 将平台客户端转换为框架原生的 Tool 对象。每个框架写一份。
# 以 DeepAgents 为例
from wisruntime.adapters.deepagents.mcp import DeepAgentsMCPTool
# MCPClient → DeepAgents BaseTool
tool = DeepAgentsMCPTool(
client=MCPClient(),
name="company_search",
description="搜索公司内部知识库"
)
agent = create_deep_agent(tools=[tool])
为什么需要这一层? DeepAgents 的 BaseTool 有特定的接口要求(如 ainvoke、schema、name)。MCPClient 返回的是原始 HTTP 响应。这层 Bridge 负责把 REST API 调用适配为框架期望的 Tool 协议。
4.4 Adapter 层
定位: 用户可选工具层。Server 不调用 Adapter,Adapter 是用户在 invoke_agent 中使用的辅助工具。
与 AgentRun 的设计一致:AgentRun 的 AgentRunConverter(仅 LangGraph 需要)是用户在 invoke_agent 内部自行使用的,不是 Server 的依赖。
两种使用方式:
方式 A: 用 wrap_agent 把 Agent 对象包装成 invoke_agent 函数 (便捷)
════════════════════════════════════════════════════════════════════
from wisruntime.adapters.deepagents import wrap_agent
agent = create_deep_agent(tools=[...])
create_server(wrap_agent(agent)).start(8000)
# wrap_agent 内部: Agent.astream_events → CanonicalEvent 流 → invoke_agent 函数
方式 B: 在 invoke_agent 内部手动做事件转换 (完全控制)
════════════════════════════════════════════════════════════════════
from wisruntime.adapters.deepagents import DeepAgentsAdapter
async def my_invoke_agent(request: AgentRequest):
agent = create_deep_agent(tools=[...])
adapter = DeepAgentsAdapter()
async for event in agent.astream_events(request.messages):
canonical = adapter.convert(event) # 框架事件 → CanonicalEvent
if canonical:
yield canonical
create_server(my_invoke_agent).start(8000)
Adapter 内部需要处理的核心问题 (参考 AgentRun AgentRunConverter):
| 问题 | 解决方案 |
|---|---|
| 流式工具调用 ID 追踪 | 维护 tool_call_index → id 映射,ToolCallStart 时携带 id |
| 推理/文本分离 | 检测 reasoning_content 或 reasoning-delta → ReasoningDelta |
| 结束检测 | v2: on_chain_end + name="LangGraph"; v3: message-finish |
| 错误降级 | on_tool_error → ToolCallEnd(error=...),不升级为全局 Error |
4.5 Server 层
核心原则: 与 AgentRun 完全一致——只接收 invoke_agent 函数,不感知框架。
┌──────────────────────────────────────────────────────────────┐
│ WisRuntimeServer │
│ │
│ 构造: create_server(invoke_agent, protocols=[DifyHandler()]) │
│ │
│ 初始化流程: │
│ 1. 创建 FastAPI app │
│ 2. 注入 ApiKeyMiddleware → contextvars │
│ 3. (可选) checkpoint 自动持久化包装 │
│ 4. 创建 AgentInvoker(invoke_agent) │
│ 5. 注册 /health 路由 │
│ 6. 挂载 ProtocolHandler 路由 │
│ │
│ 两种使用模式: │
│ │
│ 模式 1: 独立服务 (开发/调试) │
│ create_server(invoke_agent).start(port=8000) │
│ │
│ 模式 2: FastAPI 子应用 (生产推荐) │
│ app.mount("/agent", create_server(invoke_agent).as_fastapi_app())│
└──────────────────────────────────────────────────────────────┘
AgentInvoker — 唯一的归一化入口
invoke_agent 函数 → AgentInvoker.invoke(fn, request) → CanonicalEvent 流
自动检测:
├── async generator → 直接迭代
├── async function → await 得到返回值,单次 yield
├── sync function → loop.run_in_executor(线程池) + contextvars 传播
├── str → CanonicalEvent(type=TextDelta, data={delta: str})
├── CanonicalEvent → 透传
├── None → 跳过
└── Exception → CanonicalEvent(type=Error, ...)
设计决策:
├── Done 事件: AgentInvoker 在 generator 耗尽时自动插入
│ (Dify 协议必须有 message_end,AgentRun 不需要)
├── str 语义: 用户 yield 的 str 就是模型的文本输出 → TextDelta
│ 高级类型 (Reasoning/ToolCall) 用户通过直接 yield CanonicalEvent 表达
└── 函数签名: 不强约束,运行时 inspect 检测 (与 AgentRun 一致)
用户函数接收 AgentRequest 作为第一个位置参数
AgentRequest — 归一化请求模型
class Message(BaseModel):
role: Literal["system", "user", "assistant", "tool"]
content: str | list[dict] # 文本或多模态
name: str | None = None
class AgentRequest(BaseModel):
messages: list[Message] # 归一化消息列表
stream: bool = True # 是否流式
conversation_id: str | None = None # 会话ID
user_id: str | None = None # 用户ID
headers: dict[str, str] # 关键 header 副本 (可跨线程)
raw_request: Request | None = None # 原始 Starlette Request (本地可用)
protocol_extensions: dict = {} # 协议特有字段 (如 Dify 的 inputs/files)
ProtocolHandler — 响应序列化
┌─────────────────────────────────────────────────────────┐
│ DifyHandler │
│ │
│ 端点: │
│ POST /dify/v1/chat-messages SSE Streaming │
│ POST /dify/v1/chat-messages Blocking (stream=false) │
│ POST /dify/v1/chat-messages/{task_id}/stop (Phase 3) │
│ │
│ CanonicalEvent → Dify SSE 映射: │
│ TextDelta → agent_message (answer=delta) │
│ ReasoningDelta → reasoning_chunk (reasoning=delta) │
│ ToolCallStart → agent_thought (tool, tool_input) │
│ ToolCallEnd → agent_thought (observation) │
│ SubAgentStart → subagent_start │
│ SubAgentEnd → subagent_end │
│ FileOutput → message_file │
│ Usage → (累积到 message_end.metadata.usage) │
│ Error → error (message, code, status) │
│ Custom → {event: name, ...payload} │
│ Done → message_end │
│ │
│ DifyHandler 内部维护的协议特有状态: │
│ ├── agent_thought 的 id (唯一标识) + position (递增) │
│ │ CanonicalEvent 不携带 Dify 特定的 id/position, │
│ │ 由 Handler 自行生成,保持 CanonicalEvent 协议无关 │
│ └── 心跳: 每 10 秒自动发送 data: {"event": "ping"}\n\n │
│ (asyncio background task) │
│ │
│ AGUIHandler (规划中) │
│ CanonicalEvent → AG-UI SSE 格式 │
└─────────────────────────────────────────────────────────┘
WisRuntimeServer — 组装
class ServerConfig(BaseModel):
cors_origins: list[str] = ["*"]
health_path: str = "/health"
class WisRuntimeServer:
def __init__(self, invoker: AgentInvoker, protocols: list[ProtocolHandler], config: ServerConfig):
# 1. 创建 FastAPI app
# 2. (Phase 2) 注入 ApiKeyMiddleware
# 3. for handler in protocols: handler.install(app, invoker)
# 4. 注册 health 路由
# 5. 配置 CORS
def start(self, host="0.0.0.0", port=8000):
"""模式 1: 独立服务 (内部调 uvicorn.run)"""
def as_fastapi_app(self) -> FastAPI:
"""模式 2: 导出为 FastAPI 子应用,供 app.mount()"""
# 模式 3 (as_router) 不做。用户如需 include_router 级别的控制,
# 可以手动创建 AgentInvoker + DifyHandler 自行组装。
def create_server(
invoke_agent: Callable,
*,
protocols: list[ProtocolHandler] | None = None, # 默认 [DifyHandler()]
config: ServerConfig | None = None,
checkpoint_enabled: bool = False, # Phase 3
) -> WisRuntimeServer:
...
五、用户故事与实施蓝图
5.1 用户故事总览
故事 1 ──────────────────────────────────────────────────────────────
│ 用户故事: 作为 AI 工程师,我只需写一个 invoke_agent 函数, │
│ 就能获得一个 Dify 兼容的 SSE 服务端点 │
│ │
│ 验收标准: │
│ from wisruntime import create_server │
│ from wisruntime.model import AgentRequest │
│ │
│ async def my_invoke_agent(request: AgentRequest): │
│ # 用户可以自由使用任何框架、任意逻辑 │
│ async for chunk in llm.astream(request.messages): │
│ yield chunk.content # yield str 即可 │
│ │
│ create_server(my_invoke_agent).start(port=8000) │
│ # → curl -X POST http://localhost:8000/dify/v1/chat-messages │
│ # -d '{"query": "你好", "response_mode": "streaming"}' │
│ # → SSE 流式响应,包含 agent_message / agent_thought / message_end│
└─────────────────────────────────────────────────────────────────────┘
故事 2 ──────────────────────────────────────────────────────────────
│ 用户故事: 作为 AI 工程师,我接入 WIS Hub MCP 服务时, │
│ 只需创建一个 MCPClient,它能自动处理鉴权和协议转换 │
│ │
│ 验收标准: │
│ from wisruntime.mcp import MCPClient │
│ from wisruntime.adapters.deepagents.mcp import DeepAgentsMCPTool │
│ from wisruntime.adapters.deepagents import wrap_agent │
│ from deepagents import create_deep_agent │
│ │
│ client = MCPClient() # 自动读 WIS_HUB_API_KEY │
│ tool = DeepAgentsMCPTool(client, name="search") │
│ agent = create_deep_agent(tools=[tool]) │
│ create_server(wrap_agent(agent)).start(8000) │
│ # → Agent 调用工具时,MCPClient 自动携带 Bearer 头请求 WIS Hub │
└─────────────────────────────────────────────────────────────────────┘
故事 3 ──────────────────────────────────────────────────────────────
│ 用户故事: 作为 AI 工程师,我可以将 wisruntime 服务嵌入到已有 │
│ FastAPI 应用中,作为子路由挂载 │
│ │
│ 验收标准: │
│ from fastapi import FastAPI │
│ app = FastAPI() │
│ app.mount("/agent", create_server(my_invoke_agent).as_fastapi_app())│
│ # → /agent/dify/v1/chat-messages 就绪 │
│ # → 复用主应用的 middleware 和 lifecycle │
└─────────────────────────────────────────────────────────────────────┘
故事 4 ──────────────────────────────────────────────────────────────
│ 用户故事: 作为 AI 工程师,我用 wrap_agent 包装 deepagents Agent, │
│ 一行代码就生成 invoke_agent 函数 │
│ │
│ 验收标准: │
│ from deepagents import create_deep_agent │
│ from wisruntime.adapters.deepagents import wrap_agent │
│ │
│ agent = create_deep_agent(tools=[...]) │
│ create_server(wrap_agent(agent)).start(8000) │
│ # → wrap_agent 内部: astream_events → CanonicalEvent → yield │
└─────────────────────────────────────────────────────────────────────┘
故事 5 ──────────────────────────────────────────────────────────────
│ 用户故事: 作为 AI 工程师,我的 Agent 需要调用 WIS Hub 的 Skill 和 │
│ Sandbox 能力,使用与 MCP 相同的简洁 API │
│ │
│ 验收标准: │
│ from wisruntime.skill import SkillClient │
│ from wisruntime.sandbox import SandboxClient │
│ from wisruntime.adapters.deepagents.skill import DeepAgentsSkillTool│
│ from wisruntime.adapters.deepagents.sandbox import DeepAgentsSandboxTool│
│ agent = create_deep_agent(tools=[ │
│ DeepAgentsSkillTool(SkillClient(), name="data_analysis"), │
│ DeepAgentsSandboxTool(SandboxClient(), name="code_executor"), │
│ ]) │
│ create_server(wrap_agent(agent)).start(8000) │
└─────────────────────────────────────────────────────────────────────┘
故事 6 ──────────────────────────────────────────────────────────────
│ 用户故事: 作为 AI 工程师,我的 Agent 对话历史可以自动持久化到 │
│ WIS Hub Checkpoint 服务,支持断点续传 │
│ │
│ 验收标准: │
│ create_server(my_invoke_agent, checkpoint_enabled=True).start(8000) │
│ # → 每次对话自动保存到 WIS Hub │
│ # → 下次请求带有相同 conversation_id 时恢复上下文 │
└─────────────────────────────────────────────────────────────────────┘
5.2 实施阶段
Phase 0: 项目骨架 (已完成)
══════════════════════════
✅ 清理旧代码,确定新的架构方向
✅ 分析 AgentRun、LangChain、Dify 参考架构
✅ 确定 CanonicalEvent 11 种类型
✅ 确定分层架构
Phase 1: 核心基础设施 + MVP Server (当前)
════════════════════════════════════
目标: 用户故事 1 — 写 invoke_agent 函数,获得 Dify SSE 端点
范围内:
□ CanonicalEvent 11 种类型定义
□ AgentRequest + Message 模型
□ Config + CredentialContext (contextvars 定义) — ApiKeyMiddleware 后置到 Phase 2
□ AgentInvoker (async/sync/iterator 检测, str→TextDelta, Exception→Error, 自动 Done)
□ DifyHandler (parse_request + _format_stream + 心跳)
- agent_thought 的 id/position 由 Handler 内部维护
- Blocking 模式: 收集全部事件 → JSONResponse
□ WisRuntimeServer (start + as_fastapi_app) — as_router 不做
□ ProtocolRegistry + create_server 顶层 API
□ 单元测试 + SSE 端到端对接测试
范围外 (后续故事):
✗ ApiKeyMiddleware (Phase 2, 配合 MCPClient)
✗ DeepAgentsAdapter / wrap_agent (Phase 3)
✗ AGUIHandler (Phase 4)
✗ Checkpoint 自动持久化 (Phase 3)
✗ Stop endpoint (Phase 3)
✗ Platform Client 层 (Phase 2)
Phase 2: 平台能力接入
══════════════════
目标: 用户故事 2 + 5 — MCP/Skill/Sandbox 接入
□ MCPClient + MCP 数据模型
□ SkillClient + Skill 数据模型
□ SandboxClient + Sandbox 数据模型
□ DeepAgentsMCPTool (MCPClient → BaseTool)
□ DeepAgentsSkillTool (SkillClient → BaseTool)
□ DeepAgentsSandboxTool (SandboxClient → BaseTool)
Phase 3: Adapter + 高级特性
══════════════════════════
目标: 用户故事 3 + 4 + 6 — wrap_agent、FastAPI 嵌入、Checkpoint
□ DeepAgentsAdapter (astream_events → CanonicalEvent 转换)
□ wrap_agent(agent) 工厂函数
□ CheckpointClient + 自动持久化包装
□ SubAgentStart/End 支持
□ Custom 事件 (todo, recommendation_card, next_step)
□ 错误恢复与 graceful shutdown
□ Stop endpoint (对话中断)
Phase 4: 多框架 + 多协议
══════════════════════
目标: 验证可扩展性
□ AgentScope Adapter
□ AGUI Handler
□ 内部 PyPI 发布
□ 性能基准测试
5.3 目录结构 (目标态)
wisruntime/
├── __init__.py # 顶层导出: create_server, Config
├── config.py # Config, CredentialContext
├── middleware.py # ApiKeyMiddleware (纯 ASGI)
├── model.py # CanonicalEvent, AgentRequest 等核心模型
├── exceptions.py # 自定义异常
│
├── mcp/ # Platform Client: MCP
│ ├── __init__.py
│ ├── client.py # MCPClient
│ └── model.py # MCP 请求/响应模型
│
├── skill/ # Platform Client: Skill
│ ├── __init__.py
│ ├── client.py # SkillClient
│ └── model.py
│
├── sandbox/ # Platform Client: Sandbox
│ ├── __init__.py
│ ├── client.py # SandboxClient
│ └── model.py
│
├── memory/ # Platform Client: Checkpoint
│ ├── __init__.py
│ ├── client.py # CheckpointClient
│ └── model.py
│
├── adapters/ # Adapter + Capability Bridge (用户可选工具)
│ ├── __init__.py # 导出 wrap_agent 等便捷函数
│ ├── base.py # 框架事件 → CanonicalEvent 转换基类
│ └── deepagents/ # DeepAgents 框架
│ ├── __init__.py # 导出 wrap_agent, DeepAgentsAdapter
│ ├── adapter.py # DeepAgentsAdapter (事件转换)
│ ├── mcp.py # DeepAgentsMCPTool (Capability Bridge)
│ ├── skill.py # DeepAgentsSkillTool
│ └── sandbox.py # DeepAgentsSandboxTool
│
├── server/ # Server 层
│ ├── __init__.py
│ ├── server.py # WisRuntimeServer (FastAPI 组装)
│ ├── invoker.py # AgentInvoker (函数归一化)
│ ├── model.py # AgentRequest, ProtocolRegistry
│ ├── dify_handler.py # DifyHandler (SSE + Blocking)
│ └── agui_handler.py # AGUIHandler (规划中)
│
└── integration/ # 会话持久化 + 框架 Memory 适配
├── __init__.py
└── deepagents/
└── memory.py # WISCheckpointMemory (CheckpointClient → DeepAgents Memory)
六、技术规格
6.1 运行时依赖
| 包 | 版本 | 用途 |
|---|---|---|
fastapi |
≥ 0.110 | Web 框架 |
uvicorn[standard] |
≥ 0.27 | ASGI 服务器 |
sse-starlette |
≥ 2.0 | SSE 流式响应 |
pydantic |
≥ 2.0 | 数据校验与序列化 |
httpx |
≥ 0.27 | 异步 HTTP 客户端 |
6.2 环境变量
| 变量 | 用途 | 必填 |
|---|---|---|
WIS_HUB_API_KEY |
WIS Hub 统一 API-KEY | 使用 MCP/Skill/Sandbox/Checkpoint 时必填 |
WIS_HUB_ENDPOINT |
WIS Hub 地址 | 可选,默认读取 SDK 内置配置 |
6.3 Python 版本
≥ 3.11
七、参考资源
- AgentRun Python SDK 架构文档 — 阿里云 AgentRun SDK 完整架构
- LangChain 流式事件详解 — v2/v3 事件体系
- Dify vs 灵知 流式事件差异分析 — 协议兼容性分析
- PRD.md — 原始产品需求文档
Project details
Release history Release notifications | RSS feed
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 wisruntime-0.1.0.tar.gz.
File metadata
- Download URL: wisruntime-0.1.0.tar.gz
- Upload date:
- Size: 47.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bd4ddef65c4d2318997bde77203eeaf27253eb79b71de5e18121d2ea3d5991f
|
|
| MD5 |
f5e27641c10ce0417850a890644705d9
|
|
| BLAKE2b-256 |
b75f892be12d76d90e931d4fbd4d1b9189c6edb0ba01823c9264d3b80557decc
|
File details
Details for the file wisruntime-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wisruntime-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d076df3cfc792201e422b43b32687a3839b31671543b3444630953fc094ea9bc
|
|
| MD5 |
5b6c96ebd7a4be3b2d93e7f393e9f096
|
|
| BLAKE2b-256 |
a87b4d6ae8079b02ffefa8f156e62b57dff4a001c1ffbd5d7b4de22e9ce11abd
|