跳转至

序章 案例:行程助手

当前语言模型的主要应用比如:对话,代码生成等 都是相同的底层技术,本书以 搭建一个行程助手 作为贯穿整本书的实际案例,并且,先通过这个 行程助手的对话 简单,提前熟悉一些大模型术语。

这样的对话,每天我们在 豆包/gemini/chatgpt中都会有类似的询问,包括

  • 首次问题描述。模型有快速/准确的智能回答,代替传统搜索引擎的排序回复
  • 继续细化深化问题。模型有针对性的结合多层级问题的能力,代替用户自己寻找归纳
  • 纠正,更改,尝试回忆。模型拥有记忆
  • 富文本及多模态回复。模型有多模态能力
  • 精简,拟人,尝试定制化。大模型时代常见的用户希望 AI是人/非AI味 的能力
  • 扩展,建议,导流。模型有结合其他应用或更多模型的能力,作出更大的应用

用户:五一想去杭州玩三天,两个人,预算 5000,不想太赶。

助手:第一天西湖、断桥、雷峰塔;第二天灵隐寺、龙井村、九溪徒步;第三天西溪湿地。附酒店和花费估算,合计约 4600 元。

用户:第二天太累了,轻松一点。

助手:第二天改成上午灵隐寺,下午在龙井村喝茶,去掉九溪徒步。

用户:查一下那三天杭州的天气。

助手:(查询天气)5 月 2 日有雨。把西溪湿地挪到 5 月 3 日,5 月 2 日下午改去浙江省博物馆。

用户:把最终行程整理成 JSON,我要导入日历。

助手:[{"date": "2026-05-01", "time": "09:00", "place": "西湖"}, ...]

看上去,它听懂了需求,记住了预算,会查天气,还会写结构化数据。其实它们在模型里是同一个逻辑在处理。

可以看到,我混用了 模型 和 算法 这两个词,虽然算法更像是一种数学概念,但他们在本书中是一致的,都是指这种能理解语言的技术。

模型看到的是一整串文本

模型本身以文本作为输入,但是和人类理解的词句有所不同:

<|im_start|>system
你是旅行规划助手。<|im_end|>
<|im_start|>user
五一想去杭州玩三天,两个人,预算 5000,不想太赶。<|im_end|>
<|im_start|>assistant
第一天西湖、断桥、雷峰塔;第二天灵隐寺、龙井村、九溪徒步;……<|im_end|>
<|im_start|>user
第二天太累了,轻松一点。<|im_end|>
<|im_start|>assistant

<|im_start|>、<|im_end|> 是词表里专门留出来的特殊符号,各占一个编号,用来标出每一段是谁说的。这串文本停在最后一个 assistant 后面,模型要做的只有一件事:续写。它一个词一个词地续写,直到写出 <|im_end|>。应用看到这个符号,就把刚写出的内容当作一轮回复,显示给用户。

所以「聊天」在算法上就是续写:给定前面整串词句,或者我们叫做 token,预测下一个 token,把它接到末尾,再预测下一个。 token这个概念是自然而然的,是符号,是单词,是句子,你可以理解 token就是这些语言模型能理解的小东西。在第一册中我们会详细了解模型对输入的处理流程。

什么是“行程助手”

如果只拿网页、书籍、代码做预训练,得到的是基础模型。把上面那串文本交给基础模型,它也会续写,但可能写成一篇游记

「行程助手」的角色,主要靠的是后训练流程。先拿大量按上面模板写好的对话做训练数据,做监督微调,再用人类偏好或可验证的奖励做强化学习,让它更倾向写出有用、守约束的回复。后训练我们会在第三册展开讲怎么改模型。

真的有记忆么

第三轮中,用户没再提预算,助手仍然按 5000 在设计。并不是模型把预算存进了某个记忆单元中。

实际上,每一轮,模型都把全部历史重新拼进输入。第一轮那句「预算 5000」一直留在这串文本里,助手每写一个新“词”(token),一种叫注意力的算法机制 都能回头看到它。而对话中的记忆,就是模型看到了的全部token,这也叫做上下文,上下文能看到多少也是模型的一种基础能力。

所以现在,我们简单了解到

  • 历史越长,每写一个字要回看的 token 越多,越聊越慢,在第一册第四章中我们把这种行为叫做 推理 ,推理得越来越慢。
  • 模型可以理解行程中的先后顺序,在第一册第六章我们会介绍模型怎么理解位置关系。
  • 上下文还有上限,超过训练长度开头的约束可能读不准,在第一册第十一章我们会详细讨论这个问题。
  • 现代语言大模型其实工作的很流畅,可以完全替代之前的搜索引擎和专家问答系统。你会看到它们一个字一个字的吐出来,但是速度很快。这是因为 为了不在每一步重算历史,推理时会把历史 token 的关键信息(K,V)存下来复用,当然这块缓存会占掉大量存储地方(第 4 章、第 7 章)。
  • 跨会话的长期记忆,比如下个月再来时它还记得用户不爱爬山,模型本身能否做到?常见做法是应用把过去对话的要点存进外部数据库,下次按需检索出来,再塞回上下文。在第三册中我们会继续探索检索和agent等内容

外挂应用

查天气这一步,模型并没有联网。它续写出的是一段约定格式的文本,例如:

<tool_call>
{"name": "get_weather", "arguments": {"city": "杭州", "date": "2026-05-02"}}
</tool_call>

应用识别出这种格式,去调用天气接口,把返回结果作为新的一段拼回输入,模型再接着续写。它读到「5 月 2 日有雨」,据此改行程。工具调用在模型这一侧,仍然只是写文本、读文本。

最后那段 JSON 也一样。代码、JSON、表格和中文句子一样,都是 token 序列。模型在预训练里读过海量代码,又在后训练里练过按格式输出,所以能写出括号配对、字段齐全的结构;写 Python 脚本、写 SQL,是同一个原理。区别在于代码对格式极敏感,一个 token 出就跑不起来,所以生成代码时的解码通常更保守(第一册会简单提到温度与采样)。

回顾

我们会在每一章开头,尽量回到这个行程助手上,用技术组件说清楚语言模型 1. 在干什么? 2. 理论依据? 3. 会有什么问题?

问题 在哪一章回答
对话怎么变成 token;回复为什么会在结束符处停下 第 1 章
「轻松一点」怎么对上第一轮给的第二天;「记得预算」在计算上是什么;语序与归一化怎样让模型跑起来 第 2 章
字怎么变成向量、隐藏状态怎么变成下一个词;为何是 decoder-only 第 3 章
为什么聊到第 30 轮,回复明显变慢、显存越占越多 第 4 章
放大之后为何改归一化;绝对位置为何换成 RoPE;聊太长开头为何读不准 第 5–6 章
同一张显卡,怎么让对话聊得更长、同时服务更多用户 第 7 章
前两部的零件怎样配成一台能接话的模型;它为什么仍然慢、长了仍会丢约束 第 8 章
景点、交通、酒店这么多知识,怎么装进来又不让每个字更贵 第 9 章
再贴进一份 200 页的攻略,显存、速度、准确率为什么同时出问题 第 11–13 章
那份很长的 JSON 行程表,能不能写得更快 第 15 章
一个真实旗舰模型走完整段对话,卡在哪里 第 16 章