ARTICLE DETAIL

资讯详情

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

一个人+AI开发20万行代码:Harness架构与Token成本实战复盘

一个人+AI开发20万行代码:Harness架构与Token成本实战复盘 去年春天我给自己定了一个有点疯狂的目标一个人不组团队用九个月时间写出一款基于Harness架构的应用最终代码量累计20万行每个月要烧掉40亿 token的大模型用量。当时朋友听到后的第一反应是“一个人写20万行还全靠AI这项目能收得尾吗”。现在这个系统已经上线并稳定运行了三个多月我想把这九个月的踩坑和沉淀完整复盘一遍。这篇文章不写宏大叙事只讲我验证过的做法Harness架构怎么搭、AI辅助开发下token成本怎么控、以及我被各种token失效问题折磨出来的排查手册。它可以给想走同样“一个人AI”路线的开发者做一个参考也适合那些在观望AI编程工具到底能干多少活的人。1. 先回答三个问题为什么一个人、为什么Harness、为什么排九个月1.1 一个人做项目不是热血而是算清楚账我做的项目是一个数据处理自动化工作流平台核心是把“数据清洗、特征提取、模型训练、报表生成”这类多步骤任务串联起来由大模型在受控框架内决策和调用工具而不是做一个聊天机器人。启动前我认真评估过组队方案结论是没必要核心架构还没定型带人进来需要大量时间对齐认知沟通成本远大于实际产出。尤其在大模型应用这个方向很多设计问题只有自己动手跑过才知道答案别人很难靠开会帮你解决。一个人做决策链路最短晚上想到一个方案凌晨就能改代码验证。这不代表一个人什么都能扛。我的原则是确定性工程尽量自己设计重复性编码尽量交给AI。数据库表结构、接口契约、模块边界这类东西必须人脑想清楚因为它们一旦错了AI生成的20万行代码会全部跟着错。AI的角色是“放大我的工程量”——我出一份明确的设计说明书它能快速产出实现代码我再审、再改、再压测。这个循环跑顺了一个人确实能抵得上一个小团队。1.2 Harness架构到底是什么把大模型包进可控循环Harness这个词在圈内没有严格定义我更愿意把它理解为“模型工作流的外壳”——外部请求进来先被解析成标准化任务再进入调度器调度器把任务拆成多个子步骤每个子步骤可以调用函数、外部API、数据库也可以跟大模型交互每完成一步结果都会被校验不合格就带上错误信息回炉重试。结果是大模型只负责“决策”和“生成”不直接持有业务状态所有对外行为都有日志、有重试、有监控。为什么选这种架构而不是直接堆一个智能体聊天框因为智能体方案最怕“不可控”模型自由发挥工具随意调用出了问题只能看对话记录。Harness等于在模型外面套了一层交通信号灯红灯停、绿灯行走错了就绕路重来。我做数据分析平台时尤其需要这种可控性——数据不能被模型随便写错每一步都要可回滚、可审计。用Harness架构模型只是“车间里的机械臂”生产线什么时候转、往哪儿转都由调度器说了算。这种稳定性和可观测性比裸调模型高一个量级。1.3 九个月周期是怎么排出来的九个月不是拍脑袋。我把任务分成两类一类是确定性工程比如数据库设计、REST接口开发、前端页面时间可控按周估算另一类是LLM探索性任务比如工具调用格式、提示词策略、成本优化不确定性大我采取“最小可行版本先行”的办法先用简陋方案跑通再一轮轮打磨。九个月被切成三段前2个月打骨架中间4个月堆功能最后3个月重构和压测。实际进度偏差控制在了一个月以内主要靠每个阶段预留的缓冲余量。2. 20万行代码是怎么“长”出来的九个月时间线拆解2.1 第1-2个月先做能跑通的主循环哪怕它很简陋前两个月的核心任务只有一个把“调度→执行→校验→重试”的主循环跑通。我第一版主循环只有三个组件任务队列、执行器注册表、结果校验器。为了快速验证设计我甚至故意没接数据库直接用内存存任务状态先证明“模型能在一个受控循环里稳定干活”。这个决定当时看着草率回头看是关键——Harness架构最怕的不是功能少而是模型返回结果和业务执行器之间对不上。只有尽早暴露调度与LLM的交互问题后期堆功能才敢放开手脚。这段时间AI编程工具帮了大忙。我给助手描述清楚“任务对象长什么样、执行器返回什么格式”它能直接生成一整套数据模型和接口客户端代码。但我踩了个很典型的坑AI生成的数据模型太理想化把所有字段都设成必填导致实际接入业务数据时反复校验失败。从那时候起我固定了一个习惯——AI生成代码后的第一件事不是补功能而是先审数据模型和类型定义。类型不对后面写什么都是错的。2.2 第3-6个月功能堆量期按“执行器”为单位批量生产中间四个月是代码量增长最快的阶段也是40亿token消耗最凶的时期。我的工作方式变成了“执行器工厂”每周设计2到3个新的执行器比如数据清洗执行器、特征工程执行器、XGBoost模型训练执行器、报表生成执行器等。每个执行器提交给AI编程工具时我会附上一段统一的输入输出协议要求它按协议生成代码和单元测试。这一段产出速度非常惊人AI生成的代码占到了总量的七成但我的工作一点没轻松因为审查和修正它们花了大量时间。我总结了AI在这类任务上的强弱边界它擅长写样板代码、单元测试、接口封装、数据校验逻辑不擅长跨模块重构也不擅长理解复杂并发场景。比如让它改一个执行器的状态流转它常常只改局部忘了调用方结果编译都过不了。所以在堆量期我给自己定了一条规矩跨模块改动必须手动设计好接口再交给AI填充绝不让AI自己“顺便”改别的模块。这个规矩后来帮我少删了至少两万行废代码。2.3 第7-9个月重构、收尾和把LLM调用压出峰值最后三个月是前半段爽快堆代码的“还债期”。第一轮重构主要清理的是AI生成代码里的重复逻辑很多同类处理被散布在十几个执行器里我抽出了公共基类和工具函数20万行里大概有大几千行纯重复代码被干掉。第二轮重构改的是错误处理把散落的try/except统一成错误分类体系可重试错误和不可重试错误分开处理。收尾阶段还做了高并发压测发现LLM调用是绝对瓶颈——任务一多外部API的限流和超时就会拖垮流水线。也是在这三个月我真正把token成本当成了头等大事。压测期间单日token峰值能到1.5亿如果不加控制一个月的额度根本撑不住。我加了缓存、上下文压缩和并发限流最终让每月消耗稳定在40亿token的可控区间。20万行代码的构成也很值得说核心库约4万行上百个执行器约9万行前端约3万行测试代码约4万行。没有AI这个体量一个人九个月不可能完成没有人工审查这个质量九个月后也不可能上线。3. 每月40亿 token烧在哪AI辅助开发的成本账3.1 先搞明白Token是怎么被悄悄花掉的很多人觉得40亿token是个吓人的数字其实高强度AI辅助开发下很容易达到。主要花费用在三个地方第一是IDE里的代码补全它每次请求都会携带当前文件的上下文我打开一个5000行的模块文件时一次补全请求可能就要消耗8000到10000 token一天写代码加上反复触发补全轻松烧掉上百万第二是调试对话把报错日志、堆栈和代码片段喂给模型分析一段日志就是几千token多轮追问后单次会话能上万第三是我自己写的大批量自动化任务脚本比如批量生成单元测试、批量重构接口、批量审查代码风格一晚上处理几百个文件消耗几千万token非常正常。还有一个隐蔽的浪费点上下文重复发送。很多AI编程工具的补全和对话请求会把整个文件、甚至整个项目索引都带进上下文哪怕模型只需要看一个函数。这个问题在长文件上尤其致命我见过一次简单的“给函数加注释”操作实际消耗却相当于读了一篇短文档。如果不做管理token账单会像漏水的水龙头一样流走。3.2 40亿Token一个月的成本按参考价算笔账按40亿token来估算假设其中80%是输入token约32亿20%是输出token约8亿以通用大模型API的常见参考价格——输入约每百万token 1美元、输出约每百万token 8美元——算下来是类型数量单价参考费用输入token32亿1美元/百万约3200美元输出token8亿8美元/百万约6400美元合计40亿-约9600美元9600美元一个月折合人民币大概七万听着确实肉疼。但这是“全按标准价、不打折”的上限。实际运行中我做了几件事把成本压到三分之一水平命中缓存输入token会便宜很多简单生成任务用轻量模型处理只有复杂推理才用最强模型。所以标题里的“40亿token”不是虚张声势而是规模化使用AI编程后的真实消耗只是最终开销比数字本身温和得多。3.3 我实测有效的几个降本技巧成本控制从第一周就该做而不是月底看账单时才做。我用过的技巧里有几个效果特别明显上下文压缩让模型读“关键函数签名注释摘要”而不是整个文件。我写了个脚本自动提取文件里的类名、函数名、输入输出类型砍掉函数体补全和讨论都基于压缩版上下文单次请求能从8000 token降到1500 token左右。会话分段一个任务结束就开新会话不把历史对话留在上下文里重复计费。遇到长任务我会先让模型输出阶段性结论再带着结论开新会话继续避免几十轮对话的上下文不断翻倍。分级模型策略能干的活不请“专家”。简单翻译、写单元测试、生成样板代码全部走轻量模型只有架构设计、复杂调试、工具链协议设计才用最强的模型。整体token消耗不变但单价降了一大截。高频代码片段缓存我自己维护了一个“执行器模板库”把常用执行器的骨架、错误处理、日志格式都固化下来。AI生成新执行器时直接基于模板改而不是每次从零写生成质量和token开销都大幅改善。4. Harness架构应用的核心实现调度、状态与失败处理4.1 核心调度循环是整栋楼的地基Harness架构里最关键的是调度循环。我第一版写得很简单基本就是“从队列拿任务找执行器跑校验结果不对就重试”。这个循环跑通之后后面所有功能都是往这个圈里加东西。简化版的调度循环大概长这样# harness core loop (simplified) while task_queue: task task_queue.dequeue() executor registry[task.executor_name] result executor.run(task.payload) if not validator.check(task, result): task.retries 1 backoff 2 ** task.retries task_queue.requeue(task, delaybackoff) else: outbox.emit(task, result)这段代码虽然只有十来行但决定了整个系统的性格任务和执行器解耦校验失败自动重试重试有指数退避成功结果走outbox异步分发。后来加的高并发、优先级、定时调度都长在这个骨架外面。你可以把调度循环想象成餐厅的传菜台菜单进来排队后厨有人接单菜品出锅先经过检验不合格退回重做合格的才端给客人。传菜台的规则稳了整个餐厅才不会乱。4.2 工作流状态机每个任务都有明确的身份证复杂任务跑起来之后单靠队列和重试就不够了。我给每个任务引入了状态机把任务的生命周期明确定义出来。项目里的状态切换记录在案方便定位问题是出在调度、执行、还是校验环节。状态含义可转移到pending等待被调度runningrunning执行器正在处理succeeded / failed / requeuedsucceeded校验通过completedfailed执行出错且不可重试completedrequeued需要延迟重试pending状态机带来的直接好处是一个任务卡在哪里、为什么卡住打开表格一眼就能看到。我还给每个任务分配了全局唯一的task_id所有日志都带这个ID排障时按ID聚合日志就行。没有状态机的时候任务失败后到底有没有重试、重试了几次全靠猜这在生产环境是不可接受的。4.3 失败重试与幂等设计是稳定性之本Harness架构里最容易被低估的是幂等设计。任务重试意味着同一个执行器可能会被调用两次如果这个执行器不是幂等的数据就会被重复处理。我的解决办法是给每个任务生成一个request_id作为幂等键执行器在处理前先查“这个幂等键处理过没有”处理过就直接返回旧结果。存储型执行器尤其依赖这个机制写数据库、发消息、调外部API都必须带上幂等键。我还把错误分类成两类可重试错误和不可重试错误。网络超时、服务端5xx属于可重试业务参数错误、数据格式非法属于不可重试重试一万次也是白搭。调度循环里的validator.check就是错误分诊台它判断错误类型后决定到底重新入队还是直接标记失败这个判断让我少走了很多弯路。4.4 让大模型“按格式干活”协议与结构化输出Harness要是直接让大模型自由发挥结果一定乱套。我的做法是给模型规定严格的输入输出协议输入是标准化的任务对象输出必须是符合JSON Schema的固定格式。比如让模型判断一个数据清洗步骤是否完成它必须返回{status: success, summary: ..., score: 0.95}少一个字段就算校验失败。校验失败后不是直接放弃而是把校验错误信息重新喂给模型让它自己修。这个“生成→校验→反馈→再生”的循环是Harness的精髓类似于人写代码时跑测试看报错再改模型第一次输出可能有缺陷但有了反馈信号后第二次第三次的准确率会明显上升。我在执行器协议里都会写清字段含义和示例用上这招之后模型的结构化输出成功率从60%左右提到了95%以上。5. Token体系实战登录、续签与那些让人崩溃的错误5.1 Access Token和Refresh Token到底是什么关系做应用登录认证离不开Token我在这块也啃了不少硬骨头。简单说access token是短期凭证像停车场的临时卡有效期短过期就得重新领refresh token是长期凭证像车牌号可以用来换新的临时卡。JWTJSON Web Token是现在最常见的access token格式因为它自带签名和过期时间服务端不用存session就能校验。但JWT有个天然痛点一旦签发在过期前没法主动撤销。所以主流的做法是“短access token 长refresh token”access token设30分钟到2小时过期refresh token设7到30天并且可以旋转。用户快过期时前端用refresh token去换新的access token用户无感知。这样的好处是即使access token泄露攻击窗口也很短。5.2 我给应用做的JWT续签方案我实现续签逻辑时写了一个简单的token管理模块核心思路是提前几分钟检查过期时间快过期就用refresh token换新。简化代码长这样import time import jwt def get_valid_token(access_token, refresh_token, access_expires_at): # 提前5分钟检测避免请求打到一半token失效 if time.time() access_expires_at - 300: new_pair exchange_refresh_token(refresh_token) return new_pair[access_token], new_pair[refresh_token], new_pair[expires_at] return access_token, refresh_token, access_expires_at这里有个容易踩的坑refresh_token只能用一次如果客户端并发多个请求同时去续签后到的那个会失败。我的解法是在续签路径上加一个线程锁保证同时只有一个续签请求在跑其他请求等待新token下发。每次续签还会检测refresh_token是否被重复使用一旦发现重复使用就判定为泄露让整个会话失效强制重新登录。5.3 高频报错排查实录一张表帮你定位Token问题开发期间和上线后我被各种token报错折磨过。下面这张表是我根据实战整理的速查手册报错信息和排查思路都验证过。报错信息可能原因排查与解决sign-in could not be completed token exchange failedOAuth授权码换token时出错回调地址不一致或授权码已过期核对redirect_uri与注册配置完全一致开启PKCE重新走授权流程token endpoint returned 403 forbidden客户端账号权限不足或被服务端策略拒绝检查账号是否启用、scope是否合法、请求头是否正确failed to refresh token: 400 bad requestrefresh_token为空、格式错误或已经失效检查token存储字段没被截断重新登录生成新refresh_tokenyour access token could not be refreshedrefresh_token旋转失败服务端已把它标记失效清理本地缓存凭证让用户重新登录auth token is unavailable本地凭证文件不存在、格式损坏或环境变量没加载重新登录生成凭证文件检查环境变量和配置文件路径还有一个我经常忽略的原因服务器时间漂移。JWT的签名和过期时间校验依赖系统时间服务器时间不准会直接导致“token居然提前过期”的诡异现象。排查这个只需要在服务器上对一次时间偏差大就启用NTP时间同步能解决一大批莫名其妙的认证问题。5.4 和AI编程工具联调时的认证坑项目开发期间我每天跟AI编程工具打交道工具的登录态问题也踩了不少。最常见的是token exchange failed类错误通常发生在登录授权流程里授权端点返回异常、回调地址不匹配、本地缓存凭证过期。这些错误看起来吓人排查思路很固定——先看本地配置文件里凭证是否存在和过期再看登录流程有没有走完最后确认账号权限。我的建议是使用AI编程工具的CLI登录时尽量一次性走完整授权流程不要在多个终端窗口同时触发登录本地凭证文件要做好备份因为不少工具一旦凭证失效就是“请完全登出再重新登录”不会自动修复。另外环境变量配置要认真检查很多API客户端会优先读某个环境变量配置了旧值会导致新token不生效表现就是“明明重新登录了还是报认证失败”。6. 一个人维护20万行代码经验与边界6.1 怎么审查AI生成的代码才不会变成“高级CtrlC”AI写代码速度快但质量是参差的。我给自己总结了一套审查流程先看类型和接口定义再看异常处理最后看并发和资源释放。类型不对直接打回重写没有异常处理的代码跑一次真实数据就会露馅涉及文件句柄、数据库连接、线程池的代码必须人工确认资源释放不能全信AI。审查不通过的部分我会把具体问题反馈给AI让它改而不是自己默默改这样它能慢慢学会我的代码风格。我还有一个私人的“熔断规则”同一个模块如果AI连续三次生成还需要大改我就停下手来自已写不再跟它耗。因为这说明这个模块的复杂度超出了它从上下文里能理解的范围继续生成的边际成本很高。宁可自己写两小时也别跟AI耗半天的对话token。6.2 模块边界和命名比想象中更重要20万行代码靠记忆力维护是痴人说梦模块边界是唯一可靠的导航。我把系统分成核心调度层、执行器层、基础设施层三层每一层有明确的依赖方向执行器只能调用基础设施不能反向触碰调度核心。这个约束我在代码评审时盯得很死一旦发现执行器里出现了调调度器的代码一律重构。命名规则也吃了不少亏才定下来。执行器统一定义成“动词对象”格式比如clean_data、train_model、generate_report任务状态统一用枚举而不是魔法字符串。AI生成的代码里经常出现process_data_v2_final这种命名我会统一清理掉。规范命名不是为了好看是为了让AI在下一次生成时也能遵循同样的协议减少沟通成本。6.3 给也想“一个人AI”做项目的朋友的建议如果你也在考虑一个人加AI做大型项目我最大的建议有这三条先把主循环跑通再谈漂亮功能。无论做什么系统先用一个最简陋的版本打通端到端链路后面所有功能都是往这个链路上挂新节点而不是推倒重来。把token账算明白再动手。不要等账单出来了才优化。从一开始就做上下文压缩、分级模型、缓存策略否则成本失控会让你在项目中途被迫换方案。给不确定任务留缓冲。排期时先搞定确定性工程把LLM探索性任务前置到项目前期因为模型协议、提示词策略这类问题不试不知道答案留到最后会挤掉重构时间。我的体会是AI确实能让一个人干出十个人团队级别的代码量但架构决策、问题定界、成本控制这些核心能力最终还是得靠自己撑起来。项目上线三个月后我正在做的是把这套Harness内核抽出来做成一个可复用的调度底座。如果你这也是一个人在硬扛复杂项目记住一句话先让主循环跑起来再谈剩下的。九个月听起来很长但真的足够造出一款能稳定运行的应用前提是每一步都踩在可控的节奏上。
返回列表