又是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函数调用示例