广州的四月总是多雨。雨水打在宿舍的阳台玻璃上,发出沉闷的白噪音。大四的课表已经空了,室友们大多出去实习或者在准备考公,寝室里常常只有我一个人,和一台风扇狂转的笔记本电脑。
前几天整理电脑里的文件,看着按学期分类的文件夹,里面装满了我这四年在广州商学院的各种实验报告、课程设计和读书笔记。能拿到 4.02 的绩点和两次国奖,其实没有什么特别的秘诀,无非就是把别人打游戏的时间拿来敲代码和写文档。只是看着这堆积如山的 markdown 文件,我突然觉得,传统的全文搜索已经不够用了。
2024 年了,大语言模型早就过了那个只能用来闲聊解闷的阶段,它正在变成真正的生产力工具。作为软件工程专业的学生,我开始思考,怎么把这些大模型接入到我自己的工作流里。
一切的起点,还是那串最基础的 API。
很多人觉得大模型开发门槛很高,但剥开那些复杂的算法外衣,对应用层开发者来说,它本质上就是一个 HTTP 请求。
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
},
body: JSON.stringify({
model: 'gpt-4',
messages: [
{ role: 'system', content: '你是一个技术文档助手' },
{ role: 'user', content: '解释什么是 RAG' },
],
temperature: 0.7,
}),
})
第一次在终端里看到返回的 JSON 数据时,心情其实很平静。没有什么科幻电影里的震撼感,只是一行行规整的字符串。但那一刻我知道,传统的软件工程边界被打破了。以前我们写代码,输入和输出都是确定性的,if-else 决定了程序的走向。现在,我们把一部分逻辑交给了概率,交给了这个庞大的黑盒。
这种不确定性带来了新的开发范式,也就是提示词工程(Prompt Engineering)。
一开始,我总是得不到想要的输出结果。模型要么废话太多,要么格式错乱。后来查阅了很多文档,才慢慢摸索出和这个“硅基大脑”对话的节奏。
好的提示词不是玄学,它更像是一种特殊的结构化写作。你需要给模型设定一个明确的角色,比如“你是一个有着十年经验的 Node.js 工程师”。接着是清晰的任务描述,不要用模棱两可的词汇。最重要的是输出格式的约束,如果我需要解析数据,我会明确要求它只返回 JSON,不要带有任何多余的解释。如果任务复杂,提供几个示例(Few-shot learning)往往能让准确率大幅提升。
这种感觉就像是在带一个非常聪明但没有工作经验的实习生。你把上下文给足,他就能干得很漂亮。
但很快,我遇到了大模型最致命的问题——幻觉。
当我试图让它总结我大二写的一篇关于某个冷门开源库的笔记时,它一本正经地胡说八道,编造了几个根本不存在的 API。它的知识库停留在训练结束的那一天,而且它不知道自己不知道。
为了解决这个问题,我接触到了 RAG(检索增强生成)。
RAG 的逻辑其实非常符合直觉。它就像是给那个聪明的实习生配备了一个图书馆。当用户提问时,系统不再直接让大模型凭空作答,而是先去图书馆里检索相关的文档,把这些文档连同问题一起递给大模型,告诉它:“根据这几份资料,回答用户的问题。”
整个流程的构建,花了我几个通宵的时间。
首先是数据的处理。我把四年的笔记全部读取出来,进行文档分块(Chunking)。这步很关键,切得太大,超出了模型的上下文窗口,也会引入太多噪声;切得太小,又会丢失语义的连贯性。
切分好的文本块,需要通过 Embedding 模型转换成向量。这是一种很奇妙的数学映射,人类语言中的语义,被转换成了高维空间里的浮点数数组。意思相近的句子,在那个多维空间里的距离就会更近。
用户提问时,也经历同样的过程。把问题向量化,然后去向量数据库里做相似度计算(通常是余弦相似度),找出最匹配的几个文本片段。最后,把这些片段拼接在 Prompt 里,调用大模型的 API 生成回答。
在这个过程中,不可避免地要和向量数据库打交道。
市面上的选择很多。Pinecone 是托管服务,不用自己操心运维,很适合拿来做快速的原型验证。Milvus 功能全面,是企业级部署的首选,但对于我这台老旧的轻薄本来说,跑起来有些吃力。最后我选了 Chroma,它非常轻量,作为嵌入式数据库直接在本地运行,配合 Python 或者 Node.js 开发都很顺手。
经过一周的修修补补,我的“个人知识库问答”工具终于跑通了。
那天深夜,我试着在输入框里敲下:“总结一下我大三上学期《操作系统》课程里关于页面置换算法的笔记。”
终端里的光标闪烁了几下。几秒钟后,屏幕上开始流式输出回答。它不仅准确列出了 FIFO、LRU 和 OPT 算法的核心思想,甚至还在末尾附上了我当时记下的一句吐槽:“期末考试千万别算错 LRU 的缺页率”。
看着屏幕上的文字,有一种说不出的奇妙感。这些散落在硬盘角落的、冰冷的字符,经过向量化、经过检索、经过大模型的重组,仿佛有了生命。它比传统的关键词搜索强大太多了,它理解了我的问题,也理解了我过去的思考。
作为一个民办本二(现在叫本三)的学生,我经常会感到一种信息差带来的焦虑。外面的技术迭代得太快了,从 ChatGPT 诞生到现在,不过短短一年多的时间,大模型应用开发的生态已经换了好几茬。
但当我静下心来,把从 API 调用到 RAG 检索的整条链路自己动手敲了一遍之后,那种焦虑感反而减轻了。无论概念怎么炒作,底层依然是 HTTP 请求,依然是数据结构,依然是工程化的思维。
大四的尾声,大家都在寻找未来的出路。我不知道自己最终会去哪家公司,写什么样的代码。但在广州这个潮湿的春夜里,看着终端里稳定输出的日志,我觉得挺踏实的。
大模型应用开发还在快速演进,没有谁能掌握所有的知识。保持阅读,保持对新技术的敏感,然后多在本地跑跑代码。技术的世界很公平,你敲下的每一行代码,它都会给你最真实的回应。