Skip to content

MewCode — 项目设计 ​

源码:Bin-hy/EasyCoding(submodule:projects/EasyCoding) 本文是技术设计文档:设计目标 → 需求分解 → 架构决策记录(ADR)→ 数据模型 → 接口契约 → 常量总表 → 测试策略 → 未完成项。

阅读关系:

  • 想看「怎么在面试里讲架构」→ 架构分层与依赖设计
  • 想看「每个模块怎么实现的」→ 03 ~ 11 章
  • 想看「为什么这么设计、放弃了什么」→ 本文

一、设计目标与约束 ​

1.1 目标 ​

#目标衡量方式
G1从零实现一个可用的终端 Coding Agent能自主完成「读代码 → 分析 → 改多文件 → 跑测试 → 按报错修复」
G2不用 Agent 框架,把每个机制写到底无 eino / langchain / 任何 Agent 框架依赖
G3协议无关同一份上层代码同时跑通 Anthropic 与 OpenAI(含兼容端点)
G4单二进制分发go build ./cmd/mewcode 产出无外部运行时依赖的二进制
G5安全可控工具执行前有明确护栏;高危操作需人确认
G6长会话可用连续工作数小时不因上下文超限中断
G7可扩展工具/角色/钩子/技能四类扩展点都不需要改核心代码
G8可验证每个能力有编号需求(F#)+ 验收标准(AC#)+ 测试

1.2 约束 ​

约束影响
单人开发、业余时间优先做「难且能讲清楚」的机制,跳过工程化外围(CI 有了,但无压测/无 chaos)
单机 CLI,非服务不做分布式、不做多租户、状态放进程内存 + 本地文件
终端交互需要 TUI(Bubble Tea),不能是纯管道式 CLI
无 CGO排除 SQLite(除非用纯 Go 实现)、排除需要 cgo 的 tokenizer
目标岗位是 Go刻意使用 channel / goroutine / interface / 泛型等 Go 特性作为练习

二、需求分解(13 章 → 6 大能力域) ​

能力域章节核心需求(摘)
Ⅰ 协议与交互ch02 / ch05 / ch10双协议流式对话;系统提示模块化装配;Slash 命令体系
Ⅱ 工具与执行ch03 / ch04Tool 抽象 + 注册中心 + 6 内置工具;ReAct 多轮循环 + 保序分批并发
Ⅲ 安全护栏ch06 / ch12五层权限防御;Hook 生命周期拦截
Ⅳ 上下文与状态ch08 / ch09两层上下文压缩;JSONL 会话存档;项目指令;自动笔记
Ⅴ 扩展生态ch07 / ch11 / ch13MCP 客户端;Skill 系统;SubAgent + 后台任务
Ⅵ 工程质量贯穿Spec 驱动开发;go test -race;冒烟测试;CI 矩阵

三、架构决策记录(ADR) ​

格式:背景 → 决策 → 理由 → 后果(正面/负面)→ 替代方案

ADR-001 · 用 Go 而不是 Python ​

背景:Agent 生态以 Python 为主(LangChain / CrewAI / AutoGen)。 决策:用 Go 实现。 理由:① 单二进制分发,无运行时依赖;② channel/goroutine 天然表达事件流与并发执行;③ 静态类型能在编译期发现协议抽象的遗漏分支;④ 目标岗位(字节 Agent 开发)用 Go(Eino/CloudWeGo 生态)。 后果:

  • ✅ 部署极简;并发原语贴合问题域;类型安全
  • ❌ 生态少(要自己写 SSE 适配、自己写 frontmatter 解析);招人面窄 替代方案:Python + LangGraph —— 生态成熟但被框架绑架(框架帮你做了上下文管理与状态机,学不到底层),且分发麻烦。

ADR-002 · 不用 Agent 框架 ​

背景:Eino / LangGraph / OpenAI Agents SDK 都能开箱提供 Agent Loop。 决策:全部手写。 理由:项目的第一目标是理解 Agent 的机制。框架把「循环怎么收敛、上下文何时爆、权限在哪一层拦」都封装成了黑盒,用完仍然不知道里面发生了什么。 后果:

  • ✅ 每个机制都能讲到字节级;可以根据需求做框架不支持的取舍(比如「保序分批并发」很多框架没有)
  • ❌ 开发量翻倍(1.7 万行);要自己踩坑(历史一致性、goroutine 泄漏) 替代方案:用 Eino 快速出 Demo —— 适合验证想法,不适合学习与面试深挖。

ADR-003 · Provider 接口的错误走 channel 而非返回值 ​

背景:流式请求的错误可能发生在「连接建立后、事件流中途」。 决策:Stream(ctx, req) <-chan StreamEvent,错误放进 StreamEvent.Err,接口无 error 返回值。 理由:消费端只需要 for range + 一个 switch;不需要 select 两个 channel 并依赖「谁先关闭」的隐式约定。 后果:

  • ✅ 消费端代码最简;取消语义统一(都靠 ctx)
  • ❌ 「构造请求失败」这类同步错误也只能异步上报;错误类型被压平成 error替代方案:(<-chan StreamEvent, error) —— 只能表达建连前错误;或「事件流 + 独立 err channel」—— 约定更多。

ADR-004 · 事件流用单一结构体 + 非零字段分派 ​

背景:Agent 需要向 UI 吐 9 类事件(文本增量、工具开始/结束、用量、迭代、提示、完成、错误、审批、压缩)。 决策:一个 Event 结构体,谁非零就渲染谁。 理由:避免 interface{} 多态事件导致的「每个消费者都要 type switch,新增事件类型要改所有实现」。 后果:

  • ✅ TUI 侧一次 switch 分派;新增字段向后兼容
  • ❌ 结构体随功能增长(现 9 字段);「零值」与「未设置」不可区分 替代方案:Event{Type EventType; Payload any} —— 类型安全但装箱分配 + 消费端断言。

ADR-005 · 工具执行按副作用「保序分批并发」 ​

背景:模型一次可能请求 5 个工具。全串行延迟线性增长;全并发会让写操作顺序不确定。 决策:扫描调用序列,连续只读调用合并为并发批(sync.WaitGroup),有副作用调用单独串行,结果按原始下标回灌。 理由:模型给出的调用顺序含有语义(read A 在 write B 之前意味着「先看再改」),必须保持;同时只读工具之间没有依赖,可以安全并发。 后果:

  • ✅ read×3 的延迟 = 单个 read;结果顺序与模型请求顺序一致;并发只在只读集合内,无数据竞争
  • ❌ 放弃了跨批重排的优化空间(write B 后面的 read C 本可与 B 并发,但不能) 替代方案:全并发 + 依赖分析(复杂且容易出错);全串行(慢)。

ADR-006 · 工具错误是「观察结果」而不是「异常」 ​

背景:工具可能因为路径不存在、权限不足、命令失败而报错。 决策:所有错误包装成 ToolResult{IsError: true, Content: <结构化错误文本>} 回灌进对话历史,绝不中断循环。 理由:Agent 的本质是「根据反馈调整」。工具报错是有价值的观察——模型看到「文件不存在」会换个路径,看到「权限拒绝」会向用户求助。 后果:

  • ✅ 循环鲁棒;模型能自我修正
  • ❌ 错误可能被模型忽略(它可能不理会错误继续做别的);需要模型有足够的指令遵循能力 替代方案:错误直接 return err 中断 —— 简单但 Agent 就退化成「一次成功或失败」的脚本。

ADR-007 · 权限做成五层流水线而非单一检查 ​

背景:工具执行是完全裸奔的(能写任意路径、跑任意命令)。 决策:黑名单 → 路径沙箱 → 三层规则引擎 → 模式兜底 → 人在回路,命中即短路。 理由:每一层解决不同性质的威胁,且失败模式不同:黑名单防「已知恶意」,沙箱防「越界」,规则引擎表达「用户策略」,模式兜底给「默认安全姿态」,人在回路兜「未知风险」。 后果:

  • ✅ 纵深防御;每层可独立测试与演进;Bypass 模式仍然保留前两层
  • ❌ 复杂度高(1197 行);层间语义容易冲突(比如 allow 规则命中后就跳过了模式兜底) 替代方案:单一规则引擎 —— 简洁但无法表达「沙箱」这种非规则型约束。

ADR-008 · 上下文压缩做成两层而非一层 ​

背景:工具结果占 token 的 80-90%,历史随轮次单调增长。 决策:L1 确定性落盘替换(零 LLM 成本)+ L2 LLM 摘要(花钱)。 理由:成本差异巨大。L1 是纯字符串替换,每轮都可以跑;L2 要发一次完整 LLM 请求。分离后可以先做免费的,只有免费手段不够时才花钱。 后果:

  • ✅ 大幅降低成本与延迟;L1 失败不影响 L2
  • ❌ 两套状态(ContentReplacementState + AutoCompactTrackingState)增加复杂度 替代方案:只做摘要 —— 简单但每轮都花一次 LLM 调用;只做截断 —— 会丢用户需求。

ADR-009 · 替换决策冻结且保证逐字节一致 ​

背景:同一个工具结果在每轮请求里都要被重新渲染成替换体。 决策:ContentReplacementState 记录每个 tool_use_id 的决策,已决策的永不翻转;替换体字符串存在账本里,之后每轮返回同一个 string。 理由:Prompt Cache 要求前缀逐字节一致。任何重新构造(map 迭代顺序、时间戳)都会让缓存全量失效,成本上一个量级。 后果:

  • ✅ 缓存命中率稳定;决策可解释
  • ❌ 落盘失败的项无法在本轮重试(要等下一轮);账本占内存且未持久化 替代方案:每轮重新决策 —— 实现简单但缓存全废。

ADR-010 · token 估算用「锚点 + 增量」而非 tokenizer ​

背景:需要在发请求前判断是否要压缩,但不想引入 tokenizer。 决策:EstimateTokens = anchor + ceil(新增字符数 / 3.5),锚点来自 provider 返回的真实 usage。 理由:① tokenizer 会带几十 MB 词表,破坏单二进制;② 每轮对全量历史分词有 CPU 开销;③ 锚点机制让误差只累积一轮(下一轮被真实 usage 校准回来)。 后果:

  • ✅ 零依赖、零开销;误差可控(20-30%)
  • ❌ 中文系统性低估(len() 是字节数);锚点必须包含 CacheRead/CacheWrite,否则缓存命中时估算严重偏低 替代方案:调用 provider 的 count_tokens API —— 精确但多一次网络往返。

ADR-011 · 系统提示模块化装配 + 缓存通道分离 ​

背景:系统提示原本是一段揉在一起的常量,没有结构、无法按优先级排序、每轮全量重发。 决策:7 个固定模块(priority 10-70)+ 3 个可选槽(80/90/100),sort.SliceStable 按 priority 装配;System 拆成 Stable(可缓存)与 Environment(每轮变化)。 理由:① 模块化让「加一类指令」变成「加一个 Module」;② SliceStable 保证跨调用逐字节一致 → 缓存命中;③ 把「什么内容会变」变成类型级约束,而不是靠适配器猜。 后果:

  • ✅ 可扩展、可缓存、可测试
  • ❌ Module 的 priority 是魔法数字,需要人工维护不冲突 替代方案:一整段 system + 适配器猜哪部分可变 —— 不可靠;或不做缓存 —— 长会话输入成本高一个量级。

ADR-012 · MCP 工具适配成内置 Tool 接口 ​

背景:MCP 生态有海量社区工具,但它们的执行是远端/子进程。 决策:mcp/tool.go 把每个远端工具包装成 tool.Tool,命名 mcp__<server>__<tool>,走完全相同的权限链路、Agent 编排、UI 渲染。 理由:零特判 = 零漏洞面。如果为 MCP 工具开专用路径,权限、超时、截断、审计都要重做一遍,且很容易漏。 后果:

  • ✅ 接入成本极低(改 YAML 即可);权限链路自动覆盖
  • ❌ 实际存在一个漏洞:MCP 工具的 target 提取不到 → 沙箱判定被跳过(因为 isFile=false),规则 Allow(mcp__srv__*) 这类通配也匹配不上 替代方案:为 MCP 工具单独做权限 —— 更灵活但违背「统一链路」原则。

ADR-013 · SubAgent 用「独立运行时 + 共享基础设施」 ​

背景:长任务后再做无关任务时,前序中间结果成为噪声;且无法并行。 决策:子 Agent 有独立的 SessionRuntime / Conversation / token 计数,但共享 Provider / Registry / PermissionEngine / HookEngine。 理由:隔离的是「状态」,共享的是「能力」。状态隔离防污染;能力共享避免重复初始化(连接池、规则加载)并保证权限策略一致。 后果:

  • ✅ 上下文隔离 + 权限一致;Fork 模式借父对话命中 Prompt Cache
  • ❌ 无并发上限(模型可一次启动无限子 Agent);子 Agent 的审批升级链未接线 替代方案:子 Agent 完全独立进程 —— 隔离更彻底但启动开销大、无法共享缓存。

ADR-014 · 会话持久化用 JSONL 追加写 ​

背景:需要让对话历史在进程退出后可恢复。 决策:一行一条 JSON,O_APPEND 追加写,每条 fsync;压缩时写一条 compact 标记 + 全量快照,恢复时从最后一个标记之后加载。 理由:① 追加写崩溃最多丢最后一行;② 可观测(tail -f 就能看 Agent 在干什么);③ 零依赖(无 CGO/数据库驱动)。 后果:

  • ✅ 简单、可靠、可调试
  • ❌ 写放大(已知缺陷:manageAuto 每轮无条件 ReplaceMessages → 每轮写标记 + 全量重写,写放大 = 轮数 × 历史长度);无并发写保护;查询能力弱 替代方案:SQLite —— 查询强但引入依赖;或只在内存 —— 丢会话。

ADR-015 · Spec 驱动开发(每章五件套) ​

背景:单人项目容易「想到哪写到哪」,功能边界模糊、无法验收。 决策:每个功能章节先写 prompt.md → spec.md(编号需求 F# + 验收 AC#)→ plan.md → task.md,实现后写 checklist.md 逐项验收。 理由:① 把「想法」固化成可验证的需求;② 需求编号让「哪些做了、哪些没做」一目了然;③ checklist 是回归测试的素材。 后果:

  • ✅ 13 章全部有据可查;范围蔓延被抑制(每章都有「不做的事」清单)
  • ❌ 文档开销大(13 章 × 5 个文件);小改动也要走流程 替代方案:只写 README —— 快但边界模糊,容易做成「什么都沾一点」。

四、核心数据模型 ​

go
// ─── 协议层(llm)────────────────────────────────
type Message struct {
    Role        string       // user | assistant | tool
    Content     string
    ToolCalls   []ToolCall   // 仅 assistant
    ToolResults []ToolResult // 仅 tool
}
type ToolCall   struct { ID, Name string; Input json.RawMessage }
type ToolResult struct { ToolCallID, Content string; IsError bool }
type Usage      struct { InputTokens, OutputTokens, CacheWrite, CacheRead int64 }

// ─── 循环层(agent)──────────────────────────────
type Event struct {
    Text     string
    Tool     *ToolEvent
    Usage    *Usage
    Iter     int
    Notice   string
    Done     bool
    Err      error
    Approval *ApprovalRequest
    Compact  *CompactEvent
}
type SessionRuntime struct {          // 跨 Run 复用
    Replacement   *compact.ContentReplacementState
    Recovery      *compact.RecoveryState
    AutoTracking  *compact.AutoCompactTrackingState
    Session       *compact.SessionContext
    ContextWindow int
    UsageAnchor   int64
    AnchorMsgLen  int
    TurnCount     int
    ActiveSkills  *skills.ActiveSkills
    HookEngine    *hook.Engine
    PendingReminders []string
    mu            sync.Mutex
}

// ─── 执行层(tool / permission)───────────────────
type Result struct { Content string; IsError bool }
type Tool interface {
    Name() string; Description() string
    Parameters() map[string]any
    ReadOnly() bool
    Execute(ctx context.Context, args json.RawMessage) Result
}
type Engine struct {                  // permission
    root      string
    blacklist []*regexp.Regexp
    user, project, local RuleSet     // 三层配置(local > project > user)
    localPath string
    startMode Mode
}

// ─── 状态层(compact / session)───────────────────
type SessionContext struct { SessionID, SessionDir, SpillDir string }
type ContentReplacementState struct {
    mu           sync.Mutex
    seenIds      map[string]struct{}
    replacements map[string]string
}
type Entry struct {                   // JSONL 一行
    Type, Role, Content string
    ToolCalls   []llm.ToolCall
    ToolResults []llm.ToolResult
    Timestamp   int64
    Model       string                // 仅首条
}

五、接口契约与不变量 ​

5.1 五个关键接口 ​

接口位置方法数抽象的是什么
llm.Providerllm/provider.go:913协议差异
tool.Tooltool/tool.go5工具能力(含 ReadOnly 副作用语义)
agent.AgentCatalogagent/agent_tool.go:223子 Agent 角色目录(打破循环依赖)
agent.TaskManageragent/agent_tool.go:392后台任务管理(打破循环依赖)
agent.ApprovalUpgraderagent/permission_upgrade.go:12函数类型子 Agent 审批升级

5.2 必须维护的六条不变量 ​

#不变量违反后果维护点
I1每个 tool_use 必须有配对的 tool_resultprovider 返回 400executeBatched 取消分支补结果;Run 无条件 AddToolResults
I2历史末尾不能是 tool 角色模型不知道要干什么ensureAssistantTail
I3user / assistant 尽量交替Anthropic 严格校验joinAfterSummary 插 assistant 占位;appendReminderAnthropic 判断末条角色
I4替换决策冻结、替换体逐字节一致Prompt Cache 全量失效ContentReplacementState.DecideOnce
I5恢复段的工具列表 == 本次请求的 tools 参数模型以为自己有未提供的工具BuildRecoveryAttachment(snapshot, in.ToolDefs) 传同一份切片
I6锚点必须包含 CacheRead + CacheWrite缓存命中时估算严重偏低 → 压缩永不触发compact.UsageAnchor

六、常量与阈值总表 ​

面试时被问「这个数字怎么定的」,需要能说出依据。

6.1 循环与执行 ​

常量值位置依据
maxIterations25agent.go:150复杂重构典型 8-15 轮,给 2 倍余量
maxUnknownRun3agent.go:151给模型 1-2 次自我修正机会,3 次说明陷入固定错误模式
maxUnknownRunSub2run_to_completion.go:20子 Agent 试错预算更小
planReminderInterval4agent.go:152完整提醒 ~80 token,精简 ~25 token,按此频率平衡成本与遵循度
tool.DefaultTimeout30sregistry.go:13单工具执行的兜底超时
autoBackgroundDuration120sagent_tool.go:18前台子 Agent 超时自动转后台
bash 内部 timeout120sbash.go:76实际被外层 30s 压制(已知缺陷)
bash 输出截断200 行 / 8000 字符bash.go:116终端输出典型量级
read_file 截断2000 行 / 256KBread_file.go:78-80单文件读取上限
glob / grep 结果上限100 条glob.go:110 / grep.go:85避免结果撑爆上下文

6.2 上下文管理 ​

常量值位置依据
singleResultLimit50000 字节const.go:7≈14K token,超过就值得一次磁盘 IO
messageAggregateLimit200000 字节const.go:9单条 RoleTool 消息内聚合上限
SummaryReserve20000const.go:15给摘要输出预留
AutoSafetyMargin13000const.go:17吸收估算误差 + 单轮波动
ManualSafetyMargin3000const.go:19手动/紧急路径只需保证摘要请求本身塞得下
recoveryFileLimit5const.go:24文件快照数量上限
recoveryTokensPerFile5000const.go:25单文件快照 token 上限
recentKeepTokens10000const.go:30近期原文保留的 token 下界
recentKeepMessages5const.go:31近期原文保留的条数下界(与上一个同时满足)
maxConsecutiveAutoCompactFailures3const.go:36熔断阈值
ptlRetryLimit3const.go:41摘要自身撞墙时前 N 次每次丢 1 组
ptlDropPercentage0.2const.go:42之后按比例丢
estimateCharsPerToken3.5const.go:47中英混排经验值(偏保守)
previewHeadBytes / previewHeadLines2048 / 20const.go:52-53替换体头部预览
自动压缩触发线ContextWindow - 33000compact.go:109200K 窗口 → 167K 触发

6.3 扩展与其它 ​

常量值位置
connectTimeout / closeDeadline(MCP)30s / 5smcp/manager.go:20-21
MCP 统一超时30sMCP 规范约定
Hook 默认 timeout30shook/loader.go:174
maxIncludeDepth5instructions/loader.go:11
maxIndexSize(记忆索引)25KBmemory/manager.go:15
maxInstallFileSize / TotalSize / FileCount / Depth1MiB / 8MiB / 64 / 4skills/install.go:17-20
installHTTPTimeout60sskills/install.go:21
环境采集 git status 超时2sprompt/environment.go:44
会话过期清理30 天cmd/mewcode/main.go:119
恢复时会话暂停提醒阈值6 小时tui/resume.go
恢复时预压缩阈值cw - 8000tui/resume.go:57
记忆更新触发每 5 轮 或 关键词agent.go:354
补全菜单最大行数8tui/complete.go:13
默认上下文窗口Anthropic 200000 / OpenAI 128000config/protocol_defaults.go:12-14

七、测试与验收策略 ​

7.1 四层验证 ​

层手段现状
单元测试go test ./...15 个 _test.go,覆盖 agent/command/config/conversation/hook/mcp/permission/prompt/skills/tool。internal/tui 零测试(最大缺口)
竞态检测go test -race ./internal/... ./cmd/...CI 已跑(3 OS × 2 Go 版本矩阵);tui 包因无测试文件而未被实际覆盖
冒烟测试go run ./cmd/smoke非交互式验证完整 Agent Loop(需有效 API key)
端到端tmux 中真实交互,对照 checklist.md 逐项验收每章一个 checklist

7.2 CI 流水线 ​

yaml
# .github/workflows/ci.yml(触发:mewcode/** 变更 + push/PR 到 main)
lint:   golangci-lint            # working-directory: mewcode
test:   go test -v -race -coverprofile=coverage.out ./internal/... ./cmd/...
        matrix: [ubuntu, macos, windows] × [go 1.25, go 1.26]
build:  构建检查

7.3 Spec 驱动的验收闭环 ​

prompt.md  →  需求意图(用户视角)
   ↓
spec.md    →  编号功能需求 F1..Fn + 非功能需求 N1..Nn + 验收标准 AC1..ACn + 「不做的事」
   ↓
plan.md    →  实现方案与模块划分
   ↓
task.md    →  可执行的任务清单
   ↓
[写代码]
   ↓
checklist.md → 逐项对照 AC,标注通过/未通过

为什么这套流程有效:spec.md 里的「不做的事」清单是关键——它显式地划定了范围,避免「顺便把 Y 也做了」导致的半成品堆积。例如 ch04 的「不做的事」里明确写了「权限系统 / 上下文压缩 / 沙箱」都留待后续章节。


八、未完成项与后续规划 ​

8.1 路线图上的未实现功能 ​

章节功能状态
ch10LSP 集成(跳转定义、查找引用、诊断)📋 待排期
ch11插件系统(用户自定义工具加载器)📋 待排期

8.2 已知缺陷清单(按严重度) ​

#缺陷影响严重度
1edit_file 参数名与权限层不匹配工具用 file_path,权限层读 m["path"](permission/settings.go:122)→ ok=false → Engine.Check 返回 Deny「无法解析文件路径参数,安全拒绝」。核心编辑工具在主路径下一律失效🔴 高
2工具 panic 无 recover一个工具崩溃打穿整个进程🔴 高
3MCP 工具绕过沙箱extractTarget 返回空 → 沙箱检查被跳过🔴 高
4bash 不受沙箱约束「最危险的通道防护最弱」🔴 高
5ReplaceMessages 每轮触发全量重写写放大 = 轮数 × 历史长度(二次增长),每条 fsync🟠 中高
6子 Agent 审批升级链未接线WithApprovalUpgrader 定义但从未调用,子 Agent 遇 Ask 可能永久阻塞🟠 中高
7llm 层零重试零超时模型静默挂起 → 主循环无限等待🟠 中高
8Agent 工具 120s 转后台阈值永不生效外层 tool.DefaultTimeout=30s 抢先;且 Execute 返回即 cancel(),后台任务继承的 ctx 启动即失效🟠 中高
9allowedTools 不是执行层硬约束只裁剪发给模型的 schema,Registry.Execute 无白名单校验 → 可被提示注入绕过🟠 中高
10MaxTokens 硬编码 4096长输出被截断且 stop_reason 不被区分🟠 中
11thinking 一旦用过工具就永久关闭长会话拿不到扩展思考🟠 中
12permission 前四层零单测安全模块没有回归保护🟠 中
13规则匹配未归一化路径./src/secret.go 可绕过 Deny(Write(src/secret.go))🟡 低中
14escapeGlob 与 matchCommandPattern 语义不匹配含 *?[] 的命令「永久允许」后规则永不命中🟡 低中
15filter.go 工具名大小写不一致"load_skill" vs "LoadSkill" → 后台子 Agent 的 Skill 工具被静默剔除🟡 低中
16记忆索引启动读一次新笔记要重启进程才进入系统提示🟡 低中
17internal/tui 零测试最重的并发消费者无测试覆盖🟡 低中
18子 Agent 无并发上限模型可一次启动无限子 Agent🟡 低中
19git status 采集在 Run 起始一次长任务中 git 状态不更新🟢 低

面试建议:主动挑 3-4 条讲(推荐 1、2、5、6),每条说清「影响 + 修法」。缺陷 1 是最好的素材——它是「跨模块 key 不一致导致静默失效」的教科书案例,结论落在「分层必须有契约测试」,比单纯罗列功能有说服力得多。

8.3 如果要继续演进(下一步做什么) ​

优先级事项理由
P0修 edit_file 参数名不一致(核心编辑工具当前失效)功能底线
P0工具 panic 兜底 + llm 层超时/重试稳定性底线
P0修 MCP/bash 的沙箱绕过;allowedTools 下沉到执行层安全底线
P1抽公共 Agent Loop(消除 120 行重复)可维护性
P1修 ReplaceMessages 写放大性能
P1补 permission + tui 单测(含跨模块契约测试)质量底线
P1修子 Agent 审批升级链接线 + 120s 转后台阈值失效功能完整性
P2token 预算控制替代单一轮数上限成本可控
P2接入 OTel(trace + metrics)可观测,也是排障需要
P2评测集(任务级自动判据)质量闭环
P3LSP 集成代码智能

九、相关文档 ​

文档内容
项目首页定位、能力地图、阅读顺序
01 · 项目全景与面试开场三档自我介绍、简历写法、埋钩子
02 · 架构分层与依赖设计六层架构、依赖图、接口契约
03 · Agent 内核与 ReAct 循环循环、停止条件、保序分批并发
04 · 工具系统与执行编排Tool 接口、六工具、截断策略
05 · 权限与安全护栏五层防御、规则引擎、已知缺陷
06 · 上下文工程与压缩两层压缩、锚点估算、熔断
07 · 记忆、会话与项目指令三层记忆、JSONL、@include
08 · 扩展机制:MCP / Skill / Hook三种扩展点
09 · SubAgent 与后台任务主从架构、Fork、任务管理
10 · 多协议抽象与提示工程协议对照、缓存通道
11 · TUI 与 Go 并发模型Elm 架构、channel、锁
12 · 面试追问题库120 问 + 手撕题 + 反问
13 · 企业级 Agent 平台方案七个维度的生产化

持续学习,持续构建。