欢迎光临
我们一直在努力

Harness Engineering:构建企业级Agent的7大工程化设计准则

Harness Engineering:构建企业级AI工作流的7大工程化设计准则

为什么需要Harness Engineering?

过去两年,AI Agent从实验室走进生产环境,几乎每个有规模的企业都在尝试用大模型驱动的工作流替代传统的规则引擎或人工流程。但一个普遍的现象是:POC(概念验证)跑得飞快,一到生产就处处卡壳。

卡在哪里?不是模型不够强,不是框架不够好,而是缺少一套工程化的治理体系。

我们称这套体系为 Harness Engineering —— 它不是一个具体的工具或平台,而是一组设计准则和基础设施,让你的AI工作流具备:

  • 可治理的工具生态
  • 可观测的运行状态
  • 可恢复的持久化能力
  • 可控的人机协作边界

今天,大多数企业选择用 LangGraph、AutoGen 或 Dify 来搭建工作流,但无论底层框架是什么,Harness Engineering 都是决定系统能否长期稳定运行的关键。

下面,我将围绕 7 个核心设计要点,逐一拆解如何构建一套完整的 Harness Engineering 体系。我们用一张总览图先建立起全局认知:

#mermaid-svg-Ae7HOa9lZ89VcWc0{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-Ae7HOa9lZ89VcWc0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .error-icon{fill:#552222;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .marker.cross{stroke:#333333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 p{margin:0;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .cluster-label text{fill:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .cluster-label span{color:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .cluster-label span p{background-color:transparent;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .label text,#mermaid-svg-Ae7HOa9lZ89VcWc0 span{fill:#333;color:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .node rect,#mermaid-svg-Ae7HOa9lZ89VcWc0 .node circle,#mermaid-svg-Ae7HOa9lZ89VcWc0 .node ellipse,#mermaid-svg-Ae7HOa9lZ89VcWc0 .node polygon,#mermaid-svg-Ae7HOa9lZ89VcWc0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .rough-node .label text,#mermaid-svg-Ae7HOa9lZ89VcWc0 .node .label text,#mermaid-svg-Ae7HOa9lZ89VcWc0 .image-shape .label,#mermaid-svg-Ae7HOa9lZ89VcWc0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .rough-node .label,#mermaid-svg-Ae7HOa9lZ89VcWc0 .node .label,#mermaid-svg-Ae7HOa9lZ89VcWc0 .image-shape .label,#mermaid-svg-Ae7HOa9lZ89VcWc0 .icon-shape .label{text-align:center;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .node.clickable{cursor:pointer;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .arrowheadPath{fill:#333333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ae7HOa9lZ89VcWc0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ae7HOa9lZ89VcWc0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ae7HOa9lZ89VcWc0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .cluster text{fill:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .cluster span{color:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 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-Ae7HOa9lZ89VcWc0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ae7HOa9lZ89VcWc0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .icon-shape,#mermaid-svg-Ae7HOa9lZ89VcWc0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .icon-shape p,#mermaid-svg-Ae7HOa9lZ89VcWc0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .icon-shape .label rect,#mermaid-svg-Ae7HOa9lZ89VcWc0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ae7HOa9lZ89VcWc0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ae7HOa9lZ89VcWc0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ae7HOa9lZ89VcWc0 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

工具层

执行层

Harness核心治理层

用户层

审批通过

业务请求

工作流编排引擎

Tool Registry工具注册与治理

State Store状态持久化

可观测双引擎Langfuse + Sentry

Human-in-the-Loop人工审批网关

Worker 1

Worker 2

Worker N

企业工具集群API/数据库/第三方服务

接下来逐一展开。

一、Loop —— 让工作流具备“自我迭代”的能力

为什么需要 Loop?

传统的工作流(如 ETL 管道)是 DAG(有向无环图),一条路走到底。但 AI 工作流的典型特征是需要多轮推理——模型生成一个计划 → 执行 → 观察结果 → 调整计划 → 再执行……直到满足终止条件。

如果没有 Loop 能力,你只能用一个巨大的 Prompt 让模型一次性输出所有步骤,结果往往是“计划很丰满,执行很骨感”。

通用设计

Harness 中的 Loop 是一个有条件的循环结构,包含三个核心组件:

  • 执行节点:完成一个原子操作(调用模型、执行工具、等待外部信号)
  • 判断节点:评估当前状态,决定是继续循环、退出还是跳转
  • 状态累积器:每次循环更新全局上下文,确保信息不丢失
  • #mermaid-svg-eH7P6JTT8L8EaUVE{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-eH7P6JTT8L8EaUVE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eH7P6JTT8L8EaUVE .error-icon{fill:#552222;}#mermaid-svg-eH7P6JTT8L8EaUVE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eH7P6JTT8L8EaUVE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eH7P6JTT8L8EaUVE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eH7P6JTT8L8EaUVE .marker.cross{stroke:#333333;}#mermaid-svg-eH7P6JTT8L8EaUVE svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eH7P6JTT8L8EaUVE p{margin:0;}#mermaid-svg-eH7P6JTT8L8EaUVE .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE .cluster-label text{fill:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE .cluster-label span{color:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE .cluster-label span p{background-color:transparent;}#mermaid-svg-eH7P6JTT8L8EaUVE .label text,#mermaid-svg-eH7P6JTT8L8EaUVE span{fill:#333;color:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE .node rect,#mermaid-svg-eH7P6JTT8L8EaUVE .node circle,#mermaid-svg-eH7P6JTT8L8EaUVE .node ellipse,#mermaid-svg-eH7P6JTT8L8EaUVE .node polygon,#mermaid-svg-eH7P6JTT8L8EaUVE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eH7P6JTT8L8EaUVE .rough-node .label text,#mermaid-svg-eH7P6JTT8L8EaUVE .node .label text,#mermaid-svg-eH7P6JTT8L8EaUVE .image-shape .label,#mermaid-svg-eH7P6JTT8L8EaUVE .icon-shape .label{text-anchor:middle;}#mermaid-svg-eH7P6JTT8L8EaUVE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eH7P6JTT8L8EaUVE .rough-node .label,#mermaid-svg-eH7P6JTT8L8EaUVE .node .label,#mermaid-svg-eH7P6JTT8L8EaUVE .image-shape .label,#mermaid-svg-eH7P6JTT8L8EaUVE .icon-shape .label{text-align:center;}#mermaid-svg-eH7P6JTT8L8EaUVE .node.clickable{cursor:pointer;}#mermaid-svg-eH7P6JTT8L8EaUVE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eH7P6JTT8L8EaUVE .arrowheadPath{fill:#333333;}#mermaid-svg-eH7P6JTT8L8EaUVE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eH7P6JTT8L8EaUVE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eH7P6JTT8L8EaUVE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eH7P6JTT8L8EaUVE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eH7P6JTT8L8EaUVE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eH7P6JTT8L8EaUVE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eH7P6JTT8L8EaUVE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eH7P6JTT8L8EaUVE .cluster text{fill:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE .cluster span{color:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE 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-eH7P6JTT8L8EaUVE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eH7P6JTT8L8EaUVE rect.text{fill:none;stroke-width:0;}#mermaid-svg-eH7P6JTT8L8EaUVE .icon-shape,#mermaid-svg-eH7P6JTT8L8EaUVE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eH7P6JTT8L8EaUVE .icon-shape p,#mermaid-svg-eH7P6JTT8L8EaUVE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eH7P6JTT8L8EaUVE .icon-shape .label rect,#mermaid-svg-eH7P6JTT8L8EaUVE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eH7P6JTT8L8EaUVE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eH7P6JTT8L8EaUVE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eH7P6JTT8L8EaUVE :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    满足退出条件

    需要继续

    需要人工介入

    开始

    执行节点

    判断节点

    结束

    更新状态

    跳转至HIL

    工程实践要点

    • 设置最大迭代次数:必须硬性限制,防止死循环耗尽资源(建议 10~20 轮)
    • 记录每一次循环的输入输出:方便事后审计和调试
    • 循环内的每一步都要可观测:每个循环的耗时、成功/失败状态都需上报监控

    底层框架(如 LangGraph)天然支持循环边,但设计上你应把它视为 Harness 提供的基础能力,而非依赖特定框架。

    二、Tool Registry —— 让工具“可注册、可治理、可发现”

    为什么需要 Tool Registry?

    企业内的工具数量增长极快——数据库查询、邮件服务、CRM 操作、支付接口、内部知识库……一个中等规模的 Agent 系统可能涉及 50+ 个工具。如果不加治理,会出现:

    • 命名冲突:两个团队各自定义了 send_notification
    • 权限模糊:任何 Agent 都能调用删除数据的工具
    • 发现困难:新来的开发者不知道有哪些工具可用,只能翻代码

    Tool Registry 就是工具的“服务目录”,让所有工具在一个中心化的地方注册、分类、带元数据管理。

    通用设计

    一个完善的 Tool Registry 应包含以下元数据:

    字段说明示例
    name 全局唯一标识 order_query
    description 人类可读的描述 “根据订单号查询订单详情”
    risk_level 风险等级 read / write / delete
    owner 所属团队或负责人 order-team
    tags 分类标签 ["订单", "只读"]
    schema 输入输出参数定义 JSON Schema
    rate_limit 调用频率限制 100/min
    deprecated 是否已废弃 false

    #mermaid-svg-Wu4mxcK0W3TMSVJG{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-Wu4mxcK0W3TMSVJG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Wu4mxcK0W3TMSVJG .error-icon{fill:#552222;}#mermaid-svg-Wu4mxcK0W3TMSVJG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Wu4mxcK0W3TMSVJG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .marker.cross{stroke:#333333;}#mermaid-svg-Wu4mxcK0W3TMSVJG svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Wu4mxcK0W3TMSVJG p{margin:0;}#mermaid-svg-Wu4mxcK0W3TMSVJG .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .cluster-label text{fill:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .cluster-label span{color:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .cluster-label span p{background-color:transparent;}#mermaid-svg-Wu4mxcK0W3TMSVJG .label text,#mermaid-svg-Wu4mxcK0W3TMSVJG span{fill:#333;color:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .node rect,#mermaid-svg-Wu4mxcK0W3TMSVJG .node circle,#mermaid-svg-Wu4mxcK0W3TMSVJG .node ellipse,#mermaid-svg-Wu4mxcK0W3TMSVJG .node polygon,#mermaid-svg-Wu4mxcK0W3TMSVJG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .rough-node .label text,#mermaid-svg-Wu4mxcK0W3TMSVJG .node .label text,#mermaid-svg-Wu4mxcK0W3TMSVJG .image-shape .label,#mermaid-svg-Wu4mxcK0W3TMSVJG .icon-shape .label{text-anchor:middle;}#mermaid-svg-Wu4mxcK0W3TMSVJG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .rough-node .label,#mermaid-svg-Wu4mxcK0W3TMSVJG .node .label,#mermaid-svg-Wu4mxcK0W3TMSVJG .image-shape .label,#mermaid-svg-Wu4mxcK0W3TMSVJG .icon-shape .label{text-align:center;}#mermaid-svg-Wu4mxcK0W3TMSVJG .node.clickable{cursor:pointer;}#mermaid-svg-Wu4mxcK0W3TMSVJG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .arrowheadPath{fill:#333333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Wu4mxcK0W3TMSVJG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Wu4mxcK0W3TMSVJG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Wu4mxcK0W3TMSVJG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Wu4mxcK0W3TMSVJG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .cluster text{fill:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG .cluster span{color:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG 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-Wu4mxcK0W3TMSVJG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Wu4mxcK0W3TMSVJG rect.text{fill:none;stroke-width:0;}#mermaid-svg-Wu4mxcK0W3TMSVJG .icon-shape,#mermaid-svg-Wu4mxcK0W3TMSVJG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Wu4mxcK0W3TMSVJG .icon-shape p,#mermaid-svg-Wu4mxcK0W3TMSVJG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Wu4mxcK0W3TMSVJG .icon-shape .label rect,#mermaid-svg-Wu4mxcK0W3TMSVJG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Wu4mxcK0W3TMSVJG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Wu4mxcK0W3TMSVJG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Wu4mxcK0W3TMSVJG :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Registry

    可调用

    可调用

    可调用

    可调用

    可调用

    订单查询只读

    发送邮件写入

    删除用户高危

    客服Agent风险等级: write

    运维Agent风险等级: delete

    工程实践要点

    • 风险分级:只读、写入、删除三级,不同 Agent 根据其角色只能看到符合风险等级的工具
    • 动态过滤:在工作流运行时,根据上下文动态决定暴露哪些工具(例如:未登录用户不显示内部工具)
    • 版本管理:工具可能有多个版本,Registry 需支持版本路由和灰度
    • 延迟加载:工具的完整 Schema 可以在真正调用时才加载,避免启动时全量加载造成压力

    三、可观测性 —— Sentry 管系统健康,Langfuse 管AI质量

    为什么需要双引擎?

    AI 工作流比传统微服务更难调试,因为它有两层不确定性:

  • 系统层:工具调用超时、内存溢出、网络抖动(传统问题)
  • AI 层:模型输出不合预期、Token 消耗异常、Prompt 效果退化(新问题)
  • 单一工具无法同时覆盖这两层。我们的方案是 Sentry + Langfuse 双引擎,各司其职。

    通用设计

    维度SentryLangfuse
    监控对象 系统级性能、异常、错误 LLM 调用链、质量、成本
    典型场景 工具调用超时、Worker 崩溃、内存泄露 模型输出评分、Token 计数、Prompt 版本对比
    告警方式 实时错误告警、性能阈值 质量下降告警、成本超预算
    数据分析 错误聚合、性能瓶颈定位 Trace 回放、人工评分、A/B 测试

    #mermaid-svg-3Ur2Pk9v3U49rFef{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-3Ur2Pk9v3U49rFef .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3Ur2Pk9v3U49rFef .error-icon{fill:#552222;}#mermaid-svg-3Ur2Pk9v3U49rFef .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3Ur2Pk9v3U49rFef .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3Ur2Pk9v3U49rFef .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3Ur2Pk9v3U49rFef .marker.cross{stroke:#333333;}#mermaid-svg-3Ur2Pk9v3U49rFef svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3Ur2Pk9v3U49rFef p{margin:0;}#mermaid-svg-3Ur2Pk9v3U49rFef .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef .cluster-label text{fill:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef .cluster-label span{color:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef .cluster-label span p{background-color:transparent;}#mermaid-svg-3Ur2Pk9v3U49rFef .label text,#mermaid-svg-3Ur2Pk9v3U49rFef span{fill:#333;color:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef .node rect,#mermaid-svg-3Ur2Pk9v3U49rFef .node circle,#mermaid-svg-3Ur2Pk9v3U49rFef .node ellipse,#mermaid-svg-3Ur2Pk9v3U49rFef .node polygon,#mermaid-svg-3Ur2Pk9v3U49rFef .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3Ur2Pk9v3U49rFef .rough-node .label text,#mermaid-svg-3Ur2Pk9v3U49rFef .node .label text,#mermaid-svg-3Ur2Pk9v3U49rFef .image-shape .label,#mermaid-svg-3Ur2Pk9v3U49rFef .icon-shape .label{text-anchor:middle;}#mermaid-svg-3Ur2Pk9v3U49rFef .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3Ur2Pk9v3U49rFef .rough-node .label,#mermaid-svg-3Ur2Pk9v3U49rFef .node .label,#mermaid-svg-3Ur2Pk9v3U49rFef .image-shape .label,#mermaid-svg-3Ur2Pk9v3U49rFef .icon-shape .label{text-align:center;}#mermaid-svg-3Ur2Pk9v3U49rFef .node.clickable{cursor:pointer;}#mermaid-svg-3Ur2Pk9v3U49rFef .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3Ur2Pk9v3U49rFef .arrowheadPath{fill:#333333;}#mermaid-svg-3Ur2Pk9v3U49rFef .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3Ur2Pk9v3U49rFef .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3Ur2Pk9v3U49rFef .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3Ur2Pk9v3U49rFef .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3Ur2Pk9v3U49rFef .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3Ur2Pk9v3U49rFef .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3Ur2Pk9v3U49rFef .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3Ur2Pk9v3U49rFef .cluster text{fill:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef .cluster span{color:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef 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-3Ur2Pk9v3U49rFef .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3Ur2Pk9v3U49rFef rect.text{fill:none;stroke-width:0;}#mermaid-svg-3Ur2Pk9v3U49rFef .icon-shape,#mermaid-svg-3Ur2Pk9v3U49rFef .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3Ur2Pk9v3U49rFef .icon-shape p,#mermaid-svg-3Ur2Pk9v3U49rFef .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3Ur2Pk9v3U49rFef .icon-shape .label rect,#mermaid-svg-3Ur2Pk9v3U49rFef .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3Ur2Pk9v3U49rFef .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3Ur2Pk9v3U49rFef .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3Ur2Pk9v3U49rFef :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    工作流执行

    步骤1

    步骤2

    步骤3

    LangfuseLLM调用链

    Sentry系统异常

    质量看板评分/Trace

    健康看板错误率/延迟

    工程实践要点

    • 统一 Trace ID:确保 Sentry 和 Langfuse 使用相同的请求 ID,方便跨系统关联
    • 分级采样:生产环境可采用“全量错误 + 部分成功”的采样策略,控制成本
    • Prompt 版本管理:在 Langfuse 中维护 Prompt 模板,便于快速回滚和 A/B 测试
    • 自定义业务指标:除了技术指标,还应上报“任务完成率”、“用户满意度”等业务指标

    四、多智能体编排 —— 主Agent调度 + SubAgent执行

    为什么需要多智能体?

    单一 Agent 负责所有事情,会遭遇“上下文过载”和“工具选择困难”。企业级系统必须分而治之——一个协调者负责拆解任务,多个执行者各自负责一个领域。

    通用设计

    最成熟的多智能体模式是 主-从模式(Master-Sub):

    • 主 Agent(Master):负责任务理解、拆解、路由、结果整合,不直接操作具体工具
    • 子 Agent(SubAgent):每个专注一个业务领域,拥有该领域专属的工具集和知识库

    #mermaid-svg-D2BkStVaLnmUumXi{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-D2BkStVaLnmUumXi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-D2BkStVaLnmUumXi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-D2BkStVaLnmUumXi .error-icon{fill:#552222;}#mermaid-svg-D2BkStVaLnmUumXi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D2BkStVaLnmUumXi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-D2BkStVaLnmUumXi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D2BkStVaLnmUumXi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D2BkStVaLnmUumXi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-D2BkStVaLnmUumXi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D2BkStVaLnmUumXi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D2BkStVaLnmUumXi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D2BkStVaLnmUumXi .marker.cross{stroke:#333333;}#mermaid-svg-D2BkStVaLnmUumXi svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D2BkStVaLnmUumXi p{margin:0;}#mermaid-svg-D2BkStVaLnmUumXi .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-D2BkStVaLnmUumXi .cluster-label text{fill:#333;}#mermaid-svg-D2BkStVaLnmUumXi .cluster-label span{color:#333;}#mermaid-svg-D2BkStVaLnmUumXi .cluster-label span p{background-color:transparent;}#mermaid-svg-D2BkStVaLnmUumXi .label text,#mermaid-svg-D2BkStVaLnmUumXi span{fill:#333;color:#333;}#mermaid-svg-D2BkStVaLnmUumXi .node rect,#mermaid-svg-D2BkStVaLnmUumXi .node circle,#mermaid-svg-D2BkStVaLnmUumXi .node ellipse,#mermaid-svg-D2BkStVaLnmUumXi .node polygon,#mermaid-svg-D2BkStVaLnmUumXi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D2BkStVaLnmUumXi .rough-node .label text,#mermaid-svg-D2BkStVaLnmUumXi .node .label text,#mermaid-svg-D2BkStVaLnmUumXi .image-shape .label,#mermaid-svg-D2BkStVaLnmUumXi .icon-shape .label{text-anchor:middle;}#mermaid-svg-D2BkStVaLnmUumXi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-D2BkStVaLnmUumXi .rough-node .label,#mermaid-svg-D2BkStVaLnmUumXi .node .label,#mermaid-svg-D2BkStVaLnmUumXi .image-shape .label,#mermaid-svg-D2BkStVaLnmUumXi .icon-shape .label{text-align:center;}#mermaid-svg-D2BkStVaLnmUumXi .node.clickable{cursor:pointer;}#mermaid-svg-D2BkStVaLnmUumXi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-D2BkStVaLnmUumXi .arrowheadPath{fill:#333333;}#mermaid-svg-D2BkStVaLnmUumXi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D2BkStVaLnmUumXi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D2BkStVaLnmUumXi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D2BkStVaLnmUumXi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-D2BkStVaLnmUumXi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D2BkStVaLnmUumXi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-D2BkStVaLnmUumXi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D2BkStVaLnmUumXi .cluster text{fill:#333;}#mermaid-svg-D2BkStVaLnmUumXi .cluster span{color:#333;}#mermaid-svg-D2BkStVaLnmUumXi 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-D2BkStVaLnmUumXi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-D2BkStVaLnmUumXi rect.text{fill:none;stroke-width:0;}#mermaid-svg-D2BkStVaLnmUumXi .icon-shape,#mermaid-svg-D2BkStVaLnmUumXi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D2BkStVaLnmUumXi .icon-shape p,#mermaid-svg-D2BkStVaLnmUumXi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-D2BkStVaLnmUumXi .icon-shape .label rect,#mermaid-svg-D2BkStVaLnmUumXi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D2BkStVaLnmUumXi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-D2BkStVaLnmUumXi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-D2BkStVaLnmUumXi :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    技术问题

    业务问题

    售后问题

    用户请求

    主Agent意图识别 & 任务拆解

    SubAgent-技术

    SubAgent-业务

    SubAgent-售后

    技术工具集代码库/知识库

    业务工具集CRM/订单API

    售后工具集工单/邮件

    工程实践要点

    • 主Agent不持有工具:它的任务只是“路由”,工具全部下沉到 SubAgent
    • SubAgent独立部署:每个 SubAgent 可作为独立服务,由不同团队维护,独立升级
    • 通信规范:主-子之间通过标准化消息协议(如 JSON-RPC)通信,不依赖特定框架
    • 结果聚合策略:主Agent收到各 SubAgent 返回后,需要做“冲突解决”和“摘要生成”

    五、Human-in-the-Loop —— 在关键节点“踩刹车”

    为什么需要 HIL?

    AI 再强,也不能完全信任。涉及资金、隐私、权限变更的操作,必须由人类最后拍板。HIL 不是“可选增强”,而是合规和风控的刚性要求。

    通用设计

    HIL 本质上是一个中断-审批-恢复的机制:

  • 拦截点:工作流执行到需要审批的步骤时,自动暂停
  • 通知与呈现:将工具调用信息、上下文、风险提示推送给审批人
  • 审批决策:审批人可选择批准、修改参数、拒绝或直接回复
  • 恢复执行:根据审批结果继续、跳过或终止流程
  • #mermaid-svg-eIWXeWMfrZSLCaYJ{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-eIWXeWMfrZSLCaYJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eIWXeWMfrZSLCaYJ .error-icon{fill:#552222;}#mermaid-svg-eIWXeWMfrZSLCaYJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eIWXeWMfrZSLCaYJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .marker.cross{stroke:#333333;}#mermaid-svg-eIWXeWMfrZSLCaYJ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eIWXeWMfrZSLCaYJ p{margin:0;}#mermaid-svg-eIWXeWMfrZSLCaYJ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .cluster-label text{fill:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .cluster-label span{color:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .cluster-label span p{background-color:transparent;}#mermaid-svg-eIWXeWMfrZSLCaYJ .label text,#mermaid-svg-eIWXeWMfrZSLCaYJ span{fill:#333;color:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .node rect,#mermaid-svg-eIWXeWMfrZSLCaYJ .node circle,#mermaid-svg-eIWXeWMfrZSLCaYJ .node ellipse,#mermaid-svg-eIWXeWMfrZSLCaYJ .node polygon,#mermaid-svg-eIWXeWMfrZSLCaYJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .rough-node .label text,#mermaid-svg-eIWXeWMfrZSLCaYJ .node .label text,#mermaid-svg-eIWXeWMfrZSLCaYJ .image-shape .label,#mermaid-svg-eIWXeWMfrZSLCaYJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-eIWXeWMfrZSLCaYJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .rough-node .label,#mermaid-svg-eIWXeWMfrZSLCaYJ .node .label,#mermaid-svg-eIWXeWMfrZSLCaYJ .image-shape .label,#mermaid-svg-eIWXeWMfrZSLCaYJ .icon-shape .label{text-align:center;}#mermaid-svg-eIWXeWMfrZSLCaYJ .node.clickable{cursor:pointer;}#mermaid-svg-eIWXeWMfrZSLCaYJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .arrowheadPath{fill:#333333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eIWXeWMfrZSLCaYJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eIWXeWMfrZSLCaYJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eIWXeWMfrZSLCaYJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eIWXeWMfrZSLCaYJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .cluster text{fill:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ .cluster span{color:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ 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-eIWXeWMfrZSLCaYJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eIWXeWMfrZSLCaYJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-eIWXeWMfrZSLCaYJ .icon-shape,#mermaid-svg-eIWXeWMfrZSLCaYJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eIWXeWMfrZSLCaYJ .icon-shape p,#mermaid-svg-eIWXeWMfrZSLCaYJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eIWXeWMfrZSLCaYJ .icon-shape .label rect,#mermaid-svg-eIWXeWMfrZSLCaYJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eIWXeWMfrZSLCaYJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eIWXeWMfrZSLCaYJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eIWXeWMfrZSLCaYJ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    批准

    修改参数

    拒绝

    人工回复

    工作流执行

    是否需要审批

    正常执行

    通知审批人

    审批人决策

    更新参数后执行

    终止并反馈

    用人工回答替换

    工程实践要点

    • 审批超时机制:设置超时阈值(如 24 小时),超时后自动拒绝或升级给备选审批人
    • 审批历史归档:所有审批记录必须持久化,满足审计要求
    • 审批人动态绑定:根据业务内容(如金额大小、地域)动态分配审批人
    • 灰度策略:先对低风险操作启用 HIL,逐步扩大范围

    六、上下文管理 —— 让工作流“记住”自己做过什么

    为什么需要上下文管理?

    AI 工作流通常不是一次性结束,而是多轮交互。用户可能问了 5 个问题,每个问题都依赖前面的对话历史。上下文管理就是要跨轮次、跨节点地保持状态一致性。

    通用设计

    上下文管理分为三个层次:

    层次存储位置生命周期典型用途
    短期上下文 内存(单次执行) 当前请求 中间计算结果
    会话上下文 持久化存储(按会话ID) 跨多次请求 多轮对话记忆
    长期记忆 向量数据库/知识图谱 永久 用户画像、历史偏好

    统一上下文对象应该是一个键值对集合,每个节点只能修改其有权修改的字段,且修改操作应具有可追溯性(记录谁改了、何时改的)。

    #mermaid-svg-J9B6n2ukxo4YKbIj{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-J9B6n2ukxo4YKbIj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-J9B6n2ukxo4YKbIj .error-icon{fill:#552222;}#mermaid-svg-J9B6n2ukxo4YKbIj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-J9B6n2ukxo4YKbIj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-J9B6n2ukxo4YKbIj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-J9B6n2ukxo4YKbIj .marker.cross{stroke:#333333;}#mermaid-svg-J9B6n2ukxo4YKbIj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-J9B6n2ukxo4YKbIj p{margin:0;}#mermaid-svg-J9B6n2ukxo4YKbIj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj .cluster-label text{fill:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj .cluster-label span{color:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj .cluster-label span p{background-color:transparent;}#mermaid-svg-J9B6n2ukxo4YKbIj .label text,#mermaid-svg-J9B6n2ukxo4YKbIj span{fill:#333;color:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj .node rect,#mermaid-svg-J9B6n2ukxo4YKbIj .node circle,#mermaid-svg-J9B6n2ukxo4YKbIj .node ellipse,#mermaid-svg-J9B6n2ukxo4YKbIj .node polygon,#mermaid-svg-J9B6n2ukxo4YKbIj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-J9B6n2ukxo4YKbIj .rough-node .label text,#mermaid-svg-J9B6n2ukxo4YKbIj .node .label text,#mermaid-svg-J9B6n2ukxo4YKbIj .image-shape .label,#mermaid-svg-J9B6n2ukxo4YKbIj .icon-shape .label{text-anchor:middle;}#mermaid-svg-J9B6n2ukxo4YKbIj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-J9B6n2ukxo4YKbIj .rough-node .label,#mermaid-svg-J9B6n2ukxo4YKbIj .node .label,#mermaid-svg-J9B6n2ukxo4YKbIj .image-shape .label,#mermaid-svg-J9B6n2ukxo4YKbIj .icon-shape .label{text-align:center;}#mermaid-svg-J9B6n2ukxo4YKbIj .node.clickable{cursor:pointer;}#mermaid-svg-J9B6n2ukxo4YKbIj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-J9B6n2ukxo4YKbIj .arrowheadPath{fill:#333333;}#mermaid-svg-J9B6n2ukxo4YKbIj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-J9B6n2ukxo4YKbIj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-J9B6n2ukxo4YKbIj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J9B6n2ukxo4YKbIj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-J9B6n2ukxo4YKbIj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J9B6n2ukxo4YKbIj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-J9B6n2ukxo4YKbIj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-J9B6n2ukxo4YKbIj .cluster text{fill:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj .cluster span{color:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj 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-J9B6n2ukxo4YKbIj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-J9B6n2ukxo4YKbIj rect.text{fill:none;stroke-width:0;}#mermaid-svg-J9B6n2ukxo4YKbIj .icon-shape,#mermaid-svg-J9B6n2ukxo4YKbIj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J9B6n2ukxo4YKbIj .icon-shape p,#mermaid-svg-J9B6n2ukxo4YKbIj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-J9B6n2ukxo4YKbIj .icon-shape .label rect,#mermaid-svg-J9B6n2ukxo4YKbIj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J9B6n2ukxo4YKbIj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-J9B6n2ukxo4YKbIj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-J9B6n2ukxo4YKbIj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    字段1

    字段2

    字段3

    字段4

    读取

    更新字段2

    追加字段3

    会话ID

    上下文对象

    用户信息

    当前任务

    历史消息

    工具调用记录

    节点1

    节点2

    节点3

    工程实践要点

    • 状态版本控制:每次上下文变更都生成一个新版本,便于回滚和调试
    • 大小限制:长时间会话的上下文会膨胀,需设置最大长度或启用摘要压缩
    • 分离敏感信息:不要将密码、Token 等敏感数据放在上下文中,使用外部密钥管理
    • 上下文隔离:不同会话(不同 thread_id)的上下文完全隔离

    七、State Store —— 状态持久化,Worker宕机也不怕

    为什么需要 State Store?

    这是 Harness Engineering 中最容易被忽视、但在生产环境最关键的一环。

    Demo 环境里,所有状态都在内存中,Worker 挂了重启就好。但在生产环境,一个工作流可能运行几分钟甚至几小时。如果 Worker 突然宕机,没有持久化的状态,整个任务就要从头重来——这对用户是不可接受的。

    State Store 的作用就是:在每个关键步骤完成后,把整个工作流的状态持久化到外部存储,当 Worker 恢复或新 Worker 接管时,从最近的检查点继续执行。

    通用设计

    一个成熟的 State Store 应满足:

    • 原子性:保存和恢复都是原子的,不会出现半写状态
    • 高可用:存储本身需支持集群,避免单点故障
    • 低延迟:保存检查点的开销不能太大,否则拖慢执行速度
    • 支持回溯:可以恢复到任意历史检查点(时间旅行)

    #mermaid-svg-2GVx5i4KccafTfVs{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-2GVx5i4KccafTfVs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2GVx5i4KccafTfVs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2GVx5i4KccafTfVs .error-icon{fill:#552222;}#mermaid-svg-2GVx5i4KccafTfVs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2GVx5i4KccafTfVs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2GVx5i4KccafTfVs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2GVx5i4KccafTfVs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2GVx5i4KccafTfVs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2GVx5i4KccafTfVs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2GVx5i4KccafTfVs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2GVx5i4KccafTfVs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2GVx5i4KccafTfVs .marker.cross{stroke:#333333;}#mermaid-svg-2GVx5i4KccafTfVs svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2GVx5i4KccafTfVs p{margin:0;}#mermaid-svg-2GVx5i4KccafTfVs .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-2GVx5i4KccafTfVs .cluster-label text{fill:#333;}#mermaid-svg-2GVx5i4KccafTfVs .cluster-label span{color:#333;}#mermaid-svg-2GVx5i4KccafTfVs .cluster-label span p{background-color:transparent;}#mermaid-svg-2GVx5i4KccafTfVs .label text,#mermaid-svg-2GVx5i4KccafTfVs span{fill:#333;color:#333;}#mermaid-svg-2GVx5i4KccafTfVs .node rect,#mermaid-svg-2GVx5i4KccafTfVs .node circle,#mermaid-svg-2GVx5i4KccafTfVs .node ellipse,#mermaid-svg-2GVx5i4KccafTfVs .node polygon,#mermaid-svg-2GVx5i4KccafTfVs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2GVx5i4KccafTfVs .rough-node .label text,#mermaid-svg-2GVx5i4KccafTfVs .node .label text,#mermaid-svg-2GVx5i4KccafTfVs .image-shape .label,#mermaid-svg-2GVx5i4KccafTfVs .icon-shape .label{text-anchor:middle;}#mermaid-svg-2GVx5i4KccafTfVs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2GVx5i4KccafTfVs .rough-node .label,#mermaid-svg-2GVx5i4KccafTfVs .node .label,#mermaid-svg-2GVx5i4KccafTfVs .image-shape .label,#mermaid-svg-2GVx5i4KccafTfVs .icon-shape .label{text-align:center;}#mermaid-svg-2GVx5i4KccafTfVs .node.clickable{cursor:pointer;}#mermaid-svg-2GVx5i4KccafTfVs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2GVx5i4KccafTfVs .arrowheadPath{fill:#333333;}#mermaid-svg-2GVx5i4KccafTfVs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2GVx5i4KccafTfVs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2GVx5i4KccafTfVs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2GVx5i4KccafTfVs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2GVx5i4KccafTfVs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2GVx5i4KccafTfVs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2GVx5i4KccafTfVs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2GVx5i4KccafTfVs .cluster text{fill:#333;}#mermaid-svg-2GVx5i4KccafTfVs .cluster span{color:#333;}#mermaid-svg-2GVx5i4KccafTfVs 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-2GVx5i4KccafTfVs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2GVx5i4KccafTfVs rect.text{fill:none;stroke-width:0;}#mermaid-svg-2GVx5i4KccafTfVs .icon-shape,#mermaid-svg-2GVx5i4KccafTfVs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2GVx5i4KccafTfVs .icon-shape p,#mermaid-svg-2GVx5i4KccafTfVs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2GVx5i4KccafTfVs .icon-shape .label rect,#mermaid-svg-2GVx5i4KccafTfVs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2GVx5i4KccafTfVs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2GVx5i4KccafTfVs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2GVx5i4KccafTfVs :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    恢复过程

    新Worker启动

    加载检查点2

    从步骤3继续

    步骤4完成

    执行过程

    ❌ Worker崩溃

    步骤1完成

    保存检查点1

    步骤2完成

    保存检查点2

    步骤3执行中…

    宕机

    工程实践要点

    • 存储选型:开发环境可用 SQLite/内存,生产环境必须使用 PostgreSQL、MySQL 或云原生数据库(如 AWS DynamoDB)
    • 检查点频率:不是每步都存,而是按“事务边界”存——即一个不可分割的业务单元结束后存一次
    • 清理策略:过期检查点定期清理,防止存储无限膨胀(例如只保留最近 7 天)
    • 幂等恢复:恢复逻辑必须是幂等的,同一个检查点被多次加载不应产生副作用

    总结:Harness Engineering 的“生产就绪”清单

    设计要点核心目标不做的风险
    Loop 支持多轮迭代推理 复杂任务一次跑不完,只能硬编码多步骤
    Tool Registry 工具可治理、可发现 工具泛滥、权限混乱、团队协作困难
    可观测性 系统+AI 双重监控 出问题无法定位,模型退化毫无感知
    多智能体编排 专业分工、并行执行 单 Agent 上下文爆炸,效率低下
    HIL 人工审批保障安全 高风险操作完全自动,合规风险巨大
    上下文管理 跨轮次状态一致 多轮对话“失忆”,用户体验极差
    State Store 故障恢复、断点续传 Worker 宕机后任务从头再来,SLA 无法保证

    这 7 个设计要点共同构成了 Harness Engineering 的核心骨架。它们不依赖任何特定 AI 框架,无论是 LangGraph、AutoGen、Dify,还是自研工作流引擎,这些原则都同样适用。

    从 Demo 到生产,差的从来不是模型的智商,而是这套工程化治理的深度。

    希望这篇文章能帮助你在构建企业级 AI 工作流时,少走一些弯路。如果你在落地过程中遇到其他工程化问题,欢迎留言讨论。

    注:文中示例图和代码风格均为通用设计,具体实现可结合团队技术栈灵活调整。底层框架的选择(如 LangGraph)只是实现细节,不影响上述设计准则的普适性。

    赞(0)
    未经允许不得转载:171主机测评 » Harness Engineering:构建企业级Agent的7大工程化设计准则
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址