当前位置: 首页 > article >正文

用 shell 命令做 AI Agent 的插件系统:为什么 Hook 不是函数调用

用 shell 命令做 AI Agent 的插件系统为什么 Hook 不是函数调用这是 《写完一个 AI 编程助手之后我才确定 prompt 工程不是重点》 系列的第七篇最后一篇。前六篇讲了进程模型、权限、并发调度、上下文压缩、记忆系统。这一篇讲 Hook——整个项目里最丑但最有用的设计。整个项目开源github.com/your-handle/code-agent。从src/core/agent/loop.ts开始读200 行就能看完主循环。欢迎点点star。Agent 需要插件系统。记忆系统要在工具执行后记录数据。权限系统要在工具执行前拦截。上下文压缩要在 token 超限时触发。未来还会有日志、监控、审计……第一反应是写一个 EventEmitteragent.on(post-tool-use,async(event){awaitmemorySystem.record(event)})我没这么做。我用了 shell 命令。{post-tool-use:[{command:curl -X POST http://localhost:37777/api/sessions/observations ...,onError:ignore,timeout:3000}]}看起来很丑。但这是我做过的最正确的架构决策之一。一、为什么不用 EventEmitterEventEmitter 有三个致命问题1. 插件必须跟 Agent 同进程如果记忆系统跑在独立 Worker 里第二篇讲过为什么要拆EventEmitter 就没法用。你得在 listener 里写 HTTP 调用那跟直接写 shell 命令有什么区别2. 插件必须用同一种语言Agent 是 TypeScript。如果我想用 Python 写一个分析插件因为 Python 的 NLP 生态更好EventEmitter 做不到。shell 命令不关心你用什么语言实现。3. 插件崩溃会拖垮主进程EventEmitter 的 listener 如果抛异常要么你 try-catch 吞掉隐藏 bug要么让它冒泡主进程挂。shell 命令天然隔离——子进程崩了主进程只看到一个非零退出码。二、Hook 的完整实现100 行核心是HookManagersrc/core/hooks/manager.ts。两个公开方法// 触发事件不关心返回值asyncfire(event:HookEvent,env:Recordstring,string):Promisevoid// 触发事件用返回值变换 payloadasynctransformT(event:HookEvent,payload:T,env:Recordstring,string):PromiseTfire用于通知型 hook记忆记录、日志。transform用于拦截型 hook权限检查、内容过滤。底层都是同一个run方法privaterun(entry:HookEntry,extraEnv:Recordstring,string,stdin:string|null):Promisestring|null{returnnewPromise((resolve,reject){constprocspawn(bash,[-c,entry.command],{cwd:process.cwd(),env:{...process.env,...extraEnv},stdio:stdin!null?[pipe,pipe,pipe]:[ignore,pipe,pipe]})letstdout,stderrletkilledfalseconsttimersetTimeout((){killedtrueproc.kill(SIGTERM)setTimeout(()proc.kill(SIGKILL),3000)},entry.timeout)proc.stdout.on(data,d{stdoutd.toString()})proc.stderr.on(data,d{stderrd.toString()})if(stdin!nullproc.stdin){proc.stdin.write(stdin)proc.stdin.end()}proc.on(close,(code){clearTimeout(timer)if(killed){handleError(...);return}if(code!0){handleError(...);return}resolve(stdout)})})}就是spawn(bash, [-c, command])。没有 SDK没有协议没有序列化格式。数据通过环境变量传入通过stdout传出。三、环境变量是最好的 IPC 格式对于小数据Hook 需要知道当前上下文哪个工具被调用了、输入是什么、结果是什么、session id 是什么。我用环境变量传awaitthis.context.hooks?.fire(post-tool-use,{AGENT_CWD:process.cwd(),TOOL_NAME:tool.name,TOOL_INPUT:JSON.stringify(tool.input),TOOL_RESULT:resultStr.slice(0,10000),SESSION_ID:this.context.sessionManager?.getCurrentSession()?.id||unknown})Hook 命令里直接用$TOOL_NAME、$SESSION_IDcurl-XPOST http://localhost:37777/api/sessions/observations\-HContent-Type: application/json\-d{\toolName\:\$TOOL_NAME\,\contentSessionId\:\$SESSION_ID\}为什么不用 stdin JSON环境变量零解析成本。shell 直接展开不需要 jq、不需要 python -c。环境变量自文档化。看一眼 hook 配置就知道有哪些变量可用。环境变量有大小限制通常 128KB。这是优点——强制你只传必要的数据。TOOL_RESULT我截断到 10000 字符避免一个巨大的文件内容撑爆环境。stdin 留给transform型 hook——它需要接收完整 payload、修改后从 stdout 返回。这种场景数据量大环境变量装不下。小数据走环境变量大数据走 stdin/stdout。不要统一成一种格式——两种场景的约束不同。四、onError 三态ignore / warn / abortHook 失败了怎么办又是三态typeOnErrorignore|warn|abortignore吞掉错误主流程继续。记忆系统用这个——记忆挂了不影响 Agent 工作。warn打一行警告到 stderr主流程继续。日志系统用这个——你想知道它挂了但不想停。abort抛异常主流程中断。权限检查用这个——权限 hook 挂了宁可停也不能放行。这三个选项覆盖了我遇到的所有场景。不需要更多。记忆系统的 hook 配置// src/worker/hooks.tspost-tool-use:[{command:curl -X POST ... || true,onError:ignore,timeout:3000}]注意|| true——即使 curl 失败bash 也返回 0。再加上onError: ignore双重保险。记忆系统的可用性不应该影响 Agent 的可用性。五、timeout 是必须的不是可选的每个 hook 都有 timeoutconsttimersetTimeout((){killedtrueproc.kill(SIGTERM)setTimeout(()proc.kill(SIGKILL),3000)},entry.timeout)没有 timeout 的 hook 系统是定时炸弹。真实场景记忆系统的 Worker 挂了curl 连接超时默认 120 秒。如果没有 timeoutAgent 每次工具调用后都会卡 120 秒等 hook 返回。我的 timeout 设置Hook 类型timeout原因user-prompt-submit5000ms初始化可能要建表post-tool-use3000ms正常情况 500ms3s 是容错session-end2000ms只是一个 HTTP POSTtimeout 不是以防万一是一定会发生。任何网络调用都会超时区别只是你是主动控制还是被动等待。六、transform vs fire拦截 vs 通知fire是单向的——触发 hook不等返回值。适合记录、日志、监控。transform是双向的——把 payload 通过 stdin 传给 hookhook 修改后从 stdout 返回。适合拦截、过滤、变换。asynctransformT(event:HookEvent,payload:T,env:Recordstring,string):PromiseT{letcurrentpayloadfor(constentryofentries){constresultawaitthis.run(entry,env,JSON.stringify(current))if(!result?.trim())continuetry{currentJSON.parse(result.trim())}catch{this.onWarn(Hook returned non-JSON — ignoring)}}returncurrent}多个 transform hook 串行执行前一个的输出是后一个的输入。这是 Unix pipe 的思想——每个 hook 是一个 filter。实际用例pre-toolhook 可以修改工具的 input比如自动补全路径post-samplinghook 可以修改模型的输出比如过滤敏感信息pre-compresshook 可以在压缩前归档消息七、为什么这个设计能活下来这套 hook 系统上线两个月我没改过一行核心代码。期间加了记忆系统3 个 hook上下文压缩通知2 个 hook工具执行计时1 个 hook调试用的 verbose 日志1 个 hook每次都是加一条配置不动框架代码。这就是 shell 命令做 hook 的真正优势扩展点和实现完全解耦。框架只知道在这个时机执行一条命令命令可以是 curl、python 脚本、go 二进制、甚至另一个 Agent命令挂了有 onError 兜底命令慢了有 timeout 兜底最好的插件系统是最笨的那个。不要发明协议不要定义接口不要写 SDK。给一个 shell传几个环境变量收一个 stdout。够了。系列总结六篇写完了。回头看整个系列讲的是同一件事AI Agent 的难点不在 AI在工程。篇目核心判断总论prompt 工程不是重点工程问题决定好坏进程模型阻塞操作 100ms 就拆进程权限系统让工具自己说危不危险框架只做仲裁并发调度让工具自己声明并发安全调度器一行搞定上下文压缩200K 也会满四层兜底让 Agent 永不崩溃记忆系统记忆是信噪比问题不是存储问题Hook 系统这篇最笨的插件系统最耐用贯穿六篇的元原则框架的工作是定义接口不是实现逻辑。把语义留给组件把策略留给框架把实现留给 shell。整个项目开源github.com/your-handle/code-agent。从src/core/agent/loop.ts开始读200 行就能看完主循环。欢迎点点star。如果你也在写 Agent这六篇可以当 checklist 用。每改对一个体感跳一个台阶。

相关文章:

用 shell 命令做 AI Agent 的插件系统:为什么 Hook 不是函数调用

用 shell 命令做 AI Agent 的插件系统:为什么 Hook 不是函数调用 这是 《写完一个 AI 编程助手之后,我才确定 prompt 工程不是重点》 系列的第七篇(最后一篇)。前六篇讲了进程模型、权限、并发调度、上下文压缩、记忆系统。这一篇…...

Gemini3.1Pro和GPT5.5写代码到底谁更强五类任务实测数据说

做多模型编码能力横向对比测试时用了AI模型聚合平台,一站接入两个模型方便跑同一套编码任务。Gemini 3.1 Pro在SWE-Bench Verified拿到80.6%。GPT-5.5在Terminal-Bench拿到82.7%。分数接近但写代码的实际体验和分数不是一回事。这次用五类真实开发任务做了一轮系统对…...

诚邀您参加 2026 Google Cloud Startup Day

以下文章来源于谷歌云服务,作者 Google Cloud...

不是碳基,也不是硅基!你好,我是金蝶灵基,企业AI原生操作系统!

AI是危还是机?自年初小龙虾“爆炸”以来,很多企业服务巨头都或主动或被动地陷入了深深地思考:连一直仰望并追捧的偶像——Salesforce都开始快速变革,我们能无动于衷吗?这半年以来,中国软件网注意到&#xf…...

谷歌“反重力”工具更新强行替换软件,用户恢复工作困难重重!

谷歌“反重力”工具更新强行替换软件,用户恢复工作困难重重!2026年5月21日,原本打算用“反重力”工具工作的用户,遭遇了谷歌的意外安排。前一天,谷歌在2026年I/O开发者大会上推出“反重力”工具新版本,将其…...

BBEdit 16 正式发布!新增百多项功能,部分用户可免费升级

产品 产品 BBEdit Yojimbo iPad 版 Yojimbo TextWrangler 支持 支持 BBEdit Yojimbo iPad 版 Yojimbo TextWrangler 产品下载 找回序列号 SDK 与开发者信息 公司书架 商店 商店 购物车 许可协议 Mac App Store 常见问题 销售政策 查找经销商 多用户许可证 联系我们 联系我们 找…...

uv虽快但包管理体验差:命令笨拙、更新不安全,改进之路在何方?

【uv项目承接与特点】自2023年以来,作者首次有空承接新的项目。Astral的uv在Python世界掀起热潮,它速度极快,能轻松处理Python版本,还能用一个二进制文件替代半打工具,作者之前也写过多篇关于它的文章。【uv使用体验问…...

毫米波混合波束成形技术在VR中的应用与优化

1. 毫米波VR中的混合波束成形技术解析在无线VR应用中,用户对低延迟和高带宽的需求日益增长。传统Wi-Fi标准在密集环境下难以满足这些QoS要求,而毫米波技术凭借其高传输速率和低延迟特性成为理想选择。本文将深入探讨毫米波频段下混合波束成形技术的实现原…...

8051项目代码流程图工具选择与应用指南

1. 流程图工具概述接手一个大型8051项目时,快速理解代码结构是每个嵌入式工程师都会面临的挑战。我在处理遗留代码时,第一件事就是寻找合适的流程图工具来可视化程序逻辑。市面上确实存在多种能够解析C51代码并生成流程图的软件,但选择时需要…...

量子机器学习噪声挑战与HPQS混合框架解析

1. 量子机器学习中的噪声挑战与HPQS解决方案量子机器学习(QML)作为量子计算与经典机器学习的交叉领域,正在重新定义我们处理复杂模式识别问题的方式。与传统机器学习不同,QML利用量子态的叠加和纠缠特性,理论上可以在某些特定任务上实现指数级…...

混合参数化量子态(HPQS)在量子机器学习中的应用与优化

1. 混合参数化量子态(HPQS)框架解析量子机器学习在NISQ(Noisy Intermediate-Scale Quantum)时代面临两大核心挑战:参数化量子电路(PQC)因有限测量次数导致的统计不确定性,以及神经量…...

8051仿真器OMF转SIG格式的实战指南

1. Signum 8051 仿真器符号转换器使用指南在嵌入式开发领域,Signum Systems 的 8051 仿真器是一个常用的调试工具。很多开发者在使用 Vision 开发环境时,经常遇到需要将链接器生成的绝对目标模块(OMF)转换为仿真器专用格式的需求。本文将详细介绍这个转换…...

量子纠错码与逻辑门优化实现技术解析

1. 量子纠错码与逻辑门实现基础量子纠错码是量子计算中确保计算可靠性的核心技术。与经典计算不同,量子态具有相干性和不可克隆性,这使得量子信息在存储和处理过程中极易受到环境噪声的影响。稳定子码(Stabilizer Codes)作为一类重…...

Keil µVision TAB显示异常问题分析与解决方案

1. 问题现象与背景分析在Keil Vision集成开发环境中,部分用户遇到了编辑器界面显示异常的问题。具体表现为:当代码中包含TAB字符(制表符)时,屏幕上会出现奇怪的显示错乱,原本应该显示为空白缩进的区域&…...

量子纠错码与硬件定制逻辑门的优化实现

1. 量子纠错码与硬件定制逻辑门概述量子纠错码(QECC)是容错量子计算的核心组件,其核心思想是通过编码将量子信息分布在多个物理量子比特上,利用稳定子(stabilizer)测量来检测和纠正错误。在众多QECC中&…...

Keil调试中局部变量修改限制的解决方案

1. 问题现象与背景解析在嵌入式开发过程中,调试环节往往占据整个开发周期的40%以上时间。作为Keil Vision的资深用户,我最近在调试一个基于C166架构的通信协议栈时,遇到了一个看似简单却令人困扰的问题:当我在receive_data函数内部…...

到底什么是 AI 测试?AI 测试与传统测试的区别?

过去两年,AI已经从"加分项"变成了"必选项"。 不只是大厂,二线公司、甚至传统行业的测试团队都在要求:"能熟练使用AI工具提效"。 更关键的是,面试的玩法也变了。现在的技术面试早就跳出了 “考 AI 零…...

A51汇编器Error 21解析与8051开发实践

1. 解析A51汇编器Error 21的根源与应对策略在8051单片机开发过程中,使用Keil C51工具链的A51汇编器时,开发者常会遇到一个令人困惑的报错:"ERROR #21: EXPRESSION WITH FORWARD REFERENCE NOT PERMITTED"。这个错误看似简单&#x…...

量子计算与人工智能融合:技术原理与应用前景

1. 量子计算与人工智能融合的技术全景量子计算与人工智能(AI)的交叉领域正在重塑计算技术的边界。作为一名长期跟踪量子计算发展的技术研究者,我见证了从早期理论构想到如今实验室原型机的演进历程。量子计算利用量子比特的叠加与纠缠特性&am…...

Cortex-M3/M4处理器模式判断与调试技巧

1. Cortex-M3/M4处理器模式判断原理在嵌入式开发中,理解Cortex-M3和Cortex-M4处理器的运行模式对调试和异常处理至关重要。这两种处理器架构都采用了两级特权等级和两种执行模式的组合设计:特权等级(Privilege Level):…...

开源fNIRS脑机接口帽技术解析与应用

1. 开源可穿戴fNIRS脑机接口帽技术解析在神经工程领域,功能性近红外光谱(fNIRS)技术正逐渐成为研究大脑活动的重要工具。与传统的脑电图(EEG)或功能磁共振成像(fMRI)相比,fNIRS具有独…...

迁移学习提升可穿戴设备睡眠监测精度的技术解析

1. 项目概述:迁移学习如何提升可穿戴设备的睡眠监测精度作为一名长期关注健康监测技术的从业者,我见证了可穿戴设备在睡眠监测领域的快速发展。但一个核心痛点始终存在:基于PPG(光电容积图)等外周生理信号的可穿戴设备…...

Qwen-Image-2512+LoRA:构建Godot 4.x原生像素编译工作流

1. 这不是“AI画图”,而是一次像素艺术工作流的底层重构你有没有试过在Godot 4.x里导入一张Stable Diffusion生成的“像素风”图,结果放大一看全是模糊的伪像素、边缘发虚、色阶溢出,连8-bit调色板都对不上?我去年帮三个独立游戏团…...

Python循环语句从入门到精通:for和while核心用法详解

编程里,循环属于绕不开的基础操作,Python当中,for与while看似简单,然而不少人写着写着就会卡住,特别是在嵌套、break以及continue的配合方面容易出错。本文助力你理清这两种循环的核心逻辑,结合实际场景讲透…...

BarrageGrab:构建企业级直播弹幕实时采集系统的技术架构与实践指南

BarrageGrab:构建企业级直播弹幕实时采集系统的技术架构与实践指南 【免费下载链接】BarrageGrab 抖音快手bilibili直播弹幕wss直连,非系统代理方式,无需多开浏览器窗口 项目地址: https://gitcode.com/gh_mirrors/ba/BarrageGrab 在直…...

魔兽争霸3终极兼容方案:5分钟解决Win10/Win11运行问题

魔兽争霸3终极兼容方案:5分钟解决Win10/Win11运行问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸3在现代Windows系统上…...

如何重新定义华硕笔记本性能管理:探索G-Helper的轻量化解决方案

如何重新定义华硕笔记本性能管理:探索G-Helper的轻量化解决方案 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Ze…...

UDS_自动化脚本生成_10服务_V01

1、原子元素 1.1 会话原子 Session.Default() Session.Extended() Session.Programming() Session.Developer() 1.2 请求原子 10 01 10 02 10 03 10 76 10 81 10 82 10 83 10 F6 10 04 10 84 10 / 10 01 00 / 10 02 00 / 10 03 00 / 10 76 00 1.3 响应原子 50 01 00 32 01 F4 …...

Frida-ps -U 连接失败的五层排查法

1. 这不是 Frida 的问题,是你的设备和 Frida 之间“没对上暗号” 你执行 frida-ps -U ,终端卡住三秒,然后甩出一句 Failed to enumerate processes: timeout was reached ——这行报错我见过太多次了。它不像编译错误那样指向某一行代码…...

OAuthlib错误排查实战:从invalid_grant到server_error的根因定位

1. 为什么OAuthlib的错误信息总让你一头雾水?刚接手一个老项目,登录流程突然崩了,控制台只甩出一行红字:invalid_grant。我下意识去翻OAuthlib文档,结果发现它压根不解释这个错误到底意味着什么——它只告诉你“授权无…...