各位 Emacs 用户,大家好。最近在折腾 AI 编程工作流时,我越来越觉得把大模型直接塞进编辑器里才是效率最高的做法,而 Gptel 就是这样一个让我“用过就回不去”的 Emacs 包。很多人第一次听说 Gptel,会以为它只是一个聊天窗口,其实它的价值远远超过了“ChatGPT 客户端”。这篇文章将以标题 “Gptel Emacs AI Client: Beyond Just a Chat Interface” 为主线,从概念、安装、配置到实战,完整拆解 Gptel 的能力边界,帮助你把它真正融入到日常编辑、代码补全、重构、组织笔记等工作流中。
文章主要面向两类读者:一是已经熟悉 Emacs 基础操作,想在编辑器内接入大模型的开发者;二是对 AI 编程工具感兴趣,想了解 Emacs 生态中如何落地 LLM 集成的朋友。读完后,你将能独立安装 Gptel,配置多个 AI 后端,掌握上下文发送、区域改写、会话管理、多模型切换等核心用法,同时也会了解常见报错的排查思路和工程化配置建议。
1. Gptel 是什么:为什么说它不只是聊天界面
1.1 从聊天客户端到编程助手
Gptel 是 Emacs 里的一款大语言模型客户端,它基于异步请求实现,核心目标是让你在不离开 Emacs 的情况下与各类 LLM 服务交互。一个最直观的用法是M-x gptel打开一个类似聊天软件的 buffer,输入问题后按C-c C-c发送,AI 的回复会以流式的方式逐字显示出来。
但如果你只把它当作“聊天框”,那就浪费了它最强大的能力。Gptel 的设计思路更接近“上下文驱动的编辑器插件”:你可以把当前缓冲区、选中的 region、组织模式的块、甚至是函数定义直接发送给模型,模型基于这些内容生成回答。这意味着你不需要再复制粘贴代码到网页里,也不需要人工整理上下文,Gptel 会保留当前编辑环境的元信息,比如major-mode、行号、文件路径等。
1.2 它解决的痛点
很多开发者使用 ChatGPT 或同类网页工具时,最大的痛点不是模型回答不好,而是上下文搬运成本太高。写代码时,你要把函数、错误信息、需求描述粘贴到网页,再等回答,再贴回 Emacs。如果回答超过最大长度,还要分段复制。Gptel 把整个流程压缩到了几个快捷键内,而且它天然适应 Emacs 的 buffer 文化:每个对话都是一个 buffer,可以用熟悉的键位操作、保存、检索。
另一个痛点是多后端管理。Gptel 抽象了不同 API 的差异,支持 OpenAI、Azure OpenAI、Anthropic Claude、Google Gemini,以及兼容 OpenAI 接口的本地服务(如 llama.cpp、Ollama)。你可以为不同场景绑定不同的后端和模型,比如日常问答用快速模型,代码重构用能力更强的模型,从而在成本和效果之间找到平衡。
1.3 核心特性一览
- 异步流式响应:不会阻塞 Emacs。
- 基于 transient 菜单的交互控制:模型、温度、token 上限等参数可以随时调整。
- 上下文集成:发送 buffer、region、函数、组织模式条目。
- 多个会话管理:支持并行多个对话,命名后随时切换。
- 可扩展的响应处理:支持把生成内容插入当前 buffer,或替换选中区域。
- 多种补全工具配合:可以结合
completion-at-point和嵌入式补全框架,实现类似 Copilot 的效果。
看起来功能很多,但 Gptel 的配置并不复杂,接下来我们先把环境准备好。
2. 环境准备与版本说明
2.1 基础环境要求
Gptel 是一个纯 Elisp 扩展包,运行在 GNU Emacs 中。根据项目文档,它要求 Emacs 27.1 或更高版本,但为了获得更稳定的体验,推荐使用 Emacs 29 或当前较新的版本。操作系统方面,Windows、macOS、Linux 均支持,不过 Windows 用户需要注意网络代理和证书配置,这一部分我们会在常见问题中单独说明。
在写这篇文章时,Gptel 的最新版本迭代很快,具体 API 参数和配置项可能会微调。因此,本文不会死守某个具体版本的配置文件,而是演示一种常见的、稳定的配置思路。你在实际操作时,建议先查看本地包的README或者通过C-h f gptel RET查看函数文档,再根据实际情况微调。
2.2 安装包管理器选择
你可以使用 Emacs 自带的能力安装,也可以借助第三方包管理工具。我个人比较推荐用use-package统一管理配置,这样可读性和可迁移性都更好。下面是一个最小化的安装配置。
;; 文件路径:~/.emacs.d/init.el 或 ~/.config/emacs/init.el (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (use-package gptel :ensure t)如果你使用的是straight.el,同样可以通过以下配置安装:
(use-package gptel :straight (gptel :type git :host github :repo "karthink/gptel"))这里需要注意,直接使用:ensure t时,Emacs 会从 MELPA 拉取包。国内网络环境如果下载慢,可以配置package-archives为清华或中科大镜像,也可以使用straight.el配合代理下载。
2.3 获得 API 访问凭证
Gptel 本身不提供模型能力,它需要你提供一个可访问的 LLM API 服务。常见的选择有:
- OpenAI API(需要使用其 API key)。
- Azure OpenAI 服务(适用于企业环境)。
- Anthropic Claude API。
- Google Gemini API。
- 本地或内网部署的兼容 OpenAI 协议的模型服务,例如 Ollama、llama.cpp server 等。
在配置前,请确保你已经具备可用的 API 凭证。出于安全和合规考虑,不要把 API key 直接写在 Emacs 配置里,推荐使用 Emacs 的auth-source机制管理。下面是一个示例配置,它会从~/.authinfo读取凭据。
3. Gptel 安装与基础配置
3.1 使用 use-package 完成最小配置
我们先从一个能跑通的最简配置开始。假设你使用的是 OpenAI 兼容接口,并且已经为当前 shell 导出了环境变量OPENAI_API_KEY,那么以下配置就能让 Gptel 工作起来。
(use-package gptel :ensure t :config (setq gptel-default-mode #'org-mode) (setq gptel-prompt-prefix-alist '((org-mode . "** User") (markdown-mode . "**User**") (text-mode . ">>>"))) (setq gptel-org-state-heading 'org-state))这段配置做了什么?
gptel-default-mode指定 Gptel 会话 buffer 使用org-mode作为默认模式。如果你更喜欢纯文本或 Markdown,可以改为markdown-mode或text-mode。gptel-prompt-prefix-alist的作用是定义不同主模式下用户输入的标记前缀,方便解析对话内容。gptel-org-state-heading控制 org 状态下回复的标题格式。
3.2 用 auth-source 管理 API Key
不推荐在配置里写死gptel-api-key。更好的做法是让 Gptel 通过 Emacs 的认证源去查询。你可以在~/.authinfo文件中写入类似下面的内容:
machine api.openai.com login apikey password sk-xxxxxxx然后在配置中指定:
(setq gptel-api-key (lambda () (auth-source-pick-first-password :host "api.openai.com")))注意,auth-source文件默认权限应该比较严格,避免其他用户读取。在 Linux 下可以使用:
chmod 600 ~/.authinfoGptel 也支持直接从环境变量读取 key。如果你不希望额外维护文件,可以简单设置:
(setq gptel-api-key (getenv "OPENAI_API_KEY"))但这种方式在 Emacs 会话启动后不会再自动刷新,适合个人开发环境。
3.3 打开第一个会话
配置完成后,重新加载 Emacs,执行M-x gptel。如果一切正常,你会看到一个新的 buffer,底部有一个输入区域,上方是对话内容。在输入区域输入“你好,请介绍一下你自己”,然后按C-c C-c,系统会异步调用模型,并将回复逐字显示出来。
如果遇到空响应或错误提示,先检查:
gptel-api-key是否设置成功。gptel-backend是否指向了正确的服务地址。- 网络是否能正常访问 API 端点。
4. 核心用法:把编辑器上下文变成 AI 的“输入”
4.1 发送整个缓冲区或选中区域
Gptel 区别于普通聊天框的核心体验,是你能把当前编辑中的代码或文档直接作为上下文发送给模型。准备一个测试文件,比如一个 Python 脚本。
# 文件路径:/tmp/test.py def add(a, b): return a + b def multiply(a, b): return a * b打开这个文件,进入python-mode,然后执行M-x gptel-send-buffer。Gptel 会创建一个会话,并把当前 buffer 的全部内容发送给模型,随后你可以继续输入“请解释这段代码”或“请帮我添加类型注解”。此时模型已经看到了文件内容,回答会更加贴合实际代码。
如果你想只发送部分代码,可以先选中 region,执行M-x gptel-send-region。这个命令会把选中的文本作为上下文发送,并且保留上下文中的主模式信息,便于模型识别语言。
4.2 发送函数、定义或 Org 条目
除了 buffer 和 region,Gptel 还提供了一些感知结构性上下文的命令。例如在 Emacs Lisp 中,可以发送当前 defun;在 Org-mode 中,可以发送当前 heading 下的子树。常见的命令如下:
gptel-send-defun:发送当前光标所在的函数定义。gptel-send-org-element:发送 Org 元素。gptel-send-file:发送指定文件内容。gptel-send-region-to-gptel:经典区域发送。
这样,你就不需要手动裁剪代码块,模型可以获取较精确的局部上下文,进而生成更准确的回答。
4.3 设置系统提示词与角色
在 Gptel 会话中,你可以调用M-x gptel-set-system-prompt来设置系统提示词。系统提示词决定了模型的行为方式,例如“你是一个资深 Python 工程师,回答尽量简洁,并给出代码示例”。每个会话可以有不同的系统提示词,非常灵活。
此外,Gptel 也支持在配置中预设多个系统提示词,并通过 transient 菜单快速切换。你可以在gptel-prompt-alist中定义常用提示模板。
(setq gptel-prompt-alist '(("default" . "You are a helpful assistant.") ("code-review" . "You are a senior software engineer. Review the code for bugs and style issues.") ("explain" . "Explain the given code or text in simple terms.")))4.4 异步流式输出与取消
Gptel 使用异步请求,响应期间 Emacs 仍然可以继续编辑其他 buffer。如果模型输出过长,你可以按C-c C-c发送请求后,在等待过程中做别的事;如果想中断生成,可以执行M-x gptel-abort或点击中断键。这个体验和网页端的“停止生成”按钮类似。
需要留意的是,在 Gptel 会话内部调用gptel-abort,只取消当前请求,之前的对话记录依然保留。如果你发现 Emacs 卡顿,通常不是 Gptel 的问题,而是网络请求同步化或别的外部插件引起的。
5. 实战案例:用 Gptel 完成代码生成与重构
5.1 场景设定
假设我们正在开发一个简单的 Python 工具,用于处理 CSV 文件合并。传统做法是手动编写所有代码,但现在我们想用 Gptel 辅助完成。我们准备先在空文件里实现一个函数:读取多个 CSV 文件,按列合并。要求使用 pandas,但代码中没有安装 pandas 时,希望代码有友好的提示。
我们会利用 Gptel 的上下文能力,分三步完成:
- 在 Python buffer 中写一个函数签名和注释。
- 使用
gptel-send-region把这段“待实现”的骨架发给模型。 - 让模型返回完整实现,然后手动或自动插入代码。
5.2 编写骨架并发送上下文
在 Emacs 中新建/tmp/merge_csv.py,输入以下内容:
import pandas as pd def merge_csv_files(file_paths: list[str], output_path: str) -> None: """合并多个 CSV 文件,按第一列对齐。 参数: file_paths: CSV 文件路径列表。 output_path: 合并后输出文件路径。 """ # TODO: 在这里实现合并逻辑 pass选中整个函数,执行M-x gptel-send-region。在生成的 Gptel buffer 中发送指令:“请实现这个函数,要求支持不同 CSV 的不同列,并保留缺失值。给出完整代码。”
5.3 模型返回与代码插入
模型可能会返回类似下面的代码:
import pandas as pd def merge_csv_files(file_paths: list[str], output_path: str) -> None: """合并多个 CSV 文件,按第一列对齐。""" if not file_paths: raise ValueError("file_paths cannot be empty") dataframes = [] for path in file_paths: try: df = pd.read_csv(path) except FileNotFoundError: print(f"Warning: {path} not found, skipping.") continue dataframes.append(df) if not dataframes: raise ValueError("No valid CSV files to merge.") # 按第一列做 outer merge,保留所有行 merged = dataframes[0] for df in dataframes[1:]: merged = pd.merge(merged, df, on=merged.columns[0], how="outer") merged.to_csv(output_path, index=False)你可以手动把这段代码粘贴回/tmp/merge_csv.py,也可以使用 Gptel 提供的编辑功能。
5.4 使用 gptel-rewrite 直接改写代码
Gptel 的gptel-rewrite命令非常实用。选中代码后,执行M-x gptel-rewrite,它会让你输入一个改写指令,比如“添加异常处理”“转换成异步方式”“优化性能”,模型返回结果后,你可以选择替换原区域,或者只预览而不改动。
这种模式非常适合代码重构。比如,选中最开始那个带 TODO 的骨架函数,执行gptel-rewrite,输入“实现这个函数”,模型返回后,按y确认替换,Gptel 会把原 region 替换为模型生成的内容,同时保留 buffer 其余部分。
使用gptel-rewrite时要注意,它会直接修改你的缓冲区,因此建议在修改前保存文件,或者使用 Emacs 的 undo 随时回退。
6. 进阶集成:多后端、Org 模式与编辑工作流
6.1 配置多个后端并切换
前面我们使用了 OpenAI 默认后端。Gptel 支持通过gptel-backend-alist配置多个后端。下面是一个示例,展示了如何配置 OpenAI、Anthropic 与本地 Ollama 三个后端。
(use-package gptel :ensure t :config ;; OpenAI 默认后端 (setq gptel-backend-alist '(("OpenAI" :host "api.openai.com" :endpoint "/v1/chat/completions" :key (lambda () (auth-source-pick-first-password :host "api.openai.com")) :model "gpt-4o-mini" :stream t) ("Anthropic" :host "api.anthropic.com" :endpoint "/v1/messages" :key (lambda () (auth-source-pick-first-password :host "api.anthropic.com")) :model "claude-3-5-sonnet-latest" :stream t) ("Ollama" :host "localhost:11434" :endpoint "/v1/chat/completions" :key "ollama" :model "llama3.1" :stream t))))这段配置中,每个后端都包含了请求地址、模型名、认证方式和是否启用流式输出。如果你使用 OpenAI 兼容的本地服务,只需把:host改成localhost:11434,:key设置为任意值即可。
在 Gptel 会话中,执行M-x gptel-set-backend可以切换后端;执行M-x gptel-set-model可以切换同一后端下的不同模型。也可以先配置gptel-model-alist,把不同模型按场景分组。
6.2 用 Org-mode 管理对话记录
Gptel 的默认模式设置为org-mode后,每个会话 buffer 都是一个 Org 文件,对话结构会按照 heading 和 block 组织。你可以用 Org 原生的折叠、导出功能,把对话记录导出为 HTML、PDF 或 Markdown。这非常适合写技术文档时,保留 AI 回答的参考资料。
此外,Gptel 还提供gptel-send-org-element命令,可以把当前 Org 条目(包括子树)发送给模型。结合 Org Babel,你甚至可以让 Gptel 生成的代码直接进入源块,然后通过org-babel-execute-src-block执行,形成“提问-生成-执行”的闭环。
6.3 与补全框架组合实现类 Copilot 效果
Gptel 本身不是补全引擎,但它可以和company-mode、corfu等补全框架配合,在光标位置插入模型补全结果。你可以通过gptel-request或gptel-completion-at-point实现代码补全。这种方式比完整的 AI 插件更轻量,适合那些不喜欢把编辑器变得过重的用户。
不过,如果追求和 Copilot 一样的高频补全体验,建议还是配合专门的补全工具,例如copilot.el、codeium.el或lsp-bridge。Gptel 的价值更多在于对话式交互和上下文重构,二者可以并行使用。
7. 常见问题与排查思路
7.1 错误表格
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 请求后无响应 | API key 未正确配置 | 检查gptel-api-key或 auth-source 能否取到密码 |
| 提示 “401 Unauthorized” | key 无效或权限不足 | 重新生成 API key,确认后端环境变量是否生效 |
| 提示 “404 Not Found” | endpoint 或模型名不正确 | 核对后端地址和模型名,查看服务端文档 |
| 请求超时 | 网络代理未设置或远程服务慢 | 配置 Emacs 代理,或将超时时间调大 |
| Emacs 卡顿 | 并发请求过多或同步回调 | 减少同时请求数,升级 Emacs 版本 |
| 流式输出不生效 | 后端不支持流式接口 | 将:stream设为nil |
| 返回内容被截断 | token 上限设置过小 | 增大gptel-max-tokens参数 |
| 中文乱码或编码错误 | 缓冲区编码不匹配 | 设置set-language-environment "UTF-8" |
7.2 网络代理与认证
在国内网络环境下,访问部分海外 API 可能需要配置代理。Emacs 可以使用内置的url库代理设置:
(setq url-proxy-services '(("http" . "127.0.0.1:7890") ("https" . "127.0.0.1:7890")))同时,request库和gptel的curl后端也会读取环境变量HTTP_PROXY和HTTPS_PROXY。可以根据实际代理端口修改。这里需要提醒一点:涉及代理时,请确保你使用的是合法合规的网络接入方式,不要在受限网络环境中绕过访问限制。
7.3 无法加载 gptel 包
如果安装后M-x gptel提示找不到命令,可能是包没有正确加载。你可以执行M-x list-packages查看是否已经安装,也可以在*Messages*buffer 中查看报错。常见原因是 MELPA 源刷新失败或 use-package 配置写在了package-initialize之前。
确保配置顺序正确:
(package-initialize) (use-package gptel :ensure t)7.4 API 参数兼容性
不同后端对参数支持不一致。例如 OpenAI 支持temperature、top_p、max_tokens,而某些本地服务可能忽略这些字段。如果你在切换后端时发现模型行为异常,可以先关闭流式、减少参数,再逐步开启。
8. 最佳实践与工程建议
8.1 安全与密钥管理
严禁把 API key 写入公开或同步的配置仓库中。推荐使用auth-source或系统钥匙串,并确保密钥只存在于本地。如果需要共享配置,可以使用gptel-api-key的符号引用,让用户各自填写。
同时,不要轻易把敏感代码或内部数据发送给外部 LLM 服务。在发送前检查 region 是否包含密钥、数据库连接字符串等敏感信息。对于严格保密的项目,建议只在本地部署的小模型服务上使用 Gptel。
8.2 上下文管理和 Token 控制
大模型的输入输出都有 token 限制。当上下文过长时,不仅消耗 token,还可能降低回答的准确性。建议:
- 发送给模型的代码尽量精简。
- 如果只是局部问题,使用
gptel-send-region而不是整个文件。 - 为每个会话设定合适的系统提示词,减少无关指令。
可以在配置中调整gptel-max-tokens,例如:
(setq gptel-max-tokens 4096)8.3 会话管理与复用
长期使用会积累很多会话 buffer。建议定期清理不再需要的 Gptel buffer,或使用gptel-save命令保存重要会话。如果你的磁盘空间不大,可以通过gptel-kill-all-sessions删除所有会话,但这会丢失未保存的对话内容,执行前需要确认。
8.4 保持包版本更新
Gptel 迭代很快,新版本会修复 bug、增加对新模型的支持。建议定期执行M-x package-refresh-contents后升级包。如果某个旧版本配置失效,升级后注意阅读NEWS文件,看看是否有需要迁移的配置项。
8.5 用宏或函数封装常用请求
如果你经常重复执行某些请求,比如“检查当前代码的潜在 bug”,可以用 Emacs Lisp 封装成一个自定义命令,调用gptel-request并传入系统提示词。这样既能提升效率,也方便团队共享。
(defun my/gptel-review-current-function () "Send the current defun to GPTel for code review." (interactive) (gptel-send-region (point) (save-excursion (beginning-of-defun) (mark-defun) (point)) "请作为资深工程师,检查这段代码的潜在问题和优化建议。"))把这个函数绑定到方便的快键键上,比如C-c g r,就能快速完成一次代码评审。
9. 总结与后续方向
通过本文,你应该已经理解了 Gptel 在 Emacs 中的定位:它并不仅仅是把 ChatGPT 搬进编辑器,而是把编辑器本身变成了模型交互的上下文来源。它最核心的用法是“发送上下文-获得反馈-无缝应用”,这大大减少了在网页端和编辑器之间切换的成本。
下一步,你可以继续探索 Gptel 的更多细节:比如如何配置多轮多模态输入,如何在 org-dynamic-block 中嵌入 Gptel 调用,如何与transient菜单深度定制。如果身边有同事也使用 Emacs,可以一起整理一套适合团队的 Gptel 配置模板,把模型选择、提示词模板、密钥管理统一起来。如果这篇教程对你有所帮助,不妨收藏备用,后续遇到配置问题时也方便随时查阅。