news 2026/5/25 14:59:21

Harness Engineering:智能体任务执行可视化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Harness Engineering:智能体任务执行可视化

第一篇:从混沌到洞察——Harness Engineering与智能体可视化的诞生

第1章 当LLM驱动的智能体像“黑盒子”奔跑:任务执行可视化的痛点爆发(12,347字)


1.1 核心概念:什么是任务执行混沌期的LLM智能体?什么是Harness Engineering视野下的“可观测性缺口”

1.1.1 基础铺垫:从SWE-agent到AutoGPT,LLM智能体在做什么?

在过去的两年里(也就是2022年底ChatGPT爆发后的黄金发展期),我们看到了一个全新的软件工程分支——或者说更泛的AI任务自动化与执行领域——突然炸开:2023年3月,AutoGPT带着“无需人类干预自主完成长期复杂目标”的概念刷爆全网,GitHub星标在一周内突破100k;同年10月,Stanford AI Lab和UC Berkeley的SWE-agent在SWE-bench测试集上达到了15.6%的任务解决率,第一次把智能体和“解决真实软件Bug、提交可通过CI的PR”这种硬核SWE任务绑定;再往后,像LangChain、AutoGen、CrewAI这种框架层工具层出不穷,把智能体从“单枪匹马”带到了“多智能体协作、角色扮演、任务拆解嵌套”的新阶段。

那到底什么是LLM驱动的任务执行智能体?我们可以先给它一个非学术、面向工程实践的简单定义

LLM驱动的任务执行智能体,是一种封装了感知层(Perception Layer)、推理层(Reasoning Layer)、动作层(Action Layer)、记忆层(Memory Layer)四个核心模块,以“大语言模型的链式推理(Chain-of-Thought, CoT/Step-by-Step Reasoning)、工具调用(Tool Calling/Function Calling)、反思(Reflection)”为核心能力,能够在给定的明确或半明确目标下,自主规划子任务序列、调用指定工具/API/环境接口、感知执行结果并动态调整策略、最终交付目标成果的自动化执行单元。

为了让这个定义不那么抽象,我们可以用SWE-agent修复一个Python Web应用(假设是Django的TodoList应用)的“待办事项无法标记完成”的Bug这个真实的小场景,来拆解它的四个核心模块和一次任务执行的完整流程:

1.1.1.1 任务执行智能体的核心模块拆解(Django TodoList SWE场景)

我们先假设SWE-agent的输入是:

目标(Goal):修复仓库https://github.com/fake-org/fake-django-todo的Issue #42 “待办事项无法标记为已完成”
工具集(Toolset):GitHub Issue查看工具、Git克隆工具、文件浏览工具(cat/ls)、代码搜索工具(grep)、代码编辑工具(edit_file)、本地Django服务启动工具、PostgreSQL模拟测试工具、pytest运行工具、Git提交与PR创建工具
初始约束(Constraints):修复方案不能破坏现有功能的pytest覆盖率(不能低于当前的82%);提交信息必须符合fix: [Issue #42] ...的格式

1. 感知层(Perception Layer)
感知层的核心作用是把“非结构化/半结构化/结构化的外部环境输入”,转化为“推理层大语言模型能够理解的上下文提示词(Prompt Context)”。在SWE-agent这个场景里,感知层的核心输入源有三个:

  • 目标与工具约束的输入:直接来自用户或者外部调度系统(比如公司内部的DevOps流水线),已经是半结构化文本,感知层只需要做“格式适配(比如把调度系统的JSON格式Issue转化为SWE-agent的Prompt Context)”和“初步过滤冗余信息(比如Issue里的无效吐槽、重复评论)”的轻量级工作。
  • 外部工具的执行结果输入:这是感知层最核心、最频繁的输入——比如当推理层让动作层调用“cat ./todo/models.py”查看待办事项的模型定义时,感知层会拿到动作层返回的“整个models.py的内容文本(非结构化)”或者“grep搜索‘mark_completed’后的高亮结果(半结构化)”,然后把这些结果按“语义重要性排序”、“按工具执行的历史顺序拼接”、“必要时截断过长的文本(避免超过大语言模型的上下文窗口限制)”、“加上结构化的前缀(比如[Tool Execution History - Step 3: grep -r 'mark_completed' ./todo --color=never])”,整理成干净的Prompt Context。
  • 反思模块的历史输出输入:当智能体的某一步执行失败(比如pytest覆盖率掉到了78%),或者推理层对下一步行动不确定时,记忆层会触发反思模块,反思模块会生成“对前几步执行的错误分析”、“对当前策略的调整建议”这类输出,感知层也会把这些输出整理成Prompt Context的一部分,供推理层重新规划。

2. 推理层(Reasoning Layer)
推理层是LLM驱动的任务执行智能体的**“大脑”——它的输入是感知层整理好的完整Prompt Context,输出是“下一步应该调用哪个工具、工具的参数是什么、为什么要调用这个工具的链式推理说明”
在早期的AutoGPT中,推理层的Prompt Context里只有“目标、工具集、当前感知到的外部状态”,所以它的推理经常会“发散”——比如本来是要修Django Todo的Bug,它会突然去搜索“如何优化Django的数据库性能”,然后调用Git克隆工具去克隆一个完全不相关的优化教程仓库;而在SWE-agent这类面向“单一、明确、有约束的专业领域任务”的智能体里,推理层的Prompt Context会加入很多
“领域专家的思维链示例(Few-Shot CoT Examples)”、“任务拆解的结构化模板(比如SWE-agent使用的Plan→Act→Reflect→Iterate的模板)”、“外部约束的强制检查规则(比如用正则表达式要求提交信息必须符合指定格式,用工具调用前的预检查确保不会调用权限外的工具)”——这样就能大大降低推理的“发散率”,提高任务的成功率。
还是回到Django Todo的场景,我们可以模拟一下推理层在
“初步看过Issue #42和仓库的README.md后”**的第一次推理输出:

【链式推理说明(Chain-of-Thought Reasoning)】 1. 首先,我需要明确Issue #42的具体内容:虽然仓库README.md里提到TodoList有“添加待办”、“删除待办”、“标记完成/未完成”三个功能,但从Issue #42的标题“待办事项无法标记为已完成”来看,问题出在“标记完成”这个功能上。 2. 接下来,我应该先查看Issue #42的详细描述和评论,看看有没有用户提供的“复现步骤”、“错误日志”、“环境信息”——这些信息能帮我快速定位问题,不用盲目地搜索整个代码库。 3. 我调用的第一个工具应该是“GitHub Issue查看工具”,工具参数是仓库URL `https://github.com/fake-org/fake-django-todo` 和Issue编号 `42`。

【工具调用指令(Tool Calling Instruction)】
{
“tool_name”: “view_github_issue”,
“parameters”: {
“repo_url”: “https://github.com/fake-org/fake-django-todo”,
“issue_number”: 42
}
}

**3. 动作层(Action Layer)** 动作层的核心作用是**“安全、准确地执行推理层输出的工具调用指令”**——它的输入是推理层输出的结构化工具调用JSON,输出是工具执行的“成功/失败状态码”、“结构化的结果数据”或者“非结构化的错误日志”。 为什么要单独拆分出一个动作层,而不是让推理层直接和外部工具交互?这里有三个**非常重要的工程实践原因**,也是Harness Engineering( harness在这里不是“束带”,而是“ harness → 驾驭、控制 → 安全高效地控制AI系统的行为与输出”的核心思想之一): - **安全性隔离(Security Isolation):** LLM驱动的智能体推理层是“不可预测的”——哪怕你加上了很多约束,它也有可能会生成“删除整个生产环境数据库”、“调用权限外的API获取敏感数据”这类危险的工具调用指令。动作层的第一个职责就是**预检查工具调用指令的安全性**:比如在SWE-agent的动作层里,所有的工具调用指令都会先经过“权限白名单检查(只能调用用户明确授权的工具)”、“参数合法性检查(比如edit_file工具只能编辑仓库根目录及其子目录下的.py/.html/.css/.js文件,不能编辑/etc/passwd这类系统文件)”、“执行时间/资源限制检查(比如本地Django服务启动工具的执行时间不能超过30秒,否则自动停止)”——只有通过所有预检查的指令,才会被真正执行。 - **执行稳定性保障(Execution Stability):** 外部工具/API/环境接口的执行结果是“不稳定的”——比如GitHub API可能会因为网络问题返回500错误,PostgreSQL模拟测试工具可能会因为端口被占用而启动失败。动作层的第二个职责就是**处理工具执行的异常情况**:比如加上“工具调用重试机制(最多重试3次,每次重试之间间隔2秒,指数退避)”、“失败状态下的降级策略(比如本地Django服务启动失败后,降级为“直接查看pytest的测试代码,分析‘标记完成’功能的测试逻辑”)”、“执行过程的资源监控与回收(比如本地Django服务停止后,自动清理临时生成的数据库文件和日志文件)”——这样就能大大提高智能体整体的执行稳定性。 - **工具调用的标准化封装(Standardized Tool Wrapping):** 不同的外部工具/API/环境接口的调用方式、输入输出格式是“千差万别的”——比如GitHub Issue查看工具是用HTTP GET请求调用GitHub API的,返回的是JSON格式的结构化数据;而grep工具是用Shell命令调用的,返回的是纯文本格式的非结构化数据。动作层的第三个职责就是**把所有的外部工具/API/环境接口封装成“标准化的工具类”**:每个工具类都有统一的`name`(工具名称)、`description`(工具描述,供推理层理解工具的作用)、`parameters_schema`(JSON Schema格式的参数定义,供推理层生成合法的参数)、`execute()`(执行工具的方法,返回统一的`ToolExecutionResult`对象——包含`success`布尔值、`data`结构化数据字段、`error_log`非结构化错误日志字段)——这样就能大大降低推理层理解和调用工具的难度。 **4. 记忆层(Memory Layer)** 记忆层的核心作用是**“存储智能体的历史执行信息,供感知层、推理层、反思模块复用”**——它解决了大语言模型的一个**核心硬伤:上下文窗口有限,无法长期记住大量的历史信息**。比如当我们用GPT-4 Turbo(128k上下文窗口)来运行一个“需要修复一个有1000个Python文件的大型Web应用的Bug”的任务时,哪怕只存储每一步的工具执行历史,128k的上下文窗口也很快就会被填满——这时候记忆层就可以帮我们“检索和召回最相关的历史信息”,而不是把所有的历史信息都塞到推理层的Prompt Context里。 记忆层通常可以分为**短期记忆(Short-Term Memory, STM)**和**长期记忆(Long-Term Memory, LTM)**两个部分: - **短期记忆(STM):** 相当于人类的“工作记忆”,存储的是**“当前任务执行过程中最近N步的所有信息”**——比如在SWE-agent的场景里,STM可能会存储最近10步的工具调用指令、执行结果、链式推理说明、反思模块的输出。STM的信息不需要经过复杂的检索,直接按历史顺序拼接成Prompt Context的“工具执行历史”部分即可——不过STM的大小是有限制的(比如最多10步),超过限制的信息会被自动“挤出”STM,转移到LTM里。 - **长期记忆(LTM):** 相当于人类的“长期知识库”,存储的是**“当前任务执行过程中所有被挤出STM的信息”、“智能体之前执行过的类似任务的经验教训”、“领域专家的知识库(比如Django的官方文档、常见Bug的修复指南)”**。LTM的信息不能直接塞到推理层的Prompt Context里,必须先经过**“语义检索(Semantic Retrieval)”**——也就是先把当前推理层的Prompt Context里的“目标、当前状态、不确定性问题”这些信息转化为**“向量嵌入(Vector Embedding)”**,然后在LTM的向量数据库(比如Pinecone、ChromaDB、FAISS)里搜索“最相似的K个向量嵌入对应的信息”,最后把这些最相关的信息整理成Prompt Context的“长期记忆检索结果”部分。 好,现在我们已经把任务执行智能体的四个核心模块和一次真实的SWE任务场景拆解完了——接下来,我们要进入今天的第一个核心痛点:**当LLM驱动的智能体像“黑盒子”一样,在感知→推理→动作→记忆→反思→迭代的循环里不停奔跑时,我们(人类工程师/产品经理/运维人员)到底能看到什么?** --- #### 1.1.2 问题爆发:真实生产环境里,LLM智能体的“可观测性缺口”到底有多大? 为了讲清楚这个问题,我先给大家讲一个**我自己团队在2024年2月份遇到的真实案例**——这个案例让我和我的团队第一次真正意识到了“任务执行可视化”的重要性,也让我们后来决定拥抱Harness Engineering的思想,专门花了三个月的时间,在我们的内部DevOps智能体平台上搭建了一套完整的“任务执行全链路可视化系统”。 ##### 1.1.2.1 真实案例:内部DevOps智能体“DevOps-Agent-001”的首次生产环境部署 **背景介绍:** 我所在的团队是一家国内做SaaS电商平台的公司的**AI赋能DevOps团队**——我们的核心KPI是“把公司内部DevOps工程师的日常重复工作量降低50%以上”。在2023年11月到2024年1月这三个月的时间里,我们用LangChain、FastAPI、Docker、Kubernetes、ChromaDB、gpt-4-turbo-preview这些技术栈,开发了一个内部DevOps智能体,叫“DevOps-Agent-001”(以下简称“Agent-001”)。 Agent-001的核心功能是**“处理公司内部GitHub组织里所有仓库的‘CI/CD流水线失败’类的自动化Issue”**——这类Issue在我们公司内部每天大概有150-200个,其中80%以上都是“重复的、简单的、可以通过执行固定的Shell命令或者调用固定的API来解决的”,比如: 1. `lint`阶段失败:因为某个开发人员提交的代码不符合PEP8/Pylint/ESLint的规范,修复方案是运行`pre-commit run --all-files`,然后提交修复后的代码; 2. `test`阶段失败:因为某个第三方依赖库的版本更新导致测试用例失败,修复方案是在`requirements.txt`/`package.json`里锁定第三方依赖库的版本; 3. `build`阶段失败:因为Docker镜像构建超时,修复方案是在`Dockerfile`里优化镜像分层(比如把不常变的依赖安装层放到前面),然后在CI/CD流水线里提高Docker镜像构建的超时时间; 4. `deploy`阶段失败:因为Kubernetes集群的某个节点的资源不足,修复方案是把Pod调度到资源充足的节点上,或者自动扩容Kubernetes集群的节点。 在正式部署到生产环境之前,我们先在一个**内部测试环境**里对Agent-001进行了为期两周的测试——测试用例是我们从过去半年的生产环境里收集的1000个“CI/CD流水线失败”类的自动化Issue,其中有820个是之前提到的“重复的、简单的、可以通过固定步骤解决的”问题。测试结果让我们非常满意: - **任务解决率:** 81.2%(812/1000)——和我们预期的82%几乎一样; - **任务平均执行时间:** 3分27秒——而我们的DevOps工程师手动处理这类问题的平均时间是12分15秒,效率提升了254%; - **任务执行失败后的错误分析准确率:** 92.7%(17/18个“重复简单但测试失败的问题”的错误分析都是正确的)。 于是,我们团队在2024年2月15日(星期四)的下午,把Agent-001**正式部署到了生产环境**——并且给它设置了“自动处理所有标记了‘auto-fixable’标签的CI/CD流水线失败类Issue”的权限。 ##### 1.1.2.2 灾难发生:Agent-001在生产环境里的“失控” 2024年2月16日(星期五)的早上8点57分,我刚到公司,就收到了我们公司**CTO**和**核心电商业务的负责人**的连续十几条微信消息和电话——核心电商业务的负责人说:“昨晚11点多,我们的电商后台系统自动部署了一个新的版本,结果今天早上9点半要上线的‘情人节促销预热活动’的API全挂了!后台管理系统的登录页也打不开!你们赶紧看看是怎么回事!” 我当时吓得冷汗都出来了——我们公司的核心电商业务在情人节前后的日交易额大概是平时的5-10倍,如果“情人节促销预热活动”的API挂了,今天的损失可能会达到几百万甚至上千万! 我赶紧打开公司内部的Kibana日志平台和Prometheus监控平台——一看,果然有问题: 1. **Kibana日志平台:** 昨晚11点03分,我们的核心电商后台系统的GitHub仓库(`https://github.com/our-company/our-core-ecommerce-backend`)自动创建了一个PR,标题是`fix: [auto-fixable] lint阶段失败:ESLint规则`no-unused-vars`违规`,提交信息也是这个,PR的作者是我们的Agent-001;11点08分,这个PR被我们的CI/CD流水线自动通过了(因为我们给标记了“auto-fixable”标签的Issue对应的PR设置了“自动合并(Auto-Merge)”的权限,只要CI/CD流水线的`lint`、`test`、`build`、`deploy-staging`四个阶段都通过,就会自动合并到`main`分支,然后自动部署到生产环境);11点12分,这个PR被自动合并到了`main`分支;11点17分,自动部署到生产环境的流程开始;11点22分,生产环境的Pod全部重启完成;11点23分,Kibana日志平台开始大量报错——错误类型是`AttributeError: 'NoneType' object has no attribute 'get'`,错误发生在`our-core-ecommerce-backend/app/api/v1/promotion.py`的第47行。 2. **Prometheus监控平台:** 昨晚11点23分之后,核心电商后台系统的“API请求成功率”从99.9%直接掉到了0%;“Pod重启次数”在10分钟内增加了50次(因为Kubernetes的LivenessProbe和ReadinessProbe都失败了,所以Kubernetes一直在重启Pod);“CPU使用率”和“内存使用率”也一直居高不下(因为Pod一直在重启,一直在加载Python依赖库和初始化数据库连接)。 我赶紧打开GitHub仓库的PR页面,查看Agent-001自动创建的PR的代码变更——一看,我差点晕过去: Agent-001在修复`app/api/v1/promotion.py`的`no-unused-vars`ESLint规则违规时,**把一个非常重要的变量`promotion_config`给删除了!** 让我给大家看一下**PR变更前**的`app/api/v1/promotion.py`的第30-50行代码: ```python # PR变更前的代码(第30-50行) from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.database import get_db from app.models.promotion import Promotion from app.schemas.promotion import PromotionCreate, PromotionResponse from app.services.promotion_service import PromotionService from app.utils.promotion_config_loader import load_promotion_config # 导入配置加载工具 router = APIRouter(prefix="/api/v1/promotion", tags=["Promotion"]) @router.get("/preheat", response_model=list[PromotionResponse]) def get_preheat_promotions( db: Session = Depends(get_db), # 这里有一个unused的参数?不,这是我们的权限验证中间件会用到的参数,虽然在这个函数体里没有直接用,但不能删除! current_user: dict = Depends(get_current_active_admin_user) ): # 加载情人节促销预热活动的配置(这个变量在load_promotion_config里被缓存了,虽然在这个函数体里没有直接用,但load_promotion_config会在第一次调用时初始化缓存,后面的PromotionService.get_preheat_promotions会用到这个缓存!) promotion_config = load_promotion_config("valentine_preheat_2024") # 获取预热活动的列表 promotion_service = PromotionService(db) preheat_promotions = promotion_service.get_preheat_promotions() if not preheat_promotions: raise HTTPException(status_code=404, detail="No preheat promotions found") return preheat_promotions

然后再看一下PR变更后的代码:

# PR变更后的代码(第30-50行)fromfastapiimportAPIRouter,Depends,HTTPExceptionfromsqlalchemy.ormimportSessionfromapp.databaseimportget_dbfromapp.models.promotionimportPromotionfromapp.schemas.promotionimportPromotionCreate,PromotionResponsefromapp.services.promotion_serviceimportPromotionService# 哦!Agent-001还把load_promotion_config的导入语句给删除了!因为它认为这个导入语句没有被用到!router=APIRouter(prefix="/api/v1/promotion",tags=["Promotion"])@router.get("/preheat",response_model=list[PromotionResponse])defget_preheat_promotions(db:Session=Depends(get_db)# current_user参数被删除了!因为Agent-001认为它是unused的!):# promotion_config变量被删除了!因为Agent-001认为它是unused的!# 获取预热活动的列表promotion_service=PromotionService(db)preheat_promotions=promotion_service.get_preheat_promotions()# 第47行——错误发生在这里!ifnotpreheat_promotions:raiseHTTPException(status_code=404,detail="No preheat promotions found")returnpreheat_promotions

那为什么第47行会报错AttributeError: 'NoneType' object has no attribute 'get'呢?因为我们的PromotionService.get_preheat_promotions()方法里,会调用app.utils.promotion_config_loader.get_cached_promotion_config("valentine_preheat_2024")来获取预热活动的配置——而这个方法的逻辑是:

# app/utils/promotion_config_loader.py的部分代码_cached_promotion_config={}defload_promotion_config(config_name:str)->dict:""" 加载促销活动的配置,并缓存到内存里 """ifconfig_namenotin_cached_promotion_config:# 从环境变量里获取配置文件的路径config_path=os.getenv(f"PROMOTION_CONFIG_{config_name.upper()}")ifnotconfig_path:raiseValueError(f"Environment variable PROMOTION_CONFIG_{config_name.upper()}not set")# 从JSON文件里加载配置withopen(config_path,"r",encoding="utf-8")asf:config=json.load(f)# 缓存配置_cached_promotion_config[config_name]=configreturn_cached_promotion_config[config_name]defget_cached_promotion_config(config_name:str)->Optional[dict]:""" 获取缓存的促销活动的配置——如果没有缓存,返回None """return_cached_promotion_config.get(config_name)

而我们的PromotionService.get_preheat_promotions()方法里,没有检查get_cached_promotion_config()的返回值是否为None,直接就调用了config.get("preheat_start_time")——所以当load_promotion_config()没有被调用过(因为Agent-001把它的调用语句和导入语句都删除了),get_cached_promotion_config()返回None,然后就报错了。

更糟糕的是,Agent-001还把current_user参数给删除了——虽然这个参数在get_preheat_promotions()函数体里没有直接用,但它是我们的权限验证中间件get_current_active_admin_user()的返回值,这个中间件会自动把current_user的信息存储到FastAPI的请求上下文里,后面的其他API(比如创建促销活动的API、修改促销活动的API)会用到这个请求上下文里的current_user信息——也就是说,就算我们修复了AttributeError的问题,后面的其他API的权限验证也会失效,任何一个用户(包括未登录的用户)都可以创建、修改、删除我们的促销活动!

1.1.2.3 事后复盘:为什么我们没有提前发现Agent-001的“错误”?

在我们团队花了两个小时(9点10分-11点10分)紧急修复了所有问题、把核心电商后台系统恢复正常之后,我们进行了一次非常深刻的事后复盘——复盘的核心问题是:“为什么我们在测试环境里没有发现Agent-001的这个错误?为什么我们在生产环境里的PR合并和部署流程里没有发现这个错误?为什么我们直到API全挂了才知道出了问题?”

经过整整一天的复盘,我们总结出了五个核心原因——这五个原因,其实就是LLM驱动的任务执行智能体在真实生产环境里的**“五个可观测性缺口”**:

原因一:测试环境的场景覆盖不全,无法模拟生产环境里的“真实业务逻辑依赖”
在我们的测试环境里,我们给PromotionService.get_preheat_promotions()方法写的测试用例是**“Mock掉了get_cached_promotion_config()方法”的——也就是说,测试用例里的get_cached_promotion_config()方法会直接返回一个Mock的配置字典,不会真的去调用load_promotion_config()方法,也不会真的去缓存配置——所以在测试环境里,就算Agent-001把load_promotion_config()的调用语句和导入语句都删除了,测试用例也会通过!这是我们测试环境的第一个大问题。
另外,在我们的测试环境里,我们给get_preheat_promotions()函数写的测试用例是
“Mock掉了get_current_active_admin_user()中间件”**的——也就是说,测试用例里的get_preheat_promotions()函数不会真的去调用权限验证中间件,也不会真的去检查用户的权限——所以在测试环境里,就算Agent-001把current_user参数给删除了,测试用例也会通过!这是我们测试环境的第二个大问题。
但更深层次的问题是:**我们(人类工程师)怎么可能在测试环境里,模拟出所有生产环境里的“真实业务逻辑依赖”?**尤其是对于像我们这样的大型SaaS电商平台,代码库的规模非常大(我们的核心电商后台系统有超过5000个Python文件,超过200万行代码),业务逻辑非常复杂(有超过100个微服务,超过1000个API接口,超过5000个测试用例)——我们根本不可能在测试环境里,把所有的“隐含的业务逻辑依赖”(比如promotion_config变量虽然在函数体里没有直接用,但它会初始化缓存,后面的方法会用到;比如current_user参数虽然在函数体里没有直接用,但它会被权限验证中间件存储到请求上下文里,后面的其他API会用到)都覆盖到!这就意味着,LLM驱动的任务执行智能体在生产环境里,总会遇到一些测试环境里没有覆盖到的“隐含的业务逻辑依赖”,从而做出错误的决策——而如果我们没有办法“实时观测到智能体的决策过程和执行过程”,我们就只能等到“业务出现问题”的时候,才知道出了问题!

原因二:CI/CD流水线的自动合并权限设置得太松,没有人工审核的环节
在我们的生产环境里,我们给标记了“auto-fixable”标签的Issue对应的PR设置了“自动合并”的权限——只要CI/CD流水线的linttestbuilddeploy-staging四个阶段都通过,就会自动合并到main分支,然后自动部署到生产环境。
但问题是:我们的deploy-staging阶段的测试用例,和我们的测试环境里的测试用例是一样的——都是Mock掉了“隐含的业务逻辑依赖”的!所以在deploy-staging阶段,就算Agent-001做出了错误的决策,测试用例也会通过!
更深层次的问题是:**我们(人类工程师)怎么可能完全信任LLM驱动的任务执行智能体的决策?**哪怕它在测试环境里的任务解决率达到了99.9%,我们也不能完全信任它——因为LLM是“不可预测的”,它总会在某个时候,做出一些我们人类完全想不到的错误决策!这就意味着,对于生产环境里的重要操作(比如合并PR、部署到生产环境),我们必须要有“人工审核”的环节——而如果我们没有办法“清晰、直观地给人类审核人员展示智能体的决策过程和执行过程”,人类审核人员就没有办法快速、准确地判断智能体的决策是否正确,人工审核的效率就会非常低,甚至会失去人工审核的意义!

原因三:我们没有办法“实时观测到智能体的决策过程”——只能看到它的“最终执行结果”
在我们的Agent-001的初始版本里,我们只给它加了**“最终执行结果的日志记录”**——也就是当智能体的任务执行成功或者失败时,它会把“任务的目标”、“任务的最终执行状态(成功/失败)”、“任务执行失败时的错误日志”这些信息,记录到我们的Kibana日志平台里。
但问题是:我们没有办法看到智能体的“中间决策过程”——也就是它为什么会做出“删除promotion_config变量”、“删除current_user参数”、“删除load_promotion_config的导入语句”这些决策?它的链式推理说明是什么?它调用了哪些工具?工具的执行结果是什么?它有没有触发反思模块?反思模块的输出是什么?
在我们的事后复盘里,我们花了整整两个小时,才从我们的Agent-001的内部内存(因为我们没有把中间决策过程记录到日志里,只能从当时运行的Pod的临时文件里找到一些残留的信息)里,拼凑出了它的中间决策过程——让我给大家看一下拼凑出来的部分中间决策过程:

【Agent-001的内部中间决策过程残留信息(拼凑版)】 --- 【Step 1: 感知层输入】 目标:修复仓库 `https://github.com/our-company/our-core-ecommerce-backend` 的Issue #12345 “CI/CD流水线失败:lint阶段ESLint规则`no-unused-vars`违规” 工具集:...(省略) 约束:...(省略) 工具执行历史:无 --- 【Step 1: 推理层输出】 链式推理说明: 1. 首先,我需要查看Issue #12345的详细描述,看看ESLint规则`no-unused-vars`违规的具体位置在哪里。 2. 我调用的第一个工具应该是“view_github_issue”,参数是仓库URL和Issue编号。 工具调用指令:view_github_issue(...) --- 【Step 2: 感知层输入】 ...(省略view_github_issue的执行结果:ESLint规则`no-unused-vars`违规的具体位置是`app/api/v1/promotion.py`的第36行(导入语句`load_promotion_config`)、第42行(参数`current_user`)、第44行(变量`promotion_config`)) --- 【Step 2: 推理层输出】 链式推理说明: 1. 从view_github_issue的执行结果来看,ESLint规则`no-unused-vars`违规的具体位置是三个: a. `app/api/v1/promotion.py`的第36行:导入语句`from app.utils.promotion_config_loader import load_promotion_config`——没有被用到; b. `app/api/v1/promotion.py`的第42行:参数`current_user`——没有被用到; c. `app/api/v1/promotion.py`的第44行:变量`promotion_config`——没有被用到; 2. ESLint规则`no-unused-vars`的要求是“删除所有未使用的导入语句、参数、变量”——所以我需要删除这三个未使用的内容; 3. 接下来,我需要先查看一下`app/api/v1/promotion.py`的完整内容,确认这三个内容确实没有被用到; 4. 我调用的工具应该是“view_file”,参数是文件路径`app/api/v1/promotion.py`。 工具调用指令:view_file(...) --- 【Step 3: 感知层输入】 ...(省略view_file的执行结果:`app/api/v1/promotion.py`的完整内容,也就是PR变更前的代码) --- 【Step 3: 推理层输出】 链式推理说明: 1. 我已经查看了`app/api/v1/promotion.py`的完整内容,确认这三个内容确实没有被用到: a. 导入语句`load_promotion_config`:在整个文件里都没有被调用过; b. 参数`current_user`:在`get_preheat_promotions()`函数体里没有被直接用到; c. 变量`promotion_config`:在`get_preheat_promotions()`函数体里没有被直接用到; 2. 所以我需要删除这三个内容; 3. 接下来,我需要调用“edit_file”工具来修改`app/api/v1/promotion.py`; 工具调用指令:edit_file(...) --- 【Step 4: 感知层输入】 ...(省略edit_file的执行结果:修改成功) --- 【Step 4: 推理层输出】 链式推理说明: 1. 我已经成功修改了`app/api/v1/promotion.py`,删除了三个未使用的内容; 2. 接下来,我需要调用“run_pre_commit”工具来运行pre-commit钩子,确保没有其他的ESLint规则违规; 工具调用指令:run_pre_commit(...) --- 【Step 5: 感知层输入】 ...(省略run_pre_commit的执行结果:pre-commit钩子运行成功,所有ESLint规则都通过了) --- 【Step 5: 推理层输出】 链式推理说明: 1. pre-commit钩子运行成功,所有ESLint规则都通过了; 2. 接下来,我需要调用“git_add”、“git_commit”、“git_push”工具来提交和推送修改; 工具调用指令:git_add(...), git_commit(...), git_push(...) --- 【Step 6: 感知层输入】 ...(省略git_push的执行结果:推送成功) --- 【Step 6: 推理层输出】 链式推理说明: 1. 修改已经成功推送到远程仓库; 2. 接下来,我需要调用“create_github_pr”工具来创建PR; 工具调用指令:create_github_pr(...) --- 【Step 7: 感知层输入】 ...(省略create_github_pr的执行结果:PR创建成功,编号是#12346) --- 【Step 7: 推理层输出】 链式推理说明: 1. PR已经成功创建; 2. 接下来,我需要等待CI/CD流水线的`lint`、`test`、`build`、`deploy-staging`四个阶段都通过; 3. 如果四个阶段都通过,PR会自动合并到`main`分支,然后自动部署到生产环境; 4. 我的任务已经完成。 --- 【最终执行结果:成功】 记录到Kibana日志平台的信息: { "task_id": "task-123456", "agent_id": "DevOps-Agent-001", "goal": "修复仓库 https://github.com/our-company/our-core-ecommerce-backend 的Issue #12345 “CI/CD流水线失败:lint阶段ESLint规则`no-unused-vars`违规”", "status": "success", "start_time": "2024-02-15T23:00:00Z", "end_time": "2024-02-15T23:07:00Z", "duration_seconds": 420, "pr_url": "https://github.com/our-company/our-core-ecommerce-backend/pull/12346" }

看到这里,我想大家应该都明白问题出在哪里了——Agent-001的推理层根本没有意识到这三个内容是“隐含的业务逻辑依赖”!它只是简单地按照ESLint规则no-unused-vars的要求,删除了所有“在当前文件或者当前函数体里没有被直接用到的”导入语句、参数、变量!
但更深层次的问题是:如果我们当时有一套完整的“任务执行全链路可视化系统”,能够实时观测到Agent-001的中间决策过程——比如在Step 3的推理层输出里,当它说“确认这三个内容确实没有被用到”的时候,我们的可视化系统能够给我们的人类审核人员发送一个“预警”,告诉我们“智能体即将删除三个可能是隐含的业务逻辑依赖的内容,请人工审核”——那我们就可以在PR合并之前,就发现这个问题,避免灾难的发生!

原因四:我们没有办法“清晰、直观地给人类展示智能体的执行过程”——只能看到一堆杂乱无章的日志
在我们的Agent-001的初始版本里,就算我们后来把中间决策过程也记录到了Kibana日志平台里,这些日志也是**“杂乱无章的”——它们是按时间顺序排列的纯文本日志,没有任何的结构化、分类、可视化——我们的人类审核人员要想从这些日志里找到智能体的中间决策过程,就必须像“大海捞针”一样,一条一条地看日志,效率非常低!
比如在我们的事后复盘里,就算我们后来把中间决策过程也记录到了测试环境里的Kibana日志平台里,我们的一个资深DevOps工程师也要花整整30分钟,才能从测试环境里的一次类似的任务执行的日志里,找到智能体的中间决策过程——这对于需要快速审核PR的人类审核人员来说,是完全不可接受的!
更深层次的问题是:日志这种形式,根本不适合用来展示LLM驱动的任务执行智能体的执行过程——因为智能体的执行过程是“链式的、有因果关系的、包含大量的非结构化文本(比如链式推理说明)和结构化数据(比如工具调用指令、工具执行结果)的”!我们需要的是一种
“清晰、直观、交互式的可视化形式”**——能够把智能体的执行过程,按“感知→推理→动作→记忆→反思→迭代”的循环,以“流程图、时序图、树状图”等形式,清晰、直观地展示给人类;能够让人类通过“点击、拖拽、缩放”等交互式操作,查看智能体执行过程的每一个细节(比如每一步的链式推理说明、每一步的工具调用指令、每一步的工具执行结果);能够在智能体做出“可能有风险的决策”的时候,自动给人类发送“预警”;能够让人类在智能体执行过程的任何一个环节,“暂停”、“干预”、“修改”智能体的决策!

原因五:我们没有办法“量化评估”智能体的决策质量和执行质量——只能看到“任务解决率”和“任务平均执行时间”这两个宏观指标
在我们的Agent-001的初始版本里,我们只给它加了**“任务解决率”和“任务平均执行时间”这两个宏观指标的统计**——我们根本没有办法“量化评估”智能体的每一步决策的质量(比如“这一步的链式推理说明是否合理?”、“这一步的工具调用指令是否正确?”、“这一步的工具调用是否必要?”),也没有办法“量化评估”智能体的每一次任务执行的质量(比如“这次任务执行有没有对业务造成影响?”、“这次任务执行有没有破坏现有功能的测试覆盖率?”、“这次任务执行有没有浪费不必要的资源?”)!
比如在我们的事后复盘里,我们根本没有办法从我们的初始版本的统计数据里,发现Agent-001的“删除隐含的业务逻辑依赖”的决策质量问题——因为从宏观指标来看,这次任务执行是“成功”的:它成功地修复了ESLint规则no-unused-vars的违规问题;它的CI/CD流水线的四个阶段都通过了;它的任务平均执行时间也符合我们的要求!但实际上,这次任务执行的决策质量是“极差”的——它几乎给我们公司造成了几百万甚至上千万的损失!
更深层次的问题是:如果我们没有办法“量化评估”智能体的决策质量和执行质量,我们就没有办法“优化”智能体的Prompt Context、领域专家的思维链示例、工具集、约束条件——我们就没有办法提高智能体的任务解决率和决策质量,我们就没有办法在生产环境里更广泛地应用LLM驱动的任务执行智能体!


1.1.3 核心概念升级:什么是Harness Engineering(驾驭工程)?什么是Harness Engineering视野下的“智能体任务执行全链路可观测性”?什么是本文要重点讲解的“智能体任务执行可视化”

经过这次深刻的事后复盘,我们团队开始在网上搜索相关的解决方案——我们发现,在2023年底到2024年初,国内外的一些顶尖的AI研究机构和科技公司(比如OpenAI、Anthropic、Google DeepMind、Meta AI、微软亚洲研究院、阿里达摩院、腾讯AI Lab),开始提出一个全新的软件工程分支的概念——Harness Engineering(驾驭工程)

1.1.3.1 什么是Harness Engineering(驾驭工程)?

目前,Harness Engineering还没有一个统一的、官方的学术定义——不过,我们可以从国内外顶尖的AI研究机构和科技公司的相关论文、博客文章、技术分享里,总结出一个面向工程实践的Harness Engineering的定义

Harness

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 14:58:15

智能硬件设计空间探索:从PPA优化到LLM驱动

1. 硬件设计空间探索的核心价值与挑战在计算机体系结构设计领域,设计空间探索(Design Space Exploration, DSE)正经历着从人工经验驱动到智能自动化的重要转型。传统硬件设计流程中,工程师需要手动调整数十个甚至上百个架构参数&a…

作者头像 李华
网站建设 2026/5/25 14:57:20

Taotoken 的用量看板与成本管理功能如何帮助团队控制 AI 支出

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken 的用量看板与成本管理功能如何帮助团队控制 AI 支出 作为团队的技术负责人,在引入大模型能力支持业务创新的同…

作者头像 李华
网站建设 2026/5/25 14:57:08

SPT-AKI Profile Editor终极指南:轻松管理你的离线塔科夫存档

SPT-AKI Profile Editor终极指南:轻松管理你的离线塔科夫存档 【免费下载链接】SPT-AKI-Profile-Editor Программа для редактирования профиля игрока на сервере SPT-AKI 项目地址: https://gitcode.com/gh_mi…

作者头像 李华
网站建设 2026/5/25 14:55:18

5分钟掌握思源宋体:设计师必备的免费商用字体终极指南

5分钟掌握思源宋体:设计师必备的免费商用字体终极指南 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还在为商业设计项目寻找既专业又免费的中文字体而烦恼吗?…

作者头像 李华