手搓 Agent:权限护栏与 Hook 系统学习笔记

这是我手搓 coding agent 系列的第 3、4 节笔记(前两节是最小 agent loop 和多工具 dispatch)。 前两节做出来的 agent 有个吓人的特点:模型说调什么工具,循环就直接执行,包括 rm -rf /。这节就是给它装刹车,并且把刹车做成一个可扩展的系统。 一句话总结这两节的本质: s03:在工具执行前插一道检查,决定放行 / 询问 / 拒绝。 s04:把这道检查从「写死在循环里」抽象成「往事件上挂回调」,以后加功能不用再改循环。 一、s03 权限护栏:三道闸门 之前的循环是"信任模型"——handler(**args) 直接执行。s03 只做一件事:在执行之前加一段检查。整个循环、工具、dispatch 表都没动,只在执行前多调了一个 check_permission()。 核心是三道闸门,从严到松: 工具要执行了 │ 闸门1 DENY_LIST ──命中──→ ⛔ 直接拒,连问都不问 │ 没命中 闸门2 RULES ──命中──→ 闸门3 ask_user ──你按 N──→ 拒绝 │ 没命中 └──你按 y──→ 放行 │ ✅ 执行 闸门 1:硬拒绝表(deny list) 一张黑名单,命中直接拒: DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if=", "> /dev/sda"] def check_deny_list(command: str) -> str | None: for pattern in DENY_LIST: if pattern in command: # 字符串包含就算命中 return f"Blocked: '{pattern}' is on the deny list" return None # 没命中 → None 这里有个贯穿全节的约定:命中返回理由字符串(真值),没命中返回 None(假值)。这样上层一句 if reason: 就能判断。 ...

4 min · 639 words · Jiaju

给 Agent 加工具:Tool Dispatch 学习笔记

这篇是我学「给 Agent 加工具」(s02 Tool Use)时整理的笔记。接着上一篇手搓最小 Agent Loop往下走。 一句话总结这一节的核心: 给 agent 加一个工具,只需要"加一行"——循环代码完全不动,新工具注册进一张**派发表(dispatch map)**就行。 我用的还是通义千问 qwen-plus(OpenAI 兼容接口)。 一、为什么要给它多个工具 s01 里 agent 只有一个 bash。读文件要 cat,写文件要 echo "..." > file,找文件要 find。问题是:模型脑子里想的是"读这个文件",却要拼出一条 cat path/to/file 的命令——多了一层翻译,浪费 token,还容易拼错。 s02 的做法:给它 5 个专用工具,让它直接表达意图。 工具 干什么 read_file 读文件 write_file 写文件 edit_file 把文件里一段旧文字换成新文字 glob 按模式找文件,如 *.py bash 兜底,其它都不合适时才用 system prompt 里写一句"能用专用工具就别用 bash",模型就会优先挑合适的工具。 二、新概念:工具派发(dispatch) s01 只有 bash,模型一说要工具,代码闭眼调 run_bash 就行。现在有 5 个工具,模型说"我要 read_file",代码得按名字找到对应的那个 Python 函数去执行——这就是 dispatch。 实现靠一张派发表:一个把"工具名字符串"映射到"真正函数"的字典。 TOOL_HANDLERS = { "bash": run_bash, "read_file": run_read, "write_file": run_write, "edit_file": run_edit, "glob": run_glob, } ⚠️ 易错点:值是 run_bash,不要加括号。 run_bash(不加括号)= 把函数本身存进表,需要时再调 run_bash()(加括号)= 立刻执行它,存进表的是执行结果,错了 ...

3 min · 429 words · Jiaju

手搓最小 Agent Loop 学习笔记

这篇是我手搓最小 Agent Loop(s01)时整理的笔记。一句话总结它的本质: 大模型本身只会"说话"。把它的话真的执行掉、再把结果喂回去,它就从"会聊天"变成了"会干活"——这就是 agent。 我用的是通义千问 qwen-plus(走 OpenAI 兼容接口),但下面的道理换任何模型都一样。 一、Agent 到底是什么 一开始我有个困惑:大模型不是只会问答吗?它怎么还能帮我创建文件? 答案是:文件不是模型创建的,是我的代码创建的。 模型自始至终只做了一件事——输出文字。 拆开看,一个 agent 其实是三个角色凑在一起: 角色 是谁 干什么 🧠 动嘴的 大模型 只会输出文字,包括"我想用某个工具"(tool_calls) 📞 传话的 agent loop 代码 读模型的话 → 转给工具 → 把结果再转回给模型 🔧 动手的 run_bash(subprocess) 真的在电脑上执行命令 所以当我说"创建一个 hello.py",发生的是: 我说"建 hello.py" ↓ [模型] 动嘴:我想执行 echo ... > hello.py ← 只是输出文字,文件还不存在 ↓ [代码 run_bash] 动手:真的执行命令 ← ✨ 文件在这一步才诞生 ↓ [把结果喂回] → [模型] 看到成功 → 说"搞定了" ← 不再要工具,结束 关键认知:模型不会"主动调用"工具,它连发消息的能力都没有。 是我写的 for call in msg.tool_calls: 那段循环,替模型把话送到 bash 那儿。没有这段代码,模型说一万句"我想执行 ls"都没用。 ...

3 min · 446 words · Jiaju

RAG 入门:在模型回答之前,先检索资料

这篇是我学 RAG 时的白板笔记整理。RAG(Retrieval-Augmented Generation,检索增强生成)是现在几乎所有"让 AI 读自己资料"产品的底层套路,比如企业知识库问答、文档助手、客服机器人。 一句话总结它的本质: 在模型回答之前,先检索资料,再基于资料生成回答。 下面按"为什么需要它 → 它怎么工作"的顺序展开。 一、为什么需要 RAG 1. 直接把所有资料喂给模型,为什么不可行? 最朴素的想法是:把全部文档塞进 prompt,让模型自己看。这条路有三个问题: 上下文窗口有限。模型一次能读的 token 数是有上限的,几百页的文档根本塞不下。 成本。就算塞得下,每次提问都把全部资料发一遍,token 费用会爆炸。 响应速度。输入越长,模型处理越慢,用户体验直线下降。 2. 模型本身也有短板 就算不考虑塞资料的问题,纯靠模型自己回答也有硬伤: 知识过时。模型的知识停留在训练截止日期,问它昨天发生的事它不知道。 私有数据。公司内部文档、个人笔记,模型训练时根本没见过。 幻觉。不知道的事情它可能一本正经地编。 RAG 的思路就是绕开这些限制:资料放在模型外面,每次只把和问题相关的一小段喂进去。 二、核心流程 整个 RAG 分两个阶段:数据准备(离线,只做一次)和用户提问(在线,每次提问都执行)。 flowchart LR subgraph prep["① 数据准备(离线,只做一次)"] direction LR A["📄 原始文档"] --> B["切分 Chunking按章节 / 段落 / 字数……"] B --> C["🧩 Chunks每一块语义相对完整"] C --> D["Embedding(向量化)"] D --> E[("向量数据库")] end flowchart LR subgraph query["② 用户提问(在线,每次提问都执行)"] direction LR Q["❓ 用户问题"] --> QE["问题也做Embedding"] QE --> S["相似度检索找距离最近的 top-k 块"] V[("向量数据库")] --> S S --> P["相关资料 + 问题拼成 Prompt"] P --> L["🤖 LLM 生成回答"] end 第一步:数据准备 切分(Chunking) 文档不能整篇存,要先切成一块块的 chunk。切分的依据可以是章节、段落、字数……没有标准答案,但有一条核心原则: ...

1 min · 207 words · Jiaju

LLM Agents: How ReAct, Tool Use, and Planning Actually Work

“Agent” is one of the most overloaded words in AI right now. Everything from a simple function-calling wrapper to AutoGPT gets called an agent. This post cuts through the hype and explains the actual mechanics: how agents think, act, and plan, with the math to back it up. What Is an Agent? A bare LLM is a function: given a prompt, output a completion. An agent wraps that function in a loop: ...

6 min · 1219 words · Jiaju