
1. 一个人九个月二十万行代码背后的工程逻辑1.1 这个项目到底在做什么先把这个标题拆开看。一个人、九个月、20万行代码、每月40亿 token最终产出是一个基于 Harness 架构的应用。这几个数字放在一起任何一个写过代码的人都会先愣一下——20万行代码就算九个月一天不休息平均每天也要写740行左右。而每月40亿 token 的消耗量意味着这个系统在持续运行中大量调用大模型能力不是那种写完就扔的一次性脚本。Harness 这个词在当下的开发语境里指的是一套围绕 AI Agent 构建的工程化框架。它的核心思路是把大模型的调用、工具编排、上下文管理、状态持久化这些环节用一套统一的架构串起来让 Agent 能稳定地完成复杂任务。你可以把它理解成一个“AI 工作流的操作系统”——模型是发动机Harness 是底盘、变速箱和仪表盘。这个项目要解决的问题很具体当你想让 AI 帮你处理真实世界的复杂任务时单次对话远远不够。你需要它能记住上下文、调用外部工具、读写文件、管理知识库、在多个步骤之间保持状态一致。这些东西散着做也能跑但一旦任务变复杂、调用量上来就会到处漏风。Harness 架构的价值就在于把这些环节收拢到一个可控的框架里。适合谁来参考如果你正在做 AI Agent 相关的开发或者你是一个重度知识管理用户想把 Obsidian、Markdown 笔记体系和 AI 能力打通这个项目的思路和踩坑经验对你都有直接帮助。哪怕你只是好奇“一个人怎么扛住这么大的工程量”后面的工具选型和实操细节也值得一看。1.2 为什么是 Harness 而不是其他方案市面上做 Agent 的框架不少有偏重对话编排的有偏重 RAG 检索的也有偏重多 Agent 协作的。这个项目选 Harness 架构我推测核心考量是可控性和可观测性。偏对话编排的方案本质上是在 Prompt 层面做文章一旦任务链路变长上下文窗口就成了瓶颈而且中间步骤出错了很难定位。偏 RAG 的方案擅长知识检索但缺乏对“动作”的编排能力——它能告诉你答案但没法帮你把答案写进文件、更新数据库、触发下一步操作。Harness 架构的差异在于它把 Agent 的每一次“思考-行动-观察”循环都显式地管理起来。每一步调用了什么工具、传了什么参数、返回了什么结果、消耗了多少 token全都有记录。这对于一个月烧40亿 token 的系统来说不是锦上添花而是生死攸关——没有这套可观测机制你根本不知道钱花在哪了也不知道哪里出了 bug。另一个关键点是状态管理。Harness 架构通常会把 Agent 的运行状态持久化这意味着即使进程重启、任务中断也能从上次的断点继续。对于长时间运行的任务这个能力是刚需。你不可能让一个跑了三小时的任务因为一次网络抖动就全部重来。还有一点容易被忽略Harness 架构天然适合做工具注册和权限控制。Agent 能调用哪些工具、每个工具的调用频率限制、敏感操作的审批流程这些都可以在框架层面统一管理。当你的 Agent 要读写本地文件、操作 Obsidian 仓库、调用外部 API 时没有这层管控迟早出事。2. 核心技术点拆解与工具选型2.1 Claude Code 作为主力开发环境这个项目里 Claude Code 的角色很关键。它不只是一个“帮你写代码的 AI”而是整个开发流程的中枢。20万行代码的体量靠传统的手写方式九个月根本不可能完成Claude Code 承担了大量代码生成、重构、调试的工作。Claude Code 的使用有几个层次。最基础的是对话式生成代码你描述需求它输出实现。进阶用法是让它直接操作你的项目文件——读取现有代码、理解上下文、在正确的位置插入或修改代码。最高效的用法是把它接入你的开发循环写完一个模块让它自动跑测试、分析报错、提出修复方案。安装 Claude Code 本身不复杂但配置上有几个坑要注意。首先是模型选择不同任务适合不同能力的模型代码生成和代码审查可以用不同的配置。其次是工作目录的设定一定要让它在你实际的项目根目录下运行否则它读取的文件路径会乱。还有就是订阅权限的问题有些组织账号默认关闭了 Claude Code 的访问权限需要管理员在后台手动开启。实操心得Claude Code 在处理大文件时容易“迷失”建议把项目拆成合理的模块粒度每个文件控制在500行以内。超过这个规模它的修改准确率会明显下降。2.2 Obsidian 作为知识底座Obsidian 在这个项目里扮演的是“外部记忆”的角色。Agent 运行过程中产生的知识、决策记录、任务上下文全部以 Markdown 文件的形式沉淀在 Obsidian 仓库里。这样做的好处是双重的一方面 Agent 可以随时检索历史信息另一方面人也可以直接阅读和编辑这些笔记。Obsidian 的 Markdown 文件本质上是纯文本这对 Agent 非常友好。不需要复杂的解析逻辑直接读写文件就行。而且 Obsidian 的双链语法和标签系统天然适合构建知识图谱Agent 可以通过链接关系快速定位相关信息。实际使用中有几个细节值得注意。Markdown 的换行处理是个经典坑——在 Obsidian 里单个换行不会渲染成新段落需要空行或者行尾加两个空格。如果你的 Agent 生成的 Markdown 内容格式不对在 Obsidian 里看起来就会挤成一团。表格转换也是高频需求Markdown 表格转 Excel 或者反过来都有现成的工具可以用但要注意特殊字符的转义。Obsidian 的插件生态是另一个加分项。比如 Docxer 插件可以处理 Word 文档的导入导出数学公式插件能让 Markdown 里的 LaTeX 公式正常渲染。如果你要从 Zotero 导入文献笔记也有对应的插件可以打通。这些能力让 Obsidian 不只是一个笔记软件而是一个可以承载复杂知识工作流的平台。2.3 Markdown 作为 Agent 的通用语言Markdown 在这个项目里的地位被严重低估了。它不只是笔记的存储格式更是 Agent 与外部世界交互的“中间语言”。Agent 生成的报告、任务清单、决策日志全部用 Markdown 表达。这样做的好处是任何支持 Markdown 的工具都能消费这些内容不绑定特定平台。Markdown 的语法虽然简单但在 Agent 场景下有几点需要特别注意。第一是结构化程度Agent 生成的 Markdown 要有清晰的标题层级方便后续程序化解析。第二是元数据的处理YAML front matter 可以用来存储结构化的属性信息比如任务状态、优先级、创建时间等。第三是代码块的处理Agent 输出的代码必须用正确的语言标记包裹否则后续处理会出问题。表格是 Markdown 里比较容易出问题的部分。Agent 生成表格时经常出现列数不匹配、对齐符号缺失的情况。建议在 Agent 的输出规范里明确表格的格式要求并且在写入文件前做一次校验。3. 实操过程与核心环节实现3.1 从零搭建 Harness 架构的骨架搭建 Harness 架构的第一步是定义清楚 Agent 的“能力边界”。你需要列出这个 Agent 要完成哪些类型的任务每个任务需要调用哪些工具工具之间的依赖关系是什么。这一步看起来是设计工作但实际上直接决定了后续代码的组织方式。我建议用一个配置文件来管理工具注册。每个工具定义包含名称、描述、参数 schema、执行函数、权限要求这几个字段。这样做的好处是新增工具只需要改配置不需要动核心逻辑。而且这份配置可以直接作为 Prompt 的一部分喂给模型让它知道自己有哪些能力可用。核心循环的实现是 Harness 的心脏。一个典型的循环是这样的接收任务输入调用模型生成下一步动作解析动作并执行对应工具把执行结果追加到上下文判断任务是否完成未完成则继续循环。这个循环看起来简单但每个环节都有讲究。上下文管理是最容易出问题的环节。你不能把所有历史记录都塞给模型token 消耗扛不住。常见的做法是滑动窗口加摘要保留最近 N 轮完整记录更早的内容压缩成摘要。摘要的生成也要调模型所以这里有个平衡——摘要太频繁浪费 token摘要太少上下文丢失严重。状态持久化用文件系统就够了。每个任务一个目录里面存任务元数据、执行日志、中间产物。这样做的好处是透明出问题了直接看文件就知道发生了什么。而且 Obsidian 可以直接打开这个目录人机共读同一份数据。3.2 每月40亿 token 的消耗结构分析40亿 token 一个月平均每天1.3亿左右。这个量级听起来吓人但拆开看就合理了。假设你的 Agent 每天处理1000个任务每个任务平均消耗13万 token这个数字在复杂任务场景下并不夸张。token 消耗的大头通常在三个地方。第一是系统 Prompt每次调用都要带上工具定义、行为规范、输出格式要求这部分可能就占了几千 token。第二是上下文历史任务链路越长累积的上下文越多。第三是模型输出尤其是需要生成大段代码或长文本的时候。优化 token 消耗有几个实用手段。系统 Prompt 做缓存很多模型服务支持 Prompt caching重复的部分只计费一次。上下文做分级管理不是所有历史都需要完整保留关键决策点保留中间过程可以压缩。输出做流式处理边生成边消费避免一次性生成超长内容。还有一个容易被忽略的点失败重试的 token 浪费。如果工具调用失败后直接重试而失败原因是参数错误那重试多少次都是白费。正确的做法是在重试前先让模型分析失败原因修正参数后再试。这个环节加上之后重试成功率会明显提升。3.3 代码组织与模块划分20万行代码不是一个小数目没有合理的模块划分根本维护不了。这个项目的代码结构我推测大致分为这几层核心框架层、工具实现层、业务逻辑层、配置与数据层。核心框架层负责 Agent 循环、上下文管理、状态持久化、日志记录这些通用能力。这层代码应该尽量稳定不随业务需求频繁变动。工具实现层是各种具体能力的封装比如文件读写、HTTP 请求、Markdown 解析、Obsidian 仓库操作等。这层的特点是数量多但每个都不复杂适合用统一的接口规范来约束。业务逻辑层是把工具编排成具体任务流程的地方。比如“整理今日笔记并生成摘要”这个任务需要依次调用读取文件、调用模型总结、写入新文件这几个工具。这层的代码应该尽量声明式用配置或 DSL 来描述流程而不是写成一堆嵌套的 if-else。配置与数据层存放 Prompt 模板、工具定义、任务配置、运行日志这些内容。建议用 YAML 或 JSON 格式方便人工编辑和程序解析。数据文件按日期或任务 ID 分目录存放避免单目录文件过多导致性能问题。注意事项模块之间的依赖关系要严格控制方向。工具层可以依赖框架层业务层可以依赖工具层但反过来绝对不行。一旦出现循环依赖整个项目就会变成一团乱麻。4. 常见问题与排查技巧实录4.1 Agent 执行中断与恢复长时间运行的 Agent 任务最怕中断。网络抖动、进程崩溃、系统重启任何一种情况都可能导致任务半途而废。如果没有恢复机制之前消耗的 token 全部打水漂。解决方案的核心是检查点机制。在 Agent 循环的每一步之后把当前状态写入持久化存储。状态内容包括当前执行到哪一步、已经完成了哪些子任务、上下文摘要、下一步的计划。恢复时从最后一个检查点加载继续执行。检查点的粒度需要权衡。太粗恢复后要重做的步骤多太细写状态的频率太高影响性能。我的经验是每个“工具调用完成”作为一个检查点比较合适因为工具调用通常是最耗时的环节也是状态变化最明显的节点。还有一个细节检查点文件要包含版本号。当你的 Agent 逻辑升级后旧版本的检查点可能无法直接恢复。版本号可以帮助你判断是否需要做数据迁移或者干脆放弃旧检查点重新开始。4.2 工具调用失败的排查思路工具调用失败是 Agent 开发中最常见的问题。失败原因大致分几类参数格式错误、权限不足、外部服务不可用、返回结果解析失败。排查的时候要按顺序来不要跳步。先看参数。把模型生成的工具调用参数打印出来和工具定义的 schema 做对比。常见问题是模型生成了多余字段、缺少必填字段、或者类型不对比如该传数字传了字符串。这类问题可以通过在 Prompt 里加强格式约束来减少但没法完全避免所以工具执行前要做参数校验。再看权限。文件读写有没有越界、API 调用有没有超出配额、敏感操作有没有经过审批。权限问题通常表现为明确的错误码比较容易定位。关键是要在日志里记录清楚是哪个权限被拒绝了方便后续调整策略。外部服务不可用这类问题最麻烦因为不是你能控制的。应对策略是加超时和重试但重试要有退避策略不能死循环。同时要有降级方案比如某个搜索工具挂了能不能用缓存结果或者换一个数据源顶上。返回结果解析失败往往是因为外部服务的返回格式变了。这类问题的排查方法是把原始返回内容完整记录下来对比解析逻辑的预期格式。修复方式通常是让解析逻辑更宽容或者加一层格式转换。4.3 上下文膨胀的控制策略上下文膨胀是 Agent 跑久了必然遇到的问题。每一轮对话都往上下文里追加内容很快就把窗口撑满了。一旦超出模型的最大上下文长度要么报错要么被迫截断导致信息丢失。控制策略分三个层次。第一层是写入时过滤不是所有工具返回的内容都值得放进上下文。比如读取一个大文件可能只需要把文件摘要和关键段落放进去全文留在磁盘上备查。第二层是定期压缩每隔若干轮把历史对话总结成一段简短摘要替换掉原始记录。第三层是分层检索上下文里只保留最近的内容更早的信息通过检索工具按需拉取。压缩摘要的质量直接影响 Agent 的表现。摘要太简略关键信息丢失摘要太详细压缩效果不明显。我的做法是让模型生成结构化的摘要包含“已完成事项”“关键决策”“待办事项”三个部分这样既压缩了体积又保留了最重要的信息。还有一个技巧是上下文分区。把上下文分成“系统区”“任务区”“历史区”几个部分不同区域有不同的保留策略。系统区的内容基本不变任务区随任务进展更新历史区做滑动窗口。这样管理起来更清晰也方便针对性地优化。4.4 常见问题速查表问题现象可能原因排查方法解决思路Agent 循环不终止完成条件判断有误打印每轮的状态判断逻辑加最大轮次限制完善终止条件工具调用参数错误Prompt 约束不够对比生成参数与 schema加强格式说明执行前校验上下文超限历史记录累积过多统计每轮 token 消耗启用压缩和滑动窗口任务恢复后行为异常检查点状态不完整对比恢复前后上下文完善检查点内容加版本号输出格式不符合预期格式约束不明确检查 Prompt 中的格式要求提供示例加后处理校验token 消耗异常高重复调用或上下文冗余分析调用日志加缓存优化上下文管理避坑技巧在开发阶段就把日志级别调到最详细把每次模型调用的输入输出都记录下来。上线后再想排查问题没有这些日志会非常痛苦。日志文件按天切割定期归档避免单个文件过大。5. 工程化落地的经验与建议5.1 开发节奏的把控一个人做20万行代码的项目节奏把控比技术选型更重要。我的经验是先跑通再优化。不要一开始就追求完美的架构先用最直接的方式把核心流程跑通哪怕代码写得丑一点。跑通之后你才知道真正的瓶颈在哪里这时候再针对性优化。九个月的时间分配大致可以这样前两个月搭框架和核心循环中间四个月实现各种工具和业务逻辑最后三个月做优化、测试和文档。当然实际过程中会有反复但大致的阶段划分要有。每天的工作要有明确的产出目标。不要陷入“今天调了一天 bug 但什么都没完成”的状态。如果一个问题卡住超过两小时先记下来跳过去做其他能推进的事情。很多时候换个思路回来问题就迎刃而解了。5.2 代码质量的底线20万行代码如果没有质量底线后期维护会变成噩梦。几个必须坚持的原则函数职责单一一个函数只做一件事命名清晰变量和函数名要能表达意图关键逻辑必须有注释尤其是那些“为什么这么做”的决策错误处理不能省每个可能失败的操作都要有应对。测试不追求覆盖率但核心流程必须有测试。Agent 循环、上下文管理、工具调用这些关键环节改动之后要能快速验证没有破坏原有功能。测试用例不用多覆盖主要路径和边界情况就行。版本控制要用好。每个功能开发开一个分支完成后合并。提交信息写清楚做了什么、为什么这么做。这些记录在后期排查问题时非常有用尤其是当你忘了三个月前为什么改了某段代码的时候。5.3 持续迭代的方向这个项目做完之后后续可以扩展的方向很多。工具生态可以持续丰富接入更多外部服务让 Agent 的能力边界不断扩展。性能优化永无止境token 消耗、响应速度、并发处理每个维度都有提升空间。知识库的积累是另一个有价值的的方向。Agent 运行过程中产生的决策记录、问题解决方案、优质输出都可以沉淀下来形成可复用的知识资产。这些资产反过来又能提升 Agent 的表现形成正向循环。多 Agent 协作也是值得探索的方向。单个 Agent 的能力有上限多个 Agent 分工协作可以处理更复杂的任务。比如一个负责规划、一个负责执行、一个负责审查各司其职。当然这会带来新的复杂度通信、协调、冲突解决都是要解决的问题。我在实际使用中体会最深的一点是Agent 的能力上限不取决于模型有多强而取决于你给它搭建的工程框架有多完善。模型是通用的但框架是定制的。把框架做扎实普通的模型也能完成不普通的任务。反过来框架漏洞百出再强的模型也发挥不出来。最后分享一个小心得定期回顾 Agent 的运行日志看看哪些任务失败了、哪些消耗异常、哪些输出质量不高。这些日志是最好的改进线索比凭空想“哪里可以优化”有效得多。