ARTICLE DETAIL

资讯详情

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

AI原生应用单人开发:Harness架构设计与40亿Token成本控制实录

AI原生应用单人开发:Harness架构设计与40亿Token成本控制实录 一个人、九个月、20万行代码、每月消耗40亿 token这四个数字往桌面上一摆大多数人第一反应是我在讲段子。但这就是我今年真实的工作量。我从零做了一款基于 Harness 架构的 AI 原生应用从需求梳理、架构设计、前后端代码、部署上线到每个月几十亿 token 的账单管理全是自己一个人扛下来的。过程中我重度依赖 AI 编码工具和自建的自动化编码流水线每天有大把时间不是在写代码而是在和模型对话、让 agent 替我跑测试修 bug。也是在一次次模型调用的“失控”和“烧钱”里我才真正理解 Harness 架构要解决的根本不是什么技术炫技而是“一个人能不能驾驭一套大型 AI 系统”这个最现实的问题。这篇文章不打算讲某个框架的用法。我想做的是把搭这套架构的完整思路、token 成本的拆分模型以及九个月里踩过的真实大坑全部摊开来说。如果你也打算一个人做 AI 应用或者正在小团队里处理大量模型接入的问题下面的内容应该能帮你省下不少学费。1. 为什么必须自己设计一套Harness架构——一个人开发AI应用的失控困局1.1 单枪匹马根本接不住几十个外部依赖AI 原生应用和传统应用最大的区别在于系统里流动的不再只是你写的代码而是大量“外部模型行为”。LLM 接口可能限流、可能改版、可能返回非法 JSON、可能在某个 prompt 下突然胡言乱语第三方工具 API 可能挂掉、可能延迟、可能悄悄变更字段向量库、缓存、消息队列这些基础设施也会有自己的怪脾气。如果这些不确定性都直接散落在业务代码里一个人根本盯不过来。我做这个项目的第一周就犯过这个错。当时直接把 OpenAI 客户端的调用写进了业务逻辑里结果模型一改返回格式我的数据解析层就崩了一片更别提账单上莫名其妙的 token 翻倍。那种感觉就像一个人同时开十台服务器每台服务器都有自己的脾气而你只有一双手、一双眼睛。你必须想清楚怎样让这些不可控的东西全部收敛到一个自己能控制的层里而不是让它们在整个代码库里到处乱窜。1.2 “驾驭”才是这个架构的第一性原理Harness 这个英文词的本义是“马具、控制装置”。在 DevOps 领域Harness 也是一款软件交付平台的名字但这里我所说的 Harness 架构是对“驾驭层”这种架构思想的一个自我命名。它的核心定义很简单所有外部不可控能力——大模型、第三方工具、数据源——都必须通过一个标准化的接入层来驱动业务代码不允许直接触碰任何外部依赖。这个定义背后是一条铁律业务层只面对稳定、可控的内部抽象外部世界的变化被锁在上层接口之后。这样一来换了模型、改了 API、新增了工具业务代码一行都不用动。我给自己定的架构原则后来固定成四条外部依赖收敛任何模型、工具、数据源的更换都不影响业务逻辑。全链路可控请求从进入到返回每一步都有日志、token 计数、耗时记录。成本可见每个业务行为都能换算成 token 消耗每一笔成本都能追溯到用户和功能。失败可恢复模型出错、工具超时系统自动降级或重试而不是直接把错误抛给用户。这四条看似简单但真做到需要一整套层设计也就是下文的五个核心层。1.3 和传统架构的差别它管的是“外部智能体的不确定性”很多人听到分层架构、六边形架构第一反应是这不就是换了个名字吗确实有重叠但关注点完全不同。传统分层架构解决的是代码组织和依赖方向问题六边形架构解决的是领域与技术细节的隔离问题而 Harness 架构解决的是外部智能体和工具的不确定性治理问题。举一个直观的例子传统分层架构里Service 层调用 Repository 层Repository 层操作数据库这个链路是可控的因为你写的代码是你完全掌握的。但 AI 应用里你的 Service 层可能要调用一个不稳定的模型 API模型给出的输出你不能百分百预测期间还可能穿插工具调用、检索召回、多轮 agent 决策。这种“非确定性”是传统架构很少考虑的一等公民问题。Harness 架构就是把这个不确定性圈出来用网关、校验、计量、回滚这些手段让它变成一个可以预测、可以控制的过程。2. Harness架构的五个核心层——从模型接入到业务输出的全链路控制2.1 接入网关层模型路由与请求收敛我第一个动手写的模块就是模型网关。这个模块的核心职责是统一收口所有模型调用让业务层永远不要关心“这次是哪个模型在处理”。所有请求都带一个任务类型标签网关根据任务类型、上下文长度、实时成本策略决定是走大模型、小模型还是缓存结果。我维护了一个 model registry大致长这样MODEL_REGISTRY { chat: { primary: claude-3-7-sonnet, fallback: gpt-4o, context_limit: 200000, cost_per_1k_in: 0.003, cost_per_1k_out: 0.015, }, light: { primary: gpt-4o-mini, fallback: claude-3-5-haiku, context_limit: 128000, cost_per_1k_in: 0.00015, cost_per_1k_out: 0.0006, }, embedding: { primary: text-embedding-3-small, context_limit: 8000, cost_per_1k_in: 0.00002, cost_per_1k_out: 0.0, }, }网关层的路由逻辑就是读这个配置按任务优先级和成本预算打分。比如“高价值用户”和“运营内部测试”可以走强模型普通日志总结、分类标签这类任务一律走 light 档。现在很多大厂宣传的“模型路由”本质上就是这个思路只不过我一个人用一个字典就能实现。除了路由网关还要负责请求合并和熔断。合并指把同一用户短时间内相同上下文的请求聚合成一次调用熔断指某个上游模型连续超时或报错时自动切到备用模型并给运维端发告警。没有这一层一旦模型服务商出故障我的应用会立刻变成一个连环报错的雪崩现场。2.2 成本核算层token计量与预算熔断标题里“每月烧掉 40 亿 token”这个数字不是模糊估的而是成本核算层一行行记账记出来的。我建了一张计量表每个请求进来先按配额预检出去后精准计费落表。表结构不复杂但这条账必须从第一天就开始记CREATE TABLE token_usage ( id BIGSERIAL PRIMARY KEY, request_id UUID NOT NULL, user_id VARCHAR(64), project_id VARCHAR(64), model VARCHAR(64), task_type VARCHAR(64), input_tokens INT, output_tokens INT, cached_tokens INT DEFAULT 0, cost_usd NUMERIC(10, 6), latency_ms INT, created_at TIMESTAMPTZ DEFAULT now() );这张表是我九个月里最重要的“驾驶舱仪表盘”。每天凌晨会跑一个汇总任务输出各业务线的 token 消耗分布、平均时延、单用户成本。到了月底账单出来后我能精确到“哪个功能模块烧掉了多少钱”。没有这张表40 亿 token 就是一笔糊涂账优化也就无从谈起。成本核算层还要做一件事预算熔断。我在配置里设置了日预算阈值比如某个项目的日成本超过 120 美元时自动把该项目的模型路由全部降级到 light 档并发告警通知我。这算不上什么黑科技但很实用。AI 应用最容易出的账单事故就是某天功能异常导致循环调用日成本从几十美元直接飙到上千美元。熔断可以在还没烧爆之前拉停。2.3 上下文管理层记忆与检索的标准化AI 应用的上下文管理是个很藏钱的地方——很多人以为模型输出才贵实际上是输入 token 中的历史记录、工具返回结果、检索片段在悄悄吃掉大部分账单。上下文管理层的目标很简单让每次请求只带着最必要的信息去见模型。我做了两件事。第一件对对话历史做“对数窗口压缩”最近的完整保留稍早的做摘要再早的只留关键事实。这个过程本身也会花一点 token但相比每次都把整段历史倒给模型节省量非常可观。第二件把向量检索封装成统一的“记忆接口”。业务层只需要说“取某用户近期关于某个主题的记录”上下文管理层会自己决定用关键词还是向量召回再按配置把结果裁剪成合适的长度。一个在实操中很值得注意的点检索回来的内容不是越多越好。塞太多无关片段给模型它会被噪声带偏输出质量不升反降还白白烧掉输入 token。我在早期吃过亏后来把单次检索注入的片段数量上限设置为 5 段、每段 200 token效果比塞进 20 段碎片好很多。2.4 工具执行层让模型安全地调用内部能力当 AI 应用开始让模型调用外部工具时事情就会变得复杂。模型要“说人话”但工具要“说结构化数据”这中间必须有一个翻译层。Harness 架构里的工具执行层就是负责把模型想发起的动作翻译成对内部系统的安全调用。我定义的工具接口统一使用 JSON Schema 描述输入输出并且给每个工具设置了超时时间、调用权限、结果截断长度{ name: create_ticket, description: 创建一条用户工单, input_schema: { type: object, properties: { user_id: {type: string}, priority: {type: string, enum: [low, medium, high]}, content: {type: string, maxLength: 2000} }, required: [user_id, content] }, timeout_ms: 3000, truncate_result: 500 }工具执行层的价值在于权限隔离。模型不能直接查数据库不能直接发邮件只能通过注册过的工具去操作。每个工具的调用都会被记录进日志方便事后审计。一个人开发时很难保证所有模型输出都干净但至少可以让所有“危险动作”都必须经过受控的工具接口。2.5 校验与回滚层给AI输出装上“安全气囊”模型输出是不可信的这是 AI 应用开发的底层认知。校验与回滚层要做三件事格式校验、语义校验、失败回滚。格式校验最简单也最刚需。要求模型返回 JSON就先定义 JSON Schema再用解析器验证字段是否存在、类型是否正确。我遇过太多次模型输出里混入多余逗号、错误转义甚至直接输出 Markdown 而忘了 JSON 的场景。语义校验更高级一点比如一个“判断用户情绪”的功能模型输出“正面”但后面的分类逻辑发现与用户留言明显矛盾这时就要触发重试或降级。失败回滚是我一开始没做、后来哭着补上的功能。具体做法是AI 输出一旦涉及写操作比如更新数据库字段、修改状态必须先把旧值快照放到一个事务上下文里校验通过后才提交提交失败则自动回滚。这挽回过好几次灾难性事故其中最严重的一次是模型在输出中把一批订单状态写成了已取消如果不是回滚机制兜底那天的损失就不是几美元 token 的问题了。3. 40亿token都烧在哪了——AI原生应用的成本解剖与省钱打法3.1 先把账算清楚一个月40亿token意味着什么40 亿 token 拆开算其实没那么吓人。按月 30 天折算每天约 1.33 亿 token如果应用日均处理 3 万次用户会话平均每次会话消耗 4000 到 5000 token这个量包含多轮对话、上下文注入和工具返回总账是吻合的。九个月跑下来我对月账单做过一次完整的拆解消耗分布大致如下消耗方向占比说明运行时用户交互推理50%线上应用直接服务用户的模型调用开发期编码流水线25%AI agent 自动写代码、改 bug、重构自动化测试与质量门禁10%mock 之外的少量真实模型验证知识库/数据处理5%文档向量化、数据清洗、离线分类重试、熔断与缓冲10%各种失败重试和降级预留多数人只盯着第一类“用户消耗”但实际上开发期的 25% 也是一笔不可忽略的固定成本。因为你每次让 agent 跑一个重构任务都可能烧掉几十万 token。3.2 运行时token的大头上下文输入才是隐藏吞金兽很多人的成本直觉是模型输出贵所以控制输出长度就能省钱。但真实账单分析下来输入 token 往往占总量的 60% 到 70%。尤其是 agent 模式——为了完成一个任务模型可能要来回调用工具十几次每次调用都要把之前的全部工具结果重新塞回上下文。压缩输入有几个立竿见影的方法缓存热门问题的回答。相同或相似的问题直接命中缓存不调用模型。把工具返回结果做摘要。工具返回的原始 JSON 可能很大注入给模型前先洗净、压缩成要点。控制多轮 agent 的对话轮数。一个任务在五轮内解决不了的就拆成两个子任务而不是继续叠上下文。批量延迟推理。一些非实时功能比如日报总结、数据分类攒到低峰期批量跑既省成本又避免高峰熔断。我做过一次对比实验只优化上下文输入不换模型、不改业务逻辑月度 token 消耗下降了 22%。这说明 Harness 里上下文管理层的优化空间比换模型大得多。3.3 开发期token怎么花才能值回票价开发期烧掉的 token本质是“用钱买时间”。回想九个月里最贵的几次 AI 编码会话都是因为贪多——一个 prompt 里塞了五六个需求让 agent 一次改完结果它改出一堆垃圾然后又要花更多轮次去修。后来我总结出一条规律任务拆得越细token 越省代码质量越高。我给 agent 喂任务的标准模板是四段式背景、目标、约束、验收。一个任务只对应一次小改动比如“给订单模型的 xx 字段加一个唯一索引并补充对应迁移脚本不允许改动其他文件”。这样一次会话一般能控制在几万 token 以内而且成功率远高于大而全的 prompt。真正效率起飞的是夜间自动化流水线也就是我下章会详细写的 agent 循环。它会在没有任何人盯着的状态下批量执行“生成代码—跑测试—收集错误—修复—再测试”的循环。这种循环里 token 消耗确实猛但它是真正在替我省人工时间。我算过一笔账一次自动化重构烧掉 300 万 token差不多 10 美元左右如果换成我手工改这些代码至少要三个晚上。这笔账怎么算都不亏。3.4 从账本里总结出来的成本公式如果你想评估自己的 AI 应用月成本可以直接套这个公式月成本 日均请求数 × 平均单请求 token 数 × 30 × 每百万 token 综合价格这里的“每百万 token 综合价格”建议叠加上输入输出混合价而不要只看模型页面的单价。按我常用的混合模型配置综合价格大约在每百万 token 0.5 到 1 美元之间考虑用量、缓存折扣后。按这个公式反推日均 3 万请求、请求均 token 4500一个月差不多就是 40 亿 token、约 1500 到 2500 美元的实际成本。个人独立项目不是一个小数所以预算熔断必须从第一天就接好。4. 9个月、20万行代码、一个人——AI辅助开发的大型项目管理实践4.1 先接受现实AI会让代码量像滚雪球写下“20 万行”这个数字后很多人的第一反应是我在过度设计。但我必须说一句公道话AI 生成的代码天然比手写代码膨胀 30% 到 50%。模型倾向于自包含喜欢做防御性判断一个简单的 getter 它可以写上五六行注释和判空逻辑一段查询没准给你拆成三个中间变量。这些代码确实“冗余”但也不是完全没用。独立开发者应该做的不是骂 AI 生成垃圾而是接受“代码量会涨”这个现实然后用工程手段兜住。兜住的核心手段就是严格区分“核心代码”和“外围代码”。核心领域模型、关键业务路径、数据一致性逻辑必须我自己一行行写、一行行 reviewCRUD 接口、中间件、工具函数、配置文件、测试用例这类“体力活”才大胆交给 AI。这个分工在九个月里被证明非常有效——AI 写外围代码速度极快而我把有限的脑力集中在最不能出错的核心。4.2 目录结构与模块边界是保命底线一个人写 20 万行代码最大的挑战不是写不出来而是改了 A 就炸 B。为了避免这种情况我在项目根目录上花了很大心思结构大概长这样app/ gateway/ # 模型网关、路由、熔断 harness/ # Harness 核心层计量、上下文管理、工具注册 domains/ # 业务领域模块按子业务隔离 order/ user/ search/ tools/ # 智能体可调用的工具实现 workers/ # 异步任务、夜间 agent 流水线 shared/ # 通用工具库、常量、错误定义 tests/ unit/ # 单元测试 integration/ # 集成测试 e2e/ # 端到端冒烟测试 scripts/ # 部署、数据修复、批量任务模块边界的原则是依赖只能从业务模块指向 harness 层harness 层不允许反向依赖任何业务模块。这个约束是红线AI agent 自动生成的代码曾多次尝试绕过它——比如在我的业务模块里直接 new 一个 model client——后来我用静态检查工具把这个规则固化成 lint 规则谁违反谁报错AI 也不行。4.3 让AI agent流水线替你干“代码苦力”九个月里真正让我一个人撑到最后的是我写的那套 agent 循环流水线。它的运作方式很简单任务队列里放着一个个拆好的开发任务流水线按顺序丢给 agentagent 自主完成“读代码—写代码—跑测试—修 bug—再跑测试”的循环直到测试通过或达到最大重试轮数。夜间空闲算力充裕可以让它跑批量任务早上醒来就能拿到一批可运行的代码。我给这套流水线写过一个极简版的伪代码逻辑核心循环大概是这样for task in task_queue: for attempt in range(MAX_RETRY): code_patch llm.generate_patch(task.description, repo_snapshot) apply_patch(code_patch) report run_tests(task.affected_tests) if report.all_pass: task.status done break else: task.feedback report.relevant_errors llm.fix(code_patch, task.feedback)这套循环看着简单但有三点细节极其重要一是每次只改一个任务禁止跨任务混动二是测试必须先行没有测试覆盖的变更一律不合并三是给 agent 的反馈只给错误摘要不要把整个日志倾倒给它否则上下文会迅速爆炸。我自己统计下来这套流水线能解决大约七成外围代码的开发剩下的三成核心工作还是留给我自己。4.4 测试策略20万行代码的安全网没有测试一个人改 20 万行代码就是自杀式行为。我的策略有一点反直觉AI 生成的代码反而更需要测试因为它自己不会主动保证质量测试是唯一的外部约束。测试分三层。单元测试直接让 AI 生成覆盖每个模块的正常与异常路径集成测试集中在业务链路比如“订单创建—支付回调—库存扣减”这种跨模块流程必须我自己设计测试场景再让 AI 补代码冒烟测试则是最低准入条件每次部署前必须全部通过。这里有个省钱技巧凡是与模型相关的测试一律用 mock 而非真实调用。我建了一个 mock 模型服务返回预设好的响应这样测业务逻辑时不会烧一点真实 token。只有专门测试“模型适配器”本身时才跑少量真实请求这部分 token 才计入测试成本。4.5 版本管理与复盘节奏按月做一次“代码债务审计”代码规模一大技术债会以惊人的速度堆积。我以月为里程碑每个月末跑一次 AI 生成的代码分析报告把 TODO 标记、废弃函数、重复代码、长函数列表全部拉出来再结合线上错误日志圈出下个月必须重构的模块。这种复盘做和不做差别非常大。我第三个月时没做审计结果代码库里积累了十几个几乎没人能看懂的“AI 自创模式”改一个功能要翻半天。后来坚持按月梳理每次只挑五到八个重构点执行代码库的状态就可控多了。AI 工具的定位不是替你一路狂奔而是在狂奔之后帮你快速清理战场。5. 我在九个月里踩过的五个大坑——每个坑都是一个故事5.1 上下文爆炸让AI改代码结果把自己的代码改没了第四个月的时候我让 agent 去重构一个支付模块。当时为了省时间我把一个 3500 行的错误日志整个丢进 prompt让它自己找问题。结果 agent 在长长的上下文里迷了路非但没修好原来的 bug反而误删了一个订单状态转换的 handler。那次事故让我意识到给 agent 的信息越多不等于它越聪明反而更容易出错。从那以后我给 prompt 的信息永远只保留“背景—目标—约束—验收”四要素任何超过 20KB 的日志都会先做一次裁剪和摘要再喂进去。5.2 模型幻觉悄悄进了生产JSON校验捞了我一把有一次模型在生成“用户标签”时凭空造了一个文档里从未出现过的标签分类而且这个标签直接落进了生产数据库。表面看只是数据多了一个奇怪值但这个值被下游推荐逻辑读到时产生了一批完全不合理的推荐。这个事故让我真正理解了校验层的意义——它不是用来防大事故的而是用来防这种漫天飞舞的小幻觉的。补上 schema 校验和枚举白名单检查之后这类问题基本不会再见天日了。5.3 过早引入微服务单人团队的架构反噬一开始我把项目拆成了六个微服务以为这样“拆分清晰、边界明确”。结果一个人运维六个服务每次部署要处理六套日志、六套环境变量、六套依赖版本。第三个月我把它们合并成一个单体应用加一个异步 worker边界靠模块而非部署单元来维护。几乎所有同行经验都指向同一件事一个人的项目不需要微服务需要的是清晰的模块边界。微服务解决的问题是组织协作问题不是代码规模问题。5.4 把prompt硬编码进业务代码升级模型时想哭有三个月的时间我所有 prompt 模板都直接写在业务代码里。当时觉得很方便反正只有我一个人用。直到第四个月要全面升级模型测试发现新模型对旧 prompt 的理解偏差很大我才意识到prompt 也是一种需要版本管理的“配置资产”。后来我把所有 prompt 模板外置成一个配置目录结构类似{ template_id: order_summary, version: 12, model_family: claude, content: 你是一位订单分析助手…… }升级模型时我只需要为新的模型家族开一个新版本模板线上可以灰度对比。这个改动成本不大但让模型升级从“大手术”变成了“小操作”。5.5 不看token审计月底账单翻倍才发现的重复调用这是 가장让我肉疼的一坑。第七个月底拿到账单发现 token 消耗翻了一倍又三分之一赶紧查计量表发现某条批处理任务在循环里重复调用了同一个模型接口——原本应该只跑一次的文本分类在嵌套循环里跑了四遍而且这个任务已经跑了两周。这个教训的关键不是“有 bug”而是我直到账单翻倍才发现。从那以后我把 token 审计做成了每日例行任务每天扫一遍“请求量异常成本突刺”的报表宁可多看两遍也不能让这种隐匿消耗持续大半个月。6. 如果你想复刻这条路——启动清单与止损建议6.1 什么样的项目才适合“单兵AI”这种模式不是所有项目都适合一个人配 AI 硬刚我列了几个判断标准核心壁垒在产品体验和功能完整度而不是纯规模竞赛。需要大量“不核心但必须做”的代码——管理后台、API 封装、对接脚本。你自己非常清楚产品该长什么样能把需求拆成 AI 能听懂的小任务。业务对实时一致性要求不太极端能够接受偶尔的模型输出回滚和重试。反过来如果你的项目处于强监管环境、涉及复杂的分布式共识、或者核心算法需要长周期研究那这套模式大概率不适合。AI 编码工具可以加速实现但不能替你思考“到底该做什么”。6.2 第一周的启动清单如果你决定一试第一周我建议只做四件事把单体仓库和 CI 跑通把 Harness 层的接入网关和计量表先做出来给自己立三条纪律——业务代码不直接写模型调用、AI 输出必须过校验层、核心领域模型不让 AI 改然后初始化测试框架哪怕是空测试也得先跑起来。这四件事做完后面九个月你基本可以在稳定轨道上滚起来。6.3 预算规划不同阶段的模型配置组合我整理了一个能直接参考的预算配置表月预算美元建议模型组合适用阶段300 以下全 light 档模型 强缓存MVP 验证、个人工具500 到 1500核心强模型 外围 light 档有真实用户的小规模上线1500 到 3000分级路由 夜间批量 预算熔断日请求量过万的稳定服务预算规划的关键是先定预算再定模型而不是先定模型再算预算。每个阶段都去算一下“均请求成本”再把成本目标拆到每万个请求上这样加功能、做优化的时候才有明确的数字标尺。6.4 什么时候该止损这条写出来可能很多人不爱听但我真觉得很重要。如果你发现自己每天不是在写功能而是在花大量时间给 AI “擦屁股”——不停修正模型跑偏的任务描述、反复清理 AI 生成的多余代码、每次改动都要查半天它又动了哪里——这说明任务拆分和模块边界出了问题。正确做法不是硬撑而是停下两三天把任务拆得更细、把约束写得更严。与其在混乱里狂奔不如用两天的时间重新校准方向和工具。我在第三个月就经历过一次这种“止损式重构”代价是一周的工期换回了后面六个月的稳定开发节奏。结尾的部分我想说点真实感受。九个月后回头看我那份后台账单累计消耗的 token 已经叠加到数不清但心里反而很平静——最能打的架构不是最炫的而是让你在九个月后还能活着把它维护下去的那套。现在重写整个系统我大概还能砍掉一半代码、省下不少 token但那些钱和代码都不是白花的。它们换来了很多文档里不会写的认知模型不可信时系统该怎么兜底、一个人怎么在代码洪流里保持航道不偏。如果你也打算一个人走这条路希望上面这些经验能让你少付点学费把省下来的预算和时间留给真正该让你的产品与众不同的地方。
返回列表