从"查字典"到"写 Prompt":奇妙学习之旅

从"查字典"到"写 Prompt":一个程序员的奇妙学习之旅


不知道你有没有过这样的经历------在班上,老师点名提问,你低着头,心里默念"别叫我别叫我"......结果老师偏偏叫你。这个"根据名字找人"的过程,计算机科学里有个专门的名词,叫查找

翻字典的智慧

想象一下,你要在一本新华字典里找到"哈希"的"哈"字。你会怎么做?

聪明如你,肯定不会从第一页开始逐字逐句地翻------那得翻到猴年马月去。你会先找偏旁部首,或者按拼音索引,咔嚓一下翻到 H 区,再顺着 ha 的音节找到目标。整个过程,快如闪电。

这就是字典(Dict)的核心思想:用索引实现 O(1) 时间复杂度的查找。

什么叫 O(1)?就是说不管字典里有一千个字还是一百万个字,你找到目标的速度基本不变------就像你翻《新华字典》和翻《辞海》,只要你会用偏旁索引,速度差不了太多。

那不用字典怎么做呢?用两个列表呗:

ini 复制代码
names = ["张三", "李四", "王五"]
scores = [85, 92, 78]

想查李四的成绩?先遍历 names 找到下标 1,再去 scores[1] 取出来。这个操作的时间复杂度是 O(n) ------名字越多,查得越慢。这就像你找一个人的电话号码,要从通讯录第一页翻到最后一页,想想就窒息。

哈希:看不见的魔法

字典为什么这么快?因为它背后有个魔法师,叫哈希函数

整个过程就像这样:

vbnet 复制代码
你给一个 key:"李四"
       ↓
哈希函数一顿操作猛如虎
       ↓
算出一个索引:42
       ↓
跳到存储位置 42,取出 value:92
       ↓
完事儿。

无论你查多少次,哈希函数都能瞬间算出位置,然后直接去取------不需要遍历,不需要比较,一步到位。

但这魔法有个"脾气":key 必须是不可变的。 为什么?因为哈希函数要求每次同样的输入必须得到同样的输出。如果 key 是个可变的列表 [1, 2, 3],你偷偷往里面加了个 4,哈希值就变了,字典就"迷路"了------它去原来的位置找,结果发现空空如也。

这就是 Python 报 unhashable type 的原因------不是字典不讲道理,是你的 key 太善变。

空间换时间:一项公平的交易

说到这里,你可能会问:字典这么牛,那为啥不啥都用字典?

答案是:字典吃内存。

还记得上面那个哈希索引 42 吗?为了能瞬间跳到 42 号位置,字典必须预先分配一大片连续的内存空间,哪怕很多位置暂时空着。这就像你租了一整层写字楼,但目前只用了三个工位------剩下的地方都在吃灰,但你需要的时候随时能用。

反观列表,它就像一个精打细算的背包客,有多少东西占多少空间,绝不浪费。唯一的代价是------每次找东西都得翻一遍包。

Dict / 哈希表 List
查找速度 闪电 ⚡ O(1) 蜗牛 🐌 O(n)
内存占用 土豪 💰 大 打工人 🪙 小
适合场景 高频查找 顺序遍历、省内存

所以选什么数据结构,本质上是在时间空间之间做一笔交易。没有银弹,只有取舍。

Set:一个"只要钥匙不要锁"的异类

如果说 Dict 是一个钥匙配一把锁,那 Set 就是------只收钥匙,不要锁。

ini 复制代码
d = {"name": "张三"}   # dict:有 key 有 value
s = {"张三", "李四"}    # set:只有 key,没有 value

Set 的核心用途很纯粹:去重 + 快速判断存在性。 比如你想知道某个用户是不是 VIP,把 VIP 名单放进 Set 里,O(1) 时间一查便知。

它的底层和 Dict 几乎一模一样------都是哈希表。唯一的区别就是 Dict 的每个槽位存了 value 的指针,而 Set 不存。少了一根指针,但思路如出一辙。

不可变对象的"欺骗术"

说到不可变,有个特别容易踩的坑:

bash 复制代码
a = "abc"
a.replace("a", "A")
print(a)  # 你猜输出什么?

如果你猜 "Abc",恭喜你,答错了。

输出还是 "abc"

为什么?因为 "abc" 这个字符串对象本身是不可变的 ------replace 根本没有修改它,而是生成了一个全新的字符串 "Abc",然后......这个新字符串没有被任何人接收,就这么无声无息地消失了。

ini 复制代码
a = "abc"
b = a.replace("a", "A")  # b 指向新对象 "Abc"
print(a)  # "abc" ------老伙计还在
print(b)  # "Abc" ------新面孔登场

所以,"不可变对象调用自身的方法也不会改变自身",这句话值得刻进肌肉记忆里。str 的所有方法都是"创造新东西",不是"改造旧东西"。

顺便提一句:JavaScript 里如果定义了两个同名函数,最后一个会覆盖前面的------函数提升时变量优先,但函数之间后来者居上。这也算是一个历史悠久的小彩蛋。


中场休息:我们现在有了什么?

我们有了:

  • Dict:O(1) 查找的哈希表,空间换时间的典型代表
  • Set:没有 value 的 Dict,专门干去重和存在性判断
  • 不可变对象:字符串的"表面温柔,内心固执"
  • 一个重要的认知:数据结构的选择永远是取舍

那么,这些东西和 LLM、Prompt Engineering 有什么关系?

关系大了。

Prompt 的本质:给大模型一本"好字典"

想一想,大模型处理你的 Prompt 时,它在做什么?

它要把你输入的自然语言"哈希"到一个语义空间中,找到最匹配的知识和推理路径,然后生成回复。这个过程,比你想象的更像字典查找。

如果你给了一个模糊的 Prompt:

"帮我写点东西。"

大模型的"哈希函数"一算:这输入太泛了,到底映射到哪个语义区域?写诗?写代码?写情书?写辞职信?于是它开始随机采样------这就是为什么模糊的指令经常得到不着边际的回答。

但如果你给了一个清晰的 Prompt:

"你是一个资深 Python 讲师,请用通俗易懂的语言,向初学者解释什么是哈希表,要求包含代码示例和生活类比,字数控制在 500 字以内。"

大模型的"哈希函数"一算:目标明确,路径清晰------直接定位到"Python 教学 + 哈希表 + 初学者友好 + 500 字"这个语义槽位,产出自然精准。

这就是 Prompt 的第一原则:撰写清晰、具体的指令。 给大模型足够的上下文和约束,就像给哈希函数一个精确的 key------O(1) 直达目标,不走弯路。

思维链:让推理"一步步来"

还有一个高阶技巧,叫引导模型逐步推理

这就好比你问一个人:"987 × 654 等于多少?" 对方如果心算,可能出错。但如果你说:"先算 987 × 600,再算 987 × 54,然后加起来。" 他出错的概率就小多了。

大模型也是同样的道理。在 Prompt 里加上一句"让我们一步步思考",让它把推理过程写出来,最终的答案质量往往高出一截。这就是所谓的 CoT(Chain of Thought)。

LLM API:几个关键的"旋钮"

当你用代码调用大模型 API 时,有几个参数值得认识:

ini 复制代码
def get_response(prompt, model=""):
    # ...

其中 temperaturemax_tokens 是最常用的两个"旋钮":

  • temperature(0~1) :控制随机性。设为 0,模型像个严谨的数学家,同样的问题永远给出几乎一样的答案;设为 1,模型像个喝了点酒的诗人,天马行空,每次都不一样。写代码、做数学题时调低一点,写诗、头脑风暴时调高一点。
  • max_tokens:控制输出长度。相当于给模型一个字数上限,超了就截断。不是越大越好------合适才是最好的。

还有一个小技巧:Python 的 f"""...""" 是写 Prompt 的神器。三引号支持多行文本,f 前缀可以嵌入变量,整个 Prompt 就像一个模板一样清爽:

ini 复制代码
prompt = f"""
你是一个{role},请回答以下问题:
问题:{question}
要求:
- 语言:{language}
- 字数:{word_count} 字以内
"""

干净利落,比一堆 + 号拼接强太多了。


一个美丽的闭环

回过头看,你会发现一条有趣的线索贯穿始终:

概念 核心思路
字典(Dict) 精确的 key → O(1) 查找 → 准确的 value
哈希函数 同一个 key → 同一个索引 → 确定性
好 Prompt 清晰的指令 → 精准的语义定位 → 符合预期的输出
Temperature=0 同样的输入 → 同样的输出 → 确定性
思维链 分步推理 → 降低出错 → 更可靠的结果

底层逻辑出奇地一致:输入的质量决定输出的质量;确定性带来可靠性。

无论是写代码时选数据结构,还是调用大模型时写 Prompt,你都在做同一件事------用最合适的方式,把"输入"映射到"输出"。Dict 用哈希函数完成这个映射,LLM 用 Transformer 的注意力机制完成这个映射,而你的 Prompt,就是那个决定映射方向的 key。

写 Prompt 就像设计一个字典的 key:越精准,越清晰,结果就越靠谱。


感谢阅读。愿你的字典查找永远是 O(1),愿你的 Prompt 永远直击目标。🎯

相关推荐
云宝大王1 小时前
JavaScript 异步编程:从回调到探索 Promise的秘密
前端·javascript
daols881 小时前
vxe-table 进阶:同时使用 formatter 与 cell-render 实现格式化与样式定制
前端·javascript·vue.js·vxe-table
前端张三1 小时前
ant design vue table 使用虚拟滚动
前端·javascript·vue.js
Asize1 小时前
重生之我在 Vibe Coding 时代当程序员:第十一课,JS底层 :变量提升真相
前端·javascript
HYCS1 小时前
用pixi.js实现fabric.js(五):事件系统
前端·javascript·canvas
小宇AI1 小时前
用纯 Node.js 写了一个 JS 解释器 — kernel-js-lite
javascript
范什么特西2 小时前
狂神Vue
前端·javascript·vue.js
怕浪猫2 小时前
Electron 开发实战(六):系统交互与原生功能实战全解
前端·javascript·electron
wyc是xxs2 小时前
用纯 Node.js 写了一个 JS 解释器 — kernel-js-lite
开发语言·javascript·npm·node.js