自建Agent Harness:决定智能体上限的行为骨架

自建Agent Harness:决定智能体上限的行为骨架 最近一段时间agent harness 这个词在开发圈里出现的频率高得吓人。无论是 DeepSeek harness、Codex harness 这类“模型专属 harness”还是围绕 skill、memory、工具编排的讨论大家都在试图回答同一个问题当 agent 的能力边界被外部工具和上下文不断撑大时我们靠什么来保证它不失控Elvis Saravia 的建议其实点破了这层窗户纸——与其到处找现成的 agent 框架来“省事”不如亲手自建并掌控那个连接模型、工具与人的 harness。这不是情怀也不是逆技术潮流而动而是一个非常现实的工程判断真正决定 agent 上限的不是某个大模型有多聪明而是你给这个模型套了一个什么样的“骨架”。这篇文章我会从 harness 到底是什么讲起拆解它为什么值得你亲手搭再给出一条可落地的自建路径顺便把我在实操中踩过的坑一并交代清楚。无论你是刚接触 agent 开发的新手还是已经被框架追着跑的工程老手这篇文章应该都能给你一些不一样的参考。1. 先搞清楚 harness 到底是什么——以及它为什么不该被“框架”两个字带偏很多人一听“agent harness”第一反应是“这不就是 agent 框架吗”。这个词本身是有迷惑性的因为它和 framework、platform、SDK 这些词在中文语境里经常被混着用。但我想先说清楚一件事harness 和 frame work 虽然在实际项目中会重叠但它们解决的问题根本不一样。1.1 harness 的工程本义不是脚手架是安全绳harness 这个词在英文里原意是马具、安全带引申到工程领域它指的是“把某个东西安全地连接到一个更大的系统上”的那套约束装置。你去户外攀岩身上的 harness 不是用来替代你攀爬的而是保证你即便失手也不会直接摔下去。它管的是“连接方式”和“失控边界”。放到 agent 的场景里harness 就是介于大模型和外部世界工具、API、文件系统、数据库、甚至另一个 agent之间的那一层。它负责三件事告诉模型“你现在能做什么、哪些动作可以做”把模型的意图翻译成真实可执行的工具调用把执行结果正确地反馈给模型让循环能继续下去这三件事听起来简单但每件事做深了都是一个大坑。比如“告诉模型能做什么”就涉及 prompt 模板、工具描述、技能注册“翻译意图”涉及函数调用协议、参数校验、工具路由“反馈结果”涉及上下文压缩、错误处理、记忆写入。你把这套东西叠在一起它就是 agent 的“驾驶舱装置”。所以 harness 和 framework 的区别在哪框架是“盖房子的脚手架”它给你搭好结构你往里面填功能而 harness 是“驾驶员和方向盘之间的连杆机构”它决定了模型每一次思考之后动作怎么产生、怎么被约束、怎么被记录。你可以用现成的 framework 来盖 agent 这栋楼但如果 harness 不在自己手里你就永远像是坐在一辆油门刹车都被别人焊死的车里。1.2 agent harness 的具体组件清单不把范围界定清楚讨论就容易变成空谈。我自己的经验是一个合格的 agent harness 至少要包含下面这些组件组件职责失控后果模型接入层统一封装不同 LLM 的调用接口模型供应商一升级全部逻辑重写指令与提示管理维护 system prompt、skill 按需装载上下文膨胀指令互相打架工具注册表登记可用工具及其参数 schema模型调用幻觉工具参数无法对齐决策循环规划-执行-观察-再决策的主循环agent 行为没有终止条件死循环烧钱记忆模块短期上下文 长期持久化 压缩策略模型持续“失忆”多轮任务完全不可靠安全策略权限校验、确认机制、沙箱执行高危操作执行到底追责无门观测与日志记录每一轮输入输出、token 消耗、决策路径出错只能靠猜根本无法定位问题这张表里的每一行都是我在实际项目里真实趟过的需求不是从文档里抄来的理想模型。大家听过的“agent 八股”里那些面试题——agent 记忆怎么设计、工具调用失败怎么办、上下文窗口不够怎么处理——背后对应的其实都是 harness 里某一个组件的设计取舍。1.3 harness 和 agent 的边界感再补充一个容易混淆的点harness 和 agent 本身不是一回事。agent 是一个更宏观的概念它指代那个“能感知、能决策、能行动”的整体系统harness 是这个系统里那个负责“承载和约束”的机械部分。打个比方一台自动驾驶汽车整车是 agent方向盘、刹车、油门、传感器信号线束这些是 harness。你换一个大模型相当于换发动机但你还是要通过同一套线束和踏板把动力传到轮子上。如果这套线束是黑盒你根本不知道发动机转速信号到了变速箱之后发生了什么。这也是为什么我觉得“依赖别人的 harness”和“掌控自己的 harness”差异巨大——前者你只在配置别人定义好的行为边界后者你在定义行为边界本身。2. 为什么 Elvis 的建议戳中了当前 agent 开发的命门我认真观察过身边团队用 agent 框架的方式。大多数人是这样的选一个看起来最热的框架跟着文档把第一个 demo 跑通然后开始往里面堆工具、堆 prompt看起来一切正常。直到某一天 agent 在一个极端情况下出现了诡异行为——比如反复调用某个工具、把不该删的文件删了、或者在一个简单问题上陷入死循环——然后你打开框架源码开始排查发现里面层层封装了几层抽象你根本不知道决策循环里到底发生了什么。这就是现成框架的隐性成本。2.1 现成框架掩盖的“掌控权”问题市面上大多数 agent 框架都在做同一件事把复杂的技术细节藏起来让你用更少的代码实现一个 agent。这对 demo 阶段极其友好但对生产阶段非常不友好。原因很简单agent 不是传统软件它的行为不可枚举。传统软件里函数输出由代码决定输入相同必定输出相同agent 由模型驱动同样的 prompt 和工具列表两次运行结果可能完全不同。这意味着你没有任何“测试通过就是好的”这种安全感你必须能在行为出现偏差时快速定位是哪个环节出了问题——是模型理解错了是工具描述有歧义是上下文被截断了还是决策循环进入了死路径如果你用的是别人的 harness这四类问题你都要去读别人的源码、理解别人的设计意图、再考虑怎么改。而如果你是用自己掌控的 harness定位问题的路径就短得多——每一条链路都是自己写的哪怕再不优雅你知道哪里会出问题。2.2 从“模型专属 harness”流行能看到什么你会注意到一个现象DeepSeek harness、Codex harness 这种“模型专属”的 harness 在搜索热度里居高不下。这说明很多人已经意识到不同模型对工具调用的理解方式不一样对上下文格式的偏好不一样连 function calling 的返回格式都可能存在差异。同一个工具描述GPT 系、Claude 系、DeepSeek 系读出来的重点可能完全不同。这种情况下通用框架为了保证覆盖面通常会做一层“协议转换”把不同模型之间的差异抹平。这个抹平的过程是有代价的它意味着框架必须选择一套中间表示而你的所有 prompt、工具描述、返回解析都要经过这层转换。一旦模型行为出现偏差你很难判断到底是模型本身的问题还是中间层转换引入的问题。反过来如果 harness 是自己的你可以针对你正在用的模型做深度优化。比如给 DeepSeek 写更简洁的工具描述、给某个模型关掉它用不上的 function calling 开关、针对模型容易漏参数的习惯在 schema 里做校验提示。这种优化完全属于“经验活”框架给不了你。2.3 掌控的本质把决定 agent 行为骨架的代码留在自己手里Elvis 的建议可以提炼成一句朴素的话你可以用别人的轮子但方向盘必须在自己手里。落实到工程上就是 agent 的行为骨架——决策循环、终止条件、工具契约、安全策略、上下文管理——这些代码无论你用不用框架都要确保是自己能够随时改写、随时替换的。这不是说所有轮子都要自己造而是说“连接装置”要自己掌握。就像你不会把汽车的转向系统外包给第三方然后祈祷它永远不出故障一样你也不应该把 agent 最核心的行为逻辑外包给一个你不知道内部发生了什么的开源库。3. 自建 harness 的边界你真正需要掌控的是这五个环节说到自建很多人下一个问题是到底要建到什么程度我的答案是不需要把 MCP、协议解析、服务发现这些东西全造一遍但下面五个环节必须牢牢抓在自己手里。这五个环节是决定 agent 行为质量和安全边界的关键也是我觉得“掌控 harness”这句话的真正含义。3.1 决策循环不只是 ReAct而是要能插桩、能中止、能回退大多数 agent 框架采用 ReActReason-Act模式模型先思考然后决定调用哪个工具拿到结果再思考如此循环。这个模式没问题问题是很多框架把循环的细节完全封装了。你只知道“这个循环在跑”但不知道这个循环是怎么判断“该停了”、怎么处理“工具调用失败”、怎么决定“这件事我搞不定了需要人类介入”的。我建议自建的决策循环至少要包含以下能力显式的终止条件最大轮数、无进展阈值、token 预算上限三者任一满足就要强制停止可插桩的中间态每一轮决策前可以注入回调比如告警、权限确认、指标上报失败回退路径工具调用失败后不能简单重试要区分“参数错了”“工具不存在”“环境超时”给出不同处理策略一个很现实的场景agent 在使用网页搜索工具时返回了超时如果你的 harness 只是简单让模型“再试一次”模型可能会连续重试 5 次白白消耗 token 和时间。但如果 harness 能识别这是超时类错误就可以直接切换备选工具或者把当前问题拆解成更细粒度的小任务再执行。这两种结果的差距在真实业务里往往是天壤之别。3.2 工具契约与权限边界告诉 agent“手能伸多长”工具是 agent 触达世界的唯一通道。你在 harness 里给模型开放哪些工具、每个工具的输入输出定义成什么样、工具可以操作哪些资源直接决定了 agent 的边界。工具契约这里我吃过不小的亏。刚开始我习惯把工具描述写得很详细觉得描述越丰富模型就越理解。但实际上工具描述的信息熵一旦超过某个阈值模型反而更容易误用。比如我描述一个“文件写入工具”的时候写了一大段关于编码格式、路径规则、追加模式的说明结果模型在调用时反而经常把参数填错。后来我改用了一种“工具使用说明书”写法工具名称尽量用动词短语一眼看出功能参数列表用 JSON Schema 精确约束类型和枚举值使用时机说明用三句话以内告诉模型什么场景该用一个步步示例让模型能模仿调用格式这样下来工具调用的准确率比之前明显提升。工具契约这件事跟代码注释有点像不是越多越好而是该说的说透、不该说的不干扰。权限边界是另一层。每个工具都应该挂上权限标记比如“只读”“可写”“危险操作”。harness 在执行前要做一次静态检查如果模型要调用一个写权限的工具就触发权限确认流程。别小看这个机制它能在很多灾难发生前拦住 agent。3.3 记忆与上下文管理掌握压缩策略的人才真正掌握 agent上下文是 agent 的命。模型一天的记忆只有上下文窗口那么大窗口之外的一切都需要 harness 来管理。这里涉及三个子问题短期上下文管理对话多轮之后上下文可能会塞满。你需要决定哪些内容可以留在窗口里哪些内容应该被压缩或移出。常见策略有窗口滑动、摘要替换、关键信息提取等。我比较推荐“结构化摘要 原始片段保留”的组合方式先让模型对旧对话生成结构化摘要包含任务目标、已完成的步骤、已获取的关键信息然后释放旧的原始片段只保留近几轮的完整内容。长期记忆持久化跨会话的记忆要存到外部存储比如向量数据库或普通 KV 存储。这里的核心设计问题是“什么值得记”。我建议记三类东西用户偏好、领域知识工具返回的高价值信息、失败经验之前做错了什么、怎么纠正的。其他信息不进长期记忆减少噪声。压缩策略的可回归性这是最容易被忽略的一点。上下文压缩策略一旦出错agent 会“失忆”——明明前面已经决定了方案A压缩之后模型以为方案是B于是后续动作全部偏航。所以我后来一直坚持每次调整压缩策略都要用一套固定的测试任务集跑回归不能拍脑袋上线。3.4 可观测性与调试harness engineering 的核心就是“让行为可解释”很多人低估了 log 在 agent 项目里的价值。agent 和传统程序不一样传统程序出 bug 可以打断点、看堆栈、复现agent 出问题经常是不可复现的——同样的输入换个时间跑结果就不同了。所以你必须把每一步行为都记录下来才有机会事后复盘。我自己设计 harness 日志时会强制要求每一轮循环输出以下内容模型本次请求的完整输入system prompt 工具列表 历史摘录模型原始返回完整 JSON不做任何裁剪解析后的工具调用工具名、参数、置信度工具执行结果成功/失败、返回值、耗时本轮决策的关键指标token 消耗、轮次、当前上下文占用率是否有异常分支重试、权限确认、命令中止这些日志全部落盘到结构化文件JSONL 格式就行然后接入统一的查询面板。这样当用户说“agent 刚才突然干了件怪事”你能在十分钟内把它之前二十轮的决策路径完整调出来逐环节分析。没有这套机制你根本谈不上“掌控”自己的 agent。3.5 安全护栏它不是事后加的一层而是 harness 的骨头我把安全放在最后压轴因为它最容易被忽略但出事时后果最严重。agent 安全不是“加一层内容过滤”那么简单真正的护栏应该在 harness 的多个位置同时生效第一层工具权限。上面提过的工具声明阶段就标注权限级别。没有权限标记的工具harness 默认是拒绝调用的。第二层调用前审批。高危操作删除、写库、发送消息、支付类必须走确认流程。确认可以做成三种模式完全自动低危、静默记录中危执行后记录、显式审批高危执行前阻塞等待。第三层执行沙箱。agent 执行代码类工具时不能直接在本机裸跑。最低限度也要用容器隔离、限制网络、限制文件系统访问。第四层输出过滤。模型返回给用户的最终输出需要经过一层敏感信息过滤防止 agent 把内部工具返回的密钥、用户隐私信息直接原样透露出来。这四层不是可选配置而是基座设施。我见过一个团队没有做工具权限控制agent 在一次演示中把数据库里的测试表清空了当时整个演示区都安静了。还好是测试环境如果是生产环境这已经算重大事故了。安全这东西永远不该等出了事再补。4. 从零起步一个最小 agent harness 的搭建过程讲了很多概念接下来进入实操。这一节我会展示如何用最朴素的方式从一个空白项目开始搭建一个可运行的最小 harness。目标不是让你一步到位而是让你理解每块零件为什么存在、怎么咬合为你的自建之路打一个地基。4.1 先别上框架用最朴素的代码定义决策循环第一步不要急着选框架先用最朴素的 Python 代码写一个决策循环。核心结构大概是这样的def run_agent(task, max_rounds10, budget_tokens5000): messages [{role: system, content: build_system_prompt()}] messages.append({role: user, content: task}) history [] for round_idx in range(max_rounds): # 1. 计算当前轮次的 token 消耗超过预算就强制终止 if estimate_tokens(messages) budget_tokens: return finish_with_notice(history, reasontoken_budget_exceeded) # 2. 调用模型拿到带工具调用的响应 response call_llm(messages, toolsregistered_tools()) # 3. 记录原始响应到日志便于事后回溯 append_log(round_idx, model_response, response) # 4. 判断如果模型没有工具调用说明任务结束 tool_calls extract_tool_calls(response) if not tool_calls: return finish_success(history, response) # 5. 逐个执行工具调用把结果追加到消息里 for call in tool_calls: if not check_permission(call[tool_name]): return finish_with_notice(history, reasonpermission_denied) result execute_tool(call) messages.append(format_tool_result_message(call, result)) # 6. 记录本轮的决策关键指标 append_log(round_idx, metrics, { tokens: estimate_tokens(messages), round: round_idx, tool_calls: [t[tool_name] for t in tool_calls], }) return finish_with_notice(history, reasonmax_rounds_reached)这个循环只有不到 30 行有效逻辑但它包含了所有核心要素终止条件、预算控制、工具执行、权限检查、日志记录。你先把这个跑通再谈其他。别急着抽象。很多人写到这里就会想着把它封装成基类、做依赖注入、搞配置系统——这些先统统放下等代码跑到第二三个月你自然知道哪些地方需要抽象那时候再重构不迟。4.2 工具注册表的最小实现先手工写三个工具工具注册表建议从“手工写三个工具”开始而不是直接接 MCP 或一大堆现成插件。三个工具就够了比如一个计算器、一个文件读取器、一个网络搜索器。分别是三个不同方向的代表纯逻辑、本机资源、外部信息源。用装饰器实现一个极简注册表逻辑非常直观_TOOL_REGISTRY {} def register_tool(nameNone, schemaNone, permissionread): def decorator(func): tool_name name or func.__name__ _TOOL_REGISTRY[tool_name] { func: func, schema: schema, permission: permission, } return func return decorator register_tool( schema{ type: object, properties: { expression: {type: string, description: 数学表达式如 (12)*3}, }, required: [expression], }, permissionread, ) def calculator(expression: str): # 此处仅做演示实际应使用 ast 等方式安全求值 return eval(expression) register_tool( schema{ type: object, properties: { path: {type: string, description: 文件路径}, }, required: [path], }, permissionread, ) def read_file(path: str): with open(path, r, encodingutf-8) as f: return f.read(2000)手工写三个工具的价值在于你会被迫思考“模型看到的工具描述是什么样”“参数校验怎么设计”“返回值怎么格式化”。这些手感是从别处拿不来的而等你把这三个工具调顺了再接入 MCP、再接入官方 SDK逻辑迁移就很轻松。4.3 日志先行功能还没调好先把“案发现场”留好这个习惯是我强烈建议你现在就开始做的。在 agent harness 里日志不是“事后想起来再补”而是所有开发工作的起点。我甚至建议把日志模块放在工具注册表之前实现。具体做法JSONL 文件按日期切割每条日志带时间戳和 trace_id每个会话分配一个 trace_id所有轮次共享日志层级分为调用记录模型输入输出、执行记录工具调用和结果、指标记录token、耗时、轮次、异常记录权限拒绝、超时、解析失败当这些日志叠加在一起你就拥有了一套天然的“决策回放系统”。一旦 agent 行为诡异可以直接搜 trace_id 把全程拉出来复盘。这比什么可视化面板都实在。4.4 渐进式替换什么时候可以考虑引入社区 harness自建到一定程度之后你可能会发现有些外围功能自己写确实不划算。比如要支持的模型越来越多、要接的工具越来越多、要跑的评估体系越来越复杂——这时候可以考虑把社区 harness 引进来但必须是“内核自持有、外围可替换”的模式。我的建议是决策循环、权限检查、上下文管理、日志这些核心代码始终保留在自己手里协议解析、工具 SDK、模型接入这些底层组装类的部分可以用开源实现。把 harness 当作一套“插座”核心是自己的外围的零件可以插上社区方案但插座本身不能被别人拿走。5. 现有 harness / 框架怎么选——抄作业的正确姿势自建不意味着闭门造车。社区里已经有很多优秀的实现就算你不直接用也值得把它们当作参考教材来读。现在市面上的 harness 大体可以分成几类搞清楚它们各自解决什么问题你就能做出更合理的取舍。5.1 “模型专属 harness”到底是什么——以 DeepSeek harness、Codex harness 为例你搜索的时候会看到 DeepSeek harness、Codex harness 这类名词。很多人第一次看到会以为它们是官方发布的重型框架其实多数情况并不是。所谓“模型专属 harness”本质上是针对某类模型的工具调用习惯、上下文格式、function calling 能力做了一组适配和优化的 harness 配置或插件。比如某些模型对 function calling 的 JSON 格式要求比较严格对参数顺序敏感这时候通用的协议栈可能经常解析失败而专门针对它优化的 harness就知道应该在哪些位置加容错、哪些字段可以缺省。这解释了为什么大家纷纷去搜“deepseek harness 安装”“deepseek harness 插件”——因为实际使用中确实发现通用框架和模型之间经常出现“接口对不齐”的摩擦。我建议把这些模型专属 harness 当作“最佳实践参考”它们展示了同一套模型接入逻辑在不同模型下可以怎么差异优化。你完全可以阅读它们的源码把其中针对特定模型的适配逻辑抽出来融进自己的 harness 里。5.2 自建与社区 harness 的折中方案完全自建和完全用框架之间存在大量的中间地带。我自己的实践经验是“内核自持有外围用开源”具体怎么切分可以参考下面这个判断表模块建议方式理由决策循环自建这是 agent 的行为中枢必须随时可改可插桩上下文压缩自建压缩策略和业务强相关通用策略效果有限安全护栏自建安全策略要贴合自己的业务风险模型日志格式与查询自建决定你排查问题的效率不可将就工具调用协议可用社区实现协议本身有标准采用成熟实现省精力模型接入 SDK用官方 SDK官方维护接口稳定没必要重造轮子监控面板可接开源可视化展示可以借助现成工具核心数据留本地这些模块之间的边界不是死的但它给你一个思考框架凡是可以算作“行为决策”的部分自己掌握凡是“连接和展示”的部分可以借力。5.3 什么情况下尽量不要自建自建不是万金油有些情况我是真心劝你不要自建。第一种你还在做产品验证期核心目的是快速搭一个 demo 验证市场需求这时候自建 harness 是纯粹的浪费时间。用最快的框架把东西跑出来、把用户反馈收回来比什么都重要。第二种团队里没有做过 LLM 工程的人对模型行为特性还没有体感这时候自建容易把一堆工程上的坏味道沉淀进去。不如先拿框架跑一段时间积累经验后再考虑自建。第三种你的诉求只是做一个标准化的知识库问答 agent不需要复杂的工具调用和记忆管理那直接用成熟的 RAG 方案就够了没必要上 harness 这种重型结构。自建的正确时机是你已经深刻感受到“现成框架的某一层在阻碍你”且你能具体说出是哪个环节、哪种场面下出了问题。到那时候再动手也不迟。6. 我在自建 harness 过程中踩过的坑和最终体会最后分享几个让我印象深刻的踩坑经历。这些东西没法从任何文档里学到全是实打实换来的教训。6.1 坑一工具协议第一版设计得太“完美”agent 反而不工作了我第一次做工具协议时花了两周时间设计了一套非常严密的工具契约系统包括中间表示层、参数类型推导、自动重试策略、甚至还有一套给模型看的 DSL。结果模型调用工具的准确率反而特别低排查发现问题是工具调用时模型要读懂那套复杂的 DSL 才能正确构造参数而 DSL 的转换规则模型始终“理解”不彻底。解决方案很朴素——把 DSL 删掉直接让模型输出 JSON解析器加宽容错。失败率立刻降下来了。我后来总结出一条规律给模型的接口越接近它原生输出的格式越好。任何“翻译层”“抽象层”都会引入理解偏差。模型说“人话”你就尽量让人话直达工具边界少做格式转换。6.2 坑二所有指令都塞进 system prompt上下文爆炸一开始我恨不得把所有规则都写进 system prompt包括工具使用细则、输出格式要求、边界提醒、用户偏好……系统提示词一度写到了四千多字。结果 agent 不仅响应变慢还经常忘事——太长的前缀把真正重要的任务指令都给稀释了。后来我把这个做法推翻改成“按需装载”的思路把各种规则拆成独立的 skill 模块每个模块带触发条件和调用入口。任务开始时只加载最基础的 system prompt当 agent 判断当前场景需要某个 skill 时再由 harness 把对应模块动态追加到上下文里。这样做之后上下文占用下降了接近一半模型对关键指令的遵循度也提高了很多。这也是为什么我觉得 skill 机制和 agent 记忆必须由 harness 层来管理而不是一股脑塞给模型自己处理。6.3 坑三安全护栏上线太晚一次演示差点变成事故前面提到过工具权限控制的事我再具体讲讲。当时我们的 harness 已经接了十几个工具但没有做精细的权限分级。一次给客户做演示时agent 在执行某条指令时调用了一个“删除测试数据”的工具因为没有配置确认流程它在几秒内就把演示环境的测试表清空了。虽然影响范围可控但整个团队都冒了冷汗。这之后我把安全护栏直接提到了开发流程的最前面每个工具注册时必须声明权限级别高危操作一律走显式审批执行环境统一隔离。用一句话总结我的体会安全不是 agent 做好之后的附件而是 harness 设计的第一前提。6.4 一个近期一直在用的小技巧eval 驱动的 harness 演进最后分享一个让我受益最多的工程习惯每次修改 harness 的任何环节都要跑一遍固定的回归测试集。这个测试集不用很大二十个任务就够但覆盖面要广跨工具协作、长上下文推理、错误恢复、权限拦截、记忆查询。任务跑完以后统一对比结果重点关注三个指标任务成功率、平均轮次、平均 token 消耗。不要小看这三组数据。任务成功率只告诉你“行不行”平均轮次告诉你 agent 有没有在无效循环里打转平均 token 消耗则直接影响项目成本。我每次想动上下文压缩策略或者工具描述格式都会先跑一遍这个回归集用数据而不是感觉来做决策。这套机制让我在 harness 不断演进的过程中几乎没有出过大岔子。我在实际项目里越来越深刻地感受到Elvis 的建议与其说是在劝大家“别用框架”不如说是在劝大家“别把自己的核心决策权外包出去”。agent 开发的难度不在于把某个模型调通而在于你能否对那个“看似智能”的循环保持真正的掌控力。自建 harness 的过程本质上就是建立掌控力的过程。这个投入短期内看起来不如直接套框架划算但当你的 agent 开始复杂到需要调试行为、控制成本、守住安全边界的时候你会发现之前的每一分投入都在回本。