rig_experimental/
routing.rs1use std::collections::HashMap;
5
6use serde::{Deserialize, Serialize};
7
8use rig::{
9 agent::Agent,
10 completion::{CompletionModel, Prompt},
11 vector_store::VectorStoreIndex,
12};
13
14pub struct SemanticRouter<V> {
17 store: V,
18 threshold: f64,
19}
20
21pub struct SemanticRouterWithAgents<V, M: CompletionModel> {
24 store: V,
25 threshold: f64,
26 agents: HashMap<String, Agent<M>>,
27}
28
29impl<V> SemanticRouter<V> {
30 pub fn builder() -> SemanticRouterBuilder<V> {
32 SemanticRouterBuilder::new()
33 }
34}
35
36impl<V> SemanticRouter<V>
37where
38 V: VectorStoreIndex,
39{
40 pub async fn prompt(&self, query: &str) -> Option<String> {
41 let res = self.store.top_n(query, 1).await.ok()?;
42 let (score, _, SemanticRoute { tag }) = res.first()?;
43
44 tracing::info!("Retrieved route: {tag}, {score}");
45
46 if *score < self.threshold {
47 return None;
48 }
49
50 Some(tag.to_owned())
51 }
52
53 pub fn agent<M: CompletionModel>(
54 self,
55 route: &str,
56 agent: Agent<M>,
57 ) -> SemanticRouterWithAgents<V, M> {
58 let mut agents = HashMap::new();
59 agents.insert(route.to_string(), agent);
60 SemanticRouterWithAgents {
61 store: self.store,
62 threshold: self.threshold,
63 agents,
64 }
65 }
66}
67
68impl<V, M> SemanticRouterWithAgents<V, M>
69where
70 V: VectorStoreIndex,
71 M: CompletionModel,
72{
73 pub async fn prompt<R>(&self, query: R) -> Result<Option<String>, Box<dyn std::error::Error>>
75 where
76 R: Into<RouterRequest>,
77 {
78 let RouterRequest { query, turns } = query.into();
79 let res = self.store.top_n(&query, 1).await?;
80 let (score, _, SemanticRoute { tag }) = if let Some(result) = res.first() {
81 result
82 } else {
83 return Ok(None);
84 };
85
86 if *score < self.threshold {
87 return Ok(None);
88 }
89
90 let Some(agent) = self.agents.get(tag) else {
91 panic!("Couldn't find an agent that exists at tag: {tag}");
92 };
93
94 let res = if turns > 0 {
95 agent
96 .prompt(query)
97 .multi_turn(turns as usize)
98 .await
99 .unwrap()
100 } else {
101 agent.prompt(query).await.unwrap()
102 };
103
104 Ok(Some(res))
105 }
106
107 pub fn agent(mut self, route: &str, agent: Agent<M>) -> Self {
108 self.agents.insert(route.to_string(), agent);
109 self
110 }
111}
112
113pub struct RouterRequest {
114 query: String,
115 turns: u64,
116}
117
118impl RouterRequest {
119 pub fn new(query: String) -> Self {
120 Self::from(query)
121 }
122
123 pub fn with_turns(mut self, turns: u64) -> Self {
124 self.turns = turns;
125 self
126 }
127}
128
129impl From<String> for RouterRequest {
130 fn from(value: String) -> Self {
131 Self {
132 query: value,
133 turns: 0,
134 }
135 }
136}
137
138impl From<&str> for RouterRequest {
139 fn from(value: &str) -> Self {
140 Self {
141 query: value.to_string(),
142 turns: 0,
143 }
144 }
145}
146
147impl From<(String, u64)> for RouterRequest {
148 fn from((query, turns): (String, u64)) -> Self {
149 Self { query, turns }
150 }
151}
152
153impl From<(&str, u64)> for RouterRequest {
154 fn from((query, turns): (&str, u64)) -> Self {
155 Self {
156 query: query.to_string(),
157 turns,
158 }
159 }
160}
161
162#[derive(Serialize, Deserialize)]
163pub struct SemanticRoute {
164 tag: String,
165}
166
167pub trait Router: VectorStoreIndex {
168 fn retrieve_route() -> impl std::future::Future<Output = Option<String>> + Send;
169}
170
171pub struct SemanticRouterBuilder<V> {
172 store: Option<V>,
173 threshold: Option<f64>,
174}
175
176impl<V> Default for SemanticRouterBuilder<V> {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182impl<V> SemanticRouterBuilder<V> {
183 pub fn new() -> Self {
184 Self {
185 store: None,
186 threshold: None,
187 }
188 }
189
190 pub fn store(mut self, router: V) -> Self {
191 self.store = Some(router);
192
193 self
194 }
195
196 pub fn threshold(mut self, threshold: f64) -> Self {
197 self.threshold = Some(threshold);
198
199 self
200 }
201
202 pub fn build(self) -> Result<SemanticRouter<V>, SemanticRouterError> {
203 let Some(store) = self.store else {
204 return Err(SemanticRouterError::StoreNotFound);
205 };
206
207 let threshold = self.threshold.unwrap_or(0.8);
208
209 Ok(SemanticRouter { store, threshold })
210 }
211}
212
213#[derive(thiserror::Error, Debug)]
214pub enum SemanticRouterError {
215 #[error("Vector store not found")]
216 StoreNotFound,
217}