Harness Engineering 实战:用 LangGraph 重构 Deep Agents 执行框架
1. 从 Terminal Bench 的失败案例说起Deep Agents 到底卡在哪第一次接触 Harness Engineering 这个概念是在折腾一个终端自动化 Agent 的时候。当时我用的是一套基于 LangChain 搭建的 Deep Agent任务很简单让它在终端里完成一系列文件操作、命令执行和环境配置。结果跑 Terminal Bench 的时候成功率惨不忍睹——明明每一步单独拆开都能跑通串起来就各种翻车。这个现象我相信做过 Agent 开发的人都遇到过。你写了一个 Agent给它配了工具接了 LLM本地测试几个 case 都正常一上评测集就原形毕露。问题出在哪大多数人第一反应是换模型、调 prompt、加 few-shot 示例。这些手段有用但往往治标不治本。真正的问题在于我们一直在优化 Agent 的大脑却忽略了 Agent 的身体。这里的身体就是 Harness——Agent 与外部环境之间的那层执行框架。它负责把 LLM 的输出翻译成实际的工具调用、管理执行状态、处理错误恢复、控制上下文窗口。Harness 设计得好不好直接决定了 Agent 在真实任务中的表现上限。Deep Agents 这个概念指的是那些需要多步推理、长链路执行、复杂工具编排的 Agent 系统。它们不是简单的一问一答而是要在终端环境里持续工作几分钟甚至几十分钟中间涉及几十次工具调用。这种场景下Harness 的重要性被急剧放大。一个设计粗糙的 Harness 会让 Agent 在第 5 步就迷失方向而一个精心设计的 Harness 能让同样的模型多跑 20 步还不崩。Terminal Bench 这类评测之所以残酷就是因为它模拟的是真实终端环境——有文件系统、有进程管理、有权限控制、有各种边界情况。Agent 不能只会在理想环境里回答问题它得真的能在这个环境里干活。这就把 Harness Engineering 推到了台前。我后来花了不少时间研究 LangChain 和 LangGraph 在 Agent 编排上的设计思路也对比了几种不同的 Harness 实现方案。这篇文章就把这些经验整理出来聊聊怎么通过改进 Harness 来实质性提升 Deep Agents 的表现。不管你是刚入门 Agent 开发还是已经在做工业级智能体项目这些内容应该都能给你一些参考。2. Harness 与 Agent 的分工边界为什么大多数人搞混了2.1 一个容易被忽视的概念区分很多人第一次听到Harness 和 Agent 的区别这个问题时会觉得这不就是一回事吗Agent 不就是那个能自主决策、调用工具的东西吗Harness 不就是 Agent 的一部分吗这个理解不能算错但不够精确。打个比方Agent 像是驾驶员Harness 像是汽车本身。驾驶员决定去哪、怎么走但汽车的方向盘手感、油门响应、刹车距离、仪表盘信息呈现方式都会深刻影响驾驶员的决策质量和反应速度。你不能说汽车就是驾驶员的一部分它们是两个需要协同设计但又职责分明的系统。具体到技术层面Agent 的核心职责是理解任务目标规划执行步骤选择调用哪个工具根据工具返回结果调整策略而 Harness 的核心职责是把 Agent 的决策翻译成实际的系统调用管理执行过程中的状态和上下文处理工具调用的输入输出格式控制错误恢复和重试逻辑维护执行轨迹和可观测性这个区分为什么重要因为当你发现 Agent 表现不好的时候你得知道该改哪一层。如果是规划能力不行那是 Agent 层的问题可能需要换模型或者改 prompt。如果是执行过程中频繁丢失上下文、工具调用格式错误、错误恢复逻辑混乱那大概率是 Harness 层的问题改 prompt 是没用的。2.2 Deep Agents 对 Harness 的特殊要求普通的 ReAct Agent 对 Harness 的要求其实不高——一轮对话、几次工具调用、拿到答案就结束。但 Deep Agents 不一样它的特点是执行链路长。一个任务可能需要 30 到 50 次工具调用才能完成中间任何一步出错都可能导致整个任务失败。Harness 需要有能力在长链路中保持状态一致性。上下文压力大。每次工具调用的输入输出都要塞进上下文窗口几十轮下来 token 消耗惊人。Harness 需要做上下文管理决定哪些信息保留、哪些压缩、哪些丢弃。错误恢复复杂。终端环境里什么都有可能发生——命令不存在、权限不足、文件被占用、网络超时。Harness 需要区分哪些错误可以重试、哪些需要换策略、哪些必须上报给 Agent 重新规划。可观测性要求高。当 Agent 跑了 40 步之后失败了你得能回溯每一步发生了什么才能定位问题。Harness 需要记录完整的执行轨迹。我见过太多项目Agent 的 prompt 写得非常精致工具定义也很完善但 Harness 就是简单地把 LLM 输出解析成 JSON 然后执行。这种设计在简单场景下能跑一到 Deep Agents 场景就崩。因为 Harness 没有承担起它应该承担的责任。2.3 LangChain 与 LangGraph 在 Harness 设计上的取舍说到 Agent 框架LangChain 和 LangGraph 是两个绕不开的选择。很多人问LangChain 和 LangGraph 的区别是什么从 Harness Engineering 的角度看它们的核心差异在于对执行流程的控制粒度。LangChain 的 AgentExecutor 是一个相对封闭的 Harness。它帮你处理了工具调用的循环、输出解析、错误处理但你很难介入到执行流程的中间环节。这种设计上手快适合快速验证想法但当你需要精细控制 Harness 行为时就会觉得束手束脚。LangGraph 则把执行流程显式建模成图结构。每个节点是一个执行步骤边定义了状态转移逻辑。这意味着你可以精确控制什么时候压缩上下文、什么时候重试、什么时候切换到备用策略、什么时候触发 human-in-the-loop。对于 Deep Agents 来说这种控制粒度是必需的。我个人的经验是如果你只是做一个 demo 或者简单 AgentLangChain 的 AgentExecutor 够用。但如果你要认真做 Deep Agents尤其是需要跑 Terminal Bench 这类评测的场景LangGraph 的显式状态管理会帮你省掉大量调试时间。不过要注意LangGraph 也不是银弹。它给了你控制权但也意味着你需要自己设计状态结构、自己处理边界情况。Harness Engineering 的工作量并没有减少只是从和框架搏斗变成了设计自己的执行逻辑。3. 拆解 Harness 的五个核心模块从工具调用到错误恢复3.1 工具调用层格式解析只是最基础的一步工具调用层是 Harness 最直观的部分——把 LLM 输出的工具调用请求解析出来执行然后把结果返回给 LLM。听起来简单但坑非常多。第一个坑是格式稳定性。LLM 输出的工具调用格式可能千奇百怪有时候是标准 JSON有时候是带 markdown 代码块的 JSON有时候字段名会变有时候会多出一些不存在的参数。如果你的解析器只处理标准格式那 Agent 会在各种奇怪的地方失败。我的做法是在解析层加一个宽容模式先尝试标准解析失败后尝试提取 JSON 片段再失败后尝试用正则提取关键字段。同时记录每次降级解析的情况如果某个模型的降级率特别高说明 prompt 需要调整。第二个坑是参数校验。LLM 可能会传入类型错误的参数比如该传整数的传了字符串该传数组的传了单个值。Harness 需要在执行前做参数校验和类型转换而不是直接把错误参数传给工具然后等工具报错。第三个坑是工具选择的合理性。有时候 LLM 会选择不存在的工具或者在不合适的时机调用某个工具。Harness 需要维护一个工具注册表在调用前检查工具是否存在、当前状态是否允许调用。# 一个简化的工具调用解析示例 def parse_tool_call(llm_output): # 第一层标准 JSON 解析 try: return json.loads(llm_output) except json.JSONDecodeError: pass # 第二层提取代码块中的 JSON json_match re.search(r(?:json)?\s*(\{.*?\})\s*, llm_output, re.DOTALL) if json_match: try: return json.loads(json_match.group(1)) except json.JSONDecodeError: pass # 第三层正则提取关键字段 tool_name re.search(rtool\s*:\s*([^]), llm_output) if tool_name: return {tool: tool_name.group(1), args: {}} return None这段代码看起来简单但实际项目中解析层的健壮性直接决定了 Agent 的可用性。我见过太多项目在这里偷懒结果 Agent 在评测中大量失败都是因为解析问题而不是推理问题。3.2 状态管理层上下文窗口是最稀缺的资源Deep Agents 跑长任务时上下文窗口是最稀缺的资源。每次工具调用的输入输出都要占用 token几十轮下来很容易撑爆窗口。状态管理层的核心任务就是在有限的窗口里保留最关键的信息。这里有几个策略我按推荐程度排序策略一结构化摘要。不要让原始的工具输出直接进上下文而是让 Harness 先做一层摘要。比如执行了一个ls命令返回了 50 个文件Harness 可以摘要成目录下有 50 个文件包括 X、Y、Z 等关键文件。这样既保留了信息又大幅压缩了 token。策略二滑动窗口加锚点。保留最近 N 轮的工具调用同时保留最初的任务描述和关键中间结论。中间的过程性信息可以丢弃。这个策略的关键是锚点的选择——哪些信息是后续步骤必须依赖的。策略三外部记忆。把完整的执行轨迹存到外部存储上下文里只保留一个引用。当 Agent 需要回溯某一步时再按需加载。这个策略适合超长任务但增加了 Harness 的复杂度。我实际用下来策略一和策略二的组合效果最好。纯滑动窗口容易丢失关键信息纯摘要又可能丢失细节。两者结合既能控制 token 消耗又能保持信息完整性。还有一个容易被忽视的点状态的一致性。Agent 在执行过程中可能会修改文件系统、启动进程、改变环境变量。Harness 需要维护一个世界状态的模型确保 Agent 的决策基于最新的状态而不是过时的信息。3.3 错误恢复层区分可重试和需重规划错误恢复是 Harness 最能体现工程水平的地方。新手写的 Harness 通常只有两种处理方式要么直接抛错终止要么无脑重试。这两种都不对。正确的做法是把错误分类错误类型典型场景处理策略瞬时错误网络超时、资源暂时占用指数退避重试最多 3 次参数错误命令参数格式不对返回错误信息给 Agent让它修正策略错误选错了工具或方法返回错误信息提示 Agent 重新规划环境错误命令不存在、权限不足返回错误信息Agent 需要换方案致命错误系统崩溃、不可恢复状态终止任务上报人工这个分类的关键在于Harness 要能判断错误的性质而不是把所有错误都当成一回事。瞬时错误重试就好参数错误要让 Agent 知道具体哪里错了策略错误要引导 Agent 重新思考。我在实际项目中发现很多 Agent 失败不是因为不会做而是因为 Harness 没有把错误信息有效地传递回去。比如执行命令失败了Harness 只返回一个 command failedAgent 根本不知道是权限问题还是路径问题自然无法修正。正确的做法是返回完整的 stderr 输出让 Agent 有足够的信息做判断。还有一个技巧错误信息的结构化。不要返回一大段原始错误文本而是提取关键信息错误类型、错误位置、可能的修复方向。这样 Agent 处理起来更高效。3.4 执行轨迹层可观测性决定调试效率Deep Agents 跑长任务时出问题是常态。关键是你能不能快速定位问题出在哪一步。执行轨迹层的任务就是记录完整的执行历史支持事后回溯。我建议记录的信息包括每一步的时间戳LLM 的原始输出解析后的工具调用工具的实际执行结果执行耗时上下文窗口的 token 使用情况状态变更记录这些信息看起来多但真出问题的时候每一条都可能成为定位问题的关键线索。我踩过的坑是早期为了省事只记录了工具调用和结果结果有一次 Agent 在第 30 步突然行为异常我完全不知道是上下文里哪条信息导致的只能从头复现。执行轨迹的另一个用途是性能分析。通过分析轨迹你能发现 Agent 在哪些步骤上耗时最长、哪些工具调用最频繁、哪些环节最容易出错。这些数据是优化 Harness 的依据。3.5 安全边界层Agent 不能什么都干Agent 在终端环境里执行命令安全边界必须明确。这不是限制 Agent 的能力而是保护系统不被意外破坏。安全边界层需要处理的事情包括命令白名单/黑名单文件系统访问范围限制资源使用限制CPU、内存、执行时间敏感操作的二次确认执行环境的隔离我见过有人的 Agent 在测试时不小心执行了rm -rf相关的命令虽然是在容器里但也吓出一身冷汗。安全边界不是可选项是必选项。具体实现上我倾向于用容器化方案做环境隔离然后在 Harness 层加命令过滤和资源限制。命令过滤不要用简单的字符串匹配容易被绕过要用命令解析后的 AST 做判断。4. 用 LangGraph 重构 Harness一个可落地的实现路径4.1 为什么选择 LangGraph 而不是 AgentExecutor前面提到过 LangChain 和 LangGraph 的区别这里展开说说为什么 Deep Agents 场景下我推荐 LangGraph。AgentExecutor 的问题在于它是一个黑盒循环LLM 输出 → 解析 → 执行 → 结果回填 → 再循环。你只能在循环的开始和结束插入逻辑中间过程无法干预。但 Deep Agents 恰恰需要在中间过程做很多事情压缩上下文、检查状态一致性、判断是否需要人工介入、动态调整工具集。LangGraph 把这些中间环节显式化了。你可以定义这样的图结构入口节点接收任务初始化状态规划节点LLM 做任务规划工具选择节点决定调用哪个工具执行节点实际执行工具调用结果处理节点解析结果更新状态上下文管理节点压缩或扩展上下文错误处理节点分类错误决定重试还是重规划终止判断节点判断任务是否完成每个节点都可以插入自定义逻辑每个边都可以加条件判断。这种粒度对于 Deep Agents 是必需的。4.2 状态结构的设计要点用 LangGraph 重构 Harness第一步是设计状态结构。这个结构会贯穿整个执行流程设计得好不好直接影响后续的开发效率。我的状态结构通常包含这几部分class AgentState(TypedDict): # 任务相关 task_description: str task_status: str # running, completed, failed # 执行轨迹 messages: list # 对话历史 tool_calls: list # 工具调用记录 execution_trace: list # 完整执行轨迹 # 上下文管理 context_summary: str # 压缩后的上下文摘要 key_findings: list # 关键发现 # 错误处理 error_count: int last_error: dict retry_count: int # 环境状态 working_directory: str environment_vars: dict file_system_snapshot: dict这个结构的关键设计点分离 messages 和 execution_trace。messages 是给 LLM 看的需要控制 tokenexecution_trace 是给调试用的可以完整记录。两者分开避免调试信息污染上下文。key_findings 单独维护。Agent 在执行过程中会得出一些关键结论这些结论不应该被上下文压缩丢掉。单独维护一个列表确保关键信息始终可用。环境状态显式记录。不要假设 Agent 知道当前的工作目录和环境变量显式记录在状态里每次决策时都带上。4.3 上下文压缩节点的实现上下文压缩是 Harness 中最难做好的部分。压缩得太狠Agent 丢失关键信息压缩得不够token 爆掉。我的实现思路是分层压缩第一层工具输出摘要。每次工具执行完立即生成一个结构化摘要。比如执行ls -la后摘要成{type: directory_listing, count: 50, notable_files: [config.yaml, main.py]}。原始输出存到 execution_trace摘要进 messages。第二层阶段性总结。每完成一个子任务生成一个阶段性总结。比如已完成环境配置安装了 X、Y、Z 三个依赖。这个总结替换掉之前的多轮对话。第三层全局摘要。当 token 使用超过阈值时触发全局压缩。保留任务描述、关键发现、最近 N 轮对话其余全部压缩成一段摘要。def compress_context(state: AgentState) - AgentState: token_count count_tokens(state[messages]) if token_count COMPRESSION_THRESHOLD: return state # 保留最近 5 轮对话 recent_messages state[messages][-10:] # 压缩早期对话 early_messages state[messages][:-10] summary generate_summary(early_messages) # 重建 messages new_messages [ {role: system, content: f之前的执行摘要{summary}}, *recent_messages ] state[messages] new_messages state[context_summary] summary return state这个实现看起来简单但实际调优需要大量实验。压缩阈值设多少、保留几轮对话、摘要怎么生成这些参数都需要根据具体任务类型调整。4.4 错误处理节点的分类逻辑错误处理节点的核心是分类逻辑。我通常用这样的判断流程def classify_error(error: dict) - str: error_type error.get(type, unknown) error_message error.get(message, ).lower() # 瞬时错误 transient_keywords [timeout, temporarily unavailable, connection reset] if any(kw in error_message for kw in transient_keywords): return transient # 参数错误 if error_type validation_error or invalid argument in error_message: return parameter # 环境错误 env_keywords [not found, permission denied, no such file] if any(kw in error_message for kw in env_keywords): return environment # 策略错误 if error_type strategy_error: return strategy return unknown分类之后不同错误走不同处理路径transient指数退避重试最多 3 次parameter返回详细错误信息给 Agent让它修正参数environment返回错误信息提示 Agent 换方案strategy触发重新规划节点unknown记录并上报可能需要人工介入这个分类逻辑需要根据实际项目不断调整。我建议在初期把分类做得细一点宁可多分几类也不要让不同性质的错误混在一起处理。4.5 从 AgentExecutor 迁移到 LangGraph 的实操步骤如果你现在用的是 AgentExecutor想迁移到 LangGraph我建议按这个顺序来第一步先并行运行。不要直接替换而是让两套 Harness 同时跑对比结果。这样你能发现 LangGraph 版本的问题同时不影响现有系统。第二步从简单任务开始。先迁移那些执行步骤少、工具调用简单的任务验证基本流程。等稳定了再迁移复杂任务。第三步逐步增加节点。不要一开始就把所有节点都加上先实现最基本的循环规划 → 执行 → 判断跑通后再逐步加入上下文压缩、错误处理、安全边界等节点。第四步建立评测基线。迁移前后都要跑同一套评测集用数据说话。我见过有人迁移完觉得感觉变好了但实际评测指标没变甚至变差了。第五步调优参数。LangGraph 版本跑通后针对性地调优各个节点的参数压缩阈值、重试次数、超时时间等。这个迁移过程可能需要几周时间但相比推倒重来风险可控得多。5. Terminal Bench 实战那些只有踩过才知道的坑5.1 环境初始化的隐藏陷阱Terminal Bench 这类评测的环境初始化有很多隐藏陷阱。最常见的是工作目录不一致。你的 Harness 可能默认在某个目录下执行命令但评测环境可能在不同的目录。如果不显式设置工作目录Agent 会在错误的位置找文件。我的做法是在 Harness 初始化时显式设置工作目录并且在每次工具调用时都带上完整路径。不要依赖相对路径不要假设当前目录。另一个坑是环境变量。评测环境的环境变量可能和你本地不一样PATH 可能不包含某些命令某些变量可能未设置。Harness 需要在初始化时检查关键环境变量缺失的要么补上要么在 prompt 里告知 Agent。还有一个容易被忽视的点文件系统状态。评测环境可能有预置的文件也可能需要 Agent 自己创建。Harness 应该在初始化时做一次文件系统快照让 Agent 知道当前有什么。5.2 命令执行的超时与中断处理终端命令可能因为各种原因卡住等待输入、死循环、网络阻塞。Harness 必须设置超时并且能正确处理超时后的状态。我的实现是每个命令调用都设置超时通常 30 秒到 2 分钟根据命令类型调整超时后强制终止进程并返回超时错误给 Agent。关键是要确保终止进程时清理干净不要留下僵尸进程。中断处理也很重要。如果 Agent 在执行过程中被中断比如用户取消Harness 需要优雅地清理资源保存当前状态而不是直接崩溃。import subprocess import signal def execute_command(cmd: str, timeout: int 60) - dict: try: result subprocess.run( cmd, shellTrue, capture_outputTrue, textTrue, timeouttimeout ) return { success: result.returncode 0, stdout: result.stdout, stderr: result.stderr, returncode: result.returncode } except subprocess.TimeoutExpired: return { success: False, error: timeout, message: f命令执行超过 {timeout} 秒被终止 }这段代码看起来简单但实际项目中要考虑的更多进程组管理、信号处理、资源清理。我建议用专门的进程管理库而不是裸的 subprocess。5.3 输出解析的边界情况终端命令的输出格式千奇百怪解析起来比想象中难。几个典型的边界情况输出过长。有些命令会输出大量内容直接塞进上下文会爆 token。Harness 需要做截断或摘要。截断时要保留头部和尾部中间用省略号因为头部通常是命令信息尾部通常是结果。输出包含特殊字符。终端输出可能包含 ANSI 转义码、控制字符、二进制数据。这些内容直接进上下文会干扰 LLM。Harness 需要做清洗去掉 ANSI 码处理不可打印字符。输出编码问题。不同命令的输出编码可能不同有的是 UTF-8有的是 Latin-1。Harness 需要做编码检测和转换避免乱码。输出为空。有些命令成功执行但无输出有些命令失败也无输出。Harness 需要区分这两种情况不能简单地用输出为空判断成功与否。我在实际项目中的做法是对每个常用命令写专门的输出解析器而不是用通用的文本处理。比如ls的输出解析成文件列表git status的输出解析成结构化状态。这样虽然工作量大但可靠性高得多。5.4 多步任务的中间状态验证Deep Agents 跑多步任务时中间状态的验证非常重要。Agent 可能在第 10 步做了一个操作第 20 步才发现这个操作有问题但此时已经基于错误状态做了很多后续操作。Harness 需要在关键步骤后做状态验证。比如文件创建后验证文件确实存在命令执行后验证预期效果达成环境变量设置后验证变量确实生效验证失败时不要继续往下走而是返回错误让 Agent 修正。这比让 Agent 带着错误状态继续跑要高效得多。我踩过的一个坑是Agent 执行了一个配置命令命令返回成功但实际配置没生效因为配置文件路径不对。Agent 以为配置好了继续往下走结果后面所有步骤都失败。如果 Harness 在配置命令后加一个验证步骤就能提前发现问题。5.5 评测指标之外的 Harness 质量评估Terminal Bench 的评测指标是任务成功率但这个指标太粗了。两个 Harness 可能成功率一样但质量差很多。我建议从这几个维度评估 Harness 质量评估维度具体指标为什么重要执行效率平均步数、平均耗时反映 Harness 是否让 Agent 走了弯路错误恢复率出错后成功恢复的比例反映错误处理层的有效性上下文效率平均 token 消耗反映上下文管理的优劣解析成功率工具调用解析成功的比例反映解析层的健壮性可观测性问题定位平均耗时反映执行轨迹层的实用性这些指标比单纯的成功率更能反映 Harness 的真实质量。我在优化 Harness 时会同时关注这些指标避免为了提升成功率而牺牲其他方面。6. 从 Harness 视角重新理解 Agent 开发6.1 Agent 开发学习路线的常见误区网上有很多 Agent 开发学习路线但大多数都聚焦在 Agent 层学 prompt engineering、学 ReAct、学 CoT、学各种推理框架。这些当然重要但如果你只学这些做出来的 Agent 在真实场景中大概率跑不好。我的建议是Agent 开发的学习路线应该把 Harness Engineering 放在和 prompt engineering 同等重要的位置。具体来说入门阶段先理解 Agent 的基本循环LLM 输出 → 工具调用 → 结果回填。这个阶段可以用 LangChain 的 AgentExecutor 快速上手重点是理解流程。进阶阶段开始关注 Harness 的各个模块工具调用解析、状态管理、错误恢复、可观测性。这个阶段建议用 LangGraph 自己搭一套 Harness把每个模块都实现一遍。高级阶段研究不同 Harness 设计的取舍什么时候该压缩上下文、什么时候该重试、什么时候该人工介入。这个阶段需要大量实战跑各种评测集积累经验。我见过很多人卡在入门阶段会用 LangChain 搭个 demo 就觉得自己会 Agent 开发了。但真到工业级场景Harness 的复杂度会指数级上升。6.2 工业智能体项目的 Harness 设计原则工业智能体项目和 demo 的最大区别是可靠性要求高容错空间小。一个 demo 可以接受 70% 的成功率但工业项目可能要求 99% 以上。这种要求下Harness 设计要遵循几个原则原则一显式优于隐式。不要依赖框架的默认行为所有关键逻辑都显式实现。框架的默认行为可能在特定场景下不适用而你根本不知道。原则二可观测性优先。宁可多记录一些信息也不要出问题时无从下手。执行轨迹、状态变更、错误详情全部记录下来。原则三防御性编程。假设所有外部输入都不可靠所有工具调用都可能失败所有 LLM 输出都可能格式错误。每个环节都做校验和兜底。原则四渐进式降级。当某个策略失败时不要直接放弃而是降级到备用策略。比如主模型失败时切换到备用模型主工具失败时切换到备用工具。原则五人工介入通道。再好的 Harness 也有处理不了的情况。设计一个人工介入通道让 Agent 在遇到无法处理的情况时能请求人工帮助。这些原则看起来简单但真正落地需要大量工程投入。我参与过的一个工业智能体项目Harness 的代码量是 Agent 逻辑代码量的 5 倍以上。这个比例在工业场景下是正常的。6.3 关于 Agent 框架选择的个人建议最后聊聊 Agent 框架的选择。现在市面上的框架很多LangChain、LangGraph、AutoGen、CrewAI、还有各种自研框架。怎么选我的建议是分场景快速验证想法用 LangChain 的 AgentExecutor上手快代码少。需要精细控制用 LangGraph显式状态管理控制粒度细。多 Agent 协作考虑 AutoGen 或 CrewAI它们对多 Agent 场景有专门支持。工业级项目建议自研 Harness或者基于 LangGraph 深度定制。通用框架很难满足工业级的可靠性和可观测性要求。不管选哪个框架核心是要理解 Harness 的各个模块在做什么。框架只是工具Harness Engineering 的思路才是核心。理解了思路换框架只是换个实现方式而已。我在实际项目中的体会是Agent 开发的上限由模型决定下限由 Harness 决定。模型能力再强Harness 不行Agent 也跑不好。反过来模型能力一般但 Harness 设计精良Agent 也能在特定场景下表现不错。所以如果你在做 Deep Agents花时间打磨 Harness 是值得的。这个领域还在快速演进新的框架、新的评测、新的最佳实践不断出现。保持学习保持实践把每次踩坑都变成经验积累这可能是 Agent 开发最实在的成长路径。