
在大多数人的工作流里AI 客户端是一个独立窗口打开网站、复制粘贴、拿回结果、再切回编辑器。而在 Emacs 生态里gptel 提供的是另一种思路——它不只是一个聊天框更像是一条把 AI 能力接入你日常编辑、写作、Org-mode、代码管理流程的“管道”。这篇文章会从 gptel 是什么讲起逐步拆解安装、Provider 配置、基础聊天、Org-mode 集成、编程辅助、请求封装再到高频报错排查和工程化实践建议。不管你是刚接触 Emacs 的新手还是已经用了一年多、想把 AI 客户端真正嵌入工作流的开发者都可以按文章顺序跟下来。1. 背景与核心概念gptel 到底是什么1.1 从“聊天窗口”到“编辑器原生集成”先看一个最简单的场景你在写代码遇到一个函数报错需要问 AI。常规做法是打开浏览器粘贴错误信息等回复再回到编辑器修改。这个流程的问题在于上下文不连续——AI 没看到你的代码上下文你也很难把多轮对话结果直接转化成编辑动作。gptel 的出现本质上是把“AI 客户端”从独立应用变成了 Emacs 的一个扩展层。它在 Emacs 进程内调用大语言模型 API并将对话内容展示在普通缓冲区中。这意味着你可以像处理普通文本一样处理 AI 回复复制、编辑、搜索、保存甚至把回复直接作为 Org-mode 文档的一部分。更关键的是gptel 不止于“对话界面”。它对外提供了可供 Elisp 调用的请求接口也就是我们常说的“把 AI 当后端能力来用”。你可以写一小段 Elisp 调用 gptel 生成提交信息、总结代码差异、翻译注释然后在结果返回后自动插入到对应位置。1.2 gptel 能解决什么问题减少窗口切换AI 回复直接出现在 Emacs 内不需要跳浏览器。上下文连续聊天缓冲区保留完整历史事务可以在同一个缓冲区里持续跟进。可编程通过gptel-request等接口可以把 AI 能力接入任意 Elisp 函数。Provider 抽象支持 OpenAI 兼容接口、Anthropic、Ollama、Google Gemini 等切换模型时不用换工具。数据可控会话记录是纯文本缓冲区可以保存为 Org 文件方便后续检索和审计。1.3 和常见 AI 客户端的区别对比项浏览器版 ChatGPT / Claudegptel交互位置浏览器标签页Emacs 缓冲区上下文接入手动复制粘贴可读取当前文件、选中区域、Org 标题可编程性有限完全可用 Elisp 控制输出处理只能人工复制可编辑、再处理、插入文档多 Provider厂商绑定通过配置灵活切换所以“Beyond Just a Chat Interface”这个定位其实是讲 gptel 的核心价值它让 AI 成为 Emacs 工作流的一个普通函数而不是一个需要你来回切换的外挂工具。2. 环境准备与安装2.1 环境要求先说明一下gptel 的安装和使用并不复杂但需要满足几个基础条件操作系统Windows、macOS、Linux 均可但如果你在 Windows 上使用建议优先用 WSL 或 Git Bash 环境避免路径和网络配置上的额外问题。Emacs 版本一般是 27.1 以上推荐使用 29 或更高版本。如果你还在用 26 以下的老版本建议先升级因为部分 API 和异步处理能力依赖较新特性。网络环境需要能访问你选择的 API Provider 服务。这里不展开具体网络细节按你自己的实际环境配置即可。包管理器推荐使用 MELPA 源配合use-package更方便。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.2 使用 MELPA 安装 gptel如果你的~/.emacs.d/init.el里还没有配置 MELPA先加上下面这段(require package) (add-to-list package-archives (melpa . https://melpa.org/packages/) t) (package-initialize)然后执行M-x package-refresh-contents M-x package-install RET gptel RET如果使用use-package可以直接这样写(use-package gptel :ensure t :defer t)2.3 快速验证是否安装成功安装完成后执行M-x gptel如果一切正常Emacs 会打开一个名为*gptel*的缓冲区底部有输入区域。如果你已经配置过 API Key就可以直接输入问题并回车发送。第一次打开可能会提示你选择 Provider 或模型根据你的 API 服务类型选择即可。到这里一个最基本的 gptel 聊天界面就跑起来了。但别急这只是一个开始我们后面要做的是让它真正融入编辑和写作流程。3. 配置 API Provider对接你的模型服务3.1 理解 gptel 的 Provider 抽象gptel 并不直接绑定某一家厂商而是抽象出一套统一的请求方式。它支持OpenAI 官方接口及兼容接口Anthropic ClaudeGoogle GeminiOllama 本地模型其他兼容 OpenAI 协议的私有网关这意味着你可以配置多个 Provider然后在同一个*gptel*缓冲区里通过菜单切换。这种抽象对于需要比较不同模型效果、或者本地和云端模型混用的用户来说非常实用。3.2 配置 OpenAI 风格 API通常可以在init.el中通过变量来设置 API Key 和默认模型(setq gptel-api-key (getenv OPENAI_API_KEY)) (setq gptel-default-model gpt-4o) (setq gptel-stream t)这里需要注意gptel-api-key可以是一个字符串也可以是一个返回字符串的函数。推荐使用(getenv OPENAI_API_KEY)避免把密钥直接硬编码在配置里。gptel-default-model具体能填什么模型取决于你的 API 权限和账号类型。写配置时不要盲目用最新版模型名先查一下自己的账号能用哪些模型。gptel-stream表示是否启用流式输出默认开启这样 AI 回复会像打字一样逐字显示体验更好。如果你使用自定义 API 网关例如公司内部部署的 OpenAI 兼容服务可以这样配置(gptel-make-openai MyGateway :host my-gateway.example.com :endpoint /v1/chat/completions :key (getenv MY_GATEWAY_API_KEY) :models (my-model-name))不同版本 gptel 的函数签名可能稍有差异建议以你安装版本的 README 或C-h f gptel-make-openai文档为准。上面这个写法体现了通用配置思路。3.3 配置 Ollama 本地模型如果你更看重数据隐私或者想在无外部网络的环境下使用 AI可以配置 Ollama。前提是你已经在本地安装并启动了 Ollama并提前拉取了对应模型例如ollama pull llama3然后在 Emacs 中声明 Provider(gptel-make-ollama Ollama :host localhost:11434 :stream t :models (llama3 qwen2.5))配置完成后在*gptel*缓冲区中通过 transient 菜单切换 backend 到Ollama即可使用本地模型。这种方式的好处是请求不离开本机安全性更高特别适合处理公司内部代码和文档。3.4 配置多个 Provider 时的切换思路当你同时配置了 OpenAI 和 Ollama 后默认模型可以这么设置(setq gptel-default-provider OpenAI) (setq gptel-default-model gpt-4o)在聊天过程中运行M-x gptel-menu或触发 transient 菜单可以快速切换 Provider、模型、系统提示、温度等参数。这个菜单是 gptel 体验中很关键的部分它让配置不再是写死在 init.el 里的静态内容而是可以在对话过程中动态调整。关于具体按键绑定和菜单项不同版本会有差异建议安装后先看一眼gptel-menu的帮助说明。核心思想是不需要为了换一个模型去修改配置重载 Emacs直接在菜单里点选即可。4. 基础使用先用聊天界面打通链路4.1 第一次对话安装配置完成后执行M-x gptel。在*gptel*缓冲区中输入一句测试请求请用一句话介绍 Emacs 中的 gptel 是什么。回车或点击发送按钮你会看到回复以流式方式逐步输出到缓冲区。整个过程不需要离开 Emacs也不需要在文件之间切换。4.2 上下文控制的常用命令gptel 在聊天缓冲区里定义了若干常用命令比较重要的是发送当前输入通常是回车或通过C-c C-r发送选中的内容。清空当前对话历史运行M-x gptel-rewrite或直接删除缓冲区内容具体命令名以你使用的版本为准。打开 transient 菜单运行M-x gptel-menu可以切换模型、设置系统提示、调整温度。把回复插入当前文件可以在*gptel*缓冲区中复制回复内容回到编辑缓冲区后粘贴。这里要注意gptel 的对话历史保存在当前缓冲区的 overlays 和文本属性中并不是通过独立数据库管理。因此保存整个*gptel*缓冲区就等于保存了一次完整会话。4.3 在任意缓冲区发起请求聊天界面只是 gptel 的入口之一。很多场景下你并不想开一个聊天窗口而是希望在当前文件里选中一段代码直接把这段代码交给 AI 处理。这里有两个常见入口选中区域后执行gptel-request该函数会把选中内容的上下文带入请求。在编程语言缓冲区中可以把当前文件或区域内容发送给 gptel让 AI 进行解释、补全或重构。例如在 Python 文件中选中一段函数然后执行M-x gptel-requestgptel 读取所选区域内容并把请求发送给配置好的模型最终将回应展示在独立缓冲区里。这种方式适合做代码审查、解释复杂逻辑、生成注释等操作不需要人工复制粘贴。4.4 示例解释当前函数假设你在 Python 文件中有这样一段代码def parse_config(path: str) - dict: with open(path, encodingutf-8) as f: raw f.read() config {} for line in raw.splitlines(): if in line: key, value line.split(, 1) config[key.strip()] value.strip() return config你把这段代码选中然后运行gptel-request并在请求中补充一句请解释这段代码的作用并指出潜在问题。AI 会返回类似这样的分析函数读取配置文件按行解析keyvalue格式的数据。潜在问题没有处理注释行没有处理引号简单split(, 1)可能会让 value 里包含号。改进建议使用configparser标准库。这就是 gptel 在日常开发中非常实用的一个形态不打开聊天窗口直接在当前代码上下文里问 AI。5. 超越聊天界面Org-mode 集成与请求封装5.1 在 Org-mode 中让 AI 参与写作gptel 对 Org-mode 的支持是它区别于普通聊天工具的重要亮点。你可以把 AI 对话嵌入到 Org 文档结构中让每个问题、回复、后续行动项都成为可管理、可导出、可复用的内容。通常需要做两步第一步在 Org-mode 中启用 gptel(add-hook org-mode-hook #gptel-org-setup)这个 hook 会在你打开 Org 文件时加载 gptel 在 Org-mode 中需要的相关配置让你可以使用 Org 条目作为对话的上下文载体。第二步在 Org-mode 缓冲区中执行M-x gptelgptel 会识别当前 Org 标题结构把标题下的文本内容作为对话上下文。你可以把 AI 回复直接放在标题下面然后利用 Org 的导出功能把整个对话生成 HTML 或 PDF。举例来说你在写一份《项目季度总结》的 Org 文件某个小节标题是“技术风险分析”标题下方有一段已有的记录。你可以通过 gptel 让 AI 基于这段记录生成更正式的风险描述并把回复插入到当前标题下。整个过程都在同一个 Org 文件中完成不需要复制粘贴到外部对话工具。5.2 使用 gptel-request 封装自定义 AI 函数如果你想让 gptel 不只是交互工具而是成为你个人 Emacs 配置中的“AI 后端”那就要学会使用gptel-request这个核心接口。下面是一个最小示例演示如何调用 gptel 生成一段文本并在回调函数中处理结果(defun my/ask-ai (prompt) 向 gptel 发送 PROMPT并在新缓冲区展示回复。 (gptel-request prompt :system 你是一名资深 Emacs Lisp 开发者回答要简洁准确。 :callback (lambda (response info) (with-current-buffer (get-buffer-create *AI-RESPONSE*) (erase-buffer) (insert response) (display-buffer (current-buffer))))))这个函数做了什么接收一个字符串参数prompt。调用gptel-request发起异步请求。设置系统提示让 AI 的回答风格更贴合需求。请求完成后回调函数把回复写入*AI-RESPONSE*缓冲区。注意上面的参数形式是一般性示例不同版本 gptel 的gptel-request回调参数个数可能略有差异。更稳妥的做法是安装后运行C-h f gptel-request查看当前版本的文档。核心思路是你可以把 AI 请求包进自己的 Elisp 函数再绑定到快捷键或 hooks 里。5.3 将 AI 接入 git commit 消息生成这是一个很实用的工程场景。你改完代码之后经常想写一条清晰的 commit message但往往要么太简单要么太啰嗦。可以写一个函数让 gptel 帮你根据 git diff 生成建议(defun my/generate-commit-message () 根据当前 git diff 生成 commit message 建议。 (interactive) (let ((diff (shell-command-to-string git diff --cached))) (gptel-request (format 请根据以下 git diff 生成简洁的 commit message\n\n%s diff) :callback (lambda (response info) (message 建议 commit message\n%s response)))))这里需要注意执行该函数前需要先把改动git add到暂存区。否则git diff --cached可能没有内容AI 也就无法基于差异生成信息。5.4 让 AI 处理当前缓冲区的注释除了生成 commit message你还可以写一个“为当前文件所有函数添加注释”的辅助函数。先获取当前 buffer 内容发送给 gptel要求它返回带注释的版本然后替换当前区域。这比逐一复制函数更高效也体现了 gptel 的“可编程 AI 客户端”特性。不过在生产项目中使用这种自动改写功能时要谨慎AI 生成的注释可能不准确替换代码前应手动审查或者在独立缓冲区先查看修改后的内容再决定是否应用。6. 实战案例在 Emacs 中使用 gptel 完成 AI 辅助代码重构6.1 案例目标假设你在写一个 Python 项目其中有一个函数对列表进行多次遍历性能不高可读性也一般。我们要用 gptel 辅助完成一次局部的代码重构并将重构结果用于人工审查。原代码如下def get_valid_users(users): result [] for user in users: if user.get(active) is True: if user.get(email): result.append(user[email]) return result6.2 步骤一在 Python 缓冲区中选中代码在 Emacs 中打开 Python 文件使用set-mark-command或鼠标选中上面这段函数。目标是把这段代码直接作为上下文发送给 gptel。6.3 步骤二使用 gptel-request 发送重构请求选中代码后在你的配置中加入一个自定义函数并执行它(defun my/refactor-region () 让 gptel 对选中区域进行重构建议。 (interactive) (let ((region-text (buffer-substring-no-properties (region-beginning) (region-end)))) (gptel-request (format 请重构以下 Python 代码保持行为不变但提升可读性和性能\n\n%s region-text) :system 你是一名 Python 代码评审专家。 :callback (lambda (response info) (with-current-buffer (get-buffer-create *REFACTOR-SUGGESTION*) (erase-buffer) (insert response) (display-buffer (current-buffer)))))))这里也可以直接用M-x gptel-request在选中区域上发起请求然后在弹出的缓冲区里输入指令。区别在于自定义函数可以统一设置 system prompt让 AI 始终保持“代码评审专家”的角色。6.4 步骤三查看重构建议请求完成后*REFACTOR-SUGGESTION*缓冲区中会显示 AI 的建议。例如def get_valid_users(users): return [ user[email] for user in users if user.get(active) is True and user.get(email) ]AI 可能会解释使用列表推导式让过滤和提取合并成一行提升可读性对超长列表来说也减少了不必要的遍历层级。6.5 步骤四人工审查并应用这里有个很重要的工程原则AI 的重构建议未必完全符合项目规范也未必保持了完全一致的行为。例如user.get(email)返回空字符串时原代码会把空字符串加入列表而重构后的列表推导式也会加入空字符串行为一致但如果改成if user.get(email) is not None行为就发生了变化。所以拿到建议后一定要先审查再复制回源代码文件。这个案例展示了 gptel 在代码辅助中的工作流价值它不是自动改代码的魔术工具而是把 AI 建议拉进编辑器、让人工决策变得更高效的辅助层。7. 常见问题与排查思路在实际使用中gptel 最常见的报错通常集中在 API Key、模型名、网络连接和配置加载这几个方面。下面整理一张排查表并给出几个典型问题的解决思路。问题现象常见原因解决思路请求返回 401 UnauthorizedAPI Key 错误或环境变量未加载检查gptel-api-key或环境变量是否生效请求返回 404 Not Found模型名不存在或 endpoint 配置错误在 Provider 管理界面确认模型名请求返回 402 Payment RequiredAPI 账户余额不足或欠费登录服务商后台检查额度请求超时网络不稳定或模型响应慢先测试网络连通性再尝试调大请求超时时间流式输出不生效Provider 不支持 SSE 或配置关闭了流在 transient 菜单里确认 stream 开关中文回复乱码Emacs 编码设置问题检查 locale 和utf-8编码配置gptel 命令不存在包未正确加载执行package-install后重启 Emacs或检查use-package配置transient 菜单打不开gptel 版本过旧更新 gptel 到最新版7.1 请求报错 401 Unauthorized这个问题的根本原因通常是 API Key 没有正确配置。如果你在 init.el 中写了(setq gptel-api-key sk-xxx)但请求仍然返回 401可以先在*scratch*缓冲区中执行(print gptel-api-key)确认变量值是否真的生效。如果使用环境变量方式(setq gptel-api-key (getenv OPENAI_API_KEY))还需要确认 Emacs 进程启动时环境变量已经加载。有些桌面环境下 Emacs 不会继承 shell 里的环境变量这时可以在 Emacs 配置里显式读取文件或使用exec-path-from-shell这类工具。7.2 请求返回模型名错误OpenAI 接口对模型名非常敏感即使同一个服务商不同时期可用的模型名也可能不同。遇到 404 或模型不存在提示时不要在配置里继续猜直接去服务商后台查看当前可用模型列表。对于本地 Ollama可以用命令查看ollama list然后再把准确的模型名填入 gptel 配置。7.3 请求超时或连接失败如果你使用本地 Ollama执行curl http://localhost:11434可以确认服务是否正常。如果使用远程 API最简单的排查方式是使用curl模拟一次请求看能否拿到响应。日志方面可以在配置中开启 debug 输出或者使用M-x gptel-*debug*一类命令查看 gptel 内部日志。不同版本的调试命令名不同建议查看当前版本 README。核心思路是先确认网络链路通不通再排查 gptel 参数配置是否正确。7.4 避免问题再次出现的习惯不要把 API Key 直接写在 init.el 里优先用环境变量或私有配置文件。更新 gptel 前先备份配置避免新版本修改函数签名或菜单结构。每次更换模型前先在服务商后台确认模型名和权限。在 Org 文件中保存重要会话避免缓冲区关闭后丢失上下文。8. 最佳实践与工程建议8.1 密钥管理与安全边界API Key 是使用 gptel 时最需要重视的安全项。不要把密钥提交到 Git 仓库建议在项目根目录增加.gitignore忽略.env文件.env然后在 Emacs 配置中通过环境变量读取(setq gptel-api-key (getenv OPENAI_API_KEY))如果使用自定义配置文件可以单独放在~/.emacs.d/private.el并确保该文件不会被纳入版本控制。此外涉及企业内部敏感数据时优先选择本地模型如 Ollama或供应商内部部署的私有网关不要直接把内部代码发送到外部 API。8.2 合理控制 token 消耗gptel 默认会将整个缓冲区作为上下文发送给模型。如果缓冲区过大token 消耗会很高响应速度也会变慢。建议在使用时注意上下文长度必要时手动清理或仅发送选中区域。这不是 gptel 的缺陷而是大模型 API 计费模式决定的。如果你经常使用长文档问答可以考虑配置一个更精确的请求函数只发送当前段落或当前标题下的内容而不是整个文件。这样能显著节约成本也能提高响应速度。8.3 使用 transient 菜单维护统一配置gptel 的 transient 菜单是维护多 Provider、多模型配置的最佳入口。建议每次切换模型时不要直接在 init.el 里改代码而是通过菜单临时覆盖只有在确认某个配置经常使用后才把它写入默认配置。这种“临时覆盖 常态化沉淀”的方式可以减少反复重载配置文件的次数也能避免你为了一个实验性模型频繁改动全局配置。8.4 将常用 AI 操作封装成个人函数根据你的工作习惯可以把常见操作封装成函数绑定到快捷键上。下面是一个示例思路(defun my/ai-explain-region () 解释选中区域的代码。 (interactive) (let ((region-text (buffer-substring-no-properties (region-beginning) (region-end)))) (gptel-request (format 请解释这段代码\n\n%s region-text) :callback (lambda (response info) (with-current-buffer (get-buffer-create *AI-EXPLAIN*) (erase-buffer) (insert response) (display-buffer (current-buffer)))))))这类函数的好处是你把“怎么调用 AI”的细节封装在了一层自己的接口后面。之后如果想换 Provider、改 system prompt、调整输出缓冲区名称只需要修改一个函数不用在每个操作里重复配置。8.5 日志与审计如果 gptel 用在你比较重要的工作流中比如自动生成 commit message 或文档建议为每次请求保存一份日志。最简单的做法是把 AI 回复插入一个专门的 Org 文件然后定期回顾。这样既能追踪 AI 输出质量也能在问题出现时回溯当时的请求内容和系统提示。9. 总结与学习路线这篇教程从 gptel 的定位讲起带你完成了环境安装、Provider 配置、基础聊天、Org-mode 集成、请求封装和代码重构实战。核心收获可以概括为三点gptel 不是简单的聊天窗口而是 Emacs 中的一个可编程 AI 客户端层。通过gptel-request你可以把 AI 能力嵌入几乎任何 Emacs 工作流。使用多 Provider 配置和 transient 菜单可以在不同模型之间灵活切换不必被单一厂商绑定。下一步建议你继续关注阅读 gptel 自带文档重点看gptel-request、gptel-menu、gptel-system-prompt的说明。尝试配置两个 Provider一个云端、一个本地对比对话效果和响应速度。从“选中区域找 AI 解释”这个最简单的工作流出发慢慢扩展出你自己的 AI 辅助函数库。关注 gptel 仓库更新日志了解 transient 菜单和新 Provider 支持的变化。如果你在配置过程中发现某些函数名、菜单项和我这里的示例不一致不用太紧张。gptel 这类插件迭代较快不同版本的 API 细节可能有调整以你安装版本的文档为准即可。关键不是记住每一条配置而是理解 gptel 的架构思路——把 AI 真正变成 Emacs 工作流的一部分。