ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Harness架构实战:一个人如何管住20万行代码与40亿token成本

Harness架构实战:一个人如何管住20万行代码与40亿token成本 凌晨两点我盯着云服务商的账单页面看着那个数字又往上跳了一格这个月token用量突破40亿。四十亿后面跟着八个零就这么被我一个人在一个房间里用九个月时间一点一点喂给了大模型API。同时项目代码仓库里的计数器停在20万行出头不算注释和生成测试数据也差了没多少。这是一款Harness架构应用——不是那种PPT里的架构概念而是真的要把每一笔token的流向、每一次模型输出的质量、每一层的降级兜底都管起来的实操框架。这篇文章写给两类人。一类是正在用大模型做产品的独立开发者你迟早会撞上“裸调API一时爽上线之后火葬场”的墙另一类是对“AI应用架构”这四个字还停留在概念层的朋友我把账单、代码和事故记录摊开给你看省得你再用真金白银去填同一个坑。先交代背景这款应用本质上是一个重度依赖大模型来完成信息处理和数据洞察的工具用户每一次操作背后都可能触发多轮模型调用、长文档解析、跨会话记忆重建。九个月时间线里我从第一行代码写到最后一个压测脚本期间没有团队没有QA没有运维唯一的外援是一个偶尔帮我review关键模块的老朋友。1. Harness架构说了什么不是给模型“踩油门”而是给模型“套缰绳”我见过太多团队把大模型接进业务的方式在业务代码里直接写一个client.chat()prompt里塞满示例然后祈祷模型别抽风。前两个月我做Demo阶段也是这么干的结果就是上线第三天同一个问题换了个问法模型输出的JSON结构变了前端直接白屏。Harness架构解决的就是这件事。我说的Harness不是指某个开源框架的特定名称而是软件工程里test harness那个概念的延伸测试夹具负责“把被测对象固定住按预定方式输入检查输出是否符合预期”。大模型应用里的Harness层做的就是同样的事——把模型固定在你设定的行为边界内检查它每次的输出不合格就重试、降级或走兜底逻辑。1.1 Harness层要管好的四件事第一任务规划。模型不是上来就回答问题的大部分复杂任务要被拆成“检索-推理-合成-校验”多个步骤Harness层需要决定走哪条链路。第二上下文组装。这决定了你花多少钱。同样一个用户问题是把30页历史文档全部塞进去还是先摘要成800字再喂给模型Harness层的上下文管理器必须对每一段进到模型里的内容做预算审核超了就压、该丢就丢。第三输出校验。模型输出天然不稳定Harness层要用结构化解析器、正则约束、字段存在性检查、语义比对把输出转成可靠的数据结构再交给业务层。第四降级路由。主模型超时、限流、返回格式跑偏的时候是重试一次还是换模型换更便宜的模型能不能扛住Harness层要有明确的策略。1.2 为什么我不用现成的编排框架很多人听说我自己写Harness层第一反应是“LangChain不是现成的吗”。我用过的感受是通用编排框架的核心价值是让你快速跑通原型但到了成本控制和细粒度约束这个层面抽象层太高反而碍事。对比维度通用编排框架自研Harness层原型搭建速度快半天就能跑通慢第一周都在写基础设施token预算控制粗粒度按链路由每个请求级别的精确核算输出可靠性靠提示词工程解析校验重生成闭环故障降级简单的fallback多级熔断成本感知路由可观测性依赖外部平台每笔token有trace_id我的结论是如果你做的是工具类产品Harness层必须自研哪怕规模小一点。框架适合做Demo不适合做要长期烧token的业务。1.3 Harness层第一个版本长什么样第一个版本其实很朴素核心就四个文件router.py路由策略、context_manager.py上下文组装与压缩、validator.py输出校验、budget_tracker.pytoken预算与用量统计。加起来不到3000行但就是这3000行撑起了后面10万行业务代码的稳定运行。后来20万行代码里Harness层膨胀到了将近3万行但最初的四文件骨架一直没有变。这给我的教训是架构的核心稳定面要早定业务面可以后长。2. 20万行代码的体积感一个人写代码最怕的不是写不出来是写出来没人兜底九个月20万行折算下来平均每天730行。但数字没有意义有意义的是这些代码是怎么分布的、为什么会膨胀到这个量级、哪些代码是“必须手写”的、哪些其实是“为了对抗复杂度不得不写”的。2.1 代码量的真实分布我的项目仓库五大模块的代码行数分布如下模块代码行数说明Harness核心层约3万行上下文管理、向量检索封装、路由策略、输出校验领域服务层约6.5万行业务实体、链式处理管线、任务编排、状态机、重试恢复集成适配层约2.5万行各类数据源连接器、认证、导入导出、第三方工具链前端与交互层约4万行工作台界面、结果渲染、流式输出组件测试与运维脚本约4万行900多个单测、压测脚本、数据回放夹具、部署流水线看到没真正贴着“业务”的代码只有三分之一剩下的全是在为“稳定”“可观测”“可测试”服务。很多人以为一个人写20万行是效率问题其实是工程底线问题没有团队里的其他人帮你盯质量你只能靠测试脚本和日志管线自己盯自己。2.2 手写和生成代码的边界写这20万行的时候LLM辅助编码已经非常成熟了。我实际写码过程中大概有三成代码是人工一句一句敲的剩下七成是在对话式编程工具里生成、再逐段review后合入。但这里头有个极其重要的原则基础设施和Harness核心层一行生成代码都不要用。原因很简单——这两层一旦出问题排查成本是几十倍的放大而生成代码最大的弱点是“看起来对边界情况全错”。业务层、适配器层可以放心用生成代码但必须有单测兜底。我给自己的规矩是合入生成代码前至少写一个针对它的失败用例。倒逼着生成逻辑把异常路径考虑清楚。2.3 一个人怎么保证代码质量没有团队质量全靠机制。我做了三件极其偏执的事第一核心数据结构的类型标注覆盖率100%不是90%是100%包括临时脚本里的数据结构也先定义再使用第二CI流水线里强制门禁测试覆盖率低于75%直接拒绝合入第三日志管线内置到Harness层每一条LLM调用的输入输出、token花费、耗时都带同一个trace_id落到本地存储里。这套习惯前期很痛苦尤其是一个人写代码还要写测试感觉像在自我折磨。但后面发生的事证明这三道防线救了我至少五次。3. 40亿token的燃烧路径每一笔token都要有去向否则账单会教做人每个月烧掉40亿token是什么概念按折算如果全用同一档位的旗舰模型这笔钱会非常夸张。但实际账单没那么吓人原因是我做了模型路由90%的简单任务走廉价轻快模型10%的重活才上旗舰模型。即便如此40亿这个体积依然说明一个事实——LLM应用的钱不是花在一次调用上的是花在“一次次忘记缓存、一次次白问、一次次无限重试”上的。3.1 先建立token台账再谈优化我把系统里所有LLM调用按模块打了标签。每个月末拉一次账永远按消耗量排序看前十项。这个习惯是从第三个月才开始有的前三个月我完全没做结果第一个月的账单比我预估的高了一倍而且根本说不清钱花哪了。建立台账之后问题清晰了。某个月的消耗分布大致如下模块token消耗占比说明长文档解析与递归切分33%文档切块后多次调用且每块自带系统提示词多轮Agent式任务编排28%任务步骤之间反复调用重试率偏高数据清洗与分类18%大批量小任务单笔便宜但量极大高频聚合查询无缓存13%相同问题反复询问模型校验失败后的重新生成8%输出格式不规范导致的重试浪费3.2 五个消耗黑洞的成因长文档解析之所以排第一是因为我早期用了“把整篇文档一次性塞给模型”的粗暴方案。比如一份4万字的技术文档光输入就吃掉几十万token再来几份文档一天下来就是千万级消耗。后来改成“先按语义切分成块每块做局部摘要再做全局聚合”token直接砍掉一半以上。Agent式任务的浪费在于重试风暴。我最初给每一步任务设了3次重试上限但没考虑“重试前先检查上一步输出是否可靠”结果经常是第一步模型产生幻觉后面所有步骤在错误前提上反复重试烧掉的钱全是白烧。Harness层后来加了一个前置校验门每步输出先做语义一致性初筛不合格的直接低成本重试而不是带着脏数据往下跑。校验失败重生成这个坑在结构输出上尤其明显。让我印象最深的一次我让模型输出带上下文的JSON但没告诉它输出里必须做HTML转义结果模型在某个字段里返回了一个未转义的双引号JSON解析挂掉系统按“失败”走了重试同样的token又烧了一遍。后来validator里先做结构修复再决定要不要重试把这类浪费压到了1%以下。3.3 40亿token的真实账本按混合路由的均价来算假设70%的token走约$0.3/M的轻量模型、30%走约$2.5/M的旗舰模型综合成本大概是$900/千token。月消耗40亿token即4000M token每月纯token成本大约在人民币数千到一万多的量级。具体取决于模型价格浮动但这个数量级对一个没有外部融资的独立开发者来说是每天都在滴血的数字。3.4 降耗三板斧缓存、压缩、路由我一共上了三层优化效果按降耗占比排名如下语义缓存对同义改写的高频提问做向量相似度匹配命中直接返回上次结果这一层砍掉了约15%的token。中间对话压缩多轮任务中超过3轮的上下文不再拼接原始对话而是先让廉价模型生成中间摘要再用摘要继续。这一层降低了约20%的消耗。模型路由用一个小型分类器判断请求难度简单查询直接走轻量模型只有复杂推理才让旗舰模型接手。这一层省下的成本和前面两层叠加总消耗从最初的每月70亿降到了40亿出头。我算过这笔账优化前如果完全不设防地跑第三个月就会因为成本压力终止项目。Harness架构里的budget_tracker.py从某种意义上是这个项目的救命恩人。4. 九个月的节奏感一个人一支军怎么不崩盘九个月不仅是技术战更是耐力战。我见过太多独立开发者做到第三个月激情褪去就搁浅了。这个项目能活下来靠的是把九个月拆成三个明确的小周期每个周期有完全不同的节奏和目标。4.1 三个阶段验证期、建设期、打磨期第一个周期是第1到第3个月验证期。这一个阶段的产出不是“功能”而是“风险是否可控”。我只做了三件事写好Harness核心层、用1000条真实工况数据跑模型输出、搭好token台账。当时定的退出条件是如果模型输出准确率低于85%或者单次用户请求平均token超过预算线项目立刻砍掉绝不恋战。第二个周期是第4到第6个月建设期。这一个阶段不追求完美追求覆盖。把Harness层的路由策略、上下文管理、降级逻辑全部扩容业务模块一个接一个填上去。到第6个月结束时代码量从3万行涨到14万行。这个阶段最大的坑是我急于铺功能导致测试覆盖率一度掉到60%以下CI门禁直接把几次合入拦下来我不得不硬着头皮回头补测试耽误了将近两周。第三个周期是第7到第9个月打磨期。此时功能已经齐全重点转到压测、调优、降耗和修边角。9个月快结束的时候我记得自己同时开着三个终端一个跑压测一个看token账单实时数据一个对着日志排查某条长尾请求为何每次都要卡6秒。4.2 个人开发者必备的工程化习惯一个人写九个月如果没有工程化习惯大概率会死在“改A坏BC又牵连D”的连锁崩坏里。我极度依赖三样东西每日单测不管当天多晚回家跑一遍全量测试再睡保证任何改动都不会留下隔夜问题。周发布每周五固定发一个版本哪怕这周没有任何新功能也要发保持交付节奏逼自己清理坏味道。日志索引所有LLM调用、路由决策、重试事件、token消耗全部结构化落盘事后排查不求人。4.3 如何对抗疲劳与信心波动九个月里我有两次瓶颈期都是熬到凌晨三点还对着一个诡异bug没头绪的时候。我的解药是老朋友的一句话“不要追着bug跑回去看数据。”LLM应用的bug尤其如此模型不会给你线性的因果链它是概率机器。当你觉得“怎么会输成这样”的时候把对应的prompt、上下文、输出样本全部拉出来对着真实数据看往往十五分钟内就能找到是哪条上下文污染了结果。另一个对抗疲惫的方法是做“胜利清单”。每周记下三个本周解决了的问题不用大小到“优化掉了一次多余的重试”也可以。九个月后回看这条清单你会发现自己已经跨过了一道远远超过预期的坎。5. 踩坑实录三场靠日志救回来的事故完整排查链路公开我前面怎么强调写日志都显得抽象。这一章我把三个真实事故的完整排查过程写出来你拿这个当模板去查自己的系统大概率能省下一周时间。5.1 事故一一次上下文超限引发的雪崩现象某天高峰时段系统连续飘出ERROR级别的HTTP 400状态码大量请求失败连带触发熔断。过程中我注意到失败请求的耗时单调递增从2秒一路涨到9秒。排查链路先看日志里的错误码一致指向context_length_exceeded再拉失败请求的trace_id发现都集中在一个入口长文档处理模块然后对比成功与失败请求的上下文碎片发现失败请求都带了同一种“历史上下文”——某个用户的操作路径触发了跨会话记忆重建而这个重建没有走上下文裁剪直接把此前所有会话的原始片段累计超过20万字符拼进了prompt。根因Harness层的上下文管理器在构建“跨会话记忆”时只做了按时间截断没有做按预算压缩。修复方法很直接跨会话记忆一律先经轻量模型压缩成结构化摘要原始文本只保留最近两轮。修复后这个入口的失败率从9%降到0.1%以下。5.2 事故二模型升级带来的“悄悄回归”现象某次上游模型列表变更后业务方反馈“答案变快了但质量变差了”。且没有报错、没有超时、没有token暴涨一切指标都正常。可怕的地方正在于此——不是显性故障是隐性劣化。排查链路先查模型路由日志发现部分本该走旗舰模型的复杂推理请求被切到了轻量模型因为路由分类器的输入特征里包含了“上游模型ID”这个字段而模型ID的降级映射在上游变更后把两个高能力档位错误映射到了低能力档位。也就是说分类器以为自己在用旗舰模型实际发往的是轻量模型。修复路由表里增加了一个“版本映射校验job”每小时检查一次模型映射关系与上游可调用清单是否一致不一致自动暂停相关路由分支并告警。这个事故之后我加了一条铁律模型供应商的任何配置变更都必须先在测试环境跑50组回归样本。5.3 事故三token计费里的隐蔽陷阱现象连续两周月度token台账显示下游平台统计的消耗是应用层记账的1.4倍。一开始我以为是统计时间窗口不一致后来发现不是。排查链路逐项对账发现差异集中在“工具调用模式”的请求上。应用层记账只算了用户prompt的token和模型回复的token漏掉了function calling机制里包含的工具定义JSON和tool call之间的多轮内部消息。这部分token账面看不出来但账单上一分不少。修复把所有带工具定义的请求在Harness层单独开启“完整计数”模式把工具schema和隐含轮次统一纳入预算统计。从此之后账目误差控制在1%以内。这条希望做Agent类应用的朋友特别注意工具调用的隐性token比想象中大得多。6. 九个月后的复盘清单十条写给同样在单打独斗的人的建议我没有做那种“下一阶段目标”的展望只把给后来者的建议钉在这里。九个月里最值钱的经验都不是从成功里得到的而是从“烧掉的token”“白写的代码”“凌晨的崩溃”里磨出来的。第一开头就建好Harness层。不要从裸调接口开始否则三个月后重构成本会高到你后悔。第二token台账第一周就要有。一开始就按模块、按接口、按trace粒度记录省得后面补账。第三上下文压缩必须前置。任何长文本多轮场景先压缩再拼装这是成本与质量的双重保障。第四路由分类器别把上游模型ID当唯一信号。版本映射常变要加交叉校验。第五每次模型输出校验失败先尝试低成本修复如结构补全再考虑重试否则重试只是重复烧钱。第六测试覆盖率不到70%不要开发新功能先补历史债。第七计费对账要区分“应用视角token”和“平台视角token”工具调用和思维链的隐含消耗必须单独核算。第八harness_id贯穿所有日志这是排查一切问题的基础设施。第九每周发布版本。节奏感能对冲孤独感。第十最累的时候不要写新代码去写测试或补日志。这些看似次要的工作会让你在下一周感谢自己。最后再分享一个细节我给Harness层的每个路由决策都配了一个形如harness://{session}/{step}/{model}的调用链标识符后来排查上游故障时只要在日志里过滤这个标识符就能精确看到每一次模型请求是被哪条策略路由过去的、因为什么原因降级、花了多少token。就是这些看起来笨拙的工程习惯让“一个人”“九个月”“20万行代码”“40亿token”这些数字真正变成了一款能跑、能扛、能省钱的产品。
返回列表