> For the complete documentation index, see [llms.txt](https://inwt233.gitbook.io/ai-learning/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://inwt233.gitbook.io/ai-learning/di-yi-bu-fen-nlp-ji-chu/week-02/day-010.md).

# Day 010：交叉熵与困惑度

{% hint style="info" %}
**两个语言模型都能给测试句子分配非零概率时，怎样把许多长短不同的句子汇总成一个可比较的分数？困惑度为 20，又究竟表示什么？**
{% endhint %}

## 学习目标

完成本节后，你应该能够：

1. 从单个 Token 的信息量推导测试集交叉熵；
2. 区分总负对数似然、平均负对数似然、交叉熵和困惑度；
3. 证明困惑度是正确 Token 逆概率的几何平均；
4. 正确处理 `<s>`、`</s>`、PAD 与被忽略标签的计数；
5. 用 Python 评估平滑 bigram 模型，并复核真实输出；
6. 解释为什么未平滑模型遇到零概率时困惑度为无穷大；
7. 说明只有测试集、Tokenizer 和计分约定一致时，困惑度才可直接比较；
8. 识别按句平均、训练集评估和跨 Tokenizer 比较等常见错误。

{% hint style="info" %}
本节关注“如何正确计算与报告”。Day 012 会从真实分布、模型分布和 KL 散度的关系出发，进一步解释交叉熵为什么能评价语言模型。
{% endhint %}

## 1. 语言模型评估的是“给真实下一个 Token 多少概率”

给定测试序列 $$w\_1,\ldots,w\_T$$，语言模型 Q 在每个位置看到历史 $$h\_i$$，并为真实目标 $$w\_i$$ 给出条件概率：

$$
Q(w\_i\mid h\_i)
$$

如果真实 Token 的概率高，模型对该位置不太“意外”；如果概率低，模型就很“意外”。我们需要把所有位置的意外程度累积起来。

这里评估的不是：

* 概率最大的候选是否恰好命中；
* 生成文本看起来是否流畅；
* 每句话的联合概率是否最大。

交叉熵使用了模型分布对**真实目标 Token**给出的完整概率信息。即使两个模型 top-1 预测相同，它们给真实 Token 的概率不同，交叉熵也会不同。

## 2. 从信息量到负对数似然

模型认为一个事件的概率是 q 时，它的信息量或惊讶度定义为：

$$
I\_Q(w\_i\mid h\_i)=-\log\_b Q(w\_i\mid h\_i)
$$

其中 b 是对数底：

* b=2：单位是 bit；
* b=e：单位是 nat。

例如使用以 2 为底的对数：

| 正确 Token 概率 |   惊讶度 |
| ----------- | ----: |
| 1           | 0 bit |
| 1/2         | 1 bit |
| 1/4         | 2 bit |
| 1/8         | 3 bit |

概率每减半，惊讶度增加 1 bit。对数还把整句概率的连乘变为逐 Token 损失的相加：

$$
-\log Q(w\_1,\ldots,w\_T)
\=-\sum\_{i=1}^{T}\log Q(w\_i\mid h\_i)
$$

右侧就是这段序列的**总负对数似然**（negative log-likelihood，NLL）。

## 3. 交叉熵：每个预测事件平均有多意外

假设测试集一共包含 N 个实际参与计分的 next-token 事件。经验交叉熵为：

$$
H\_b(\text{test},Q)
\=-\frac{1}{N}\sum\_{i=1}^{N}\log\_b Q(w\_i\mid h\_i)
$$

它就是平均 NLL：

$$
H=\frac{\text{total NLL}}{N}
$$

在固定测试集和计分约定下，交叉熵越低，说明模型平均给真实 Token 的概率越高。

### 3.1 为什么要除以 Token 数

联合概率会随序列变长不断连乘，长句通常天然比短句概率小。总 NLL 也会随 Token 数大致增长。除以 N 后，才得到长度归一化的“每个预测事件平均损失”。

### 3.2 这里的 N 不是句子数

如果一条包含 3 个普通 Token 的句子还要预测 `</s>`，它就贡献 4 个计分事件。多个句子应把所有有效事件的 NLL 加起来，再除以所有有效事件总数。

错误做法是先算每句平均损失，再把句子等权平均。那会让短句中的每个 Token 获得更大权重。

## 4. 困惑度：把平均对数损失还原到概率尺度

以 b 为底计算交叉熵时，困惑度定义为：

$$
\operatorname{PP}\_b=b^{H\_b}
$$

若使用自然对数：

$$
\operatorname{PP}=\exp\left(
-\frac{1}{N}\sum\_{i=1}^{N}\ln Q(w\_i\mid h\_i)
\right)
$$

只要前后底数一致，用 bit 或 nat 最终得到的困惑度相同。

### 4.1 困惑度是逆概率的几何平均

从定义展开：

$$
\begin{aligned}
\operatorname{PP}
&=\exp\left(-\frac{1}{N}\sum\_i\ln q\_i\right)\\
&=\exp\left(\frac{1}{N}\ln\prod\_i\frac{1}{q\_i}\right)\\
&=\left(\prod\_i\frac{1}{q\_i}\right)^{1/N}
\end{aligned}
$$

因此，困惑度不是“候选词数量的算术平均”，而是正确 Token 逆概率的几何平均。

### 4.2 “有效分支数”的直觉

如果模型在每个位置都在 K 个候选上给出均匀概率 1/K，那么：

$$
H=-\log\_2(1/K)=\log\_2K
$$

$$
\operatorname{PP}=2^{\log\_2K}=K
$$

所以困惑度常被直观解释为平均每一步面对多少个“同等可能的有效选择”。

但这只是直觉。真实模型的分布通常不均匀，困惑度 20 不意味着每一步恰好有 20 个概率相同的词。

## 5. 熵、交叉熵和 NLL 不要混用

### 5.1 熵 H(P)

熵描述真实数据分布 P 自身的不确定性：

$$
H(P)=-\mathbb{E}\_{x\sim P}\[\log P(x)]
$$

### 5.2 交叉熵 H(P,Q)

交叉熵描述数据来自 P，却用模型分布 Q 编码时的平均代价：

$$
H(P,Q)=-\mathbb{E}\_{x\sim P}\[\log Q(x)]
$$

测试集公式用样本平均近似这个期望。因为真实分布 P 不可直接获得，我们通常报告的是经验交叉熵。

### 5.3 NLL

在语言模型评估中：

* 总 NLL：所有有效位置的 $$-\log q\_i$$ 之和；
* 平均 NLL：总 NLL 除以有效位置数；
* 使用相同对数底时，平均 NLL 就是经验交叉熵。

很多深度学习框架中的 `CrossEntropyLoss(reduction="mean")` 返回的正是有效标签上的平均损失，但还必须核对标签移位、掩码和 `ignore_index`。

## 6. 到底哪些位置进入分母

沿用 Day 008–009 的约定，一句话：

```
我 喜欢 自然语言
```

扩展为：

```
<s> → 我 → 喜欢 → 自然语言 → </s>
```

计分事件共有 4 个：

1. $$P(\text{我}\mid<s>)$$
2. $$P(\text{喜欢}\mid\text{我})$$
3. $$P(\text{自然语言}\mid\text{喜欢})$$
4. $$P(</s>\mid\text{自然语言})$$

`<s>` 只提供上下文，不是预测目标，所以不计入 N。`</s>` 是模型需要预测的真实结束事件，所以计入。

### 6.1 批处理神经语言模型

批处理为了对齐长度而加入 PAD 时，PAD 通常不应参与损失和分母。若目标标签使用 `-100` 表示忽略位置，则：

$$
N={i|y\_i\ne-100}
$$

不是张量的总元素数，也不是 `batch_size × max_length`。

{% hint style="warning" %}
报告交叉熵或困惑度时，必须写清是否计入 `</s>`、忽略了哪些标签、按 Token 还是按字符归一化。分母约定不同，数字就不是同一个指标。
{% endhint %}

## 7. 手算一个两位置示例

假设模型对两个真实 Token 给出的概率分别为：

$$
q\_1=\frac12,\qquad q\_2=\frac18
$$

以 2 为底：

$$
\text{NLL}= -\log\_2\frac12-\log\_2\frac18=1+3=4
$$

$$
H=\frac{4}{2}=2\text{ bits/token}
$$

$$
\operatorname{PP}=2^2=4
$$

也可用逆概率几何平均核对：

$$
\sqrt{2\times8}=4
$$

## 8. Python 实现：评估加 k bigram 模型

下面用 Day 009 的训练语料，对两条测试句进行评估。第一条包含训练中没出现过的 bigram，因此能直接看到未平滑与平滑模型的差别。

```python
from collections import Counter
from math import inf, log2


class BigramLM:
    def __init__(self, k=0.0, bos="<s>", eos="</s>"):
        if k < 0:
            raise ValueError("k 不能小于 0")
        self.k = k
        self.bos = bos
        self.eos = eos
        self.vocab = set()
        self.context_counts = Counter()
        self.bigram_counts = Counter()

    def fit(self, corpus):
        self.vocab = {self.eos}
        self.context_counts.clear()
        self.bigram_counts.clear()

        for sentence in corpus:
            self.vocab.update(sentence)
            sequence = [self.bos, *sentence, self.eos]

            for context, token in zip(sequence, sequence[1:]):
                self.context_counts[context] += 1
                self.bigram_counts[(context, token)] += 1

        return self

    def probability(self, token, context):
        if token not in self.vocab:
            raise ValueError(f"测试 Token {token!r} 不在训练词表中")

        count = self.bigram_counts[(context, token)]
        context_count = self.context_counts[context]

        if self.k == 0:
            # 未平滑模型遇到未见上下文时无法形成有效条件分布。
            return 0.0 if context_count == 0 else count / context_count

        denominator = context_count + self.k * len(self.vocab)
        return (count + self.k) / denominator

    def evaluate(self, corpus):
        total_nll_bits = 0.0
        event_count = 0

        for sentence in corpus:
            sequence = [self.bos, *sentence, self.eos]

            for context, token in zip(sequence, sequence[1:]):
                probability = self.probability(token, context)
                event_count += 1  # 包括 </s>，但不把 <s> 当作预测目标。

                if probability == 0:
                    return {
                        "events": event_count,
                        "total_nll_bits": inf,
                        "cross_entropy_bits": inf,
                        "perplexity": inf,
                    }

                total_nll_bits -= log2(probability)

        cross_entropy = total_nll_bits / event_count
        return {
            "events": event_count,
            "total_nll_bits": total_nll_bits,
            "cross_entropy_bits": cross_entropy,
            "perplexity": 2 ** cross_entropy,
        }


train_corpus = [
    ["我", "喜欢", "自然语言"],
    ["我", "喜欢", "机器学习"],
    ["我", "学习", "自然语言"],
    ["你", "喜欢", "自然语言"],
]

test_corpus = [
    ["你", "学习", "机器学习"],  # 含未见 bigram：你→学习、学习→机器学习
    ["我", "喜欢", "自然语言"],
]

for k in (0.0, 0.1, 1.0):
    model = BigramLM(k=k).fit(train_corpus)
    metrics = model.evaluate(test_corpus)
    print(
        f"k={k:<3} | events={metrics['events']} | "
        f"H={metrics['cross_entropy_bits']:.6f} bits/token | "
        f"PP={metrics['perplexity']:.6f}"
    )
```

输出：

```
k=0.0 | events=2 | H=inf bits/token | PP=inf
k=0.1 | events=8 | H=1.673504 bits/token | PP=3.189885
k=1.0 | events=8 | H=2.089340 bits/token | PP=4.255534
```

### 8.1 为什么未平滑模型只显示 `events=2`

评估器在第二个事件 `你 → 学习` 发现概率为 0 后立即返回，因为此时整组测试数据的总 NLL 和困惑度已经确定为无穷大。这里的 `events=2` 表示“检查到第 2 个事件时失败”，不是测试集只有 2 个事件。

若希望报告完整事件总数，可以先遍历全部数据统计分母，再单独累积损失；示例选择提前返回，是为了让零概率的失败位置更直观。

### 8.2 为什么 k=0.1 比 k=1 好

在这份测试集上，加一平滑给大量未见候选分配了过多概率，压低了真实已见事件的概率。较小的 k=0.1 在“保留训练证据”和“照顾未见事件”之间取得了更好的平衡。

这不意味着 0.1 永远最好。应在开发集选择 k，然后只在测试集做最终报告。

### 8.3 用均匀模型做可解释基线

本例可预测词表大小为 7。若每一步都给所有 Token 概率 1/7：

$$
H=\log\_2 7\approx2.807355
$$

$$
\operatorname{PP}=7
$$

加 0.1 模型的困惑度约为 3.19，说明它在这份测试集上明显优于完全均匀猜测。均匀基线不能代表强模型，却很适合发现公式、分母或概率归一化中的严重错误。

## 9. 正确聚合：先加总损失，再除以总事件数

假设句子 A 有 2 个事件，平均交叉熵为 1 bit；句子 B 有 8 个事件，平均交叉熵为 3 bits。

正确的语料级交叉熵是：

$$
H\_{\text{corpus}}
\=\frac{2\times1+8\times3}{2+8}
\=2.6
$$

而不是：

$$
\frac{1+3}{2}=2
$$

也不能先求两句困惑度 2 和 8，再做算术平均得到 5。正确语料困惑度是：

$$
2^{2.6}\approx6.063
$$

### 9.1 分布式或多批次评估

每个批次都应返回：

```
该批次有效位置的 loss 总和
该批次有效位置数量
```

最后全局求和：

$$
H=\frac{\sum\_b \text{loss\_sum}\_b}{\sum\_b N\_b}
$$

不要直接平均各批次的 `mean loss`，除非每个批次的有效 Token 数完全相同。

## 10. 神经语言模型中的对应关系

自回归神经语言模型通常输出 logits。对每个位置做 softmax 后，取真实目标 Token 的负对数概率，就是该位置的交叉熵损失。

概念流程是：

```
输入 Token:  <s>   我    喜欢   自然语言
目标 Token:   我   喜欢  自然语言  </s>
                 ↓ 标签向左移动一位
logits → log_softmax → 取目标 Token 对应值 → 求负 → 对有效位置平均
```

使用 PyTorch 时，`CrossEntropyLoss` 可以直接接收未归一化 logits；`NLLLoss` 则要求输入为 log-probability。二者都要正确设置被忽略的标签位置。

示意代码：

```python
import torch
import torch.nn.functional as F

# logits: [batch, sequence_length, vocabulary_size]
# labels: [batch, sequence_length]，不计分的位置约定为 -100。
logits = torch.randn(2, 4, 7)
labels = torch.tensor([
    [1, 2, 3, 4],
    [2, 5, -100, -100],
])

# 展平后，框架只在非 -100 标签上计算平均交叉熵。
mean_nll_nats = F.cross_entropy(
    logits.reshape(-1, logits.size(-1)),
    labels.reshape(-1),
    ignore_index=-100,
    reduction="mean",
)

perplexity = torch.exp(mean_nll_nats)
print(mean_nll_nats.item(), perplexity.item())
```

这段代码用于说明接口关系，随机 logits 每次运行的具体数值会变化。真正评估时还要确认模型是否已完成标签移位，避免把当前 Token 泄漏给当前目标。

## 11. 什么时候困惑度可以直接比较

两个困惑度要直接比较，至少必须一致：

1. **同一个测试集**：文本内容与数据版本相同；
2. **同一个 Tokenizer**：分词边界和词表相同；
3. **同一个 OOV 规则**：`<UNK>` 或字节回退方式相同；
4. **同一个边界约定**：是否预测 `</s>` 相同；
5. **同一个计分掩码**：PAD、提示词或其他忽略位置相同；
6. **同一个归一化单位**：按 Token、字符还是字节相同；
7. **同一种概率定义**：必须是归一化概率，而不是任意排序分数。

### 11.1 为什么不能随便跨 Tokenizer 比较

同一段文本可以被切成不同数量的 Token。一个模型每个词一个 Token，另一个模型把同一个词拆成三个子词，它们的“每 Token 平均损失”分母不同，候选空间也不同。

因此，直接说“模型 A 的 perplexity 低于模型 B，所以 A 更好”，如果 Tokenizer 不同，通常没有充分意义。需要跨分词方案比较时，可以考虑统一到 bit/byte、bit/character 等单位，或者使用下游任务与人工评估，但仍需明确具体协议。

### 11.2 对数底不同不是根本障碍

如果一个报告用 bit，另一个用 nat，只要知道底数并正确换算，困惑度可以一致：

$$
H\_{\text{bits}}=\frac{H\_{\text{nats}}}{\ln2}
$$

真正麻烦的是 Tokenizer、测试数据与分母约定不同。

## 12. 困惑度能说明什么，不能说明什么

### 12.1 能说明什么

在严格一致的评估协议下，较低困惑度表示模型对测试序列中的真实 next-token 平均赋予更高概率，是一种内在（intrinsic）语言建模指标。

### 12.2 不能单独保证什么

较低困惑度不自动保证：

* 生成内容更真实、更安全；
* 问答任务准确率更高；
* 摘要更符合人类偏好；
* 对长程依赖和事实知识处理更好；
* 在分布外数据上仍然更好。

困惑度只衡量评估分布上的概率拟合。实际项目还要结合下游指标、鲁棒性检查和人工评估。

## 13. 常见误区与故障排查

### 误区一：在训练集上报告困惑度

训练困惑度主要说明模型拟合训练数据的程度，不能可靠代表泛化能力。应至少使用独立开发集和测试集。

### 误区二：把整句概率直接平均

句子长度不同，联合概率不可直接等权平均。应转成 Token 级 NLL，汇总后按有效事件数归一化。

### 误区三：先算每批平均 loss，再平均批次

若各批有效 Token 数不同，这会错误加权。应累计 `loss_sum` 和 `token_count`。

### 误区四：忘记计入 `</s>`

如果训练时建模结束事件、评估时却漏掉，模型的句子概率链不完整，也会让不同长度句子的处理不一致。

### 误区五：把 PAD 算入分母

PAD 只是批处理占位符。除非任务明确要求预测 PAD，否则必须用 mask 或 `ignore_index` 排除。

### 误区六：概率为 0 时加一个 epsilon 只为避免报错

临时执行 `max(p, 1e-12)` 会改变模型分布，而且通常不再归一化。应在模型层使用有理论约束的平滑，而不是在评估器中悄悄篡改概率。

### 误区七：把任意分数指数化成困惑度

困惑度要求每一步输入的是归一化条件概率。stupid backoff 分数、检索相关性分数或未经 softmax 的 logits 不能直接代入。

### 误区八：困惑度越低就一定更会生成

解码策略也会影响输出。温度、top-k、top-p 与重复惩罚不会改变基础模型在固定测试集上的标准困惑度，却会显著改变实际生成结果。

## 14. 推荐的评估报告模板

一个可复现的语言模型评估至少应报告：

```
数据：测试集名称、版本、样本数
分词：Tokenizer 名称/版本、词表大小、OOV 规则
边界：是否计入 BOS/EOS，如何切分长文
掩码：哪些标签不计分，ignore_index 是什么
模型：平滑方式或模型检查点
聚合：总 NLL、有效 Token 数、平均 NLL
单位：bit/token 或 nat/token
结果：cross-entropy 与 perplexity
异常：零概率、溢出、截断或跳过样本数量
```

同时报告总 NLL 和有效 Token 数，能够让读者独立复算平均交叉熵，也更容易发现分母错误。

## 练习与面试准备

### 30 秒口述题

请在 30 秒内回答：

> 交叉熵与困惑度是什么关系？为什么语言模型通常报告平均负对数概率，而不是直接报告句子概率？

合格答案应包含：连乘转相加、按有效 Token 数归一化、$$\operatorname{PP}=b^H$$，以及长句联合概率天然更小。

### 基础题 1：手算指标

某模型对三个真实 Token 给出的概率依次为 $$1/2,1/4,1/4$$。使用以 2 为底的对数，计算总 NLL、交叉熵和困惑度。

<details>

<summary>参考答案</summary>

三个位置的损失为 1、2、2 bit。总 NLL 为 5 bit，交叉熵为 $$5/3\approx1.6667$$ bit/token，困惑度为 $$2^{5/3}\approx3.1748$$。

</details>

### 基础题 2：数清分母

一个 batch 有两句话，普通 Token 数分别为 3 和 5；两句都预测 `</s>`；为了对齐加入了 4 个 PAD，PAD 不计分。有效事件数 $N$ 是多少？

<details>

<summary>参考答案</summary>

$N=(3+1)+(5+1)=10$。`<s>` 只作上下文不计入，两个 `</s>` 计入，4 个 PAD 排除。

</details>

### 进阶题 3：发现错误聚合

批次 A 有 100 个有效 Token，平均损失为 2；批次 B 有 20 个有效 Token，平均损失为 5。正确的总体平均损失是多少？为什么不能直接得到 3.5？

<details>

<summary>参考答案</summary>

总体损失为 $$100\times2+20\times5=300$$，有效 Token 数为 120，所以平均损失为 2.5。直接平均 2 和 5 会让只有 20 个 Token 的批次获得与 100 个 Token 批次相同的权重。

</details>

### 进阶题 4：代码审查

下面的代码有哪些风险？

```python
batch_losses = []
for batch in loader:
    loss = model(batch).loss
    batch_losses.append(loss.item())

perplexity = math.exp(sum(batch_losses) / len(batch_losses))
```

<details>

<summary>参考答案</summary>

各批有效 Token 数可能不同，直接平均 batch mean 会错误加权；还需确认 `loss` 使用自然对数、PAD/提示部分是否忽略、标签是否正确移位。更稳妥的做法是累计每批 loss 总和与有效 Token 数，再相除并取指数。

</details>

### 面试追问 5：困惑度为 10 怎么解释

推荐回答：它表示模型对真实 Token 的逆概率几何平均为 10，也可直观理解为平均面对约 10 个等可能有效选择；但真实分布并不均匀，不能解释为每步恰有 10 个候选。

### 面试追问 6：两个模型的困惑度能否比较

在回答“能”或“不能”前，先核对测试集、Tokenizer、OOV、边界、mask 和归一化单位。若 Tokenizer 不同，每 Token 困惑度通常不能直接横比。

### 项目答辩题 7：为什么离线困惑度降低，线上效果却没提升

可以从以下方向排查：

* 离线测试分布与线上请求不同；
* 下游任务不只依赖 next-token 概率；
* Tokenizer 或评估 mask 存在差异；
* 解码策略掩盖了模型差异；
* 困惑度改善集中在大量容易 Token，而关键事实或长程位置没有改善；
* 线上指标还受安全、延迟、工具调用和格式遵循影响。

## 延伸阅读

1. [Speech and Language Processing：N-gram Language Models](https://web.stanford.edu/~jurafsky/slp3/ed3book.pdf)\
   给出语言模型交叉熵、困惑度及其与测试集概率的标准定义，也是本节公式的主要来源。
2. [Claude Shannon：Prediction and Entropy of Printed English](https://onlinelibrary.wiley.com/doi/pdf/10.1002/j.1538-7305.1951.tb01366.x)\
   从逐字符预测实验讨论英语的不确定性，是语言预测与信息熵联系的经典来源。
3. [PyTorch：NLLLoss](https://docs.pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html)\
   官方说明输入应为 log-probability，并解释 `ignore_index` 与平均损失的计算范围。
4. [PyTorch：CrossEntropyLoss](https://docs.pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html)\
   官方说明 logits、类别标签、`ignore_index` 和 reduction 的语义，适合核对神经语言模型评估实现。

## 一页回顾

```
单位置惊讶度：
I(w|h) = -log_b Q(w|h)
概率越低，损失越大

总负对数似然：
NLL = -Σ log_b Q(w_i|h_i)

经验交叉熵：
H = NLL / N
N 是实际参与计分的 next-token 事件数

困惑度：
PP = b^H
   = (Π 1/q_i)^(1/N)
即正确 Token 逆概率的几何平均

计数约定：
<s> 只作上下文，不作目标
</s> 若被模型预测，就进入损失与分母
PAD、-100 等忽略位置不进入分母

正确聚合：
先汇总所有位置的 loss 总和
再除以所有有效 Token 数
不要等权平均句子 PP 或 batch mean

零概率：
q_i = 0
→ -log q_i = +∞
→ 交叉熵与困惑度为 +∞
应在模型层做平滑，而不是评估时偷偷加 epsilon

可比条件：
同测试集、同 Tokenizer、同 OOV、同边界、同 mask、同单位

指标边界：
较低 PP 表示在该评估协议下概率拟合更好
不自动保证事实性、安全性或下游任务表现
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://inwt233.gitbook.io/ai-learning/di-yi-bu-fen-nlp-ji-chu/week-02/day-010.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
