深入解析 SmartPrintAI:基于 MAF + DeepSeek + MCP 的智能物流打印平台
一、项目概述
SmartPrintAI(Devn.AxiomSmartAI)是一个面向制造业的智能物流打印平台,对接鼎捷 TopGP 5.3 ERP 系统,覆盖 **7 个工厂*的装车单打印全生命周期管理。
核心场景:仓库装车完成后,ERP 过账操作自动触发打印工作流 → 数据提取 → 标签渲染打印 → OA 审批提交 → 结果通知。整个过程由AI Agent 自动编排,支持流式实时反馈(SSE/AG-UI 协议),以及断点续跑(Durable Workflow)。
三大子系统
- PrintAgent— 全自动打印工作流编排
- QueryAgent— 自然语言查询与故障诊断
- PrintTaskStore— 内存任务状态机 + SSE 实时推送
关键指标
- 7 工厂 Oracle 多库直连
- 20 个 MCP 工具(Oracle ×11 / Printer ×5 / OA ×4)
- SSE 流式对话 + 打字机效果
- 防幻觉 — 无效单号代码拦截
二、系统架构全景图
┌──────────────────────────────────────────────────────────────────┐ │ SmartPrintAI 整体架构 │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ ┌─ Vue 3 + Element Plus ──────────────────────────────────┐ │ │ │ Agent 工作台 │ AI 对话面板 │ 任务看板 │ 打印监控 │ │ │ └──────────────────────┬──────────────────────────────────┘ │ │ │ HTTP REST + SSE │ │ ┌──────────────────────▼──────────────────────────────────┐ │ │ │ ASP.NET Core 10 Minimal API │ │ │ │ ┌──────────┬──────────┬──────────┬─────────────────┐ │ │ │ │ │ Agent │ SSE │ Print │ Config │ │ │ │ │ │ Endpoints│ Endpoints│ Task API │ Admin API │ │ │ │ │ └──────────┴──────────┴──────────┴─────────────────┘ │ │ │ └──────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────────────────┐ │ │ │ 服务层 (Services) │ │ │ │ AiPipeline │ PromptBuilder │ SkillLoader │ Memory │ │ │ │ PrintTask │ ChatHistory │ DurableWF │ McpClient │ │ │ └──────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────────────────┐ │ │ │ 3 个 MCP Server(工具协议层) │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Oracle (11T) │ │ Printer (5T) │ │ OA (4T) │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ └─────────┼──────────────────┼──────────────────┼──────────┘ │ │ ┌────▼────┐ ┌─────▼──────┐ ┌────▼────┐ │ │ │ Oracle │ │ ZT410 / │ │ OA │ │ │ │ ERP │ │ TTP-244 │ │ 审批流 │ │ │ └─────────┘ └────────────┘ └─────────┘ │ └──────────────────────────────────────────────────────────────────┘三、技术栈详解
| 层级 | 技术选型 | 说明 |
|---|---|---|
| 前端 | Vue 3 + Element Plus + TypeScript + Pinia | SPA 工作台,SSE 实时流式渲染 |
| 后端 | .NET 10 ASP.NET Core Minimal API | 轻量路由,原生 AOT 就绪 |
| AI 框架 | Microsoft Agent Framework (MAF) v1.6.1 | Agent 编排 + Workflow + Durable |
| 大模型 | DeepSeek V4 Pro (OpenAI 兼容 API) | 中文优化,成本可控 |
| 工具协议 | MCP (Model Context Protocol) v1.3.0 | 标准化工具接入,3 Server 20 Tools |
| 缓存 | IMemoryCache (50MB) + Redis (可选) | 分布式缓存加速 AI 响应 |
| 记忆 | MemoryService (关键词匹配) | 三层知识注入:静态 + 动态 + 实时 |
四、核心工作流:从 ERP 过账到打印完成
整个打印流程由 AI Agent 自动编排,分为 6 个步骤:
- ERP 过账触发— 鼎捷 TopGP 过账后,Oracle 触发器写入
tc_pct_file表 - 数据提取— Agent 调用 Oracle MCP 工具查询订单、出库单、客户信息
- 标签渲染— 根据模板生成 ZPL/EPL 打印指令
- 打印执行— 调用 Printer MCP 工具发送指令到 ZT410 / TTP-244 打印机
- OA 审批— 调用 OA MCP 工具提交审批流
- 结果通知— SSE 推送打印结果到前端,更新任务状态
五、核心代码实现
5.1 Agent 定义与工作流编排
使用 MAF v1.6.1 的ChatAgent和Workflow构建打印 Agent:
// PrintAgent.cs — Agent 定义publicstaticChatAgentCreatePrintAgent(McpClientManagermcp){vartools=mcp.GetAllTools();// 20 个 MCP 工具varagent=newChatAgent("PrintAgent",tools){SystemMessage=""" 你是 SmartPrintAI 打印助手,负责处理装车单打印全流程。 工作流步骤:1.查询 Oracle 获取装车单数据2.检查打印条件是否满足3.调用打印机渲染标签4.提交 OA 审批5.返回打印结果 请严格按照以上步骤执行,每一步完成后确认结果再进入下一步。"""};returnagent;}5.2 SSE 流式响应与打字机效果
后端通过 SSE 协议将 AI 响应实时推送到前端:
// AgentEndpoints.cs — SSE 流式端点app.MapGet("/api/v1/agent/chat/stream",async(HttpContextcontext,stringmessage,string?sessionId)=>{context.Response.ContentType="text/event-stream";context.Response.Headers["Cache-Control"]="no-cache";context.Response.Headers["Connection"]="keep-alive";varwriter=context.Response.BodyWriter;varagent=context.RequestServices.GetRequiredService<ChatAgent>();awaitforeach(varchunkinagent.InvokeStreamingAsync(message)){varjson=JsonSerializer.Serialize(new{content=chunk});awaitwriter.WriteAsync(Encoding.UTF8.GetBytes($"event: message\ndata:{json}\n\n"));awaitwriter.FlushAsync();}awaitwriter.WriteAsync(Encoding.UTF8.GetBytes("event: done\ndata: {}\n\n"));awaitwriter.FlushAsync();});5.3 打印工作流编排
使用 MAF 的Workflow实现多步骤编排:
// PrintWorkflow.cs — 工作流编排publicclassPrintWorkflow{privatereadonlyMcpClientManager_mcp;privatereadonlyPrintTaskStore_store;privatereadonlyDurableWorkflowService_durable;publicasyncTaskExecuteAsync(stringshipmentNo,stringplantCode){varsessionId=Guid.NewGuid().ToString();await_store.CreateAsync(sessionId,shipmentNo);// Step 1: 查询 Oracle 数据await_durable.SaveCheckpointAsync(sessionId,"OracleQuery");varorderData=await_mcp.InvokeOracleQueryAsync(shipmentNo,plantCode);// Step 2: 检查打印条件await_durable.SaveCheckpointAsync(sessionId,"PrintConditionCheck");varcanPrint=await_mcp.InvokePrintConditionCheckAsync(orderData);// Step 3: 渲染并打印标签await_durable.SaveCheckpointAsync(sessionId,"PrintExecutor");varprintResult=await_mcp.InvokePrinterAsync(orderData);// Step 4: 提交 OA 审批await_durable.SaveCheckpointAsync(sessionId,"OASubmit");varoaResult=await_mcp.InvokeOaSubmitAsync(shipmentNo,printResult);// Step 5: 更新任务状态await_store.CompleteAsync(sessionId,oaResult);}}5.4 MCP 工具管理层:20 个工具的注册与调用
McpClientManager负责管理 3 个 MCP Server 的连接生命周期,包含指数退避重试、健康检查和超时控制:
// McpClientManager.cs — Oracle 工具示例privatestaticList<AIFunction>CreateOracleTools()=>new(){CreateTool("oracle_query_oga","查询订单主表(oga)",...),CreateTool("oracle_query_ogb","查询订单明细(ogb)",...),CreateTool("oracle_query_oea","查询出库单(oea)",...),CreateTool("oracle_query_tqm","查询客户信息(tqm)",...),CreateTool("oracle_query_tc_pct","查询提示任务(tc_pct)",...),CreateTool("oracle_insert_tc_pct","插入提示任务",...),CreateTool("oracle_query_print_task","查询打印任务完整信息",...),CreateTool("oracle_check_print_condition","检查打印条件",...),CreateTool("oracle_get_plant_info","获取工厂信息",...),CreateTool("oracle_get_related_plants","获取关联工厂(多角贸易)",...),CreateTool("oracle_cross_plant_query","跨工厂查询",...),};// 连接重试:指数退避,最多 3 次,单次超时 10sprivatestaticasyncTask<McpConnection>ConnectWithRetryAsync(stringname,Func<List<AIFunction>>toolFactory,intmaxRetries=3){for(inti=0;i<maxRetries;i++){try{vartools=toolFactory();varconn=awaitMcpConnection.ConnectStdioAsync(name,tools);returnconn;}catch{awaitTask.Delay(TimeSpan.FromSeconds(Math.Pow(2,i)));}}thrownewInvalidOperationException($"MCP{name}failed after{maxRetries}retries");}5.5 Durable Workflow:文件系统 Checkpoint 断点续跑
当工作流执行到第 3 步 OA 审批时若系统崩溃,重启后可以从最近的 Checkpoint 恢复:
// DurableWorkflowService.cs — Checkpoint 核心publicasyncTaskSaveCheckpointAsync(stringsessionId,stringstepName,object?state){varentry=newCheckpointEntry{SessionId=sessionId,StepName=stepName,StateJson=stateisnull?null:JsonSerializer.Serialize(state),CreatedAt=DateTimeOffset.UtcNow,Version=CheckpointCount+1};varjson=JsonSerializer.Serialize(entry);awaitFile.WriteAllTextAsync($"%LocalAppData%/SmartPrintAI/checkpoints/{sessionId}.json",json);}publicasyncTask<CheckpointEntry?>LoadCheckpointAsync(stringsessionId){varfilePath=Path.Combine(_checkpointDir.FullName,$"{sessionId}.json");if(!File.Exists(filePath))returnnull;returnJsonSerializer.Deserialize<CheckpointEntry>(awaitFile.ReadAllTextAsync(filePath));}5.6 记忆系统:三层知识注入架构
每次 AI 对话前,系统会构建三层上下文注入到 System Prompt:
// AgentEndpoints.cs — BuildSystemContextprivatestaticasyncTask<string>BuildSystemContext(stringmessage,...){varsb=newStringBuilder();// L1: SKILL.md 静态知识varskills=skillLoader.LoadAllSkills();sb.AppendLine(skills);// L2: MemoryService 动态经验varmemories=awaitmemoryService.SearchAsync(message,limit:3);foreach(varmeminmemories)sb.AppendLine($"- [{mem.Category}]{mem.Content}→ 解决:{mem.Solution}");// L3: 实时数据(Oracle + PrintTaskStore)foreach(varcodeincandidates){vartask=awaitstore.GetAsync(code);if(task!=null)sb.AppendLine($"任务{task.TaskId}: 送货单={task.ShipmentNo}状态={task.Status}");}returnsb.ToString();}5.7 前端 Vue 3 SSE 流式消费
前端使用原生EventSource消费 SSE 事件流:
// composables/useAiChat.tsexportfunctionuseAiChat(){constmessages=ref<ChatMessage[]>([]);constisStreaming=ref(false);asyncfunctionsendMessage(text:string,sessionId?:string){consturl=`/api/v1/agent/chat/stream?message=${encodeURIComponent(text)}&sessionId=${sessionId}`;consteventSource=newEventSource(url);eventSource.addEventListener('message',(e)=>{const{content}=JSON.parse(e.data);messages.value[messages.value.length-1].content+=content;});eventSource.addEventListener('agent/tool_call',(e)=>{const{tool,args}=JSON.parse(e.data);// 渲染工具调用指示器});eventSource.addEventListener('agent/tool_result',(e)=>{const{tool,result}=JSON.parse(e.data);// 渲染工具结果});eventSource.addEventListener('done',()=>{eventSource.close();isStreaming.value=false;});}}六、防幻觉机制:从数据源头消除 AI 幻觉
在物流打印场景中,AI 幻觉可能导致错误的打印任务被触发,造成严重的业务事故。我们设计了三层防线:
第一道:单号格式校验
正则提取单号后,立即查询 Oracletc_pct_file表。若查不到数据,直接返回 “未找到”,不让 AI 模型参与回答— 从源头切断幻觉产生。
第二道:数据标记
所有注入 System Prompt 的数据都带有明确标记"=== 查询结果(已核实,数据真实)===",并追加指令"请基于以上真实数据回答"。
第三道:工具调用闭环
Agent 的工具调用结果不经过模型 “理解”,而是以ChatRole.User身份直接注入对话历史,强制模型基于工具返回的原始数据作答。
// 防幻觉核心逻辑// ① 无效单号 → 直接拦截,AI 不参与if(shipmentNo!=null&&queryResultis{Found:false}){awaitwriter.WriteAsync($"未找到单号{shipmentNo}的相关数据。\n请核实单号是否正确。");return;}// ② 历史对话中剔除旧工具调用标记varcleanContent=Regex.Replace(h.Content,@"\[调用工具:\s*\w+\]\n?","");// ③ 工具结果注入为 User 消息chatMessages.Add(new(ChatRole.User,$"以下是系统查询到的真实数据,请直接回答用户:\n{string.Join("\n---\n",toolResults)}"));七、项目结构与依赖关系
Devn.AxiomSmartAI.slnx ├── src/ │ ├── Devn.AxiomSmartAI.Backend/ ← ASP.NET Core 10 主程序 │ │ ├── Agents/ AgentDefinitions, PrintWorkflow, WorkflowCallbacks │ │ ├── Endpoints/ AgentEndpoints, SseEndpoints, ConfigAdminEndpoints │ │ ├── Services/ AiPipelineSetup, PromptBuilder, SkillLoader, │ │ │ MemoryService, DurableWorkflowService, │ │ │ McpClientManager, PrintTaskQueryTools, │ │ │ PrintTaskStore, ChatHistoryStore, ResiliencePipeline │ │ └── Config/ AgentSettings, McpServerSettings, SpeechSettings │ │ │ ├── Devn.AxiomSmartAI.Shared/ ← 共享 DTO / 模型 │ │ │ └── Devn.AxiomSmartAI.McpServers/ ← 3 个 MCP 工具服务器 │ ├── McpOracleServer/ 11 tools: oga, ogb, oea, tqm, tc_pct, ... │ ├── McpPrinterServer/ 5 tools: print, status, list, cancel, defau