对大语言模型(LLM)应用的理解
为什么LLM记不住历史?
在模型厂商烧显卡训练出LLM的那一刻,LLM的知识和记忆就冻结了,LLM此时就相当于一个无状态的纯函数:
type llm = (prompt: string) => string
比如Claude 3.5 Sonnet,prompt长度最大就是200K 200K即200,000,我们可简单理解为文本长度,实际各家计算方式不一致
那上层应用的记忆是怎么实现的?
对于LLM的上层应用,如MCopilot,原理就类似于:
code = llm(`${对话历史} ${文档上下文} ${代码上下文} ${用户问题}`)
具体就是,把各种文本拼起来,然后送入LLM期盼结果。
const 对话历史 = '对话历史:用户:请你帮我设计一个表单组件;系统:好的,先确认需求再开始。'
const 文档上下文 = '检索到的文档:表单组件 文档示例,用以收集、校验或提交数据,主要由输入框、选择器、单选按钮组、复选框等录入项和操作按钮等构成。'
const 代码上下文 = '用户当前代码:<template><div></div></template>'
const 用户问题 = '用户问题:帮我写个包含用户名、密码的登录表单'
const code = llm(`${对话历史} ${文档上下文} ${代码上下文} ${用户问题}`)
因为LLM是无状态的,所以记忆(对话历史)其实也是入参的一部分。
每次都拼上历史记忆很难吗,为什么还是一关闭就忘光?
因为钱。
LLM按输入长度算钱。
以Claude 3.5 Sonnet为例,以200K长度输入调一次,输入成本就需**¥1.4**。
所以,所有上层应用都在努力最小化LLM的入参长度。
如:
保存全量对话历史,但调用LLM前先裁剪,只将最近的记录拼到入参里:llm(
${对话历史**.slice(-500)**} ${用户问题})保存全量对话历史,但调用LLM前先搜索,只将相关的记录拼到入参里:llm(
${**search**(对话历史, 用户问题)} ${用户问题})
够了,我有钱。

除了成本,也有原因:
-
LLM有最大输入长度限制,如 Claude 3.5 Sonnet 就是 200K
-
LLM的输入不止记忆,200K里,还得留些文本长度给文档、代码、人设、工具、用户问题之类的描述
-
LLM面对超长输入注意力也容易涣散,表现没那么好
所以开发上层应用其实就是一种 在有限的输入长度内 平衡各文本成分 以获取更好结果 的艺术。
应用案例
智能客服
// 一般的:直接让大模型回答
回答 = llm(`${用户问题}`)
// 高级点:先常规文本搜索一波,再结合搜索结果和用户问题,送给大模型阅读后回答(RAG)
回答 = llm(`${search(知识库, 用户问题)} ${用户问题}`)
// 再高级点的:在文本搜索前,先让大模型提炼下用户问题里的关键字,提高搜索结果质量(优化RAG召回)
回答 = llm(`${search(知识库, llm(`提炼关键字 ${用户问题}`))} ${用户问题}`)
// 再再高级点的:纯文本关键字匹配还是弱,不如先把句子编码为向量,在高维语义空间检索相关内容(优化RAG召回:引入向量数据库)
回答 = llm(`${search(embedding(知识库), embedding(用户问题)))} ${用户问题}`)
智能代理(AI Agent)
此时,LLM的角色为:
自然语言需求 的任务规划器
自然语言需求 -> 标准命令调用 的解析器
自然语言需求 + 命令调用结果 的总结器
// 穿衣建议 AI Agent 伪代码
function AI穿衣建议() {
工具函数 = [
获取今天日期: () => 日期,
查询某日天气: (日期) => 天气,
]
对话记录 = [
`系统:你负责根据天气给出穿衣建议,你有这些工具可用:${工具函数},需要使用时请按工具描述回复,给出建议后请以<END>结尾`,
]
do {
对话记录.push(`用户:${input()}`)
回答 = llm(`${对话记录}`)
if (回答是要调用工具) {
对话记录.push(`调用工具:${回答}`)
工具结果 = 按回答调用工具函数(回答)
对话记录.push(`工具结果:${工具结果}`)
continue;
}
// 普通回答
对话记录.push(回答)
} while(回答.endWith('<END>'))
return 对话记录[-1] // 返回最后一个大模型的回答
}
AI穿衣建议('明天穿裙子可以吗?') // 预期:获取今日日期 -> 加一天 -> 查询天气 -> 综合总结建议
AI穿衣建议('我准备去跑个10公里') // 预期:获取今日日期 -> 查询天气 -> 综合总结建议
AI穿衣建议('雨天适合穿什么鞋?') // 预期:建议