我们把 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模型的对接,并且能够很好的适应生产环境,可以让大家只引入一个库就解决主要问题。

相关推荐
sunfdf4 分钟前
Next.js 新手从零部署到首跑实战指南
开发语言·javascript·ecmascript
YHHLAI8 分钟前
Agent 智能体开发实战 · 第六课:MCP 协议 —— 让 Agent 跨进程调用工具
前端·人工智能
SmartBoyW14 分钟前
前端死磕:一文彻底搞懂 JS 事件循环 (Event Loop) 与宏微任务
前端·javascript
爱勇宝38 分钟前
3位工程师靠“删AI代码”创业,一周收费1万美元:以后最贵的能力,可能不是写代码
前端·后端·架构
Curvatureflight41 分钟前
客户端日志上报怎么设计?让线上问题不再只靠用户截图
前端·系统架构
hold?fish:palm1 小时前
从源码到可执行文件:C++程序的编译过程
开发语言·c++
不法1 小时前
uniapp map地图导航/地图路线
前端·vue.js·uni-app
mONESY1 小时前
基于MCP协议搭建全链路智能Agent:地图检索+浏览器自动化+本地文件操控实战
javascript
随性而行3601 小时前
微信API接口与AI自动化:开发者的实现思路
运维·服务器·开发语言·人工智能·微信·自动化