1. 先聊聊这个项目到底在做什么一个人九个月二十万行代码每个月消耗四十亿以上的 token——这几个数字摆在一起任何一个写过代码的人都会先愣一下。不是因为它有多夸张而是因为它太具体了。二十万行代码意味着什么如果按每天有效编码四小时算九个月大概是二百七十天平均每天要产出七百多行能跑、能维护、能迭代的代码。而每月四十亿 token 的消耗量换算成日常使用场景相当于每天都在让模型处理海量的上下文、生成大量的结构化内容、反复做推理和校验。这个项目的核心是围绕Harness 架构构建一款应用。这里说的 Harness不是某个具体的库或者框架名字那么简单它代表的是一种工程思路把 AI Agent 的能力像套具一样“架”在现有的工作流、知识库和工具链之上让模型不是孤立地回答问题而是真正参与到任务的执行、状态的维护和结果的交付中。热词里出现的deepseek harness、harness anything、harness engineering、阿里 harness creator skill这些词其实都指向同一个方向——大家正在尝试把 Agent 从“聊天玩具”变成“生产工具”。那这款应用到底解决什么问题简单说它要处理的是知识工作者的上下文断裂问题。你可能有 Obsidian 知识库里面有几千篇笔记你可能用 Claude Code 或者类似的工具写代码你可能需要把 Markdown 表格转成 Excel把会议记录整理成结构化文档把零散的想法串成可执行的方案。这些动作单独做都不难难的是让它们在一个统一的 Agent 执行框架里自动流转起来。Harness 架构要做的就是给 Agent 套上一副“挽具”让它能拉着你的知识库、工具链和输出格式往前走而不是每换一个任务就要重新教它一遍。适合谁来参考如果你正在搭自己的 Obsidian 知识库或者想用 Claude Code 做点自动化的事情又或者你对 Agent 开发有兴趣但不知道从哪里下手这个项目的思路和踩坑记录应该能帮你省下不少时间。哪怕你只是好奇“一个人怎么写出二十万行代码”后面的内容也会给你一个真实的答案——不是靠手速是靠架构和工具链的配合。2. 为什么选 Harness 架构而不是直接调 API2.1 直接调 API 的困境在哪里很多人做 Agent 项目的第一步就是写一个循环用户输入 → 调模型 → 解析输出 → 执行动作 → 把结果塞回上下文 → 再调模型。这个循环写起来很快几十行代码就能跑通一个 demo。但当你把它放到真实场景里问题会一个接一个冒出来。第一个问题是状态管理。模型本身是无状态的每次调用都要把历史上下文重新传进去。如果你的任务需要跨天、跨会话、跨设备继续执行你就得自己维护一个状态存储层。这个层要处理序列化、版本兼容、并发读写、失败恢复写到最后你会发现光是状态管理就占了整个项目一半的代码量。第二个问题是工具调用的可靠性。模型输出的工具调用参数经常是“看起来对但实际跑不通”的。比如它让你读一个文件路径里可能多了一个空格它让你执行一个命令参数顺序可能是反的。你需要一层校验和重试机制还要能区分“模型错了”和“工具本身挂了”。第三个问题是上下文窗口的浪费。每次调用都把全部历史塞进去token 消耗是指数级增长的。四十亿 token 一个月如果按每百万 token 几块钱算账单是很可观的。你需要做上下文压缩、摘要、检索增强而这些逻辑如果散落在业务代码里维护起来就是噩梦。2.2 Harness 架构的核心思路Harness 架构的本质是把上面这些脏活累活抽出来做成一个可配置的执行层。你可以把它想象成马具马还是那匹马模型但有了挽具之后它能拉车、能耕地、能按缰绳的方向走而不是到处乱跑。具体来说Harness 层要提供几个关键能力。第一是统一的工具注册与发现机制。你写一个工具声明它的名称、参数 schema、执行函数Harness 负责把它暴露给模型并在模型调用时做参数校验和结果封装。第二是上下文生命周期管理。Harness 决定哪些历史要保留、哪些要压缩、哪些要从外部知识库检索回来。第三是执行状态机。一个任务可能包含多个步骤Harness 要记录当前走到哪一步、下一步该做什么、失败了怎么回滚。热词里提到的harness engineering和harness creator skill其实就是在说这套东西的工程化实践。你不是在写一个脚本你是在设计一套让 Agent 可靠运行的“操作系统”。2.3 为什么是 Markdown 和 Obsidian 作为知识底座这个项目选择 Markdown 作为核心格式Obsidian 作为知识库载体是有实际考量的。Markdown 是纯文本模型处理起来 token 效率高不像 JSON 或者 HTML 那样有大量冗余标签。Obsidian 的库本质上就是一个文件夹里面全是.md文件你可以用 Git 做版本管理可以用脚本做批量处理可以用插件扩展功能。更重要的是Obsidian 的双向链接和标签系统天然适合做知识检索。当 Agent 需要查找相关信息时它不需要做复杂的向量检索直接沿着链接和标签走就能找到相关笔记。热词里的obsidian git、obsidian插件推荐、obsidian知识库搭建这些都是这个生态里的常见话题。把 Agent 架在 Obsidian 上相当于给它配了一个结构化的、可编程的外部记忆。3. 核心模块拆解与实操要点3.1 工具层怎么让模型稳定地调用外部能力工具层的设计目标很简单模型说“我要做 X”Harness 能可靠地执行 X 并返回结果。但实现起来有几个坑。第一个坑是参数校验。模型输出的参数经常是“差不多对”的。比如它要创建一个文件路径写成了./notes/ meeting.md中间多了一个空格。如果你直接拿这个路径去创建文件可能会创建一个名字奇怪的文件或者直接报错。我的做法是在工具注册时给每个参数定义严格的类型和格式约束Harness 在执行前先做一轮校验不通过就返回错误信息让模型重试。第二个坑是超时和重试。有些工具调用可能很慢比如调用外部 API 或者处理大文件。如果 Harness 没有超时机制整个 Agent 循环就会卡死。我的配置是普通工具超时 30 秒网络类工具超时 60 秒超时后自动重试一次重试还失败就返回错误让模型决定下一步。第三个坑是结果格式化。模型需要的是结构化的、简洁的结果而不是原始的工具输出。比如你执行了一个ls命令返回了几百个文件直接塞给模型会浪费大量 token。Harness 应该在返回前做一层过滤和摘要只把最相关的信息给模型。下面是一个工具注册的示例结构用 Python 伪代码展示class Tool: name: str description: str parameters: dict # JSON Schema execute: callable def register_tool(tool: Tool): # 校验参数 schema 合法性 validate_schema(tool.parameters) # 注册到全局工具表 tool_registry[tool.name] tool # 生成给模型看的工具描述 return generate_tool_prompt(tool)注意工具描述的文字要反复打磨。模型能不能正确调用工具很大程度上取决于描述写得清不清楚。我试过同一个工具描述改了三版调用成功率从 60% 提到了 95%。3.2 上下文层四十亿 token 是怎么烧掉的每月四十亿 token听起来很多但拆开看就明白了。假设你有一个中等规模的知识库五千篇笔记每篇平均五百字全部加载进去就是两百五十万字按中文粗略估算大概是三百多万 token。如果每次任务都要把这三百多万 token 塞进上下文一天跑一百次任务那就是三亿多 token。一个月下来四十亿 token 一点都不夸张。所以上下文层的核心任务是做减法。我的策略是三层过滤第一层是元数据过滤。每篇笔记都有 frontmatter里面记录了标签、创建时间、修改时间、关联项目。当 Agent 需要查找信息时先根据元数据缩小范围只加载相关的笔记。第二层是摘要压缩。对于必须加载的长文档先用模型生成一个摘要把摘要放进上下文原文留在外部存储。如果 Agent 需要看原文再通过工具调用去取。第三层是滑动窗口。对话历史只保留最近 N 轮更早的历史要么丢弃要么压缩成一句话摘要。N 的大小取决于任务复杂度我一般设 10 到 20 轮。热词里提到的markdown换行、markdown语法、markdown表格转换excel这些其实都和上下文处理有关。Markdown 的格式细节会影响模型的理解比如表格的管道符对齐、换行的处理方式如果不统一模型解析起来就容易出错。我的做法是在 Harness 层做一次格式规范化把所有 Markdown 统一成标准格式再喂给模型。3.3 执行层Agent 循环怎么设计才不失控Agent 循环的基本逻辑是观察 → 思考 → 行动 → 再观察。但如果没有约束这个循环可能永远跑下去或者陷入死循环。我的设计里加了几个硬约束。第一是最大步数限制。一个任务最多执行 50 步超过就强制终止并返回当前结果。第二是重复动作检测。如果模型连续三次调用同一个工具、传同样的参数Harness 会拦截并提示模型换一种方式。第三是人工确认点。对于删除文件、发送请求、修改外部系统这类不可逆操作Harness 会暂停执行等待人工确认后再继续。这些约束看起来简单但实际写起来要考虑很多边界情况。比如“同一个工具、同样的参数”怎么判断参数里可能有时间戳或者随机 ID每次都不一样。我的做法是对参数做归一化去掉时间戳、排序键值对再做哈希比较。热词里的agent execution terminated due to error这个报错我遇到过很多次。大部分情况是因为工具执行抛了未捕获的异常导致整个循环崩溃。解决办法是在工具执行层加一个全局的 try-catch把异常转换成模型能理解的错误信息让模型决定是重试还是换方案。4. 九个月二十万行代码是怎么堆出来的4.1 代码结构不是一个人写得多是架构让代码自己长出来二十万行代码如果全靠手写九个月是绝对写不完的。关键在于代码生成和代码复用。我的项目里大概有百分之四十的代码是模型生成的。不是让模型随便写而是我定义好接口和测试用例让模型填充实现。比如工具层的每个工具结构都是一样的定义参数 schema、写执行函数、写单元测试。我把这个模式抽象成一个模板模型只需要填业务逻辑剩下的样板代码自动生成。另外百分之三十是配置和声明式代码。Harness 架构的一个好处是很多行为可以通过配置文件定义而不是写死在代码里。比如工具的超时时间、重试次数、上下文窗口大小都放在 YAML 文件里。这样调整行为不需要改代码改配置就行。剩下的百分之三十才是手写的核心逻辑主要是状态机、错误处理、上下文压缩算法这些需要精细控制的部分。4.2 开发节奏每天怎么安排时间九个月里我的日常节奏大概是这样的。早上两小时做设计和规划把当天要做的任务拆成小步骤每个步骤不超过两小时。上午剩下的时间写核心代码这时候不碰模型纯手写。下午用模型辅助写样板代码和测试同时跑集成测试。晚上花一小时做复盘记录当天遇到的问题和解决方案。这个节奏的关键是把创造性和机械性工作分开。写核心逻辑的时候需要深度思考不能被模型打断。用模型辅助的时候要先把任务拆得足够细细到模型能一次做对。如果让模型做一个模糊的大任务它大概率会跑偏你修它的时间比自己写还长。4.3 版本管理二十万行代码怎么不混乱代码量大了之后版本管理就是生命线。我的做法是主干开发加短分支。所有功能分支从主干切出来最多活两天做完就合并回去。合并前必须跑通全部测试测试覆盖率低于百分之八十不允许合并。另外我用 Git 的 hook 做了自动化检查。每次提交前自动跑格式化、静态检查、单元测试。不通过就拒绝提交。这个机制帮我省了大量修低级错误的时间。热词里的obsidian git也是类似的思路。知识库和代码库一样需要版本管理。我的 Obsidian 库每天自动 commit 一次这样即使误删了笔记也能找回来。5. 常见问题与排查技巧实录5.1 模型不按格式输出怎么办这是最常见的问题。你让模型输出 JSON它给你输出一段解释文字加 JSON。你让它用 Markdown 表格它给你用列表。解决办法有两个一是在 prompt 里给示例不是描述格式而是直接给一个正确的输出样例。二是在 Harness 层做后处理用正则或者解析器把模型输出里的目标内容提取出来。我试过用 JSON schema 约束输出效果不稳定。后来改成“先让模型自由输出再用一个小模型做格式转换”成功率反而更高。因为大模型擅长理解意图小模型擅长做格式转换各司其职。5.2 工具调用参数错误怎么自动修复模型传错参数是常态。我的 Harness 层加了一个参数修复模块。当参数校验失败时不是直接报错而是尝试自动修复。比如路径多了空格就 trim数字传成字符串就转换枚举值大小写不对就归一化。修复成功就继续执行修复失败才返回错误。这个模块大概花了三天写但后面省下的调试时间至少有三周。5.3 上下文太长导致模型“失忆”怎么办上下文太长的时候模型会忽略中间部分的信息只记住开头和结尾。这是注意力机制的特性不是 bug。解决办法是把重要信息放在开头和结尾中间放次要信息。另外用显式的分隔符把不同部分隔开比如用---或者###标记帮助模型定位。如果上下文实在太长就做分层摘要。先对每个部分做摘要再把摘要拼起来做二级摘要。这样虽然会损失一些细节但能保证模型抓住主干。5.4 常见问题速查表问题现象可能原因排查步骤解决方案模型输出格式错误prompt 不清晰或缺少示例检查 prompt 里的格式说明添加正确输出示例加后处理提取工具调用失败参数校验不通过打印模型原始输出和校验错误加参数修复模块优化工具描述上下文丢失超出窗口限制统计 token 数量做摘要压缩重要信息前置循环卡死模型重复调用同一工具打印调用历史加重复检测强制换方案执行超时工具执行太慢加日志记录每个工具耗时设超时优化慢工具状态不一致并发写入冲突检查状态存储的锁机制加乐观锁或串行化写入提示这张表是我从实际报错日志里整理出来的覆盖了百分之九十以上的常见问题。遇到新问题先查表查不到再深入调试。6. 一些踩过的坑和真实体会第一个坑是过早优化。项目初期我花了两周做上下文压缩算法结果后来发现大部分任务根本用不到那么复杂的压缩简单的滑动窗口就够了。教训是先跑通再优化不要为想象中的问题写代码。第二个坑是工具太多。一开始我给模型注册了五十多个工具结果模型经常选错工具。后来砍到十五个核心工具调用准确率反而上去了。工具不在多在于每个都清晰、独立、不重叠。第三个坑是忽略日志。有段时间 Agent 经常莫名其妙失败我查了两天才发现是某个工具在特定条件下返回了空结果导致后续步骤全部错位。后来我加了结构化日志每个步骤的输入输出都记录下来排查问题的时间从两天缩短到十分钟。第四个坑是测试覆盖不够。Harness 层的代码看起来简单但边界条件特别多。我一开始只测了正常流程上线后发现各种异常情况都没处理。后来补了异常测试包括网络超时、文件不存在、权限不足、模型返回空结果等等。关于 token 消耗我的体会是不要怕烧 token但要烧得明白。每个月四十亿 token 里大概有百分之六十是必要的上下文和推理百分之三十是重试和纠错百分之十是浪费。把浪费的部分压下去把纠错的部分优化好整体效率就能提升一大截。最后分享一个实用技巧给 Agent 加一个“思考日志”。让模型在每一步行动前先用一句话说明它打算做什么、为什么这么做。这个日志不参与后续推理只用于人工排查。加了之后调试效率至少提升一倍因为你能清楚看到模型的决策路径而不是只看到最终结果。这个项目后续还可以往几个方向扩展。一是支持多 Agent 协作让不同的 Agent 负责不同的工具域通过消息传递协调。二是接入更多知识源不只是 Obsidian还可以是 Notion、语雀、本地文件夹。三是做可视化调试界面把 Agent 的执行过程画成流程图方便非技术人员理解和干预。这些方向我都在探索有新的进展再分享。