Chapter 03
第三章 大语言模型基础
大语言模型是现代 Agent 的核心基础设施。本章不追求训练大模型,而是让你理解 Agent 开发中最常遇到的 LLM 概念:语言建模、向量表示、Transformer、Prompt、Token、开源模型调用、模型选择和幻觉。
本章学习目标
3.1 语言模型与 Transformer 架构
3.1.1 从 N-gram 到 RNN
语言模型的基本任务是预测文本序列的概率。最朴素的 N-gram 模型会统计“某个词后面跟着另一个词”的频率,用局部上下文预测下一个词。虽然它很简单,但能帮助你建立一个关键直觉:语言模型不是事实数据库,而是根据上下文做概率预测。
from collections import Counter, defaultdict
class NGramLanguageModel:
def __init__(self, n: int = 2) -> None:
self.n = n
self.table: dict[tuple[str, ...], Counter[str]] = defaultdict(Counter)
def fit(self, corpus: list[str]) -> None:
for sentence in corpus:
tokens = ["<s>"] * (self.n - 1) + sentence.split() + ["</s>"]
for index in range(len(tokens) - self.n + 1):
context = tuple(tokens[index:index + self.n - 1])
target = tokens[index + self.n - 1]
self.table[context][target] += 1
def next_token_distribution(self, context_words: list[str]) -> list[tuple[str, float]]:
context = tuple(context_words[-(self.n - 1):])
counts = self.table.get(context, Counter())
total = sum(counts.values())
if total == 0:
return []
return [(token, count / total) for token, count in counts.most_common()]
if __name__ == "__main__":
lm = NGramLanguageModel(n=2)
lm.fit(["agent uses tools", "agent reads memory", "agent uses memory"])
print(lm.next_token_distribution(["agent"]))
配套文件:n_gram.py。N-gram 的问题是上下文太短,没见过的组合难以泛化。RNN、LSTM 等神经网络曾经用于建模更长序列,但并行效率和长距离依赖仍然受限。Transformer 的出现改变了这个局面。
3.1.1 补充:词向量与语义空间
神经语言模型不会直接处理字符串,而是把词或 Token 转成向量。向量可以参与加减和相似度计算,因此模型能把语义关系编码到连续空间中。下面用一个极简例子演示“向量相似度”和类比计算。
import math
VECTORS = {
"king": [0.8, 0.6, 0.1],
"queen": [0.75, 0.65, 0.2],
"man": [0.7, 0.2, 0.0],
"woman": [0.65, 0.25, 0.1],
"agent": [0.1, 0.9, 0.8],
}
def cosine(left: list[float], right: list[float]) -> float:
dot = sum(a * b for a, b in zip(left, right))
left_norm = math.sqrt(sum(a * a for a in left))
right_norm = math.sqrt(sum(b * b for b in right))
return dot / (left_norm * right_norm)
def add(*vectors: list[float]) -> list[float]:
return [sum(values) for values in zip(*vectors)]
def sub(left: list[float], right: list[float]) -> list[float]:
return [a - b for a, b in zip(left, right)]
target = add(sub(VECTORS["king"], VECTORS["man"]), VECTORS["woman"])
ranked = sorted(
((word, cosine(vector, target)) for word, vector in VECTORS.items()),
key=lambda item: item[1],
reverse=True,
)
print(ranked)
真实词向量维度会高很多,训练方式也更复杂。对 Agent 来说,词向量最直接的应用是语义检索:把问题和文档都转成向量,再找最相近的内容,这就是许多 RAG 系统的基础。
3.1.2 Transformer 架构解析
Transformer 的核心是注意力机制。它让模型在处理一个 Token 时,可以根据相关性动态关注输入序列中的其他 Token。注意力通常由 Query、Key、Value 三组向量计算得到。
import math
def dot(left: list[float], right: list[float]) -> float:
return sum(a * b for a, b in zip(left, right))
def softmax(row: list[float]) -> list[float]:
shifted = [item - max(row) for item in row]
values = [math.exp(item) for item in shifted]
total = sum(values)
return [item / total for item in values]
def attention(query: list[list[float]], key: list[list[float]], value: list[list[float]]):
dim = len(query[0])
scores = [[dot(q, k) / math.sqrt(dim) for k in key] for q in query]
weights = [softmax(row) for row in scores]
outputs = []
for row in weights:
outputs.append([
sum(weight * value[index][column] for index, weight in enumerate(row))
for column in range(len(value[0]))
])
return outputs, weights
配套文件:transformer_attention.py。注意力的工程启发是:上下文会影响输出,但上下文不是越多越好。Agent 需要把最相关的目标、工具、观察和约束放进模型输入。
3.1.3 Decoder-Only 架构
很多主流大语言模型采用 Decoder-only 架构。它们按从左到右的方式预测下一个 Token,每次生成的新 Token 又会成为后续上下文的一部分。聊天、代码补全、工具调用 JSON,本质上都可以看作“在上下文条件下继续生成”。
| 架构概念 | 直觉理解 | 对 Agent 的影响 |
|---|---|---|
| 自回归生成 | 一个 Token 接一个 Token 生成。 | 长输出可能偏离格式,需要流式校验或后处理。 |
| 上下文窗口 | 模型一次能看到的 Token 数有限。 | Agent 需要摘要、检索和 checkpoint。 |
| 采样参数 | temperature、top_p 会影响随机性。 | 工具调用通常需要低随机性,创意写作可以高一些。 |
3.2 与大语言模型交互
3.2.1 提示工程
Prompt 工程不是神秘咒语,而是把任务、约束、示例、输出格式和上下文组织给模型。Agent 场景下,Prompt 通常还要包含工具说明和安全边界。
| 提示方式 | 使用方法 | 适合场景 |
|---|---|---|
| 零样本提示 | 直接描述任务和输出要求。 | 简单分类、摘要、格式转换。 |
| 少样本提示 | 提供几个输入输出样例。 | 风格迁移、复杂格式、业务规则示范。 |
| 分步提示 | 要求模型先拆任务或按步骤检查。 | 规划、调试、推理密集任务。 |
| 结构化输出 | 要求模型输出 JSON 或工具调用参数。 | Agent 决策、函数调用、自动化执行。 |
SYSTEM_PROMPT = """你是一个 Agent 决策模块。
只能输出 JSON,不要输出解释。
允许的 action: answer, call_tool, ask_human。
如果证据不足,必须 ask_human。"""
USER_PROMPT = """任务:根据搜索结果判断是否需要继续检索。
当前观察:只找到一个来源,且来源可信度未知。
输出字段:action, reason, tool, arguments。"""
3.2.2 文本分词
模型看见的不是字符或人类意义上的词,而是 Token。分词器会把文本拆成 Token ID。不同模型的分词方式不同,同一段文本的 Token 数也可能不同,这会影响成本、上下文长度和截断策略。
from collections import Counter
class SimpleBPE:
def __init__(self) -> None:
self.merges: list[tuple[str, str]] = []
def best_pair(self, words: list[list[str]]) -> tuple[str, str]:
counts: Counter[tuple[str, str]] = Counter()
for pieces in words:
for index in range(len(pieces) - 1):
counts[(pieces[index], pieces[index + 1])] += 1
return counts.most_common(1)[0][0]
def merge_pair(self, pieces: list[str], pair: tuple[str, str]) -> list[str]:
merged = []
index = 0
while index < len(pieces):
if index + 1 < len(pieces) and (pieces[index], pieces[index + 1]) == pair:
merged.append(pieces[index] + pieces[index + 1])
index += 2
else:
merged.append(pieces[index])
index += 1
return merged
if __name__ == "__main__":
words = [list(word) + ["</w>"] for word in ["agent", "agents", "agenda"]]
bpe = SimpleBPE()
pair = bpe.best_pair(words)
print(pair)
print([bpe.merge_pair(word, pair) for word in words])
配套文件:bpe.py。Agent 做长文档任务时,一定要考虑 Token 预算:哪些内容进入上下文,哪些内容只保留摘要,哪些内容通过检索按需取回。
3.2.3 调用开源大语言模型
学习阶段可以用开源模型理解完整流程:加载 tokenizer、加载模型、构造 messages、编码输入、生成输出、解码新 Token。生产阶段则要根据成本、延迟、部署资源和安全要求选择 API 或自部署。
# 伪代码:需要安装 transformers 和对应模型权重后运行
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "Qwen/Qwen2.5-0.5B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
messages = [
{"role": "system", "content": "你是一个简洁的 Agent 教学助手。"},
{"role": "user", "content": "用三句话解释工具调用。"},
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer(text, return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=128)
print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True))
3.2.4 模型的选择
Agent 里不同步骤可以使用不同模型。规划和复杂推理需要强模型,格式转换和简单分类可以用小模型,Embedding 检索需要专门向量模型,安全审核可能需要独立分类器。
| 任务 | 模型选择重点 | 常见风险 |
|---|---|---|
| 规划 | 推理能力、上下文理解、工具意识。 | 计划过度乐观、步骤不可执行。 |
| 工具参数生成 | 结构化输出稳定性、低随机性。 | 参数缺失、工具名错误、越权调用。 |
| 总结 | 长上下文、压缩能力、引用保真。 | 遗漏关键事实、混淆来源。 |
| 事实核查 | 检索结合、保守回答、证据意识。 | 幻觉、自信错误。 |
3.3 大语言模型的缩放法则与局限性
3.3.1 缩放法则
模型能力通常会随着参数量、数据量和计算量增长而提升,但这不是免费的。更大的模型意味着更高的推理成本、更高的延迟和更复杂的部署要求。Agent 开发中经常要做分层选择:关键决策用强模型,普通步骤用便宜模型。
3.3.2 模型幻觉
幻觉是 Agent 最需要警惕的模型局限之一。模型可能生成不存在的事实、编造引用、误读工具返回值,或者对不确定内容给出很自信的表达。Agent 一旦把幻觉结果直接送进工具层,就可能造成真实损失。
3.4 本章小结
本章从 N-gram 讲到 Transformer,再讲 Prompt、分词、开源模型调用、模型选择和幻觉。对 Agent 开发者来说,最重要的不是记住每个公式,而是理解模型是如何接收上下文、生成 Token、受 Prompt 影响,并在工程系统里表现出不稳定性。
前三章到这里完成基础铺垫。后续学习经典 Agent 范式时,你会反复用到本章概念:ReAct 需要结构化行动,Plan-and-Solve 需要规划 Prompt,RAG 需要向量和分词,上下文工程需要 Token 预算,评估需要理解幻觉和模型选择。
习题
-
练习 3.1:实现三元模型。
把
NGramLanguageModel的 n 改成 3,比较 bigram 和 trigram 的预测差异。 - 练习 3.2:词向量相似度。 给词向量示例增加 5 个词,观察 cosine 相似度是否符合你的直觉。
- 练习 3.3:多轮 BPE 合并。 连续执行 5 次最佳 pair 合并,记录每轮词表变化。
- 练习 3.4:Prompt 改写。 把一个自由回答 Prompt 改造成结构化 JSON 输出 Prompt,并写出校验字段。
- 练习 3.5:模型选择表。 为一个调研 Agent 设计模型选择表,至少包含规划、搜索参数、摘要、核查四个步骤。
参考文献
- Attention Is All You Need:Transformer 经典论文。
- Neural Machine Translation of Rare Words with Subword Units:BPE 子词分词代表性工作。
- Scaling Laws for Neural Language Models:缩放法则研究。