阅读路线:先调用模型,再构建智能体
调用模型是 Agent 的基础,但一次模型调用不等于一个 Agent。本系列把原来的长文拆成四篇,每篇解决一个问题:
| 顺序 | 文章 | 学习目标 |
|---|---|---|
| 1 | 本篇:LLM API 模型调用服务 | 读懂一次请求与响应 |
| 2 | 生成参数、Token 与上下文管理 | 控制随机性和预算,维护上下文 |
| 3 | 结构化输出与工具调用 | 把模型建议转换成经过校验的动作 |
| 4 | 错误处理与模型适配器 | 处理失败,隔离供应商差异 |
前置知识:能阅读 Python、JSON,知道 HTTP 请求与响应的基本概念即可。
核对日期:2026-09-21。 通用概念与厂商实现分开说明。示例使用 OpenAI Python SDK,但连接 DeepSeek 时,服务提供方仍是 DeepSeek。API、模型别名及参数支持会变化,请以对应厂商文档为准。
示例验证范围:代码使用 OpenAI Python SDK 3.0.0、Pydantic 2.13.4 做了语法和模拟响应测试,未调用付费模型。实际运行仍需有效密钥、账户权限与兼容模型。
1. LLM API 在 Agent 中负责什么
可以把基础 Agent 理解为一个由应用程序控制的循环:整理上下文 → 请求模型 → 检查结果 → 必要时执行工具 → 把观察结果交回模型。
graph TD
A[用户提出任务] --> B[应用整理指令与上下文]
B --> C[调用 LLM API]
C --> D{检查模型响应}
D -->|最终回答| E[返回用户]
D -->|工具调用请求| F[应用校验参数和权限]
F -->|允许| G[执行工具]
G --> H[记录工具结果]
H --> B
D -->|拒答或异常| I[停止或按策略处理]
F -->|拒绝| I
图中的 LLM 负责生成回答或提出工具调用请求;应用负责权限、执行、状态和停止条件。工具可以是查询数据库、读取文件等函数。自定义函数不会因为出现在模型响应中,就自动在你的电脑上运行。[1]
本文先把“调用模型”这一格讲清楚,工具闭环放到第三篇。
2. 先分清模型、API 和 SDK
| 名词 | 是什么 | 不代表什么 |
|---|---|---|
| 模型 | 实际执行推理的模型或服务别名 | 不等于接口协议 |
| API | 请求与响应的协议,例如 Chat Completions、Responses | 不等于某个 Python 包 |
| SDK | 帮助构造请求、解析响应的客户端库 | 安装了 SDK,不表示服务端支持 SDK 的全部方法 |
| 兼容接口 | 另一家服务实现了某种请求/响应格式 | 不表示参数、状态管理、工具能力完全一致 |
例如,OpenAI(base_url=...) 可以连接实现相应协议的其他服务。能调用 client.chat.completions.create(),不能单凭这一点推断它也支持 client.responses.create()。
本次核对时,DeepSeek 官方已经支持 Responses API,所以原文用 OpenAI SDK 调 DeepSeek Responses 的方向没有错;需要补充的是兼容范围,而不是把它误判为“不支持”。[2]
3. Chat Completions:以消息列表为中心
3.1 messages 是本次请求的上下文
1 | 请求:messages[] |
choices[] 表示候选结果。普通单候选请求通常读取第一项,但message.content 不是整个响应的唯一入口:工具调用可能放在 tool_calls 中,文本也可能为 None。还要读取 finish_reason 和 usage。[3][4]
| role | 工程含义 | 注意事项 |
|---|---|---|
system |
应用设置的全局指令 | 不要把外部网页、工具结果提升成系统指令 |
developer |
OpenAI 部分模型使用的开发者指令角色 | 不是所有兼容服务都支持相同语义 |
user |
用户请求及相关输入 | 不能仅凭 role 判断内容可信 |
assistant |
模型先前的输出 | 工具调用也属于模型输出 |
tool |
工具返回的观察结果 | 用调用 ID 与相应工具请求关联 |
把消息全部拼成一个字符串并非技术上“无法调用”,但会丢失协议层的来源、角色及工具关联信息,不利于上下文管理。角色分层是组织信息的手段,不是阻止提示注入的安全沙箱。
3.2 最小可运行示例:DeepSeek Chat Completions
本系列使用 Python 3.10+。在自己的示例项目中安装依赖,不需要安装 Agent 框架:
1 | python -m pip install openai python-dotenv 'pydantic>=2,<3' |
在示例项目目录创建 .env,并把它加入 .gitignore:
1 | DEEPSEEK_API_KEY=替换为你自己的密钥 |
模型名说明:截至 2026-09-21 核对日,官方推荐使用
deepseek-flash。原文中的deepseek-v4-flash仍被接受,但已经作为旧别名路由到 DeepSeek-V4.1-Flash;不能再用这个别名声称复现了旧模型实验。[5]
下面代码可独立保存为 Python 文件执行:
1 | import os |
这里使用的是 OpenAI SDK + DeepSeek API,不是“DeepSeek 官方 SDK”。max_tokens 和 thinking 按 DeepSeek 文档配置;换供应商时不能无条件照搬。[4]
真实诗句、token 数和延迟每次可能不同。教学上应观察“文本、结束原因、用量”三个部分,不必把一整段 SDK 对象打印日志当成接口规范。
4. Responses:以类型化输入项和输出项为中心
4.1 input 不只是 messages 改名
Responses 的 input 可以是字符串,也可以是输入项列表。列表既能承载带 role 的消息,也能承载函数调用结果等项目;output[] 则是一次响应中的输出项序列,不是多个候选答案。[6]
1 | response |
这是形状示意,不表示每次都会返回全部项目,也不表示输出项顺序固定。
需要纠正三个常见误解:
- 仍然可以使用
system/developer消息,不是只能有user/assistant。顶层instructions是设置指令的便利方式,不意味着input禁止系统消息。[2][6] - 拒答通常是
message.content[]中的refusal内容块,不是与message并列的顶层输出项。[7] - 不要固定访问
output[0].content[0].text。首项可能是推理或工具请求;纯文本展示可用 Python SDK 的response.output_text,调度逻辑则要检查状态和项目类型。[6]
output_text 是 SDK 汇总文本的便利属性,不要假设所有原始 HTTP 响应都包含同名顶层字段。它也不会替你执行工具或处理失败。
4.2 最小可运行示例:DeepSeek Responses
沿用上面的 .env,下面是另一个可独立运行的脚本:
1 | import os |
这两个脚本都刻意限定为“非流式、无工具、纯文本”。生产应用应分类处理异常,不是把所有情况永久转换成同一种 RuntimeError。
4.3 兼容 Responses,不等于拥有全部 OpenAI 功能
根据 DeepSeek 核对日的兼容说明:[2]
| 能力 | DeepSeek Responses 的边界 |
|---|---|
| 文本输入输出、自定义函数调用 | 支持 |
previous_response_id、conversation |
不支持服务端会话续接,需要应用回传上下文 |
store、background |
不支持,不能据此设计持久会话或后台任务 |
OpenAI 内置 web_search、file_search 等工具 |
不能按 OpenAI 能力使用,兼容表标为忽略 |
developer 消息角色 |
当前按 user 处理,不能假设与 OpenAI 指令优先级相同 |
| 未支持参数 | 某些参数被静默忽略,HTTP 成功不代表参数生效 |
因此,多供应商应用除了统一字段,还需要确认实际能力与语义。
5. 如何选择 Chat Completions 与 Responses
| 维度 | Chat Completions | Responses |
|---|---|---|
| 输入组织 | messages[] |
字符串或输入项列表,可用 instructions |
| 输出组织 | choices[] 中的消息 |
output[] 中的类型化输出项 |
| 读取纯文本 | 检查状态后读取 message.content |
检查状态后使用 SDK 的 output_text |
| 自定义工具请求 | message.tool_calls |
output[] 中的 function_call |
| 自定义工具执行者 | 应用程序 | 应用程序 |
| 多轮状态 | 通常由应用维护消息 | OpenAI 可使用会话关联;其他供应商要查兼容表 |
| 多模态 | 取决于模型与端点能力 | 同样取决于模型与端点能力 |
不要按“聊天用 Chat、Agent 必须用 Responses”机械划分。 两者都可以支持工具循环。对 OpenAI 新项目,官方推荐 Responses;对兼容生态、已有应用或特定供应商,应以所需能力、迁移成本及评测结果选型。[1][6]
OpenAI Responses 中可通过 previous_response_id 关联前次响应,但这不是无限记忆,也不是历史上下文从此不消耗预算。跨请求的应用指令应按接口约定明确维护。[8]
6. 流式输出:增量不等于完整结果
非流式调用返回完整响应;流式调用逐步收到事件或片段。界面可以边收边展示,但程序不能把任意片段当作完整 JSON 或可执行工具参数。
- Chat Completions 通常读取
choices[].delta,不是每个 chunk 都有完整message。 - Responses 按事件类型读取,例如
response.output_text.delta。 - 需要等到终止状态,确认是否完整、失败或截断;连接断开不代表正常结束。
- 工具参数必须收集完整并校验后才能执行;用量是否在最后返回,要看厂商实现。[2][4]
7. 本篇小结
记住三层即可:SDK 是客户端,API 是协议,模型是能力来源。
读一次响应时,先问:
- 请求有没有成功到达并完成?
- 返回的是文本、拒答,还是工具调用?
- 有没有截断?消耗了多少 token?
下一篇:生成参数、Token 与上下文管理。
参考资料
以下均为官方资料,核对日期为 2026-09-21;兼容矩阵随服务更新而变化。