又是Debug的一天
2024-08-19 07:23
有一天,你……
- 通过Hugging Face下载了meta-llama/Meta-Llama-3.1-8B-Instruct 模型。
- 按照官网指导,向模型提供了一些本地函数,让模型调用。
- 比如官网上的这个例子:本地有一个python函数可以获取各个城市的气温,你告诉Llama这个函数的函数名和参数列表,然后问它:巴黎现在是多少度?
- Llama会回复一个特殊的消息,本质是说它想call什么什么函数,参数是“法国,巴黎”。
- 你call了这个函数,得到结果是22.0。你在消息历史里添加了两条:一是Assistant说它想call什么什么函数;二是你在本地调用了什么什么函数,返回值是什么。
- (那么你为什么不自己去用这个函数查看巴黎的温度呢?问得好!下次别问了。)
- 你准备把这个消息历史发还给Llama。
- 你把消息历史交给tokenizer,让它用聊天模板进行tokenize。
- tokenizer报错:TypeError: Object of type Undefined is not JSON serializable
- 你开始debug…
- 你发现:触发这个异常的是Jinja2。
- 你去学习什么是Jinja2…
- 你回来了。你没学懂。
- 好像是说Jinja2要转换一个JSON序列,惊奇地发现对方的类型不是JSON序列,而是Undefined。
- Python里有Undefined类型吗?你只知道JavaScript里有。
- 这件事情发生在使用模板生成prompt的阶段。
- 你去找tokenizer用的模板…
- 找到了!从一个什么config.json文件里读取的。
- 你点开一看,模板是一个字符串,不分行,有几千个字符。
- 你按照字符串里换行符的位置敲回车给字符串分行…
- 敲着敲着你终于看懂了。这篇长文讲述了tokenizer如何从消息列表中提取信息,插入到prompt模板中。
- 做这件事的是Jinja2.
- 原来这tm叫Jinja2。
- 你看到有一部分是关于如何处理含有函数调用的消息。
- 你跟着它描述的过程,看哪一步时可能会出问题…
- 看到处理函数参数的那一步,你发现:
- 模板里说应该从消息里读取“arguments”关键字。
- 你再看你实际上插入消息历史的那条,里面用的关键字是“parameters”。
- 同义词。
- 所以模板找不到“arguments”,返回Undefined。
- 然后Jinja2试图将其转化为JSON序列,果不其然就抛异常了。
- 你真是太聪明了!
- 你去查为什么该用“arguments”的地方用了“paramenters”。
- 到底谁的英语没学好,把同义词搞错了!
- 是Llama。是它生成的内容里引入了“parameters”这个词。
- 所以是AI错了!
- 你再看。你在模板字符串里搜索“parameters”。
- 原来prompt模板里给AI指定了生成格式,里面用的就是“parameters”。
- 原来不是AI错了!是人类瞎指挥弄错了。差点冤枉AI。
- 你把模板里的“parameters”全部改成“arguments”。
- 从头开始,问Llama巴黎的气温。
- Llama说它要调用函数。这次它说的是“arguments”。
- 你更新了消息历史,交给tokenizer。
- Tokenize完成了!
- 你把tokenize后的prompt交给Llama。
- Llama说:
- “巴黎的温度是22度。”
(上述代码可见:Llama函数调用示例)