用 Python 接入大模型 API:从 0 到 1 实现文本分类/抽取/匹配

0 阅读12分钟

写在前面

随着ChatGPT、通义千问等大语言模型的兴起,越来越多的开发者希望在自己的应用中集成AI能力,我决定通过实践来学习大模型API的调用方法。

我使用Python作为开发语言,采用阿里云百炼的通义千问模型(qwen3-max)作为基础模型,同时也体验了本地Ollama部署的qwen3:4b模型。

主题:围绕"科技资讯"这个方向,一步步实现文本分类信息抽取语义匹配三个常见场景。

1.环境准备

1.1 安装python

www.python.org/downloads/

验证 Python 环境是否安装成功

# 通用命令(推荐,所有系统兼容)
python3 --version
# 补充:Windows系统若已配置PATH,也可执行
python --version

验证 pip3(Python 包管理工具)pip3 是 Python3 默认的包管理工具类似于安装Nodejs中npm包管理工具,用于安装第三方库,验证命令:

# 通用命令
pip3 --version
# Windows补充命令
pip --version

安装成功 image.png

2. OpenAI 库的基础使用

Python 库已经成为了调用大模型的"事实标准"。不管是 OpenAI 官方、阿里云 DashScope、还是本地 Ollama,都提供了 OpenAI 兼容的接口。这意味着写一套代码,换个 base_url 就能切换模型。

2.1 安装openai

pip install openai

模型可以使用阿里云百炼,也可以使用 Ollama本地部署模型,先启动 Ollama 并拉取模型:

image.png

2.2 第一次调用OpenAI

最简单的调用只需要三步:创建 client → 构造 messages → 发起请求。

from openai import OpenAI

# 1. 创建 client 对象
client = OpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    # api_key="YOUR_API_KEY"  # 如果环境变量没配,这里需要手动传
)

# 2. 调用模型
response = client.chat.completions.create(
    model="qwen3-max",
    messages=[
        {"role": "system", "content": "你是一个科技资讯助手"},
        {"role": "user", "content": "2026年AI领域有哪些重要趋势?"},
    ]
)

# 3. 打印结果
print(response.choices[0].message.content)

image.png

api_key可以直接配置到全局环境变量中~./zshrc,就无需在创建client时明文传入了

export OPENAI_API_KEY="your key"
export DASHSCOPE_API_KEY="your key"

关键点拆解

参数作用
base_urlAPI 地址,换这个就能切换不同服务商
model模型名称,不同平台名称不一样
messages对话历史,system 设定人设,user 是用户输入,assistant 是模型回复
role三条消息角色:system(系统设定)、user(用户)、assistant(助手)

system 消息就像是给演员的"角色剧本",告诉模型"你是谁、该怎么做"。assistant 消息可以用作 few-shot 示例,让模型"照着学"。

2.3 流式输出:让用户体验"打字机"效果

非流式调用会等模型全部生成完才返回,用户可能要等十几秒。开启 stream=True 后,模型每生成一段就返回一段,实现类似 ChatGPT 的打字机效果。

from openai import OpenAI

client = OpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

response = client.chat.completions.create(
    model="qwen3-max",
    messages=[
        {"role": "system", "content": "你是一个科技资讯助手,回答问题时请简洁"},
        {"role": "user", "content": "什么是大语言模型?用一句话解释"},
    ],
    stream=True     # 开启流式输出
)

# 流式返回的结果需要遍历 chunk
for chunk in response:
    print(chunk.choices[0].delta.content, end="", flush=True)

流式处理要点

  • chunk.choices[0].delta.content 是每一小段文本,可能是几个字或一个词
  • end="" 避免 print 自动换行,flush=True 立即刷新到终端
  • 第一个 chunk 的 delta.content 可能为 None,生产环境需要做空值判断

2.4 附带历史消息:让模型"记住"上下文

大模型本身是无状态的,每次调用都是独立的。要实现多轮对话,需要把之前的消息一起发过去。

from openai import OpenAI

client = OpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 把之前的对话历史全部带上
response = client.chat.completions.create(
    model="qwen3-max",
    messages=[
        {"role": "system", "content": "你是科技资讯助手,回答简洁"},
        {"role": "user", "content": "英伟达最新一代GPU是什么?"},
        {"role": "assistant", "content": "英伟达最新一代数据中心GPU是Blackwell架构的B200。"},
        {"role": "user", "content": "它比上一代性能提升多少?"},   # 这个问题依赖上文
    ],
    stream=True
)

for chunk in response:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

为什么需要历史消息? 第二个问题"它比上一代性能提升多少?"中的"它"指代的是前面提到的 B200。如果不带上历史消息,模型就不知道"它"是谁。

3. 提示词优化实战

提示词(Prompt)决定了模型的输出质量。下面通过三个实战案例,展示几种最常用且效果立竿见影的提示词优化技巧。

统一主题:所有案例都围绕"科技资讯处理"场景,包括科技文章分类、关键信息抽取、语义相似度判断。

3.1 案例一:科技文本分类(Few-Shot 提示)

场景:给定一段科技相关的文本,自动判断它属于哪个类别。

核心思路:Few-Shot Learning

直接让模型分类,它可能按自己的理解来。但如果给它几个"输入→输出"的示例,它就能照葫芦画瓢,准确率大幅提升。这就是 Few-Shot Prompting

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1"  # 本地 Ollama
)

# 示例数据:类别 → 文本
examples_data = {
    'AI前沿': 'OpenAI今日发布了GPT-5,该模型在多项基准测试中超越前代,特别是在数学推理和代码生成方面表现突出。',
    '产品发布': '苹果公司在WWDC上正式推出了Vision Pro二代,售价降低至2000美元,新增手势追踪和眼动交互功能。',
    '行业分析': '据IDC最新报告,2025年Q2全球AI芯片市场规模达到180亿美元,同比增长65%,其中GPU占比超过70%。',
    '投融资': 'AI编程助手Cursor完成1亿美元C轮融资,估值达到100亿美元,红杉资本领投。'
}

# 待分类的文本
questions = [
    "今日,华为在开发者大会上发布了HarmonyOS NEXT正式版,全面支持纯血鸿蒙应用生态,不再兼容Android应用。",
    "据市场分析机构Gartner预测,到2026年全球企业级AI软件支出将突破5000亿美元,SaaS和AI Agent是主要增长点。",
    "字节跳动旗下豆包大模型团队宣布开源新一代多模态模型,支持文本、图像和视频的联合理解与生成。",
    "今天天气真不错,适合出去散步。"  # 干扰项,不属于任何科技类别
]

# 构造 messages:system 说明任务 + 示例对话
messages = [
    {
        "role": "system",
        "content": "你是科技资讯专家,请将文本分类为['AI前沿', '产品发布', '行业分析', '投融资']之一,不属于任何类别的回答'不清楚类别'。以下是示例:"
    },
]

# 把示例数据转为 user/assistant 对话对
for category, text in examples_data.items():
    messages.append({"role": "user", "content": text})
    messages.append({"role": "assistant", "content": category})

# 批量分类
for q in questions:
    response = client.chat.completions.create(
        model="qwen3:4b",
        messages=messages + [{"role": "user", "content": f"请分类:{q}"}]
    )
    print(f"文本: {q[:30]}... → 类别: {response.choices[0].message.content}")

消息构造示意图

messages 最终结构:
┌─────────────────────────────────────────────────┐
│ system: 你是科技资讯专家,请分类为[...]            │
│ user:   OpenAI今日发布了GPT-5...                  │
│ assistant: AI前沿                                │
│ user:   苹果公司在WWDC上正式推出...                 │
│ assistant: 产品发布                               │
│ user:   据IDC最新报告...                          │
│ assistant: 行业分析                               │
│ user:   AI编程助手Cursor完成...                    │
│ assistant: 投融资                                 │
│ user:   请分类:今日,华为在开发者大会上...         │  ← 实际要分类的
└─────────────────────────────────────────────────┘

image.png

3.2 案例二:科技信息抽取(结构化输出)

场景:从一篇科技新闻中提取关键字段(日期、公司名、产品名、金额等),并以 JSON 格式返回。

核心思路:JSON 结构化输出 + Few-Shot 示例

直接让模型"提取信息",它可能返回自然语言描述。但如果要求它输出 JSON,并在示例中展示格式,它就能稳定返回结构化数据,方便后续程序处理。

from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:11434/v1")

# 定义要抽取的字段
schema = ['日期', '公司名称', '产品名称', '融资金额', '投资方']

# 示例数据
examples_data = [
    {
        "content": "2025年3月15日,AI编程公司Cursor宣布完成1亿美元C轮融资,由红杉资本领投,Andreessen Horowitz跟投。该公司主打产品Cursor AI Editor已成为开发者热门工具。",
        "answers": {
            "日期": "2025年3月15日",
            "公司名称": "Cursor",
            "产品名称": "Cursor AI Editor",
            "融资金额": "1亿美元",
            "投资方": "红杉资本、Andreessen Horowitz"
        }
    },
    {
        "content": "昨日,华为在深圳总部正式发布Mate 70系列手机,搭载全新麒麟9100芯片,起售价5499元。",
        "answers": {
            "日期": "昨日",
            "公司名称": "华为",
            "产品名称": "Mate 70系列",
            "融资金额": "原文未提及",
            "投资方": "原文未提及"
        }
    }
]

# 待抽取的文本
questions = [
    "2025年6月1日,月之暗面科技宣布完成10亿元人民币B轮融资,高榕资本独家领投,公司将用于Kimi智能助手的产品迭代。",
    '特斯拉于上海超级工厂投产了搭载HW5.0芯片的新一代自动驾驶硬件,马斯克称这是"史上最大升级"。'
]

# 构造 messages
messages = [
    {
        "role": "system",
        "content": f"你是信息抽取专家。请从文本中提取 {schema} 这些字段,以JSON格式输出。如果某字段信息不存在,填'原文未提及'。参考以下示例:"
    },
]

# 追加示例
for example in examples_data:
    messages.append({"role": "user", "content": example["content"]})
    messages.append({
        "role": "assistant",
        "content": json.dumps(example["answers"], ensure_ascii=False)
    })

# 批量抽取
for q in questions:
    response = client.chat.completions.create(
        model="qwen3:4b",
        messages=messages + [{"role": "user", "content": f"请抽取以下文本的信息:{q}"}]
    )
    result = response.choices[0].message.content
    print(f"原文: {q[:40]}...")
    print(f"抽取结果: {result}\n")

image.png 关键技巧

  1. 明确字段列表:在 system 消息中列出要抽取的所有字段
  2. JSON 格式约束:要求模型输出 JSON,方便后续 json.loads() 直接解析
  3. 缺失值处理:约定"原文未提及"作为默认值,避免模型编造信息
  4. 示例中展示完整格式:模型会严格模仿示例的 JSON 结构

实际使用中,拿到结果后建议用 json.loads() 验证一下,确保返回的是合法 JSON:

parsed = json.loads(result)
print(parsed["公司名称"])  # 直接按 key 取值

3.3 案例三:科技文本匹配判断(对比推理)

场景:给定两句话,判断它们描述的是否是同一件事/同一主题。这在资讯去重、推荐系统等场景很常见。

核心思路:正负示例对比 + 格式化输入

让模型判断两句话是否"匹配",关键是要给它正面示例(匹配)负面示例(不匹配),让它学会区分。

from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1")

# 正负示例
examples_data = {
    "是": [   # 这两句说的是同一件事
        ("英伟达发布Blackwell架构B200芯片,性能比H100提升30倍。", "英伟达推出新一代GPU B200,采用Blackwell架构,性能远超H100。"),
        ("字节跳动旗下豆包大模型团队宣布开源新一代多模态模型。", "豆包团队开源了多模态大模型。"),
    ],
    "不是": [  # 两句话各说各的
        ("英伟达股价今日下跌5%。", "苹果宣布Vision Pro二代正式发布。"),
        ("特斯拉上海工厂开始生产HW5.0芯片。", "SpaceX星舰完成第六次试飞。"),
    ]
}

# 待判断的文本对
questions = [
    ("华为发布HarmonyOS NEXT正式版,不再兼容Android。", "纯血鸿蒙系统正式发布,安卓应用将无法运行。"),
    ("AI芯片市场Q2增长65%。", "AI编程助手Cursor完成1亿美元融资。"),
    ("小米SU7交付量突破10万台。", "小米汽车市场表现强劲,累计交付超10万辆SU7。"),
]

# 构造 messages
messages = [
    {
        "role": "system",
        "content": "你帮我完成文本匹配判断。我会给你两个句子,用[]包围,请判断它们是否描述同一件事,只回答'是'或'不是'。参考以下示例:"
    },
]

# 追加正负示例
for label, pairs in examples_data.items():
    for s1, s2 in pairs:
        messages.append({"role": "user", "content": f"句子1:[{s1}],句子2:[{s2}]"})
        messages.append({"role": "assistant", "content": label})

# 批量判断
for s1, s2 in questions:
    response = client.chat.completions.create(
        model="qwen3:4b",
        messages=messages + [{"role": "user", "content": f"句子1:[{s1}],句子2:[{s2}]"}]
    )
    print(f"句子1: {s1[:35]}...")
    print(f"句子2: {s2[:35]}...")
    print(f"匹配结果: {response.choices[0].message.content}\n")

image.png 关键技巧

  1. [] 包裹句子:让模型清楚知道哪里是句子边界,避免混淆
  2. 正负示例均衡:匹配和不匹配的例子各给几个,防止模型偏向某一方
  3. 约束输出:要求"只回答'是'或'不是'",避免模型输出多余解释

4. 核心知识点总结

4.1 OpenAI SDK 调用流程

不管什么场景,调用流程都是固定的三步:

# 第一步:创建 client
client = OpenAI(base_url="xxx", api_key="xxx")

# 第二步:构造 messages 并调用模型
response = client.chat.completions.create(
    model="模型名",
    messages=[...],
    stream=True/False
)

# 第三步:处理结果
# 非流式:response.choices[0].message.content
# 流式:遍历 response,每次取 chunk.choices[0].delta.content

4.2 提示词优化的三个实用技巧

技巧适用场景核心做法
Few-Shot 示例分类、抽取、判断在 messages 中塞入几个"输入→输出"的示例对
JSON 结构化信息抽取、API 返回要求模型输出 JSON,并在示例中展示格式
格式化输入文本对比、多段输入用特殊符号(如 [])标注边界,避免混淆

4.3 本地 vs 云端模型选择

本地 Ollama云端 DashScope
base_urlhttp://localhost:11434/v1https://dashscope.aliyuncs.com/compatible-mode/v1
模型示例qwen3:4bqwen3-max
优点免费、隐私安全、离线可用模型更强、无需本地算力
缺点小模型能力有限需要 API Key、按量计费

4.4 JSON 基础回顾

提示词优化案例中频繁用到 JSON 序列化/反序列化,这里简单回顾:

import json

# dict → JSON 字符串
data = {"name": "张三", "age": 25}
json_str = json.dumps(data, ensure_ascii=False)
# '{"name": "张三", "age": 25}'

# JSON 字符串 → dict
parsed = json.loads(json_str)
# {'name': '张三', 'age': 25}

# list → JSON 字符串
items = [{"name": "A"}, {"name": "B"}]
json.dumps(items, ensure_ascii=False)
# '[{"name": "A"}, {"name": "B"}]'

ensure_ascii=False 很重要,否则中文会被转成 \uXXXX 编码,不方便阅读和调试。

写在最后

我们做的,并不只是“调用一个大模型 API”,而是在尝试一种新的开发方式。

过去,我们习惯用代码去精确描述规则,而现在,我们开始用自然语言去“定义能力”。

这两者的区别在于:

  • 代码解决的是确定性问题
  • 大模型更擅长处理模糊、复杂、难以穷举规则的问题