2025-06-10 08:50:32
🖼️ 多图
坐上 K684,开启去往大连的旅途。
这趟卧铺有很多好处:
酒店定在了中山广场,
早上 7 点到了酒店,直接就可以办入住了(赞一波亚朵)。
然后包放下以后就直接坐地铁来到了东港。
这一天还是端午节的最后一天,并且天气一般,预想到体验可能不会很好,不过实际逛下来还是比想象中的好不少。
几个景点的感受:
回酒店吃了一个午饭歇了一会,下午直接打车到海之韵公园继续漫步。
海之韵公园从北门进,上来就是一段超级大上坡,差点没给人累死,在大太阳下走了快半小时才到山顶,不过从山上眺望大海的感觉还蛮好的。
往山下走,为了看一个网红景点「圣象天门」跟着一群大胆的游客翻了好几个护栏和挡板,到了以后发现不过如此,一大群人排队围着一个山洞拍照,虽然到达这里花了很大一番功夫,但是真正到了之后,我也懒得挤过去凑热闹了。
可能每个人对于旅行的理解都不一样,不过我是不太喜欢到了一个地方,就要打卡那些「出片」的网红景点,反倒是喜欢钻入无人的犄角旮旯去探索一下。
一路上发现了好多可爱小猫,最喜欢的是这只大橘和这俩狸花:
出了海之韵公园南门,就一直沿着滨海东路走啊走啊,一个下午走了快 30km,4 万步。自己走路有一个好处就是不必迁就他人,遇到想走的路和想看的东西,就直接走就完事了。
大连是丘陵地带,海边没有沙滩,只有断崖和礁石滩,这边整个滨海东路都是断崖,也是一种独特的风格。
随处可见这样的告示:
途中遇到可以拐下去的地方,无一例外都选择了下去看看,遇到了很多惊喜的景点。
许多地方就是沿着断崖修建的小路或者房子,左边是树林,右边就是一望无际的大海。
第二天一早就打车来到了老虎滩-菱角湾。
假期过了,天气晴了,大海的颜色变成深邃的蓝,拍照非常好看。
大连的海边有非常多的本地钓鱼佬,都是轻装出行,一根钓竿一把小椅子,一坐就是大半天,给人一种非常 chill 的感觉。
一路上都是这种非常舒适的步行木栈道,基本覆盖了从海之韵公园出来一直到星海广场这一条几十公里长长的海岸线。
走到付家庄公园,远看是一个沙滩,近看原来是石子组成的。
快黄昏时走到了大连的标志性建筑「星海湾大桥」,这个 6.8km 的跨海大桥从各个角度看过去都很壮观。
日落时桥上还会亮起不同颜色的灯光,不过当时有点冷,就没在山顶逗留了,不然俯视角下的夜景应该会很好看。
体验了一下大连的有轨电车,由于是工作日车上没什么人,车晃悠的不行、叮铃哐啷的很有意思。
大连城市的街道两旁见不到任何共享单车,不过倒是有一些共享的电动车,可能是因为城市规划的原因(没有非机动车道),并且丘陵地带很多陡峭的上下坡,确实不太适合骑单车。
晚上 8 点来到南山街,没有想象中热闹的街景,只有节日过后人们正在收拾残局。
而且大连的风真的很大,即使在城区里也能吹的人头秃,于是匆匆离开。
写这篇 Blog 的时候这次旅行已经过去快 2 周了,不过一切景物还是历历在目。
旅行这种事情确实能极大的减缓时间流逝的感觉,让人重拾起一种控制时间与生活的信心。
滨海城市的旅行体验真的极好,有时间会再去威海、青岛这些地方看看。
很喜欢的一句话:
只有一个人旅行时,才听得到自己的声音。它会告诉你,这世界比自己想象中更宽阔。
2025-05-29 19:35:05
毕业答辩结束,又因为还需要等着提交材料没法长途跋涉,想着天津离北京这么近又还没去过,索性去看看。
5月末,白天的天津,炎热难耐,走在大街上,似乎不存在斑马线和行人红绿灯。
好多好多的单行道和狭窄街道。下火车出了地铁左转,因为没有人行道,只能在逆行穿过一股酒味的涵洞。
第一顿当然尝一下天津菜,没想到分量巨大无比,一盆炒鸡估计炒了不止一只鸡。
两个饭量还不错的人吃了一个小时,最后菜和没动一样。
晚上去天津站码头坐了海河游船,也是此次天津之行感觉最值回票价的体验。
出了天津站就是码头,长长的海河沿线几乎包含了所有天津有名的景点。
如果天津没有这条海河,也许我给的评价还不如我老家。
周围高楼林立,每个楼都闪着金光,有种轻奢感。
平平无奇的周内工作日,海河周围散步的人也是熙熙攘攘。
到了晚上 10 点多才逐渐安静下来,这时沿着河边散步几乎只剩下一个个卖酒的小摊贩。
心情还不错的时候,吹着晚风这么喝一杯还挺惬意。
白天走马观花的看了世纪钟广场、津湾广场、西开教堂、北安桥、意式风情街、瓷房子、五大道等等一系列建筑。
如果天气凉快一点,也许还有心情停下来欣赏一番,然而 30 度的艳阳天只能让我像特种兵打卡一样匆匆拍个照就走人。
体验一般,不过即使是凉快下来,感觉白天的天津相比晚上也差了不少意思。
下午的时候实在逛不下去了,干脆花 2 小时去听下相声。
直到开场的时候才陆续来了其他两桌人,不然直接包场了,那样还挺尬的。
第一次线下花这么长时间完整的听完一场相声,感觉还不错,主要空调还很凉快。
最后又在夜风中搭观光车溜达了一圈,感觉天津城区真的好小,已经有点腻了。
还是更喜欢山川湖海。
2025-04-21 22:45:28
注意,本文不是翻译,只是针对自己觉得有用的一些地方的记录和总结;对于我自己觉得已经比较清楚的概念,就完全没有记录。其中最后的「最佳实践 Best Practice」部分个人感觉比较有用,强烈建议结合原版 PDF 的一些示例 demo 进行对比查看。
简单介绍:
「Prompt Engineering」是 Google 推出的提示词工程白皮书,一共 60 多页,原始版本可以在 https://www.kaggle.com/whitepaper-prompt-engineering 上获取到,或者直接 下载链接 (googledrive)。
主要三个可配置项:
作用的先后顺序: Top-K -> Top-P -> Temperature
假设我们有以下设置:
当模型预测下一个词时,可能给出了这样的概率分布:
应用步骤:
几种极端情况的 LLM 实现考虑:
Use Case | Temperature | Top-P | Top-K | Description |
---|---|---|---|---|
通用场景 General Purpose | 0.2 | 0.95 | 30 | Relatively coherent results with some creativity |
高创造力场景 High Creativity | 0.9 | 0.99 | 40 | Especially creative results |
比较精确的场景 (比如coding) Low Creativity |
0.1 | 0.9 | 20 | Less creative results |
Single Correct Answer | 0 | - | - | For tasks with only one correct answer (e.g., math problems) |
系统提示(System Prompting)、上下文提示(Contextual Prompting)和角色提示(Role Prompting)都是用于指导大型语言模型(LLMs)生成文本的技术,但它们关注的重点不同。尽管这些提示类型之间存在相当大的重叠(例如,一个提示可能同时为系统分配角色并提供上下文),但每种提示的主要目的略有不同。
以下是三种提示类型的核心区别和作用:
提示类型 | 主要目的与功能 | 特点与作用 |
---|---|---|
System Prompt | 定义模型的基本能力和总体目的。 | 设定语言模型的“大局观”,例如翻译语言、分类评论等,指导模型的整体行为。 |
Contextual Prompt | 提供与当前对话或任务相关的具体细节或背景信息,指导模型生成针对性的回应。 | 高度特定于当前任务或输入,具有动态性,帮助模型理解细微差别并调整回应。 |
Role Prompt | 为模型分配特定的角色或身份,帮助模型生成与该角色一致的回应。 | 塑造模型的输出风格和语气,增加具体性和个性,使回应符合角色的知识和行为。 |
1 |
|
1 |
|
1 |
|
在为AI模型创建提示时,提供示例非常有帮助。示例可以帮助模型理解您的需求,尤其是在希望模型输出特定结构或模式时特别有用。
Step-back prompting 是一种通过提示 LLM 先考虑与具体任务相关的一般性问题,然后将该问题的答案输入到后续的具体任务提示中来提升性能的技术。这种“step back”方法使 LLM 在尝试解决具体问题之前激活相关的背景知识和推理过程。通过考虑更广泛和基本的原则,LLM 能够生成更准确和有洞察力的回应。
Step-back prompting 鼓励 LLM 批判性思考并以新的和创造性的方式应用知识,通过利用 LLM 参数中的更多知识来改变执行任务的最终提示,而这些知识在直接提示 LLM 时可能不会被激活。它还可以通过关注一般原则而非具体细节来帮助减轻 LLM 回应中的偏见。
传统 prompt:
1 |
|
step-back prompt:
1 |
|
1 |
|
编写提示(prompt)可能是一项复杂的任务。为了解决这个问题,可以采用Automatic Prompt Engineering (APE)方法。这种方法不仅减少了人工输入的需求,还能提升模型在各种任务中的表现。你可以让模型生成更多提示,对它们进行评估,可能的话修改好的提示,然后重复这个过程。
case:
1 |
|
这节没什么特别出彩的,就是列举了几个 coding 的用法,不过可以参考一下 Gemini 在 coding 时是如何推荐配置 topk, topp 和 temperature 的
Top-P:1
writing code
1 |
|
1 |
|
1 |
|
1 |
|
这个很有价值,一些很容易想到和验证的概念,但是 Google 帮你总结出来了
最重要的原则是在提示中提供示例(one shot/few shot)。这是高效的方法,因为它能作为强大的教学工具。这些示例展示了期望的输出或类似的响应,让模型从中学习并相应地调整其生成内容,提高准确性、风格和语调。
提示应该简洁、清晰,易于你和模型理解。如果对你来说已经令人困惑,对模型来说也可能令人困惑。尽量不要使用复杂的语言,不要提供不必要的信息。
示例改进:
1 |
|
尝试使用描述动作的动词,例如: Act, Analyze, Categorize, Classify, Contrast, Compare, Create, Describe, Define, Evaluate, Extract, Find, Generate, Identify, List, Measure, Organize, Parse, Pick, Predict, Provide, Rank, Recommend, Return, Retrieve, Rewrite, Select, Show, Sort, Summarize, Translate, Write.
要明确期望的输出内容。简洁的指令可能不足以引导LLM或过于笼统。在提示中提供具体细节(通过系统或上下文提示)可以帮助模型专注于相关内容,提高整体准确性。
推荐做法:
1 |
|
不推荐的做法:
1 |
|
研究表明,在提示中专注于积极指令比过度依赖约束更有效。这与人类偏好积极指令而非列出不应做的事项的方式一致。
指令直接传达期望的结果,而约束可能让模型猜测什么是允许的。指令在定义的边界内提供灵活性并鼓励创造力,而约束可能限制模型的潜力。此外,约束列表可能相互冲突。
约束在某些情况下仍然有价值,例如防止模型生成有害或有偏见的内容,或当需要严格的输出格式或风格时。
如果可能,使用积极指令:不要告诉模型不要做什么,而是告诉它应该做什么。这可以避免混淆并提高输出的准确性。
示例:
1 |
|
要控制生成的LLM响应的长度,你可以在配置中设置最大token限制,或在提示中明确要求特定长度。例如:
1 |
|
在提示中使用变量,可以针对不同输入而改变。例如,提供关于城市的事实的提示。与其在提示中硬编码城市名称,不如使用变量。变量可以通过避免重复自己来节省时间和精力。如果需要在多个提示中使用相同的信息,可以将其存储在变量中,然后在每个提示中引用该变量。在将提示集成到自己的应用程序中时,这非常有意义。
示例:
1 |
|
不同的模型、模型配置、提示格式、词汇选择和提交方式可能产生不同的结果。因此,实验提示属性如风格、词汇选择和提示类型(零样本、少样本、系统提示)很重要。
例如,对于一个目标是 “生成关于革命性视频游戏机Sega Dreamcast的文本” 的 Prompt,其可以表述为问题、陈述或指令,产生不同的输出:
一般来说,few-shot (少样本)示例的顺序不太重要。然而,在进行分类任务时,确保在few-shot示例中混合可能的响应类别。这是因为否则你可能会过度拟合到示例的特定顺序。通过混合可能的响应类别,你可以确保模型正在学习识别每个类别的关键特征,而不是简单地记住示例的顺序。这将导致在未见数据上更强健和可泛化的性能。
一个好的经验法则是从6个few-shot 示例开始,并从那里开始测试准确性。
跟踪模型架构变化、添加的数据和功能很重要。尝试更新的模型版本,并调整提示以更好地利用新的模型特性。
例如,对于非创造性任务,如提取、选择、解析、排序、排名或分类数据,尝试让输出以结构化格式如JSON或XML返回。
从提取数据的提示中返回JSON对象有一些好处。在真实应用中,我不需要手动创建JSON格式,可以直接以排序顺序返回数据(处理日期时间对象时非常方便),但最重要的是,通过提示要求JSON格式,它迫使模型创建结构并限制产生幻觉。
使用JSON输出的好处总结:
对于CoT Prompt,将答案放在推理之后是必需的,因为推理的生成会改变模型在预测最终答案时获得的tokens。
使用CoT和自我一致性时,你需要能够从提示中提取最终答案,与推理分开。
对于CoT Prompt,将temperature设置为0。
思维链提示基于贪婪解码,根据语言模型分配的最高概率预测序列中的下一个词。一般来说,使用推理来得出最终答案时,可能只有一个正确答案。因此,temperature始终应设置为0。
前面已经提到过,但我们再次强调:详细记录你的提示尝试,这样你可以随时了解哪些方法行之有效,哪些不行。
提示输出可能在不同模型、不同采样设置,甚至同一模型的不同版本之间有所不同。此外,即使对同一模型的相同提示,输出句子格式和词汇选择也可能存在细微差异。(例如,如前所述,如果两个tokens具有相同的预测概率,则可能随机打破平局。这可能影响后续预测的tokens。)
建议创建一个Google表格,使用模板记录:
还建议跟踪提示的版本(迭代),记录结果是否OK/NOT OK/SOMETIMES OK,以及反馈。如果有幸使用Vertex AI Studio,保存提示(使用与文档中相同的名称和版本),并在表格中跟踪保存的提示超链接。这样,你只需一次点击就可以重新运行提示。
在使用检索增强生成系统时,还应捕获影响插入到提示中的内容的RAG系统的特定方面,包括查询、块设置、块输出和其他信息。
一旦你觉得提示接近完美,将其带入项目代码库。在代码库中,将提示保存在与代码分开的文件中,这样更容易维护。最后,理想情况下,你的提示是一个可操作系统的一部分,作为提示工程师,你应该依靠自动化测试和评估程序来了解你的提示如何针对任务泛化。
提示工程是一个迭代过程。制作并测试不同的提示,分析并记录结果。根据模型的表现改进你的提示。继续实验直到达到期望的输出。当更改模型或模型配置时,回去继续实验先前使用的提示。
2025-03-02 17:08:43
最近在看 vllm 的代码,cpu offloading 这部分它的实现还是比较简单的,这里简单记录一下。
由于大模型的参数量实在很大,所以如果想在单机上运行一般都需要跑量化蒸馏后的模型,但是有时又不想牺牲模型质量,于是CPU/SSD 卸载成为一种折衷方案,通过增加推理时间来降低内存需求。
vllm 也实现了一个简单的 cpu offload 的机制,可以通过 --cpu-offload-gb
启用。
这里发现他的实现还是比较简单的,主要就是通过这个 PR ,添加了一个 func 叫 maybe_offload_to_gpu
:
1 |
|
这个函数只有一个地方调用了:
1 |
|
cpu offload 的整个流程可以概括为:
cpu_offload_gb
读取为_CPU_OFFLOAD_MAX_BYTES
。_CPU_OFFLOAD_BYTES += p.data.numel() * p.data.element_size()
, 即参数数量 x 字节大小) 到 _CPU_OFFLOAD_BYTES
,直到超过用户配置的可 offload 大小。forward
函数,新的 forward 函数和原来的区别就是:在每次 forward 的时候,将 CPU 上的参数复制到 GPU 上,计算完后再释放 1 |
|
这里的 forward 替换设计挺有意思:
(original_forward = module.forward
):保存模块原始的前向传播函数到变量 original_forward
,为后续恢复原始实现做准备。
(在 forward
函数内的 module.forward = original_forward
):在自定义的 forward
函数内部首行,当函数被调用时,立即将模块的前向传播方法恢复为原始方法。这一步确保 functional_call
能够使用原始的前向传播逻辑,避免递归调用。
(在 forward
函数内末尾的 module.forward = forward
):前向传播完成后,再次将模块的前向传播方法设置回自定义的 forward
函数,确保下次调用时仍能触发这个包含参数加载逻辑的自定义函数。
(函数末尾的 module.forward = forward
):为了确保每次都能 hook 到 cpu -> gpu 这部分的逻辑 (参考原 PR 的解释:https://github.com/vllm-project/vllm/pull/6496/files#r1682069375)
这里的核心是使用 functional_call
配合临时的 device_state
,实现参数从 CPU 到 GPU 的动态加载。初看可能会疑惑为什么没有将参数从 GPU 释放回 CPU 的逻辑,其实这是因为 device_state
是个局部变量,函数执行完毕后其引用的 GPU 张量会自动被 Python 的垃圾回收机制释放。而原始参数依然保存在 CPU 内存中,从而实现了内存优化的目的。
同时还有一个小知识点:
nn.Module
, .cuda()
, .cpu()
和 .to(device)
方法都是就地操作,因此可以直接 model.cuda()
torch.Tensor
, nn.Parameter
这些,.to(device)
, .cpu()
, .gpu()
方法本质都是创建一个新的 Tensor,原始 Tensor 不变,因此也必须使用 a = b.cuda()
2025-01-30 18:31:18
在试用了一众 “稍后读” 和 “剪藏” 软件后, 仍然找不到满意的软件。
总结了一下针对当前的「网页剪藏」软件,现在自己不满意的几个点:
1 - 快照使用「服务器采集」: cubox, pocket 等
这种方式的缺点就在于,很多内容平台,特别是国内的平台,都需要登录才能访问完整内容。
那么这样的采集方式受限就很大,服务器端采集无法携带用户的认证信息,因此往往只能获取到部分内容或者直接无法访问。
2 - 自带的「网页解析」或者「解析为 Markdown」: obsidian / upnote 等笔记软件的 clipper
网页结构和样式的多样性使得通用解析器很难完美处理所有情况,特别是对于代码块、表格、数学公式等特殊格式,解析质量往往不尽如人意。
3 - 仅能保存 URL 的「稍后读」: raindrop 等
内容的持久性在互联网上并不能得到保证,特别是:
对于一些时刻可能下架的敏感内容,或者经常变动的网站,url 可能过一阵子就看不了了。
于是我搭建了一个联动 SingleFile, dropbox, notion, 和 telegram bot 的 workflow 来满足我的需求。
之所以说是工作流 Workflow,实际上就是将一大堆 API 串起来。
整体实现起来不难,把所有 API 写好,作为一个 notepad 喂给 cursor,基本上 10 分钟就完成了,然后接下来用了几个小时来完善整个流程。
以下是 Demo (youtube):
PS:demo 实际展示了 Telegram 的提示过程 + 服务端日志,实际上对于我而言只需要按一下「
cmd + shift + s
」 快捷键之后,剩下的一切都是服务端处理了。PPS:演示的时候 DeepSeek 又卡了,还好加了一个备用的 API。。
简单来说这个工作流如下:
总体来说个人还是挺满意的,最近搞了不少自动化,这个算是折腾比较久的和比较好玩的,于是写出来分享下。
2025-01-29 19:26:37
这几天有个需求,就是将一些中英文对话录音文件转文本,然后进行一些分析。所以就调研了一下录音转文本的方案。顺便总结一下 MacOS 上的录音/录屏方案。
STT 全称 Speech-to-Text,即语音转文本。一般有两种常见的需求:一种是将实时语音转文本的识别(流式处理),一种是将录音文件转文本。本文主要记录后者的一些方案。
目前最常见的模型是 OpenAI 的 Whisper 模型。
使用起来也非常简单,只需要两步:
1 |
|
目前一些其他的「自建」方案基本都是基于 OpenAI 的 whisper 模型: HuggingFace 的 Whisper 模型
这种自部署的优势就是安全,缺点是需要消耗本地算力,如果算力不足会比较慢,其次感觉 Whipser 对于纯英语识别来说比较好,但是对于中英文混杂的环境,效果还是比较差的。
用几家大厂的 API 方案, 比如:
目前价格是每分钟 $0.006:https://openai.com/api/pricing/
其实这个价格也不算便宜了,转一个 1 小时左右的文本就要 3 RMB 左右。
这个更贵,目前价格是每分钟 $0.016:https://cloud.google.com/speech-to-text/pricing
更多的一些厂商:
服务提供商 | 服务名称 | 收费标准 | 参考链接 |
---|---|---|---|
微软 Azure | Azure 语音服务 | 按秒计费,包含标准和自定义语音转文本,以及按字符计费的文本转语音服务 | 价格详情 |
百度智能云 | 语音识别服务 | 支持预付费包和后付费阶梯计价,根据语言模型类型定价 | 价目详情 |
阿里云 | 智能语音服务 | 一句话识别按次计费,录音文件按时长计费,语音合成按字符计费 | 费用说明 |
腾讯云 | 语音识别 | 实时识别和文件识别按日使用量计费 | 计费概述 |
华为云 | 语音交互 | 按调用时长收费,支持按量付费和套餐包 | 服务价格 |
Sonix | 转录服务 | 按小时收费或月度订阅制 | 价格详情 |
总之,API的方案确实很方便,但是价格其实都并不便宜。
于是最后我还是将眼光瞄向了国内的一些在线平台。
主要试用了科大讯飞的讯飞听见,阿里的通义听悟和字节的飞书妙记。
用起来体验如下:
Link: https://tingwu.aliyun.com/
阿里通义听悟在中英混合文本识别方面表现最为出色,且提供充足的免费额度(赠送500小时, 除此之外每天签到都可以领取 10 小时)
然后功能方面做的也很好,包括内容摘要,发言人识别,文本替换,AI改写等比较好用的功能。
Link: https://www.feishu.cn/product/minutes
飞书妙记也还不错,每月提供300分钟免费额度,勉强也还够用。
但是如果额度一旦用完,价格就有点贵了,只能付费升级到「飞书 Plus」来用不限时。
另外界面做的也挺朴素的,功能不像阿里的那么丰富,但是比较简练,作为常用的会议记录的用途也足够了。
每月仅提供20分钟免费额度,识别效果也相对一般,充值也很贵,39.8RMB/月。
性价比较低。
作为录制会议或者演讲等用途,经常有一个需求就是想同时录制 麦克风 + 系统声音.
这里介绍一下我现在用的两种能获得录音音频的方式:
录屏的话 MacOS 的 Screeshot(截屏)可以直接做到:
cmd + shift + 5
打开录屏,在选项中选择「麦克风」即可。.mov
视频文件。QuickTime Player
打开视频文件,在「文件」菜单中选择「导出为音频文件」,即可获得一个 .m4a
音频文件。有时候我们不被允许录制屏幕,这时候只能通过单独录音的方式,而 MacOS 自带的 “QuickTime” 录音只能单独录制麦克风声音,这时候就需要用到其他手段。
一种方案是利用 BlackHole,BlackHole 作为一个虚拟音频设备,可以将 macOS 系统的音频输出捕获并重新路由,使其既能被录制软件录下又能通过扬声器播放出来。具体操作可以看:知乎:macOS使用BlackHole录制系统声音的同时输出声音
另一种就是通过安装其他应用的方式,一般用的最多的是 obs,但是 obs 太大了,搞起来比较复杂和麻烦。
于是我找到了一个使用起来还不错的很轻量的开源软件「QuickRecorder」:https://github.com/lihaoyun6/QuickRecorder
使用这个软件录制出来会生成一个 .qma
文件
qma 这种文件包格式可以容纳 2个音频文件,以及一个属性文件。
使用 QuickRecorder 内置的 QMA 播放器打开 .qma
可以同步播放系统声音和麦克风声音,并且可以独立调节音量(调节之后,音量属性会被记录在文件信息里,下次打开这个文件还是这套音量配置)。如果不需要分享的话,直接用 qma 格式保存在硬盘上就行了。如果需要发给别人,qma 播放器自带导出功能,可以将两个音频文件按照用户设定的音量比例混缩成一个普通的单轨音频文件 .mp3 / .m4a
。ref