知识目录 /

接入大模型:从第一个 Hello World 到多模态对话

手把手教你接入大模型 API,从最基础的 curl 调用开始,实现单轮对话、持续对话,再到多模态能力。以 OpenAI Chat 协议为例,掌握 LLM 对接的核心技能。

接入大模型:从第一个 Hello World 到多模态对话

在上一篇文章Agent开发入门——从理解到实践中,我们一起写了第一个简单的 Agent。你可能注意到了一个关键细节:在 decide 方法里,我留了一行注释——"这里可以集成大模型进行决策"。

今天,我们就来真正实现这一步。

为什么要接入大模型?

还记得在快速补全你的认知差中讲的吗?LLM 就像一个极其聪明的大脑,但它被锁在了一个盒子里——这个盒子只有输入和输出两个端口,而且只接受文本。

我们写好的 SimpleAgent 现在就像一个"假装聪明"的机器人——它能接收输入、能执行动作,但"思考"的部分只是简单地拼接字符串。它不理解你的问题,也不会推理。

接入大模型,就是给这个机器人换上一个真正的大脑。

LLM 的主要对接接口协议

在正式开始之前,我们先了解一下主流的 LLM 对接方式。目前市面上的大模型,主要有以下三种对接协议:

协议类型 代表厂商 特点
Chat 协议 OpenAI、智谱、月之暗面、百川、DeepSeek 等 最早标准化,消息列表格式,几乎所有 LLM 都兼容
Response 协议 OpenAI(新版)、部分国产模型 单条消息格式,更简洁,适合简单场景
Claude 协议 Anthropic Claude 独立的消息格式,system 提示单独传参,支持更长上下文

为什么我们选择 Chat 协议?

因为它就像 HTTP 之于 Web 开发一样——它是事实上的行业标准

OpenAI 在 2022 年底推出 ChatGPT 时,同时开放了 Chat Completions API。由于它设计得足够简洁、足够好用,几乎所有后来的大模型厂商都选择了兼容这个协议。这意味着:

  • 你学会了一次,就能对接几十个不同的大模型
  • 切换模型时,只需要改 API 地址和 Key,代码基本不用动
  • 社区资源最丰富,遇到问题最容易找到解决方案

这就像你学 Java 时先学 Spring Boot 一样——掌握了它,你就掌握了整个生态。

补充说明: Claude 协议与 Chat 协议的主要区别在于,Claude 把 system 提示放在顶层参数中,而不是 messages 数组里。如果你以后需要对接 Claude,只需要调整一下请求结构即可,核心思路是一样的。

准备工作

在开始之前,你需要准备:

  1. 一个大模型 API Key:可以是 OpenAI 的,也可以是国内兼容 OpenAI 协议的服务商(如智谱、月之暗面、DeepSeek 等)
  2. curl 命令行工具:macOS 和 Linux 自带,Windows 可以使用 Git Bash 或 WSL
  3. 一颗好奇的心:这比你想象的简单得多

为什么先用 curl 而不是直接写 Java?

因为我想让你先看到最原始的请求和响应。就像学 JDBC 之前先理解 SQL 一样——当你亲眼看到 HTTP 请求长什么样,后面写代码时就知道每一行在做什么。

第一步:最基础的 Hello World

让我们从最简单的开始——给大模型发一句话,让它回复我们。

单轮对话(curl 版本)

bash
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "user",
        "content": "你好,请用一句话介绍你自己"
      }
    ]
  }'

把上面的 YOUR_API_KEY 替换成你的真实 Key,然后在终端里运行它。

如果你用的是国内的兼容服务(比如智谱、月之暗面、DeepSeek),只需要把 URL 换成它们的地址即可。比如:

bash
# 智谱 GLM
curl https://open.bigmodel.cn/api/paas/v4/chat/completions \
  # ... 其他部分完全一样

# DeepSeek
curl https://api.deepseek.com/v1/chat/completions \
  # ... 其他部分完全一样

# 月之暗面 Kimi
curl https://api.moonshot.cn/v1/chat/completions \
  # ... 其他部分完全一样

看到了吗?除了 URL 不同,其他部分一模一样。这就是标准化协议的好处。

理解请求格式

让我们仔细看看这个请求的结构:

json
{
  "model": "gpt-3.5-turbo",        // 使用哪个模型
  "messages": [                     // 消息列表
    {
      "role": "user",               // 角色:user(用户)
      "content": "你好,请用一句话介绍你自己"  // 消息内容
    }
  ]
}

messages 是一个数组,每个元素都有两个字段:

  • role:消息的角色,可以是 system(系统提示)、user(用户)、assistant(助手)
  • content:消息的内容

为什么是数组而不是单条消息? 因为要支持多轮对话。我们马上就会讲到。

理解响应格式

运行上面的 curl 命令后,你会收到类似这样的响应:

json
{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "created": 1234567890,
  "model": "gpt-3.5-turbo",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "你好!我是一个AI助手,很高兴为你服务。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 20,
    "completion_tokens": 15,
    "total_tokens": 35
  }
}

关键字段解读:

  • choices[0].message.content:大模型的回复内容
  • choices[0].finish_reason:结束原因,stop 表示正常结束
  • usage:Token 使用情况,用于计费

这就像调用一个 REST API 返回的 JSON 响应一样简单,对吧?

第二步:加入系统提示

在实际应用中,我们通常需要告诉大模型"你是谁"、"你应该怎么做"。这就需要用到 system 角色。

bash
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "你是一个专业的Java技术顾问,擅长Spring Boot和微服务架构。回答问题时请简洁明了,并给出代码示例。"
      },
      {
        "role": "user",
        "content": "如何在Spring Boot中配置数据源?"
      }
    ]
  }'

注意到区别了吗? 我们在 messages 数组的第一项添加了一个 system 角色的消息。这条消息不会显示给用户,但会影响大模型的行为方式。

这就像你在写 Java 代码时,先定义好接口规范,然后再实现具体逻辑一样。

第三步:持续对话

还记得前面说的吗?"所谓的多轮对话,其实是客户端把历史记录拼成了一段长长的文本,每次一起发过去。"

让我们来体验一下:

bash
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "你是一个友好的助手"
      },
      {
        "role": "user",
        "content": "我叫小明,我是一个Java后端开发"
      },
      {
        "role": "assistant",
        "content": "你好小明!很高兴认识你。作为一名Java后端开发,有什么我可以帮你的吗?"
      },
      {
        "role": "user",
        "content": "你还记得我叫什么吗?"
      }
    ]
  }'

大模型会回答:"你叫小明"。 为什么?因为它"看到"了前面所有的对话历史。

这就像你在 Controller 里维护了一个 session,把用户的信息保存下来一样。只不过这里的"session"是整个消息列表,每次都发给大模型。

多轮对话的代码模式

理解了原理之后,多轮对话的实现模式就很清晰了:

java
// 用一个 List 维护对话历史
List<Map<String, String>> messages = new ArrayList<>();

// 添加系统提示
messages.add(Map.of("role", "system", "content", "你是一个友好的助手"));

// 第一轮对话
messages.add(Map.of("role", "user", "content", "我叫小明"));
String reply1 = callLLM(messages);  // 调用大模型
messages.add(Map.of("role", "assistant", "content", reply1));  // 保存助手回复

// 第二轮对话
messages.add(Map.of("role", "user", "content", "你还记得我叫什么吗?"));
String reply2 = callLLM(messages);  // 再次调用,带上历史
messages.add(Map.of("role", "assistant", "content", reply2));

是不是和你平时在 Web 应用中维护用户会话很像? 概念完全一样,只是存储的内容不同。

第四步:多模态对话

什么是多模态? 简单说,就是大模型不只能处理文本,还能处理图片、音频、视频等不同类型的数据。

但请注意:不是所有大模型都支持多模态。 在使用之前,你需要先确认你使用的大模型是否支持。

支持多模态的常见模型

模型 支持的多模态类型
GPT-4V、GPT-4o 图片
Claude 3 图片
Gemini Pro Vision 图片、视频
通义千问 VL 图片
GLM-4V 图片

图片理解示例

如果大模型支持图片,你可以这样发送请求:

bash
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "这张图片里有什么?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "https://example.com/image.jpg"
            }
          }
        ]
      }
    ]
  }'

注意 content 的变化: 从原来的字符串变成了一个数组,每个元素有不同的 type

多模态的条件检查

在实际开发中,我们需要先检查大模型是否支持多模态:

java
/**
 * 检查模型是否支持图片输入
 * 类似于检查数据库是否支持某种特性
 */
boolean supportsVision(String modelName) {
    // 已知支持视觉能力的模型列表
    List<String> visionModels = Arrays.asList(
        "gpt-4o", "gpt-4-vision-preview",
        "claude-3-opus", "claude-3-sonnet",
        "gemini-pro-vision"
    );
    return visionModels.stream()
        .anyMatch(model -> modelName.toLowerCase().contains(model));
}

第五步:用 Java 调用大模型

前面我们用 curl 体验了 OpenAI Chat 协议,现在让我们把它变成真正的 Java 代码。

作为 Java 开发者,你可能已经在想: "这不就是一个 HTTP POST 请求吗?我用 HttpURLConnection 或者 OkHttpClient 就能搞定。"

没错,就是这样。 大模型 API 就是一个普通的 REST 接口,你用你熟悉的任何 HTTP 客户端都能调用。

下面是一个完整的 Java 示例:

java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;

/**
 * 一个简单的 LLM 客户端
 * 用 Java 11+ 的 HttpClient 实现,无需任何第三方依赖
 */
public class SimpleLlmClient {

    private final String apiKey;
    private final String apiUrl;
    private final String model;

    public SimpleLlmClient(String apiKey, String apiUrl, String model) {
        this.apiKey = apiKey;
        this.apiUrl = apiUrl;
        this.model = model;
    }

    /**
     * 调用大模型 API
     * 
     * @param messages 消息列表,格式与 curl 示例一致
     * @return 大模型的回复内容
     */
    public String chat(List<Map<String, String>> messages) throws IOException, InterruptedException {
        // 构建请求体(和 curl 的 -d 参数一模一样)
        String requestBody = buildRequestBody(messages);

        // 创建 HTTP 请求
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(apiUrl))
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + apiKey)
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        // 发送请求并获取响应
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        // 解析响应,提取大模型的回复
        return parseResponse(response.body());
    }

    /**
     * 构建请求体
     * 将 Java 对象转换为 JSON 字符串
     */
    private String buildRequestBody(List<Map<String, String>> messages) {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"model\":\"").append(model).append("\",\"messages\":[");

        for (int i = 0; i < messages.size(); i++) {
            Map<String, String> msg = messages.get(i);
            if (i > 0) sb.append(",");
            sb.append("{\"role\":\"").append(msg.get("role")).append("\",");
            sb.append("\"content\":\"").append(escapeJson(msg.get("content"))).append("\"}");
        }

        sb.append("]}");
        return sb.toString();
    }

    /**
     * 解析响应 JSON,提取 choices[0].message.content
     * 这里用简单的字符串操作,生产环境建议用 JSON 库
     */
    private String parseResponse(String responseBody) {
        // 简单解析,找到 "content":"..." 的内容
        int contentStart = responseBody.indexOf("\"content\":\"") + 11;
        int contentEnd = responseBody.indexOf("\"", contentStart);
        return responseBody.substring(contentStart, contentEnd);
    }

    /**
     * 转义 JSON 特殊字符
     */
    private String escapeJson(String str) {
        return str.replace("\\", "\\\\")
                  .replace("\"", "\\\"")
                  .replace("\n", "\\n")
                  .replace("\r", "\\r")
                  .replace("\t", "\\t");
    }

    /**
     * 使用示例
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        // 配置你的 API Key 和地址
        String apiKey = "YOUR_API_KEY";
        String apiUrl = "https://api.openai.com/v1/chat/completions";
        String model = "gpt-3.5-turbo";

        // 创建客户端
        SimpleLlmClient client = new SimpleLlmClient(apiKey, apiUrl, model);

        // 构建消息列表(和 curl 的 messages 一模一样)
        List<Map<String, String>> messages = List.of(
            Map.of("role", "system", "content", "你是一个友好的Java技术专家"),
            Map.of("role", "user", "content", "你好,请简单介绍一下Spring Boot")
        );

        // 调用大模型
        String reply = client.chat(messages);
        System.out.println("大模型回复:" + reply);
    }
}

运行这段代码,你会看到和 curl 一样的效果。 因为本质上,它们做的是同一件事——发送一个 HTTP POST 请求。

使用 OkHttp 的版本(更常用)

如果你的项目已经在用 OkHttp 或 Retrofit,可以用更简洁的方式:

java
/**
 * 使用 OkHttp 调用大模型
 * 更适合 Spring Boot 项目
 */
public String chatWithOkHttp(List<Map<String, String>> messages) throws IOException {
    OkHttpClient client = new OkHttpClient();
    
    String jsonBody = buildRequestBody(messages);
    RequestBody body = RequestBody.create(jsonBody, MediaType.parse("application/json"));
    
    Request request = new Request.Builder()
            .url(apiUrl)
            .addHeader("Authorization", "Bearer " + apiKey)
            .post(body)
            .build();
    
    try (Response response = client.newCall(request).execute()) {
        return parseResponse(response.body().string());
    }
}

你会发现,无论是用原生的 HttpClient,还是 OkHttp,代码结构都是一样的:

  1. 构建请求体(JSON)
  2. 发送 POST 请求
  3. 解析响应

这就是标准化协议的好处——你只需要写一次对接逻辑,就能适配所有兼容 OpenAI 协议的大模型。

实战:用 curl 完成一次完整的对话流程

让我们把前面学到的知识串起来,完成一个完整的对话流程:

bash
# 第1步:发送第一条消息,建立对话
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {"role": "system", "content": "你是一个Java技术专家"},
      {"role": "user", "content": "你好,我是小明,我在学习Spring Boot"}
    ]
  }'

# 第2步:根据响应,继续对话
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {"role": "system", "content": "你是一个Java技术专家"},
      {"role": "user", "content": "你好,我是小明,我在学习Spring Boot"},
      {"role": "assistant", "content": "你好小明!很高兴你对Spring Boot感兴趣..."},
      {"role": "user", "content": "能给我一个简单的REST API例子吗?"}
    ]
  }'

注意到第2步了吗? 我们把第1步的所有消息(包括大模型的回复)都放了进去,然后再加上新的用户消息。

总结

让我们回顾一下今天学到的内容:

  1. LLM 的三种主要对接协议:Chat 协议(最通用)、Response 协议(更简洁)、Claude 协议(独立格式)
  2. Chat 协议是事实上的行业标准——学会它,你就能对接几乎所有大模型
  3. 请求格式很简单——model + messages 数组
  4. 多轮对话的原理——把历史消息都放在 messages 里一起发送
  5. 多模态需要先检查能力——不是所有模型都支持
  6. Java 调用大模型——就是发一个 HTTP POST 请求,用你熟悉的 HttpClient 或 OkHttp 都行

你已经掌握了对接大模型的核心技能。 接下来,我们就要把这些知识应用到 Agent 中,让你的 SimpleAgentdecide 方法接入真正的大模型。

下一步

在下一篇文章中,我们将:

  • 封装一个通用的 LLM Client(支持多模型切换)
  • 实现完整的对话记忆管理
  • SimpleAgent 升级为真正能"思考"的智能体

请阅读:封装 LLM Client 与实现智能体 记住:你不是在学习一门全新的技术,而是在用你已经熟悉的 Java 技能,连接一个新的能力。 就像你在 Spring 项目中调用其他微服务一样——只是这次,那个"微服务"是一个拥有智能的大模型。

动手试试上面的 curl 命令和 Java 代码吧!当你看到大模型的回复时,你会对接下来的学习充满信心。