AI时代开发者进阶指南:从Prompt到大模型工程实践
John Henry 这个名字,在欧美民间传说里代表一位与蒸汽锤比赛凿石头的铁路工人。他赢了比赛,却因为过度透支倒在了终点线上。这个一百多年前的寓言,放在今天几乎成了“程序员 vs AI 编程工具”的原始模板。只是这一次,角色变了:蒸汽锤变成了大模型,而很多开发者正在不知不觉地站上 John Henry 的位置——用最快的速度打代码,和 AI 比谁能更快地产出。
这篇文章不打算讲“人定胜天”的鸡汤,也不打算制造“AI 即将替代程序员”的焦虑。我想从工程实践角度出发,把这个议题拆解成一条可执行的路径:AI 时代,开发者到底该学什么、做什么、怎么用工具。文中会给出完整的大模型接入示例、AI 辅助编码工作流的实战代码,以及我在实际项目里遇到的高频问题和排查思路。
无论你是刚接触 AI 开发的新手,还是想在现有项目中引入大模型能力的后端工程师,这篇文章都能给你一套可以落地的方法。
1. 背景与核心概念
1.1 John Henry 的隐喻与 AI 时代开发者困境
John Henry 的故事最早流传于 19 世纪美国铁路建设时期。他是一名凿石工,在隧道工程中与一台新引进的蒸汽钻孔机比赛,最终靠人力凿穿了更多岩石,但随即倒地身亡。
这个故事的悲剧内核在于:他把“人”和“机器”放在了同一个赛道上,用机器的时间尺度来衡量自己的劳动。
今天的 AI 编程工具,本质上也是一种“蒸汽锤”。GitHub Copilot、Cursor、通义灵码、DeepSeek 等工具,能在几秒钟内生成一段可以运行的代码。如果开发者仍然用“和 AI 比手速”的方式工作,那确实会被效率碾压。
但换个角度想,蒸汽锤没有取代凿石工,它只是重新定义了凿石工的工作内容:从“挥锤子”变成了“判断往哪砸”。同样,AI 不会让开发者失业,但会把开发者的核心竞争力从“怎么写代码”转移到“怎么描述需求、怎么判断代码质量、怎么组织工程结构”。
1.2 AI 辅助开发的本质是“人在回路”
在 AI 工程实践里,有一个词叫 Human-in-the-Loop,翻译过来就是“人在回路”。它的意思是:AI 系统并不是完全自动运行的,而是在关键节点需要人来输入、审查、纠偏。
放到软件开发场景,可以这样理解:
- 需求拆解:AI 可以帮忙列出任务清单,但优先级和边界需要人来定。
- 代码生成:AI 可以写出函数实现,但业务规则和异常处理需要人来补充。
- 代码审查:AI 可以发现潜在的 bug,但架构决策和数据安全需要人来把关。
- 测试补全:AI 可以生成单元测试用例,但业务预期值需要人来确认。
所以,AI 时代的开发者更像一个“驾驶者”,而不是“划桨者”。你不需要和 AI 比力气,而要学会控制方向。
1.3 开发者需要构建的新能力模型
如果把 AI 辅助开发作为一个技术主题来看,它需要的能力模型可以拆成三层:
- 基础层:能写好 Prompt,理解大模型的输入输出规律。
- 工具层:会调用大模型 API,会封装函数,能处理返回结果。
- 工程层:理解 Function Calling、RAG、Agent 等概念,能把 AI 能力嵌入到真实业务系统。
文章接下来的部分,会围绕这三层能力展开。我会用一个完整的小项目,把从 Prompt 设计到模型调用再到代码生成的流程跑通。项目不大,但足够覆盖 AI 辅助开发的核心链路。
2. 环境准备与版本说明
2.1 运行环境选择
为了适配更多读者,本文示例采用 Python 3 编写。Python 版本建议使用 3.9 及以上,因为新版代码在类型注解和异常处理上更友好。
需要说明的是,大模型相关 SDK 和 API 接口更新速度非常快,不同服务商的接口格式存在差异。本文以“OpenAI 兼容接口”为例编写代码,这是目前国内大多数大模型服务商(包括 DeepSeek、通义千问、Moonshot 等)都支持的通用协议。这意味着,你只需要替换base_url和api_key,代码思路可以复用。
2.2 获取大模型 API Key
无论使用哪家服务商,流程基本一致:
- 注册开发者账号。
- 在控制台创建 API Key。
- 查看接口文档,找到
base_url和模型名称。 - 给账号充值或领取免费额度。
在本地开发时,不要直接把 API Key 写死在代码里。推荐用环境变量管理:
export LLM_API_KEY="你的密钥" export LLM_BASE_URL="https://api.example.com/v1" export LLM_MODEL="your-model-name"这样做的好处是:代码仓库里不会出现密钥,换不同服务商时也不需要改代码,只需要改环境变量。
2.3 项目依赖与目录结构
本文示例只依赖requests库,这是一个非常通用的 HTTP 客户端库。安装命令:
pip install requests完整项目结构如下:
ai_assistant/ ├── main.py # 命令行入口 ├── llm_client.py # 大模型客户端封装 ├── prompts.py # Prompt 模板管理 ├── requirements.txt # 依赖清单 └── output/ # 生成结果输出目录如果你用的是 PyCharm 或 VS Code,可以直接打开这个目录作为项目根目录。如果你用的是 IDEA,也可以按照同样的结构创建 Python 项目。
3. 核心原理拆解:从 Prompt 到大模型应用
3.1 Prompt 工程:把模糊需求变成指令
Prompt 是用户输入给大模型的文本。大模型的输出质量,很大程度上取决于 Prompt 的质量。一个常见的误区是:把 Prompt 当成聊天时的随意表达,想到什么写什么。
在工程化场景中,Prompt 应该被当作代码来管理。它需要有结构、有版本、有变更记录。下面是一个最简单的对比:
低质量的 Prompt:
帮我写一个爬虫。高质量的 Prompt:
请用 Python 编写一个爬虫程序,目标网站是 example.com。 要求: 1. 使用 requests 库发送 HTTP 请求。 2. 使用 BeautifulSoup 解析 HTML。 3. 提取页面中所有 h2 标题的文本内容。 4. 将结果保存到 output/titles.txt 文件中。 5. 添加异常处理,避免因网络超时导致程序退出。可以看出,高质量 Prompt 具备了三个特征:
- 角色约束:告诉 AI“你是一个 Python 工程师”。
- 任务描述:明确要做什么,输入输出是什么。
- 约束条件:指定技术栈、边界和容错要求。
在本文的实战项目中,我会把这些要素结构化地写进 Prompt 模板。
3.2 大模型 API 的调用方式
目前主流的大模型服务商,API 格式逐渐向 OpenAI 标准靠拢。一次完整的对话请求通常包含以下几个部分:
model:模型名称。messages:对话消息列表,每个消息包含role和content。temperature:采样温度,值越小输出越确定。
一个最小请求示例如下:
curl https://api.example.com/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "model": "your-model-name", "messages": [ {"role": "system", "content": "你是一名 Python 工程师。"}, {"role": "user", "content": "请写一个计算斐波那契数列的函数。"} ] }'在实际项目里,我们不会直接使用 curl 调用,而是用 Python 封装一个统一的客户端。这部分的代码会在下一节实战案例中完整给出。
3.3 从单次对话到 Agent 的演进
很多开发者第一次接触大模型 API 会问:这个和网页聊天有什么区别?为什么工程上要强调 API?
答案是:网页聊天只适合临时对话,API 才能让 AI 能力嵌入到业务系统里。
当我们需要让 AI 自主执行多个步骤时,就会接触到 Agent 的概念。一个 AI Agent 通常包含三个要素:
- 规划(Planning):把复杂任务拆成多个子任务。
- 工具调用(Function Calling / Tool Use):Agent 在需要时调用外部函数,比如查询数据库、调用搜索接口。
- 记忆(Memory):在多轮对话中记住上下文和中间结果。
本文的实战项目不会直接实现完整的 Agent,但会先实现大模型客户端封装这一基础层。如果你理解了这一层,后续学习 LangChain、Spring AI 或自研 Agent 框架都会容易很多。
3.4 RAG:让 AI 回答私域知识的问题
还有一个常被提到的是 RAG(Retrieval-Augmented Generation),即检索增强生成。简单说,就是先把你自己的文档切片、向量化,当用户提问时,先去知识库中检索相关内容,拼接进 Prompt,再交给大模型生成回答。
RAG 解决的核心问题是:大模型的知识截止日期有限,且不懂企业内部文档。通过 RAG,可以让 AI 在回答问题之前先“查资料”。
本文不展开 RAG 的完整实现,但需要明白它和直接调 API 的关系:RAG 是 API 之上的一层业务封装,底层的模型调用逻辑是一样的。
4. 完整实战:构建一个 AI 辅助编码助手
这一节我们来实现一个真实的命令行工具。它的功能是:接收用户输入的需求描述,调用大模型生成 Python 代码,再自动生成对应的单元测试。这个工具虽然小,但已经具备了“AI 辅助开发”的完整闭环。
4.1 创建项目结构
在终端中执行以下命令:
mkdir ai_assistant cd ai_assistant mkdir output touch main.py llm_client.py prompts.py requirements.txt4.2 安装依赖
在requirements.txt中写入:
requests>=2.25.0然后执行:
pip install -r requirements.txt4.3 封装大模型客户端
文件路径:llm_client.py
import os import requests class LLMClient: """大模型客户端封装,兼容 OpenAI 格式接口。""" def __init__(self, api_key: str = None, base_url: str = None, model: str = None): self.api_key = api_key or os.getenv("LLM_API_KEY") self.base_url = (base_url or os.getenv("LLM_BASE_URL", "https://api.example.com/v1")).rstrip("/") self.model = model or os.getenv("LLM_MODEL", "your-model-name") if not self.api_key: raise ValueError("未找到 API Key,请检查环境变量 LLM_API_KEY 或构造参数 api_key。") def chat(self, messages: list, temperature: float = 0.2, max_tokens: int = 2000) -> str: """发送对话请求,返回模型生成的文本内容。""" url = f"{self.base_url}/chat/completions" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } payload = { "model": self.model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens } try: resp = requests.post(url, headers=headers, json=payload, timeout=60) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"] except requests.exceptions.Timeout: raise TimeoutError("请求超时,请检查网络或增大 timeout 参数。") except requests.exceptions.HTTPError as e: status_code = e.response.status_code if status_code == 401: raise PermissionError("API Key 无效或未授权。") elif status_code == 429: raise RuntimeError("请求过于频繁,触发限流。") else: raise RuntimeError(f"HTTP 请求失败,状态码: {status_code}, 错误信息: {e.response.text}") if __name__ == "__main__": # 简单自测 client = LLMClient() resp = client.chat([ {"role": "system", "content": "你是一个有用助手。"}, {"role": "user", "content": "请回复 OK"} ]) print(resp)代码说明:
- 构造函数从环境变量读取 API Key、接口地址和模型名,同时允许调用方覆盖。
chat方法接收messages列表,内部构造 HTTP 请求。- 对超时、401、429 等常见异常做了明确分类,方便上层捕获和处理。
if __name__ == "__main__"分支用于快速验证客户端是否可用。
4.4 管理 Prompt 模板
文件路径:prompts.py
SYSTEM_PROMPT = """你是一名资深 Python 工程师,擅长编写高质量、可读性强的代码。 你的任务是根据用户的需求描述,生成完整可运行的 Python 代码。 要求: 1. 代码必须包含必要的 import。 2. 函数需要有类型注解和 docstring。 3. 边界条件需要处理。 4. 只输出 Python 代码,不要输出解释性文字。 """ TEST_PROMPT = """你是一名测试工程师,擅长 unittest 和 pytest。 请根据给定的源代码,生成对应的单元测试代码。 要求: 1. 使用 pytest 风格编写。 2. 测试用例需要覆盖正常情况和边界情况。 3. 只输出 Python 代码,不要输出解释性文字。 """ def build_code_generation_messages(requirement: str) -> list: """根据需求描述,构造生成代码的 messages。""" return [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": f"需求描述:{requirement}\n请输出完整可运行的 Python 代码。"} ] def build_test_generation_messages(source_code: str) -> list: """根据源代码,构造生成测试的 messages。""" return [ {"role": "system", "content": TEST_PROMPT}, {"role": "user", "content": f"源代码:\n{source_code}\n请输出对应的 pytest 单元测试代码。"} ]将 Prompt 单独放在一个模块中,是工程化开发的基本习惯。这样做的原因有两个:
- 后续迭代 Prompt 时,不会影响业务代码。
- 可以像管理普通代码一样,对 Prompt 做 Git 版本管理。
4.5 实现命令行主程序
文件路径:main.py
import argparse import os import re from llm_client import LLMClient from prompts import ( build_code_generation_messages, build_test_generation_messages, ) def extract_code(text: str) -> str: """从模型输出中提取纯代码,去掉 Markdown 代码块标记。""" # 匹配 ```python ... ``` 格式 pattern = r"```(?:python)?\s*(.*?)```" matches = re.findall(pattern, text, re.DOTALL) if matches: return matches[0].strip() return text.strip() def save_code(content: str, filepath: str) -> None: """将内容写入指定文件。""" os.makedirs(os.path.dirname(filepath), exist_ok=True) with open(filepath, "w", encoding="utf-8") as f: f.write(content) print(f"已保存到: {filepath}") def main(): parser = argparse.ArgumentParser(description="AI 辅助编码助手") parser.add_argument("--requirement", "-r", type=str, required=True, help="需求描述") args = parser.parse_args() client = LLMClient() # 第一步:生成业务代码 print("正在生成业务代码...") code_response = client.chat(build_code_generation_messages(args.requirement)) source_code = extract_code(code_response) save_code(source_code, "output/generated_code.py") # 第二步:生成单元测试 print("正在生成单元测试...") test_response = client.chat(build_test_generation_messages(source_code)) test_code = extract_code(test_response) save_code(test_code, "output/test_generated_code.py") print("生成完成!") if __name__ == "__main__": main()这个主程序的核心逻辑很简单:
- 用户通过命令行传入需求描述。
- 构造用于代码生成的 messages,调用大模型。
- 使用正则表达式提取代码块内容。
- 将生成结果保存到
output目录。 - 把上一步生成的代码作为上下文,再让大模型生成 pytest 测试。
4.6 运行与验证
在项目根目录执行:
python main.py -r "写一个函数,接收一个列表,返回去重后的列表,并且保持原有顺序。"预期输出:
正在生成业务代码... 已保存到: output/generated_code.py 正在生成单元测试... 已保存到: output/test_generated_code.py 生成完成!打开output/generated_code.py,你会看到类似下面的内容:
from typing import List def deduplicate_preserve_order(items: List[int]) -> List[int]: """对输入列表去重,并保持原有顺序。 Args: items: 输入列表。 Returns: 去重后的新列表。 """ seen = set() result = [] for item in items: if item not in seen: seen.add(item) result.append(item) return result打开output/test_generated_code.py,会看到对应测试用例:
import pytest def test_deduplicate_normal_case(): assert deduplicate_preserve_order([1, 2, 2, 3, 3, 3]) == [1, 2, 3] def test_deduplicate_empty_list(): assert deduplicate_preserve_order([]) == [] def test_deduplicate_no_duplicate(): assert deduplicate_preserve_order([4, 5, 6]) == [4, 5, 6]运行测试:
cd output pip install pytest pytest test_generated_code.py -v预期输出:
test_deduplicate_normal_case PASSED test_deduplicate_empty_list PASSED test_deduplicate_no_duplicate PASSED到这里,一个最简单的 AI 辅助编码闭环就跑通了:需求描述 -> 代码生成 -> 测试生成 -> 本地验证。
5. 常见问题与排查思路
在实际使用大模型 API 和 AI 编程工具时,最高频的问题可以归纳为下面几类。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 调用时报 401 Unauthorized | API Key 错误或已过期 | 检查环境变量是否正确,重新生成 API Key |
| 请求超时 | 网络不稳定或模型负载高 | 增加 timeout 参数,加入重试机制 |
| 返回内容包含 Markdown 标记 | 模型默认带格式输出 | 正则提取代码块,或把格式要求写进 Prompt |
| 生成代码缩进错误 | 模型输出被截断 | 检查 max_tokens 是否足够,尝试增大参数 |
| 上下文超限 | 输入内容太长 | 裁剪输入,或把长任务拆成多个短任务 |
| 触发限流 429 | 请求频率过高 | 增加 sleep 间隔,使用指数退避重试 |
| 测试用例不稳定 | 大模型随机采样导致输出波动 | 将 temperature 调低到 0.1 左右 |
下面详细说一下最容易踩坑的两个点。
5.1 API Key 泄露问题
很多人习惯把 API Key 写在代码里,然后提交到 Git 仓库,这是非常危险的习惯。一旦仓库公开,密钥就可能被滥用,造成费用损失。
解决方案是:
- 使用环境变量或
.env文件保存密钥。 .gitignore中忽略.env文件。- 定期轮换 API Key。
- 在云服务商控制台设置消费上限。
5.2 模型输出不稳定
同一个 Prompt,调用两次可能得到不同的代码。这在 AI 编程工具中非常常见。要解决这个问题,可以采取三类手段:
- 调低 temperature:在代码生成场景,
temperature=0.1左右会让输出更稳定。 - 增加约束:在 Prompt 中明确“不要输出额外解释”“只输出代码”,减少无效部分。
- 增加校验:如果生成的代码无法运行,自动把报错信息回传给模型,让它修复。这其实就是 AI Agent 中的“反思”机制。
5.3 生成代码不完整
当需求较大时,模型可能会只输出部分代码,或者截断。这时可以:
- 把大需求拆成多个小需求,依次生成。
- 让模型输出到文件,而不是在对话中直接给全部内容。
- 检查 max_tokens 参数,有些服务商默认值偏小。
6. 最佳实践与工程建议
6.1 把 AI 编码能力沉淀为团队工具
一个人用 Cursor 或 Copilot 写代码,是个人效率提升;但如果团队想规模化使用 AI 编码能力,最好沉淀成统一工具。比如,把上面这种命令行助手接入到 CI 流水线,自动为每次提交生成测试用例。这样,AI 带来的能力就不再是某个人的经验,而是团队的工程资产。
在团队落地时,有几个关键点:
- 统一底层模型:不同模型能力差异明显,尽量固定版本。
- 统一 Prompt 模板:避免每个人风格不同导致输出差异。
- 统一错误处理:用相同的重试和降级逻辑。
- 统一质量评估:准备一组固定的测试用例,评估模型输出质量。
6.2 优化成本:缓存、降级与模型选择
大模型 API 调用不是免费的。生产环境中,成本控制是一个必须考虑的问题。
常用手段包括:
- 缓存:对相同输入的请求做本地缓存,避免重复计费。
- 降级:主模型失败时切换到备用模型。
- 分级:简单任务用轻量模型,复杂任务才用旗舰模型。
- 批处理:把大量小请求合并成一次请求。
以本文的项目为例,如果生成代码后内容没有变化,完全可以缓存到本地 Redis 或文件中,下次直接读取。
6.3 建立 AI 生成代码的审查机制
在代码评审环节,AI 生成的代码和普通代码不应有区别对待。甚至应该更严格,因为模型可能生成“看起来很正确但隐含 bug”的代码。
建议的审查 checklist:
- 是否包含异常处理?
- 是否处理了空值、超长输入等边界条件?
- 是否存在 SQL 注入、路径穿越、反序列化等安全问题?
- 代码是否经过真实运行验证?
- 是否有对应的单元测试?
在任何生产环境中,未经审查的 AI 生成代码都不应该直接合并到主分支。
6.4 安全边界:隐私、合规与审计
在 AI 工程实践中,安全是需要优先考虑的问题。
具体而言:
- 内部代码片段、客户数据、数据库结构和密钥,不应随意发送给外部模型。
- 涉及隐私数据的场景,优先考虑私有化部署模型。
- AI 生成内容需要留痕,记录调用时间、模型版本、输入输出摘要,便于事后审计。
- 一旦发现模型输出包含不当内容,要有熔断和屏蔽机制。
在企业环境中,这些是合规底线。
6.5 结合 Java 技术栈:关注 Spring AI
如果你的团队技术栈是 Java,可以重点关注 Spring AI 项目。它是 Spring 生态官方推出的 AI 应用开发框架,提供了类似 Spring Data 的抽象层,屏蔽了不同大模型服务商之间的差异。
Spring AI 的核心价值在于:
- 统一的 ChatClient 接口。
- 支持 Function Calling。
- 与 Spring Boot 配置体系无缝集成。
- 内置 RAG 相关的向量数据库抽象。
如果你熟悉 Spring Boot,可以从 Spring AI 开始上手 AI 应用开发,这比从零构建 AI 客户端要高效得多。
6.6 关注模型部署与私有化方案
对于数据敏感的企业,模型私有化部署是一个重要方向。常见的部署方案包括:
- vLLM:高性能推理框架。
- Ollama:本地快速部署小模型。
- 云厂商的私有化部署服务。
如果你负责的团队有强烈的数据合规需求,建议把“模型部署”和“应用开发”分开考虑。应用层可以保持接口兼容,底层模型可以随时切换,这是比较稳妥的架构方式。
7. 总结与学习路线
这篇文章从 John Henry 的隐喻出发,讨论了 AI 时代开发者应该如何重新定位自己的工作方式。重点内容包括:
- AI 辅助开发的本质是“人在回路”,开发者需要从执行者变成决策者。
- 大模型 API 的调用逻辑并不复杂,复杂的工程问题在于如何设计 Prompt、处理异常、管理上下文。
- 通过一个完整的实战项目,跑通了“需求描述 -> 代码生成 -> 测试生成”的闭环。
- 生产中必须重视安全问题、成本控制和代码审查机制。
读完这篇文章之后,你可以按下面的路径继续深入:
- 第一步:把文章中的例子跑通,替换成你自己的 API Key。
- 第二步:尝试修改 Prompt 模板,观察输出变化。
- 第三步:研究 Function Calling,让模型可以调用外部工具。
- 第四步:学习 RAG,把企业内部文档变成 AI 的知识库。
- 第五步:接触 LangChain 或 Spring AI 等框架,实现更复杂的 Agent 应用。
如果你在实战中有什么踩坑经验,欢迎在评论区分享。比 AI 更强大的,是“会使用 AI 的人”的判断能力。把 John Henry 的竞争剧本反过来读:不是人和工具赛跑,而是人用工具跑得更远。这才是 AI 时代开发者真正值得练的内功。
