1. 项目缘起与整体架构思路1.1 为什么一个人敢碰20万行代码的工程先说结论这个项目不是“写代码”而是“造一个能自己写代码的系统”。九个月、一个人、20万行代码、每月40亿 token的消耗量这几个数字放在一起很多人第一反应是“不可能”。但如果你把视角从“手写业务逻辑”切换到“设计一套让Agent自动完成工作的Harness架构”这件事的逻辑就通了。Harness这个词在软件工程里原本指的是“测试夹具”或“脚手架”但在AI Agent语境下它指的是一套约束、调度、验证Agent行为的框架层。你可以把它理解成Agent是工人Harness是工地上的脚手架、安全网、质检员和工头。没有HarnessAgent就是一个会胡说八道的聊天机器人有了Harness它才能稳定地完成复杂工程任务。这个项目的核心思路是把软件开发流程拆解成Agent可执行的原子步骤用Markdown作为中间表示层用Claude Code作为执行引擎用Obsidian作为知识管理和项目台账的可视化层。整个系统围绕一个闭环运转需求输入 → Markdown任务分解 → Agent执行 → 结果验证 → 知识沉淀 → 下一轮迭代。为什么选择Markdown作为核心中间层因为Markdown是人类可读、机器可解析、版本可控的三重最优解。Agent生成的计划、代码说明、测试用例、变更日志全部以Markdown格式落盘既方便人审查又方便程序解析。而且Obsidian天然支持Markdown的双向链接可以把零散的任务卡片串联成知识图谱。1.2 40亿token到底烧在了哪里很多人好奇每月40亿 token的消耗构成。我拆解一下大致比例消耗模块占比说明代码生成与重构35%Agent反复生成、审查、修改代码上下文注入25%每次执行前注入项目规范、历史决策、相关文件测试与验证20%自动生成测试用例、执行、分析失败原因知识检索与摘要12%从Obsidian库中检索相关笔记并摘要规划与任务分解8%将大需求拆解为可执行的小任务关键洞察是上下文注入占了四分之一。这意味着Harness架构的核心成本不在“生成”而在“让Agent知道该知道什么”。这也是为什么Markdown文件组织和Obsidian知识库设计如此重要——它们直接决定了每次注入的上下文质量和数量。1.3 整体架构分层系统分为四层表示层Markdown文件 Obsidian库负责人可读的任务描述、知识沉淀、项目台账调度层Harness核心负责解析Markdown、生成Agent指令、管理执行队列、处理失败重试执行层Claude Code作为主力Agent引擎配合其他专用Agent处理特定任务验证层自动化测试、代码审查Agent、人工抽检三者结合这四层之间通过文件系统和标准输入输出通信没有复杂的微服务架构。一个人维护的系统简单可靠比先进重要。2. 核心细节解析与实操要点2.1 Markdown作为Agent指令载体的设计规范Agent要稳定执行任务指令格式必须严格。我设计了一套Markdown任务模板每个任务卡片包含以下字段--- task_id: TASK-2024-001 status: pending priority: high depends_on: [TASK-2023-089] agent: claude-code estimated_tokens: 50000 --- ## 任务描述 实现用户登录接口的JWT校验中间件。 ## 输入 - 现有代码路径src/middleware/auth.js - 接口规范见 [[API-SPEC-登录模块]] ## 输出要求 - 生成完整中间件代码 - 附带单元测试 - 更新 [[变更日志-2024-Q1]] ## 验收标准 - [ ] 测试覆盖率 90% - [ ] 通过所有现有集成测试 - [ ] 代码审查Agent无阻断性意见这套模板的关键在于YAML frontmatter承载机器可读的元数据正文承载人类可读的上下文。Harness解析frontmatter决定调度策略Agent阅读正文理解任务意图。注意depends_on字段是任务调度的核心。没有依赖关系的任务可以并行执行有依赖的必须串行。我踩过的坑是早期没有严格维护依赖关系导致Agent在未完成的代码上继续开发产生大量返工。2.2 Claude Code的配置与调用策略Claude Code在这个项目中承担了约70%的代码生成工作。配置要点如下安装与基础配置在项目根目录创建.claude文件夹放入settings.json{ model: claude-sonnet-4-20250514, max_tokens: 8192, temperature: 0.3, system_prompt_file: .claude/system.md, allowed_tools: [read_file, write_file, run_command, search], working_directory: ./workspace }temperature设为0.3而不是0是因为完全确定性的输出在代码生成场景下反而容易陷入局部最优。0.3保留了少量随机性让Agent在遇到困难时能尝试不同方案。system prompt的设计是Harness的灵魂。我的system.md大约2000字核心内容包括项目技术栈和代码规范文件命名和目录结构约定错误处理原则优先抛出明确异常禁止静默失败注释规范只注释“为什么”不注释“是什么”禁止行为清单如不得修改配置文件、不得删除测试用例实操心得system prompt每增加100字每月token消耗大约增加2%。所以每个字都要反复推敲。我删掉了大量“礼貌性”描述只保留硬性约束。2.3 Obsidian知识库的组织方式Obsidian在这个项目中不是笔记工具而是项目的大脑。目录结构如下vault/ ├── 00-项目台账/ │ ├── 任务看板.md │ ├── 里程碑.md │ └── 风险登记.md ├── 01-架构决策/ │ ├── ADR-001-选择Markdown作为中间层.md │ └── ADR-002-Agent调度策略.md ├── 02-模块文档/ │ ├── 认证模块.md │ └── 数据层.md ├── 03-变更日志/ │ └── 2024-Q1.md └── 04-Agent提示词库/ ├── 代码生成.md └── 代码审查.md每个模块文档使用Obsidian的双向链接语法[[文档名]]建立关联。Harness在注入上下文时会从当前任务卡片出发沿着链接抓取一层相关文档。这个策略叫一跳上下文注入实测比全量注入节省60%的token同时保持了足够的相关性。2.4 任务分解的粒度控制任务粒度太粗Agent容易跑偏太细调度开销过大。我的经验值是单个任务对应Agent一次会话能完成的工作量大约5000-15000 token的输出。具体判断标准如果一个任务需要Agent修改超过5个文件拆如果需要超过3轮对话才能澄清需求拆如果验收标准超过5条拆如果预估token超过20000拆反过来如果两个任务总是被同一个Agent连续执行且中间不需要人工介入可以考虑合并。3. 实操过程与核心环节实现3.1 从零搭建Harness的完整步骤第一步环境准备mkdir harness-project cd harness-project mkdir -p workspace vault .claude logs npm init -y npm install anthropic-ai/sdk chokidar gray-mattergray-matter用于解析Markdown的YAML frontmatterchokidar用于监听文件变化触发任务调度。第二步编写Harness核心调度器核心逻辑是一个事件循环const chokidar require(chokidar); const matter require(gray-matter); const fs require(fs); const path require(path); const TASK_DIR ./vault/00-项目台账/任务看板; async function loadTasks() { const files fs.readdirSync(TASK_DIR).filter(f f.endsWith(.md)); return files.map(f { const content fs.readFileSync(path.join(TASK_DIR, f), utf-8); const { data, content: body } matter(content); return { ...data, body, file: f }; }); } function getExecutableTasks(tasks) { const doneIds tasks.filter(t t.status done).map(t t.task_id); return tasks.filter(t t.status pending (t.depends_on || []).every(dep doneIds.includes(dep)) ); } async function executeTask(task) { // 注入上下文 const context buildContext(task); // 调用Claude Code const result await callClaudeCode(context); // 验证结果 const verified await verifyResult(task, result); // 更新状态 updateTaskStatus(task.file, verified ? done : failed); }第三步上下文构建函数这是最关键的环节。buildContext函数负责从Obsidian库中抓取相关文档function buildContext(task) { const links extractWikiLinks(task.body); // 提取[[链接]] const relatedDocs links.map(link readVaultDoc(link)); const systemPrompt fs.readFileSync(.claude/system.md, utf-8); return [ systemPrompt, ## 当前任务\n task.body, ## 相关文档\n relatedDocs.join(\n---\n), ## 输出要求\n严格按照任务描述中的输出要求执行。 ].join(\n\n); }第四步验证层实现验证分三级自动测试运行项目测试套件全绿才通过代码审查Agent用另一个Claude实例审查生成的代码检查规范符合度人工抽检每天随机抽检10%的任务结果async function verifyResult(task, result) { // 第一级自动测试 const testPass await runTests(); if (!testPass) return false; // 第二级代码审查Agent const reviewPrompt 审查以下代码变更检查是否符合项目规范\n${result.diff}; const review await callClaude(reviewPrompt); if (review.includes(阻断性问题)) return false; return true; }3.2 一次完整任务执行的现场记录以“实现JWT校验中间件”为例记录完整执行过程T0minHarness检测到TASK-2024-001状态为pending且依赖已满足加入执行队列。T1min构建上下文注入system prompt2000字 任务描述500字 相关文档认证模块.md、API规范.md共3000字。总输入约5500字约8000 token。T2min调用Claude CodeAgent开始生成代码。生成过程中调用了read_file读取现有auth.js调用了search查找项目中其他中间件的写法。T8minAgent输出完成生成authMiddleware.js120行、authMiddleware.test.js200行、变更日志更新。T9min自动测试运行3个测试用例失败。Harness将失败信息注入下一轮上下文。T12minAgent根据失败信息修复代码重新生成。测试通过。T13min代码审查Agent介入提出2条建议非阻断。Harness记录建议标记任务完成。T14min更新任务状态为done触发依赖此任务的下游任务。整个流程消耗约45000 token其中输入32000输出13000。按Claude Sonnet定价单任务成本约0.5美元。3.3 月度40亿token的成本控制策略40亿token听起来吓人但拆解到每天约1.3亿按8小时工作制每小时1600万。这个量级需要精细控制策略一上下文缓存。相同模块的文档在多个任务中重复注入用prompt caching可以节省90%的重复输入成本。策略二分级模型。简单任务用Haiku复杂任务用Sonnet只有架构级决策才用Opus。实测可以降低40%成本。策略三输出长度限制。在system prompt中明确要求“代码注释不超过必要限度”、“不重复输出未修改的代码段”。这一条节省了约15%的输出token。策略四失败快速终止。如果Agent连续3轮无法通过测试自动终止并标记为需要人工介入避免无限重试烧token。4. 常见问题与排查技巧实录4.1 Harness failed to load plugins的排查这是最高频的问题之一。表现是Harness启动时报错“failed to load plugins”Agent无法执行。排查顺序检查插件目录权限ls -la .claude/plugins/确保当前用户有读写权限检查插件依赖每个插件目录下的package.json是否完整运行npm install补全检查版本兼容Harness核心版本与插件API版本是否匹配查看插件文档的兼容性矩阵查看详细日志tail -f logs/harness.log通常会有具体的加载失败原因我遇到最多的情况是插件依赖的某个npm包版本冲突。解决方案是在插件目录下单独维护node_modules不要和主项目共用。4.2 Agent execution terminated due to error的常见原因这个错误信息很笼统实际原因需要看上下文错误现象可能原因解决方案执行到一半突然终止输出token超限拆分任务减小单次输出量刚开始就终止输入token超限精简上下文启用缓存特定任务必现任务描述有歧义重写任务描述增加示例随机出现API限流增加重试机制降低并发工具调用后终止工具返回格式错误检查工具实现增加格式校验4.3 Markdown表格转换Excel的实用技巧项目台账中有大量Markdown表格有时需要导出给非技术人员看。我写了一个小脚本import pandas as pd import re def md_table_to_excel(md_file, excel_file): with open(md_file, r, encodingutf-8) as f: content f.read() # 提取所有Markdown表格 tables re.findall(r(\|.\|\n\|[-:| ]\|\n(?:\|.\|\n?)), content) with pd.ExcelWriter(excel_file) as writer: for i, table in enumerate(tables): lines [l for l in table.strip().split(\n) if l.strip()] headers [c.strip() for c in lines[0].split(|)[1:-1]] rows [] for line in lines[2:]: rows.append([c.strip() for c in line.split(|)[1:-1]]) df pd.DataFrame(rows, columnsheaders) df.to_excel(writer, sheet_namefTable_{i1}, indexFalse)这个脚本处理了大部分标准Markdown表格。注意如果表格单元格内有|字符需要先转义。4.4 Obsidian与Agent协作的避坑指南坑一文件锁冲突。Obsidian打开文件时会加锁Harness同时写入会失败。解决方案是Harness写入前检查文件是否被Obsidian占用或者约定Harness只写入特定目录Obsidian只读。坑二双向链接断裂。Agent重命名文件时不会自动更新其他文件中的[[链接]]。解决方案是在Harness中增加重命名钩子自动扫描并更新所有引用。坑三frontmatter格式错误。Agent有时会生成不合法的YAML导致解析失败。解决方案是在写入前用js-yaml校验不合法则拒绝写入并报错。坑四知识库膨胀。九个月积累了上万个Markdown文件检索变慢。解决方案是定期归档已完成项目的文档只保留活跃项目的文档在主库中。4.5 常见问题速查表问题快速排查根治方案Agent不执行任务检查任务状态和依赖完善依赖关系维护生成代码不符合规范检查system prompt增加规范示例token消耗异常高查看上下文注入量启用缓存精简文档任务反复失败查看失败日志拆分任务或人工介入Obsidian同步冲突检查文件锁分离读写目录测试通过但线上出问题检查测试覆盖增加集成测试5. 九个月迭代中的关键决策复盘5.1 为什么最终选择Claude Code而非自建Agent项目初期我尝试过自建Agent框架用开源模型加自己的调度逻辑。三个月后放弃转向Claude Code。原因有三第一工具调用能力。Claude Code内置了文件读写、命令执行、搜索等工具且经过大量优化。自建的话光工具调用的稳定性和错误处理就要花两个月。第二上下文管理。Claude Code自动处理上下文窗口、压缩、缓存。自建需要自己实现滑动窗口、摘要压缩效果远不如官方。第三迭代速度。官方每月都在更新模型和工具自建框架需要持续跟进。一个人的精力有限应该把时间花在Harness层而不是重复造轮子。5.2 Markdown换行与语法踩过的坑Markdown看似简单但在Agent场景下有大量细节换行标准Markdown中单个换行不产生新段落需要两个空格或空行。Agent经常忘记导致生成的文档格式混乱。解决方案是在system prompt中明确要求“段落之间必须空行”。表格Markdown表格不支持单元格内换行复杂内容需要改用列表或代码块。数学符号Agent生成数学公式时经常用错定界符。Obsidian支持$...$和$$...$$但标准Markdown不支持。需要在渲染层做兼容。代码块嵌套在Markdown中写包含代码块的文档时外层用四个反引号内层用三个。5.3 从20万行代码中提炼的Harness设计原则九个月下来20万行代码中真正核心的Harness逻辑只有约5000行其余都是配置、文档、测试和生成代码。核心原则可以浓缩为五条一切皆文件。任务、状态、日志、知识全部落盘为Markdown或JSON不依赖数据库。好处是可版本控制、可人工编辑、可被Agent直接读写。单向数据流。任务从创建到完成只经过一条路径不搞复杂的回调或事件总线。简单意味着可预测。失败即信号。任何失败都要记录详细上下文作为下一轮迭代的输入。失败不是异常是系统的正常反馈。人工在环。关键决策点必须有人工确认Agent只负责执行和提议。完全自动化的系统在复杂项目中不可靠。成本可见。每个任务的token消耗都要记录定期分析成本分布找出优化点。5.4 后续可以扩展的方向这套Harness架构目前主要服务于个人项目但有几个明确的扩展方向多Agent协作当前主要是单Agent串行执行可以引入多个专用Agent并行处理独立任务。知识库自动更新目前知识沉淀还需要人工整理可以让Agent在完成任务后自动生成知识卡片。跨项目复用将Harness核心抽象为通用框架不同项目只需替换system prompt和知识库。成本预测基于历史数据在任务创建时预估token消耗帮助决策是否值得自动化。我在实际使用中发现这套系统最大的价值不是省了多少时间而是把模糊的工程决策变成了可记录、可追溯、可优化的显式流程。每次Agent失败都是一次学习机会每次成功都是一次知识沉淀。九个月下来最大的收获不是那20万行代码而是这套让代码自己生长的机制。