OpenAI API使用教程:快速接入AI能力

霸气_导师
2025-12-14 01:20
阅读 614

去年十月,成都的秋天刚刚有点凉意,我还在啃《深入理解计算机系统》。作为一个双非院校大二学生,白天上课、晚上刷LeetCode,周末还得去图书馆抢座——典型的“卷又卷不动,躺又躺不平”的状态。但谁想到,就在我用MacBook Air M1跑第一个Spring Boot项目时,命运(其实是隔壁组的学长)给我丢了一个需求:“能不能在咱们那个小破论坛里加个AI回复功能?”

我心想,这不就是调个API的事儿?结果……打脸来得太快,就像龙卷风。


起因:被“赋能”了

事情是这样的。我们学校有个学生技术社区,用的是自己搭的Spring Boot后端 + Vue前端,部署在阿里云学生机上(99一年那种,别笑)。产品负责人(其实就是辅导员兼任的)突然说:“现在不是AI很火嘛?咱们也搞点智能互动,提升用户粘性!”——典型的PPT式需求,连PRD都没写清楚。

更离谱的是,Deadline定在下周五上线,而今天已经是周三晚上十点。我坐在玉林路的小茶馆里,捧着一杯冰美式,看着微信里产品经理发来的“这个功能很简单吧?”的消息,差点一口咖啡喷出来。

但没办法,为了简历上能多一行“主导AI模块开发”,硬着头皮也得上。


初探OpenAI API:你以为的简单,其实全是坑

一开始我以为:不就是HTTP请求发个JSON,拿个response回来渲染一下?结果光是认证就卡了我俩小时。

OpenAI用的是Authorization: Bearer sk-xxx,但Spring Boot里怎么优雅地管理这个key?总不能硬编码在代码里吧?Git提交一不小心就泄露了,轻则被封号,重则被扫走余额——听说有人一天被刷掉几千刀,想想就冒冷汗。

安全第一:配置别乱放

我最后用了Spring Boot的application.yml + 环境变量:

openai:
  api-key: ${OPENAI_API_KEY}
  model: gpt-3.5-turbo
  timeout: 30s

然后本地启动时:

export OPEN AI_API_KEY=sk-xxxxxx
./mvnw spring-boot:run

生产环境直接让运维(其实就是我自己)在服务器上配环境变量。这样至少不会把密钥提交到GitHub——虽然我的仓库是私有的,但保不齐哪天手滑点成public。

血泪教训:千万别在代码里写死API Key!我见过学长因为这事被GitHub机器人自动关了账号,哭着求客服解封。


封装Client:别每次都new RestTemplate

第一次我直接在Controller里写了:

RestTemplate restTemplate = new RestTemplate();
// 构造headers、body、发送请求...

结果测试时发现超时、重试、日志都没法统一处理。而且GPT返回的内容有时候带Markdown,前端渲染还出问题。

于是痛定思痛,写了个OpenAIService

@Service
@Slf4j
public class OpenAIService {

    private final RestTemplate restTemplate;
    private final String apiKey;
    private final String model;

    public OpenAIService(@Value("${openai.api-key}") String apiKey,
                         @Value("${openai.model}") String model) {
        this.apiKey = apiKey;
        this.model = model;
        this.restTemplate = createRestTemplate();
    }

    private RestTemplate createRestTemplate() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(30000); // OpenAI默认最长60s,但咱不能等太久
        return new RestTemplate(factory);
    }

    public String generateResponse(String prompt) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(apiKey);
        headers.setContentType(MediaType.APPLICATION_JSON);

        Map<String, Object> requestBody = Map.of(
            "model", model,
            "messages", List.of(Map.of("role", "user", "content", prompt)),
            "temperature", 0.7
        );

        HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);

        try {
            ResponseEntity<OpenAIResponse> response = restTemplate.postForEntity(
                "https://api.openai.com/v1/chat/completions",
                request,
                OpenAIResponse.class
            );
            return response.getBody().getChoices().get(0).getMessage().getContent().trim();
        } catch (Exception e) {
            log.error("调用OpenAI失败: {}", e.getMessage());
            throw new RuntimeException("AI暂时罢工,请稍后再试");
        }
    }
}

这里有几个细节:

  • 超时设置很重要:GPT-3.5一般几秒内返回,但网络抖动或高负载时可能卡住。用户可不想等一分钟。
  • 异常要兜底:别让用户看到500错误,至少给个友好提示。
  • 日志记录prompt:方便debug,但千万别记API Key和完整response,有隐私风险!

实战场景:论坛自动回复机器人

我们的需求是在用户发帖后,AI自动生成一个“参考回复”。比如有人问:“Spring Boot怎么整合Redis?”,AI就回一段示例代码。

但直接丢问题过去,效果很差。GPT经常答非所问,或者啰嗦半天。后来我加了system prompt

“你是一个Java后端开发者,擅长Spring Boot。请用简洁、专业的语言回答技术问题,必要时提供代码示例。不要解释你是AI。”

效果立竿见影!准确率从60%提到85%以上。

// 在messages里加一条system消息
List<Map<String, String>> messages = new ArrayList<>();
messages.add(Map.of("role", "system", "content", SYSTEM_PROMPT));
messages.add(Map.of("role", "user", "content", userQuestion));

开发心得:Prompt engineering真的是一门玄学。有时候改一个词,效果天差地别。建议建个Excel记录不同prompt的效果,比瞎调强多了。


性能与成本:别让老板破产

GPT-3.5按token计费,一次对话大概0.002美元。看起来不多,但如果论坛每天有1000个帖子,每人触发一次AI回复,一个月就是60美元——对我们这种学生项目来说,已经算巨款了。

所以必须做缓存频率限制

我用Redis做了两级缓存:

  1. 相同问题直接返回历史答案(比如“如何配置DataSource?”这种高频问题)
  2. 用户限流:每个IP每分钟最多请求3次
@Cacheable(value = "aiResponses", key = "#prompt")
public String getCachedResponse(String prompt) {
    return openAIService.generateResponse(prompt);
}

同时,在Nginx层面加了限流(虽然我们没用Nginx,但假装有 😅)。

策略 成本降低 用户体验影响
缓存相同问题 ~40% 几乎无感
IP限流 ~20% 偶尔提示“操作太频繁”
截断长输入 ~15% 需要前端配合

测试环节:被QA虐哭的一晚

上周五晚上,我刚提测,测试同学(我们社团的学妹)就甩过来一堆Bug:

  • “输入‘你好’,AI回了300字人生哲理!”
  • “特殊字符导致JSON解析失败”
  • “中文标点被转义了”

原来是我没处理输入清洗和输出转义。

赶紧补上:

// 输入清洗:去掉危险字符、限制长度
String safePrompt = prompt.replaceAll("[<>]", "")
                          .substring(0, Math.min(prompt.length(), 500));

// 输出转义:防止XSS
String escapedContent = StringEscapeUtils.escapeHtml4(aiResponse);

还加了单元测试:

@Test
void shouldReturnValidJsonWhenInputIsNormal() {
    String result = openAIService.generateResponse("什么是Spring Boot?");
    assertThat(result).isNotEmpty().doesNotContain("<script>");
}

那一晚,我凌晨两点才离开实验室,路上还在想:写代码容易,写健壮的代码难啊


上线后:意外收获

功能上线后,论坛活跃度涨了30%。更神奇的是,有些用户开始故意问奇怪问题来“调戏”AI,比如“你能帮我写情书吗?”、“用李白的风格写一段Controller代码”。

虽然这些不属于技术范畴,但说明AI的“人格化”能带来情感连接——这可能是产品经理没想到的价值。

不过最让我开心的,是收到了一家成都本地初创公司的实习面试邀请。他们看到我在GitHub上开源了这个模块,直接问:“你对LLM应用落地有什么看法?”

那一刻,我觉得熬夜值了。


总结:给同样在折腾的你

作为一个非科班、没大厂背景的学生,我能搞定OpenAI接入,你肯定也可以。几点真心话:

  1. 别怕动手:API文档其实很友好,官方例子跑通就成功一半。
  2. 安全永远第一:API Key、用户数据、XSS,一个都不能漏。
  3. Prompt是核心资产:花时间打磨它,比调参重要得多。
  4. 监控和日志:上线后一定要看调用量、错误率、响应时间。
  5. 别追求完美:先跑起来,再优化。我们第一版连缓存都没有,但用户反馈很好。

最后,分享一句我贴在显示器上的话:

“代码可以重构,机会只有一次。”

如果你也在成都,用Mac写Spring Boot,喜欢抠底层原理——欢迎来玉林路一起喝杯咖啡,聊聊AI,或者吐槽产品经理。反正生活节奏舒服,bug慢慢修嘛。


附:关键依赖(pom.xml)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.10.0</version>
</dependency>

注:本文所有代码已在GitHub开源,搜索“campus-forum-ai”就能找到。别忘了Star~(手动狗头)

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝