1. 为什么要在本地折腾一个 AI 编程助手
1.1 从“云端补全”到“本地可控”的动机转变
我最早用 AI 写代码,走的是最省事的路子——浏览器开个网页,把报错贴进去,等它吐答案。刚开始挺爽,直到有几次把公司内部接口的字段名贴进去,才后知后觉地冒冷汗。后来我开始认真考虑把 AI 编程助手搬到本地来跑,核心动机其实就三条:数据不出机器、断网也能用、模型和上下文完全自己说了算。
Codex 这类工具的本质,是一个能读写你项目文件、执行命令、根据自然语言指令改代码的智能体(Agent)。它和普通的代码补全插件最大的区别在于:补全插件只“看”当前文件,而 Codex 会主动去读你的目录结构、翻你的依赖文件、跑你的测试命令。这就意味着它对本地环境的访问权限相当大,也正因如此,把它放在本地、用本地模型驱动,才让人心里踏实。
这篇文章面向的是有一定命令行基础、想在自己电脑或内网服务器上跑起 AI 编程助手的开发者。你不需要是运维专家,但至少要能看懂docker ps的输出、知道什么是环境变量。我会把从环境准备、模型接入、容器编排到排错的完整链路拆开讲,尽量做到你照着做就能复现。
1.2 本地部署到底解决了哪些真实痛点
先说清楚本地部署不是万能药,它解决的是特定场景的问题。我把它归纳成一张表,你可以对照自己的情况判断值不值得折腾:
| 痛点场景 | 云端方案的表现 | 本地部署的表现 |
|---|---|---|
| 代码含敏感业务逻辑 | 需上传到第三方,合规风险高 | 数据全程留在本机 |
| 网络不稳定或受限 | 请求超时、频繁断连 | 局域网内稳定可用 |
| 想固定模型版本 | 服务方随时升级,行为漂移 | 版本锁定,行为可复现 |
| 高频调用成本 | 按 token 计费,量大肉疼 | 一次性硬件投入,边际成本近零 |
| 定制系统提示词 | 受平台限制 | 完全自由 |
我自己的判断标准很简单:如果你每天用 AI 写代码超过一小时,且项目涉及任何不方便外传的内容,本地部署的投入就值回票价。反过来,如果你只是偶尔问问语法,云端方案更省心。
1.3 整体架构:Codex 与本地模型是怎么协作的
很多人一上来就卡在概念上,以为“本地部署 Codex”就是把整个模型塞进 Codex 里。其实不是。Codex 是一个客户端/智能体框架,它负责的是“理解任务、规划步骤、调用工具、读写文件”这套编排逻辑;真正生成代码的“大脑”是背后的大语言模型。这两者可以分离部署。
所以典型的本地架构是这样一条链路:
- Codex 客户端:跑在你的开发机上,负责交互、文件操作、命令执行。
- 模型服务:跑在本地或内网,对外暴露一个兼容 OpenAI 接口规范的 HTTP 端点。
- 容器运行时:用 Docker 把模型服务、依赖环境打包隔离,避免污染宿主机。
Codex 通过配置一个base_url指向你的本地模型服务,就能把请求发过去。理解了这一点,后面所有的配置其实都是在解决“怎么让这条链路通起来”的问题。
提示:模型服务和 Codex 客户端可以不在同一台机器上。开发机性能一般、但有台带显卡的服务器时,把模型服务放服务器、客户端放本地,是很常见的组合。
2. 环境准备:Docker 与运行时的正确打开方式
2.1 Docker Desktop 安装与虚拟化检测
本地部署绕不开 Docker,而 Docker 在 Windows 和 macOS 上最省事的入口就是 Docker Desktop。但这一步的坑特别多,我见过最多的报错就是启动时提示虚拟化支持未检测到。这个问题的根源在于:Docker Desktop 在 Windows 上依赖 WSL2 或 Hyper-V 提供的虚拟化能力,如果 BIOS 里没开虚拟化,或者 WSL2 没装好,它就直接罢工。
排查顺序我建议这样走:
- 进 BIOS 确认虚拟化开关。Intel 平台叫 VT-x,AMD 平台叫 SVM,通常在 Advanced 或 CPU Configuration 菜单里。这一步必须在重启时进 BIOS 操作,系统里改不了。
- 确认系统组件。Windows 下打开“启用或关闭 Windows 功能”,勾选“虚拟机平台”和“适用于 Linux 的 Windows 子系统”。
- 安装 WSL2 内核更新包。装完重启,命令行执行
wsl --status看默认版本是不是 2。 - 再启动 Docker Desktop。
macOS 用户相对省心,Apple Silicon 芯片原生支持虚拟化,装完基本能用。但要注意:M 系列芯片是 ARM 架构,拉镜像时务必选 arm64 版本,否则会跑在模拟层上,性能打骨折。
2.2 镜像加速与网络连通性排查
国内拉 Docker 镜像慢是常态,配置镜像加速器几乎是必做项。在 Docker Desktop 的设置里找到 Docker Engine,编辑 JSON 配置,加上 registry-mirrors 字段。改完点 Apply & Restart 生效。
配置完别急着高兴,先验证一下:
docker info | grep -A 5 "Registry Mirrors" docker pull hello-world如果docker pull卡住不动,八成是加速器地址失效了。这时候可以换一个源,或者干脆用docker pull时指定完整仓库地址。我踩过的坑是:加速器配置写错了 JSON 格式,Docker 直接起不来,所以改配置前最好把原内容备份一份。
还有一个高频问题是容器内网络不通。典型表现是容器起来了,但访问不了外网或访问不了宿主机服务。这里要分清两种情况:容器访问外网走的是 NAT,一般没问题;容器访问宿主机服务,则要用宿主机在 Docker 网络里的特殊地址(Linux 下是172.17.0.1,Mac/Windows 下用host.docker.internal)。搞混这两个,就会出现“明明服务在跑却连不上”的诡异现象。
2.3 资源分配:给模型服务留足内存和显存
Docker Desktop 默认给虚拟机的资源是偏保守的,跑个小服务够用,但要跑大语言模型就捉襟见肘了。在设置里的 Resources 页面,我一般这样分配:
- 内存:至少给到宿主机的一半。跑 7B 级别的量化模型,建议不低于 8GB;跑 14B 以上,16GB 起步。
- CPU:给 4 核以上,模型推理对多核有依赖。
- 磁盘:模型文件动辄几个 GB,镜像层叠起来也占地方,留 50GB 以上比较从容。
- GPU:如果宿主机有独立显卡,需要在 Docker Desktop 里开启 GPU 支持,并安装对应的容器工具包。
这里有个容易被忽略的点:WSL2 的内存占用是动态的,但上限受.wslconfig文件控制。如果你发现 Docker 用着用着内存爆了,可以在用户目录下建一个.wslconfig,手动限制 WSL 的内存和 CPU 上限,避免它把整台机器拖垮。
3. 模型服务选型与本地接入方案
3.1 本地模型服务的主流选择与取舍
Codex 背后需要一个能说“OpenAI 方言”的模型服务。市面上能本地跑、又兼容这套接口的方案有好几类,我按使用体验排个序:
- Ollama:上手最快,一条命令拉模型、一条命令起服务,自带兼容接口。适合想快速验证的人。缺点是并发和精细控制弱一些。
- vLLM:吞吐量强,适合多人共用或高频调用。配置稍复杂,对显卡要求高。
- LM Studio:图形界面友好,适合不熟悉命令行的用户,也能开兼容接口。
- 各类推理框架自建:灵活度最高,但要自己处理接口适配。
我的建议是:先用 Ollama 把整条链路跑通,确认 Codex 能正常调用,再根据性能需求决定要不要换 vLLM。一上来就追求极致性能,很容易在配置阶段就劝退。
选模型时还要注意一个现实问题:模型名称必须和 Codex 配置里写的对上。有些模型服务对外暴露的模型 ID 和你拉取时的名字不完全一致,配置写错了就会报“模型不支持”之类的错误。这个后面排错章节会细讲。
3.2 用 Docker 跑模型服务的编排思路
把模型服务放进 Docker,最大的好处是环境隔离和可复现。我习惯用docker compose来管理,一个compose.yaml把服务、端口、卷、环境变量全写清楚,换台机器复制过去就能起。
一个典型的编排要考虑这几件事:
- 端口映射:模型服务默认端口映射到宿主机,Codex 才能访问。
- 模型缓存卷:把模型文件目录挂载出来,避免每次重建容器都重新下载。
- GPU 透传:有显卡的话,在 compose 里声明 GPU 资源。
- 健康检查:加一个健康检查,确保服务真正就绪再让 Codex 连。
services: model-server: image: ollama/ollama:latest ports: - "11434:11434" volumes: - ./ollama-data:/root/.ollama restart: unless-stopped这段配置看着简单,但每一行都有讲究。volumes那行如果不写,容器一删模型就没了,重新拉取又要等半天。restart策略设成unless-stopped,机器重启后服务能自动起来,省得每次手动敲命令。
3.3 Codex 侧的关键配置项解析
Codex 要连上本地模型,核心就是改配置。不同版本的 Codex 配置方式略有差异,但本质都是告诉它三件事:请求发到哪、用哪个模型、带什么凭证。
以常见的配置文件为例,关键字段包括:
base_url:指向本地模型服务的地址,比如http://localhost:11434/v1。注意结尾的/v1不能少,这是兼容接口的路径约定。model:模型标识符,必须和模型服务里实际存在的名字一致。api_key:本地服务通常不校验,但字段不能空着,随便填个占位符即可。
配置改完,最直接的验证方式是发一个最小请求:
curl http://localhost:11434/v1/models能返回模型列表,说明服务通了;再让 Codex 跑一个简单任务,比如“列出当前目录的文件”,能正常执行就说明整条链路打通了。
注意:
base_url里用localhost还是host.docker.internal,取决于 Codex 本身跑在容器里还是宿主机上。如果 Codex 也在容器里,localhost指向的是它自己,就连不到模型服务了。这个细节坑过很多人。
4. 完整实操流程与关键环节实现
4.1 从零到跑通的分步操作记录
我把整个流程拆成可复现的步骤,你按顺序来就行。
第一步:装 Docker Desktop 并验证。装完打开终端,执行docker version,能看到 Client 和 Server 两段信息才算真正就绪。只有 Client 没有 Server,说明后台服务没起来。
第二步:拉取模型服务镜像。以 Ollama 为例:
docker pull ollama/ollama:latest第三步:启动服务并拉取模型。先起容器,再进容器拉模型:
docker run -d -v ollama-data:/root/.ollama -p 11434:11434 --name ollama ollama/ollama docker exec -it ollama ollama pull qwen2.5-coder:7b这里选 coder 系列的模型是有原因的——它们针对代码任务做过专门优化,在补全和重构场景下表现明显好于通用模型。
第四步:验证接口。用 curl 打一下/v1/models,确认返回里有你刚拉的模型。
第五步:配置 Codex。把base_url指向http://localhost:11434/v1,model填qwen2.5-coder:7b。
第六步:跑通第一个任务。让 Codex 读一个文件、改一行代码,观察它是否能正确调用本地模型并执行文件操作。
4.2 参数计算:模型大小与硬件匹配
选模型不能只看名字,得算一下硬件扛不扛得住。核心公式是:
显存需求 ≈ 参数量 × 每参数字节数 + 上下文开销
以 7B 模型为例,不同精度下的占用差别很大:
| 精度 | 每参数字节 | 7B 模型显存需求 | 适用硬件 |
|---|---|---|---|
| FP16 | 2 | 约 14GB | 16GB 显存以上 |
| INT8 | 1 | 约 7GB | 8GB 显存 |
| INT4 | 0.5 | 约 3.5GB | 6GB 显存或纯 CPU |
如果显存不够,模型会退到 CPU 上跑,速度会慢一个数量级。我实测下来,7B 的 INT4 量化模型在纯 CPU 上也能用,但响应时间从秒级变成十几秒级,适合不赶时间的场景。有显卡的话,优先用 GPU 跑,体验差距非常明显。
上下文长度也要算进去。上下文越长,KV Cache 占用越大。如果你经常让 Codex 处理大文件,记得把上下文窗口调大,同时预留更多显存。
4.3 让 Codex 真正“干活”的配置细节
模型通了只是第一步,让 Codex 高效干活还需要调一些细节。
系统提示词决定了 Codex 的行为风格。本地部署的好处就是可以随便改。我一般会加上项目约定,比如“优先使用项目已有的工具函数”“改动前先读相关文件”,这样它生成的代码更贴合项目习惯。
工具权限要控制好。Codex 能执行命令、写文件,权限给太大有风险。建议在配置里限制它能操作的目录范围,避免它误改系统文件。
超时设置容易被忽略。本地模型首次加载慢,如果超时设得太短,第一个请求就失败了。我一般把超时设到 120 秒以上,给模型留足冷启动时间。
并发控制也要注意。本地模型服务的并发能力有限,同时发太多请求会排队甚至崩溃。单人使用一般不用管,多人共用时要在服务端做限流。
5. 常见报错与排查技巧实录
5.1 模型不支持类报错的定位思路
有一类报错特别典型,大意是“当前配置下不支持某个模型”。这个问题的根源通常不在模型本身,而在模型标识符不匹配。
排查步骤:
- 先确认模型服务里到底有哪些模型。执行
curl http://localhost:11434/v1/models,把返回的 ID 列表记下来。 - 对比 Codex 配置里的
model字段,看是否和列表里的某个 ID 完全一致。注意大小写、冒号、连字符,差一个字符都不行。 - 如果模型服务是通过别名暴露的,确认别名映射是否正确。
我遇到过一次,配置里写的是qwen2.5-coder,但服务里实际是qwen2.5-coder:7b,少了标签就报不支持。这种问题看着玄乎,其实就是字符串没对上。
5.2 网络与代理相关的连接失败
连接失败是另一大类问题,表现是 Codex 发请求时超时或拒绝连接。排查要分层进行:
- 先测模型服务本身:在宿主机上 curl 一下服务端口,通不通。
- 再测容器到宿主机的连通性:如果 Codex 在容器里,用
host.docker.internal试。 - 检查端口映射:
docker ps看端口有没有正确映射出来。 - 检查防火墙:宿主机防火墙可能拦了端口。
还有一种隐蔽情况:系统里配了全局代理,导致本地请求被代理走了。本地地址应该走直连,如果代理规则没排除localhost和127.0.0.1,请求就会绕一圈然后失败。检查一下代理的绕过列表,把本地地址加进去。
5.3 高频问题速查表
我把实际踩过的坑整理成一张表,方便你对照排查:
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| Docker 启动失败,提示虚拟化未检测到 | BIOS 虚拟化未开或 WSL2 未装 | 进 BIOS 开虚拟化,装 WSL2 |
| 拉镜像卡住 | 加速器失效或网络问题 | 换加速器源,检查网络 |
| 容器访问不了宿主机服务 | 地址用错 | 容器内用 host.docker.internal |
| 模型报不支持 | 模型 ID 不匹配 | 核对服务端模型列表 |
| 请求超时 | 冷启动慢或超时太短 | 调大超时,预热模型 |
| 响应极慢 | 模型跑在 CPU 上 | 检查 GPU 是否被正确使用 |
| 内存爆掉 | 资源分配过大或未限制 | 调小分配,配置 .wslconfig |
| 容器重启后模型丢失 | 未挂载数据卷 | 加 volumes 挂载模型目录 |
5.4 几个只有踩过才知道的实操心得
第一,模型预热很重要。服务刚起来时第一个请求特别慢,因为要把模型加载进内存。我习惯在服务启动后先发一个空请求预热,等 Codex 真正用时就是热状态了。
第二,日志是你的朋友。模型服务和 Codex 都有日志输出,出问题时先看日志,比瞎猜快得多。Docker 下用docker logs -f 容器名实时看。
第三,配置改动要小步验证。一次只改一个配置项,改完立刻验证。同时改好几个地方,出问题都不知道是哪个引起的。
第四,别迷信大模型。本地硬件有限时,一个调优好的 7B 模型,实际体验可能好过一个跑不动的 32B 模型。选模型要匹配硬件,不是越大越好。
第五,备份配置文件。配置改乱了想回退,有备份就几秒钟的事,没备份就得重新摸索。
6. 性能调优与长期使用建议
6.1 让响应更快的那几个开关
跑通之后,下一步就是让它更快。我试过几个有效的方向:
量化精度换速度。从 FP16 降到 INT8 甚至 INT4,显存占用大幅下降,速度提升明显,代价是精度略有损失。对代码补全这类任务,INT4 的质量通常够用。
批处理与并发。如果模型服务支持批处理,把多个请求合并处理能提升吞吐。但要注意延迟会上升,交互式场景要权衡。
KV Cache 复用。多轮对话时,复用之前的 KV Cache 能省掉重复计算。支持这个特性的推理框架,多轮对话速度会快不少。
硬件层面,如果预算允许,加显存比加内存对模型推理的帮助大得多。显存决定了模型能不能全量放进 GPU,放不下就得来回搬运,速度断崖式下跌。
6.2 安全边界:本地不等于绝对安全
本地部署降低了数据外传的风险,但不等于高枕无忧。几个要注意的点:
- 模型服务端口不要暴露到公网。默认只监听本地或内网,别图方便映射到 0.0.0.0 又不做认证。
- Codex 的文件操作权限要收敛。限制在项目目录内,别给它整个磁盘的读写权。
- 模型文件来源要可信。从官方或可信渠道拉取,避免加载来路不明的模型。
- 定期更新镜像。基础镜像和推理框架的安全更新要及时跟进。
6.3 后续可以怎么扩展
跑通单机版之后,还有不少可以玩的方向。比如把模型服务放到内网服务器,多台开发机共用一套推理资源;比如接入不同的模型,按任务类型路由——简单补全用小模型,复杂重构用大模型;再比如把 Codex 和 CI 流程结合,让它在提交前自动做一轮代码检查。
我自己目前的做法是:日常补全用本地小模型,遇到复杂重构再切到更强的模型。这样既保证了日常响应速度,又能在关键任务上拿到更好的结果。硬件和模型都在快速迭代,今天跑不动的配置,过半年可能就轻松了,所以这套本地环境搭起来,长期看是划算的。