尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用 Python3 从零搭建命令行 AI 编程助手:环境配置、提示词工程与 Agent 化实践

用 Python3 从零搭建命令行 AI 编程助手:环境配置、提示词工程与 Agent 化实践 在折腾 Python3 的 AI 编程助手时我发现真正的难点不是“调 API”而是“把 AI 接到自己的工程习惯里”。市面上现成工具很多但要么是闭源的黑盒、不方便改要么模型和提示词绑定死、没法按自己的项目定制。所以我从零搭了一个基于 Python3 的命令行 AI 编程助手把代码生成、解释、审查、测试生成这些高频动作全串了起来。这篇文章就是完整记录包括环境准备、核心代码、提示词方案、Agent 化思路以及我实际踩过的一堆坑。适合手里有 Python 基础、想自建私有化 AI 编程工作流的朋友参考。1. 为什么用 Python3 搭自己的 AI 编程助手先说结论不是现成的 AI 编程工具不好用而是“用别人搭好的”和“自己搭一个”是完全不同的体验。我最初也只是在 IDE 里装插件用但用了两周后发现几个痛点——公司代码不能往外传、私有模型没法接、插件里预置的提示词质量参差不齐最关键的是当我想让 AI 去执行“按项目现有风格补充模块、顺手把单测写了、再跑一遍给我看”这种复合任务时现成工具基本做不到。1.1 从“用 AI”到“造 AI 助手”的转变用现成工具你是在别人的产品边界内提需求自建助手是把 AI 的能力塞进自己的脚本和工作流里。举个例子我希望在终端里跑ai gen 用 FastAPI 写一个文件上传接口然后助手不但生成代码还把依赖写进 requirements.txt、输出启动命令。这种“终端内一步到位”的体验现成 IDE 插件做不到但用 Python 写一个几十行的脚本就能贴近实现。同时自建最大的好处是可审计。每次调用模型发了什么 prompt、模型返回了什么、哪些步骤需要人工确认全部有日志、可控。对自己做技术复盘、优化提示词都很重要。说白了用 Python3 写 AI 编程助手不是为了炫技而是为了在一个你完全掌控代码和流程的前提下把大模型的生成能力嵌入到实际工程循环里。1.2 整体架构与核心功能拆解我搭的助手整体分四层每层都很薄但职责清晰模型访问层统一管理 API Key、模型名、超时与重试逻辑底层用openaiPython SDK但通过base_url指向兼容接口这样换模型只需要改环境变量。提示词管理层把不同任务生成、解释、审查、测试的 system prompt 和 user prompt 模板集中存放模板里支持注入上下文和代码片段。交互层命令行子命令入口比如ai gen、ai explain、ai review、ai test支持--file、--clipboard等参数读取代码上下文。工具链扩展层预留函数调用function calling的位置后面接代码执行、Git 状态检查、需求文件读取等能力这是从“问答”升级到“Agent”的关键。功能上覆盖四个高频场景代码生成、代码解释、代码审查、单元测试生成。这四个场景对提示词的要求完全不同不能共用一个 prompt所以后台对每个场景单独设计。2. Python3 环境准备版本、依赖与常见陷阱写这个助手之前我先确定要支持 Python 3.10 及以上版本。原因很简单新版类型语法X | None、match语句、更友好的报错提示这些在写 AI 工具时经常用到旧版本会平白报错。但真开始准备环境问题就来了。2.1 多版本共存与“没有 python 命令”的问题我先后在 Windows 和 Linux 上都遇到过“明明装了 Python3但终端里敲python就是没反应”。Windows 上常见原因是安装时没勾选Add Python to PATH虽然能通过py命令启动但很多脚本和工具不会去调py。另一个烦人的点是 Windows 上 store 版 Python 会优先拦截命令行导致装的是 3.11 却找不到可执行文件。Linux 上则是另一个故事很多发行版默认只提供python3命令不提供python为了兼容旧脚本又不好直接改符号链接。我的做法是在需要大量手敲命令的机器上执行sudo apt install python3-is-python这会安全地把python指向python3不会影响系统自带 Python如果是手动编译安装的多版本环境就用update-alternatives来管理优先级而不是直接改软链。2.2 python3-dev 依赖冲突与麒麟/统信系统注意事项如果你在 Ubuntu 22.04 上装过 python3-dev大概率见过这种报错python3-dev : 依赖: python3 ( 3.10.6-1~22.04) 但是 3.10.6-1~22.04.1 正要被安装第一次遇到时我差点以为是系统坏了。其实本质很简单python3-dev 的版本写死了3.10.6-1~22.04但软件源里的 python3 已经更新到3.10.6-1~22.04.1版本号不匹配apt 就不让装。遇到这种情况不要强行apt -f install或者删 python3那会牵连一堆依赖。我的排查步骤是apt-cache policy python3 python3-dev看两头到底是哪些版本。如果只是小版本号差异用sudo apt install python33.10.6-1~22.04 python3-dev3.10.6-1~22.04把 python3 锁到旧版本装完再升级或者反过来升级 python3-dev 到匹配版本。如果是本地源和线上源混用比如国产系统镜像源滞后或混了多个源先清理/etc/apt/sources.list和/etc/apt/sources.list.d/下的重复条目再apt update。在麒麟、统信这类基于 Debian/Ubuntu 的系统上处理方式大致相同但有一点格外值得注意不要动系统自带 python3桌面环境、包管理器全都依赖它。正确的姿势是另装一个隔离的 Python例如用python3-venv建虚拟环境或干脆用conda管理独立环境。2.3 用虚拟环境把依赖彻底隔离无论什么场景我都强烈建议在虚拟环境里跑这个助手。原因很直接助手会依赖openai、rich、click等第三方库直接装在系统环境里容易跟其他项目打架而且一旦系统 Python 被升级助手可能就起不来了。创建虚拟环境非常简单python3 -m venv .venv source .venv/bin/activate # Windows 下是 .venv\Scripts\activate pip install openai rich click有个小技巧虚拟环境的 Python 版本其实是在创建那一刻就固定下来的所以我通常先确认系统里有没有 3.10 或 3.11再创建虚拟环境python3.11 -m venv .venv这样可以彻底避免“虚拟环境看着在其实是系统 Python 的软链”这种问题。3. 核心代码实现从大模型 API 到可用的编程助手环境准备好了接下来是最关键的部分写一个真正能用的命令行助手。我不会一上来就做很复杂的东西先让核心链路通起来——用户输入需求、程序组装 prompt、模型返回代码、打印到终端。3.1 选型与配置模型、接口与参数调用大模型目前最省事的方式是走 OpenAI 兼容接口因为多数模型服务都支持。代码里直接使用openai库通过环境变量切换模型名和 base_url。这种设计的好处是今天用 GPT 系列、明天换其他兼容模型改环境变量就行代码一行不动。参数上有几个值得注意的点temperature代码生成任务我一般设 0.2 左右太高容易输出天马行空的“幻觉代码”太低则可能只做字面替换。max_tokens代码生成很吃长度我至少设 4096有些复杂项目生成会超过这个值后续要考虑续写或者让模型只输出关键片段。timeout大模型推理慢是常态我在 SDK 请求层设 60 秒超时并加了三次重试避免网络抖动导致整个流程中断。环境变量配置我写在.env文件里用python-dotenv读取不进 Git 仓库。这不是安全洁癖是基本卫生习惯。3.2 提示词工程让模型输出能直接用的代码这是整个助手里性价比最高的一环。我发现把大模型当“同事”而不是“搜索引擎”效果会好很多。写提示词时我固定了一个原则告诉模型你是谁、要做什么、有哪些约束、输出什么格式。拿代码生成举例我的模板长这样你是一名资深 Python 工程师负责编写高质量、可直接运行的代码。 需求{requirement} 技术栈{tech_stack} 约束 1. 只输出代码不输出解释除非代码里包含关键注释 2. 对不明确的需求给出合理假设并在开头一行注释中写明 3. 包含必要的 import、错误处理和 main 入口。为什么要这样设计因为如果不加“只输出代码”模型会附带一堆说明你还要花额外精力剥离。如果不说“给出合理假设”模型可能反问一大堆问题导致流程卡住。AI 编程助手的核心是“把不确定的决策点尽量收敛成可执行的默认行为”这正是提示词要干的事。同理代码审查的模板强调“按严重程度排序、给出具体修复建议、指出可能引发 bug 的边界条件”测试生成的模板强调“覆盖正常路径、边界条件和异常路径”这些约束都是为了让输出更贴合实际工程需要。3.3 完整代码一个可运行的命令行 AI 编程助手下面是我实际用的精简版代码去掉了跟特定环境绑定的部分保留了完整骨架。文件结构很简单一个main.py就够import os import sys import argparse from dotenv import load_dotenv from openai import OpenAI load_dotenv() API_KEY os.getenv(OPENAI_API_KEY) BASE_URL os.getenv(OPENAI_BASE_URL, https://api.openai.com/v1) MODEL_NAME os.getenv(MODEL_NAME, gpt-4o-mini) client OpenAI(api_keyAPI_KEY, base_urlBASE_URL, timeout60, max_retries3) SYSTEM_PROMPTS { gen: 你是一名资深 Python 工程师根据用户需求输出可直接运行的代码。只输出代码不输出解释。, explain: 你是一名经验丰富的 Python 开发者请用中文逐步解释下面的代码包含关键逻辑、潜在问题和改进建议。, review: 你是一名严格的代码审查者请逐条列出问题按严重程度严重/中等/轻微排序并给出修复建议。, test: 你是一名测试工程师请为下面的代码生成 pytest 单元测试覆盖正常路径、边界条件和异常路径。, } def call_model(system_prompt, user_prompt): response client.chat.completions.create( modelMODEL_NAME, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature0.2, max_tokens4096, ) return response.choices[0].message.content def read_context(args): 从文件、剪贴板或环境变量读取代码上下文 if args.file: with open(args.file, r, encodingutf-8) as f: return f.read() if args.clipboard: import pyperclip return pyperclip.paste() return args.code or def main(): parser argparse.ArgumentParser(descriptionPython3 AI 编程助手) subparsers parser.add_subparsers(destcommand, requiredTrue) p_gen subparsers.add_parser(gen, help生成代码) p_gen.add_argument(requirement, nargs*, help需求描述) p_gen.add_argument(--file, help参考文件路径) p_gen.add_argument(--clipboard, actionstore_true, help读取剪贴板作为上下文) p_explain subparsers.add_parser(explain, help解释代码) p_explain.add_argument(--file, help代码文件路径) p_explain.add_argument(--code, help直接传入代码) p_review subparsers.add_parser(review, help审查代码) p_review.add_argument(--file, help代码文件路径) p_review.add_argument(--code, help直接传入代码) p_test subparsers.add_parser(test, help生成单元测试) p_test.add_argument(--file, help代码文件路径) p_test.add_argument(--code, help直接传入代码) args parser.parse_args() if not API_KEY: print(请先设置 OPENAI_API_KEY 环境变量) sys.exit(1) if args.command gen: requirement .join(args.requirement) context read_context(args) user_prompt requirement if context: user_prompt f\n\n参考代码如下\npython\n{context}\n result call_model(SYSTEM_PROMPTS[gen], user_prompt) print(result) elif args.command in (explain, review, test): code read_context(args) if not code: print(需要提供 --file 或 --code 参数) sys.exit(1) user_prompt f代码如下\npython\n{code}\n result call_model(SYSTEM_PROMPTS[args.command], user_prompt) print(result) if __name__ __main__: main()这个代码跑通之后你在终端里就能直接这样用python main.py gen 写一个用 requests 获取网页标题的函数 python main.py review --file helper.py python main.py test --file calculator.py再配合 Shell alias比如alias aipython ~/dev/ai-assistant/main.py日常使用就很顺手。这里有个细节提醒read_context里的--clipboard需要pyperclip库在 Linux 上可能还要装xclip或wl-clipboard作为底层剪贴板支持。Windows 和 macOS 上pyperclip通常开箱即用。如果你在 Linux 遇到剪贴板读取失败先检查系统剪贴板工具不要马上怀疑代码。4. 从“问答”到“Agent”给助手加上工具能力基础版助手其实还停留在“单轮问答”阶段给我需求、给代码、给结果一步完事。但现实工程里代码生成完总要跑一下、报错了要修、修完还要再跑人工反复复制粘贴非常烦。所以下一步很自然就是让助手不仅能生成代码还能自己执行代码、看报错、自动修复跑通这个循环。这就成了 Agent 化。4.1 为什么单轮问答不够用单轮问答的核心缺陷是没有反馈回路。模型生成了一段代码它自己并不知道能不能跑通也不知道这段代码跟项目里现有模块的依赖关系。你把它生成的代码贴进项目一运行ImportError你又得把报错复制回去重新生成一次。一次两次还行几十个来回就非常低效。解决思路是引入“执行-反馈-修复”循环。助手生成代码 → 自动放到临时目录运行 → 把 stdout/stderr 喂回给模型 → 模型根据报错修改代码 → 再跑直到通过或达到迭代上限。就是这个循环把工具从“会写代码的聊天机器人”变成了“能干活的编程助手”。4.2 工具调用Function Calling的实现思路Chat Completion 接口本身就支持函数调用Function Calling我们可以在请求里声明一个工具比如execute_python让模型在需要执行代码时主动传参调用它而不是自己假装运行。定义如下tools [ { type: function, function: { name: execute_python, description: 在临时目录中执行 Python 代码返回标准输出和标准错误, parameters: { type: object, properties: { code: { type: string, description: 要执行的 Python 代码, } }, required: [code], }, }, } ]然后请求里带上toolstools。模型觉得该执行代码时会在返回里带着tool_calls代码里解析一下分别执行并回传结果if response.choices[0].message.tool_calls: for call in response.choices[0].message.tool_calls: if call.function.name execute_python: code json.loads(call.function.arguments)[code] result run_code_in_sandbox(code) messages.append({ role: tool, tool_call_id: call.id, content: result, }) # 再次请求让模型根据执行结果继续回答这个流程听起来简单但实际跑起来需要非常注意一个点执行代码的安全边界。模型生成的代码虽然大部分时候无害但偶尔会包含危险操作比如删文件、连接外部服务。所以我在封装run_code_in_sandbox时做了四件事在系统临时目录下创建sandbox子目录代码文件和工作目录都放在里面。通过subprocess.run执行设置timeout30防止死循环。剥离环境变量只保留最小必要的 PATH。对输出长度做截断比如只保留最后 2000 字符防止模型被刷屏。我的体会是Agent 化的安全措施永远要提前做不要等出事了再补救。4.3 简化版不依赖 Function Calling 的实现如果使用的模型服务不支持 Function Calling或者你想快速验证效果还有一个朴素方案让模型输出一个特定标记块比如python ...代码里用正则提取然后直接执行。这个方案能用但稳定性稍差因为模型偶尔会忘记包代码块或者在里面加解释文字。import re def extract_code(text): pattern rpython\n(.*?) match re.search(pattern, text, re.DOTALL) if match: return match.group(1).strip() return None跑通了基础功能后我强烈建议还是切到 Function Calling因为它在交互流程上更规整模型的工具调用是结构化参数不用解析文本出错概率低很多。5. 从命令行到 IDE把助手嵌入日常开发终端里能用只是个开始。大多数人 90% 的编程时间还是待在 IDE 里所以我把这个助手接到了 IDE 和日常提示词工作流里才算真正发挥了作用。5.1 在 VS Code / IDEA 里接入自建助手在 VS Code 里我推荐用 Continue 这类开源插件它支持自定义模型提供商。配置在config.json里写一段 OpenAI 兼容配置即可{ models: [ { title: Local Assistant, provider: openai, model: gpt-4o-mini, apiBase: http://localhost:8000/v1, apiKey: your-key } ] }IDE 插件的价值不只是聊天而是能一键选中代码、让 AI 解释或生成单测还能自动把当前文件的上下文带入请求。在 IDEA 里类似的方案是用 Continue 插件或者自己写一个简单的 HTTP 服务把 IDE 的 HTTP Client 指向自建接口。我自己的习惯是保留命令行版本因为很多场景下我人在 SSH 终端里没有 IDE 可开。5.2 结合“AI 编程提示词”提效的实用模板提示词写得好不好直接决定输出的可用率。我在实际使用中总结了一套“需求五要素”写法特别适合让助手产出可落地的代码输入是什么描述函数或接口的输入参数、类型、范围。输出是什么明确返回值、数据结构、是否写文件/数据库。约束条件比如“不要用第三方库”、“兼容 Python 3.8”、“算法复杂度 O(n log n)”。边界情况比如“输入为空怎么办”、“超长文本怎么处理”。参考实现给出项目里已有的类似风格代码让模型模仿风格。给一个我觉得很有效的实际 prompt 示例请用 Python 写一个函数 parse_config(path: str) - dict。 输入是 ini 格式的配置文件路径输出是解析后的字典。 约束不引入第三方库使用标准库 configparser遇到格式错误时抛出包含行号的异常 边界文件不存在时返回空 dict同一个 section 下重复 key 以后出现的值为准。 参考实现风格与项目 utils/reader.py 保持一致该文件内容如下。这种 prompt 生成出来的代码基本不用大改。5.3 从代码生成到评审测试的完整工作流我现在日常开发里最常用的一个循环是这样先用ai gen按五要素写初始实现然后用ai review --file让助手做代码审查重点让它找边界条件和潜在 bug再用ai test --file让它生成单测最后结合自动执行能力把报错喂回去修复。这个过程大大压缩了从“想法”到“可运行代码”的时间。要注意的是AI 生成的代码必须有人工 Review尤其是涉及数据库操作、权限判断、资金相关的逻辑绝不能直接信任。我把 AI 编程助手定位为“高智商但没社会经验的实习生”它快、它聪明但你要检查它做的事。6. 常见问题与排查技巧实录自建 AI 编程助手的过程中我遇到了不少奇奇怪怪的问题。有些问题报错很明显有些则是“看起来能用但结果不对”。下面按频率整理一份排查实录。6.1 常见报错速查表现象原因解决方法报APIConnectionError网络不通或 base_url 配置错误先curl -v测试接口地址确认环境变量拼写检查代理设置是否影响本机请求返回内容被截断max_tokens太小调大max_tokens或改造 prompt 让模型先输出核心逻辑后续再补全代码里有不存在的 API模型“幻觉”在 prompt 里强调“只能使用标准库或已列出的第三方库”生成后人工核对 importWindows 下中文乱码终端编码问题在代码开头加# -*- coding: utf-8 -*-控制台执行chcp 65001切换 UTF-8多字节字符被模型截断导致语法错误token 边界切断对生成代码做基础语法检查python -m py_compile file.py失败则自动重新请求python3和python3-dev版本冲突源版本不一致apt-cache policy对比版本锁定到同一版本重新安装请求超时模型推理时间长或网络慢SDK 设置timeout60、max_retries3对大任务拆分请求6.2 失败重试与上下文裁剪的独家技巧模型对话有上下文窗口限制一旦超过就报错或直接遗忘前面的内容。在处理大文件时我会做两层裁剪第一层把代码文件按函数/类切块只把和当前任务相关的函数传给模型第二层用摘要代替原文例如“第 3 行的load_data函数负责读取 CSV 并返回 DataFrame返回值包含 user_id、click_time 两列”而不是把整个函数体塞进去。这样既保留了上下文又节省 token。重试方面我给助手加了个“自动重试一次”的机制。如果第一次生成的代码运行报错就把 stderr 原样追加到原始 prompt 后面让模型重新生成。很多情况下第二次结果就能跑通。要注意记录重试次数避免陷入“改一个错产生另一个错”的死循环最多重试三次超过就打印错误并停止。6.3 给新手的三个实在建议如果你是第一次搭这种工具有三点建议值得听别急着上 Agent。先把单轮回合跑通、把提示词调好再谈工具调用和执行循环。上来就搞全套容易顾此失彼出了问题都不知道是哪一环坏了。从简单、具体的任务开始。比如先写一个“解释代码”的助手再扩展到生成和审查。任务越聚焦提示词越容易调优迭代更快。日志一定要留。每次请求的 prompt、response、耗时都落本地文件方便排查。没有日志出了问题只能瞎猜。我在实际使用中还有一个切身体会自建工具最怕“半途而废”。能坚持用下来的动力来自顺手而顺手的核心是把入口尽量缩短、套进自己已有的工作流里。真能做到在终端里一句ai gen就得到能跑的代码你才会真正依赖它。另外再分享一个小技巧配合 astropy 这类重计算型库的项目我在让助手生成代码时会把官方文档里的用法示例直接粘进 prompt作为参考实现。同样的道理适用于任何 API 复杂的库——模型对公开资料充足的库生成质量更高所以喂参考代码比空口描述需求有效得多。这条我在实际项目里反复验证过比单纯“调整 prompt 语气”带来的提升更明显。
返回列表