微信扫码
与创始人交个朋友
我要投稿
事实上,提示词工程正在经历一次重大的转型。它不再仅仅是寻找"魔法词"的艺术,而是正在演化成为一种更加复杂、更富有表现力的语言演变。这种演变使我们能够更精确地指导AI模型,处理更复杂的任务,并在更广泛的情境中应用,这不仅用于日常的LLM交互,还将更广泛的应用于机器人、脑机接口等前沿技术。
在这场演变中,APPL(A Prompt Programming Language)提示编程语言脱颖而出,成为一种极具潜力的工具。APPL不仅仅是一种新的编程语言,它代表了一种全新的范式,将自然语言提示与编程结构无缝融合。
初识APPL是在一个AI战略研究的代码中,作者精确无误的使用这种用语言实现了一个高级功能,当时使我极为震惊。直到昨日,我介绍谷歌重磅:LLM时代,我们用Prompt生成代码大纲,用文学编程 的自然语言大纲(Natural Language Outlines,简称NL Outlines)又让我想起APPL,应该和大家分享一下。
图片由修猫制作
01
为什么我们需要APPL?
使用提示编程的核心动机之一是能够以自动化方式评估和优化提示词。但实际应用中,这还远远不够!在这些框架中,优化提示可能只是一项简单的任务。但随着LLM能力的不断提升,我们需要用提示词工程来完成越来越复杂的任务。这就出现了新的问题:
1. 提示工程变得越来越复杂,维护成本高昂
2. 与传统编程范式的融合存在挑战
3. 并行化和性能优化困难重重
4. 从结构化数据到自然语言的转换不够流畅
APPL正是为解决这些问题而生的。它不仅仅是一个新的编程语言,更是一个连接传统计算机程序和LLM的桥梁。它用到Python中的一个高级功能装饰器,因此本文三级标题将带上@,以示区别。
@APPL的设计基于三大核心原则:
1. 可读性与灵活性并重
2. 轻松实现并行化
3. 便捷的数据转换
这些原则贯穿了APPL的方方面面,让它成为一个真正有价值的工具。
02
APPL的语法与语义:优雅与强大的结合
APPL巧妙地扩展了Python语法,实现了自然语言提示和LLM调用与传统编程结构的深度融合。让我们来看看它的一些关键特性:
@ APPL函数:提示编程的基石
appl函数是APPL的核心构建块,通过@ppl装饰器来定义。每个APPL函数都有一个隐式的上下文来存储与提示相关的信息。这种设计使得提示的管理变得异常简单和直观。
在Python中,@装饰器的作用是为函数或方法添加额外的功能,而无需修改原函数的代码。它们通过将原函数作为参数传递给另一个函数(即装饰器函数),然后返回一个新的函数,从而实现功能增强,在许多Python库和框架中都有广泛应用,如Flask、Django等。
@装饰器的作用
1、代码复用:装饰器允许你将常见的功能(例如日志记录、权限检查、性能监控等)提取出来并应用到多个函数中。
2、逻辑分离:装饰器使得核心业务逻辑与附加功能(例如事务管理、缓存、权限验证等)分离,代码更加清晰和可维护。
3、函数增强:通过装饰器,你可以在不改变原函数的情况下,为其添加额外的行为或修改其行为。
@装饰器的特点
1、函数是对象:在Python中,函数是对象,因此可以像其他对象一样被传递、返回或存储。装饰器正是基于这一特性实现的。
2、可组合:多个装饰器可以叠加在一起使用,顺序从里到外(或从上到下)依次应用。
3、可接受参数:装饰器本身可以接受参数,使得其行为可以动态调整。
4、保持原函数的签名:使用functools.wraps装饰器可以保留被装饰函数的元数据(如函数名、文档字符串等)。
@ 表达式语句与提示捕获:与上下文的交互
@ppl
def intro():
f"Today is 2024/02/29."
return records()
这里,"Today is 2024/02/29."会被自动捕获并添加到提示中
@ 上下文管理器:精细控制提示累积
APPL提供了两类上下文管理器:角色切换器和提示合成器。这些工具让你能够精确控制提示是如何被累积的,从而构建出结构更加清晰的提示。
@ 定义:概念的抽象与复用
APPL引入了Definition这一特殊基类,用于创建自定义定义。这个功能在处理频繁出现的概念时特别有用,大大提高了代码的可读性和可维护性。
作者用这张图很好地概述了APPL (A Prompt Programming Language) 的运行机制和核心概念。
代码与上下文交互:图的左侧展示了APPL代码,它将可读的提示与Python代码无缝混合。这些代码与右侧的Context/Frame(上下文/框架)交互。
上下文管理:右侧的Context/Frame展示了APPL如何管理本地变量(locals())、全局变量(globals())和会话(convo(): Conversation)。这说明APPL能够灵活地处理不同层次的上下文信息。
工具集成:底部展示了如何将Python函数(如search)作为工具集成到APPL中。这些函数的文档字符串被用作工具描述,便于LLM理解和使用。
LLM交互:图的右侧展示了与LLM的交互过程,包括发送请求、接收响应,以及工具调用。
异步和并行执行:图中提到了"Asynchronous and parallel Execution",这是APPL的一个重要特性,允许独立的请求并行执行。
上下文传递:图中提到了"Inter-function context passing",展示了APPL支持的四种上下文传递方式:new、copy、same和resume。
颜色编码:图使用不同的颜色来区分提示、Python控制流、LLM请求/响应和外部工具,使得整个流程一目了然。
上图展示了APPL如何将传统编程与提示工程无缝结合,以及它如何管理上下文、集成工具和优化执行。
03
APPL运行时:强大而灵活
APPL的运行时环境是它强大功能的关键所在。让我们深入了解一下它的几个核心特性:
@ 上下文传递:四种方式应对不同场景
APPL提供了四种上下文传递方式:new、copy、same和resume。这种灵活性使得APPL能够适应各种复杂的提示工程场景。
1. new: 默认创建一个全新的上下文,适用于大多数情况。
2. copy:创建调用者上下文的副本,适用于需要独立和异步LLM调用的场景。这类似于编程语言中的按值调用。被调用者的上下文是调用者上下文的副本,因此被调用者上下文的更改不会影响调用者的上下文。
3. same:使用与调用者相同的上下文,适用于需要直接修改原始上下文的情况。这类似于编程语言中的引用调用。被调用者的上下文与调用者的上下文相同,因此被调用者上下文的更改将影响调用者的上下文。
4. resume:从上一次运行恢复上下文,适用于构建具有历史记录的交互式代理。这会在每次调用函数时恢复函数的上下文,即在调用之间保留上下文,使函数有状态。它将第一次调用的调用者上下文复制为初始上下文。当您想继续上次通话的对话时,此功能非常有用。
这种设计让你可以根据具体需求选择最合适的上下文传递方式,大大提高了代码的灵活性和可复用性。
@ 异步语义:自动并行化的秘密武器
APPL借鉴了PyTorch的异步语义思想,使得LLM调用(gen)是异步的。这意味着主线程不会被gen阻塞,直到真正需要访问生成结果时才会同步。这种设计为自动并行化提供了基础,让你几乎不需要额外的代码就能实现高效的并行处理。
@ 工具调用:无缝集成外部资源
APPL通过分析Python函数的文档字符串和签名,自动创建工具规范。这使得将Python丰富生态系统中的函数集成为LLM可用的工具变得异常简单。更妙的是,APPL还能自动将LLM的输出转换为可直接执行的函数调用,大大简化了工具调用的流程。
@ 追踪与缓存:强大的调试和恢复能力
APPL支持对APPL函数和LLM调用进行追踪,这不仅方便了调试,还为失败恢复提供了可能。通过加载缓存的LLM调用响应,你可以重现(部分)执行结果,而无需重新发送这些调用。这个特性在调试单个LLM调用时尤其有用,同时也为分析程序逻辑、成本和运行时提供了可视化支持。
04
APPL VS DSPy
APPL和DSPy都是为了简化和优化大语言模型(LLM)应用开发而设计的工具,但它们在设计理念、功能特性和使用场景上有一些重要的区别。之前,我有很多文章介绍过DSPy:
往期推荐
别再写脆弱的prompt讨好LLM啦!快用DSPy拯救你宝贵的prompt思维,偷偷甩掉99%的人
重磅 | DSPy让你不写一句Prompt照样构建Agent,从此,你不再卑躬屈膝讨好LLM
ICLR2024重磅 | DSPy或将手写Prompt推进历史,悄悄学会DSPy,一线技术圈很缺你这类人才
内隐语境Prompt,让LLM更懂你的弦外音,用DSPy实现
意图识别,用DSPy理解用户的“弦外音”
接下来让我们详细比较一下这两个工具:
1. 设计理念和目标
APPL (A Prompt Programming Language):
- 目标是将提示无缝嵌入到Python函数中,反之亦然。
- 侧重于将提示工程与传统编程范式融合
- 强调代码的可读性和可维护性
DSPy (Declarative Symbolic Programming in PYthon):
- 目标是以符号化的方式表达语言模型程序,并自动优化它们。
- 侧重于声明式编程和自动优化
- 强调将复杂的NLP任务分解为可优化的模块
2. 语言设计
APPL:
- 扩展了Python语法
- 引入了特殊的装饰器和上下文管理器
- 提供了自动提示捕获机制
例如:如果在Jupyter中运行,请先!pip install -U applang
import appl
from appl import gen, ppl
appl.init() # initialize APPL
@ppl # the @ppl decorator marks the function as an `APPL function`
def greeting(name: str):
f"Hello World! My name is {name}." # Add text to the prompt
return gen() # call the default LLM with the current prompt
print(greeting("APPL")) # call `greeting` as a normal Python function
DSPy:
- 基于Python,但引入了自己的模块和抽象
- 使用Signatures和Modules来定义任务
- 提供了Teleprompter等优化工具
例如:
class QA(dspy.Signature):
"""Answer questions based on the given context."""
context = dspy.InputField()
question = dspy.InputField()
answer = dspy.OutputField(desc="Answer to the question")
class RAG(dspy.Module):
def __init__(self):
self.retrieve = dspy.Retrieve(k=3)
self.generate_answer = dspy.ChainOfThought(QA)
def forward(self, question):
context = self.retrieve(question).passages
answer = self.generate_answer(context=context,question=question)
return answer
3. 并行化和性能优化
APPL:
- 提供自动并行化机制
- 使用异步语义和Future对象
- 性能优化主要通过并行执行实现
DSPy:
- 提供自动优化工具如Teleprompter
- 可以通过实验自动生成和优化提示
- 性能优化更多地关注于任务分解和提示优化
4. 工具集成
APPL:
- 提供了自动从Python函数创建工具规范的功能
- 支持直接将Python函数作为LLM工具使用
DSPy:
- 提供了丰富的内置模块,如dspy.ChainOfThought和
dspy.Predict
等
- 支持自定义模块和签名
5. 上下文管理
APPL:
- 提供了多种上下文传递方式(new, copy, same, resume)
- 支持细粒度的上下文控制,比DSpy更为细致
DSPy:
- 通过Signatures和Modules管理上下文
- 更关注任务级别的上下文管理
6. 优化和调试
APPL:
- 提供了追踪和缓存机制
- 支持失败恢复和重放
DSPy:
- 提供了Teleprompter等自动优化工具
- 支持通过实验自动优化提示和模型选择
7. 使用场景
APPL:
- 更适合需要细粒度控制提示和LLM交互的场景
- 对于需要与现有Python代码深度集成的项目很有优势
DSPy:
- 更适合构建复杂的NLP管道和系统
- 对于需要自动优化和实验的项目很有帮助
8. 学习曲线
APPL:
- 对于熟悉Python的中高级开发者来说,学习曲线相对平缓
- 主要需要学习新的装饰器和上下文管理器用法
DSPy:
- 引入了更多新概念,如Signatures和Modules
- 可能需要更多时间来掌握其声明式编程范式
9. 社区和生态系统
APPL:
- 相对较新,生态系统还在发展中,GitHub上star不足50
- 与标准Python库和工具高度兼容
DSPy:
- 已经有一定的社区和用户基础
- 提供了一些预训练的模块和优化器
APPL和DSPy都是强大的工具,不矛盾甚至可以相互结合,它们适用于不同的场景:
- 如果你需要对提示和LLM交互进行精细控制,并且希望无缝集成到现有Python代码中,APPL可能是更好的选择。
- 如果你正在构建复杂的NLP系统,需要自动优化和实验,并且喜欢声明式编程风格,DSPy可能更适合你。
提示词工程发展太快了,了解这两种工具的优缺点将使你能够根据项目需求选择最合适的工具。在某些情况下,甚至可以考虑结合使用这两种工具,以充分发挥它们各自的优势。
05
APPL实现:巧妙的编译与异步执行
APPL的实现充分体现了其设计者的智慧。让我们来看看它的两个关键部分:
@ 编译:AST变换的艺术
APPL选择将Python源代码编译(更准确地说是转译)为插入了上下文的代码。这个过程主要包括以下步骤:
1. 上下文管理:使用ctx关键字表示函数的上下文。
2. 捕获表达式语句:为APPL函数中的所有表达式语句添加一个执行函数包装器。
这种方法使得APPL能够在保持Python语法的同时,提供强大的提示编程功能。通过比较不同任务实现的AST节点数量,我们可以看到APPL的代码简洁性优势:
这些数据表明,APPL通常只需要其他语言一半左右的代码复杂度就能实现相同的功能。
@ 异步执行与Future对象:并行化的关键
APPL引入了StringFuture和BooleanFuture概念,这些对象表示可能尚未准备好的字符串或布尔值。这种设计允许APPL尽可能延迟同步,理想情况下只在调用str方法时才同步。这为高效的并行执行提供了基础。
这些数据显示,APPL能够有效地并行化LLM调用,在不同场景下都能达到显著的性能提升。
究竟appl封装了哪些模块和函数,让它这么强大?限于篇幅,来群里,我将细致为你解释!
这是APPL项目cookbook的链接 appl-team.github.io/appl/ ,但也缺乏函数的详细说明。你也可以保存上图,实战时必将获益。
05
APPL在实际应用中的表现
为了展示APPL的强大功能,我们来看几个具体的应用场景:
@创建结构化提示词
class Req(Definition):
name = "Requirement"
@ppl
def func():
f"... the following {Req}s:"
with NumberedList(indent=2):
Req(desc="Input should ...")
Req(desc="Output should ...")
return records()
@ 思维链与自洽性(CoT-SC)
@ppl
def cot(num_trials: int):
"... (three examples omitted)"
"Q: You need to cook 9 eggs."
"A: Let's think step by step."
return [gen() for _ in range(num_trials)]
answers = cot(num_trials)
在实现CoT-SC时,APPL展现出了其简洁性和清晰性。相比LMQL、SGLang和Guidance等其他提示语言,APPL在以下几个方面表现出色:
1. 并行化:APPL实现了自动并行化,而且对程序员完全透明。
2. 生成和输出检索:APPL的gen是独立的函数调用,其返回值可以赋给Python变量,这提供了更好的IDE互操作性。
3. 上下文管理和提示捕获:APPL自动捕获独立的表达式语句到提示上下文中,简化了提示的构建过程。
@ ReAct工具使用代理
tools = [search, is_lucky, ...]
f"User Instruction: {instruction}"
for i in range(num_iterations):
with AIRole():
f"Thoughts: {gen(tools=tools, tool_choice='none')}"
(actions := gen(tools=tools, tool_choice='required'))
(observations := actions.run_tool_calls())
这个例子展示了APPL如何简化ReAct算法的实现,自动处理工具规范和执行。在实现ReAct这样的工具使用代理时,APPL的工具调用功能展现出了巨大的优势。APPL提供了对LLM工具调用三个步骤(编码、解析和执行)的开箱即用支持,大大简化了开发过程。
class Agent:
def __init__(self, name: str):
self._name = name
self._setup()
@ppl
def _setup():
... # setup context and init the chat
@ppl(ctx="resume")
def chat(self, messages):
if messages is None:
return
messages
with AIRole():
(reply := gen())
return reply
这个例子展示了如何使用APPL的resume上下文传递方式来实现有状态的聊天代理。APPL灵活的上下文传递方法使得实现复杂的多代理系统变得简单。无论是显式维护聊天历史还是使用resume上下文,APPL都提供了清晰、简洁的实现方式。
@ APPL的性能表现:并行化的威力
APPL的自动并行化能力在实际应用中表现出色。在CoT-SC、SoT(Skeleton-of-Thought)和MemWalker等任务中,APPL实现的并行版本都达到了接近理论估计的显著加速比。这证明了APPL不仅易用,而且高效。
@APPL vs 其他提示语言:代码简洁性的胜利
通过比较不同任务实现的AST节点数量,我们可以看到APPL的代码通常只需要其他语言一半左右的复杂度。这不仅意味着更少的代码量,更重要的是意味着更好的可读性和可维护性。
@APPL:未来AI开发的方向
APPL的出现标志着我们进入了一个新的AI开发时代。它不仅仅是一个提示编程语言,更是一个连接传统计算和AI的桥梁。通过APPL,我们可以:
1. 大幅降低提示工程的复杂度和维护成本
2. 实现传统编程范式与LLM的无缝融合
3. 轻松实现高效的并行化处理
4. 优雅地处理结构化数据和自然语言之间的转换
作为一名Prompt工程师,掌握APPL将让你在AI开发领域占据先机。它不仅能提高你的工作效率,还能让你设计出更复杂、更强大的AI系统。
学习和掌握APPL,不仅能够提升你的工作效率,更能让你在AI开发领域保持竞争力。APPL代表了一种新的思维方式- 一种将传统编程智慧与AI能力无缝结合的方式。它不仅是一个工具,更是一个平台,一个生态系统。通过APPL,我们可以更好地理解和利用AI的力量,创造出前所未有的智能应用。
提示词工程发展的速度可能超出你我想象,除了顶级机构的研究,各种LLM也在飞速自我进化。而我们似乎只关注如何提问,忽视了编程语言这种基本范式的发展可能性。
不管未来LLM进化的多么智能,我相信,未来提示工程的很大一部分仍然涉及提示词编程。尽管如此,回到我们的主要问题:提示工程会消亡吗?不,它只会更加强大、更加复杂、当然,还会涉及更多的工程,比如APPL
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-09-18
2024-07-18
2024-07-02
2024-07-10
2024-07-09
2024-07-15
2024-07-10
2024-08-14
2024-07-14
2024-07-26
2024-11-20
2024-11-13
2024-10-31
2024-10-29
2024-10-16
2024-09-19
2024-08-28
2024-08-24