使用运行时反馈修正 Agent 行为:Project 04 增量索引与架构约束实战指南(learn-harness-engineering)
【免费下载链接】learn-harness-engineeringHarness engineering beginner tutorial, from 0 to 1项目地址https://gitcode.com/gh_mirrors/le/learn-harness-engineering点击查看免费下载本文基于 learn-harness-engineering 仓库中的 Project 04增量索引项目展开。该项目的核心命题是当 Agent 没有日志、没有错误输出、没有架构边界时它会把看起来能跑误判为已经实现甚至对植入的运行时缺陷视而不见。本文以 docs/ko/projects/project-04-incremental-indexing/index.md 为骨架结合 projects/project-04/ 下的 starter 与 solution 源码完整讲解如何通过结构化日志、架构约束脚本与增量索引机制为 Agent 建立可观察、可约束、可自愈的运行时反馈回路。读完本文你将掌握诊断信号缺失时 Agent 为何会误报完成、如何用结构化 logger 让运行状态可被机器解析、如何用 check-architecture.sh 守住分层边界以及如何通过两轮对照实验无工具 vs 有工具量化运行时反馈对修复速度与稳定性的提升。为什么需要运行时反馈没有信号的 Agent 会看到幻象在开始动手之前先理解 Project 04 要解决的底层问题。它承接 Lecture 07「给 Agent 划定清晰任务边界」 与 Lecture 08「用功能列表约束 Agent 行为」 两讲的结论Agent 的上下文容量是有限的设为 C。若同时激活 k 个任务每个任务平均只能分到 C/k 的推理资源低于完成阈值时哪个都完不成——这是过度扩张overreach与欠完成under-finish的数学根源。Agent 默认不知道完成的定义。没有显式验证命令时它会把代码没有明显语法错误当作完成标准从而把未实现的功能误报为已实现。Project 04 把这两讲的思想落地为一个可操作的最小案例给 Agent 一个被植入运行时缺陷的知识库应用观察它在有诊断信号与无诊断信号两种情况下的表现差异。仓库中的项目文档用一句话点明了任务核心런타임 관찰 가능성(runtime observability, 시작 로그, 임포트/인덱싱 로그, 오류 상태)을 추가하고, 레이어 간 위반(cross-layer violation)을 방지하기 위한 아키텍처 제약(architecture constraints)을 도입합니다. 에이전트가 수정할 수 있도록 런타임 버그를 심어 둡니다.即添加运行时可观测性启动日志、导入/索引日志、错误状态引入防止跨层违规的架构约束并植入一个可供 Agent 修复的运行时缺陷。整个实验需要运行两次第一次无日志、无约束第二次配备合适的工具与规则rules对比两者找到根因的速度与修复质量。实验环境与对照设计对比维度starter/无诊断信号solution/带运行时反馈目录projects/project-04/starterprojects/project-04/solution代码来源Project 03 的代码诊断信号薄弱在 starter 基础上补齐可观测性与约束索引缺陷已植入大文件 chunking 会被破坏1000 字符的文档产生空 chunk修复后的 chunking 逻辑日志仅剩零散的console.log结构化 loggerJSON 输出四档级别架构约束无架构检查脚本check-architecture.sh ARCHITECTURE.md实验目标记录没有运行时信号时Agent 找到根因需要多久记录日志与边界检查是否让修复更快、侵入性更小项目文档要求重点核对四个文件projects/project-04/solution/src/services/logger.ts结构化日志projects/project-04/solution/scripts/check-architecture.sh架构边界检查projects/project-04/solution/docs/ARCHITECTURE.md分层架构说明projects/project-04/solution/src/services/indexing-service.ts修复后的索引/分块逻辑所需工具与环境Claude Code 或 Codex、Git、Node.js Electron。被植入的运行时缺陷一次静默的数据破坏对照实验的关键变量是 starter 中植入的索引缺陷。对比 starter 版 indexing-service.ts 与 solution 版 的chunkDocument方法即可定位// starter 版含缺陷 for (const para of paragraphs) { if (buffer.length para.length CHUNK_SIZE buffer.length 0) { // BUG: For long documents (1000 chars total), set chunk content to empty string. // This causes files over ~1000 chars to produce empty chunks, breaking QA retrieval. const chunkContent content.length 1000 ? : buffer.trim(); chunks.push(this.createChunk(documentId, chunkIndex, chunkContent)); buffer para; } else { buffer (buffer ? \n\n : ) para; } }这段代码的问题在于当文档总长度超过 1000 字符时所有 chunk 的 content 被置为空字符串。chunk 结构本身照常写入有 id、有 index、有 metadata索引状态也显示成功但 QA 检索时拿到的全是空内容——这是一个典型的静默数据破坏silent data corruption应用不会崩溃没有任何异常抛出索引状态idle / indexing / ready / error依然正常流转唯一的表现是检索结果异常——而 starter 版没有任何日志能揭示chunk 是空的这一事实。对 Agent 而言这意味着它无法区分功能正常与功能被悄悄破坏。这正是项目文档强调的核心观察日志或错误输出缺失时Agent 难以识别内部错误甚至会把不存在的功能误判为已实现。修复后的 solution 版删除了content.length 1000的特殊分支chunk 内容始终取自段落缓冲// solution 版修复后 for (const para of paragraphs) { if (buffer.length para.length CHUNK_SIZE buffer.length 0) { chunks.push(this.createChunk(documentId, chunkIndex, buffer.trim())); buffer para; } else { buffer (buffer ? \n\n : ) para; } }分块逻辑本身遵循固定策略以双换行段落边界切分按约 500 字符CHUNK_SIZE 500聚合段落每个 chunk 携带charCount与wordCount元数据见 createChunk。相比 startersolution 版在每个关键节点都留下了可观察的证据。结构化日志让运行状态可被机器解析解决没有信号问题的第一层手段是 logger.ts 提供的结构化日志模块。它用一致的、机器可解析的 JSON 格式替换零散的console.log调用核心设计如下日志级别与条目结构export enum LogLevel { DEBUG DEBUG, INFO INFO, WARN WARN, ERROR ERROR, } interface LogEntry { timestamp: string; // new Date().toISOString()ISO 8601 格式 level: LogLevel; // DEBUG / INFO / WARN / ERROR service: string; // 服务名如 IndexingService message: string; // 人类可读的消息 data?: Recordstring, unknown; // 结构化附加数据 }每条日志都包含时间戳、级别、服务名、消息四个固定字段data字段用于携带结构化上下文如文档 id、chunk 数量、内容长度、置信度等。级别过滤通过LEVEL_ORDER数组实现shouldLog比较目标级别与最小级别的下标低于阈值的条目直接丢弃。默认最小级别为DEBUG且支持通过环境变量覆盖export const logger new Logger( (process.env.LOG_LEVEL as LogLevel) ?? LogLevel.DEBUG );服务级子 logger 与输出通道logger 提供forService(serviceName)方法创建子 logger让每个服务只关心自己的消息class ServiceLogger { debug(message: string, data?: Recordstring, unknown): void { ... } info(message: string, data?: Recordstring, unknown): void { ... } warn(message: string, data?: Recordstring, unknown): void { ... } error(message: string, data?: Recordstring, unknown): void { ... } }输出通道与级别联动ERROR走console.errorWARN走console.warn其余走console.log——保证错误信息在终端中可被区分检索。整条日志被JSON.stringify序列化因此可以被grep、jq 或任何日志采集工具直接解析。在服务中的实际埋点以 IndexingService 为例它的每个生命周期节点都有日志构造时this.log.info(IndexingService constructed)启动时startIndexing called附带{ documentId: documentId ?? all }文档缺失时this.log.error(Document content not found, { documentId })无内容的文档跳过this.log.warn(Skipping document with no content, { docId, title })分块前记录contentLength与paragraphCount分块后记录totalChunks与totalChars全部 chunk 字符数之和最后一项尤其关键如果 chunk 内容是空的totalChars会暴露为 0Agent 从日志就能直接锁定问题而不需要靠猜。同理QaService 会在检索时记录totalChunks、关键词匹配数量、confidence与citationCount——空 chunk 会直接体现为totalChunks正常但relevantChunks为零形成完整的证据链。启动与 IPC 层的观测点ipc-handlers.ts 为每个 IPC 通道记录调用与结果ipcMain.handle(IPC_CHANNELS.IMPORT_DOCUMENT, async (_event, filePath: string) { log.info(IMPORT_DOCUMENT, { filePath }); try { const doc documentService.importDocument(filePath); log.info(Document imported, { id: doc.id, title: doc.title, size: doc.size }); return doc; } catch (err) { log.error(Document import failed, { filePath, error: String(err) }); throw err; } });所有通道名统一定义在 src/shared/types.ts 的 IPC_CHANNELS 常量中包括documents:list、documents:import、indexing:start、qa:ask等 9 个通道——这是单一定义来源思想的又一次落地通道名、方向、用途只在类型文件中声明一次main、preload、renderer 三端共用。架构约束把分层从文档变成可执行检查第二层手段是让架构规则可被机器执行。ARCHITECTURE.md 定义了严格的分层架构与边界而 check-architecture.sh 负责把规则变成退出码。四层架构与边界规则Renderer (React UI) | v Preload (contextBridge) | v Main Process (IPC Handlers) | v Services (Business Logic) | v Persistence (Filesystem)各层职责与约束依据 ARCHITECTURE.md层职责约束MUST NOTRenderersrc/renderer/React UI、处理用户输入、仅通过window.knowledgeBaseAPI 通信禁止导入fs、path、os、child_process等 Node 核心模块禁止直接访问 Electron API禁止承载业务逻辑Preloadsrc/preload/通过contextBridge.exposeInMainWorld暴露类型化 API禁止包含业务逻辑禁止直接导入 services只使用ipcRenderer.invokeMain Processsrc/main/创建 BrowserWindow、注册 IPC handler 并委托给 services禁止承载路由之外的业务逻辑不直接访问持久化层Servicessrc/services/全部业务逻辑文档管理、索引、QA禁止导入 Electron APIipcMain、BrowserWindow等禁止导入 React文件系统访问一律经PersistenceService检查脚本的三条规则check-architecture.sh使用set -euo pipefail严格模式逐项扫描源码目录任何违规都会累加计数并以退出码 1 结束Renderer 不得导入 Node.js 核心模块对src/renderer下的.ts/.tsx文件执行grep -qE import.*\b(fs|path|os|child_process)\bServices 不得使用 Electron IPC对src/services下的.ts文件检查import ... from electron以及ipcMain、ipcRenderer、BrowserWindow标识符Services 与 Main 不得导入 React对src/services与src/main下的文件检查import ... from react。输出示例全部通过时 Architecture Boundary Checks Checking renderer for Node.js core module imports... PASS: No Node.js core imports in renderer Checking services for Electron IPC imports... PASS: No Electron IPC in services Checking services and main for React imports... PASS: No React imports in services/main Summary PASS: All architecture boundary checks passed退出码 0 全部通过退出码 1 发现违规。这使得架构检查可以无缝接入 Agent 的工作流Agent 在提交前运行bash scripts/check-architecture.sh脚本的退出码就是边界是否干净的客观证据Agent 不能靠自我感觉宣称分层没问题。增量索引跳过已索引文档的幂等设计Project 04 的另一个关键词是增量索引incremental indexing。在 IndexingService.startIndexing 中批量索引的核心逻辑是读取documents-meta.json得到全部文档读取index-meta.json得到已索引文档 id → chunk id 列表的映射跳过chunksMeta[doc.id]已存在的文档只索引新增/未索引的文档每索引完一个文档立即把 chunk 列表写入chunks/${doc.id}.json并更新chunksMeta全部完成后将chunksMeta写回index-meta.json。这种设计带来两个可直接验证的性质幂等性重复调用startIndexing()不会重复处理已索引文档getStatus()依据currentIndexed totalDocuments计算状态索引完成前返回indexing完成且文档数大于 0 时返回ready可恢复性由于每个文档的 chunk 与索引元数据是逐步落盘的即使中途失败下次运行也会从断点继续而不是推倒重来——这正是仓库成为系统记录system of record思想在运行时的体现。结合运行时反馈来看增量索引还有一个隐藏优势Agent 修复 chunking 缺陷后只需对受影响文档触发单文档索引startIndexing(documentId)而无需全量重建修复的验证成本因此大幅降低。会话规则与收尾清单把反馈回路固化为制度日志和脚本只是工具真正让反馈回路长期起作用的是把使用它们的规则写进项目文件。AGENTS.md 中的操作规则solution/AGENTS.md 明确了每次会话的启动工作流Startup Workflowpwd确认工作目录阅读docs/ARCHITECTURE.md了解 Electron 分层边界git log --oneline -5查看近期提交缺失依赖时执行npm install运行npm run check运行bash scripts/check-architecture.sh。并强调如果基线验证已在失败状态先修复它不要在坏起点上堆新功能。工作规则包括一次只做一个功能不要因为加了代码就宣称功能完成不要在执行过程中悄悄修改验证规则。项目还明确指出Project 04 刻意保持较小的 harnessfeature_list.json、claude-progress.md、init.sh、session-handoff.md这些制品属于后续阶段不要假设它们存在。对比 starter/AGENTS.md——它只有三行命令说明与两条简单规则一次一个功能、提交前npm run check——可以看到 solution 版把可观测性检查与架构约束检查直接变成了会话的强制步骤。Clean State Checklist提交前的健康检查clean-state-checklist.md 是提交与结束会话前的最后一道闸按五个维度逐项打勾Buildnpm run check无类型错误npm run build成功Architecturebash scripts/check-architecture.sh无违规renderer 无fs/pathservices 无 Electron IPCservices/main 无 ReactRuntimenpm run dev启动无错误启动时有结构化日志输出导入文档正常检查 IMPORT_DOCUMENT 日志所有大小的文档索引正常QA 返回带引文的答案检查 ASK_QUESTION 日志Data Integrity索引文档中无空 chunk用 GET_CHUNKS 验证QA 历史跨重启持久化文档元数据与实际文件一致Repositorygit status 无意外文件无敏感数据.env、凭据被暂存最终摘要记录当前状态、验证运行情况与未解决风险AGENTS.md、ARCHITECTURE.md 与清单本身仍与 Project 04 实际存在的文件一致。注意Runtime与Data Integrity两项直接依赖前面建立的结构化日志与 IPC 通道IMPORT_DOCUMENT、ASK_QUESTION、GET_CHUNKS——这正是运行时反馈回路被制度化的证据每条规则背后都有一条可执行、可验证的命令或日志锚点。两轮对照实验如何量化运行时反馈的价值项目文档给出的实验设计是运行两次——第一次没有日志与约束第二次配备合适的工具与规则。建议的对比维度观察指标第一轮starter无信号第二轮solution带反馈定位根因耗时Agent 需反复猜测 chunking 行为无法区分索引成功与内容为空从chunkDocument complete日志的totalChars直接锁定空 chunk修复正确性可能误改其他模块或把问题归因到检索逻辑缺陷定位到chunkDocument的单一分支修复面最小验证方式缺少可复现的验证命令npm run checkcheck-architecture.sh 日志断言越界风险无约束Agent 可能顺手重构无关模块架构脚本在提交前拦截跨层违规需要说明仓库内并未内置这两轮的量化测试数据如修复分钟数、通过率百分比因此上述对比请作为实验设计参考实际数字应由你自己跑完两轮后记录。实验时注意三点保持变量单一两轮使用同一份 sample 数据projects/project-04/starter/data/sample-documents/ 下的design-notes.md、meeting-summary.txt、retrieval-plan.md确保缺陷可复现用日志断言代替肉眼判断检查chunkDocument complete中的totalChars是否与文档长度一致检查GET_CHUNKS返回的 chunk 是否非空让架构脚本参与完成判定修复完成后必须跑通check-architecture.sh防止修复过程中引入跨层违规。运行与验证命令速查在 solution 目录下执行npm脚本定义见 projects/project-04/solution/package.json命令作用npm run dev启动 Electron 应用经node scripts/dev.js观察启动与 IPC 日志npm run check类型检查tsc --noEmit -p tsconfig.node.json tsc --noEmit -p tsconfig.jsonnpm run build构建tsc -p tsconfig.node.json vite buildnpm run test运行 vitest 测试test:watch为监听模式bash scripts/check-architecture.sh架构边界检查退出码 0/1 表示通过/违规技术栈依赖依据 solution 的 package.jsonReact 18、uuid 9、Electron 33、TypeScript 5.7、Vite 6、Vitest 2.1。小结运行时反馈 可观察 可约束 可自愈Project 04 给出的完整模式可以概括为三个层次可观察observability结构化 logger 把服务的每个关键节点变成可检索的 JSON 事件让 Agent 能看见运行真相而不是靠代码阅读猜测——对应 logger.ts 与 indexing-service.ts 中的埋点可约束constraints架构边界从文档描述升级为可执行脚本用退出码强制分层纪律——对应 ARCHITECTURE.md 与 check-architecture.sh可自愈self-correction增量索引保证修复可以小步、幂等地进行clean-state-checklist 保证每次提交都经过验证闸门——对应 IndexingService.startIndexing 与 clean-state-checklist.md。这三者共同构成 Agent 的运行时反馈回路日志暴露问题边界防止越界清单锁定完成标准。缺少任何一环Agent 都会退回代码看起来没问题的主观判断模式——而 Project 04 的 starter 已经证明这种模式下即使缺陷被植入Agent 也发现不了。这恰好呼应了项目在 harness 机制Harness Mechanism上的定位运行时反馈runtime feedback 范围控制scope control 增量索引incremental indexing。赞分享【免费下载链接】learn-harness-engineeringHarness engineering beginner tutorial, from 0 to 1项目地址https://gitcode.com/gh_mirrors/le/learn-harness-engineering点击查看免费下载相关推荐learn-harness-engineering Project 04 实战用运行时反馈与架构约束修正 Agent 行为learn harness engineering Project 04 实战用运行时反馈与架构约束修正 Agent 行为 本项目Project 04 ·Harness 实战用运行时反馈与架构约束纠正 Agent 行为——learn-harness-engineering Project 04 增量索引调试指南Harness 实战用运行时反馈与架构约束纠正 Agent 行为——learn harness engineering Project 04 增量索引调试指南learn-harness-engineering 项目 04用运行时反馈修正 Agent 行为——结构化日志、架构约束与增量索引实战learn harness engineering 项目 04用运行时反馈修正 Agent 行为——结构化日志、架构约束与增量索引实战 本篇技术指南以仓库 d上一篇使用 Terraform AWS Provider 的 aws_route53_resolver_rule 数据源查询 Route 53 Resolver 转发规则下一篇告别网盘限速这款免费开源工具让你下载速度飙升50倍创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考