
最近在折腾 Emacs 的 agent-shell我最大的感受是AI 编程这件事终于从“聊天框里问问题”变成了“在编辑器里切切实实干活”。作为一个把 Emacs 当主战场的用户我一直在找那种能让 AI 直接碰我的文件、跑我的命令、改我的配置的工具。agent-shell 正好补上了这个缺口。这篇文章把我这几周的配置过程、踩过的坑以及几个典型实战场景都整理出来重点聊聊怎么让这套工作台真正“自我进化”。如果你也打算在 Emacs 里搭一套可复用的 AI 工作台这篇文章应该能帮你少走不少弯路。1. 为什么要在 Emacs 里放一个 agent-shell1.1 AI 编程不是自动补全是“干活”过去大家对 AI 编程的想象多半停留在代码补全你写个函数名AI 帮你补完几行。实际用过以后你会发现这种模式的帮助很有限因为大部分时间我们并不是卡在“不知道某行代码怎么写”而是卡在“这一批逻辑改下来要动哪几个文件、顺序是什么、改完怎么验证”。这种问题需要 AI 具备对项目的整体认知甚至需要它主动去执行命令、查看报错、调整代码。agent-shell 的设计思路就是把 AI 从“被动的回答者”变成“主动的执行者”。它可以读取目录结构、查看特定文件、在 shell 里跑命令、把输出结果返回给模型再根据结果决定下一步操作。这个过程和真人程序员的工作方式非常接近先看项目情况再动手改代码最后跑测试确认。我用它处理过一个比较典型的场景一组 Python 工具函数散落在不同模块里很多代码是重复的。我让 agent-shell 在项目根目录启动会话先让它列出所有相关文件再让它识别重复逻辑最后统一重构并运行测试。整个过程中我几乎没写几行代码但每一步它都能给出可验证的中间结果而不是直接丢给我一大段不知对错的代码。1.2 agent-shell 解决的真实痛点普通的 AI 插件通常只能“看”你当前编辑的文件。但实际项目里一个问题往往涉及十几个文件、环境变量、构建脚本甚至外部服务。agent-shell 这类工具解决的核心问题就是让 AI 拥有操作完整工作台的能力。它不再局限于单个 buffer而是能把 Emacs 本身当成一个操作系统来用。比如读取项目文件时走的是find-file那套逻辑能自动识别项目根目录执行命令时可以直接在eshell或term中运行输出是 Emacs 原生文本能搜索、能操作修改文件时通过 diff 方式应用改动而不是整文件覆盖避免误伤甚至可以调用你的 Emacs 配置函数比如打开某个模块、运行某组 test、格式化文件。这个能力的价值在于AI 不再靠“猜”而是靠“看”。它能先收集现场信息再做出决策。我实际用下来最大的变化不是 AI 写代码的速度而是它给出的方案更贴合项目现状不需要我再做大量转译。2. agent-shell 是怎么跑起来的2.1 一次任务请求的完整链路要理解 agent-shell 的工作方式关键看一次交互发生了什么。当你在会话里输入“帮我把utils.py里的重复函数合并一下”agent-shell 会做下面这几步把输入连同系统提示词、历史上下文、工具描述一起拼装成模型请求调用大模型 API我这边配置的是 GPT 系列和 Claude 轮换使用模型返回一个结构化结果这个结果可能是普通文本也可能是“工具调用意图”agent-shell 解析工具调用意图在 Emacs 内执行对应操作比如read_file、edit_file、run_shell执行完成后把结果作为“观察结果”重新发回给模型模型根据观察结果继续规划直到任务完成或者它明确给出结论。这个循环是 agent-shell 的核心。它和普通聊天最大的区别在于模型可以多次调用工具每次调用后都能看到真实的执行结果再决定下一步怎么做。比如让它“合并重复函数”它可能会先grep找出重复片段再打开文件确认上下文然后生成 diff最后跑一遍 pytest。每一步都有一个事实反馈而不是让 AI 凭空让想象力发挥。我在第一次看到这个循环跑通的时候最直观的感受就是这不光是补全这真的是一个“外包程序员坐在你终端里干活”。2.2 工具权限与上下文怎么设计工具调用能干活但也存在巨大的滥用风险。agent-shell 在权限设计上给了两组关键配置agent-shell-tool-enable-list和agent-shell-tool-confirm-list。第一组控制哪些工具启用第二组控制哪些工具在执行前需要人工确认。默认情况下我会禁用所有写文件和执行命令的自动确认而是把它们放进确认列表。因为大部分任务我都不想每一步都按确认但删除文件和跑危险命令时必须让我点头。上下文管理也很重要。模型能处理的信息有限不可能把整个项目塞进去。我的做法是让 agent-shell 读取项目根目录下的AGENTS.md这个文件只描述项目结构、约定动作和常用命令不给大段代码每次请求前增加最近修改过的文件列表让模型有个大致方向如果涉及的核心代码量太大直接让模型先自己 grep 或者读取指定文件而不是把所有内容放进 prompt。这样既控制了 token 成本又能让模型掌握足够的信息来干活。有一次我让它排查一个测试失败它连续调用了多次run_shell去跑 pytest、读 conftest、读 mock 数据最终定位在一个环境变量没设置的问题上。如果一开始就把几十个文件全塞进去不仅 token 爆掉也不一定能找到线索。3. 搭建 AI 工作台安装、配置、第一个 agent3.1 安装和初始化我用的配置环境是 Doom Emacs不过 agent-shell 本身不依赖 Doom纯 vanilla Emacs 也能跑。只需要保证你的 Emacs 版本在 28 以上并且有plz或request这类的 HTTP 客户端就够了。安装步骤很简单git clone https://github.com/yourname/agent-shell ~/.emacs.d/site-lisp/agent-shell/然后在配置里加载它(use-package agent-shell :load-path ~/.emacs.d/site-lisp/agent-shell/ :commands (agent-shell-open agent-shell-create-agent) :config (setq agent-shell-api-key (getenv OPENAI_API_KEY)))这里有个教训不要把 API key 硬编码进配置。我一开始图省事直接写在 init.el 里后来一不留神把配置分享到了公开仓库虽然几分钟内就撤销了但那段时间足够别人把你的 key 拿走。现在我都用getenv从环境变量里读或者干脆让 agent-shell 从~/.authinfo里读取。初始化的时候它会让你选模型后端。支持 OpenAI、Anthropic以及任何兼容 OpenAI SDK 的自建模型服务。我平时主力用 Claude 的 long context 模型处理大项目时优势明显但日常琐碎任务用 GPT 系列更省 token。你也可以在同一会话里配置多个 backend按任务类型切换。3.2 创建属于你的第一个 agentagent-shell 的核心抽象是 agent一个 agent 就是一套“角色 模型 工具权限 系统提示词”的组合。比如我给自己建了一个“代码审查员”(agent-shell-create-agent :name reviewer :model gpt-4o :system-prompt 你是一名高级代码审查员。审查代码时先输出总体意见再按严重程度列出问题。 对每个问题必须给出文件路径和行号并提供修改建议。不要直接修改文件除非用户明确要求。 :tools (:read :grep :run-shell) :confirm-tools (:run-shell))这里的关键是工具权限裁剪。审查员只需要读代码和搜索不需要写文件权限。给它run-shell是为了跑测试但必须确认。这样即使模型被 prompt injection 攻击也无法直接删文件。另一个我常驻的 agent 是“项目保姆”主要负责回答“这个项目的 xxx 在哪”“这个模块是怎么组织的”这类问题。它只给:read和:grep权限不吃命令执行权限响应速度快、风险低。建议刚开始时不要把所有工具都开给一个 agent。先用最小权限跑通流程再慢慢放开。很多人在这一步因为工具太丰富导致模型频繁误操作最后把配置改到坏第一印象就很差。3.3 上下文管理的几个偷懒技巧我后来发现决定 agent-shell 是否好用的关键往往不是模型而是你怎么管理上下文。第一个技巧是给项目写一份简洁的AGENTS.md。这份文件不长核心就是告诉 AI 这个项目的命令入口、目录约定、不要碰哪些目录、用什么测试框架。agent-shell 的 startup 流程会优先读取它大大提升初始回答质量。第二个技巧是善用 Emacs 自身的 buffer。如果你正在读某个文件可以把它加入当前 session 的上下文让 agent 优先参考。agent-shell 提供了一个agent-shell-add-buffer-to-context函数把当前 buffer 的内容作为参考快照发过去。注意这个操作很耗 token我只在需要它理解当前修改点时使用。第三个技巧是不要把整个目录结构都塞给它。agent-shell 默认只展示项目根目录下两级结构和对gitignore的过滤这个设计非常聪明。你不需要让模型知道node_modules里有哪些文件只需要让它知道项目根层有哪些入口。4. 自我进化的核心让 agent 改自己的工作台4.1 为什么必须让配置可回溯“AI 工作台的自我进化”这个词听起来有点玄但实际上是指让 agent 能修改它自己的运行配置、优化提示词、新增工作流然后让这套系统在使用中变得越来越顺手。但要实现这一点首先要保证配置可回溯。因为 agent 一旦获得写配置文件的权限就必然会产生错误。你必须给配置目录建 git 仓库每次改动都自动 commit这样出问题随时能回滚。我自己是把~/.emacs.d/agent-config单独做成一个 git 仓库并在 agent-shell 的系统提示里要求任何配置修改完成后都要运行agent-shell-validate-config做语法检查并展示 git diff 让用户确认。这样 agent 可以大胆尝试但我始终保留“一票否决权”。4.2 用 agent-journal 记录决策历史自我进化不能是随机改动。我给 agent-shell 加了一个轻量记忆机制每次重要操作后都会把“问题背景、做了什么、结果如何、经验教训”追加到一个agent-journal.el文件里。这个文件本身也是 Emacs Lisp 代码每次加载时会注册一组defvar用来保存历史经验。例如它会记录这样的条目;; 2025-06-12: 重构 utils.py 时发现项目使用 pytest-mock 而非 unittest.mock ;; 结论后续所有 mock 操作优先使用 pytest-mock fixture (defvar agent-experience--pytest-mock-preference (prefer pytest-mock fixtures over unittest.mock.patch) 关于 mock 工具的偏好记录。)后续创建新 agent 的时候可以从这个 journal 里自动抽取相关经验加入系统提示词。这使得整个工作台有一种“成长感”它越用越懂你的项目约定而不是每次都从零开始。4.3 一个能落地的自动化改进闭环我目前稳定运行的自我进化闭环分四步第一步每次任务结束agent-shell 会在后台生成一份简短执行报告包含调用的工具、修改的文件、最终状态。第二步如果任务成功报告会被收入agent-journal.el如果失败则单独写入agent-errors.el并附上当时的报错输出。第三步每周我会跑一个脚本让 agent 自己读取这些日志找出重复出现的失败模式然后提出配置改进建议。第四步我审阅建议后让 agent 执行具体修改并自动跑测试。举个例子前几周我发现每次让 agent 运行某个项目的测试时它老是漏传PYTHONPATH。重复几周后agent 在自己的 journal 里找到了这个模式主动在我的项目AGENTS.md里加了一行“运行测试前请确认 PYTHONPATH 包含项目根目录”。改了以后这个问题再也没出现过。这才是“自我进化”真正的意义不是 AI 变得更强了而是这套工作台对它所在的环境形成了经验积累。它的能力边界不再取决于模型版本而取决于你有没有给它留出“记住教训”的出口。5. 三个亲测好用的实战模式5.1 代码重构让 agent 先分析再动手用 agent-shell 做重构我总结了一套固定流程。第一步先只给 agent 读权限让它输出重构方案。比如“把utils.py中三个重复的日期格式化函数合并成一个format_date函数保留原函数作为兼容层”。这一步让它先给方案、列出影响范围。第二步我确认方案后再给它写文件权限要求它生成 diff 而不是直接覆盖。第三步应用 diff 后立即让它运行测试。这里有个很关键的命令M-x agent-shell-apply-changes这个命令会读取模型建议的补丁通过diff-mode展示改动这样我在应用前能看到每一行内容。注意 agent-shell 不会直接写文件而是通过 diff 的方式应用这让我在代码重构时非常安心。5.2 编译错误自动诊断另一个每天都在用的场景是自动诊断编译错误。我在 Emacs 里绑定了一个快捷键当compile窗口报错时直接调用 agent-shell 发送报错上下文让 agent 分析原因。它做的事通常包括读取*compilation*buffer提取错误行号和消息跳转到出错文件读取周围代码运行相关命令获取更多上下文比如python -m pytest或tsc --noEmit返回一个诊断报告包含根因和修复建议。最牛的一次是它发现错误真正原因不在报错那一行而在另一个文件里的类型导出。它连续看了四个文件才找到源头且给出了最小改动方案。这种深度分析能力在普通聊天工具中很难实现因为聊天工具拿不到你的真实编译环境和项目文件。5.3 多 agent 协作流水线agent-shell 还支持在一个会话里交多个 agent 协作。我设计了一个简单的“程序员 审查员”流水线程序员 agent 负责写实现代码写完以后自动把 diff 发到另一个会话让审查员 agent 审查审查意见返回后程序员 agent 根据意见修改再次提交。这个流程可以通过以下方式起一个并行会话(agent-shell-send-to-agent reviewer 请审查刚才的 diff重点看边界条件处理)多 agent 协作时要注意上下文隔离。每个 agent 有自己的历史会话不要在它们之间混用状态。我一般让程序员只关注实现审查员只关注质量和安全这样各自的 prompt 更聚焦模型也不会因为目标冲突而输出低质内容。6. 问题排查与安全边界6.1 高频问题速查我整理了一个高频问题速查表都是这几周自己踩坑得来的。问题现象可能原因解决方式模型回复速度很慢上下文太长模型处理耗时清理会话历史使用 AGENTS.md 代替全量代码输出被系统截断max-tokens设置过小调高到 8000 或 12000或拆分成子任务agent 执行命令后无反应工具调用超时或权限拦截检查agent-shell-tool-confirm-list是否弹出了确认框修改代码后格式混乱agent 没有遵守项目格式约定在系统 prompt 中加入格式要求或配置保存后自动运行 prettierAPI 提示余额不足token 消耗超预算设置agent-shell-max-tokens-per-session限制单会话 token 量agent 修改了配置但没生效没有重新加载配置要求 agent 修改后执行agent-shell-reload-config最容易被忽略的是“确认框没被看到”。当你把run-shell放入确认列表后如果 Emacs 不在前台确认框不会弹出agent 就一直等待。我后来设置了一个延时自动拒绝机制20 秒没确认就自动取消避免任务卡死。6.2 一定要设置的资源红线使用 agent-shell 这类自主执行工具安全边界比功能更重要。我给自己定了几条铁律。第一敏感数据默认不进 prompt。如果在代码中发现 API key、密码、真实姓名agent-shell 会在发送前自动脱敏。第二写文件权限默认开启 diff 应用模式不让模型直接用整文件覆盖。第三危险命令默认确认例如rm -rf、git push --force、docker rm这类操作我都加在白名单之外。第四成本控制上设置每日 token 上限超过后 agent-shell 会自动暂停非确认任务。你要知道agent 只是模型不是可信的运维系统。它可能被 prompt injection 攻击某个文件里的注释可能试图诱导 agent 执行危险命令。所以工具权限的最小化不是胆小而是基本素养。6.3 我的工作流建议从这几周的实践里我慢慢形成了自己的使用节奏把 agent-shell 当作“可交互的同事”不是“自动运行的脚本”。需要复杂操作时我会全程盯着输出长任务建议分阶段跑每次只让它做一步确认后再下一步所有配置和 agent 定义都放进 git让进化有迹可循每周留一点时间让 agent 自主分析自己的执行记录提出改进建议这就是前面说的自我进化闭环。说实话真正让我觉得“这套东西值了”的瞬间不是它替我写出了一个多优雅的算法而是它把我从“复制报错到聊天框、再粘贴回编辑器”这种机械劳动里解放了出来。回到开头说的“自我进化”我的体会是不要指望 agent 一夜之间变成超级人工智能更重要的是给这套工作台留出反馈回路。即使是一个最简单的 journal 文件只要它能被 agent 回头读取并影响下一次决策进化就已经发生了。下一步我打算把这套 agent 配置整理成一个可直接复用的发行版让更多人不用从零开始搭环境就能在 Emacs 里拥有一个懂项目、能干活、会成长的 AI 工作台。