我们把 Prompt 函数和类更进一步了

前言

上次我们发了一篇文章,很好的解决了 Prompt 的使用问题:

最好的Prompt管理和使用依然是 Class 和 Function - 继续让LLM和编程语言融合

相比其他方案,具有非常大的优势,完全融入到了现有的编程语言里,而不是大段的文本变量或者文件来做管理。

阅读本文前,建议大家先阅读上面的文章获得一个基础认知,再来看看我们如何进一步简化其使用。

问题

我们来看下面一段代码:

python 复制代码
import ray
import functools
import inspect
import byzerllm
import pydantic
from byzerllm.utils.client import ByzerLLM


ray.init(address="auto",namespace="default",ignore_reinit_error=True)  


data = {
    'name': 'Jane Doe',
    'task_count': 3,
    'tasks': [
        {'name': 'Submit report', 'due_date': '2024-03-10'},
        {'name': 'Finish project', 'due_date': '2024-03-15'},
        {'name': 'Reply to emails', 'due_date': '2024-03-08'}
    ]
}




class RAG():
    def __init__(self):        
        self.llm = ByzerLLM()
        self.llm.setup_template(model="sparkdesk_chat",template="auto")
        self.llm.setup_default_model_name("sparkdesk_chat")        
    
    @byzerllm.prompt(lambda self:self.llm,render="jinja2")
    def generate_answer(self,name,task_count,tasks)->str:
        '''
        Hello {{ name }},


        This is a reminder that you have {{ task_count }} pending tasks:
        {% for task in tasks %}
        - Task: {{ task.name }} | Due: {{ task.due_date }}
        {% endfor %}


        Best regards,
        Your Reminder System
        '''


t = RAG()


response = t.generate_answer(**data)
print(response)


## output:Hello! Is there anything else I can assist you with?

RAG 是一个 prompt class, 里面有个 prompt function generate_answer,

可以看到这个方法是一个传统意义上的空方法,但是里面的 doc 则是一段jinja 模板代码。prompt function 的执行器实际上是大模型,所以这段doc 会作为代码给到大模型,然后返回一个结果。

但是这个prompt 函数有两个地方比较复杂:

  1. prompt 注解需要传一个 lambada 表达式,这个是为了获得 llm 实例。

  2. 我们用到了jinja2 的for循环等

实际用起来,我们往往还是希望能够对会绑定到 doc 里的参数做一些处理的,这样可以使得模板更简单一些。

解决方案

现在你可以这么做:

python 复制代码
@byzerllm.prompt(lambda self:self.llm,render="jinja2")
    def generate_answer(self,name,task_count,tasks)->str:
        '''
        Hello {{ name }},


        This is a reminder that you have {{ task_count }} pending tasks:
            
        {{ tasks }}


        Best regards,
        Your Reminder System
        '''
        
        tasks_str = "\n".join([f"- Task: {task['name']} | Due: { task['due_date'] }" for task in tasks])
        return {"tasks": tasks_str}

这次,我们提供了方法体,这个方法体实际上是对参数做一次预处理,然后再返回一个字典,这个新的字典会覆盖方法的参数的值,比如此时 tasks 值从原来的一个对象变成了一个字符串,可以直接放到 jinja2 doc 里渲染了。

此外,这也意味着你可以可能还可以做一些逻辑判断,来决定实际渲染到doc里的值是什么样子的,而不是在代码里做模板拼接。

这是第一个变化,prompt function 也允许有方法体,可以对入参做一些二次处理。只是你的方法体返回的值必须是一个字典。

其次,

@byzerllm.prompt(llm=lambda self:self.llm,render="jinja2")

中的 llm 目前可以接受三种值了:

  1. lambda 表达式,获取当前对象的llm 实例。

  2. 字符串,也就是模型的名字,系统会自动构建一个llm实例用于某次调用。

  3. llm 实例, 你可以直接传递一个llm实例。

比如:

@byzerllm.prompt(llm="kimi_chat")

系统会自动寻找名字为 kimi_chat的模型。

此外,在这次新版本(0.1.58)我们将 render 默认值改成 jinja2 而非simple。

总结

Byzer-LLM 是一个比较特殊的存在,它的终极愿景是让大家更好的使用大模型,而实现这一愿景主要是通过让变成语言和大模型更好的做融合,为此我们提供了非常多的能力,包括大模型无关的function calling, response class 和 function impl 等功能,也包括 prompt function 和prompt class。

为了能够让这些能力变得好用,Byzer-LLM 还支持主流的开源模型和SaaS模型的对接,并且能够很好的适应生产环境,可以让大家只引入一个库就解决主要问题。

相关推荐
Myli_ing12 分钟前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
在下不上天14 分钟前
Flume日志采集系统的部署,实现flume负载均衡,flume故障恢复
大数据·开发语言·python
陌小呆^O^27 分钟前
Cmakelist.txt之win-c-udp-client
c语言·开发语言·udp
dr李四维29 分钟前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
I_Am_Me_43 分钟前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
雯0609~1 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
重生之我是数学王子1 小时前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
℘团子এ1 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
Ai 编码助手1 小时前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript