上一篇速通 AI(五):现代大模型架构——LLaMA 系列 — RMSNorm、RoPE、SwiGLU、KV Cache、GQA

目标:掌握 LLM 应用开发的核心技能——提示词工程、LangChain 框架、OpenAI API 调用,能够独立开发 AI 应用。

前置要求:上一篇(LLaMA 架构理解、Transformer 基础)


本阶段知识依赖图

flowchart TD
    A["LLaMA 架构(上一篇)"]
    A --> C["提示词工程(高效使用大模型)"]
    C -->|输出格式、指令设计| C1[基础技巧]
    C -->|CoT、ToT、Few-shot| C2[高级技巧]
    C -->|Temperature、Top-P| C3[参数调优]
    A --> D["LangChain框架(应用开发框架)"]
    D -->|统一接口| D1[LLM调用]
    D -->|结构化提示| D2[提示模板]
    D -->|组合多个组件| D3["链(Chain)"]
    D -->|文档加载与向量| D4[文档处理]
    D -->|检索增强生成| D5[RAG链入门]
    D -->|自主决策| D6[Agent入门]
    A --> F["OpenAI API(模型调用接口)"]
    F -->|文本向量化| F1[Embedding]
    F -->|对话接口| F2[Chat Completion]

1. 提示词工程——高效使用大模型

为什么提示词工程重要?

类比:和外国人交流

  • 你说:“帮我写个东西”
    • 外国人(大模型):写什么?写给谁?什么风格?多长?
    • 输出:一段泛泛而谈的文字
  • 你说:“你是一位资深电商文案专家。请为一款售价 299 元的蓝牙耳机写一段小红书种草文案。要求:标题吸引眼球,突出降噪功能,使用 emoji , 200 字以内。”
    • 外国人(大模型):明白了!
    • 输出:一篇精准、专业的文案

提示词工程 = 学会如何清晰、精确地表达你的需求。

基础技巧

结构化提示词的四要素

  1. 角色(Role):告诉模型“你是谁”
    • 设定专业背景,让模型调用相关知识
    • 例:“你是一位有 10 年经验的 Python 高级工程师”
  2. 任务(Task):告诉模型“做什么”
    • 明确、具体的任务描述
    • 例:“请帮我写一个 FastAPI 接口,实现用户登录功能”
  3. 格式(Format):告诉模型“怎么输出”
    • 指定输出的格式和结构
    • 例:“输出为完整的 Python 代码,包含注释和错误处理”
  4. 约束(Constraint):告诉模型“边界在哪”
    • 限制条件、质量要求
    • 例:“使用异步函数,返回 JSON 格式,包含 token 过期时间”

四要素的组合效果

  • 只有任务:“帮我写个 API” → 输出不确定
  • 任务 + 格式:“帮我写个 API ,输出 Python 代码” → 稍好
  • 任务 + 格式 + 约束:“帮我写个 FastAPI 用户登录 API ,用 Python 代码输出,包含 JWT 认证” → 更好
  • 全部四个:“你是一位 Python 高级工程师。请帮我写一个 FastAPI 用户登录接口。输出完整的 Python 代码,包含注释。要求:使用异步函数,实现 JWT 认证,添加输入验证和错误处理,返回标准 JSON 响应。” → 最好

提示词工程的代价:长 prompt 消耗更多 token(增加 API 费用和延迟);prompt injection 安全风险(恶意用户在输入中嵌入指令覆盖系统提示);过度依赖 prompt 工程可能掩盖模型本身的能力不足。

高级技巧

零样本思维链(Zero-shot CoT)——激活推理能力

  • 普通提示:“小明有 5 个苹果,给了小红 2 个,又买了 3 个,现在有几个?”
    • 模型可能直接猜“6”(可能错)
  • 加一句“让我们一步一步思考”:
    • “小明有 5 个苹果,给了小红 2 个,又买了 3 个,现在有几个?让我们一步一步思考。”
    • 模型会展示中间步骤:
        1. 小明开始有 5 个苹果
        1. 给了小红 2 个,剩下 5-2=3 个
        1. 又买了 3 个,变成 3+3=6 个
      • 答案: 6 个

为什么加一句话就能提升准确率?

  • “让我们一步一步思考”激活了模型的“慢思考”模式
  • 模型被迫展示中间步骤,减少了“跳步”导致的错误
  • 类似于人类“打草稿”比“心算”更准确

少样本提示(Few-shot)——用示例教会模型

  • 零样本(Zero-shot):直接让模型做任务
    • “请判断情感:这家餐厅很好吃 → ?”
    • 模型可能理解你要什么,也可能不理解
  • 少样本(Few-shot):给几个示例,让模型学会模式
    • “请判断以下评论的情感:
      • 评论:这家餐厅太好吃! → 正面
      • 评论:服务态度很差 → 负面
      • 评论:菜品种类丰富 → 正面
      • 评论:等了一个小时才上菜 → ?”
    • 模型学会了“判断情感”的模式,准确率大幅提升

关键:示例的质量和多样性很重要

  • 至少 2-3 个正例和 2-3 个反例
  • 示例要覆盖典型情况
  • 示例的格式要和目标任务一致

思维树(Tree of Thought)——多路径推理

思维链(CoT):一条推理路径(线性)

  • A → B → C → D → 答案
  • 问题:如果 B 错了,后面全错

思维树(ToT):多条推理路径(树状)

graph TD
    A[问题] --> B1[路径 1]
    A --> B2[路径 2]
    A --> B3[路径 3]
    B1 --> C1[答案 1]
    B2 --> C2[答案 2]
    B3 --> C3[答案 3]

适用场景:需要多步推理的复杂问题(数学证明、策略规划、代码调试)。

参数调优——调参的艺术

  • Temperature(温度)
    • 0.0 → 完全确定性,每次输出相同(适合代码、数学)
    • 0.3 → 高度确定性,偶尔有小变化(适合翻译、摘要)
    • 0.7 → 平衡模式(适合对话、写作)
    • 1.0 → 高随机性(适合创意、头脑风暴)
  • Top-P(核采样)
    • 0.1 → 只从最可能的几个词中选(极度保守)
    • 0.9 → 从累积概率 90% 的词中选(推荐默认值)
    • 1.0 → 从所有词中选(最多样)
  • Frequency Penalty(频率惩罚)
    • 0.0 → 不惩罚重复(默认)
    • 0.5 → 轻微减少重复
    • 1.0 → 强烈避免重复(适合长文本生成)
  • Presence Penalty(存在惩罚)
    • 0.0 → 不鼓励新话题(默认)
    • 0.5 → 轻微鼓励新话题
    • 1.0 → 强烈鼓励新话题(适合头脑风暴)

提示词参数调优速查表

场景TemperatureTop-PFrequency Penalty说明
代码生成0.01.00.0确定性输出,一行解
翻译/摘要0.30.90.0高准确性,少量变化
一般对话0.70.90.0平衡质量和多样性
创意写作1.00.950.5高多样性,避免重复
头脑风暴1.01.01.0最大随机性,鼓励新话题

模块小结:提示词工程

你学到了什么为什么重要
结构化提示词四要素角色+任务+格式+约束
Zero-shot CoT激活推理能力
Few-shot 提示用示例教会模型
Tree of Thought多路径推理
Temperature/Top-P 参数控制生成风格

2. LangChain 框架——AI 应用开发的标准工具

LangChain 是什么?

类比: Spring Boot 之于 Java Web 开发, LangChain 之于 LLM 应用开发

没有 LangChain 时,开发一个 RAG 应用需要:

  1. 手动调用 OpenAI API
  2. 手动加载和切分文档
  3. 手动实现向量搜索
  4. 手动组装提示词
  5. 手动处理输出解析
  6. 手动管理对话历史

→ 每个项目都要重复造轮子。

有了 LangChain :

  1. 统一的 LLM 调用接口(支持 OpenAI 、本地模型、各种 API)
  2. 内置的文档加载和切分工具
  3. 内置的向量存储和检索
  4. 标准化的提示模板
  5. 自动化的输出解析
  6. 内置的记忆管理

→ 专注于业务逻辑,不用重复造轮子。

核心组件 1 : LLM 调用——统一接口

from langchain_openai import ChatOpenAI
from langchain_community.llms import Ollama

# OpenAI API
llm = ChatOpenAI(model="gpt-4", temperature=0.7)

# 本地模型(Ollama部署的Qwen3)
llm = Ollama(model="qwen3:8b")

# 智谱AI
from langchain_community.chat_models import ChatZhipuAI
llm = ChatZhipuAI(model="glm-4")

# 统一接口:不管底层是什么模型,调用方式完全一样
response = llm.invoke("什么是RAG?")
print(response.content)

# 这就是LangChain的核心价值之一:
# 一行代码切换模型,不需要修改业务逻辑

核心组件 2 :提示模板——结构化提示词

from langchain_core.prompts import ChatPromptTemplate

# 创建模板(类似填空题)
template = ChatPromptTemplate.from_messages([
    ("system", "你是一位{role},请用{style}的方式回答问题。"),
    ("user", "{question}")
])

# 填充模板(把空填上)
prompt = template.invoke({
    "role": "AI专家",
    "style": "简洁明了",
    "question": "什么是Transformer?"
})

# 发送给模型
response = llm.invoke(prompt)

为什么需要模板?

类比:邮件模板

  • 没有模板:每次写邮件都要从头写
  • 有模板:填入姓名、日期等变量,自动生成完整邮件

提示模板同理:

  • 定义一次模板,多次复用
  • 变量可以在运行时动态填充
  • 保证提示词的一致性

核心组件 3 :链(Chain)——LCEL 管道语法

from langchain_core.output_parsers import StrOutputParser

# LCEL(LangChain Expression Language)管道语法
chain = template | llm | StrOutputParser()

# 等价于:
# 1. template处理输入 → 生成提示词
# 2. llm处理提示词 → 生成回答
# 3. StrOutputParser处理回答 → 提取纯文本

# 执行链
result = chain.invoke({
    "role": "AI专家",
    "style": "简洁明了",
    "question": "什么是Transformer?"
})

# 管道语法的魔力:可以用 | 把任意组件串联起来
# 就像Unix的管道:cat file | grep "error" | sort

核心组件 4 :文档加载与向量存储

from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS

# 1. 加载文档(把PDF变成可处理的文本)
loader = PyPDFLoader("document.pdf")
documents = loader.load()

# 2. 文本切分(把长文档切成小块)
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,     # 每块500个字符
    chunk_overlap=50    # 相邻块重叠50个字符
)
chunks = splitter.split_documents(documents)

# 3. 向量化(把文本变成数字向量)
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(chunks, embeddings)

# 4. 检索(找到最相关的文档块)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
docs = retriever.invoke("什么是机器学习?")

为什么要切分?为什么要有 overlap ?

为什么切分:

  • 大模型有上下文长度限制(如 4K 、 8K 、 128K tokens)
  • 一次塞入整本文档不现实
  • 检索时需要精确匹配,整本文档太粗糙

为什么 overlap (重叠):

  • 如果在句子中间切断,前后两块的语义都不完整
  • overlap 让相邻块有重叠部分,确保信息的连续性
  • 类比:看书时翻页,上一页的最后一行和下一页的第一行能衔接上

核心组件 5 : RAG 链——检索增强生成

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

# RAG提示模板
rag_prompt = ChatPromptTemplate.from_template("""
请根据以下参考信息回答用户的问题。
如果参考信息中没有相关内容,请说明你不确定。

参考信息:
{context}

用户问题:
{question}
""")

# RAG链的构建(LCEL管道语法)
rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | rag_prompt
    | llm
    | StrOutputParser()
)

# 使用
answer = rag_chain.invoke("什么是注意力机制?")
# 流程:
# 1. "什么是注意力机制?" → retriever检索相关文档
# 2. 检索到的文档 + 问题 → 填入提示模板
# 3. 填充后的提示 → 发送给LLM
# 4. LLM的回答 → 提取纯文本 → 返回

核心组件 6 : Agent——让模型自主决策

from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool

# 定义工具(给模型"武器")
@tool
def search_web(query: str) -> str:
    """搜索网页获取最新信息"""
    return "搜索结果..."

@tool
def calculate(expression: str) -> str:
    """计算数学表达式"""
    # 警告:eval() 有安全风险,生产环境应使用 ast.literal_eval 或 sympy
    return str(eval(expression))

# 创建Agent(给模型"大脑")
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个有用的助手,可以使用工具来回答问题。"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])
tools = [search_web, calculate]
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 使用
result = agent_executor.invoke({"input": "今天北京的天气怎么样?"})
# Agent会自动:
# 1. 分析问题 → "需要查天气"
# 2. 选择工具 → search_web
# 3. 调用工具 → search_web("北京今天天气")
# 4. 整合结果 → 生成自然语言回答

Chain vs Agent 的区别

  • Chain(链):固定流程, A → B → C
    • 类比:工厂流水线——每一步都是预设的
    • 适合:流程明确的任务(RAG 问答、文本翻译)
  • Agent(智能体):动态决策,根据情况选择下一步
    • 类比:真人客服——根据问题类型灵活应对
    • 适合:需要判断和选择的任务(多工具调用、复杂查询)

模块小结: LangChain 框架

你学到了什么为什么重要
统一 LLM 调用接口一行代码切换模型
提示模板结构化、可复用的提示词
LCEL 管道语法链式组合组件
文档加载与切分RAG 的数据准备基础
RAG 链构建检索增强生成的标准实现
Agent 智能体让模型自主决策

3. OpenAI API 与 Embedding

Embedding——把文本变成"语义坐标"

类比:给每个词/句子在"语义地图"上定位

  • Embedding = 把文本转换为一个固定长度的数字向量
  • “猫” → [0.2, 0.8, -0.1, 0.5, …](1536 维)
  • “狗” → [0.3, 0.7, -0.2, 0.4, …](和“猫”接近)
  • “汽车” → [-0.5, 0.1, 0.9, -0.3, …](和“猫”很远)

语义相似的文本 → 向量接近(余弦相似度接近 1) 语义不同的文本 → 向量远离(余弦相似度接近 0)

from openai import OpenAI
import numpy as np

client = OpenAI()

# 获取Embedding
response = client.embeddings.create(
    model="text-embedding-3-small",
    input="什么是机器学习?"
)
embedding = response.data[0].embedding  # 1536维向量

# 计算相似度
def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# 获取三个句子的 Embedding
embedding1 = client.embeddings.create(model="text-embedding-3-small", input="机器学习是什么").data[0].embedding
embedding2 = client.embeddings.create(model="text-embedding-3-small", input="什么是机器学习").data[0].embedding
embedding3 = client.embeddings.create(model="text-embedding-3-small", input="今天天气怎么样").data[0].embedding

# "机器学习是什么" 和 "什么是机器学习" → 几乎相同的问题 → 高相似度
sim1 = cosine_similarity(embedding1, embedding2)  # ≈ 0.95

# "什么是机器学习" 和 "今天天气怎么样" → 完全不同的话题 → 低相似度
sim2 = cosine_similarity(embedding1, embedding3)  # ≈ 0.1

Embedding 是 RAG 的基础

  • RAG 的检索步骤 = 把用户问题和所有文档都转为 Embedding ,然后找最相似的
  • 用户问题:“什么是注意力机制?” → Embedding → [0.1, 0.5, -0.3, …]
  • 文档 1 :“注意力机制是一种让模型关注重要信息的技术”
    • Embedding → [0.1, 0.5, -0.2, …] ← 高相似度
  • 文档 2 :“今天天气很好”
    • Embedding → [-0.4, 0.1, 0.8, …] ← 低相似度
  • 返回文档 1 给模型作为参考

Chat Completion API

from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "你是一位AI助手"},
        {"role": "user", "content": "解释什么是RAG"}
    ],
    temperature=0.7,
    max_tokens=500,
    stream=True  # 流式输出,详见 §4 流式输出小节
)

模块小结: OpenAI API

你学到了什么为什么重要
Embedding 向量化把文本变成语义坐标
Chat Completion API对话接口的标准用法
流式输出提升用户体验
余弦相似度衡量语义相似性

4. RAG 系统深入——检索增强生成

为什么需要 RAG?——大模型的三大硬伤

大模型虽然强大,但有三个根本性缺陷:

  1. 知识截止日期:GPT-4 的知识截止到训练数据的时间点,不知道"今天的新闻"
  2. 幻觉(Hallucination):大模型会"一本正经地胡说八道"——对不知道的事实编造看起来合理的答案
  3. 企业私有数据:大模型从未见过你公司的内部文档、产品手册

RAG 的解决方案:不让大模型"凭记忆回答",而是先帮它"查资料",再让它"基于资料回答"。

Function Calling——让大模型使用工具

大模型就像一个博学的顾问——他知道很多知识,但没有"手"(不能查数据库、不能发邮件、不能搜索网页)。Function Calling = 给这个顾问配上"工具箱"。

工作流程:

  1. 用户提问 → 大模型分析问题,判断需要调用哪个工具
  2. 大模型生成工具调用指令(函数名 + 参数)→ 外部系统执行工具
  3. 工具返回结果 → 大模型整合结果生成最终回答

代码示例(OpenAI Function Calling):

import openai

# Step 1:定义工具(告诉模型有哪些工具可用)
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "获取指定城市的天气",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "城市名称"}
            },
            "required": ["city"]
        }
    }
}]

# Step 2:用户提问,模型决定是否调用工具
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
    tools=tools,
    tool_choice="auto"  # 让模型自动决定是否调用工具
)

# Step 3:模型返回 tool_calls(函数名 + 参数)
tool_call = response.choices[0].message.tool_calls[0]
# → function: get_weather, arguments: {"city": "北京"}

# Step 4:外部系统执行工具,返回结果
weather_result = get_weather(city="北京")  # 你自己的函数

# Step 5:将结果交给模型,生成最终回答
final_response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "user", "content": "北京今天天气怎么样?"},
        response.choices[0].message,  # 模型的 tool_calls
        {"role": "tool", "tool_call_id": tool_call.id, "content": str(weather_result)}
    ]
)
# → "北京今天晴,气温 25°C,适合出行。"

关键理解:大模型不直接执行工具,它只是"决策者"——决定用什么工具、传什么参数。执行由外部系统完成。完整的 Function Calling 和 MCP 协议详解见第八篇 §4。

流式输出——提升用户体验

普通输出:等模型生成全部内容后一次性返回 → 用户等待时间长,体验差。

流式输出(Streaming):模型每生成一个 token 就立即返回 → 用户看到文字逐字出现,像"打字机"一样。底层通过 SSE(Server-Sent Events)或 chunked transfer encoding 实现——服务端不需要等所有内容生成完,每生成一小块就推送给客户端。

# 流式输出的关键参数
response = client.chat.completions.create(
    model="gpt-4",
    messages=[...],
    stream=True  # 启用流式输出
)

# 逐块接收并显示
for chunk in response:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

RAG 的完整体系(向量数据库、高级检索策略、GraphRAG、评估体系)详见第七篇。

模块小结:RAG 系统深入

你学到了什么为什么重要
RAG 三大硬伤知识截止、幻觉、私有数据——RAG 的动机
Function Calling 工作流程让大模型使用外部工具的三步机制
流式输出逐 token 返回,提升用户体验

5. 国产大模型实战

ChatGLM——智谱 AI 生态

ChatGLM 是智谱 AI 开发的开源对话大模型系列。

核心特点:

  • 中文能力强:专门为中文优化,中文理解准确度高
  • 支持 Function Calling :可以调用外部工具
  • 提供云端 API :通过智谱 AI 的 API 直接调用
  • 支持本地部署:开源模型可以自己部署
  • 与 LangChain 集成:有专门的 LangChain 集成包

架构特点:

  • 基于 Prefix LM (不是纯 Decoder)
  • 同时支持理解和生成
  • 上下文窗口: 128K tokens

Qwen3——通义千问

Qwen3 是阿里云开发的开源大模型系列。

核心特点:

  • 多尺寸可选: 0.6B / 1.7B / 4B / 8B / 14B / 32B / 72B
    • 从手机端到服务器端都有合适的模型
  • 深度思考模式(Thinking Mode):
    • 类似 o1 的“慢思考”能力
    • 在回答前先进行内部推理
    • 数学、编程、逻辑推理能力大幅提升
  • 混合推理(Hybrid Mode):
    • 简单问题用快速模式
    • 复杂问题自动切换到深度思考模式
    • 兼顾速度和质量
  • 嵌入模型同步可用:
    • Qwen3-Embedding :文本向量化
    • Qwen3-Reranker :检索结果重排序

TEXT2SQL+Qwen3 项目实战

项目目标:用户输入自然语言问题,自动生成 SQL 查询并返回结果。

技术栈:

  • Qwen3 大模型:理解用户意图,生成 SQL 语句
  • MCP 服务端:封装数据库操作工具(查表结构、执行 SQL)
  • LangGraph :编排工作流(意图识别 → 查表结构 → 生成 SQL → 执行 → 返回) 完整流程: 用户:“上个月销售额最高的产品是什么?” ↓ Step 1: Qwen3 理解意图 → “需要查询销售数据” ↓ Step 2: 调用 MCP 工具 → 获取数据库表结构 ↓ Step 3: Qwen3 生成 SQL → SELECT product_name FROM sales WHERE … ORDER BY amount DESC LIMIT 1 ↓ Step 4: 调用 MCP 工具 → 执行 SQL 查询 ↓ Step 5: Qwen3 整合结果 → “上个月销售额最高的产品是 iPhone 15 ,销售额为 500 万元。”

模块小结:国产大模型实战

你学到了什么为什么重要
ChatGLM 生态中文能力强的开源模型
Qwen3 多尺寸模型从端侧到云端全覆盖
深度思考模式复杂推理能力提升
TEXT2SQL 实战项目MCP + LangGraph 综合应用

下一篇预告:本文掌握了 LLM 应用开发的基础工具链。在速通 AI(七):RAG 检索增强生成中,你将深入学习 RAG 的完整体系——向量数据库、高级检索策略、GraphRAG、评估体系。