langchain_rust/prompt/
few_shot.rs1use std::{fmt, sync::Arc};
2
3use super::{
4 example_selector::ExampleSelector, FormatPrompter, PromptArgs, PromptError, PromptFromatter,
5 PromptTemplate,
6};
7use crate::schemas::{messages::Message, prompt::PromptValue};
8
9#[derive(Clone)]
11enum Examples {
12 Fixed(Vec<PromptArgs>),
13 Selector(Arc<dyn ExampleSelector>),
14}
15
16#[derive(Clone)]
43pub struct FewShotPromptTemplate {
44 examples: Examples,
45 example_prompt: PromptTemplate,
46 prefix: Option<PromptTemplate>,
47 suffix: Option<PromptTemplate>,
48 separator: String,
49}
50
51impl FewShotPromptTemplate {
52 pub fn new(example_prompt: PromptTemplate, examples: Vec<PromptArgs>) -> Self {
54 Self::build(example_prompt, Examples::Fixed(examples))
55 }
56
57 pub fn with_selector<S: ExampleSelector + 'static>(
59 example_prompt: PromptTemplate,
60 selector: S,
61 ) -> Self {
62 Self::with_shared_selector(example_prompt, Arc::new(selector))
63 }
64
65 pub fn with_shared_selector(
68 example_prompt: PromptTemplate,
69 selector: Arc<dyn ExampleSelector>,
70 ) -> Self {
71 Self::build(example_prompt, Examples::Selector(selector))
72 }
73
74 fn build(example_prompt: PromptTemplate, examples: Examples) -> Self {
75 Self {
76 examples,
77 example_prompt,
78 prefix: None,
79 suffix: None,
80 separator: "\n\n".into(),
81 }
82 }
83
84 pub fn with_prefix(mut self, prefix: PromptTemplate) -> Self {
86 self.prefix = Some(prefix);
87 self
88 }
89
90 pub fn with_suffix(mut self, suffix: PromptTemplate) -> Self {
92 self.suffix = Some(suffix);
93 self
94 }
95
96 pub fn with_separator<S: Into<String>>(mut self, separator: S) -> Self {
98 self.separator = separator.into();
99 self
100 }
101
102 pub async fn format(&self, input_variables: PromptArgs) -> Result<String, PromptError> {
105 let examples = match &self.examples {
106 Examples::Fixed(examples) => examples.clone(),
107 Examples::Selector(selector) => selector.select_examples(&input_variables).await?,
108 };
109 self.assemble(&examples, input_variables)
110 }
111
112 fn assemble(
114 &self,
115 examples: &[PromptArgs],
116 input_variables: PromptArgs,
117 ) -> Result<String, PromptError> {
118 let mut pieces = Vec::with_capacity(examples.len() + 2);
119 if let Some(prefix) = &self.prefix {
120 pieces.push(prefix.format(input_variables.clone())?);
121 }
122 for (i, example) in examples.iter().enumerate() {
123 let text = self.example_prompt.format(example.clone()).map_err(|e| {
124 PromptError::OtherError(format!("formatting example {}: {e}", i + 1))
125 })?;
126 pieces.push(text);
127 }
128 if let Some(suffix) = &self.suffix {
129 pieces.push(suffix.format(input_variables)?);
130 }
131 pieces.retain(|piece| !piece.is_empty());
132 Ok(pieces.join(&self.separator))
133 }
134}
135
136impl fmt::Debug for FewShotPromptTemplate {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 let examples = match &self.examples {
139 Examples::Fixed(examples) => format!("{} fixed", examples.len()),
140 Examples::Selector(_) => "selector".to_string(),
141 };
142 f.debug_struct("FewShotPromptTemplate")
143 .field("examples", &examples)
144 .field("example_prompt", &self.example_prompt.template())
145 .field("prefix", &self.prefix.as_ref().map(|p| p.template()))
146 .field("suffix", &self.suffix.as_ref().map(|p| p.template()))
147 .field("separator", &self.separator)
148 .finish()
149 }
150}
151
152#[async_trait::async_trait]
153impl FormatPrompter for FewShotPromptTemplate {
154 fn format_prompt(&self, input_variables: PromptArgs) -> Result<PromptValue, PromptError> {
157 match &self.examples {
158 Examples::Fixed(examples) => {
159 let text = self.assemble(examples, input_variables)?;
160 Ok(PromptValue::from_messages(vec![
161 Message::new_human_message(text),
162 ]))
163 }
164 Examples::Selector(_) => Err(PromptError::OtherError(
165 "a FewShotPromptTemplate with an example selector has to be formatted with \
166 format_prompt_async (chains already do)"
167 .into(),
168 )),
169 }
170 }
171
172 async fn format_prompt_async(
173 &self,
174 input_variables: PromptArgs,
175 ) -> Result<PromptValue, PromptError> {
176 let text = self.format(input_variables).await?;
177 Ok(PromptValue::from_messages(vec![
178 Message::new_human_message(text),
179 ]))
180 }
181
182 fn get_input_variables(&self) -> Vec<String> {
184 let mut variables: Vec<String> = Vec::new();
185 for template in self.prefix.iter().chain(self.suffix.iter()) {
186 for variable in template.variables() {
187 if !variables.contains(&variable) {
188 variables.push(variable);
189 }
190 }
191 }
192 variables
193 }
194}