项目八 智能体互联网应用开发与创新实践
对应标准:GB/Z 185 全系列------应用使能层综合实践
建议学时:12 学时(理论 3 + 实践 9)
前置项目:项目一至项目七全部内容
项目导读
情境引入
经过前七个项目的学习,校园 IoA 平台已经具备了从身份认证、能力描述、自动发现、交互协作、工具调用、安全治理到统一网关与监控运维的全栈能力。但信息化办公室的王主任又提出了更高的要求------
"平台搭好了,但真正的应用场景呢?开学季新生入学,从查询专业信息、选宿舍、领校园卡、选课到加入社团,涉及五六个部门的服务。能不能让智能体自动编排 这些流程,新生只需要说一句'我是新生,帮我完成入学手续',智能体就自动协调所有服务?另外,能不能开放一个创新工坊,让学生自己设计智能体应用?"
这就是项目八要解决的------从"平台基础设施"走向"应用使能与创新":
- 工作流编排:让智能体按预设流程自动协调多步骤任务
- 全场景应用:构建覆盖完整业务场景的多智能体应用
- 创新实践:提供脚手架和评估框架,让学生自主开发智能体应用
学习目标
| 目标维度 | 具体要求 |
|---|---|
| 知识 | ① 理解 GB/Z 185 四层架构中应用使能层的定位与职责;② 掌握四种工作流编排模式(顺序、并行、条件、循环);③ 理解智能体应用的设计方法论与评估框架 |
| 技能 | ① 能开发工作流编排引擎,支持声明式任务编排;② 能设计并实现覆盖完整业务场景的多智能体应用;③ 能使用创新脚手架自主开发智能体应用并完成评估 |
| 素养 | ① 建立"应用驱动"的思维------技术为业务服务;② 形成"编排自动化"的工程意识;③ 培养创新实践与团队协作能力 |
项目任务总览
| 任务 | 名称 | 核心能力 | 产出物 |
|---|---|---|---|
| 任务 8.1 | 智能体工作流编排引擎 | 顺序/并行/条件/循环编排 | workflow_engine.py------工作流引擎 |
| 任务 8.2 | 智慧校园全场景智能体应用 | 多智能体场景设计与实现 | smart_campus_app.py------全场景应用 |
| 任务 8.3 | 智能体应用创新实战 | 项目脚手架与评估框架 | innovation_workshop.py------创新工坊 |
#mermaid-svg-Zlioem1iVJuHzbC8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Zlioem1iVJuHzbC8 .error-icon{fill:#552222;}#mermaid-svg-Zlioem1iVJuHzbC8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Zlioem1iVJuHzbC8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Zlioem1iVJuHzbC8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Zlioem1iVJuHzbC8 .marker.cross{stroke:#333333;}#mermaid-svg-Zlioem1iVJuHzbC8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Zlioem1iVJuHzbC8 p{margin:0;}#mermaid-svg-Zlioem1iVJuHzbC8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 .cluster-label text{fill:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 .cluster-label span{color:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 .cluster-label span p{background-color:transparent;}#mermaid-svg-Zlioem1iVJuHzbC8 .label text,#mermaid-svg-Zlioem1iVJuHzbC8 span{fill:#333;color:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 .node rect,#mermaid-svg-Zlioem1iVJuHzbC8 .node circle,#mermaid-svg-Zlioem1iVJuHzbC8 .node ellipse,#mermaid-svg-Zlioem1iVJuHzbC8 .node polygon,#mermaid-svg-Zlioem1iVJuHzbC8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Zlioem1iVJuHzbC8 .rough-node .label text,#mermaid-svg-Zlioem1iVJuHzbC8 .node .label text,#mermaid-svg-Zlioem1iVJuHzbC8 .image-shape .label,#mermaid-svg-Zlioem1iVJuHzbC8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Zlioem1iVJuHzbC8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Zlioem1iVJuHzbC8 .rough-node .label,#mermaid-svg-Zlioem1iVJuHzbC8 .node .label,#mermaid-svg-Zlioem1iVJuHzbC8 .image-shape .label,#mermaid-svg-Zlioem1iVJuHzbC8 .icon-shape .label{text-align:center;}#mermaid-svg-Zlioem1iVJuHzbC8 .node.clickable{cursor:pointer;}#mermaid-svg-Zlioem1iVJuHzbC8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Zlioem1iVJuHzbC8 .arrowheadPath{fill:#333333;}#mermaid-svg-Zlioem1iVJuHzbC8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Zlioem1iVJuHzbC8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Zlioem1iVJuHzbC8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zlioem1iVJuHzbC8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Zlioem1iVJuHzbC8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zlioem1iVJuHzbC8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Zlioem1iVJuHzbC8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Zlioem1iVJuHzbC8 .cluster text{fill:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 .cluster span{color:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Zlioem1iVJuHzbC8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Zlioem1iVJuHzbC8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Zlioem1iVJuHzbC8 .icon-shape,#mermaid-svg-Zlioem1iVJuHzbC8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zlioem1iVJuHzbC8 .icon-shape p,#mermaid-svg-Zlioem1iVJuHzbC8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Zlioem1iVJuHzbC8 .icon-shape .label rect,#mermaid-svg-Zlioem1iVJuHzbC8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zlioem1iVJuHzbC8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Zlioem1iVJuHzbC8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Zlioem1iVJuHzbC8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 提供编排能力
提供场景参考
反哺创新
任务 8.1工作流引擎四种编排模式
任务 8.2全场景应用新生入学场景
任务 8.3创新实战脚手架+评估
项目与前序项目的关系
项目一:搭建智能体 → 体验协作 → 画架构图
项目二:身份码 → 注册中心 → 凭证验证
项目三:能力名片 → 发现服务 → 自动匹配
项目四:任务状态 → 流式交互 → 多轮对话 → 主从协作
项目五:工具服务 → 工具调用 → 综合实战
项目六:安全网关 → 合规检测 → 生命周期管理
项目七:统一网关 → 监控看板 → 部署实战
项目八:工作流引擎 → 全场景应用 → 创新实战 ← 你在这里(应用使能)
项目定位:项目一至七解决了"怎么建、怎么认、怎么找、怎么交互、怎么用工具、怎么管安全、怎么部署运维"的问题。项目八解决"怎么编排自动化、怎么构建完整应用、怎么让学生创新"的应用使能问题------这是从"平台"到"应用"的最后一跃。
GB/Z 185 四层架构与项目映射
#mermaid-svg-0IST84SGnkzpV3Yi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0IST84SGnkzpV3Yi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0IST84SGnkzpV3Yi .error-icon{fill:#552222;}#mermaid-svg-0IST84SGnkzpV3Yi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0IST84SGnkzpV3Yi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0IST84SGnkzpV3Yi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0IST84SGnkzpV3Yi .marker.cross{stroke:#333333;}#mermaid-svg-0IST84SGnkzpV3Yi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0IST84SGnkzpV3Yi p{margin:0;}#mermaid-svg-0IST84SGnkzpV3Yi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0IST84SGnkzpV3Yi .cluster-label text{fill:#333;}#mermaid-svg-0IST84SGnkzpV3Yi .cluster-label span{color:#333;}#mermaid-svg-0IST84SGnkzpV3Yi .cluster-label span p{background-color:transparent;}#mermaid-svg-0IST84SGnkzpV3Yi .label text,#mermaid-svg-0IST84SGnkzpV3Yi span{fill:#333;color:#333;}#mermaid-svg-0IST84SGnkzpV3Yi .node rect,#mermaid-svg-0IST84SGnkzpV3Yi .node circle,#mermaid-svg-0IST84SGnkzpV3Yi .node ellipse,#mermaid-svg-0IST84SGnkzpV3Yi .node polygon,#mermaid-svg-0IST84SGnkzpV3Yi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0IST84SGnkzpV3Yi .rough-node .label text,#mermaid-svg-0IST84SGnkzpV3Yi .node .label text,#mermaid-svg-0IST84SGnkzpV3Yi .image-shape .label,#mermaid-svg-0IST84SGnkzpV3Yi .icon-shape .label{text-anchor:middle;}#mermaid-svg-0IST84SGnkzpV3Yi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0IST84SGnkzpV3Yi .rough-node .label,#mermaid-svg-0IST84SGnkzpV3Yi .node .label,#mermaid-svg-0IST84SGnkzpV3Yi .image-shape .label,#mermaid-svg-0IST84SGnkzpV3Yi .icon-shape .label{text-align:center;}#mermaid-svg-0IST84SGnkzpV3Yi .node.clickable{cursor:pointer;}#mermaid-svg-0IST84SGnkzpV3Yi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0IST84SGnkzpV3Yi .arrowheadPath{fill:#333333;}#mermaid-svg-0IST84SGnkzpV3Yi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0IST84SGnkzpV3Yi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0IST84SGnkzpV3Yi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0IST84SGnkzpV3Yi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0IST84SGnkzpV3Yi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0IST84SGnkzpV3Yi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0IST84SGnkzpV3Yi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0IST84SGnkzpV3Yi .cluster text{fill:#333;}#mermaid-svg-0IST84SGnkzpV3Yi .cluster span{color:#333;}#mermaid-svg-0IST84SGnkzpV3Yi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0IST84SGnkzpV3Yi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0IST84SGnkzpV3Yi rect.text{fill:none;stroke-width:0;}#mermaid-svg-0IST84SGnkzpV3Yi .icon-shape,#mermaid-svg-0IST84SGnkzpV3Yi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0IST84SGnkzpV3Yi .icon-shape p,#mermaid-svg-0IST84SGnkzpV3Yi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0IST84SGnkzpV3Yi .icon-shape .label rect,#mermaid-svg-0IST84SGnkzpV3Yi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0IST84SGnkzpV3Yi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0IST84SGnkzpV3Yi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0IST84SGnkzpV3Yi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 基础资源层
智能体互联层
协作管理层
应用使能层
项目八 8.1
项目八 8.2
项目八 8.3
项目六
项目七
项目七
项目二
项目三
项目四
项目五
工作流编排
场景应用
创新工坊
安全网关
统一网关
监控运维
身份认证
描述发现
交互协作
工具调用
智能体运行时
网络通信
| 架构层 | 职责 | 对应项目 |
|---|---|---|
| 基础资源层 | 智能体运行时、网络通信 | 项目一 |
| 智能体互联层 | 身份、描述、发现、交互、工具 | 项目二至五 |
| 协作管理层 | 安全、网关、监控、部署 | 项目六至七 |
| 应用使能层 | 工作流编排、场景应用、创新实践 | 项目八 |
全书服务端口总览(更新)
| 服务 | 端口 | 对应项目 | 说明 |
|---|---|---|---|
| 发现服务 | 8000 | 项目三 | 智能体发现与匹配 |
| 工具服务 | 8001 | 项目五 | 工具列表与工具调用 |
| 安全网关 | 8002 | 项目六 | 身份鉴别与访问控制 |
| 生命周期管理 | 8003 | 项目六 | 注册/锁定/注销管理 |
| 统一网关 | 8004 | 项目七 | 统一入口,服务路由 |
| 监控看板 | 8005 | 项目七 | 监控大屏,可视化 |
| 工作流引擎 | 8006 | 项目八 | 工作流编排与执行 |
| 全场景应用 | 8007 | 项目八 | 智慧校园场景应用 |
| 创新工坊 | 8008 | 项目八 | 脚手架+评估+作品展厅 |
| 智能体服务 | 9999 | 项目一/四 | A2A 智能体(通知助手等) |
任务 8.1 智能体工作流编排引擎
建议学时:4 学时
① 任务情境
校园里有大量需要多步骤协调的流程------新生入学、社团活动审批、报修处理等。这些流程往往涉及多个智能体和服务,如果靠人工一步步触发,效率很低。
你需要开发一个工作流编排引擎,支持声明式定义工作流,自动按顺序协调多个智能体完成任务。引擎需要支持四种编排模式:
- 顺序执行:任务 A → 任务 B → 任务 C
- 并行执行:任务 A 和任务 B 同时进行,全部完成后继续
- 条件分支:根据上一步结果决定走哪条路径
- 循环重试:重复执行某任务直到满足条件
② 知识准备
一、四种工作流编排模式
#mermaid-svg-Bxi98uNEbgiSAyXa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Bxi98uNEbgiSAyXa .error-icon{fill:#552222;}#mermaid-svg-Bxi98uNEbgiSAyXa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Bxi98uNEbgiSAyXa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Bxi98uNEbgiSAyXa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Bxi98uNEbgiSAyXa .marker.cross{stroke:#333333;}#mermaid-svg-Bxi98uNEbgiSAyXa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Bxi98uNEbgiSAyXa p{margin:0;}#mermaid-svg-Bxi98uNEbgiSAyXa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa .cluster-label text{fill:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa .cluster-label span{color:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa .cluster-label span p{background-color:transparent;}#mermaid-svg-Bxi98uNEbgiSAyXa .label text,#mermaid-svg-Bxi98uNEbgiSAyXa span{fill:#333;color:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa .node rect,#mermaid-svg-Bxi98uNEbgiSAyXa .node circle,#mermaid-svg-Bxi98uNEbgiSAyXa .node ellipse,#mermaid-svg-Bxi98uNEbgiSAyXa .node polygon,#mermaid-svg-Bxi98uNEbgiSAyXa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Bxi98uNEbgiSAyXa .rough-node .label text,#mermaid-svg-Bxi98uNEbgiSAyXa .node .label text,#mermaid-svg-Bxi98uNEbgiSAyXa .image-shape .label,#mermaid-svg-Bxi98uNEbgiSAyXa .icon-shape .label{text-anchor:middle;}#mermaid-svg-Bxi98uNEbgiSAyXa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Bxi98uNEbgiSAyXa .rough-node .label,#mermaid-svg-Bxi98uNEbgiSAyXa .node .label,#mermaid-svg-Bxi98uNEbgiSAyXa .image-shape .label,#mermaid-svg-Bxi98uNEbgiSAyXa .icon-shape .label{text-align:center;}#mermaid-svg-Bxi98uNEbgiSAyXa .node.clickable{cursor:pointer;}#mermaid-svg-Bxi98uNEbgiSAyXa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Bxi98uNEbgiSAyXa .arrowheadPath{fill:#333333;}#mermaid-svg-Bxi98uNEbgiSAyXa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Bxi98uNEbgiSAyXa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Bxi98uNEbgiSAyXa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bxi98uNEbgiSAyXa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Bxi98uNEbgiSAyXa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bxi98uNEbgiSAyXa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Bxi98uNEbgiSAyXa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Bxi98uNEbgiSAyXa .cluster text{fill:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa .cluster span{color:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Bxi98uNEbgiSAyXa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Bxi98uNEbgiSAyXa rect.text{fill:none;stroke-width:0;}#mermaid-svg-Bxi98uNEbgiSAyXa .icon-shape,#mermaid-svg-Bxi98uNEbgiSAyXa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bxi98uNEbgiSAyXa .icon-shape p,#mermaid-svg-Bxi98uNEbgiSAyXa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Bxi98uNEbgiSAyXa .icon-shape .label rect,#mermaid-svg-Bxi98uNEbgiSAyXa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bxi98uNEbgiSAyXa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Bxi98uNEbgiSAyXa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Bxi98uNEbgiSAyXa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 循环重试
否
是
任务A
完成?
任务B
条件分支
满足
不满足
任务A
条件判断
任务B
任务D
并行执行
任务A
合并
任务B
任务C
顺序执行
任务A
任务B
任务C
| 模式 | 适用场景 | 示例 |
|---|---|---|
| 顺序 | 有严格先后依赖的任务 | 注册身份 → 生成名片 → 注册发现服务 |
| 并行 | 无依赖、可同时进行的任务 | 同时查询天气和查询课表 |
| 条件 | 需要根据结果决策的流程 | 天气下雨→通知改室内;不下雨→正常活动 |
| 循环 | 需要重试或轮询的任务 | 轮询服务状态直到上线 |
二、工作流定义格式
工作流采用声明式定义------用 JSON/dict 描述流程结构,引擎负责解释执行:
python
# 工作流定义示例
workflow = {
'name': '新生入学引导',
'version': '1.0',
'steps': [
{
'id': 'step1',
'type': 'task', # 单任务节点
'name': '查询专业信息',
'service': 'tool', # 通过网关代理的服务
'path': 'tools/call',
'method': 'POST',
'params': {'toolId': 'info_query', 'params': {'type': 'major'}},
'output_key': 'major_info', # 结果存入上下文
},
{
'id': 'step2',
'type': 'parallel', # 并行节点
'name': '并行办理',
'tasks': [
{'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'dorm_assign', 'params': {}},
'output_key': 'dorm'},
{'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'card_issue', 'params': {}},
'output_key': 'card'},
],
},
{
'id': 'step3',
'type': 'condition', # 条件分支节点
'name': '宿舍分配检查',
'expression': 'dorm.success == true',
'then': {'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'notify', 'params': {'msg': '宿舍已分配'}},
'output_key': 'notify_ok'},
'else': {'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'notify', 'params': {'msg': '宿舍待分配'}},
'output_key': 'notify_fail'},
},
],
}
三、工作流引擎核心组件
#mermaid-svg-0mv5QXhnkCW8LwCm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0mv5QXhnkCW8LwCm .error-icon{fill:#552222;}#mermaid-svg-0mv5QXhnkCW8LwCm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0mv5QXhnkCW8LwCm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0mv5QXhnkCW8LwCm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0mv5QXhnkCW8LwCm .marker.cross{stroke:#333333;}#mermaid-svg-0mv5QXhnkCW8LwCm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0mv5QXhnkCW8LwCm p{margin:0;}#mermaid-svg-0mv5QXhnkCW8LwCm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm .cluster-label text{fill:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm .cluster-label span{color:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm .cluster-label span p{background-color:transparent;}#mermaid-svg-0mv5QXhnkCW8LwCm .label text,#mermaid-svg-0mv5QXhnkCW8LwCm span{fill:#333;color:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm .node rect,#mermaid-svg-0mv5QXhnkCW8LwCm .node circle,#mermaid-svg-0mv5QXhnkCW8LwCm .node ellipse,#mermaid-svg-0mv5QXhnkCW8LwCm .node polygon,#mermaid-svg-0mv5QXhnkCW8LwCm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0mv5QXhnkCW8LwCm .rough-node .label text,#mermaid-svg-0mv5QXhnkCW8LwCm .node .label text,#mermaid-svg-0mv5QXhnkCW8LwCm .image-shape .label,#mermaid-svg-0mv5QXhnkCW8LwCm .icon-shape .label{text-anchor:middle;}#mermaid-svg-0mv5QXhnkCW8LwCm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0mv5QXhnkCW8LwCm .rough-node .label,#mermaid-svg-0mv5QXhnkCW8LwCm .node .label,#mermaid-svg-0mv5QXhnkCW8LwCm .image-shape .label,#mermaid-svg-0mv5QXhnkCW8LwCm .icon-shape .label{text-align:center;}#mermaid-svg-0mv5QXhnkCW8LwCm .node.clickable{cursor:pointer;}#mermaid-svg-0mv5QXhnkCW8LwCm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0mv5QXhnkCW8LwCm .arrowheadPath{fill:#333333;}#mermaid-svg-0mv5QXhnkCW8LwCm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0mv5QXhnkCW8LwCm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0mv5QXhnkCW8LwCm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0mv5QXhnkCW8LwCm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0mv5QXhnkCW8LwCm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0mv5QXhnkCW8LwCm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0mv5QXhnkCW8LwCm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0mv5QXhnkCW8LwCm .cluster text{fill:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm .cluster span{color:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0mv5QXhnkCW8LwCm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0mv5QXhnkCW8LwCm rect.text{fill:none;stroke-width:0;}#mermaid-svg-0mv5QXhnkCW8LwCm .icon-shape,#mermaid-svg-0mv5QXhnkCW8LwCm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0mv5QXhnkCW8LwCm .icon-shape p,#mermaid-svg-0mv5QXhnkCW8LwCm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0mv5QXhnkCW8LwCm .icon-shape .label rect,#mermaid-svg-0mv5QXhnkCW8LwCm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0mv5QXhnkCW8LwCm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0mv5QXhnkCW8LwCm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0mv5QXhnkCW8LwCm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} task
parallel
condition
loop
工作流定义JSON/dict
解析器
执行引擎
执行上下文存储中间结果
任务执行器
并行执行器
条件评估器
循环控制器
统一网关 8004
后端服务集群
状态追踪器
状态查询 API
③ 任务实施
步骤 1:准备项目目录
powershell
cd d:\潘志宏工作空间\IoA-Agent\ioa-lab
.venv\Scripts\activate
mkdir project8
cd project8
步骤 2:编写工作流编排引擎
新建文件 workflow_engine.py:
python
# workflow_engine.py
# 智能体工作流编排引擎------声明式任务编排
# 支持四种模式:顺序、并行、条件、循环
# 通过统一网关(8004)调用后端服务
import asyncio
import json
import re
from datetime import datetime
from enum import Enum
from typing import Any, Optional
import httpx
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI(
title='智能体工作流编排引擎',
description='GB/Z 185 应用使能层------工作流编排',
version='1.0.0',
)
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_methods=['*'],
allow_headers=['*'],
)
# ============================================================
# 一、工作流状态定义
# ============================================================
class StepStatus(str, Enum):
"""步骤执行状态。"""
PENDING = 'pending'
RUNNING = 'running'
SUCCESS = 'success'
FAILED = 'failed'
SKIPPED = 'skipped'
class WorkflowStatus(str, Enum):
"""工作流整体状态。"""
PENDING = 'pending'
RUNNING = 'running'
COMPLETED = 'completed'
FAILED = 'failed'
CANCELED = 'canceled'
# 工作流执行记录(内存存储,实际场景应使用数据库)
workflow_instances: dict[str, dict] = {}
GATEWAY_URL = 'http://127.0.0.1:8004'
def _value_equal(left, right) -> bool:
"""比较两个值是否相等(容忍布尔值之间的严格匹配)。"""
return left == right
# ============================================================
# 二、执行上下文------存储中间结果
# ============================================================
class ExecutionContext:
"""工作流执行上下文。
存储每个步骤的输出结果,供后续步骤引用。
支持 expression 表达式求值,访问上下文变量。
"""
def __init__(self):
self.variables: dict[str, Any] = {}
self.step_results: dict[str, dict] = {}
self.history: list[dict] = []
def set(self, key: str, value: Any) -> None:
"""设置上下文变量。"""
self.variables[key] = value
def get(self, key: str, default: Any = None) -> Any:
"""获取上下文变量。"""
return self.variables.get(key, default)
def record_step(self, step_id: str, status: str, result: Any = None,
error: str = '') -> None:
"""记录步骤执行结果。"""
entry = {
'step_id': step_id,
'status': status,
'result': result,
'error': error,
'timestamp': datetime.now().isoformat(),
}
self.step_results[step_id] = entry
self.history.append(entry)
def evaluate(self, expression: str) -> bool:
"""评估条件表达式(不使用 eval,清晰且安全)。
支持表达式形式:
- ``变量路径 == true`` 布尔相等,如 ``dorm_result.success == true``
- ``变量路径 != false`` 布尔不等
- ``变量路径 > 0`` 数值比较,如 ``check_result.count > 0``
- ``变量路径 == '文本'`` 字符串比较
- ``变量路径.contains('关键字')`` 包含判断
说明:路径以 ``.`` 分隔逐级索引,例如 ``dorm_result.success``
表示读取上下文变量 ``dorm_result`` 的 ``success`` 字段。
"""
try:
expr = expression.strip()
# 形式 1:contains 包含判断------变量路径.contains('关键字')
m = re.fullmatch(r"([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\.contains\((.*)\)", expr)
if m:
value = self._resolve_path(m.group(1))
keyword = m.group(2).strip()
keyword = keyword[1:-1] if len(keyword) >= 2 and keyword[0] == keyword[-1] else keyword
return value is not None and keyword in str(value)
# 形式 2:解析「路径 运算符 字面量」三段,如 dorm_result.success == true
match = re.fullmatch(
r"([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*(==|!=|>=|<=|>|<)\s*(.+)",
expr,
)
if not match:
return False
path, op, literal_text = match.group(1), match.group(2), match.group(3).strip()
left = self._resolve_path(path)
right = self._parse_literal(literal_text)
# 数量比较(> >= < <=)------ 类型不匹配时由 try/except 兜底返回 False
if op in ('>', '>=', '<', '<='):
if isinstance(left, bool) or isinstance(right, bool):
return False
try:
return {
'>': left > right,
'>=': left >= right,
'<': left < right,
'<=': left <= right,
}[op]
except TypeError:
return False
# 相等比较:== 与 !=
if op == '==':
return _value_equal(left, right)
return not _value_equal(left, right)
except Exception:
# 表达式求值失败时返回 False
return False
def _resolve_path(self, path: str):
"""按点分路径逐级读取上下文变量,如 dorm_result.success。"""
value = self.variables
for part in path.split('.'):
if isinstance(value, dict):
if part not in value:
return None
value = value[part]
else:
value = getattr(value, part, None)
return value
@staticmethod
def _parse_literal(text: str):
"""把表达式的右侧字面量转换成 Python 值。"""
token = text.strip()
if token.lower() == 'true':
return True
if token.lower() == 'false':
return False
if token.lower() in ('none', 'null'):
return None
# 单引号 / 双引号包裹的字符串
if len(token) >= 2 and token[0] == token[-1] and token[0] in ('\'', '"'):
return token[1:-1]
# 数字
try:
if '.' in token:
return float(token)
return int(token)
except ValueError:
return token
# ============================================================
# 三、任务执行器------通过统一网关调用后端服务
# ============================================================
class TaskExecutor:
"""任务执行器------通过统一网关代理调用后端服务。"""
@staticmethod
async def execute_task(task: dict, context: ExecutionContext) -> dict:
"""执行单个任务节点。
通过统一网关的 /proxy/{service}/{path} 接口转发请求。
"""
service = task.get('service', '')
path = task.get('path', '')
method = task.get('method', 'GET').upper()
params = task.get('params', {})
output_key = task.get('output_key', '')
timeout = task.get('timeout', 15.0)
url = f'{GATEWAY_URL}/proxy/{service}/{path}'
try:
async with httpx.AsyncClient(timeout=timeout, trust_env=False) as client:
if method == 'GET':
resp = await client.get(url, params=params)
elif method == 'POST':
resp = await client.post(url, json=params)
elif method == 'PUT':
resp = await client.put(url, json=params)
elif method == 'DELETE':
resp = await client.delete(url, params=params)
else:
return {'success': False, 'error': f'不支持的方法:{method}'}
if resp.status_code == 200:
try:
result = resp.json()
except Exception:
result = {'raw': resp.text}
# 存入上下文
if output_key:
context.set(output_key, result)
return {'success': True, 'data': result, 'status_code': resp.status_code}
else:
return {
'success': False,
'error': f'HTTP {resp.status_code}',
'status_code': resp.status_code,
}
except httpx.ConnectError:
return {'success': False, 'error': '统一网关未启动(8004)'}
except httpx.TimeoutException:
return {'success': False, 'error': f'请求超时({timeout}秒)'}
except Exception as e:
return {'success': False, 'error': str(e)}
# ============================================================
# 四、工作流执行引擎------核心逻辑
# ============================================================
class WorkflowEngine:
"""工作流执行引擎。
解析工作流定义,按顺序执行各步骤,
支持四种节点类型:task、parallel、condition、loop。
"""
def __init__(self):
self.context = ExecutionContext()
async def execute_workflow(self, workflow: dict,
instance_id: str = '') -> dict:
"""执行完整工作流。"""
if not instance_id:
instance_id = f'wf_{datetime.now().strftime("%Y%m%d%H%M%S")}'
steps = workflow.get('steps', [])
wf_name = workflow.get('name', '未命名工作流')
# 初始化实例记录
workflow_instances[instance_id] = {
'instance_id': instance_id,
'workflow_name': wf_name,
'status': WorkflowStatus.RUNNING.value,
'total_steps': len(steps),
'completed_steps': 0,
'started_at': datetime.now().isoformat(),
'finished_at': None,
'context': {},
'history': [],
}
# 逐步执行
for step in steps:
step_id = step.get('id', '')
step_type = step.get('type', 'task')
# 更新实例状态
workflow_instances[instance_id]['current_step'] = step_id
try:
if step_type == 'task':
await self._execute_task_node(step, instance_id)
elif step_type == 'parallel':
await self._execute_parallel_node(step, instance_id)
elif step_type == 'condition':
await self._execute_condition_node(step, instance_id)
elif step_type == 'loop':
await self._execute_loop_node(step, instance_id)
else:
self.context.record_step(step_id, StepStatus.SKIPPED.value,
error=f'未知节点类型:{step_type}')
workflow_instances[instance_id]['completed_steps'] += 1
except Exception as e:
self.context.record_step(step_id, StepStatus.FAILED.value,
error=str(e))
# 标记工作流失败
workflow_instances[instance_id]['status'] = WorkflowStatus.FAILED.value
workflow_instances[instance_id]['finished_at'] = datetime.now().isoformat()
workflow_instances[instance_id]['context'] = self.context.variables
workflow_instances[instance_id]['history'] = self.context.history
return {
'instance_id': instance_id,
'status': WorkflowStatus.FAILED.value,
'failed_step': step_id,
'error': str(e),
}
# 工作流完成
workflow_instances[instance_id]['status'] = WorkflowStatus.COMPLETED.value
workflow_instances[instance_id]['finished_at'] = datetime.now().isoformat()
workflow_instances[instance_id]['context'] = self.context.variables
workflow_instances[instance_id]['history'] = self.context.history
return {
'instance_id': instance_id,
'status': WorkflowStatus.COMPLETED.value,
'total_steps': len(steps),
'completed_steps': workflow_instances[instance_id]['completed_steps'],
'context': self.context.variables,
}
async def _execute_task_node(self, step: dict, instance_id: str) -> None:
"""执行 task 类型节点------单个任务。"""
step_id = step['id']
self.context.record_step(step_id, StepStatus.RUNNING.value)
result = await TaskExecutor.execute_task(step, self.context)
if result.get('success'):
self.context.record_step(step_id, StepStatus.SUCCESS.value,
result=result.get('data'))
else:
self.context.record_step(step_id, StepStatus.FAILED.value,
error=result.get('error', '未知错误'))
# 如果步骤标记为必需,则抛出异常中断工作流
if step.get('required', True):
raise Exception(f"步骤 {step_id} 失败:{result.get('error')}")
async def _execute_parallel_node(self, step: dict, instance_id: str) -> None:
"""执行 parallel 类型节点------并行任务。"""
step_id = step['id']
self.context.record_step(step_id, StepStatus.RUNNING.value)
tasks = step.get('tasks', [])
if not tasks:
self.context.record_step(step_id, StepStatus.SKIPPED.value,
error='无并行任务')
return
# 并发执行所有任务
coroutines = [TaskExecutor.execute_task(task, self.context) for task in tasks]
results = await asyncio.gather(*coroutines, return_exceptions=True)
# 检查结果
all_success = True
for i, result in enumerate(results):
if isinstance(result, Exception):
all_success = False
output_key = tasks[i].get('output_key', f'task_{i}')
self.context.set(output_key, {'success': False, 'error': str(result)})
elif not result.get('success'):
all_success = False
if all_success:
self.context.record_step(step_id, StepStatus.SUCCESS.value,
result=f'{len(tasks)} 个并行任务全部成功')
else:
self.context.record_step(step_id, StepStatus.FAILED.value,
error='部分并行任务失败')
if step.get('required', False):
raise Exception(f'并行节点 {step_id} 存在失败任务')
async def _execute_condition_node(self, step: dict, instance_id: str) -> None:
"""执行 condition 类型节点------条件分支。"""
step_id = step['id']
self.context.record_step(step_id, StepStatus.RUNNING.value)
expression = step.get('expression', 'false')
condition_met = self.context.evaluate(expression)
# 选择分支
branch = step.get('then', {}) if condition_met else step.get('else', {})
if branch:
branch_result = await TaskExecutor.execute_task(branch, self.context)
branch_name = 'then' if condition_met else 'else'
if branch_result.get('success'):
self.context.record_step(step_id, StepStatus.SUCCESS.value,
result=f'分支:{branch_name}')
else:
self.context.record_step(step_id, StepStatus.FAILED.value,
error=f'分支 {branch_name} 失败:{branch_result.get("error")}')
else:
self.context.record_step(step_id, StepStatus.SKIPPED.value,
result='无匹配分支任务')
async def _execute_loop_node(self, step: dict, instance_id: str) -> None:
"""执行 loop 类型节点------循环重试。"""
step_id = step['id']
self.context.record_step(step_id, StepStatus.RUNNING.value)
task = step.get('task', {})
exit_condition = step.get('until', 'true')
max_iterations = step.get('max_iterations', 5)
delay = step.get('delay', 1.0)
iterations = 0
last_result = None
while iterations < max_iterations:
iterations += 1
result = await TaskExecutor.execute_task(task, self.context)
last_result = result
if result.get('success'):
# 检查退出条件
if self.context.evaluate(exit_condition):
self.context.record_step(step_id, StepStatus.SUCCESS.value,
result=f'循环 {iterations} 次后满足退出条件')
return
else:
# 任务失败,检查是否应继续重试
if not step.get('retry_on_fail', True):
self.context.record_step(step_id, StepStatus.FAILED.value,
error=f'第 {iterations} 次执行失败:{result.get("error")}')
if step.get('required', False):
raise Exception(f'循环节点 {step_id} 失败')
return
# 等待延迟
if delay > 0 and iterations < max_iterations:
await asyncio.sleep(delay)
# 达到最大迭代次数
self.context.record_step(step_id, StepStatus.FAILED.value,
error=f'达到最大循环次数 {max_iterations}')
if step.get('required', False):
raise Exception(f'循环节点 {step_id} 达到最大重试次数')
# ============================================================
# 五、API 接口
# ============================================================
class WorkflowRequest(BaseModel):
"""工作流执行请求。"""
workflow: dict
instance_id: str = ''
@app.post('/workflows/execute')
async def execute_workflow(req: WorkflowRequest):
"""接口 1:执行工作流。
接收工作流定义,异步执行并返回执行结果。
"""
engine = WorkflowEngine()
result = await engine.execute_workflow(req.workflow, req.instance_id)
return result
@app.get('/workflows/instances')
async def list_instances():
"""接口 2:列出所有工作流实例。"""
return {
'count': len(workflow_instances),
'instances': [
{
'instance_id': iid,
'workflow_name': data['workflow_name'],
'status': data['status'],
'started_at': data['started_at'],
'finished_at': data.get('finished_at'),
'completed_steps': data.get('completed_steps', 0),
'total_steps': data.get('total_steps', 0),
}
for iid, data in workflow_instances.items()
],
}
@app.get('/workflows/instances/{instance_id}')
async def get_instance(instance_id: str):
"""接口 3:查询单个工作流实例详情。"""
if instance_id not in workflow_instances:
raise HTTPException(status_code=404, detail=f'未找到实例:{instance_id}')
return workflow_instances[instance_id]
@app.post('/workflows/demo')
async def run_demo_workflow():
"""接口 4:运行演示工作流。
执行一个包含四种编排模式的演示工作流。
演示场景:社团活动准备------查询天气 → 并行(通知成员+预订教室) → 条件(确认人数) → 循环(等待签到)
"""
demo_workflow = {
'name': '社团活动准备流程',
'version': '1.0',
'steps': [
{
'id': 'step1',
'type': 'task',
'name': '查询天气',
'service': 'tool',
'path': 'tools/call',
'method': 'POST',
'params': {'toolId': 'weather_query', 'params': {'city': '北京'}},
'output_key': 'weather',
},
{
'id': 'step2',
'type': 'parallel',
'name': '并行准备',
'tasks': [
{
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'calendar_add', 'params': {
'title': '社团活动', 'date': '2026-09-01',
'time': '14:00', 'location': 'A301',
}},
'output_key': 'calendar',
},
{
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'email_send', 'params': {
'to': 'members@club.edu', 'subject': '活动通知',
'body': '本周五下午2点A301社团活动,请准时参加。',
}},
'output_key': 'email',
},
],
'required': False,
},
{
'id': 'step3',
'type': 'condition',
'name': '邮件发送结果检查',
'expression': 'email.success == true',
'then': {
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'email_send', 'params': {
'to': 'leader@club.edu', 'subject': '准备完成',
'body': '活动通知已发送,教室已预订。',
}},
'output_key': 'confirm',
},
'else': {
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'email_send', 'params': {
'to': 'leader@club.edu', 'subject': '准备异常',
'body': '通知发送失败,请手动处理。',
}},
'output_key': 'alert',
},
},
{
'id': 'step4',
'type': 'loop',
'name': '等待签到确认',
'task': {
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {'toolId': 'calendar_query', 'params': {'date': '2026-09-01'}},
'output_key': 'check_result',
},
'until': 'check_result.count > 0',
'max_iterations': 3,
'delay': 0.5,
'required': False,
},
],
}
engine = WorkflowEngine()
result = await engine.execute_workflow(demo_workflow)
return {
'workflow_name': demo_workflow['name'],
'result': result,
}
@app.get('/')
async def root():
"""引擎首页。"""
return {
'name': '智能体工作流编排引擎',
'version': '1.0.0',
'standard': 'GB/Z 185 应用使能层',
'supported_patterns': ['task', 'parallel', 'condition', 'loop'],
'endpoints': {
'execute': 'POST /workflows/execute',
'instances': 'GET /workflows/instances',
'detail': 'GET /workflows/instances/{id}',
'demo': 'POST /workflows/demo',
},
}
# ============================================================
# 入口
# ============================================================
if __name__ == '__main__':
import uvicorn
print('=' * 60)
print('智能体工作流编排引擎')
print('GB/Z 185 应用使能层------工作流编排')
print('服务地址:http://127.0.0.1:8006')
print('统一网关:http://127.0.0.1:8004')
print('支持模式:task / parallel / condition / loop')
print('\n主要接口:')
print(' POST /workflows/execute - 执行工作流')
print(' GET /workflows/instances - 工作流实例列表')
print(' POST /workflows/demo - 运行演示工作流')
print('=' * 60)
uvicorn.run(app, host='127.0.0.1', port=8006)
步骤 3:启动工作流引擎
确保统一网关(8004)和工具服务(8001)正在运行,然后新开窗口:
powershell
python workflow_engine.py
预期输出:
============================================================
智能体工作流编排引擎
GB/Z 185 应用使能层------工作流编排
服务地址:http://127.0.0.1:8006
统一网关:http://127.0.0.1:8004
支持模式:task / parallel / condition / loop
主要接口:
POST /workflows/execute - 执行工作流
GET /workflows/instances - 工作流实例列表
POST /workflows/demo - 运行演示工作流
============================================================
INFO: Uvicorn running on http://127.0.0.1:8006 (Press CTRL+C to quit)
步骤 4:测试工作流引擎
测试 1:运行演示工作流
powershell
curl -X POST http://127.0.0.1:8006/workflows/demo
应返回包含四种编排模式的执行结果,工作流状态为 completed。
测试 2:自定义工作流
powershell
curl -X POST http://127.0.0.1:8006/workflows/execute -H "Content-Type: application/json" -d "{\"workflow\":{\"name\":\"简单测试\",\"steps\":[{\"id\":\"s1\",\"type\":\"task\",\"service\":\"tool\",\"path\":\"tools/list\",\"method\":\"GET\",\"params\":{},\"output_key\":\"tools\"}]}}"
应返回工作流执行结果,context 中包含 tools 变量。
测试 3:查询工作流实例
powershell
curl http://127.0.0.1:8006/workflows/instances
应返回已执行的工作流实例列表。
✅ 验证要点:
- 顺序执行:task 节点按定义顺序依次执行,结果存入上下文
- 并行执行:parallel 节点中的任务并发执行,全部完成后继续
- 条件分支:condition 节点根据表达式评估结果选择 then/else 分支
- 循环重试:loop 节点按 max_iterations 限制循环,满足 until 条件后退出
- 容错处理:服务不可用时标记失败,required=False 的步骤不中断整体流程
④ 任务评价
| 评价维度 | 优秀(9-10分) | 良好(7-8分) | 合格(6分) | 需改进(<6分) |
|---|---|---|---|---|
| 编排模式 | 四种模式全部实现 | 三种模式 | 两种模式 | 仅顺序执行 |
| 上下文管理 | 变量传递+表达式求值 | 变量传递 | 简单存储 | 无上下文 |
| 容错处理 | required 标记+重试+跳过 | 基本容错 | 简单 try-catch | 无容错 |
| 状态追踪 | 实例管理+历史记录+查询 API | 实例管理 | 基本记录 | 无追踪 |
任务 8.2 智慧校园全场景智能体应用
建议学时:4 学时
① 任务情境
工作流引擎有了,现在需要用它构建一个真实的校园应用场景。王主任选定"新生入学日"作为试点------
"新生报到当天,要办的手续多达十几项:查询专业信息、分配宿舍、领取校园卡、选课、加入社团......如果让新生自己跑,一天都办不完。能不能用智能体自动编排这些流程?"
你需要设计并实现一个覆盖完整入学场景的多智能体应用,整合前七个项目的全部能力。
② 知识准备
一、应用使能层架构
渲染错误: Mermaid 渲染失败: Lexical error on line 7. Unrecognized text. ... subgraph 应用使能层(项目八) APP[全场 ---------------------^
二、新生入学场景流程设计
#mermaid-svg-9B9mYKGglo7Nc3Kw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9B9mYKGglo7Nc3Kw .error-icon{fill:#552222;}#mermaid-svg-9B9mYKGglo7Nc3Kw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9B9mYKGglo7Nc3Kw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .marker.cross{stroke:#333333;}#mermaid-svg-9B9mYKGglo7Nc3Kw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9B9mYKGglo7Nc3Kw p{margin:0;}#mermaid-svg-9B9mYKGglo7Nc3Kw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .cluster-label text{fill:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .cluster-label span{color:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .cluster-label span p{background-color:transparent;}#mermaid-svg-9B9mYKGglo7Nc3Kw .label text,#mermaid-svg-9B9mYKGglo7Nc3Kw span{fill:#333;color:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .node rect,#mermaid-svg-9B9mYKGglo7Nc3Kw .node circle,#mermaid-svg-9B9mYKGglo7Nc3Kw .node ellipse,#mermaid-svg-9B9mYKGglo7Nc3Kw .node polygon,#mermaid-svg-9B9mYKGglo7Nc3Kw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .rough-node .label text,#mermaid-svg-9B9mYKGglo7Nc3Kw .node .label text,#mermaid-svg-9B9mYKGglo7Nc3Kw .image-shape .label,#mermaid-svg-9B9mYKGglo7Nc3Kw .icon-shape .label{text-anchor:middle;}#mermaid-svg-9B9mYKGglo7Nc3Kw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .rough-node .label,#mermaid-svg-9B9mYKGglo7Nc3Kw .node .label,#mermaid-svg-9B9mYKGglo7Nc3Kw .image-shape .label,#mermaid-svg-9B9mYKGglo7Nc3Kw .icon-shape .label{text-align:center;}#mermaid-svg-9B9mYKGglo7Nc3Kw .node.clickable{cursor:pointer;}#mermaid-svg-9B9mYKGglo7Nc3Kw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .arrowheadPath{fill:#333333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9B9mYKGglo7Nc3Kw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9B9mYKGglo7Nc3Kw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9B9mYKGglo7Nc3Kw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9B9mYKGglo7Nc3Kw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .cluster text{fill:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw .cluster span{color:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9B9mYKGglo7Nc3Kw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9B9mYKGglo7Nc3Kw rect.text{fill:none;stroke-width:0;}#mermaid-svg-9B9mYKGglo7Nc3Kw .icon-shape,#mermaid-svg-9B9mYKGglo7Nc3Kw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9B9mYKGglo7Nc3Kw .icon-shape p,#mermaid-svg-9B9mYKGglo7Nc3Kw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9B9mYKGglo7Nc3Kw .icon-shape .label rect,#mermaid-svg-9B9mYKGglo7Nc3Kw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9B9mYKGglo7Nc3Kw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9B9mYKGglo7Nc3Kw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9B9mYKGglo7Nc3Kw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 成功
失败
新生发起入学请求
step1: 查询专业信息调用信息查询工具
step2: 并行办理分配宿舍 + 领取校园卡
step3: 条件判断宿舍是否分配成功?
step4: 选课推荐调用课程工具
step4: 通知辅导员手动分配宿舍
step5: 社团推荐调用发现服务
step6: 循环确认等待新生确认社团
入学手续完成
| 步骤 | 编排模式 | 调用服务 | 说明 |
|---|---|---|---|
| step1 | 顺序 | 工具服务 | 查询录取专业信息 |
| step2 | 并行 | 工具服务 ×2 | 同时分配宿舍和领取校园卡 |
| step3 | 条件 | --- | 根据宿舍分配结果分支 |
| step4 | 顺序 | 工具服务 | 根据专业推荐课程 |
| step5 | 顺序 | 发现服务 | 发现并推荐社团智能体 |
| step6 | 循环 | 工具服务 | 等待新生确认加入社团 |
③ 任务实施
步骤 1:编写全场景应用
新建文件 smart_campus_app.py:
python
# smart_campus_app.py
# 智慧校园全场景智能体应用------新生入学日
# 整合项目一至七的全部能力,通过工作流引擎编排完整业务场景
from datetime import datetime
import httpx
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from pydantic import BaseModel
app = FastAPI(
title='智慧校园全场景应用',
description='GB/Z 185 应用使能层------新生入学场景',
version='1.0.0',
)
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_methods=['*'],
allow_headers=['*'],
)
# ============================================================
# 一、服务地址配置
# ============================================================
GATEWAY_URL = 'http://127.0.0.1:8004' # 统一网关
WORKFLOW_URL = 'http://127.0.0.1:8006' # 工作流引擎
# ============================================================
# 二、新生入学工作流定义
# ============================================================
ENROLLMENT_WORKFLOW = {
'name': '新生入学日全流程',
'version': '1.0',
'description': '从专业查询到社团加入的完整入学流程',
'steps': [
# === step1: 顺序------查询专业信息 ===
{
'id': 'step1_major_info',
'type': 'task',
'name': '查询录取专业信息',
'service': 'tool',
'path': 'tools/call',
'method': 'POST',
'params': {
'toolId': 'info_query',
'params': {'student_id': 'STU2026001', 'type': 'major'},
},
'output_key': 'major_info',
'required': True,
},
# === step2: 并行------分配宿舍 + 领取校园卡 ===
{
'id': 'step2_parallel_enrollment',
'type': 'parallel',
'name': '并行办理入学手续',
'tasks': [
{
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {
'toolId': 'dorm_assign',
'params': {'student_id': 'STU2026001', 'gender': 'male'},
},
'output_key': 'dorm_result',
},
{
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {
'toolId': 'card_issue',
'params': {'student_id': 'STU2026001', 'type': 'campus_card'},
},
'output_key': 'card_result',
},
],
'required': False, # 部分失败不中断
},
# === step3: 条件------宿舍分配结果检查 ===
{
'id': 'step3_dorm_check',
'type': 'condition',
'name': '宿舍分配结果检查',
'expression': 'dorm_result.success == true',
'then': {
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {
'toolId': 'email_send',
'params': {
'to': 'student@campus.edu',
'subject': '宿舍分配通知',
'body': '您的宿舍已分配,请查看校园卡信息。',
},
},
'output_key': 'dorm_notify',
},
'else': {
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {
'toolId': 'email_send',
'params': {
'to': 'counselor@campus.edu',
'subject': '宿舍分配异常',
'body': '学生 STU2026001 宿舍分配失败,请手动处理。',
},
},
'output_key': 'dorm_alert',
},
},
# === step4: 顺序------课程推荐 ===
{
'id': 'step4_course_recommend',
'type': 'task',
'name': '课程推荐',
'service': 'tool',
'path': 'tools/call',
'method': 'POST',
'params': {
'toolId': 'course_recommend',
'params': {'student_id': 'STU2026001'},
},
'output_key': 'courses',
'required': False,
},
# === step5: 顺序------社团发现 ===
{
'id': 'step5_club_discovery',
'type': 'task',
'name': '社团智能体发现',
'service': 'discovery',
'path': 'discover/search',
'method': 'GET',
'params': {'keyword': '社团'},
'output_key': 'clubs',
'required': False,
},
# === step6: 循环------等待新生确认 ===
{
'id': 'step6_confirmation',
'type': 'loop',
'name': '等待新生确认',
'task': {
'service': 'tool', 'path': 'tools/call', 'method': 'POST',
'params': {
'toolId': 'status_check',
'params': {'student_id': 'STU2026001'},
},
'output_key': 'confirm_status',
},
'until': 'confirm_status.success == true',
'max_iterations': 3,
'delay': 0.5,
'required': False,
},
],
}
# ============================================================
# 三、应用状态记录
# ============================================================
enrollment_records: list[dict] = []
# ============================================================
# 四、API 接口
# ============================================================
class EnrollmentRequest(BaseModel):
"""新生入学请求。"""
student_id: str = 'STU2026001'
student_name: str = '张三'
@app.post('/enrollment/start')
async def start_enrollment(req: EnrollmentRequest):
"""接口 1:启动新生入学流程。
通过工作流引擎编排完整入学流程,
返回工作流实例 ID 和执行结果。
"""
# 构造工作流请求
workflow_payload = {
'workflow': ENROLLMENT_WORKFLOW,
'instance_id': f'enroll_{req.student_id}_{datetime.now().strftime("%H%M%S")}',
}
try:
async with httpx.AsyncClient(timeout=60.0, trust_env=False) as client:
resp = await client.post(
f'{WORKFLOW_URL}/workflows/execute',
json=workflow_payload,
)
if resp.status_code == 200:
result = resp.json()
# 记录入学流程
record = {
'student_id': req.student_id,
'student_name': req.student_name,
'instance_id': result.get('instance_id', ''),
'status': result.get('status', 'unknown'),
'started_at': datetime.now().isoformat(),
'steps_completed': result.get('completed_steps', 0),
'steps_total': result.get('total_steps', 0),
'context': result.get('context', {}),
}
enrollment_records.append(record)
return {
'message': f'新生 {req.student_name} 入学流程已启动',
'student_id': req.student_id,
'instance_id': result.get('instance_id'),
'status': result.get('status'),
'steps_completed': result.get('completed_steps'),
'steps_total': result.get('total_steps'),
'context_summary': _summarize_context(result.get('context', {})),
}
else:
raise HTTPException(
status_code=502,
detail=f'工作流引擎返回错误:HTTP {resp.status_code}',
)
except httpx.ConnectError:
raise HTTPException(
status_code=503,
detail='工作流引擎未启动(8006),请先启动 workflow_engine.py',
)
def _summarize_context(context: dict) -> dict:
"""汇总上下文关键信息。"""
summary = {}
# 专业信息
if 'major_info' in context:
info = context['major_info']
summary['major'] = info.get('major', '未知') if isinstance(info, dict) else '未知'
# 宿舍
if 'dorm_result' in context:
dorm = context['dorm_result']
summary['dorm_assigned'] = dorm.get('success', False) if isinstance(dorm, dict) else False
summary['dorm_room'] = dorm.get('room', '') if isinstance(dorm, dict) else ''
# 校园卡
if 'card_result' in context:
card = context['card_result']
summary['card_issued'] = card.get('success', False) if isinstance(card, dict) else False
# 社团
if 'clubs' in context:
clubs = context['clubs']
summary['clubs_found'] = clubs.get('total', clubs.get('count', 0)) if isinstance(clubs, dict) else 0
return summary
@app.get('/enrollment/records')
async def list_records():
"""接口 2:查询所有入学流程记录。"""
return {
'count': len(enrollment_records),
'records': enrollment_records,
}
@app.get('/enrollment/records/{student_id}')
async def get_record(student_id: str):
"""接口 3:查询单个学生的入学流程记录。"""
student_records = [r for r in enrollment_records if r['student_id'] == student_id]
if not student_records:
raise HTTPException(status_code=404, detail=f'未找到学生 {student_id} 的记录')
return {'student_id': student_id, 'records': student_records}
@app.get('/enrollment/workflow')
async def get_workflow_definition():
"""接口 4:获取入学工作流定义。"""
return {
'workflow_name': ENROLLMENT_WORKFLOW['name'],
'description': ENROLLMENT_WORKFLOW['description'],
'total_steps': len(ENROLLMENT_WORKFLOW['steps']),
'steps': [
{
'id': s['id'],
'type': s['type'],
'name': s.get('name', ''),
}
for s in ENROLLMENT_WORKFLOW['steps']
],
}
@app.get('/platform/status')
async def platform_status():
"""接口 5:查询平台各服务状态。"""
services_to_check = [
('统一网关', f'{GATEWAY_URL}/health'),
('工作流引擎', f'{WORKFLOW_URL}/'),
]
statuses = []
async with httpx.AsyncClient(timeout=5.0, trust_env=False) as client:
for name, url in services_to_check:
try:
resp = await client.get(url)
statuses.append({
'service': name,
'url': url,
'status': 'online' if resp.status_code == 200 else 'error',
'http_status': resp.status_code,
})
except Exception:
statuses.append({
'service': name,
'url': url,
'status': 'offline',
'http_status': None,
})
return {
'checked_at': datetime.now().isoformat(),
'services': statuses,
'all_online': all(s['status'] == 'online' for s in statuses),
}
# ============================================================
# 五、应用首页(简易看板)
# ============================================================
@app.get('/', response_class=HTMLResponse)
async def index():
"""应用首页。"""
total = len(enrollment_records)
completed = sum(1 for r in enrollment_records if r['status'] == 'completed')
failed = sum(1 for r in enrollment_records if r['status'] == 'failed')
return f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>智慧校园全场景应用</title>
<style>
body {{ font-family: "Microsoft YaHei", sans-serif; background: #f5f5f5; padding: 30px; }}
h1 {{ color: #1565c0; }}
.card {{ background: #fff; border-radius: 8px; padding: 20px; margin: 16px 0;
box-shadow: 0 2px 8px rgba(0,0,0,0.1); }}
.stat {{ display: inline-block; margin-right: 30px; text-align: center; }}
.stat .num {{ font-size: 36px; font-weight: bold; color: #1565c0; }}
.stat .label {{ color: #666; font-size: 14px; }}
.btn {{ display: inline-block; background: #1565c0; color: #fff; padding: 10px 24px;
border-radius: 4px; text-decoration: none; margin: 10px 5px; }}
table {{ width: 100%; border-collapse: collapse; }}
th, td {{ padding: 10px; border: 1px solid #e0e0e0; text-align: left; }}
th {{ background: #1565c0; color: #fff; }}
</style>
</head>
<body>
<h1>智慧校园全场景智能体应用</h1>
<p>GB/Z 185 应用使能层 · 新生入学日场景</p>
<div class="card">
<h2>流程统计</h2>
<div class="stat"><div class="num">{total}</div><div class="label">总流程数</div></div>
<div class="stat"><div class="num" style="color:#2e7d32">{completed}</div><div class="label">已完成</div></div>
<div class="stat"><div class="num" style="color:#c62828">{failed}</div><div class="label">失败</div></div>
</div>
<div class="card">
<h2>快速操作</h2>
<a class="btn" href="/enrollment/workflow">查看工作流定义</a>
<a class="btn" href="/enrollment/records">查看流程记录</a>
<a class="btn" href="/platform/status">平台状态</a>
</div>
<div class="card">
<h2>API 接口</h2>
<table>
<tr><th>接口</th><th>方法</th><th>说明</th></tr>
<tr><td>/enrollment/start</td><td>POST</td><td>启动新生入学流程</td></tr>
<tr><td>/enrollment/records</td><td>GET</td><td>查询所有流程记录</td></tr>
<tr><td>/enrollment/workflow</td><td>GET</td><td>获取工作流定义</td></tr>
<tr><td>/platform/status</td><td>GET</td><td>查询平台服务状态</td></tr>
</table>
</div>
</body>
</html>'''
# ============================================================
# 入口
# ============================================================
if __name__ == '__main__':
import uvicorn
print('=' * 60)
print('智慧校园全场景智能体应用')
print('GB/Z 185 应用使能层------新生入学日场景')
print('服务地址:http://127.0.0.1:8007')
print('工作流引擎:http://127.0.0.1:8006')
print('统一网关:http://127.0.0.1:8004')
print('\n场景说明:')
print(' 新生入学流程包含 6 个步骤:')
print(' step1 查询专业 → step2 并行(宿舍+校园卡)')
print(' → step3 条件(宿舍检查) → step4 课程推荐')
print(' → step5 社团发现 → step6 循环(等待确认)')
print('\n主要接口:')
print(' POST /enrollment/start - 启动入学流程')
print(' GET /enrollment/records - 流程记录')
print(' GET /enrollment/workflow - 工作流定义')
print('=' * 60)
uvicorn.run(app, host='127.0.0.1', port=8007)
步骤 2:启动全场景应用
确保以下服务正在运行:
- 统一网关(8004)
- 工具服务(8001)
- 工作流引擎(8006)
然后新开窗口:
powershell
python smart_campus_app.py
预期输出:
============================================================
智慧校园全场景智能体应用
GB/Z 185 应用使能层------新生入学日场景
服务地址:http://127.0.0.1:8007
工作流引擎:http://127.0.0.1:8006
统一网关:http://127.0.0.1:8004
场景说明:
新生入学流程包含 6 个步骤:
step1 查询专业 → step2 并行(宿舍+校园卡)
→ step3 条件(宿舍检查) → step4 课程推荐
→ step5 社团发现 → step6 循环(等待确认)
主要接口:
POST /enrollment/start - 启动入学流程
GET /enrollment/records - 流程记录
GET /enrollment/workflow - 工作流定义
============================================================
INFO: Uvicorn running on http://127.0.0.1:8007 (Press CTRL+C to quit)
步骤 3:测试全场景应用
测试 1:启动新生入学流程
powershell
curl -X POST http://127.0.0.1:8007/enrollment/start -H "Content-Type: application/json" -d "{\"student_id\":\"STU2026001\",\"student_name\":\"张三\"}"
应返回入学流程启动结果,包含工作流实例 ID、执行状态和上下文摘要。
测试 2:查看工作流定义
powershell
curl http://127.0.0.1:8007/enrollment/workflow
应返回 6 个步骤的定义,涵盖四种编排模式。
测试 3:查询流程记录
powershell
curl http://127.0.0.1:8007/enrollment/records
应返回已执行的入学流程记录列表。
测试 4:访问应用首页
打开浏览器访问 http://127.0.0.1:8007/,可看到应用看板首页,包含流程统计和快速操作入口。
✅ 验证要点:
- 全场景编排:6 个步骤覆盖完整入学流程,使用四种编排模式
- 多服务整合:通过统一网关调用工具服务、发现服务等多个后端
- 上下文传递:step1 的专业信息可被后续步骤引用
- 容错降级:部分步骤失败时(required=False)流程继续执行
- 状态可查:流程记录、工作流定义、平台状态均可通过 API 查询
④ 任务评价
| 评价维度 | 优秀(9-10分) | 良好(7-8分) | 合格(6分) | 需改进(<6分) |
|---|---|---|---|---|
| 场景设计 | 完整入学流程+四种编排 | 多步骤流程 | 简单顺序流程 | 无场景设计 |
| 服务整合 | 整合4+个后端服务 | 整合2-3个服务 | 整合1个服务 | 无整合 |
| 上下文管理 | 完整传递+摘要汇总 | 基本传递 | 简单存储 | 无上下文 |
| 应用界面 | 看板+统计+操作入口 | 有基本页面 | 有API | 无界面 |
任务 8.3 智能体应用创新实战
建议学时:4 学时
① 任务情境
前两个任务展示了工作流引擎和全场景应用的能力。现在,王主任希望把这套能力开放给学生------
"我想开设一个创新工坊,让学生分组设计自己的智能体应用。比如智慧食堂、智能图书馆、校园导览......给他们一个脚手架和评估标准,让他们放手去做。"
你需要构建一个创新工坊系统,提供:
- 项目脚手架:标准化项目模板,快速创建智能体应用
- 示例项目:一个完整的智慧食堂智能体示例
- 评估框架:自动化的项目评估检查工具
- 作品展示:项目展厅页面
② 知识准备
一、创新项目设计方法论
#mermaid-svg-X6cCEyRj4LsvyUmM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-X6cCEyRj4LsvyUmM .error-icon{fill:#552222;}#mermaid-svg-X6cCEyRj4LsvyUmM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-X6cCEyRj4LsvyUmM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-X6cCEyRj4LsvyUmM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-X6cCEyRj4LsvyUmM .marker.cross{stroke:#333333;}#mermaid-svg-X6cCEyRj4LsvyUmM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-X6cCEyRj4LsvyUmM p{margin:0;}#mermaid-svg-X6cCEyRj4LsvyUmM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM .cluster-label text{fill:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM .cluster-label span{color:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM .cluster-label span p{background-color:transparent;}#mermaid-svg-X6cCEyRj4LsvyUmM .label text,#mermaid-svg-X6cCEyRj4LsvyUmM span{fill:#333;color:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM .node rect,#mermaid-svg-X6cCEyRj4LsvyUmM .node circle,#mermaid-svg-X6cCEyRj4LsvyUmM .node ellipse,#mermaid-svg-X6cCEyRj4LsvyUmM .node polygon,#mermaid-svg-X6cCEyRj4LsvyUmM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-X6cCEyRj4LsvyUmM .rough-node .label text,#mermaid-svg-X6cCEyRj4LsvyUmM .node .label text,#mermaid-svg-X6cCEyRj4LsvyUmM .image-shape .label,#mermaid-svg-X6cCEyRj4LsvyUmM .icon-shape .label{text-anchor:middle;}#mermaid-svg-X6cCEyRj4LsvyUmM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-X6cCEyRj4LsvyUmM .rough-node .label,#mermaid-svg-X6cCEyRj4LsvyUmM .node .label,#mermaid-svg-X6cCEyRj4LsvyUmM .image-shape .label,#mermaid-svg-X6cCEyRj4LsvyUmM .icon-shape .label{text-align:center;}#mermaid-svg-X6cCEyRj4LsvyUmM .node.clickable{cursor:pointer;}#mermaid-svg-X6cCEyRj4LsvyUmM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-X6cCEyRj4LsvyUmM .arrowheadPath{fill:#333333;}#mermaid-svg-X6cCEyRj4LsvyUmM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-X6cCEyRj4LsvyUmM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-X6cCEyRj4LsvyUmM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X6cCEyRj4LsvyUmM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-X6cCEyRj4LsvyUmM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X6cCEyRj4LsvyUmM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-X6cCEyRj4LsvyUmM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-X6cCEyRj4LsvyUmM .cluster text{fill:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM .cluster span{color:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-X6cCEyRj4LsvyUmM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-X6cCEyRj4LsvyUmM rect.text{fill:none;stroke-width:0;}#mermaid-svg-X6cCEyRj4LsvyUmM .icon-shape,#mermaid-svg-X6cCEyRj4LsvyUmM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X6cCEyRj4LsvyUmM .icon-shape p,#mermaid-svg-X6cCEyRj4LsvyUmM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-X6cCEyRj4LsvyUmM .icon-shape .label rect,#mermaid-svg-X6cCEyRj4LsvyUmM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X6cCEyRj4LsvyUmM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-X6cCEyRj4LsvyUmM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-X6cCEyRj4LsvyUmM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 循环
1.需求发现发现校园痛点
2.方案设计设计智能体方案
3.原型开发使用脚手架开发
4.测试验证自动化评估
5.展示答辩作品展示与评审
6.迭代优化持续改进
| 阶段 | 关键活动 | 产出物 |
|---|---|---|
| 需求发现 | 调研校园场景,识别痛点 | 需求文档 |
| 方案设计 | 设计智能体架构和工作流 | 设计文档 |
| 原型开发 | 使用脚手架编码实现 | 可运行代码 |
| 测试验证 | 运行评估检查工具 | 评估报告 |
| 展示答辩 | 演示功能、回答提问 | 答辩PPT |
| 迭代优化 | 根据反馈改进 | 优化版本 |
二、项目评估维度
| 评估维度 | 权重 | 检查内容 |
|---|---|---|
| 标准符合性 | 20% | 是否遵循 GB/Z 185 标准、A2A 协议 |
| 功能完整性 | 25% | 核心功能是否实现、流程是否闭环 |
| 技术创新性 | 20% | 编排模式运用、场景创新度 |
| 代码质量 | 15% | 结构清晰、注释完整、可运行 |
| 工程实践 | 10% | 容错处理、可观测性、可部署性 |
| 展示答辩 | 10% | 演示效果、问题回答、文档质量 |
三、创新工坊系统架构
#mermaid-svg-YgiJ8xKFDHwuhbZr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YgiJ8xKFDHwuhbZr .error-icon{fill:#552222;}#mermaid-svg-YgiJ8xKFDHwuhbZr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YgiJ8xKFDHwuhbZr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .marker.cross{stroke:#333333;}#mermaid-svg-YgiJ8xKFDHwuhbZr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YgiJ8xKFDHwuhbZr p{margin:0;}#mermaid-svg-YgiJ8xKFDHwuhbZr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .cluster-label text{fill:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .cluster-label span{color:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .cluster-label span p{background-color:transparent;}#mermaid-svg-YgiJ8xKFDHwuhbZr .label text,#mermaid-svg-YgiJ8xKFDHwuhbZr span{fill:#333;color:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .node rect,#mermaid-svg-YgiJ8xKFDHwuhbZr .node circle,#mermaid-svg-YgiJ8xKFDHwuhbZr .node ellipse,#mermaid-svg-YgiJ8xKFDHwuhbZr .node polygon,#mermaid-svg-YgiJ8xKFDHwuhbZr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .rough-node .label text,#mermaid-svg-YgiJ8xKFDHwuhbZr .node .label text,#mermaid-svg-YgiJ8xKFDHwuhbZr .image-shape .label,#mermaid-svg-YgiJ8xKFDHwuhbZr .icon-shape .label{text-anchor:middle;}#mermaid-svg-YgiJ8xKFDHwuhbZr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .rough-node .label,#mermaid-svg-YgiJ8xKFDHwuhbZr .node .label,#mermaid-svg-YgiJ8xKFDHwuhbZr .image-shape .label,#mermaid-svg-YgiJ8xKFDHwuhbZr .icon-shape .label{text-align:center;}#mermaid-svg-YgiJ8xKFDHwuhbZr .node.clickable{cursor:pointer;}#mermaid-svg-YgiJ8xKFDHwuhbZr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .arrowheadPath{fill:#333333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YgiJ8xKFDHwuhbZr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YgiJ8xKFDHwuhbZr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YgiJ8xKFDHwuhbZr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YgiJ8xKFDHwuhbZr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .cluster text{fill:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr .cluster span{color:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YgiJ8xKFDHwuhbZr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YgiJ8xKFDHwuhbZr rect.text{fill:none;stroke-width:0;}#mermaid-svg-YgiJ8xKFDHwuhbZr .icon-shape,#mermaid-svg-YgiJ8xKFDHwuhbZr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YgiJ8xKFDHwuhbZr .icon-shape p,#mermaid-svg-YgiJ8xKFDHwuhbZr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YgiJ8xKFDHwuhbZr .icon-shape .label rect,#mermaid-svg-YgiJ8xKFDHwuhbZr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YgiJ8xKFDHwuhbZr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YgiJ8xKFDHwuhbZr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YgiJ8xKFDHwuhbZr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创新工坊系统
生成
参考
提交
生成报告
展示
投票
项目脚手架生成项目模板
示例项目智慧食堂
评估引擎自动检查
作品展厅展示页面
学生项目
评估报告
排行榜
③ 任务实施
步骤 1:编写创新工坊系统
新建文件 innovation_workshop.py:
python
# innovation_workshop.py
# 智能体应用创新工坊------脚手架、示例项目、评估引擎、作品展厅
# 对应标准:GB/Z 185 应用使能层------创新实践
from datetime import datetime
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from pydantic import BaseModel
app = FastAPI(
title='智能体应用创新工坊',
description='GB/Z 185 应用使能层------创新实践',
version='1.0.0',
)
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_methods=['*'],
allow_headers=['*'],
)
# ============================================================
# 一、项目脚手架模板
# ============================================================
SCAFFOLD_TEMPLATE = '''# {project_name}
# {project_description}
# 团队:{team_name}
# 创建时间:{created_at}
"""
项目信息:
- 项目名称:{project_name}
- 项目描述:{project_description}
- 团队成员:{team_members}
- 对应标准:GB/Z 185 {standard_part}
- 创新点:{innovation}
使用方法:
1. 启动服务:python {file_name}
2. 访问首页:http://127.0.0.1:{port}/
3. 查看 API 文档:http://127.0.0.1:{port}/docs
"""
from datetime import datetime
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
app = FastAPI(
title='{project_name}',
description='{project_description}',
version='1.0.0',
)
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_methods=['*'],
allow_headers=['*'],
)
# ============================================================
# 一、数据模型(根据项目需求修改)
# ============================================================
# TODO: 定义项目所需的数据结构
# ============================================================
# 二、核心功能接口
# ============================================================
@app.get('/')
async def index():
"""项目首页。"""
return {{
'project': '{project_name}',
'team': '{team_name}',
'version': '1.0.0',
'status': 'running',
}}
# TODO: 添加项目核心功能接口
# ============================================================
# 三、工作流定义(如需编排,参考任务 8.1)
# ============================================================
# TODO: 定义工作流(可选)
# ============================================================
# 入口
# ============================================================
if __name__ == '__main__':
import uvicorn
print('=' * 60)
print('{project_name}')
print('团队:{team_name}')
print(f'服务地址:http://127.0.0.1:{port}')
print('=' * 60)
uvicorn.run(app, host='127.0.0.1', port={port})
'''
# ============================================================
# 二、示例项目------智慧食堂智能体
# ============================================================
CANTEEN_EXAMPLE = {
'project_name': '智慧食堂智能体',
'project_description': '提供食堂菜单查询、营养分析、排队预测、智能点餐功能',
'team_name': '示例团队',
'team_members': '张三、李四、王五',
'standard_part': '全系列应用',
'innovation': '结合排队预测与营养推荐,优化就餐体验',
'port': 8010,
'features': [
{'name': '菜单查询', 'endpoint': '/menu', 'method': 'GET',
'description': '查询当日各食堂菜单'},
{'name': '营养分析', 'endpoint': '/nutrition', 'method': 'GET',
'description': '分析菜品营养成分'},
{'name': '排队预测', 'endpoint': '/queue', 'method': 'GET',
'description': '预测各食堂排队时长'},
{'name': '智能点餐', 'endpoint': '/order', 'method': 'POST',
'description': '根据偏好推荐并下单'},
],
'workflow': {
'name': '智能点餐流程',
'steps': [
{'id': 's1', 'type': 'task', 'name': '查询菜单',
'description': '获取各食堂当日菜单'},
{'id': 's2', 'type': 'parallel', 'name': '并行分析',
'description': '同时进行营养分析和排队预测'},
{'id': 's3', 'type': 'condition', 'name': '推荐决策',
'description': '根据用户偏好和排队情况推荐'},
{'id': 's4', 'type': 'task', 'name': '下单',
'description': '提交订单并返回取餐码'},
],
},
}
# ============================================================
# 三、评估引擎
# ============================================================
class ProjectSubmission(BaseModel):
"""项目提交信息。"""
project_name: str
team_name: str
team_members: str
description: str
standard_part: str = 'GB/Z 185 全系列'
innovation: str = ''
port: int = 8010
has_workflow: bool = False
has_discovery: bool = False
has_tools: bool = False
has_security: bool = False
has_monitoring: bool = False
code_lines: int = 0
has_tests: bool = False
has_docs: bool = False
has_dockerfile: bool = False
# 评估记录
evaluation_records: list[dict] = []
def evaluate_project(submission: ProjectSubmission) -> dict:
"""评估项目提交,生成评估报告。"""
checks = []
total_score = 0
# === 维度1:标准符合性(20分)===
std_score = 0
if submission.standard_part:
checks.append({'item': '标准引用', 'status': 'PASS', 'detail': submission.standard_part})
std_score += 5
if submission.has_discovery:
checks.append({'item': '智能体发现', 'status': 'PASS', 'detail': '集成了发现服务'})
std_score += 5
if submission.has_tools:
checks.append({'item': '工具调用', 'status': 'PASS', 'detail': '集成了工具服务'})
std_score += 5
if submission.has_security:
checks.append({'item': '安全防护', 'status': 'PASS', 'detail': '集成了安全网关'})
std_score += 5
if not submission.has_security:
checks.append({'item': '安全防护', 'status': 'WARN', 'detail': '未集成安全网关'})
total_score += std_score
# === 维度2:功能完整性(25分)===
func_score = 0
if submission.has_workflow:
checks.append({'item': '工作流编排', 'status': 'PASS', 'detail': '使用了工作流引擎'})
func_score += 10
else:
checks.append({'item': '工作流编排', 'status': 'INFO', 'detail': '未使用工作流引擎'})
if submission.code_lines >= 200:
checks.append({'item': '代码规模', 'status': 'PASS', 'detail': f'{submission.code_lines} 行'})
func_score += 8
elif submission.code_lines >= 100:
checks.append({'item': '代码规模', 'status': 'WARN', 'detail': f'{submission.code_lines} 行(建议200+)'})
func_score += 5
else:
checks.append({'item': '代码规模', 'status': 'FAIL', 'detail': f'仅 {submission.code_lines} 行'})
func_score += 2
if submission.innovation:
checks.append({'item': '创新点描述', 'status': 'PASS', 'detail': submission.innovation})
func_score += 7
else:
checks.append({'item': '创新点描述', 'status': 'FAIL', 'detail': '未描述创新点'})
total_score += func_score
# === 维度3:技术创新性(20分)===
inno_score = 0
pattern_count = sum([
submission.has_workflow,
submission.has_discovery,
submission.has_tools,
submission.has_security,
])
if pattern_count >= 3:
checks.append({'item': '技术整合度', 'status': 'PASS',
'detail': f'整合 {pattern_count} 项 IoA 能力'})
inno_score += 15
elif pattern_count >= 2:
checks.append({'item': '技术整合度', 'status': 'WARN',
'detail': f'整合 {pattern_count} 项(建议3+)'})
inno_score += 10
else:
checks.append({'item': '技术整合度', 'status': 'FAIL',
'detail': f'仅整合 {pattern_count} 项'})
inno_score += 5
if submission.innovation and len(submission.innovation) > 20:
inno_score += 5
total_score += inno_score
# === 维度4:代码质量(15分)===
quality_score = 0
if submission.has_docs:
checks.append({'item': 'API 文档', 'status': 'PASS', 'detail': '有文档'})
quality_score += 5
if submission.has_tests:
checks.append({'item': '测试用例', 'status': 'PASS', 'detail': '有测试'})
quality_score += 5
if submission.code_lines >= 100:
quality_score += 5
total_score += quality_score
# === 维度5:工程实践(10分)===
eng_score = 0
if submission.has_dockerfile:
checks.append({'item': '容器化部署', 'status': 'PASS', 'detail': '有 Dockerfile'})
eng_score += 5
if submission.has_monitoring:
checks.append({'item': '监控集成', 'status': 'PASS', 'detail': '集成监控看板'})
eng_score += 5
total_score += eng_score
# === 维度6:展示答辩(10分)------现场评分,此处给基础分===
total_score += 7 # 基础分,答辩时调整
# 确定等级
if total_score >= 90:
grade = 'A(优秀)'
elif total_score >= 80:
grade = 'B(良好)'
elif total_score >= 70:
grade = 'C(合格)'
elif total_score >= 60:
grade = 'D(基本合格)'
else:
grade = 'F(需改进)'
return {
'total_score': total_score,
'grade': grade,
'dimension_scores': {
'标准符合性(20)': std_score,
'功能完整性(25)': func_score,
'技术创新性(20)': inno_score,
'代码质量(15)': quality_score,
'工程实践(10)': eng_score,
'展示答辩(10)': 7,
},
'checks': checks,
'suggestions': _generate_suggestions(checks),
}
def _generate_suggestions(checks: list[dict]) -> list[str]:
"""根据检查结果生成改进建议。"""
suggestions = []
for check in checks:
if check['status'] == 'FAIL':
suggestions.append(f"【建议】{check['item']}:{check['detail']},需要改进")
elif check['status'] == 'WARN':
suggestions.append(f"【提示】{check['item']}:{check['detail']}")
elif check['status'] == 'INFO':
suggestions.append(f"【可选】{check['item']}:{check['detail']}")
if not suggestions:
suggestions.append('项目各方面均达标,继续保持!')
return suggestions
# ============================================================
# 四、API 接口
# ============================================================
class ScaffoldRequest(BaseModel):
"""脚手架生成请求。"""
project_name: str
project_description: str
team_name: str
team_members: str = ''
standard_part: str = 'GB/Z 185 全系列'
innovation: str = ''
port: int = 8010
@app.post('/scaffold/generate')
async def generate_scaffold(req: ScaffoldRequest):
"""接口 1:生成项目脚手架代码。
根据项目信息生成标准化的项目模板代码,
学生在模板基础上开发自己的智能体应用。
"""
file_name = req.project_name.replace(' ', '_').lower() + '.py'
code = SCAFFOLD_TEMPLATE.format(
project_name=req.project_name,
project_description=req.project_description,
team_name=req.team_name,
team_members=req.team_members or '待填写',
standard_part=req.standard_part,
innovation=req.innovation or '待填写',
port=req.port,
file_name=file_name,
created_at=datetime.now().strftime('%Y-%m-%d'),
)
return {
'file_name': file_name,
'port': req.port,
'code': code,
'instructions': [
f'1. 将代码保存为 {file_name}',
f'2. 运行 python {file_name}',
f'3. 访问 http://127.0.0.1:{req.port}/',
f'4. 访问 http://127.0.0.1:{req.port}/docs 查看 API 文档',
'5. 在 TODO 标记处添加项目核心功能',
'6. 开发完成后提交评估:POST /evaluate',
],
}
@app.post('/evaluate')
async def evaluate(submission: ProjectSubmission):
"""接口 2:评估项目提交。
自动检查项目各方面指标,生成评估报告。
"""
report = evaluate_project(submission)
record = {
'project_name': submission.project_name,
'team_name': submission.team_name,
'submitted_at': datetime.now().isoformat(),
'total_score': report['total_score'],
'grade': report['grade'],
'report': report,
}
evaluation_records.append(record)
return record
@app.get('/example/canteen')
async def get_canteen_example():
"""接口 3:获取智慧食堂示例项目信息。"""
return CANTEEN_EXAMPLE
@app.get('/evaluate/records')
async def list_evaluations():
"""接口 4:查询所有评估记录。"""
return {
'count': len(evaluation_records),
'records': sorted(
evaluation_records,
key=lambda r: r['total_score'],
reverse=True,
),
}
@app.get('/evaluate/dimensions')
async def get_dimensions():
"""接口 5:获取评估维度说明。"""
return {
'dimensions': [
{'name': '标准符合性', 'weight': 20,
'description': '是否遵循 GB/Z 185 标准、集成 A2A 协议'},
{'name': '功能完整性', 'weight': 25,
'description': '核心功能是否实现、流程是否闭环'},
{'name': '技术创新性', 'weight': 20,
'description': '编排模式运用、场景创新度'},
{'name': '代码质量', 'weight': 15,
'description': '结构清晰、注释完整、可运行'},
{'name': '工程实践', 'weight': 10,
'description': '容错处理、可观测性、可部署性'},
{'name': '展示答辩', 'weight': 10,
'description': '演示效果、问题回答、文档质量'},
],
'grade_scale': {
'A': '90-100(优秀)',
'B': '80-89(良好)',
'C': '70-79(合格)',
'D': '60-69(基本合格)',
'F': '<60(需改进)',
},
}
# ============================================================
# 五、作品展厅页面
# ============================================================
@app.get('/', response_class=HTMLResponse)
async def showroom():
"""创新工坊作品展厅首页。"""
total = len(evaluation_records)
avg_score = (
sum(r['total_score'] for r in evaluation_records) / total
if total > 0 else 0
)
# 生成排行榜表格
if evaluation_records:
sorted_records = sorted(
evaluation_records,
key=lambda r: r['total_score'],
reverse=True,
)
rows = ''
for i, r in enumerate(sorted_records, 1):
medal = ['🥇', '🥈', '🥉'][i - 1] if i <= 3 else f'{i}'
rows += f'''<tr>
<td style="text-align:center;font-size:18px">{medal}</td>
<td>{r['project_name']}</td>
<td>{r['team_name']}</td>
<td style="text-align:center"><strong>{r['total_score']}</strong></td>
<td style="text-align:center">{r['grade']}</td>
<td>{r['submitted_at'][:10]}</td>
</tr>'''
ranking_table = f'''<table>
<tr><th style="width:50px">排名</th><th>项目</th><th>团队</th>
<th style="width:60px">分数</th><th style="width:100px">等级</th><th>日期</th></tr>
{rows}
</table>'''
else:
ranking_table = '<p style="color:#999;text-align:center">暂无作品,快来做第一个吧!</p>'
return f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>智能体应用创新工坊</title>
<style>
body {{ font-family: "Microsoft YaHei", sans-serif; background: #f5f5f5; padding: 30px; }}
h1 {{ color: #1565c0; }}
.card {{ background: #fff; border-radius: 8px; padding: 20px; margin: 16px 0;
box-shadow: 0 2px 8px rgba(0,0,0,0.1); }}
.stat {{ display: inline-block; margin-right: 30px; text-align: center; }}
.stat .num {{ font-size: 36px; font-weight: bold; color: #1565c0; }}
.stat .label {{ color: #666; font-size: 14px; }}
.btn {{ display: inline-block; background: #1565c0; color: #fff; padding: 10px 24px;
border-radius: 4px; text-decoration: none; margin: 8px 5px; }}
.btn:hover {{ background: #0d47a1; }}
table {{ width: 100%; border-collapse: collapse; }}
th, td {{ padding: 10px; border: 1px solid #e0e0e0; text-align: left; }}
th {{ background: #1565c0; color: #fff; }}
.feature-list {{ display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }}
.feature {{ background: #e3f2fd; padding: 12px; border-radius: 6px; }}
.feature h4 {{ margin: 0 0 4px; color: #1565c0; }}
.feature p {{ margin: 0; color: #555; font-size: 13px; }}
</style>
</head>
<body>
<h1>智能体应用创新工坊</h1>
<p>GB/Z 185 应用使能层 · 创新实践平台</p>
<div class="card">
<h2>工坊统计</h2>
<div class="stat"><div class="num">{total}</div><div class="label">已提交作品</div></div>
<div class="stat"><div class="num">{avg_score:.1f}</div><div class="label">平均分</div></div>
</div>
<div class="card">
<h2>快速开始</h2>
<div class="feature-list">
<div class="feature"><h4>📋 生成脚手架</h4><p>POST /scaffold/generate<br/>创建项目模板代码</p></div>
<div class="feature"><h4>📊 提交评估</h4><p>POST /evaluate<br/>获取自动评估报告</p></div>
<div class="feature"><h4>🍽️ 示例项目</h4><p>GET /example/canteen<br/>查看智慧食堂示例</p></div>
<div class="feature"><h4>📐 评估维度</h4><p>GET /evaluate/dimensions<br/>查看评分标准</p></div>
</div>
</div>
<div class="card">
<h2>🏆 作品排行榜</h2>
{ranking_table}
</div>
<div class="card">
<h2>📝 创新项目设计流程</h2>
<ol>
<li><strong>需求发现</strong>:调研校园场景,识别痛点</li>
<li><strong>方案设计</strong>:设计智能体架构和工作流</li>
<li><strong>原型开发</strong>:使用脚手架(POST /scaffold/generate)创建项目</li>
<li><strong>测试验证</strong>:提交评估(POST /evaluate)获取报告</li>
<li><strong>展示答辩</strong>:演示功能、回答提问</li>
<li><strong>迭代优化</strong>:根据反馈持续改进</li>
</ol>
</div>
</body>
</html>'''
# ============================================================
# 入口
# ============================================================
if __name__ == '__main__':
import uvicorn
print('=' * 60)
print('智能体应用创新工坊')
print('GB/Z 185 应用使能层------创新实践')
print('服务地址:http://127.0.0.1:8008')
print('\n工坊功能:')
print(' POST /scaffold/generate - 生成项目脚手架')
print(' POST /evaluate - 提交项目评估')
print(' GET /example/canteen - 查看示例项目')
print(' GET /evaluate/dimensions - 评估维度说明')
print(' GET /evaluate/records - 评估记录排行')
print('\n评估维度(6项,满分100):')
print(' 标准符合性(20) + 功能完整性(25) + 技术创新性(20)')
print(' + 代码质量(15) + 工程实践(10) + 展示答辩(10)')
print('=' * 60)
uvicorn.run(app, host='127.0.0.1', port=8008)
步骤 2:启动创新工坊
powershell
python innovation_workshop.py
预期输出:
============================================================
智能体应用创新工坊
GB/Z 185 应用使能层------创新实践
服务地址:http://127.0.0.1:8008
工坊功能:
POST /scaffold/generate - 生成项目脚手架
POST /evaluate - 提交项目评估
GET /example/canteen - 查看示例项目
GET /evaluate/dimensions - 评估维度说明
GET /evaluate/records - 评估记录排行
评估维度(6项,满分100):
标准符合性(20) + 功能完整性(25) + 技术创新性(20)
+ 代码质量(15) + 工程实践(10) + 展示答辩(10)
============================================================
INFO: Uvicorn running on http://127.0.0.1:8008 (Press CTRL+C to quit)
步骤 3:测试创新工坊
测试 1:生成项目脚手架
powershell
curl -X POST http://127.0.0.1:8008/scaffold/generate -H "Content-Type: application/json" -d "{\"project_name\":\"智慧图书馆\",\"project_description\":\"智能图书检索与推荐\",\"team_name\":\"第一组\",\"team_members\":\"张三,李四\",\"port\":8020}"
应返回生成的项目模板代码,包含标准化的项目结构和 TODO 标记。
测试 2:提交项目评估
powershell
curl -X POST http://127.0.0.1:8008/evaluate -H "Content-Type: application/json" -d "{\"project_name\":\"智慧食堂\",\"team_name\":\"示例团队\",\"team_members\":\"张三,李四,王五\",\"description\":\"食堂菜单查询与智能点餐\",\"standard_part\":\"GB/Z 185 全系列\",\"innovation\":\"结合排队预测与营养推荐\",\"port\":8010,\"has_workflow\":true,\"has_discovery\":true,\"has_tools\":true,\"has_security\":false,\"has_monitoring\":true,\"code_lines\":350,\"has_tests\":true,\"has_docs\":true,\"has_dockerfile\":false}"
应返回评估报告,包含总分、等级、各维度得分、检查项和改进建议。
测试 3:查看示例项目
powershell
curl http://127.0.0.1:8008/example/canteen
应返回智慧食堂示例项目的完整信息,包含功能列表和工作流定义。
测试 4:访问作品展厅
打开浏览器访问 http://127.0.0.1:8008/,可看到创新工坊展厅首页,包含工坊统计、快速开始入口、作品排行榜和设计流程。
✅ 验证要点:
- 脚手架生成:根据项目信息生成标准化模板代码,包含 TODO 标记
- 自动评估:6 维度评估,生成总分、等级、检查项和改进建议
- 示例参考:智慧食堂示例项目提供完整的功能和工作流设计参考
- 作品展厅:排行榜按分数排序,展示项目名、团队、分数和等级
- 闭环支持:脚手架→开发→评估→展示→迭代,覆盖完整创新流程
④ 任务评价
| 评价维度 | 优秀(9-10分) | 良好(7-8分) | 合格(6分) | 需改进(<6分) |
|---|---|---|---|---|
| 脚手架 | 完整模板+使用说明 | 有模板 | 有基本结构 | 无脚手架 |
| 评估引擎 | 6维度+建议+等级 | 4-5维度 | 2-3维度 | 无评估 |
| 示例项目 | 完整功能+工作流 | 有功能列表 | 有基本信息 | 无示例 |
| 展厅页面 | 排行榜+统计+流程 | 有基本展厅 | 有API | 无界面 |
项目总结与全书展望
项目八知识体系
项目八:智能体互联网应用开发与创新实践
├── 任务 8.1:智能体工作流编排引擎
│ ├── 四种编排模式:顺序(task)、并行(parallel)、条件(condition)、循环(loop)
│ ├── 声明式工作流定义:JSON/dict 描述流程结构
│ ├── 执行上下文:变量传递 + 表达式求值
│ ├── 容错机制:required 标记 + 重试 + 跳过
│ └── 状态追踪:实例管理 + 历史记录 + 查询 API
├── 任务 8.2:智慧校园全场景智能体应用
│ ├── 新生入学场景:6 步骤覆盖完整流程
│ ├── 四种编排模式实战:查询→并行办理→条件检查→循环确认
│ ├── 多服务整合:工具服务 + 发现服务 + 工作流引擎
│ ├── 上下文摘要:自动汇总关键信息
│ └── 应用看板:统计 + 操作入口 + API 列表
└── 任务 8.3:智能体应用创新实战
├── 项目脚手架:标准化模板 + TODO 标记 + 使用说明
├── 示例项目:智慧食堂(功能 + 工作流 + 创新点)
├── 评估引擎:6 维度自动评分 + 等级 + 检查项 + 改进建议
├── 作品展厅:排行榜 + 统计 + 设计流程
└── 创新方法论:需求发现→方案设计→原型开发→测试验证→展示答辩→迭代优化
全书八个项目完整知识体系
| 项目 | 主题 | 对应标准 | 架构层 | 能力层级 | 关键产出 |
|---|---|---|---|---|---|
| 项目一 | 认识智能体互联网 | GB/Z 185.1 | 基础资源层 | L1 认知 | 社团通知助手 |
| 项目二 | 身份码与身份管理 | GB/Z 185.2-3 | 互联层 | L2 安全 | AID 生成器、注册中心 |
| 项目三 | 描述与发现 | GB/Z 185.4-5 | 互联层 | L3 可见 | Agent Card、发现 API |
| 项目四 | 智能体交互 | GB/Z 185.6 | 互联层 | L4 交互 | 状态管理、多轮对话、编排器 |
| 项目五 | 工具调用 | GB/Z 185.7 | 互联层 | L5 增强+L6 整合 | 工具服务、综合助理 |
| 项目六 | 安全与生命周期 | GB/Z 185 全系列 | 协作管理层 | L7 治理 | 安全网关、合规工具、管理平台 |
| 项目七 | 综合平台与运维 | GB/Z 185 全系列 | 协作管理层 | L8 工程化 | 统一网关、监控看板、部署测试 |
| 项目八 | 应用开发与创新 | GB/Z 185 全系列 | 应用使能层 | L9 应用创新 | 工作流引擎、全场景应用、创新工坊 |
GB/Z 185 四层架构完整覆盖
应用使能层 ← 项目八(工作流编排、场景应用、创新实践)
↑
协作管理层 ← 项目六-七(安全治理、统一网关、监控运维、容器部署)
↑
智能体互联层 ← 项目二-五(身份、描述、发现、交互、工具)
↑
基础资源层 ← 项目一(智能体运行时、网络通信、A2A 协议)
能力进阶全路径(完整版)
| 层级 | 能力描述 | 对应项目 |
|---|---|---|
| L1 认知 | 知道 IoA 是什么 | 项目一 |
| L2 安全 | 能给智能体上身份 | 项目二 |
| L3 可见 | 能让智能体被发现 | 项目三 |
| L4 交互 | 能让智能体协作 | 项目四 |
| L5 增强 | 能让智能体调用工具 | 项目五 |
| L6 整合 | 能构建完整 IoA 系统 | 项目五综合实战 |
| L7 治理 | 能管安全、查合规、管生命周期 | 项目六 |
| L8 工程化 | 能统一网关、做监控、容器化部署 | 项目七 |
| L9 应用创新 | 能编排工作流、构建全场景应用、自主创新 | 项目八 |
全书服务端口总览(最终版)
| 服务 | 端口 | 项目 | 说明 |
|---|---|---|---|
| 发现服务 | 8000 | 项目三 | 智能体发现与匹配 |
| 工具服务 | 8001 | 项目五 | 工具列表与工具调用 |
| 安全网关 | 8002 | 项目六 | 身份鉴别与访问控制 |
| 生命周期管理 | 8003 | 项目六 | 注册/锁定/注销管理 |
| 统一网关 | 8004 | 项目七 | 统一入口,服务路由 |
| 监控看板 | 8005 | 项目七 | 监控大屏,可视化 |
| 工作流引擎 | 8006 | 项目八 | 四种编排模式 |
| 全场景应用 | 8007 | 项目八 | 新生入学场景 |
| 创新工坊 | 8008 | 项目八 | 脚手架+评估+展厅 |
| 智能体服务 | 9999 | 项目一/四 | A2A 智能体 |
课后拓展
- (基础) 为工作流引擎增加"子工作流"支持------一个工作流步骤可以嵌套调用另一个完整工作流。
- (进阶) 为全场景应用增加"断点恢复"功能------工作流执行到某步失败后,可从该步重试而非从头开始。
- (实操) 使用创新工坊脚手架,分组开发一个完整的智能体应用(如智慧图书馆、校园导览、智能答疑),并提交评估。
- (探索) 研究 LLM 驱动的智能体(如 ReAct 模式),将大模型推理能力集成到工作流编排引擎中,实现"理解→规划→执行→反思"的智能编排。
全书结语
恭喜你完成了全部八个项目的学习!
从项目一的"认识 IoA",到项目八的"应用开发与创新实践",你已经走完了智能体互联网从认知到创新创造的完整旅程:
- 基础资源层:让智能体运行起来(GB/Z 185.1)→ 项目一
- 身份层:让智能体可信(GB/Z 185.2-3)→ 项目二 + 项目六
- 描述层:让智能体可见(GB/Z 185.4-5)→ 项目三
- 交互层:让智能体协作(GB/Z 185.6)→ 项目四
- 工具层:让智能体强大(GB/Z 185.7)→ 项目五
- 治理层:让智能体安全可控(GB/Z 185 全系列)→ 项目六
- 工程层:让智能体好管好运维(GB/Z 185 全系列)→ 项目七
- 应用层:让智能体服务真实场景、激发创新(GB/Z 185 全系列)→ 项目八
八个项目,九个台阶,从 L1 认知到 L9 应用创新,你已掌握了智能体互联网从标准规范到工程实践再到应用创新的全栈能力。
更重要的是,通过项目八的创新工坊,你不仅学会了"怎么做",更学会了"怎么创"------这才是技术教育的终极目标。
智能体互联网的未来,由你创造!