会调模型 API 还不够:用 Python 开发 LLM 应用的能力清单

2026-09-29 30 预计阅读时间: 1 分钟
来源: realpython.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Python LLM 应用开发已经不只是“把问题发给模型,再打印答案”。一个可用的系统通常横跨模型 API、提示词设计、RAG、智能体、工具调用与 MCP,还要处理超时、成本、安全和评测。真正值得检验的,不是记住多少术语,而是能否把这些组件组合成一个行为可预测、故障可定位的应用。

从一次 API 调用开始,但不要停在那里

最基础的能力,是稳定地调用模型 API。除了请求格式,还应考虑环境变量、超时、错误响应、模型配置和结构化输出。

下面是一个可直接改造的 Python 示例。它假设模型服务提供与 OpenAI Chat Completions 类似的 HTTP 接口;运行前需要按实际供应商修改 LLM_BASE_URL、LLM_MODEL 和密钥。

import json
import os
import sys
import urllib.error
import urllib.request

BASE_URL = os.getenv("LLM_BASE_URL", "https://api.openai.com/v1")
API_KEY = os.environ["LLM_API_KEY"]
MODEL = os.getenv("LLM_MODEL", "gpt-4o-mini")


def ask_model(question: str) -> str:
    payload = {
        "model": MODEL,
        "temperature": 0,
        "messages": [
            {
                "role": "system",
                "content": (
                    "你是 Python 技术助手。回答必须简洁;"
                    "如果信息不足,明确说明缺少什么,不要编造。"
                ),
            },
            {
                "role": "user",
                "content": f"请回答下面的问题:\n<question>\n{question}\n</question>",
            },
        ],
    }

    request = urllib.request.Request(
        f"{BASE_URL.rstrip('/')}/chat/completions",
        data=json.dumps(payload).encode("utf-8"),
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        method="POST",
    )

    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            result = json.loads(response.read().decode("utf-8"))
            return result["choices"][0]["message"]["content"]
    except urllib.error.HTTPError as exc:
        detail = exc.read().decode("utf-8", errors="replace")
        raise RuntimeError(f"模型 API 返回 {exc.code}: {detail}") from exc


if __name__ == "__main__":
    question = " ".join(sys.argv[1:]) or "解释 Python 生成器适合解决什么问题"
    print(ask_model(question))

运行方式:

export LLM_API_KEY="替换为你的密钥"
export LLM_BASE_URL="https://api.openai.com/v1"
export LLM_MODEL="gpt-4o-mini"
python app.py "RAG 与模型微调有什么区别?"

这段代码只是基线。进入生产环境后,还需要增加重试与指数退避、速率限制、请求追踪、令牌用量记录,以及对响应字段缺失或格式异常的处理。

提示词也不应被当成一段随意拼接的字符串。系统规则、用户输入、检索资料和工具返回值应有清晰边界。尤其不要把检索到的网页内容直接视为可信指令,因为其中可能包含提示词注入文本。

RAG 的难点在检索链路,而不只是向量数据库

RAG,也就是检索增强生成,解决的是“回答前先找到相关外部资料”的问题。一个完整链路通常可以拆成:

  1. 文档解析与清洗;
  2. 分块并保存来源、标题、时间等元数据;
  3. 为查询召回候选内容;
  4. 过滤或重排候选片段;
  5. 将证据交给模型生成答案;
  6. 返回引用,并评估答案是否受证据支持。

判断一个 RAG 系统时,应把“没找到资料”和“模型没有正确使用资料”区分开。前者属于检索问题,后者更接近生成或提示词问题。只检查最终答案,很难定位故障发生在哪一层。

可以用下面的测试集格式保存最小评测数据,并在更换分块策略、嵌入模型或重排器后重复执行:

{"question":"退款申请需要哪些材料?","expected_doc_ids":["policy-refund-2025"],"must_include":["订单号","付款凭证"]}
{"question":"企业账户如何修改管理员?","expected_doc_ids":["account-admin-guide"],"must_include":["身份验证"]}

至少分别记录两类指标:检索阶段是否命中预期文档,以及最终回答是否覆盖必要事实。这样可以避免用“答案看起来不错”代替可重复的评测。

智能体和 MCP:一个负责决策,一个负责连接

智能体并不等于一段更长的提示词。它通常包含循环:模型观察当前状态、选择动作、调用工具、读取结果,再决定继续还是结束。循环带来了能力,也带来了新的风险:重复调用、成本失控、越权操作,以及把恶意工具输出当成可信指令。

MCP 可以放在另一层理解:它为模型应用发现和使用外部上下文或工具提供标准化连接方式。MCP 本身不替应用决定业务权限,也不会自动解决工具是否安全的问题。即使工具通过统一协议接入,应用仍要执行身份认证、参数验证、审计和授权。

可以这样定义一份与具体框架无关的工具策略,并在智能体执行器中强制实施:

agent_policy:
  max_steps: 6
  timeout_seconds: 45
  require_confirmation:
    - delete_file
    - send_email
    - create_payment
  allowed_tools:
    - search_docs
    - get_order_status
    - draft_email
  limits:
    search_docs: 5
    get_order_status: 3
  redact_from_logs:
    - api_key
    - access_token
    - customer_phone

关键点是把权限控制放在确定性的应用代码中,而不是仅靠提示词要求模型“谨慎操作”。只读工具可以默认开放;写操作、高成本操作和不可逆操作应增加人工确认或事务审批。

上线前,用这些问题做一次自测

可以用下面的清单检验自己是否真正掌握了 Python LLM 应用开发:

  • 模型 API 超时或返回 429、500 时,程序会怎样处理?
  • 提示词、模型版本和推理参数是否可以追踪?
  • 输出是否需要 JSON Schema 或业务规则校验?
  • RAG 失败时,能否判断是解析、分块、召回、重排还是生成出了问题?
  • 检索结果是否携带来源,用户能否核对证据?
  • 智能体是否有最大步数、超时、预算和工具白名单?
  • 工具参数是否在服务端再次验证?
  • MCP 服务不可用或返回恶意内容时,应用是否能安全降级?
  • 日志中是否意外保存了密钥、个人信息或完整对话?
  • 是否存在一组固定测试,用于比较提示词、模型和检索策略的变更?

成熟的 LLM 应用不是依赖一次“聪明回答”,而是依赖可观测、可评测、可限制的工程流程。建议从单次 API 调用开始,随后加入结构化输出和测试,再逐步引入 RAG、工具和智能体。每增加一层自主性,都应同步增加权限边界、失败处理和审计能力。


相关推荐