ToolBox

AI 应用开发实战教程

第 2 章 · 认知打底与 Prompt 工程

3/9
教程/AI 应用开发实战教程/第 2 章 · 认知打底与 Prompt 工程
3 节 / 共 9 AI 应用开发实战教程

第 2 章 · 认知打底与 Prompt 工程

第 2 章 · 认知打底与 Prompt 工程

本章目标:搞懂"大模型到底是什么",并能熟练地"指挥"它干活。不涉及任何神经网络公式。


2.1 大模型到底是什么

先破掉一个常见的错误直觉。很多人以为大模型是个"聪明的搜索引擎"或"知识库"。它不是。

大模型(LLM,Large Language Model)本质上做一件事:给定前面的一段文字,预测下一个最可能出现的词(token)

举个例子,如果你给它:

"中国的首都是"

它会基于海量训练数据,算出下一个词最可能是"北京"(概率约 99%),其次是"上海"等。它没有去"查询"一个数据库,而是"算"出了概率最高的续写。

这带来两个直接推论,也是你后面理解一切的钥匙:

  1. 它生成的是"最像"的答案,不是"正确"的答案。 所以它会一本正经地编造——这叫"幻觉"。
  2. 它的能力上限取决于训练数据。 训练数据截止之前的、公开的、高频的知识它知道;你公司的内部文档、你昨天才改的代码,它一概不知。这正是后面 RAG(第 4 章)要解决的问题。

所以,把 LLM 当成一个"会推理、但会出错的组件"来用,而不是当成真理来源。 这句话贯穿整个教程。


2.2 Token:模型的最小处理单位

模型不直接读"字",而是读 token。Token 是文本被切分后的最小单元。

  • 英文里,一个常见单词 ≈ 1 个 token(如 "hello" ≈ 1 token,但 "unbelievable" 可能拆成 2-3 个)。
  • 中文里,1 个汉字 ≈ 1~2 个 token(通常约 1.5 个)。所以"你好"大概 2~3 个 token。

为什么你必须懂 token?因为几乎所有东西都按 token 算

  • 计费:API 按"每百万 token"收费。输入 token 和输出 token 价格通常不同(输出更贵,一般是输入的 2~4 倍)。
  • 上下文窗口:模型一次能处理的 token 总量是有限的(比如 128K)。
  • 成本优化:一个请求里,输入 token 越多越贵。所以后面会学"怎么少喂、喂精"。

记一个量级:128K 上下文 ≈ 10 万~15 万汉字。一本 30 万字的小说约 40 万 token,超出了 128K 窗口。


2.3 上下文窗口:模型的"短期记忆"

上下文窗口(Context Window) 是模型一次能"同时看到"的 token 总数上限。

你一次请求里塞进去的所有东西——system 提示词 + 历史对话 + 用户问题 + 模型要输出的内容——全部加起来不能超过这个窗口

两个必须知道的后果:

  1. 超了会截断。 如果对话太长,最早的内容会被挤出去,模型就"忘了"前面说过的话。这就是为什么你跟 ChatGPT 聊久了,它会忘记你一开始交代的事。
  2. 窗口不是越大越好用。 即使没超,内容塞得越长,模型越容易"注意力涣散"——关键信息被淹没在大量无关文字里。所以工程上讲究"把最相关的信息精炼地喂进去",而不是"全塞进去"。

对应到实战:长对话要主动做"记忆管理"(第 6 章),RAG 要"只检索最相关的几段"喂进去(第 4 章)。


2.4 三种角色:system / user / assistant

调用 API 时,messages 是一个数组,每个元素是一个 {role, content}。三种角色各有分工:

角色 作用 例子
system 定"人设"和全局规则,优先级最高 "你是一个严谨的数据库专家,只写标准 SQL。"
user 用户的具体提问/指令 "把'上月入库总量'翻译成 SQL。"
assistant 模型自己的回答(用于记录历史,或给模型做示范) 模型上一条回答的内容

一个关键技巧:system 是"管住模型行为"的第一道闸。你把规则写进 system,比写进 user 更稳,模型更不容易跑偏。比如你要它"只输出 JSON、不要废话",写进 system 比每次在 user 里叮嘱更可靠。

另外,assistant 角色能用来"做示范"——你在历史里放几组"用户这样问、助手这样答"的例子,模型会模仿这个风格。这就是 Few-shot 的原理(见 2.7)。


2.5 核心参数:temperature 和 max_tokens

temperature(温度,控制随机性)

取值范围通常 0~2,决定模型输出的"发散程度":

  • 越低(如 0):输出越确定、越保守,几乎每次都一样。适合需要稳定、准确的场景(SQL 生成、JSON 输出、抽取)。
  • 越高(如 1 以上):输出越随机、越有创意。适合写诗、起名、头脑风暴。

经验法则:要"确定性"的任务(代码、SQL、结构化数据)用低温度;要"创意"的任务(文案、标题)用高温度。

max_tokens(最大输出长度)

限制模型最多输出多少 token。注意它只管输出,不管输入。设小了答案会被截断,设大了浪费钱。

其他参数(top_p、frequency_penalty 等)前期不必深究,需要时查文档即可。


2.6 幻觉:为什么模型会一本正经地胡说

幻觉不是 bug,是 LLM 的"本性"——因为它做的是"预测最像的续写",不是"查证事实"。

典型场景:

  • 编造事实:你问"XX 公司的股价",它可能编一个数字。
  • 编造引用:你让它列参考文献,它可能编出根本不存在的论文。
  • 编造 API:你让它写代码,它可能调用一个不存在的函数(这也是为什么第 3 章要强调"结构化输出 + 人工校验")。

缓解幻觉的几条实用手段(按性价比排序):

  1. RAG(第 4 章):把真实资料检索出来喂给它,让它"基于资料回答",而不是凭空编。
  2. 约束输出:让它只输出你给定格式的内容,不给它自由发挥的空间。
  3. 降低温度:减少随机性,减少"脑补"。
  4. 让它承认不知道:在 prompt 里写"如果信息不足,直接说'我不知道',不要编造"。
  5. 人工/程序校验:关键数据(数字、SQL、接口)永远要程序二次验证。

2.7 Prompt 工程:怎么把话说清楚

Prompt(提示词)就是你和模型的"沟通语言"。写 Prompt 没有玄学,核心就一条:把"背景、任务、要求、输出格式"都说清楚,别让模型猜。

下面这套方法,按实用性从高到低排:

方法 1:结构化指令(最常用,先用起来)

一个清晰的 Prompt 通常包含四块:

  1. 角色:你是谁、擅长什么。
  2. 背景/上下文:这件事的前因后果、可用信息。
  3. 任务:要做什么,拆成清晰的步骤。
  4. 要求/输出格式:怎么输出、有什么约束。

差例子(信息全要模型猜):

帮我写个SQL

好例子

你是一名数据库工程师。
背景:我们有一张收粮入库表 grain_inbound,字段有:id、batch_no(批次号)、
      weight_kg(入库重量公斤)、grain_type(粮食品种)、inbound_time(入库时间)。
任务:把用户的需求翻译成一条 MySQL 查询语句。
要求:只输出 SQL 代码,不要解释,不要用代码块包裹。

差别一目了然:好例子给了表结构、给了输出约束,模型几乎不会跑偏。

方法 2:Few-shot(给例子)

模型特别擅长"模仿"。你给它 2~3 个"输入→输出"的例子,它就能照葫芦画瓢。

把用户需求翻译成 SQL,规则如下。

示例1:
用户:"查一下玉米的总入库量"SELECT SUM(weight_kg) FROM grain_inbound WHERE grain_type='玉米'
示例2:
用户:"昨天入库了几批"SELECT COUNT(*) FROM grain_inbound WHERE DATE(inbound_time)=CURDATE()-INTERVAL 1 DAY

现在处理:
用户:"上个月小麦一共进了多少吨?"

给了例子,模型对"该怎么翻"有了明确的参照,准确率大幅提升。

方法 3:思维链(Chain of Thought,CoT)

对于需要推理的复杂任务,加一句"请一步一步思考,先分析再给结论",能让模型多"想"一会儿,显著减少低级错误。

用户问题:某批次玉米入库 5000 公斤,含水率 14%,按标准含水率 12% 折算,
         应计多少公斤?

请一步步思考:先算水分差,再算折合重量,最后给出结论和计算过程。

注意:现在很多模型(如 DeepSeek 的思考模式)自带"深度思考"能力,会自己输出思考过程。但对于普通 chat 模型,显式加 CoT 仍然有效。

方法 4:约束输出格式

让模型按你需要的格式吐结果,方便程序直接解析:

  • JSON只输出 JSON,格式为 {"sql": "...", "说明": "..."}
  • Markdown 表格用 Markdown 表格输出,列为:品种、入库量、占比
  • 列表用要点列出,每条一行

配合第 3 章的"结构化输出"技术,这是让 AI 从"聊天"变成"可用接口"的关键一步。

方法 5:反向提示 / 自我检查

让模型自己检查自己,能再压掉一批错误:

生成 SQL 后,请自查:
1. 字段名是否都存在于给定的表结构中?
2. 是否有 SQL 注入风险?
3. 能否进一步优化?

2.8 动手:一个完整的 Prompt 实战

下面用 DeepSeek API 跑一个"会议纪要整理"的完整例子,把上面方法串起来。先确保装了 SDK:

pip install openai
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("DEEPSEEK_API_KEY", "sk-你的key"),                 # 形如 sk-xxx
    base_url="https://api.deepseek.com",
)

# 这是一段原始、杂乱的会议记录
raw_notes = """
老王说禾丰科技智粮系统这周要上线,卡在称重数据对不上,
小李说可能是地磅的串口数据有延迟,得加个重试。
张姐问财务对账功能啥时候能好,老王说下周。
最后大家定了:本周先修称重,下周财务对账,上线推到月底。
"""

response = client.chat.completions.create(
    model="deepseek-v4-flash",
    temperature=0.3,                   # 纪要要准确,温度调低
    messages=[
        {
            "role": "system",
            "content": (
                "你是一名项目助理,擅长把杂乱的口语会议记录整理成结构化纪要。\n"
                "要求:\n"
                "1. 用 Markdown 输出,分「议题」「结论」「待办」三个部分;\n"
                "2. 待办用列表,每条格式为「事项 — 负责人 — 截止时间」;\n"
                "3. 只写记录里明确提到的信息,没有的不要脑补。"
            ),
        },
        {
            "role": "user",
            "content": f"请整理以下会议记录:\n{raw_notes}",
        },
    ],
)

print(response.choices[0].message.content)

这段代码里值得注意的点:

  1. temperature=0.3:整理类任务要准确,温度压低。
  2. 规则全部写进 system:让模型从第一条回复就守规矩。
  3. 明确要求"不要脑补":直接对抗幻觉。

2.9 本章小结与练习

你该记住的:

  • LLM 是"预测下一个 token",所以会幻觉,所以要用 RAG、约束、校验来兜底。
  • token 是一切计费和长度限制的单位;上下文窗口是模型的短期记忆上限。
  • system 定规则、user 提需求、assistant 记录/示范。
  • 确定性任务低温度,创意任务高温度。
  • 写 Prompt 的四件套:角色、背景、任务、输出格式。

练习(照做才算学会):

  1. 用上面的代码,把 raw_notes 换成你自己的一段工作记录,跑通并看输出。
  2. 写一个 Prompt,让模型把你一句话的需求翻译成 SQL,并对比"有表结构说明"和"没有表结构说明"两种写法的输出差异。
  3. 故意问模型一个它不知道的冷门公司数据,观察它会不会编造,然后再加一句"不知道就说不知道",看差异。

下一章:把模型调用的"工程细节"吃透——返回结构、流式输出、异常处理、结构化输出,然后做出第一个真正的工具。