惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
Help Net Security
Help Net Security
月光博客
月光博客
N
News and Events Feed by Topic
Cloudbric
Cloudbric
博客园 - 司徒正美
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tenable Blog
The Register - Security
The Register - Security
The Hacker News
The Hacker News
I
InfoQ
The Last Watchdog
The Last Watchdog
MyScale Blog
MyScale Blog
Schneier on Security
Schneier on Security
WordPress大学
WordPress大学
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
K
Kaspersky official blog
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
F
Fortinet All Blogs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
C
Cisco Blogs
N
News and Events Feed by Topic
V2EX - 技术
V2EX - 技术
Latest news
Latest news
PCI Perspectives
PCI Perspectives
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
T
Tor Project blog
Project Zero
Project Zero
云风的 BLOG
云风的 BLOG
Webroot Blog
Webroot Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

lznauy的技术小屋

Kubelet Pod 生命周期管理 Kubernetes 存储 PV/PVC/CSI 体系 Kubernetes API Server—请求处理链路 Kubernetes 调度器—Pod 如何被分配到节点 Kubernetes Controller 调谐循环的实现原理 Kubernetes 核心资源模型的设计哲学 Gin 路由为什么快:Radix Tree 源码剖析 前路茫茫 用AI开发新主题仅需一天 AIAgent开发杂谈 CodeAgent的开发比我想象的难的多 nix语法初入门 记录一次家里老人受骗 nixos美化shell及常用软件安装 皖南川藏线之旅 nixos配置kitty以及桌面美化 nixos安装niri和noctalia nixos-shell及配置优化 nixos-flake和home-manager nixos折腾之旅 claude源码泄漏事件及简单剖析 春季赏花之旅 曲折的离职过程 年味越来越淡了 城市里没有爱情? 日常碎记(三) 利用DeepSeek分析你的隐藏天赋 SELinux技术介绍 我们的认知可能被裹挟了 日常碎记(二)
NekoCode 深度解析
lznauy · 2026-06-30 · via lznauy的技术小屋

前言 @

上个月在《AI Agent 开发杂谈》里聊了 NekoCode 的架构思路,但那篇偏概述。这篇文章换个角度,从工程实现层面拆开几个核心子系统:它们解决什么问题,代码里怎么落地,又如何互相配合。

UI 设计 @

在聊子系统之前,先说说 NekoCode 长什么样。毕竟一个终端工具,交互体验决定了你用不用得下去。

GUI 界面包含 session 切换、明暗两种色调、上下文状态,以及 Skill、MCP、Plugin 管理页面。

gui gui gui gui gui gui

TUI 界面的整体风格我称之为「深夜书房」——暗色背景上,teal 色(#4ec9b0)偶尔闪现,像暗处猫眼的反光。色彩体系刻意克制,只用了六种颜色:

  • 主文字 #a0a0a0:柔和灰,长时间看不累
  • Teal 主色 #4ec9b0:用于 Assistant 标签、spinner、处理卡片边框
  • User 暗金 #c9a96e:用户消息的左侧竖条,暖而不刺眼
  • #7a8ba0:推理过程的分隔线
  • #e06c75:错误和危险操作
  • Diff 绿 #98c379:代码增行

弱化文字用 #666666#808080,边框线用 #333333 隐入背景。整套配色没有高饱和色,在终端里看久了也不会视觉疲劳。

tui

tui tui

下面是整个 UI 最花心思的部分。Agent 执行任务时,界面会实时展示当前状态:

  • Summary 行:猫颜文字 + 工具调用计数(“3 tools · 1 change”)+ 活跃的子 Agent 彩色圆点
  • Activity 区:最近 5 条非持久工具调用,每条显示工具名和参数摘要
  • Changes 区:持久工具块的结果展示,当前包括 edit、bash、write,其中 edit 会内联展示 diff
  • Output 区:模型流式输出的文本,固定 6 行高度,内容自动滚动
  • Thinking 区:模型的推理过程(CoT),固定 6 行高度
  • Header 行:spinner + 阶段名(“Thinking”)+ 当前 skill + token 计数(↑↓)+ 微压缩计数(🧹)

整个处理卡片用 teal 色 NormalBorder 包裹,和已完成的消息在视觉上明确区分。

start chat

这里简单解释下:猫爪图标代表主 Agent 的工具调用,不同颜色的子 Agent 图标代表不同子 Agent 的工具调用。Header 里出现几个子 Agent 图标,就表示当前同时启动了几个子 Agent。

当 Agent 要执行 modify/danger 级别的操作时,底部弹出确认栏。确认栏用 box-drawing 字符画边框,显示具体命令和路径,而不是只显示工具名。等级标签 [modify] / [danger] 使用黄色,[blocked] 使用红色;[safe] 命令自动放行,不弹确认框。yes/no 按钮带背景色:绿色底 [enter] yes,红色底 [esc] no

输入交互 @

输入框支持多行(最多 8 行),Alt+Enter 换行,Enter 发送。输入 / 时底部弹出命令补全面板,Tab/Shift+Tab 选择,Enter 填入。↑/↓ 翻阅历史消息。Ctrl+E 切换工具块的折叠/展开。处理中按 Enter 触发 BTW 中断——注入新消息打断当前 LLM 调用。

设计思路 @

UI 设计上主要遵循几个原则:

  1. 信息密度适中:终端空间有限,不能什么都展示。非持久工具收进 Activity,edit/bash/write 这类持久结果放到 Changes,Activity 限制 5 条,让用户聚焦在模型的文本输出上,细节按需展开。
  2. 状态可见:Agent 在干什么、调了什么工具、token 花了多少、有没有触发压缩——这些信息实时可见,不会让人焦虑「它是不是卡住了」。
  3. 操作低摩擦:safe 命令自动放行、斜杠命令有补全、BTW 随时打断——减少不必要的确认和等待。
  4. 视觉克制:不用高饱和色、不用闪烁动画(除了猫眼)、不用 emoji 堆砌。终端本身就适合安静、专注的氛围。

子系统全景 @

NekoCode 目前由 10 个子系统 组成,按职责分为三层:

核心层——Agent 运行的基础设施:

# 子系统 代码位置 一句话职责
1 Agent 循环 bot/agent/runtime/ ReAct 循环引擎,驱动 Reason → Execute → Feedback 全流程
2 LLM 抽象层 bot/llm/ 多协议适配(Anthropic / OpenAI),流式调用,指数退避重试
3 上下文管理 bot/contextmgr/ 分层上下文构建 + 五级自动压缩 + 全局 Memory + 会话快照与恢复
4 工具系统 bot/tools/ 13 个固定注册工具 + 条件/动态工具,Bash 四级安全分级,oldString/newString 内容锚定编辑

治理层——约束模型行为、保障安全:

# 子系统 代码位置 一句话职责
5 Hook 系统 bot/hooks/ 事件驱动治理,8 个注入点,12 个内置 Hook,5 种动作类型
6 Policy 系统 bot/policy/ Ledger 操作账本 + 探索效率追踪,为 Hook 提供决策数据
7 Prompt 构建 bot/prompt/ System Prompt 分层组装,动态注入项目规范、Skills、Hints

扩展层——能力外延与工程支撑:

# 子系统 代码位置 一句话职责
8 子 Agent bot/agent/subagent/ 独立上下文的任务委派,3 种类型,8 槽位并发管理
9 扩展生态 bot/extension/ Plugin / MCP / Skill 三大扩展机制的统一接入
10 代码索引 bot/index/ Tree-sitter 多语言解析 + FTS5 全文搜索,加速代码理解

下面逐一展开。


1. Agent 循环 @

Agent 循环是整个系统的骨架,入口是 Agent.Run()。核心是一个 for 循环,每轮调用 runTurn()

Prepare → Reason → [有工具调用?] → Execute → Feedback → PostTurn
                        ↓ 无
                     PostTurn → 结束

Prepare 阶段 @

每轮开始前做三件事:触发自动压缩(AutoCompactIfNeeded,按需执行 MicroCompact 或 Compact)、计算本轮工具配额(budget.ComputeQuota,基于剩余 token 动态分配)、执行 PreTurn Hook 注入 hints。

Reason 阶段 @

调用 LLM,传入当前上下文和工具定义。返回结果分三种情况:文本回复(ActionChat)→ 进入 PostTurn;工具调用列表(ActionExecuteTool)→ 进入 Execute;工具调用解析失败(GarbledToolCall)→ 标记后进入 PostTurn,由 Hook 处理。

Execute 阶段 @

executeAndFeedback 是执行的核心。先过 filterToolCalls——检查配额是否够用、执行 PreToolUse Hook(可能 block 某些调用)、注入 pre-tool hints。然后 Executor.ExecuteBatch 并行执行允许的工具(worker pool 上限 10),收集结果后执行 PostToolUse Hook 和 PostTool Hook。最后工具结果写回上下文,下一轮 Reason 会看到这些结果。

PostTurn 阶段 @

LLM 给出文本回复后,执行 PostTurn Hook。这里会检查回答质量、验证声明是否属实、是否有未完成任务等。如果 Hook 注入了 hint 或 block 了 final answer,循环继续;否则结束。

保护机制 @

  • 步数上限:硬上限 150 步(maxAgentSteps),防止死循环
  • 连续 hint 检测:连续 3 次 PostTurn hint 注入(模型一直说话但不调工具)→ 强制停止
  • 连续失败检测:连续 5 次 LLM 调用失败 → 强制停止
  • 兜底合成:循环结束但没有文本输出时,额外发一次 LLM 请求要求总结;主路径失败还有 emergency fallback(30s 超时 + 自动压缩 + 不重试)

BTW 中断 @

用户可以在 Agent 执行中按 Enter 插入新消息。实现上通过 steering channel(buffer 4)接收中断,replaceCtx() 取消当前 LLM 调用的 context。被中断的调用返回 context.Canceled,Reason 阶段检测到后标记 Interrupted=truerunTurn 把上下文截断到调用前状态(TruncateTo),清空 steering channel 中的消息注入上下文,重新开始 Reason。


2. LLM 抽象层 @

LLM 层负责屏蔽不同供应商的协议差异。核心接口是 types.LLM,两个实现:

  • Anthropic 协议bot/llm/anthropic/):原生 Messages API,支持 thinking/reasoning 内容分离
  • OpenAI 兼容协议bot/llm/openai/):Chat Completions API,DeepSeek、MiniMax 等国内模型通过此协议接入

流式处理 @

tools.CallLLM 封装了统一的流式调用逻辑。支持三个回调:TextCallback(文本增量)、ReasoningCallback(推理过程增量)、CheckDone(检查是否应提前终止)。流式解析时自动分离 reasoning content 和普通 content。

重试机制 @

withRetry 实现指数退避重试,处理网络抖动和临时性 API 错误。重试次数和间隔可配置。

Thinking 控制 @

子 Agent 的 thinking 模式强制关闭(节省 token),主 Agent 根据模型配置决定。跨协议统一控制——Anthropic 通过 thinking.budget_tokens,OpenAI 兼容协议通过 reasoning_effort 或 extra_body 参数。


3. 上下文管理 @

上下文管理是 Agent 系统最复杂的子系统之一。核心挑战:窗口有限、前缀缓存宝贵、压缩不能丢关键信息。

分层构建 @

Build() 按以下顺序组装上下文:

Layer 0:  System Prompt(最稳定,最大化前缀缓存命中)
Layer 0M: 项目记忆(~/.nekocode/memory.md)
Layer 0.5: Archive(压缩摘要)+ Skills + Hints
Layer 1:  对话消息(经过 filterValidMessages 过滤)
Layer 2:  Todo 列表

filterValidMessages 做两件事:移除没有对应 tool result 的 assistant tool_call 消息(孤儿调用);移除没有对应 tool_call 的 tool 消息(孤儿结果);空 content 的非 system 消息补 .(某些 API 不允许空 content)。

五级压缩 @

compact.Compactor 驱动,基于上下文窗口剩余量自动触发,默认阈值如下:

级别 剩余 token 动作 是否调 LLM
Normal > 44,800 无操作 -
Warning ≤ 44,800 仅告警 -
MicroCompact ≤ 35,200 清除旧的只读工具结果,保留最近 5 个
Compact ≤ 25,600 LLM 生成结构化摘要,压缩最旧消息
Blocking ≤ 6,400 拒绝新输入,强制压缩

MicroCompact 是轻量级操作——只清除标记为 compactable 的工具结果(read/grep/glob 等只读工具的旧输出),不触发 LLM 调用,不影响前缀缓存。Compact 调用独立 LLM 客户端生成摘要。

摘要合并 @

多次 Compact 后会产生多个 Archive。Summarize() 调用 MergeClient(独立 LLM 客户端)将新旧 Archive 合并为一个,避免 Archive 膨胀。

Project Memory @

项目记忆当前是全局文件 ~/.nekocode/memory.md,启动时加载并注入 Layer 0。文件按 5 个固定段落组织:Tech Stack、Active Goals、Completed Tasks、Key Architecture Map、User Preferences。代码里已经有 MergeFromCompaction,用于把压缩摘要里的关键事实合并回 memory,但它不是按 session 单独写入 ~/.nekocode/sessions/<id>/memory.md

快照与恢复 @

ManagerSnapshot 捕获完整状态——SystemPrompt、Skills、Archive、Memory、Hints、Messages、CompactBoundary、Budget、Tracker。支持会话存档和恢复,/sessions 命令依赖此机制。


4. 工具系统 @

注册机制 @

工具通过 Registry 统一管理,基于泛型 common.Registry[Tool]。每个工具实现 Tool 接口(Name()Description()Parameters()),注册后自动生成 LLM function calling 的 tool definitions。支持条件注册和动态注册(Skill 加载时动态添加工具)。

固定工具与条件工具 @

工具 功能 安全等级 执行模式
bash Shell 命令执行 Safe~Blocked(智能分级) Sequential
read 文件读取 + 二进制检测 Safe Parallel
write 文件创建/覆盖 Modify Sequential
edit oldString/newString 内容锚定替换 Modify Sequential
list 目录列表 Safe Parallel
tree 目录树可视化 Safe Parallel
glob 文件模式匹配 Safe Parallel
grep ripgrep 内容搜索 Safe Parallel
web_search Web 搜索 Safe Parallel
web_fetch 网页抓取 Safe Parallel
question 向用户提问 Safe Sequential
todo_write 任务列表更新 Safe Sequential
task 子 Agent 委派 Safe Parallel
image_gen AI 文生图,配置了图片模型后注册 Safe Sequential
project_info 代码索引查询,索引管理器可用时注册 Safe Parallel
skill Skill 加载工具,扩展层动态注册 Safe Sequential

固定注册在 bot/tools/catalog.RegisterAll 里的工具是 bash、read、write、list、tree、glob、edit、grep、web_search、web_fetch、question、todo_write、task。image_gen 只有在配置了图片生成模型时注册,project_info 在代码索引管理器可用时注册,skill 由扩展层动态注册;MCP 工具则来自外部服务器。

Bash 四级智能分级 @

不是简单的「允许/禁止」二分,而是按关键词智能分级:

  • Safe(自动放行):git loggit diffgit statusgo versiongo vetlscatpsdufile 等纯输出命令
  • Modify(弹框确认):默认级别
  • Danger(警告确认):curlwgetrmchmodkillrebootgit pushgit reset --hard
  • Blocked(直接拒绝):sudoevalsshcurl | bashddmkfs

Edit 内容锚定 @

使用 oldString/newString 模式而非行号替换。hasSufficientEditAnchor 检查锚定充分性:oldString ≥ 200 字符,或包含 ≥ 5 个非空行。锚定充分时,即使文件未被 read 过也能放行(ReadBeforeWriteHook 的例外)。编辑后自动跑 gofmt 检查 Go 文件语法。

工具结果预算 @

写入上下文前会经过 BudgetResult。当前实现只对 grep 结果做首尾保留:保留前 50 行和后 50 行,中间用截断标记替代,避免大范围搜索结果撑爆上下文窗口;其他工具结果暂不在这里做通用 50KB 截断。


5. Hook 系统 @

Hook 是 NekoCode 最核心的治理机制。设计思想:不修改 Agent 循环代码,通过事件注入约束模型行为

8 个注入点 @

UserSubmit → PreTurn → PreModelRequest → [Reason] → PreToolUse → [Execute]
                                                         ↓
                                                    PostToolUse → PostTool
                                                         ↓
                              [Reason 返回文本] → PostTurn → Stop

5 种动作类型 @

动作 效果
Hint 注入提示到下一轮上下文,引导模型行为
Stop 立即终止 Agent 循环
BlockTool 阻止某个工具调用执行
RequireTool 要求模型必须调用某类工具(否则 block final answer)
BlockFinal 阻止模型输出最终答案(要求修正后重试)

12 个内置 Hook @

Hook 注入点 职责
QuotaHook PreTurn 工具调用配额管理
ToolResultGuardrailHook PreModelRequest 工具结果过多时提醒检查未完成任务
ReadBeforeWriteHook PreToolUse 未读文件不准改
ReadOnlySpiralHook PostTool 连续只读不写 → 要求总结
VerificationHook PostTurn 有未完成任务但没调工具 → block
ExplorationExhaustedHook PreTurn 探索配额耗尽 → 要求行动
ExplorationGuardHook PreToolUse 探索耗尽后 block 探索类工具
ExploreCascadeHook PostTool 过多 researcher 子 Agent → 提醒收敛
ProgressStallHook PostTool 连续 8 轮无进展 → 强制要求 edit/write/bash
CompletionQualityHook PostTurn 回答质量检查
GarbledCircuitBreaker PostTurn 累计 5 次乱码 → Stop
FinalCheckHook PostTurn 最终答案诚实性校验(3 条规则)

FinalCheckHook 的三条规则 @

  1. missing_verification:修改了非文档文件但没有通过验证,且回答未声明「未验证」→ block
  2. unsupported_test_claim:回答声称测试通过,但 ledger 无验证记录 → block
  3. unreported_tool_error:存在工具错误,但回答声称完成且未提及失败 → block

Response Gate @

BlockFinalRequireTool 不是无限重试。responseGate 限制最多 2 次重试,超过后放行答案,防止「被 block → 重试 → 再被 block」的死循环。

状态共享 @

Hook 之间通过 storemap[string]int64)和 strValsmap[string]string)共享状态。Policy Manager 每轮开始时同步 Ledger 数据到 store,Hook 可通过 StatePatch 修改状态。


6. Policy 系统 @

Policy Manager 是 Hook 系统和 Agent 循环之间的桥梁,持有三个核心组件:

  • HookReg:Hook 注册表引用
  • Ledgerbot/policy/ledger/):操作账本,记录文件读取、修改、验证、工具错误、被 block 的工具调用
  • Explorationbot/policy/budget/):探索效率追踪器——评估探索类工具调用的收益递减

每轮同步 @

ResetTurnBetween 在每轮开始时将 Ledger 状态同步到 Hook store:

  • StoreLedgerModified:已修改文件数
  • StoreLedgerVerified:是否有通过验证
  • StoreLedgerErrors:工具错误数
  • StoreLedgerNonDocModified:是否有非文档类修改
  • StoreLedgerProgress:本轮是否有新进展(新读取/修改/验证)

Hook 基于这些状态做出决策。例如 ProgressStallHook 检查 StoreLedgerProgress,连续 8 轮为 0 则触发。

探索追踪 @

ExplorationTracker 评估探索类工具调用的效率。每次探索类调用后更新评分,评分归零且调用超过 10 次时,ExplorationExhaustedHook 触发。


7. Prompt 构建 @

System Prompt 采用分层组装策略,由 bot/prompt/ 负责构建:

  • 基础层:角色设定(黑猫形象、软萌风格)、核心准则(先理清思路、按需探索、信任权威数据等)
  • 工程规范层:不添加超出需求的功能、不设计假设性需求、修改成本大时直接重写
  • 输出规范层:工具调用时禁止解释性文字、ASCII 树必须套代码块、inline code 仅用于短路径
  • 工具准则层:优先专用工具、并行只读、串行修改、edit/write 前必须 Read
  • 动态注入层:Skills 列表、Hints(Hook 注入)、项目规范(NEKOCODE.md)、环境信息(OS/Arch/日期/工作目录)

动态注入的内容放在 System Prompt 末尾,保证前缀缓存最大化——基础层几乎不变,动态层变化频繁但放在最后。


8. 子 Agent @

子 Agent 通过 task 工具触发,三种类型:

类型 用途 可用工具
executor 执行编码任务 read/write/edit/bash/grep/glob/list
researcher 代码探索/调研 read/grep/glob/list/web_search/web_fetch
verify 验证修改 read/grep/glob/list/bash

Slot 管理 @

subSlotManager 控制并发——最多 8 个 slot,每个有独立颜色索引(0-7,TUI 中区分)。Acquire 在无可用 slot 时阻塞等待(sync.Cond),Release 后唤醒等待者。

上下文隔离 @

子 Agent 使用 NewSub 创建轻量级 ContextManager——独立 SystemPrompt 和 Messages,不继承主 Agent 对话历史。这种「纯净委派」避免上下文污染,也更省 token(前缀缓存更友好)。

回调桥接 @

子 Agent 的工具调用通过 TaskCallbackFn 回调到主 Agent 前端——sub_tool_startsub_execute_toolsub_agent_startsub_agent_end。回调携带 subID:colorIdx 标签,前端据此渲染不同颜色的子 Agent 卡片。

设计原则 @

遵循「Self-Serve First」——主 Agent 优先自己完成任务,只有满足三个条件才委派:跨 5 个以上文件、需要独立上下文、单回合确实太复杂。


9. 扩展生态 @

三大扩展机制统一接入:

  • Pluginbot/extension/plugin/):兼容 Claude Code 插件格式,支持 GitHub 和本地路径安装。当前主要接入插件声明的 Hooks、MCP 配置、commands 与 agents 等资源
  • MCPbot/extension/mcp/):JSON-RPC 2.0 协议,接入外部工具服务器。当前实现以 stdio 进程客户端为主,并通过动态工具适配器暴露 MCP tools
  • Skillbot/extension/skill/):YAML 定义技能包,/<skill> 一键加载。Skill 可注入 System Prompt 片段,并通过动态 skill 工具按需加载

10. 代码索引 @

基于 Tree-sitter 的多语言代码解析 + SQLite FTS5 全文搜索。

  • 符号索引:解析函数、类型、变量定义,支持 symbol: 查询
  • 依赖分析:解析 import/include,支持 deps: 查询
  • 全文搜索:FTS5 索引所有源码,支持 search: 查询
  • 文件定位:文件名模糊匹配,支持 file: 查询

通过 project_info 工具暴露给 Agent,减少不必要的 read/grep 调用,加速代码理解。


结尾 @

NekoCode 的 10 个子系统围绕几个核心原则设计:分层解耦,比如上下文分层、Hook 独立于循环;纵深防御,通过多层 Hook 交叉验证;预算意识,把前缀缓存、配额管理和探索收益递减检测放进主循环;失败可恢复,依靠快照/恢复、兜底合成和 response gate 限流。

目前项目还在实验阶段,Hook 规则和压缩策略还有很多调优空间。如果你对某个子系统的实现细节感兴趣,docs/ARCHITECTURE.md 有更完整的代码级文档。欢迎到 GitHub 提 issue 或 PR。