尧图精选

Harness架构实战:单人九个月20万行代码的AI管道设计

🕒 发布时间:2026/10/2 19:30:31 📁 来源:尧图网络
1. 项目缘起与整体架构思路1.1 为什么选择 Harness 架构而不是传统 Agent 框架一个人、九个月、20 万行代码、每个月烧掉 40 亿 token这几个数字放在一起任何一个做过 AI 应用开发的人都会先愣一下。40 亿 token 是什么概念按主流大模型 API 的定价粗略估算每个月光推理成本就是一笔相当可观的支出。而 20 万行代码由一个人写完意味着平均每天要产出 700 行以上的有效代码且持续九个月不间断。这个项目能跑起来核心不在于代码写得多快而在于架构选对了方向。Harness 架构和市面上常见的 Agent 框架有本质区别。大多数 Agent 框架的思路是“给模型一堆工具让它自己决定调哪个”本质上是一个调度器加工具集。Harness 的思路完全不同——它把模型当作一个需要被“约束”和“引导”的执行引擎通过精心设计的外围结构来控制模型的输入输出行为。你可以把它理解成普通 Agent 框架是给一个聪明人一张地图让他自己找路Harness 是给这个人修了一条带护栏的高速公路他只能沿着这条路走但走得极快且不会跑偏。这个区别在实际项目中影响巨大。我试过用纯 Agent 框架做长流程任务最大的问题是模型会在某个环节突然“自由发挥”输出格式变了、调用了一个不该调的工具、或者在中途丢失了上下文。Harness 架构通过强约束的输入输出管道把这类问题压到了最低。具体来说它做了三件事第一把每个任务拆成固定阶段的流水线每个阶段有明确的输入契约和输出契约第二用 Markdown 作为中间表示层所有阶段之间的数据传递都通过结构化的 Markdown 文档完成第三每个阶段都有校验和回退机制输出不符合契约就自动重试或降级处理。为什么用 Markdown 做中间层这个选择乍看有点奇怪但实际用下来非常合理。Markdown 既是人类可读的又是机器可解析的。当你需要调试一个跑了十几个阶段的流水线时能直接打开中间产物看一眼比去翻 JSON 日志高效得多。而且 Markdown 的语法足够简单模型生成 Markdown 的准确率远高于生成复杂 JSON 结构的准确率。这一点在长时间运行的任务中特别重要——每多一个格式错误就多一次重试多一次重试就多烧一批 token。1.2 九个月的时间线是怎么分配的很多人好奇九个月到底花在哪了。根据这类项目的常见实践时间分配大致是这样的前两个月做架构设计和核心管道搭建中间四个月做各阶段的具体实现和调优最后三个月做集成测试、性能优化和边缘情况处理。但实际过程中前两个月和中间四个月是有大量重叠的——因为你在实现某个阶段的时候经常会发现架构设计需要调整。真正耗时的不是写代码而是调 prompt。Harness 架构的核心竞争力在于每个阶段的 prompt 设计而 prompt 调优是一个极其消耗 token 的过程。你写了一个 prompt跑一遍发现输出格式不对改一改再跑还是不对再改。一个关键阶段的 prompt 可能要迭代几十次才能稳定。每次迭代都要消耗 token这就是为什么每个月能烧掉 40 亿 token——大部分都花在开发和调试阶段的反复试跑上了。这里有一个很重要的经验在 Harness 架构中prompt 不是写在代码里的字符串而是作为配置文件独立管理的。每个阶段的 prompt 有版本号可以单独回滚可以做 A/B 测试。这个设计决策在后期帮了大忙——当某个阶段的表现突然变差时你可以快速定位是不是某次 prompt 修改导致的。1.3 20 万行代码的构成分析20 万行代码听起来很多但拆开看就合理了。核心管道逻辑大概占 15%各阶段的处理器占 40%数据模型和校验逻辑占 20%工具函数和辅助模块占 15%测试代码占 10%。其中占比最大的是各阶段的处理器因为每个阶段都需要处理输入解析、prompt 组装、模型调用、输出解析、格式校验、异常处理这一整套流程。代码量大的另一个原因是类型定义。为了让整个管道在编译期就能发现类型不匹配的问题项目里用了大量的类型定义和接口声明。这些代码虽然不直接产生功能但极大地减少了运行时的调试时间。在一个单人开发的项目里编译期能发现的问题越多运行期需要排查的问题就越少这个投入产出比是非常划算的。2. 核心模块拆解与关键技术点2.1 输入解析层把非结构化内容变成结构化数据整个 Harness 管道的第一步是输入解析。不管原始输入是一段文字、一个网页、还是一个 Markdown 文件都需要先被解析成管道能处理的内部格式。这一层的核心挑战在于输入的多样性——用户可能丢进来任何东西而管道需要从中提取出结构化的信息。以 Markdown 文件为例解析层需要处理的事情包括识别标题层级、提取代码块、解析表格、处理数学公式、识别引用块和 callout。这些看起来是标准的 Markdown 解析任务但实际做起来有很多坑。比如 Markdown 的换行规则在不同解析器下行为不一致有的把单个换行当作换行有的当作空格。数学公式的定界符也有多种写法$...$和$$...$$在不同场景下含义不同。表格的解析更麻烦因为 Markdown 表格允许省略前导和尾随的管道符还允许在单元格内使用转义字符。处理这些问题的方法是先做一轮标准化预处理把所有变体统一成一种规范格式然后再用统一的解析器处理。预处理阶段会做这些事统一换行符、统一数学公式定界符、补全表格的管道符、规范化 callout 语法。这个预处理层大概花了三周时间才稳定下来但后面所有阶段都受益于它——因为输入格式统一了后续处理逻辑就不用到处写兼容代码。实操心得Markdown 解析不要自己从头写。用成熟的解析库做基础解析然后在解析结果上做二次处理。自己写解析器看起来可控但边缘情况太多了维护成本极高。2.2 阶段处理器Harness 架构的核心执行单元每个阶段处理器是 Harness 架构的基本执行单元。一个阶段处理器接收上一阶段的输出按照预定义的 prompt 模板组装请求调用模型解析模型输出校验格式然后传递给下一阶段。这个流程听起来简单但每个环节都有需要仔细处理的地方。Prompt 组装阶段的关键是上下文管理。模型有上下文窗口限制你不能把之前所有阶段的输出都塞进去。项目里采用的方法是每个阶段只接收它真正需要的上游数据而不是全量上下文。具体来说每个阶段在定义时会声明它依赖哪些上游阶段的哪些字段管道在组装 prompt 时只提取这些字段。这个设计让每个阶段的 prompt 都保持在合理长度内既节省 token 又提高输出质量。模型调用的关键是重试策略。不是所有失败都需要重试也不是所有重试都用同样的方式。项目里把失败分成了三类格式错误输出不符合契约、内容错误输出格式对但内容不对、超时错误模型响应超时。格式错误直接重试因为大概率是模型随机性导致的内容错误会先尝试用更明确的 prompt 重新请求如果连续失败则标记为需要人工介入超时错误会降低请求复杂度后重试。这个分类处理策略让重试的成功率提高了不少。输出解析的关键是容错。模型输出不可能 100% 符合预期格式所以解析器需要有一定的容错能力。比如期望输出是一个 Markdown 表格但模型在表格前后多写了一段说明文字解析器应该能自动识别并提取表格部分。项目里的做法是先用严格模式解析失败则用宽松模式解析再失败则用正则表达式提取关键部分最后还失败才标记为解析错误。这个多级容错策略把解析成功率从最初的 70% 左右提升到了 95% 以上。2.3 校验与回退机制让管道在异常时也能继续跑校验机制是 Harness 架构可靠性的基石。每个阶段的输出在传递给下一阶段之前都要经过校验。校验分两层格式校验和语义校验。格式校验检查输出是否符合预定义的结构比如是否包含必需的字段、字段类型是否正确、枚举值是否在允许范围内。语义校验检查输出内容是否合理比如生成的代码是否能通过语法检查、提取的关键词是否在原文中出现过。回退机制的设计思路是当某个阶段失败时不是直接终止整个管道而是尝试用降级方案继续。降级方案有三种一是用更简单的 prompt 重新请求二是跳过该阶段用默认值填充三是回退到上一个稳定状态重新执行。具体用哪种降级方案取决于该阶段的重要程度——关键阶段用第一种非关键阶段用第二种状态不一致时用第三种。这个机制在实际运行中救了很多次。有一次在一个长流程任务中中间某个阶段连续失败了五次按照传统做法整个任务就废了。但因为有回退机制系统自动切换到降级方案用默认值填充了该阶段的输出后续阶段继续执行最终产出的结果虽然有瑕疵但整体可用。如果没有这个机制那次任务消耗的 token 就全白费了。2.4 与 Obsidian 的集成让产出直接可用项目的一个亮点是跟 Obsidian 的深度集成。Obsidian 是目前最流行的本地 Markdown 知识管理工具它的文件格式就是纯 Markdown天然适合作为 Harness 管道的输出目标。集成方式很简单管道的最终输出直接写入 Obsidian 仓库的指定目录利用 Obsidian 的文件夹结构和标签系统来组织产出。但简单集成之外还有一些细节处理。比如 Obsidian 的 callout 语法 [!note]这种需要在输出时正确生成否则在 Obsidian 里显示不出效果。Obsidian 的内部链接语法[[文件名]]也需要在适当的地方使用让产出之间能互相引用。还有 frontmatter 的处理——Obsidian 用 YAML frontmatter 来存储元数据管道输出时需要自动生成合适的 frontmatter包括创建时间、标签、别名等字段。这些细节看起来小但直接影响产出能不能直接用。如果每次生成完还要手动调整格式那自动化的价值就大打折扣了。项目里专门花了两周时间做 Obsidian 集成的细节打磨包括 callout 类型映射、内部链接自动生成、frontmatter 模板管理等。这部分工作虽然不涉及复杂的算法但对最终用户体验的影响非常大。3. 实操流程与关键环节实现3.1 从零搭建 Harness 管道的完整步骤搭建一个 Harness 管道不是从写代码开始的而是从定义阶段划分开始的。你需要先想清楚整个任务要分成几个阶段每个阶段的输入是什么、输出是什么、依赖哪些上游阶段。这个设计阶段大概需要一到两周但值得花这个时间——阶段划分不合理后面改起来非常痛苦。阶段划分的原则是每个阶段只做一件事且这件事可以用一句话描述清楚。比如“从输入中提取所有标题”、“根据标题生成大纲”、“根据大纲生成正文”就是三个清晰的阶段。如果一个阶段需要两句话才能描述清楚那大概率应该拆成两个阶段。阶段拆得细一些每个阶段的 prompt 就更简单输出更可控调试也更容易。定义完阶段后下一步是定义每个阶段的输入输出契约。契约用类型定义来描述包括字段名、字段类型、是否必需、默认值等。这个契约就是阶段之间的接口上游阶段的输出必须满足下游阶段的输入契约否则管道在编译期就会报错。这个设计让很多问题在写代码阶段就被发现了而不是等到运行时才暴露。契约定义完之后就可以开始实现阶段处理器了。每个处理器的实现遵循同样的模板解析输入、组装 prompt、调用模型、解析输出、校验格式、返回结果。这个模板化的结构让新增阶段变得很快——你只需要关注这个阶段特有的逻辑通用的流程代码可以复用。3.2 Prompt 模板的设计与调优方法Prompt 模板的设计是 Harness 架构中最需要经验的部分。一个好的 prompt 模板应该包含这几个要素角色定义、任务描述、输入数据、输出格式要求、示例。角色定义让模型知道它在这个阶段扮演什么角色任务描述告诉它要做什么输入数据是它需要处理的内容输出格式要求约束它的输出结构示例给它一个参考。输出格式要求是最关键的部分。在 Harness 架构中每个阶段的输出格式都是严格定义的prompt 里必须明确告诉模型输出应该长什么样。最好的做法是给一个完整的输出示例而不是用文字描述格式。模型对示例的理解远好于对文字描述的理解。比如你要模型输出一个 Markdown 表格与其说“输出一个包含三列的表格”不如直接给一个三列表格的示例。调优 prompt 的方法论是先写一个能跑通的版本然后收集失败案例针对失败案例修改 prompt再跑一遍看失败案例是否解决、有没有引入新的失败。这个循环可能要重复几十次。为了提高效率项目里建了一个测试集包含各种典型的输入和期望输出每次修改 prompt 后都跑一遍测试集看通过率的变化。这个测试集是逐步积累的每次遇到新的失败案例就加进去。注意事项prompt 里不要写太复杂的逻辑。如果发现 prompt 里出现了多层条件判断那说明这个阶段应该拆成多个阶段。模型处理简单明确的指令比处理复杂条件逻辑要可靠得多。3.3 Token 消耗的监控与优化每个月 40 亿 token 的消耗需要精细的监控和优化。项目里建了一套 token 消耗的监控系统记录每个阶段、每次调用的 token 使用量按阶段、按日期、按模型类型做汇总。这个监控系统帮了大忙——通过分析数据发现某个阶段的 token 消耗异常高原因是它的 prompt 里包含了大量不必要的上下文。优化后该阶段的 token 消耗降低了 60%。Token 优化的主要手段有这几个一是精简 prompt去掉所有不必要的内容二是控制上下文长度只传必要的上游数据三是选择合适的模型简单任务用便宜的小模型复杂任务才用大模型四是缓存重复请求的结果同样的输入不重复调用模型五是批量处理把多个小请求合并成一个大请求。其中效果最明显的是模型选择。项目里把阶段分成了三档简单阶段格式转换、信息提取用最便宜的小模型中等阶段内容生成、摘要用中等模型复杂阶段推理、规划才用大模型。这个分档策略让整体成本降低了大约一半而输出质量几乎没有下降。因为大部分阶段其实不需要大模型的推理能力小模型完全够用。3.4 并发处理与性能调优Harness 管道天然适合并发处理——不同任务之间没有依赖关系可以并行执行。项目里用了一个任务队列来管理并发每个任务独立走完整个管道任务之间互不干扰。并发数的设置需要根据模型 API 的速率限制来调整设太高会被限流设太低则吞吐量不够。除了任务级并发阶段级也可以并发。在一个任务内部如果某几个阶段之间没有依赖关系也可以并行执行。比如“提取标题”和“提取关键词”这两个阶段都只依赖原始输入可以同时跑。项目里用一个简单的依赖图来管理阶段间的并行关系没有依赖的阶段自动并行执行。性能调优的另一个重点是减少不必要的模型调用。有些阶段其实可以用规则引擎代替模型比如格式转换、字段提取这类确定性任务。项目里把这类任务从模型调用改成了规则处理不仅速度快了很多还省了大量 token。判断标准很简单如果这个任务的输出可以用明确的规则描述那就不需要模型。4. 常见问题与排查技巧实录4.1 模型输出格式不稳定的排查思路格式不稳定是 Harness 架构中最常见的问题。表现是同一个 prompt有时候输出符合格式有时候不符合。排查这个问题的第一步是确认 prompt 本身是否足够明确。如果 prompt 里对输出格式的描述有歧义模型就会在不同理解之间摇摆。解决方法是把格式要求写得更具体最好给完整的示例。如果 prompt 没问题但格式仍然不稳定那可能是模型本身的问题。不同模型对格式的遵循能力差异很大同一个模型在不同温度参数下表现也不同。项目里的做法是把温度参数调低0.1 到 0.3 之间并在 prompt 里加上“严格按照以下格式输出”这样的强调语句。如果还是不稳定就换一个格式遵循能力更强的模型。还有一个容易被忽略的原因是输入数据的问题。如果输入数据里包含了跟输出格式冲突的内容模型可能会被带偏。比如你要求输出 Markdown 表格但输入数据里有一个格式混乱的表格模型可能会模仿输入数据的格式而不是你要求的格式。解决方法是在 prompt 里明确区分输入和输出用分隔符把输入数据包起来并强调输出格式要求。4.2 Token 消耗异常的定位与处理Token 消耗突然升高是一个需要立即处理的问题。排查的第一步是看监控数据确认是哪个阶段的消耗升高了。如果是单个阶段升高那可能是这个阶段的输入数据变长了或者 prompt 被改长了。如果是整体升高那可能是任务量增加了或者某个上游阶段的输出变长了导致下游阶段的输入变长。定位到具体阶段后下一步是分析这个阶段的 token 构成。输入 token 和输出 token 的比例是多少如果输入 token 远大于输出 token说明 prompt 太长了需要精简。如果输出 token 远大于输入 token说明模型在生成大量不必要的内容需要在 prompt 里加上长度限制。处理 token 消耗异常的常见手段包括精简 prompt、限制输出长度、用更便宜的模型、增加缓存、批量处理。其中增加缓存的效果往往被低估。很多请求其实是重复的比如同一个文档被多次处理或者相似的输入产生了相似的输出。项目里加了一层缓存对输入做哈希相同的输入直接返回缓存结果这一层就省了大约 15% 的 token。4.3 管道中断的恢复策略长流程任务最怕的就是跑到一半中断了。中断的原因可能是模型 API 超时、网络抖动、程序异常等。如果没有恢复机制中断后只能从头再跑之前消耗的 token 全白费。项目里的恢复策略是每个阶段完成后把状态持久化到磁盘中断后可以从最后一个成功的阶段继续执行。状态持久化包括两部分一是每个阶段的输出结果二是管道的执行状态哪些阶段已完成、哪些未完成。恢复时读取持久化的状态跳过已完成的阶段从断点继续。这个机制看起来简单但实现时需要注意状态的一致性——如果持久化过程中程序崩溃了状态文件可能不完整。项目里用了原子写入来保证状态文件的完整性写的时候先写临时文件写完再重命名。还有一个细节是状态的清理。持久化的状态文件会占用磁盘空间需要定期清理已完成任务的状态。项目里设置了一个保留期限超过期限的状态文件自动删除。同时对于正在执行的任务状态文件会加锁防止并发修改。4.4 常见问题速查表问题现象可能原因排查方法解决方案输出格式不符合预期prompt 描述不明确检查 prompt 中的格式要求补充完整示例降低温度参数Token 消耗突然升高某阶段输入变长查看监控数据定位阶段精简 prompt增加缓存管道执行到一半中断API 超时或程序异常查看日志确认中断位置启用断点恢复从最后成功阶段继续输出内容质量下降模型选择不当对比不同模型的输出切换到更强的模型或优化 prompt并发任务被限流并发数设置过高查看 API 返回的限流信息降低并发数增加重试等待解析失败率升高输入数据格式变化检查输入数据的格式更新预处理规则增加容错缓存命中率低输入哈希不稳定检查哈希算法和输入规范化规范化输入后再哈希状态文件损坏写入过程中断检查状态文件完整性使用原子写入增加校验4.5 独家避坑经验分享第一个坑是过度依赖模型做确定性任务。项目初期把很多本该用规则处理的任务交给了模型结果不仅慢而且贵还经常出错。后来把这些任务改成规则处理后不仅成本降了可靠性也提高了。判断标准很简单如果这个任务的输出可以用 if-else 描述清楚那就不要用模型。第二个坑是 prompt 版本管理混乱。项目中期有段时间 prompt 改来改去改到最后不知道哪个版本是好的。后来引入了版本管理每次修改都记录版本号和修改原因可以随时回滚到之前的版本。这个习惯在后期排查问题时帮了大忙——当某个阶段表现变差时可以快速确认是不是某次 prompt 修改导致的。第三个坑是忽略了输入数据的预处理。项目初期直接拿原始输入喂给模型结果模型经常被输入数据里的格式问题带偏。后来加了一层预处理把输入数据规范化后再喂给模型输出稳定性明显提高。预处理包括统一换行符、清理多余空格、规范化特殊字符等看起来是小事但效果立竿见影。第四个坑是没有做充分的错误分类。项目初期所有错误都走同样的重试逻辑结果有些错误重试一百次也没用有些错误重试一次就好了。后来把错误分成格式错误、内容错误、超时错误三类分别用不同的重试策略重试成功率提高了不少。这个经验适用于任何跟模型交互的系统——错误分类是提高可靠性的关键。第五个坑是低估了状态管理的重要性。长流程任务的状态管理比想象中复杂不仅要记录每个阶段的输出还要记录阶段之间的依赖关系、执行顺序、重试次数等。项目中期重构了一次状态管理模块把状态设计成了不可变的数据结构每次状态变更都生成新的状态对象。这个设计让状态的回滚和调试变得非常简单。5. 从 Harness 到 Agent 的边界思考5.1 Harness 和 Agent 的本质区别很多人把 Harness 和 Agent 混为一谈但它们在设计哲学上有本质区别。Agent 的核心是自主性——模型自己决定做什么、怎么做、用什么工具。Harness 的核心是约束性——模型在预定义的管道中执行预定义的任务自主空间被严格限制。这个区别决定了它们适合的场景不同。Agent 适合开放性的、探索性的任务比如“帮我研究一下某个话题并写一份报告”。这类任务没有固定的流程需要模型根据中间结果动态调整策略。Harness 适合确定性的、流程化的任务比如“把这份文档转换成特定格式并提取关键信息”。这类任务的流程是固定的不需要模型做策略决策。在实际项目中两者经常结合使用。外层用 Agent 做任务规划和策略决策内层用 Harness 做具体执行。这样既有 Agent 的灵活性又有 Harness 的可靠性。项目里的做法是顶层用一个轻量的 Agent 做任务分解把大任务拆成小任务每个小任务交给 Harness 管道执行。这个混合架构兼顾了灵活性和可靠性。5.2 什么场景该用 Harness什么场景该用 Agent判断标准其实很简单如果你的任务流程可以用流程图清晰地画出来那就用 Harness。如果画不出来或者流程图里有大量的条件分支和循环那就用 Agent。Harness 的优势在于可靠性和可调试性——因为流程是固定的每个环节都可以单独测试和优化。Agent 的优势在于灵活性——能处理预定义流程覆盖不了的情况。另一个判断维度是任务的可重复性。如果同样的输入应该产生同样的输出那用 Harness。如果同样的输入可以有不同的处理路径那用 Agent。Harness 的确定性让它非常适合需要稳定输出的场景比如批量文档处理、数据提取、格式转换。Agent 的随机性让它适合需要创造性或探索性的场景比如内容创作、问题诊断、方案设计。成本也是一个考虑因素。Harness 因为流程固定可以针对每个阶段选择最合适的模型整体成本可控。Agent 因为需要模型做决策通常需要用更强的模型成本更高。在 token 预算有限的情况下能用 Harness 解决的尽量用 Harness。5.3 混合架构的实践要点混合架构的关键是定义好 Agent 和 Harness 之间的接口。Agent 负责把大任务拆成小任务每个小任务需要满足 Harness 管道的输入契约。这个接口定义清楚了两者就能顺畅协作。项目里的做法是Agent 输出一个任务列表每个任务包含任务类型和输入数据Harness 根据任务类型选择对应的管道执行。另一个要点是错误处理的分工。Agent 层面的错误比如任务拆分不合理由 Agent 自己处理Harness 层面的错误比如某个阶段执行失败由 Harness 内部处理。两层各自处理自己的错误互不干扰。只有当 Harness 内部无法处理时才把错误上报给 Agent由 Agent 决定是重试、跳过还是终止。还有一个要点是状态的传递。Agent 需要知道每个 Harness 任务的执行状态以便决定下一步做什么。项目里用一个共享的状态存储来管理Agent 和 Harness 都读写这个存储。Agent 写入任务列表Harness 写入执行结果Agent 读取执行结果决定后续动作。这个共享状态让两层的协作变得透明和可追踪。6. 工具链与生态集成6.1 Claude Code 在开发流程中的角色Claude Code 在这个项目中扮演了重要角色但用法可能跟大多数人想的不一样。它不是用来生成业务代码的而是用来做代码审查和重构建议的。项目里的做法是写完一个模块后把代码丢给 Claude Code 做审查让它指出潜在的问题和改进建议。这个用法比让它直接写代码更可靠——审查代码比生成代码对模型的推理能力要求更低输出质量更稳定。Claude Code 的另一个用途是生成测试用例。给它一个函数的签名和文档让它生成覆盖各种边缘情况的测试用例。这个用法效率很高因为测试用例的生成是相对确定的任务模型做得很好。生成的测试用例再人工审查一遍补充一些模型没想到的情况就能得到比较完整的测试覆盖。安装和配置 Claude Code 的过程这里不展开网上教程很多。重点说一下使用心得给它足够的上下文很重要。如果你只给它一个函数它只能看到这个函数如果你给它整个模块它能理解函数之间的关系给出的建议更有价值。项目里会把相关的类型定义、接口声明、调用方代码一起提供给 Claude Code这样它的审查质量明显更高。6.2 Obsidian 作为知识管理终端的配置要点Obsidian 在这个项目中不仅是输出目标还是知识管理的终端。管道产出的所有内容都进入 Obsidian 仓库通过文件夹、标签、内部链接组织起来。配置 Obsidian 时有几个要点一是文件夹结构要提前规划好不要等产出多了再整理二是标签体系要统一避免同义词标签三是 frontmatter 模板要标准化方便后续检索和筛选。Obsidian 的插件生态也很重要。项目里用了几个关键插件Dataview 用来做动态查询和汇总Templater 用来做模板自动化QuickAdd 用来做快速录入。这些插件让 Obsidian 从一个简单的 Markdown 编辑器变成了一个知识管理平台。特别是 Dataview可以用类 SQL 的语法查询笔记非常适合做产出内容的统计和分析。还有一个细节是 Obsidian 的同步策略。如果多台设备都要访问这个仓库需要配置同步方案。项目里用的是 Git 做版本控制和同步每次管道产出后自动提交到 Git 仓库其他设备拉取更新。这个方案的好处是有完整的版本历史任何一次产出都可以追溯和回滚。6.3 Markdown 生态工具的选型建议Markdown 工具链的选型直接影响开发效率。编辑器方面Typora 是最流行的选择之一所见即所得的编辑体验很好。但如果需要处理大量文件VS Code 加 Markdown 插件可能更合适因为可以批量操作和搜索。项目里两者都用——日常编辑用 Typora批量处理和搜索用 VS Code。Markdown 解析库的选择也很关键。Python 生态里常用的有 markdown、mistune、markdown-it-py 等。项目里用的是 markdown-it-py因为它的扩展性好可以自定义解析规则。而且它的解析结果是 token 流比直接生成 HTML 更灵活方便做二次处理。数学公式的处理需要额外的库。Markdown 本身不支持数学公式需要借助 MathJax 或 KaTeX 来渲染。解析层面需要识别数学公式的定界符并做特殊处理。项目里用的是 KaTeX因为它的渲染速度快而且对公式语法的支持比较完整。表格转换是另一个常见需求。Markdown 表格转 Excel 或者反过来都有现成的工具。项目里用的是 Python 的 tabulate 库做表格格式化用 openpyxl 做 Excel 读写。这两个库配合使用可以方便地在 Markdown 表格和 Excel 之间转换。7. 成本控制与规模化思考7.1 每月 40 亿 token 的成本构成分析40 亿 token 听起来很多但拆开看就合理了。假设每个任务平均消耗 10 万 token40 亿 token 就是 4 万个任务。九个月平均下来每个月大约 4400 个任务每天大约 150 个任务。对于一个自动化管道来说这个任务量并不夸张。成本构成上输入 token 和输出 token 的比例大约是 3:1输入占大头。输入 token 多的原因是每个阶段都需要把上游数据作为上下文传给模型。虽然项目里已经做了上下文精简但长流程任务的上下文累积仍然可观。优化输入 token 的主要手段是只传必要的字段、压缩上下文长度、用摘要代替全文。项目里对长文档做了分层摘要每个阶段只传相关部分的摘要而不是全文这个优化省了大量 token。输出 token 的控制相对容易主要是限制生成长度和避免冗余输出。项目里在每个阶段的 prompt 里都加了长度限制比如“输出不超过 500 字”。这个简单的措施让输出 token 降低了大约 30%而且输出质量没有下降——因为模型本来就不需要生成那么长的内容。7.2 规模化时的架构调整当任务量从每天 150 个增长到 1500 个时架构需要做相应调整。首先是并发控制需要更精细的速率限制和队列管理避免触发 API 限流。项目里用了一个令牌桶算法来做速率控制每个模型 API 有独立的桶请求前先从桶里取令牌取不到就等待。这个机制让并发请求平滑分布避免了突发流量导致的限流。其次是状态存储的扩展。单机文件存储在小规模下够用但规模大了之后需要换成数据库。项目里从文件存储迁移到了 SQLite后来又迁移到了 PostgreSQL。每次迁移都保持了接口不变所以上层代码不需要修改。这个经验值得借鉴——状态存储的接口要抽象好底层实现可以随时替换。还有监控和告警的完善。小规模时人工看日志就够了大规模时需要自动化的监控和告警。项目里建了一套指标采集系统采集每个阶段的成功率、延迟、token 消耗等指标超过阈值就发告警。这个系统让问题能在影响扩大之前被发现和处理。7.3 成本优化的长期策略成本优化不是一次性的工作而是持续的过程。项目里建立了一个成本优化的循环监控数据、发现异常、分析原因、实施优化、验证效果。这个循环每个月跑一次每次都能找到一些优化点。累积下来整体成本比初期降低了大约 60%。长期来看成本优化有几个方向一是模型选择的持续优化随着新模型的推出不断评估是否有更便宜且效果相当的替代品二是 prompt 的持续精简随着对任务理解的深入prompt 可以写得更简洁三是缓存的持续完善随着任务量的增加缓存的命中率会提高节省的 token 也更多四是规则引擎的持续扩展把更多确定性任务从模型调用改成规则处理。还有一个容易被忽略的方向是任务去重。很多任务其实是重复的或者高度相似的如果能识别出来并复用结果能省不少 token。项目里用了一个简单的相似度检测对输入做哈希和模糊匹配相似的输入直接返回缓存结果。这个机制在批量处理相似文档时特别有效。8. 个人开发者的项目管理经验8.1 单人项目的节奏控制一个人做九个月的项目节奏控制是生死攸关的事。项目里采用的节奏是每周定一个小目标每天记录进展每月做一次回顾。小目标要具体可衡量比如“本周完成输入解析层的表格处理”而不是“本周做输入解析”。每天记录进展包括完成了什么、遇到了什么问题、明天计划做什么。每月回顾看整体进度是否符合预期如果落后了就调整计划。节奏控制的关键是避免两种极端一种是冲得太猛连续高强度工作后精力耗尽另一种是拖得太久每天只做一点点项目迟迟完不成。项目里的做法是保持稳定的节奏每天工作六到八小时每周休息一天。这个节奏看起来不快但能持续九个月总产出反而比短期冲刺更高。还有一个经验是定期做“清理日”。每两周抽一天时间专门做代码清理、文档更新、待办整理。这些事平时容易积压积压多了会影响开发效率。清理日把这些事集中处理让平时的开发更专注。8.2 代码质量与开发速度的平衡单人项目最容易犯的错误是为了速度牺牲质量。短期内看起来快了但后期维护成本会急剧上升。项目里的做法是核心模块保证质量边缘模块可以适当妥协。核心模块包括管道调度、状态管理、错误处理这些基础设施它们被所有阶段依赖出问题影响面大。边缘模块包括具体的阶段处理器它们相对独立出问题影响面小。保证核心模块质量的手段包括写单元测试、做代码审查、定期重构。单元测试覆盖核心模块的主要路径和边缘情况代码审查用 Claude Code 做重构每两个月做一次。这些投入看起来拖慢了开发速度但实际上减少了后期的调试时间总体效率更高。边缘模块的妥协包括不写单元测试、不做代码审查、允许一定的代码重复。这些妥协的前提是边缘模块的接口清晰出问题容易定位和替换。项目里对边缘模块的接口做了严格定义实现可以粗糙但接口必须规范。8.3 持续学习的路径九个月的项目过程中技术栈在不断变化。新的模型版本、新的工具、新的最佳实践层出不穷。保持学习是必须的但要有选择地学。项目里的做法是每周花半天时间看行业动态每月花一天时间深入学习一个新东西。看行业动态是为了知道有什么新东西深入学习是为了真正掌握有用的新东西。学习的内容要有针对性。项目里主要关注三类内容一是模型能力的更新新模型在哪些任务上更强、成本更低二是工具链的更新有没有更好的解析库、更高效的开发工具三是方法论的学习其他人在做类似项目时有什么经验教训。这三类内容直接跟项目相关学完就能用上。还有一个学习途径是看别人的开源项目。GitHub 上有很多类似的项目看他们的架构设计、代码组织、问题处理方式能学到很多。项目里定期会看一些相关的开源项目借鉴他们的好的做法避免他们踩过的坑。8.4 心态管理与长期坚持九个月的单人项目心态管理比技术能力更重要。中间会有很多次想放弃的时刻——遇到解决不了的问题、看到进度落后、觉得做的东西没价值。项目里应对这些时刻的方法是回顾已经完成的部分看看从零到现在走了多远跟朋友聊聊把问题说出来往往就没那么可怕了暂时放下问题去做点别的事回来再看往往有新思路。长期坚持的关键是找到内在动力。如果只是为了完成一个项目而做很容易在遇到困难时放弃。如果是因为对这件事本身感兴趣遇到困难时反而会更有动力去解决。项目里的动力来自于对 Harness 架构本身的兴趣——想看看这种架构到底能做到什么程度想验证自己的想法是否正确。这个内在动力支撑了九个月的持续投入。还有一个经验是接受不完美。单人项目不可能做到尽善尽美总会有没处理好的边缘情况、没优化的性能瓶颈、没写完的文档。接受这些不完美把精力放在最重要的部分上比追求完美但迟迟完不成要好。项目里定了一个“足够好”的标准核心功能可用、主要路径稳定、关键问题有处理。达到这个标准就发布后续再迭代改进。9. 后续扩展方向与个人体会这个项目后续还可以往几个方向扩展。一是支持更多的输入格式目前主要处理 Markdown 和纯文本后续可以加上 PDF、Word、网页等格式的解析。二是支持更多的输出目标目前主要输出到 Obsidian后续可以加上 Notion、语雀、飞书文档等平台。三是增加更多的阶段类型目前主要是文本处理相关的阶段后续可以加上图像处理、数据分析等阶段。还有一个扩展方向是把管道本身做成可配置的。目前阶段划分和连接关系是硬编码的后续可以做成配置文件驱动用户自己定义阶段和连接关系。这个扩展会让 Harness 架构从专用工具变成通用平台适用范围大大扩展。但这也带来复杂性需要设计好配置格式和校验机制。我个人在实际操作中的体会是Harness 架构的价值不在于技术有多复杂而在于它把复杂问题拆解成了简单问题的组合。每个阶段只做一件简单的事但组合起来能完成复杂的任务。这个思路不仅适用于 AI 应用开发也适用于很多其他领域——把大问题拆成小问题逐个解决最后组合起来就是大问题的解。最后再分享一个小技巧在 Harness 管道中给每个阶段加一个“置信度”字段。模型在输出结果的同时也输出一个 0 到 1 之间的置信度分数。下游阶段可以根据置信度决定是否需要额外校验或人工介入。这个简单的机制让管道在保持自动化的同时对不确定的情况有了处理能力。置信度低的输出会被标记出来后续可以人工审查或者触发更严格的校验流程。这个技巧在长流程任务中特别有用因为长流程中错误的累积效应很明显早发现早处理能避免后面的大量返工。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →