1use std::{
4 cmp::Ordering,
5 fmt,
6 sync::{Arc, RwLock},
7};
8
9use async_trait::async_trait;
10
11use super::{PromptArgs, PromptError, PromptFromatter, PromptTemplate};
12use crate::{embedding::Embedder, schemas::messages::value_to_text};
13
14#[async_trait]
18pub trait ExampleSelector: Send + Sync {
19 async fn add_example(&self, example: PromptArgs) -> Result<(), PromptError>;
21
22 async fn select_examples(
25 &self,
26 input_variables: &PromptArgs,
27 ) -> Result<Vec<PromptArgs>, PromptError>;
28}
29
30type LengthFn = Arc<dyn Fn(&str) -> usize + Send + Sync>;
31
32pub struct LengthBasedExampleSelector {
45 example_prompt: PromptTemplate,
46 max_length: usize,
47 length_fn: LengthFn,
48 examples: RwLock<Vec<(PromptArgs, usize)>>,
50}
51
52impl LengthBasedExampleSelector {
53 pub const DEFAULT_MAX_LENGTH: usize = 2048;
55
56 pub fn new(
59 example_prompt: PromptTemplate,
60 examples: Vec<PromptArgs>,
61 ) -> Result<Self, PromptError> {
62 let selector = Self {
63 example_prompt,
64 max_length: Self::DEFAULT_MAX_LENGTH,
65 length_fn: Arc::new(word_count),
66 examples: RwLock::new(Vec::new()),
67 };
68 for example in examples {
69 selector.push(example)?;
70 }
71 Ok(selector)
72 }
73
74 pub fn with_max_length(mut self, max_length: usize) -> Self {
76 self.max_length = max_length;
77 self
78 }
79
80 pub fn with_length_fn<F>(mut self, length_fn: F) -> Self
83 where
84 F: Fn(&str) -> usize + Send + Sync + 'static,
85 {
86 self.length_fn = Arc::new(length_fn);
87 let examples = std::mem::take(self.examples.get_mut().unwrap_or_else(|e| e.into_inner()));
88 for (example, _) in examples {
89 let _ = self.push(example);
91 }
92 self
93 }
94
95 fn push(&self, example: PromptArgs) -> Result<(), PromptError> {
96 let length = (self.length_fn)(&self.example_prompt.format(example.clone())?);
97 self.examples
98 .write()
99 .unwrap_or_else(|e| e.into_inner())
100 .push((example, length));
101 Ok(())
102 }
103}
104
105impl fmt::Debug for LengthBasedExampleSelector {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 f.debug_struct("LengthBasedExampleSelector")
108 .field("max_length", &self.max_length)
109 .field(
110 "examples",
111 &self
112 .examples
113 .read()
114 .unwrap_or_else(|e| e.into_inner())
115 .len(),
116 )
117 .finish()
118 }
119}
120
121#[async_trait]
122impl ExampleSelector for LengthBasedExampleSelector {
123 async fn add_example(&self, example: PromptArgs) -> Result<(), PromptError> {
124 self.push(example)
125 }
126
127 async fn select_examples(
128 &self,
129 input_variables: &PromptArgs,
130 ) -> Result<Vec<PromptArgs>, PromptError> {
131 let input_length: usize = input_variables
132 .values()
133 .map(|v| (self.length_fn)(&value_to_text(v)))
134 .sum();
135 let mut remaining = self.max_length.saturating_sub(input_length);
136 let mut selected = Vec::new();
137 for (example, length) in self
138 .examples
139 .read()
140 .unwrap_or_else(|e| e.into_inner())
141 .iter()
142 {
143 if *length > remaining {
144 break;
145 }
146 remaining -= length;
147 selected.push(example.clone());
148 }
149 Ok(selected)
150 }
151}
152
153fn word_count(text: &str) -> usize {
155 text.split_whitespace().count()
156}
157
158pub struct SemanticSimilarityExampleSelector {
175 embedder: Arc<dyn Embedder>,
176 k: usize,
177 input_keys: Option<Vec<String>>,
178 examples: RwLock<Vec<(PromptArgs, Vec<f64>)>>,
179}
180
181impl SemanticSimilarityExampleSelector {
182 pub const DEFAULT_K: usize = 4;
184
185 pub fn new<E: Embedder + 'static>(embedder: E) -> Self {
187 Self::with_embedder(Arc::new(embedder))
188 }
189
190 pub fn with_embedder(embedder: Arc<dyn Embedder>) -> Self {
192 Self {
193 embedder,
194 k: Self::DEFAULT_K,
195 input_keys: None,
196 examples: RwLock::new(Vec::new()),
197 }
198 }
199
200 pub async fn from_examples<E: Embedder + 'static>(
202 examples: Vec<PromptArgs>,
203 embedder: E,
204 k: usize,
205 ) -> Result<Self, PromptError> {
206 let selector = Self::new(embedder).with_k(k);
207 selector.add_examples(examples).await?;
208 Ok(selector)
209 }
210
211 pub fn with_k(mut self, k: usize) -> Self {
213 self.k = k;
214 self
215 }
216
217 pub fn with_input_keys<I, S>(mut self, keys: I) -> Self
220 where
221 I: IntoIterator<Item = S>,
222 S: Into<String>,
223 {
224 self.input_keys = Some(keys.into_iter().map(Into::into).collect());
225 self
226 }
227
228 pub async fn add_examples(&self, examples: Vec<PromptArgs>) -> Result<(), PromptError> {
230 if examples.is_empty() {
231 return Ok(());
232 }
233 let texts: Vec<String> = examples.iter().map(|e| self.text_of(e)).collect();
234 let vectors = self
235 .embedder
236 .embed_documents(&texts)
237 .await
238 .map_err(|e| PromptError::OtherError(format!("embedding examples: {e}")))?;
239 if vectors.len() != examples.len() {
240 return Err(PromptError::OtherError(format!(
241 "embedder returned {} vectors for {} examples",
242 vectors.len(),
243 examples.len()
244 )));
245 }
246 self.examples
247 .write()
248 .unwrap_or_else(|e| e.into_inner())
249 .extend(examples.into_iter().zip(vectors));
250 Ok(())
251 }
252
253 #[cfg(test)]
254 pub(crate) fn examples_for_test(&self, examples: Vec<(PromptArgs, Vec<f64>)>) {
255 self.examples
256 .write()
257 .unwrap_or_else(|e| e.into_inner())
258 .extend(examples);
259 }
260
261 fn text_of(&self, args: &PromptArgs) -> String {
264 let mut keys: Vec<&String> = match &self.input_keys {
265 Some(keys) => keys.iter().filter(|k| args.contains_key(*k)).collect(),
266 None => args.keys().collect(),
267 };
268 keys.sort();
269 keys.iter()
270 .map(|k| value_to_text(&args[*k]))
271 .collect::<Vec<_>>()
272 .join(" ")
273 }
274}
275
276impl fmt::Debug for SemanticSimilarityExampleSelector {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 f.debug_struct("SemanticSimilarityExampleSelector")
279 .field("k", &self.k)
280 .field("input_keys", &self.input_keys)
281 .field(
282 "examples",
283 &self
284 .examples
285 .read()
286 .unwrap_or_else(|e| e.into_inner())
287 .len(),
288 )
289 .finish()
290 }
291}
292
293#[async_trait]
294impl ExampleSelector for SemanticSimilarityExampleSelector {
295 async fn add_example(&self, example: PromptArgs) -> Result<(), PromptError> {
296 self.add_examples(vec![example]).await
297 }
298
299 async fn select_examples(
300 &self,
301 input_variables: &PromptArgs,
302 ) -> Result<Vec<PromptArgs>, PromptError> {
303 if self.k == 0
304 || self
305 .examples
306 .read()
307 .unwrap_or_else(|e| e.into_inner())
308 .is_empty()
309 {
310 return Ok(Vec::new());
311 }
312 let query = self
313 .embedder
314 .embed_query(&self.text_of(input_variables))
315 .await
316 .map_err(|e| PromptError::OtherError(format!("embedding the input: {e}")))?;
317 let examples = self.examples.read().unwrap_or_else(|e| e.into_inner());
318 let mut scored: Vec<(f64, &PromptArgs)> = examples
319 .iter()
320 .map(|(example, vector)| (cosine_similarity(&query, vector), example))
321 .collect();
322 scored.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));
324 Ok(scored
325 .into_iter()
326 .take(self.k)
327 .map(|(_, example)| example.clone())
328 .collect())
329 }
330}
331
332fn cosine_similarity(a: &[f64], b: &[f64]) -> f64 {
334 let dot: f64 = a.iter().zip(b).map(|(x, y)| x * y).sum();
335 let norm = |v: &[f64]| v.iter().map(|x| x * x).sum::<f64>().sqrt();
336 let denominator = norm(a) * norm(b);
337 if denominator == 0.0 {
338 0.0
339 } else {
340 dot / denominator
341 }
342}