PDL: 선언적 프롬프트 단어 프로그래밍 언어

AI 기술 자료7개월 전 업데이트 AI 공유 서클
11.8K 00

초록

대규모 언어 모델(LLM)은 전 세계적으로 광범위한 관심을 불러일으키며 이전에는 구현하기 어려웠던 많은 AI 애플리케이션을 가능하게 했습니다. LLM은 고도로 표현적인 텍스트 프롬프트에 의해 제어되며 텍스트 답변을 반환합니다. 그러나 이러한 구조화되지 않은 입력 및 출력 텍스트는 LLM 기반 애플리케이션을 취약하게 만듭니다. 이로 인해 LLM과 외부 세계의 상호작용을 규제하는 힌트 프레임워크가 등장하게 되었습니다. 그러나 기존의 힌트 프레임워크는 학습 곡선이 길거나 개발자가 정확한 힌트를 제어할 수 없습니다. 이러한 딜레마를 해결하기 위해 이 백서에서는 프롬프트 선언적 언어(PDL)를 소개합니다. PDL은 YAML을 기반으로 하는 간단한 선언적 데이터 지향 언어로, 프롬프트를 핵심으로 하며, 여러 LLM 플랫폼 및 LLM과 잘 작동하고 LLM 및 도구를 호출하는 대화형 애플리케이션의 작성을 지원하며 챗봇, RAG 또는 에이전트 등의 일반적인 사용 사례에 쉽게 구현할 수 있습니다. 챗봇, RAG 또는 프록시와 같은 일반적인 사용 사례를 쉽게 구현할 수 있습니다. PDL을 통해 더 쉽고, 더 강력하고, 더 즐거운 프로그래밍을 할 수 있기를 바랍니다.

 

1. 소개

대규모 언어 모델(LLM)은 큰 발전을 거듭하며 다양한 유용한 작업을 수행할 수 있는 능력을 입증했습니다. LLM은 자연어 단서를 통해 제어되기 때문에 단서 엔지니어링은 정확도를 높이기 위한 임시적인 방법이 되었습니다(White et al.2023). 문맥 학습과 같은 큐잉 패턴을 통한 학습(Brown et al.2020), 다중 LLM 호출 체인(Chase et al.2022), 향상된 생성(RAG)(Lewis et al.2020), 도구 사용(Schick et al.2023), 절차적 보조 언어 모델(PAL)(Gao et al.2023) 및 에이전트(Yao et al.2023)를 사용하면 더 많은 기능을 사용할 수 있습니다. 그러나 강력한 기능에도 불구하고 LLM은 때때로 예상되는 구문과 유형을 따르지 않거나 심지어는 오류가 발생하는 등 여전히 취약한 부분이 있습니다.

큐잉 프레임워크(Liu et al.2023)를 사용하면 개발자는 취약성을 줄이면서 LLM 및 관련 힌트 패턴을 더 쉽게 사용할 수 있습니다. LangChain(Chase et al.2022) 및 AutoGen(Wu et al.2023), RAG 또는 프록시와 같이 자주 사용되는 패턴에 대한 특정 기능을 제공합니다. 그러나 이러한 기능은 사용자가 기본 프롬프트에 대한 제어권을 박탈하고 많은 복잡한 프레임워크 기능을 익히도록 강요할 수 있습니다. 이와는 대조적으로 안내와 같은 낮은 수준의 프롬프트 프레임워크(Microsoft.2023) 및 LMQL(Beurer-Kellner et al.2023) 구문과 유형을 통해 더 많은 제어 기능을 제공합니다. 그러나 이러한 프레임워크는 사용자가 파이썬이나 타입스크립트와 같은 명령형 언어로 프로그래밍해야 합니다. 다른 쪽 끝에 있는 프레임워크인 DSPy(Khattab et al.2023) 및 비에이라(Li et al.2024), 프롬프트를 자동으로 생성하여 수기로 작성하는 것을 완전히 피할 수 있습니다. 안타깝게도 이렇게 하면 개발자로부터 제어권이 더 멀어집니다. 따라서 어떻게 하면 LLM 프로그래밍을 더 강력하게 만들고 단순성을 유지하면서 개발자가 주도권을 유지할 수 있을지가 문제입니다.

이 문제를 해결하기 위해 오랜 시간 검증된 프로그래밍 언어 설계 아이디어를 활용합니다. 직교성의 원칙은 강력한 기능을 달성하기 위해 결합된 작고 단순한 함수 집합을 사용하는 것을 옹호합니다(van Wijngaarden et al.1977). 이러한 맥락에서 직교성은 가능한 한 특수한 경우를 피하는 것을 의미합니다. 힌트 프레임워크의 경우 직교성은 특정 기능을 피하는 방법입니다. 다음으로, 언어가 유형 및 역할 검사를 통과할 수 있는 경우(2023)가 구조적으로 적용되면 개발자는 취약성 문제로 어려움을 덜 겪을 것입니다. 한편으로는 개발자가 정확한 힌트를 제어할 수 있어야 하고, 다른 한편으로는 단순한 선언적 언어가 필요하다는 풀기 어려운 긴장이 남아 있습니다. 이러한 이유로 저희는 의도적으로 절차(예: 체인 및 도구)와 데이터(힌트) 사이의 경계를 모호하게 하는 데이터 지향 언어를 선택했습니다. 이러한 영감은 데이터형 코드라는 오래된 개념에서 비롯되었습니다(McCarthy.1960), 레이어리스 프로그래밍에 대한 중요한 연구(Cooper et al.2006).

이 백서에서는 직교 및 타입 데이터 지향 언어인 프롬프트 선언 언어(PDL)를 소개합니다. 명령형 언어에 내장된 다른 프롬프트 언어와 달리 PDL은 YAML을 기반으로 합니다(Ben-Kiki et al.2004YAML은 사람이 읽을 수 있고(비정형 문자열에 대한 간단한 구문을 용이하게 함으로써) 구조화(JSON 호환)된 데이터 직렬화 형식이며, PDL의 변수는 JSON 값을 보유하며 선택적으로 JSON 스키마를 사용합니다(Pezoa et al.2016) 유형이 입력됩니다.PDL은 현재 동적 유형 검사를 수행하는 인터프리터에 의해 구현됩니다. 프로그램을 데이터로 표현하는 것의 한 가지 장점은 프로그램 변환이 쉽다는 것입니다(Mernik et al.2005), 예를 들어 최적화를 위해. 데이터 표현 형식으로 프로그램을 렌더링하면 PAL과 유사한 대규모 언어 모델을 통해 PDL 프로그램을 쉽게 생성할 수도 있습니다(Gao et al.2023).

PDL 프로그램은 블록(YAML 개체)으로 구성되며, 각 블록은 프롬프트 컨텍스트에 데이터를 추가합니다. 이러한 사고방식은 챗봇이나 에이전트와 같은 프롬프트 기술에 사용하기에 이상적입니다. 프로그램 실행 시 명시적인 파이프라인 없이 대화나 궤적을 암시적으로 구축하기 때문입니다. 이 컨텍스트는 다음 LLM 호출을 위한 입력이 됩니다.PDL은 네이티브 LLM뿐만 아니라 IBM Watsonx1 및 Replicate2의 오픈 소스 Granite 모델을 포함하되 이에 국한되지 않는 여러 공급업체에서 호스팅하는 LLM을 지원합니다(Abdelaziz et al.2024Granite 팀, IBM.2024PDL은 모듈화를 위해 루프 및 조건부 제어 구조와 함수 및 파일 소개를 제공하며, PDL은 Jinja2(Ronacher.2008) 표현식을 사용하여 힌트뿐만 아니라 전체 프로그램을 템플릿으로 만들 수 있습니다.

이 문서에서는 소개 예시를 통해 PDL에 대한 개요를 제공합니다(섹션 2), 언어에 대한 자세한 설명(섹션 3). PDL 프로그램을 실행하고 편집하는 도구에 대해 설명합니다(섹션 4), PDL의 추가 적용을 입증하는 사례 연구를 제공합니다(섹션 5). 마지막으로 관련 작업에 대해 설명합니다(섹션 6), 그리고섹션 7PDL은 오픈 소스이며 다음에서 찾을 수 있습니다. https://github.com/IBM/prompt-declaration-language 이해하기. 전반적으로 PDL은 간단하지만 강력한 새로운 LLM 프롬프트 프로그래밍 언어입니다.

 

2. 개요

이 섹션에서는 챗봇 예시를 통해 PDL 기능에 대한 개요를 제공합니다. PDL 프로그램은 일련의 (지구의) 덩어리각 블록에서 생성된 데이터는 백그라운드 컨텍스트에 기여합니다. 모델 호출, stdin 또는 파일에서 데이터 읽기, 다양한 JSON 데이터 직접 생성, 코드 실행 등 다양한 방식으로 데이터를 생성할 수 있는 다양한 유형의 블록이 있습니다. 또한 PDL 사용자가 풍부한 데이터 파이프라인과 AI 애플리케이션을 표현할 수 있는 다양한 제어 블록(if-then-else, for, repeat)이 있습니다.

지도 1(a)는 간단한 챗봇의 PDL 코드를 보여줍니다. 1~4줄의 read: 블록은 사용자에게 쿼리를 입력하라는 메시지를 출력하고 stdin에서 이를 읽습니다. 그림. 1(b) 동일한 프로그램을 실행한 흔적이 표시됩니다. 예를 들어 사용자가 "언어 샐러드가 무엇인가요?"라고 질문할 수 있습니다. . 반복을 피하기 위해 "속성: [컨텍스트]" 절은 사용자 응답을 백그라운드 컨텍스트에 넣지만 결과(stdout에 출력되는 내용)는 넣지 않습니다.

5-16줄의 repeat:until: 블록에는 중첩된 text: 블록이 포함되어 있으며, 이 블록은 차례로 두 개의 중첩된 블록 시퀀스를 포함합니다. text: 블록은 중첩된 블록의 결과를 문자열로 변환하여 연결합니다. 7~9줄의 model: 블록은 현재 누적된 문맥을 힌트로 사용하는 대규모 언어 모델(LLM)을 호출합니다. 루프의 첫 번째 반복에서 컨텍스트는 "쿼리가 무엇인가요?"와 "언어 샐러드가 무엇인가요?"라는 두 줄로만 구성됩니다. 'stop: [\n\n]' 모델 매개변수는 두 줄 바꿈이 연속적으로 생성된 후 LLM이 토큰 생성을 중지하도록 합니다. LLM 인터프리터는 LLM 출력을 녹색으로 인쇄합니다(그림 1. 1(b)는 이 예제에서 LLM이 "언어 샐러드는 [...]입니다."를 생성했음을 보여줍니다. 10~15줄의 read: 블록은 YAML의 여러 줄 문자열 구문(세로줄(|)로 시작)을 사용하여 메시지를 인쇄합니다. 이 예는 PDL이 프롬프트를 우선시하면서 읽기 쉽게 만들고 개발자에게 정확한 제어 기능을 제공하는 방법을 보여줍니다. 오른쪽의 인터프리터 추적을 보면 사용자가 "시로 말해줘!"라고 입력했으며, 이는 왼쪽 10줄의 가변 질문으로 정의되고 12줄의 컨텍스트에 추가되었음을 알 수 있습니다. 16줄의 until: 절은 Jinja2 표현식 '${question == "quit"}’ PDL은 '${...}' 구문을 사용하여 '{{...}}' 대신에 Jinja2 템플릿을 포함시킵니다. 대신 '{{...}}'를 사용하는데, 이는 후자가 YAML의 특수 문자(중괄호)와 호환되지 않기 때문입니다.

루프의 두 번째 반복에서 컨텍스트는 루프의 첫 번째 반복의 효과를 포함합니다. 따라서 모델의 두 번째 실행: 블록은 첫 번째 실행의 출력을 보고 다음과 같이 "많은 방언이 있는 세상에서 [...]"라는 시로 의역할 수 있습니다. 1(b). 결국 이 예제의 두 번째 읽기: 블록 실행 중에 사용자가 "quit"을 입력하면 루프가 종료됩니다. 이제 몇 가지 일반적인 PDL 블록(읽기:, 반복:, 텍스트: 및 모델:)이 작동하는 것을 보았으므로 두 번째 읽기: 블록으로 넘어갈 수 있습니다. 3 섹션에서 나머지 블록과 언어 기능에 대해 설명합니다.

PDL:声明式提示词编程语言

(a) 코드

- read:
contribute: [context]
message: |
您的查询是什么?
- repeat:
text:
- model: watsonx/ibm/granite-13b-chat-v2
parameters:
stop: ["\n\n"]
- def: question
read:
contribute: [context]
message: |
输入查询或说“quit”退出。
until: ${question == "quit"}

(b) 인터프리터 추적

您的查询是什么?
什么是语言沙拉?
语言沙拉是一个术语,用于描述在单一对话或文本中混合不同语言和方言。它可以被看作是[…]
输入查询或说“quit”退出。
用诗的形式表达!
在语言众多的世界中,
语言沙拉诞生,喜悦中成长。
词语交织,和谐中流动,
五彩缤纷的语言,活力绽放。
输入查询或说“quit”退出。
quit

그림 1. PDL의 간단한 챗봇

 

3. 언어

PDL:声明式提示词编程语言

그림 2. PDL 빠른 참조

PDL은 YAML에 내장된 언어로, 각 PDL 프로그램을 PDL 아키텍처를 준수하는 유효한 YAML 문서로 만들어 줍니다. 그림 2 은 PDL에 대한 빠른 참조이며 이 섹션에서는 구문 규칙을 사용하여 설명합니다. 프로그램은 블록 또는 블록의 목록으로, 블록은 다음 구문 규칙에 표시된 대로 표현식 또는 구조화된 블록이 될 수 있습니다:

pdl ::= 블록 | [블록, . . . ,블록]블록 ::= 식 | 구조화된_블록

이 섹션의 모든 구문 규칙은 YAML의 흐름 스타일 구문(예: [블록, ...,블록])을 사용합니다. ...,블록]). 예를 들어 동일한 PDL 코드를 YAML의 블록 스타일 구문으로 렌더링할 수도 있습니다:

  • 블록
    ...
  • 블록

각 블록에는 블록의 유형을 나타내는 키워드(예: 모델 또는 읽기)가 포함된 블록 본문이 포함되어 있습니다. 블록 본문에는 15가지 유형이 있습니다(선택적 필드는 물음표로 주석 처리됨):

PDL:声明式提示词编程语言 block_body ::=

model:expression,input:?pdl,parameters:?  
expression  
| read:file,message:?  
string,message:?  
bool  
| text:pdl  
| lastOf:pdl  
| array:pdl  
| object:pdl  
| data:json  
| include:file  
| function:args,return:pdl  
| call:𝑓,args:args  
| if:expression,then:pdl,else:?pdl  
| for:args,repeat:𝑝𝑑𝑙,join:?  
join  
| repeat:pdl,num_iterations:n,join:?  
join  
| repeat:pdl,until:expression,join:?  
join  
| code:pdl,lang:string

이전 섹션에서 model: 및 read: 블록에 대해 이미 살펴보았습니다. model: 블록은 큰 언어 모델을 호출합니다. 선택적 입력: 필드를 지정하지 않는 한 프롬프트는 현재 컨텍스트에서 가져옵니다. 선택적 매개 변수: 필드는 모델의 추론 동작을 구성하는 데 사용됩니다. read: 블록은 파일에서 입력을 읽거나 파일 이름이 지정되지 않은 경우 표준 입력에서 입력을 읽습니다. 선택적 메시지: 필드는 사용자에게 메시지를 표시하는 데 사용되며, 선택적 다중 줄 바꿈: 필드는 줄 바꿈에서 멈출지 여부를 결정합니다.

데이터를 생성하기 위한 5가지 블록 유형은 text:, lastOf:, array:, object:, data: 등입니다. 그림 2 간단한 예제를 보여드리겠습니다. 키워드가 없는 블록 목록은 lastOf: 로 표시됩니다. object: 블록과 data: 블록의 차이점은 PDL 인터프리터는 데이터: 블록의 PDL 키워드를 무시하고 일반 JSON 필드로 취급한다는 점입니다.

모듈화를 위해 PDL은 include: 블록과 함수를 지원합니다. include: 블록은 지정된 상대 경로에서 PDL 프로그램을 열고 출력이 나타나는 위치에 해당 출력을 추가합니다. 함수 인수의 구문은 다음과 같습니다:

args::={x:exp ression,... ,x:expres sion}

각 x:expressi 의 매개변수 이름을 타입 명세(함수: 정의) 또는 값(함수 호출:)에 매핑합니다. 반환: 키워드는 중첩된 블록을 포함할 수 있는 함수의 본문을 제공합니다. 2 간단한 Jinja2 표현식의 예가 나와 있습니다. 선택 사항인 pdl_context: 키워드는 호출 중에 컨텍스트를 빈 컨텍스트 []로 재설정합니다.

제어 블록에는 if:, for: 및 다양한 반복: 형식의 세 가지 유형이 있습니다. 중첩된 블록이나 간단한 표현식을 포함할 수 있으며, 블록 목록이 포함된 경우 기본적으로 목록은 lastOf: 동작을 합니다. lastOf: 동작을 원하지 않는 경우 일반적인 접근 방식은 루프 본문을 text: 블록으로 캡슐화하거나 join: 키워드를 사용하여 루프 반복 결과를 병합하는 것입니다:

join::=as:? (text∣array∣lastOf),with:? 문자열

위의 15개 블록은 모든 블록에 적용되는 0개 이상의 선택적 키워드와 조합하여 사용할 수 있습니다:

구조화된 _block::=

{ block_body,
description:?
string,
def:?
x,
defs:?
defs,
role:?
string,
contribute:?
contribute,
parser:?parser,
spec:?
type }

description: 특수 주석입니다. def: 블록의 결과를 변수에 할당합니다. 1 PDL 코드의 10번째 줄에 이미 예제가 있습니다. 이와 대조적으로 defs: 는 각각 고유한 이름인 x를 가진 여러 변수 정의를 생성하고 중첩된 PDL 프로시저를 통해 값을 할당합니다:

defs::={x:pdl ,...,x:pdl}

역할: 블록에서 생성된 데이터에 '사용자', '어시스턴트' 또는 '시스템'과 같은 특정 역할을 할당합니다.채팅 모델에 대한 PDL 호출은 일반 텍스트가 아닌 {content:str, role:str} 쌍의 시퀀스를 프롬프트로 전달하여 최신 채팅 API의 일반적인 관행을 따릅니다. 그러면 모델 API는 모델별 채팅 템플릿을 적용하고 적절한 제어 태그를 삽입하여 시퀀스를 플랫화하여 PDL 프로그램에 모델 독립성을 부여합니다. 블록에 role: 이 명시적으로 지정되지 않은 경우 모델 블록은 기본적으로 '어시스턴트'로, 다른 블록은 '사용자'로 기본 설정됩니다. 임베디드 블록의 역할은 외부 블록의 역할과 일치합니다. 향후 연구에서는 역할을 사용하여 권한 기반 보안 메커니즘도 구현할 계획입니다.

기여: 키워드를 사용하여 두 대상 '결과' 또는 '컨텍스트'에 대한 (비어 있을 수 있는) 하위 집합을 지정할 수 있습니다. 기본적으로 각 모듈은 자체 결과와 후속 LLM(대규모 언어 모델) 호출에 사용되는 배경 컨텍스트에 기여합니다. 그림 1 2줄은 출력을 단순화하기 위해 모듈 기여를 백그라운드 컨텍스트로만 제한하는 예제를 보여줍니다.

parser: 키워드는 일반적으로 플랫 문자열만 생성하는 모듈(예: LLM 호출)이 구조화된 데이터를 생성할 수 있도록 합니다. 지원되는 파서에는 json, yaml, 정규식, jsonl이 있습니다. spec: 키워드는 유형을 지정합니다. PDL의 유형은 JSON 스키마의 하위 집합입니다(Pezoa et al. 2016), 그림. 2 일반적인 속기 구문에 대한 간단한 데모는 다음과 같습니다. 예를 들어 '{질문: [str], 답변: [str]}' 유형은 질문과 답변에 대한 두 개의 필드를 포함하는 객체로, 둘 다 문자열 배열을 포함합니다. 첫 번째 5 섹션에서는 parser: 와 spec: 가 어떻게 함께 작동하는지 보여드릴 것입니다. 향후 작업에서도 이러한 키워드를 제약 조건 디코딩에 활용할 예정입니다(Scholak et al. 2021).

원자 블록은 표현식입니다:

표현식 ::= bool | 숫자 | 문자열 | ${𝑗𝑖𝑛𝑗𝑎_𝑒𝑥𝑝𝑟𝑒{𝑗𝑖𝑛𝑗𝑎_𝑒𝑟𝑒} 𝑠𝑠𝑖𝑜𝑛} | 문자열_표현식

표현식은 기본값, Jinja2 표현식(Ronacher. 2008) 또는 진자 표현식이 포함된 문자열로 힌트 템플릿을 지정하는 편리한 방법으로, 힌트의 일부는 하드코딩하고 다른 부분은 표현식으로 채울 수 있습니다. 그러나 PDL은 개발자가 개별 힌트뿐만 아니라 전체 모델 콜 체인 및 기타 모듈을 템플릿화할 수 있도록 함으로써 Jinja2의 사용 범위를 더욱 확장합니다. 가능한 표현식의 전체 목록은 Jinja2 설명서를 참조하는 것이 좋지만, 그림 2 PDL은 다음과 같은 진자2 문을 제외한 진자2 표현식만 사용합니다. {% if .. %} 어쩌면 {% for .. %}이는 이미 PDL의 if: 및 for: 함수와 겹치기 때문입니다.

마지막으로 PDL에는 특정 프로그래밍 언어로 코드를 실행할 수 있는 코드: 모듈이 있습니다(이 글을 쓰는 현재로서는 Python만 지원됨). 다음 섹션에서는 임의 코드 실행의 위험을 줄이기 위해 샌드박싱 기능을 제공하는 인터프리터를 포함한 PDL 도구에 대해 설명합니다. 자세한 내용은 PDL의 GitHub 리포지토리에 있는 튜토리얼 링크를 참조하세요.

 

4. 도구

PDL은 PDL 프로그램을 쉽게 작성, 실행 및 이해할 수 있는 도구를 제공합니다.

첫째, PDL 통역사 은 스크립팅 언어에서 기대할 수 있는 명령줄 인터페이스를 갖춘 실행 엔진입니다. 이 인터프리터는 스트리밍 모드를 지원하며, LLM 출력이 생성되는 동안 점진적으로 표시되므로 보다 대화형 채팅 환경을 제공합니다. 또한 인터프리터는 컨테이너에서 실행할 수 있는 샌드박싱을 지원하므로 LLM으로 생성된 작업이나 코드를 실행할 때 권장됩니다.

PDL IDE 지원 구문 강조 표시, 자동 완성, PDL 키워드에 대한 툴팁 및 오류 확인을 통해 PDL 코드를 더 쉽게 작성할 수 있도록 VSCode가 개선되었습니다. 이러한 기능은 부분적으로 유효한 PDL을 정의하는 JSON 스키마인 PDL 메타모드에 의해 구동됩니다.

%%pdl 마법 단위 주피터 노트북으로 개선된 개발자는 PDL에서 직접 코드 단위를 작성할 수 있습니다. 이러한 방식으로 호스팅된 노트북 플랫폼을 프롬프트의 대화형 탐색을 위한 간단한 놀이터로 사용할 수 있습니다. 동일한 노트북에 여러 개의 PDL 코드 단위가 있는 경우, 이후 단위는 이전 단위에서 정의된 변수를 사용할 수 있습니다. 또한 이후 단위의 배경 컨텍스트가 이전 단위에서 이어지므로, 이를 원하지 않는 경우 개발자는 다음을 사용할 수 있습니다. %%pdl --reset-context 를 사용하여 이 동작을 재정의할 수 있습니다.

PDL 실시간 문서 시각화 도구 PDL 프로그램 실행의 특정 흔적은 LLM 팁에 대한 논문이나 블로그 게시물에서 볼 수 있는 일반적인 그래픽과 유사한 색상이 중첩된 상자 형태로 표시됩니다. 그런 다음 사용자는 데이터를 표시하는 스프레드시트 셀과 유사하게 상자 중 하나를 선택하여 해당 PDL 코드를 표시할 수 있으며, 해당 데이터를 생성한 공식을 검토하기 위해 해당 상자를 선택할 수 있습니다. 이 실시간 보기를 통해 사용자는 특정 데이터를 빠르게 이해한 다음 해당 데이터를 생성한 코드를 이해하는 단계로 넘어갈 수 있습니다.

마지막으로 PDL에는 SDK(소프트웨어 개발 키트)는 파이썬에서 PDL을 호출하기 위한 작은 파이썬 라이브러리로, 에이전트와 같은 힌트 기반 절차를 사용하도록 대규모 파이썬 애플리케이션을 확장하는 데 유용합니다. 섹션에 설명된 대로 3 섹션에서 설명한 대로 PDL 파일은 코드 블록에 Python을 포함할 수 있습니다. PDL을 사용하여 대규모 애플리케이션을 개발할 때는 별도의 Python 파일에 함수를 정의한 다음 PDL에서 호출하여 이 코드를 몇 줄로 유지하는 것이 유용하다는 것을 알게 되었습니다. 좋은 방법은 PDL과 Python 간에 JSON 객체 형태로 데이터를 전달하는 것입니다. 선택적으로 PDL의 spec: 키워드를 사용하고, 다음 섹션에 표시된 것처럼 파이썬 쪽에서는 TypedDict 또는 Pydantic을 사용하여 유형 검사를 수행합니다. 3 표시됨.

PDL:声明式提示词编程语言 (a) PDL 코드

1text:
2- lang: python
3 code: |
4 import rag_mbpp
5 PDL_SESSION.mbpp = rag_mbpp.initialize()
6 result = ""
7- defs:
8 test_query: >-
9 编写一个 Python 函数,从字符串中删除给定字符的第一个和最后一个出现。
12 retrieved:
13 lang: python
14 spec: [{query: str, answer: str}]
15 code: |
16 import rag_mbpp
17 result = rag_mbpp.retrieve(
18 PDL_SESSION.mbpp, "${test_query}", 5
19 )
20 text: >
21 给定文本在 "Q:" 之后,生成一个 Python 函数在 "A:" 之后。
24 这里有一些示例,请完成最后一个:
25- for:
26 few_shot_sample: ${retrieved}
27 repeat: |
28 Q: ${few_shot_sample.query}
29 A: ‘‘‘${few_shot_sample.answer}‘‘‘
30- |-
31 Q: ${test_query}
32 A:
33- model: watsonx/ibm/granite-3-8b-instruct
34 parameters:
35 stop: ["Q:", "A:"]

(b) Python 코드

1from typing import TypedDict
2import datasets
3from sklearn.feature_extraction.text \
4 import TfidfVectorizer
5
6def initialize():
7 train_in = datasets.load_dataset(
8 "mbpp", "sanitized", split="train"
9 )
10 corpus = [row["prompt"] for row in train_in]
11 tfidf = TfidfVectorizer().fit(corpus)
12 def embed(text):
13 sparse_result = tfidf.transform(
14 raw_documents=[text]
15 )
16 return sparse_result.toarray().flatten()
17 train_em = train_in.map(
18 lambda row: {"em": embed(row["prompt"])}
19 )
20 vec_db = train_em.add_faiss_index("em")
21 return vec_db, embed
22
23QA = TypedDict("QA", {"query":str,"answer":str})
24def retrieve(mbpp, query, n: int) -> list[QA]:
25 vec_db, embed = mbpp
26 key = embed(query)
27 nearest = vec_db.get_nearest_examples(
28 "em", key, n
29 )
30 queries = nearest.examples["prompt"]
31 answers = nearest.examples["code"]
32 return [
33 {"query": q, "answer": a}
34 for q, a in zip(queries, answers)
35 ]

그림 3. RAG PDL의 예

5. 사례 연구

우리는 첫 번째 2 이 섹션에서는 간단한 PDL 챗봇의 예시를 살펴보았습니다. 이 섹션에서는 RAG, 프록시, PDL에서 PDL 생성 등 조금 더 복잡한 PDL 사용 사례를 보여드리겠습니다.

5.1 강화 생성 가져오기

검색 강화 세대 또는 RAG는 먼저 관련 컨텍스트를 검색한 다음 모델의 프롬프트에 추가하여 답을 생성하는 방식으로 작동합니다(Lewis et al. 2020). 그림. 3(a) 코드 생성 작업을 위한 소수의 예제를 검색하기 위해 RAG를 사용하는 PDL 프로그램을 보여줍니다. 코드: 2~6행은 Python을 사용하여 "대부분 기본적인 Python 프로그램"(Austin et al., 2008)으로 구성된 MBPP 데이터 세트에 대한 훈련 분할의 벡터 데이터베이스를 초기화합니다. 2021). 그래프를 사용합니다. 3(b)에 정의된 파이썬 함수와 이후 코드 블록에 상태를 전달할 수 있는 PDL_SESSION 특수 변수를 사용합니다. 그림 3(a)의 8~11번째 줄은 Python 코드를 생성한 자연어 요청에 test_query 변수를 초기화합니다. 12~19행은 학습 데이터에서 가장 유사한 5개의 예시로 검색된 변수를 초기화합니다.

20~24줄은 컨텍스트에 명령어를 추가하고, 25~29줄은 컨텍스트에 몇 가지 예제를 추가하며, 30~32줄은 컨텍스트에 테스트 쿼리를 추가합니다. 25줄의 for: 루프는 PDL을 사용하여 데이터를 생성하는 일반적인 방법이며, 이 경우에는 컨텍스트 학습에 사용됩니다. 마지막으로 33~35줄에서는 Granite 3 모델(Granite Team, IBM 2024), 누적 컨텍스트를 사용하여 쿼리 요청을 테스트하는 Python 함수를 생성하도록 합니다. 이것은 간단한 예시이긴 하지만, 저희는 Codellm-Devkit(Krishna et al. 2024)는 다양한 프로그래밍 언어의 소스 코드를 정적으로 분석하는 도구와 함께 사용되며, 코딩 작업을 위해 LLM에 메시지를 표시할 때 다른 관련 컨텍스트를 검색합니다.

PDL:声明式提示词编程语言 (a) 코드

1text:
2- read: react_few_shot_samples.txt
3- |
4
5 Hudson River 的发现者是什么时候出生的?
6- repeat:
7 text:
8 - def: thought
9 model: watsonx/ibm/granite-34b-code-instruct
10 parameters:
11 stop: ["Act:"]
12 include_stop_sequence: true
13 - def: action
14 model: watsonx/ibm/granite-34b-code-instruct
15 parameters:
16 stop: ["\n"]
17 parser: json
18 spec: {name: str, arguments: {topic: str}}
19 - def: observation
20 if: ${ action.name == "Search" }
21 then:
22 text:
23 - "Obs: "
24 - lang: python
25 code: |
26 import wikipedia
27 query = "${ action.arguments.topic }"
28 result = wikipedia.summary(query)
29 until: ${ action.name != "Search" }

(b) 인터프리터 추적

科罗拉多造山运动东部区域的海拔范围是多少?
Tho: 我需要搜索科罗拉多造山运动,找出东部区域的范围。
Act: {”name”: ”Search”, ”arguments”: {”topic”: ”科罗拉多造山运动”}}
Obs: 科罗拉多造山运动是一个事件 […]
[…]
Hudson River 的发现者是什么时候出生的?
Tho: 我需要搜索 Hudson River 的发现者,找出他是什么时候出生的。
Act: {”name”: ”Search”, ”arguments”: {”topic”: ”Hudson River 的发现者”}}
Obs: Hudson River 是一条 315 英里长的 […]
Tho: Hudson River 的发现者是 Henry Hudson。我需要搜索 Henry Hudson,找出他是什么时候出生的。
Act: {”name”: ”Search”, ”arguments”: {”topic”: ”Henry Hudson”}}
Obs: Henry Hudson (约 1565 年 – 消失 […]
Tho: Henry Hudson 于 1565 年出生。Act: {”name”: ”Finish”, ”arguments”: {”topic”: ”1565”}}

그림 4. ReAct 책임 있는 위치에서 SB를 대신하여 행동합니다.

5.2.리액트 에이전트

대규모 언어 모델링 기반 책임 있는 위치에서 SB를 대신하여 행동합니다. 대규모 언어 모델 선택 및 구성 가능 움직임in 매트릭스 에서 이러한 액션이 실행되고, 액션의 출력은 빅 언어 모델로 피드백됩니다. 주의. 이러한 에이전트에 대한 다양한 모델이 있습니다(예: ReAct(Yao et al. 2023) 및 ReWOO(Xu et al. 2023). 작업은 대규모 언어 모델을 기반으로 합니다. 도구 호출 (Schick et al. 2023), 에이전트는 동적인 대규모 언어 모델 부트스트랩 시퀀스에서 여러 도구 호출을 함께 연결합니다. 목표는 AI 기반 애플리케이션을 덜 규범적이고 더 목표 지향적으로 만드는 것입니다. 또한 상담원은 관찰 결과를 피드백으로 사용하여 작업이 잘못되었을 때 복구할 수 있습니다.

지도 4 는 간단한 ReAct 에이전트의 PDL 예시를 보여줍니다. ReAct의 핵심은 생각-행동-관찰 루프이며, 코드에서는 생각(8줄), 행동(13줄), 관찰(19줄)에 대한 변수 정의로 표현됩니다. 사고는 예를 들어 그림에서와 같이 모델 생성의 자연어입니다. 4(b)의 인터프리터 트레이스에서 '허드슨강 발견자를 검색하여 그가 언제 태어났는지 알아내야 합니다. 이 작업은 모델이 학습 데이터를 사용하여 Granite 모델의 도구와 일치시키기 위해 생성한 JSON입니다(Abdelaziz et al. 2024). 왼쪽의 17행과 18행은 빅 언어 모델 출력이 JSON으로 구문 분석되어 {name, arguments} 스키마를 준수하는지 확인하고, 오른쪽의 인터프리터 추적은 모델이 실제로 그러한 객체를 생성한다는 것을 보여줍니다. 따라서 진자2를 사용하여 27줄의 ${ action.arguments.topic }과 같은 객체의 필드에 액세스할 수 있습니다. 관찰은 환경, 이 경우에는 Wikipedia를 호출하는 Python 코드에 의해 생성됩니다. 27줄에 표시된 것처럼 4 섹션에서 설명한 대로 대규모 언어 모델에서 (부분적으로) 생성된 코드를 실행해야 하는 경우 PDL의 샌드박싱 기능을 사용하는 것이 좋습니다.

지도 4(b)의 인터프리터 트레이스는 이 실행에 에이전트 루프가 두 번 반복된다는 것을 보여줍니다. 이것은 간단한 예시이지만, 저희는 커밋4의 일부로 SWE-bench Lite 리더보드에서 사용된 PDL을 사용하여 코드 편집 에이전트도 구현했습니다(Jimenez et al. 2024). 이 제출물은 오픈 소스 모델만을 사용하여 23.7%의 첫 번째 사례를 풀었으며, 이는 오픈 소스 모델을 사용한 이전 결과보다 높으며 프론티어 모델의 결과와 비슷합니다.

5.3.빅 언어 모델을 사용하여 PDL에서 PDL 생성하기

이전 섹션에서는 인간 개발자가 PDL을 사용하여 다양한 큐잉 패턴을 인코딩하는 방법을 살펴보았습니다. 이 섹션에서는 대규모 언어 모델에 대해 살펴보고 이러한 언어 모델을 PDL 생성에도 사용할 수 있는 방법을 보여줍니다. 이러한 메타-PDL 생성은 에이전트 워크플로의 일부로 문제 해결 계획을 만들어야 할 때 유용합니다. 기존에는 이러한 계획이 텍스트, JSON 또는 Python 코드로만 작성되었습니다. PDL을 사용하면 이러한 계획은 완전히 실행 가능한 모델과 코드 호출의 조합이 될 수 있습니다. 이 섹션에서는 GSMHard 데이터 세트5 에서 PDL 메타 생성의 사용에 대해 살펴봅니다.

GSMHard는 간단한 산술 또는 기호 추론이 필요한 초등학교 수학 문제가 포함된 GSM8k의 더 어려운 버전으로, 입력인 수학 문제 문과 출력인 문제를 푸는 Python 코드가 포함되어 있습니다. 우리는 PAL (Gao et al. 2023) 메서드를 사용하지만, 파이썬 코드를 생성하는 대신 대규모 언어 모델에 PDL을 생성하도록 요청합니다. 텍스트 연쇄 사고는 PDL 텍스트 블록으로 표현되고 산술은 PDL 코드 블록을 사용하여 수행됩니다.

지도 6 PDL 코드를 생성하고 동일한 프로그램에서 실행하는 PDL 프로그램이 표시됩니다. 변수 데모에는 모델에 PDL 코드를 생성하는 방법을 가르치기 위해 고안된 몇 가지 예제가 포함되어 있습니다. 32줄에서 모델 호출 블록은 이러한 예제와 자유 변수를 입력으로 사용하는 문제를 사용합니다. 그 결과 문제를 해결하기 위한 PDL 프로그램이 생성됩니다. 38행에서는 PDL 프로그램을 추출하고 파이썬에서 실행합니다. 이 프로그램은 입력 문제를 채우는 GSMHard 데이터 세트에 적용됩니다.

이 실험에서 GSMHard 데이터 세트의 10%는 실측값이 질문과 일치하지 않아 실제로 잘못된 것으로 나타났습니다. 그림. 6 이러한 불일치의 예는 다음과 같습니다. 생성된 PDL 코드는 사람이 읽을 수 있어 기준 데이터와 일치하지 않는 데이터 포인트를 쉽게 확인할 수 있었고, 일부 경우 기준 데이터가 잘못되었다는 것을 발견할 수 있었기 때문에 PDL을 사용하면 이러한 문제를 발견하는 데 도움이 되었습니다. 대규모 언어 모델을 사용하여 전체 데이터 세트를 대상으로 일관성이 없는 것으로 보이는 예시를 체계적으로 골라냈습니다. 그런 다음 결과를 수동으로 선별하여 오탐을 제거하고 10%에서 이 문제가 있는 데이터 포인트를 식별했습니다.

PDL:声明式提示词编程语言

 

1 定义:
2 示例:
3 数据:
4 文本:
5 |
6 ...
7
8 问题: Roger 有 5 个网球。
9 他又购买了 2 罐网球。
10 每罐有 3 个网球。
11 现在他总共有多少个网球?
12
13 答案:
14 ```
15 文本:
16 - "Roger 起初有\n"
17 - 定义: tennis_balls
18 数据: 5
19 - "\n个网球。\n"
20 - "2 罐,每罐有 3 个网球,总共是\n"
21 - 语言: python
22 定义: bought_balls
23 代码: result = 2 * 3
24 - "\n个网球。\n"
25 - "结果是:\n"
26 - 语言: python
27 定义: RESULT
28 代码: result = ${ tennis_balls } + ${ bought_balls }
29 ```
30 原始: true
31 文本:
32 - 模型: watsonx/meta-llama/llama-3-70b-instruct
33 定义: PDL
34 输入:
35 文本:
36 - ${ demos.text }
37 - "问题: ${ question }"
38 - 语言: python
39 代码: |
40 from pdl.pdl import exec_str
41 s = """${ PDL }"""
42 pdl = s.split("```")[1]
43 result = exec_str(pdl)
44 定义: RESULT

그림 5.

James 决定每周跑 1793815 次冲刺
每次冲刺 60 米。
他每周总共跑多少米?
def solution():
sprints_per_day = 1793815
days_per_week = 3
meters_per_sprint = 60
total_sprints = sprints_per_day * days_per_week
total_meters = total_sprints * meters_per_sprint
result = total_meters
return result

그림 6: GSMHard 샘플 문제 데이터 포인트

 

6. 관련 작업

최근 연구에 따르면 큐 프레임 LLM과 사용자, 도구 또는 기타 모델 간의 상호 작용을 관리, 단순화 및 용이하게 하는 계층으로 정의됩니다(Liu et al.2023). 이 연구는 큐잉 프레임워크의 가장 큰 단점은 가파른 학습 곡선이라는 점을 강조합니다.

아마도 오늘날 가장 인기 있는 프롬프트 프레임워크는 LangChain일 것입니다(Chase et al.2022), 풍부한 기능으로 인해 강력하면서도 복잡한데, 미니체인의 주된 동기는 바로 이러한 복잡성을 피하기 위함입니다(Rush.2023), 고급 애플리케이션을 위해 결합할 수 있는 더 적은 수의 간단한 기능을 제공합니다. 그러나 LangChain과 미니체인은 모두 파이썬 기반 프레임워크로, 개발자가 명령형 코드를 작성해야 하기 때문에 비선언적이며, PDL은 미니체인과 비슷한 동기를 가지고 있지만 파이썬이 아닌 YAML을 기본으로 사용함으로써 한 단계 더 나아갑니다.

다른 프롬프트 프레임워크와 마찬가지로 PDL의 목표는 LLM을 더욱 강력하게 만드는 것입니다.지침(Microsoft.2023)는 파이썬 기반 프레임워크로, 보다 구조화된 디자인을 제공하지만 LangChain보다 더 원시적입니다. 마찬가지로 LMQL(Beurer-Kellner et al.2023)는 유형과 제한된 디코딩을 사용하는 파이썬에 내장된 도메인별 언어로, 힌트와 프로그래밍을 얽는다는 점에서 LMQL에서 일부 영감을 얻었지만 LMQL과 달리 명령형 파이썬 코드에 덜 의존합니다.PDL은 유한 상태 기계를 사용하여 다양한 지능형 루프의 내부 흐름을 공식적으로 지정합니다(Crouse et al.2024); 이것은 흥미로운 시도이지만 정교한 큐잉 언어를 도입하지는 않습니다.

도메인별 언어의 장점 중 하나는 최적화와 같은 프로그램 변환을 구현할 수 있다는 점입니다(Mernik et al.2005).DSPy 큐잉 프레임워크(Khattab et al.2023)의 모토는 "힌트가 아닌 프로그래밍"으로, 힌트를 자동으로 생성하므로 개발자가 수동으로 작성할 필요가 없습니다. 마찬가지로, 비에이라(Li et al.2024)는 Prolog를 확장하여 LLM을 확률 관계로 사용하고 프롬프트를 자동으로 생성합니다.DSPy와 Vieira는 모두 매우 고급 프레임워크이지만 PDL과 달리 특정 프롬프트에 대한 개발자의 제어를 약화시킵니다.Lale(Baudart et al.2021)는 사용자가 AI 파이프라인에서 자동화와 제어 간의 균형을 점진적으로 조정할 수 있는 언어이지만 LLM 단서에 초점을 맞추지는 않습니다.DSPy, Vieira 및 Lale은 예측 성능을 위해 최적화하는 반면 다른 최적화는 계산 성능을 목표로 합니다.SGLang(Zheng et al.2023)는 접두사 캐시를 더 잘 활용하여 KV 캐시에서 더 많은 캐시 히트를 생성함으로써 이를 달성합니다(Kwon et al.2023). 향후 연구에서는 PDL의 선언적 특성으로 유사한 계산 성능 최적화를 구현할 수 있는지 살펴볼 예정입니다.

최근에는 LLM 에이전트에 초점을 맞춘 LLM(대규모 언어 모델링) 기반 프롬프트 프레임워크가 다수 등장했습니다.AutoGen(Wu et al.2023)는 모든 콘텐츠가 에이전트와 대화로 구성되는 멀티 에이전트 프레임워크입니다. 다른 멀티 에이전트 프레임워크에는 CrewAI(Moura.2023) 및 GPTSwarm(Zhuge et al.2024). 이러한 프레임워크는 다른 LLM 기반 사용 사례보다 프록시에 대한 지원을 우선시하며, PDL은 프록시를 지원하면서도 프록시를 여러 큐잉 기술 중 하나로 취급하여 보다 균형 잡힌 입장을 추구합니다.

 

7. 결론

PDL은 선언적 데이터 지향 언어로, 프로그램은 리터럴 또는 생성 데이터인 YAML 블록으로 구성됩니다. 사고 모델은 데이터를 배경 컨텍스트에 추가하여 블록을 실행하는 것이며, 이는 이후 더 큰 언어 모델을 호출할 때 단서로 사용됩니다. 이 논문에서는 샘플 프로그램과 함께 이 언어를 소개하고 구문 및 도구에 대한 안내를 제공합니다. 또한 선언적 언어의 특성상 속도, 정확성 및 보안을 위한 자동 최적화를 쉽게 구현할 수 있으며, 이는 향후 작업에서 점진적으로 구현될 예정입니다.PDL은 이제 바로 사용할 수 있으며 다음 URL에서 오픈 소스로 제공됩니다:https://github.com/IBM/prompt-declaration-language.

© 저작권 정책

관련 문서

댓글 없음

댓글에 참여하려면 로그인해야 합니다!
지금 로그인
없음
댓글 없음...