venkat-srinivasan-nexusflow commited on
Commit
2ed01e6
1 Parent(s): b5c5d91

Upload 3 files

Browse files
.gitattributes CHANGED
@@ -34,3 +34,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  tokenizer.json filter=lfs diff=lfs merge=lfs -text
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
+ agent.png filter=lfs diff=lfs merge=lfs -text
agent.png ADDED

Git LFS Details

  • SHA256: f146935cbfdb35ebeff55a016f5c2d99323edbc77cb3c73e16acfdfa6db2f964
  • Pointer size: 132 Bytes
  • Size of remote file: 1.52 MB
example/vllm_v2_extraction_agent.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ from typing import List, Dict, Any, Optional
3
+ import json
4
+ import requests
5
+ from bs4 import BeautifulSoup
6
+ from openai import OpenAI
7
+
8
+ """
9
+ EXAMPLE OUTPUT:
10
+
11
+ What is the current population for the city where Einstein was born?
12
+
13
+ Turn 1
14
+ ----------------------------------------
15
+
16
+ Executing: fetch_wiki_content
17
+ Arguments: {'title': 'Albert Einstein'}
18
+
19
+ Turn 2
20
+ ----------------------------------------
21
+
22
+ Executing: deliver_answer
23
+ Arguments: {'fields': ['Ulm, German Empire']}
24
+ ANSWER FROM THE ASSISTANT: ['Ulm, German Empire']
25
+
26
+ Turn 3
27
+ ----------------------------------------
28
+
29
+ Executing: fetch_wiki_content
30
+ Arguments: {'title': 'Ulm'}
31
+
32
+ Turn 4
33
+ ----------------------------------------
34
+
35
+ Executing: deliver_answer
36
+ Arguments: {'fields': ['128,928']}
37
+ ANSWER FROM THE ASSISTANT: ['128,928']
38
+
39
+ Turn 5
40
+ ----------------------------------------
41
+ Extraction Complete
42
+
43
+
44
+ Why was Einstein famous?
45
+
46
+ Turn 1
47
+ ----------------------------------------
48
+
49
+ Executing: fetch_wiki_content
50
+ Arguments: {'title': 'Albert Einstein'}
51
+
52
+ Turn 2
53
+ ----------------------------------------
54
+
55
+ Executing: deliver_answer
56
+ Arguments: {'fields': ['Best known for developing the theory of relativity, Einstein also made important contributions to quantum mechanics.', 'His mass–energy equivalence formula E = mc2, which arises from special relativity, has been called "the world\'s most famous equation."', 'He received the 1921 Nobel Prize in Physics.']}
57
+ ANSWER FROM THE ASSISTANT: ['Best known for developing the theory of relativity, Einstein also made important contributions to quantum mechanics.', 'His mass–energy equivalence formula E = mc2, which arises from special relativity, has been called "the world\'s most famous equation."', 'He received the 1921 Nobel Prize in Physics.']
58
+
59
+ Turn 3
60
+ ----------------------------------------
61
+ Extraction Complete
62
+ """
63
+
64
+ @dataclass
65
+ class WikiConfig:
66
+ """Configuration for OpenAI and Wikipedia settings"""
67
+ api_key: str = "sk-123"
68
+ api_base: str = "{info}/v1"
69
+ model: Optional[str] = None
70
+ max_turns: int = 5
71
+ wikipedia_base_url: str = "https://en.wikipedia.org/wiki/"
72
+
73
+ class WikiTools:
74
+ """Collection of Wikipedia and extraction tools"""
75
+
76
+ def __init__(self, base_url: str):
77
+ self.base_url = base_url
78
+
79
+ def fetch_wiki_content(self, title: str, section: Optional[str] = None) -> str:
80
+ """Fetch and clean Wikipedia article content, optionally from a specific section"""
81
+ url = f"{self.base_url}{title.replace(' ', '_')}"
82
+ response = requests.get(url)
83
+ soup = BeautifulSoup(response.content, 'html.parser')
84
+
85
+ # Remove unwanted sections
86
+ for unwanted in soup.find_all(['script', 'style', 'footer', 'header']):
87
+ unwanted.decompose()
88
+
89
+ if section:
90
+ # Find specific section if requested
91
+ section_tag = soup.find('span', {'id': section})
92
+ if section_tag:
93
+ content = section_tag.parent.find_next_siblings()
94
+ text = ' '.join(tag.get_text() for tag in content)
95
+ else:
96
+ return "Section not found"
97
+ else:
98
+ # Get main content
99
+ content = soup.find(id='mw-content-text')
100
+ if content:
101
+ text = content.get_text()
102
+ else:
103
+ return "Content not found"
104
+
105
+ # Clean and normalize text
106
+ text = ' '.join(text.split())
107
+ return text[:8000] # Truncate to avoid token limits
108
+
109
+ @staticmethod
110
+ def deliver_answer(fields: List[str]) -> Dict[str, Any]:
111
+ """Extract specific information from text spans"""
112
+ print (f"ANSWER FROM THE ASSISTANT: {fields}")
113
+ return {
114
+ "extracted_fields": "Provided fields was delivered to the user successfully."
115
+ }
116
+
117
+ class ToolRegistry:
118
+ """Registry of available tools and their schemas"""
119
+
120
+ def __init__(self, wiki_tools: WikiTools):
121
+ self.wiki_tools = wiki_tools
122
+
123
+ @property
124
+ def available_functions(self) -> Dict[str, callable]:
125
+ return {
126
+ "fetch_wiki_content": self.wiki_tools.fetch_wiki_content,
127
+ "deliver_answer": self.wiki_tools.deliver_answer
128
+ }
129
+
130
+ @property
131
+ def tool_schemas(self) -> List[Dict[str, Any]]:
132
+ return [
133
+ {
134
+ "type": "function",
135
+ "function": {
136
+ "name": "fetch_wiki_content",
137
+ "description": "Fetch content from a Wikipedia article",
138
+ "parameters": {
139
+ "type": "object",
140
+ "properties": {
141
+ "title": {
142
+ "type": "string",
143
+ "description": "The title of the Wikipedia article"
144
+ },
145
+ "section": {
146
+ "type": "string",
147
+ "description": "Optional: Specific section ID to fetch",
148
+ "optional": True
149
+ }
150
+ },
151
+ "required": ["title"]
152
+ }
153
+ }
154
+ },
155
+ {
156
+ "type": "function",
157
+ "function": {
158
+ "name": "deliver_answer",
159
+ "description": "Extract specific information from the fetched text",
160
+ "parameters": {
161
+ "type": "object",
162
+ "properties": {
163
+ "fields": {
164
+ "type": "array",
165
+ "items": {"type": "string"},
166
+ "description": "List of text spans from the article that are relevant to the query"
167
+ }
168
+ },
169
+ "required": ["fields"]
170
+ }
171
+ }
172
+ }
173
+ ]
174
+
175
+ class WikiExtractionAgent:
176
+ """Main agent class that handles the extraction process"""
177
+
178
+ def __init__(self, config: WikiConfig):
179
+ self.config = config
180
+ self.client = OpenAI(api_key=config.api_key, base_url=config.api_base)
181
+ self.wiki_tools = WikiTools(config.wikipedia_base_url)
182
+ self.tools = ToolRegistry(self.wiki_tools)
183
+ self.messages = [{"system" : "1. First fetch any wikipedia pages you might need to answer the user query. Do not answer from parametric knowledge.\n\n2.Then, provide the answer to the user using the deliver_answer from the retrieved wikipedia page.\n\n3. You may need to issue multiple calls to wikipedia after extracting answers if there are nested dependencies for information."}]
184
+
185
+ if not config.model:
186
+ models = self.client.models.list()
187
+ self.config.model = models.data[0].id
188
+
189
+ def _serialize_tool_call(self, tool_call) -> Dict[str, Any]:
190
+ """Convert tool call to serializable format"""
191
+ return {
192
+ "id": tool_call.id,
193
+ "type": tool_call.type,
194
+ "function": {
195
+ "name": tool_call.function.name,
196
+ "arguments": tool_call.function.arguments
197
+ }
198
+ }
199
+
200
+ def process_tool_calls(self, message) -> List[Dict[str, Any]]:
201
+ """Process and execute tool calls from assistant"""
202
+ results = []
203
+
204
+ for tool_call in message.tool_calls:
205
+ function_name = tool_call.function.name
206
+ function_args = json.loads(tool_call.function.arguments)
207
+
208
+ print(f"\nExecuting: {function_name}")
209
+ print(f"Arguments: {function_args}")
210
+
211
+ function_response = self.tools.available_functions[function_name](**function_args)
212
+ results.append({
213
+ "tool": function_name,
214
+ "args": function_args,
215
+ "response": function_response
216
+ })
217
+
218
+ self.messages.append({
219
+ "role": "tool",
220
+ "content": json.dumps(function_response),
221
+ "tool_call_id": tool_call.id,
222
+ "name": function_name
223
+ })
224
+
225
+ return results
226
+
227
+ def extract_information(self, query: str) -> List[Dict[str, Any]]:
228
+ """Main method to handle the extraction process"""
229
+ self.messages = [{
230
+ "role": "user",
231
+ "content": f"""Extract information from Wikipedia to answer this query: {query}
232
+
233
+ You can use these tools:
234
+ 1. fetch_wiki_content: Get article content
235
+ 2. deliver_answer: deliver relevant information
236
+
237
+ Please fetch content first, and iterate as needed to get to the webpage with the correct answer and then deliver the relevant information."""
238
+ }]
239
+
240
+ all_results = []
241
+
242
+ for turn in range(self.config.max_turns):
243
+ print(f"\nTurn {turn + 1}")
244
+ print("-" * 40)
245
+
246
+ response = self.client.chat.completions.create(
247
+ messages=self.messages,
248
+ model=self.config.model,
249
+ tools=self.tools.tool_schemas,
250
+ temperature=0.0,
251
+ )
252
+
253
+ message = response.choices[0].message
254
+
255
+ if not message.tool_calls:
256
+ print("Extraction Complete")
257
+ break
258
+
259
+ self.messages.append({
260
+ "role": "assistant",
261
+ "content": json.dumps(message.content),
262
+ "tool_calls": [self._serialize_tool_call(tc) for tc in message.tool_calls]
263
+ })
264
+
265
+ results = self.process_tool_calls(message)
266
+ all_results.extend(results)
267
+
268
+ return all_results
269
+
270
+ def main():
271
+ # Example usage
272
+ config = WikiConfig()
273
+ agent = WikiExtractionAgent(config)
274
+
275
+ # Multi-step query example
276
+ results = agent.extract_information(
277
+ query="""What is the current population for the city where Einstein was born?"""
278
+ )
279
+
280
+ # Single query example
281
+ results = agent.extract_information(
282
+ query="Why was Einstein famous?"
283
+ )
284
+
285
+
286
+ if __name__ == "__main__":
287
+ main()
example/vllm_v2_weather_agent.py ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ import json
3
+ from typing import List, Dict, Any, Optional
4
+ from openai import OpenAI
5
+ """
6
+ EXAMPLE OUTPUT:
7
+
8
+ ****************************************
9
+ RUNNING QUERY: What's the weather for Paris, TX in fahrenheit?
10
+ Turn 1
11
+ ----------------------------------------
12
+
13
+ Executing: get_geo_coordinates
14
+ Arguments: {'city': 'Paris', 'state': 'TX'}
15
+ Response: The coordinates for Paris, TX are: latitude 33.6609, longitude 95.5555
16
+
17
+ Turn 2
18
+ ----------------------------------------
19
+
20
+ Executing: get_current_weather
21
+ Arguments: {'latitude': [33.6609], 'longitude': [95.5555], 'unit': 'fahrenheit'}
22
+ Response: The weather is 85 degrees fahrenheit. It is partly cloudy, with highs in the 90's.
23
+
24
+ Turn 3
25
+ ----------------------------------------
26
+ Conversation Complete
27
+
28
+
29
+ ****************************************
30
+ RUNNING QUERY: Who won the most recent PGA?
31
+ Turn 1
32
+ ----------------------------------------
33
+
34
+ Executing: no_relevant_function
35
+ Arguments: {'user_query_span': 'Who won the most recent PGA?'}
36
+ Response: No relevant function for your request was found. We will stop here.
37
+
38
+ Turn 2
39
+ ----------------------------------------
40
+ Conversation Complete
41
+ """
42
+
43
+ @dataclass
44
+ class WeatherConfig:
45
+ """Configuration for OpenAI and API settings"""
46
+ api_key: str = "" # FILL IN WITH YOUR VLLM_ENDPOINT_KEY
47
+ api_base: str = "" # FILL IN WITH YOUR VLLM_ENDPOINT
48
+ model: Optional[str] = None
49
+ max_turns: int = 5
50
+
51
+ class WeatherTools:
52
+ """Collection of available tools/functions for the weather agent"""
53
+
54
+ @staticmethod
55
+ def get_current_weather(latitude: List[float], longitude: List[float], unit: str) -> str:
56
+ """Get weather for given coordinates"""
57
+ # We are mocking the weather here, but in the real world, you will submit a request here.
58
+ return f"The weather is 85 degrees {unit}. It is partly cloudy, with highs in the 90's."
59
+
60
+ @staticmethod
61
+ def get_geo_coordinates(city: str, state: str) -> str:
62
+ """Get coordinates for a given city"""
63
+ coordinates = {
64
+ "Dallas": {"TX": (32.7767, -96.7970)},
65
+ "San Francisco": {"CA": (37.7749, -122.4194)},
66
+ "Paris": {"TX": (33.6609, 95.5555)}
67
+ }
68
+ lat, lon = coordinates.get(city, {}).get(state, (0, 0))
69
+ # We are mocking the weather here, but in the real world, you will submit a request here.
70
+ return f"The coordinates for {city}, {state} are: latitude {lat}, longitude {lon}"
71
+
72
+ @staticmethod
73
+ def no_relevant_function(user_query_span : str) -> str:
74
+ return "No relevant function for your request was found. We will stop here."
75
+
76
+ class ToolRegistry:
77
+ """Registry of available tools and their schemas"""
78
+
79
+ @property
80
+ def available_functions(self) -> Dict[str, callable]:
81
+ return {
82
+ "get_current_weather": WeatherTools.get_current_weather,
83
+ "get_geo_coordinates": WeatherTools.get_geo_coordinates,
84
+ "no_relevant_function" : WeatherTools.no_relevant_function,
85
+ }
86
+
87
+ @property
88
+ def tool_schemas(self) -> List[Dict[str, Any]]:
89
+ return [
90
+ {
91
+ "type": "function",
92
+ "function": {
93
+ "name": "get_current_weather",
94
+ "description": "Get the current weather in a given location. Use exact coordinates.",
95
+ "parameters": {
96
+ "type": "object",
97
+ "properties": {
98
+ "latitude": {"type": "array", "description": "The latitude for the city."},
99
+ "longitude": {"type": "array", "description": "The longitude for the city."},
100
+ "unit": {
101
+ "type": "string",
102
+ "description": "The unit to fetch the temperature in",
103
+ "enum": ["celsius", "fahrenheit"]
104
+ }
105
+ },
106
+ "required": ["latitude", "longitude", "unit"]
107
+ }
108
+ }
109
+ },
110
+ {
111
+ "type": "function",
112
+ "function": {
113
+ "name": "get_geo_coordinates",
114
+ "description": "Get the latitude and longitude for a given city",
115
+ "parameters": {
116
+ "type": "object",
117
+ "properties": {
118
+ "city": {"type": "string", "description": "The city to find coordinates for"},
119
+ "state": {"type": "string", "description": "The two-letter state abbreviation"}
120
+ },
121
+ "required": ["city", "state"]
122
+ }
123
+ }
124
+ },
125
+ {
126
+ "type": "function",
127
+ "function" : {
128
+ "name": "no_relevant_function",
129
+ "description": "Call this when no other provided function can be called to answer the user query.",
130
+ "parameters": {
131
+ "type": "object",
132
+ "properties": {
133
+ "user_query_span": {
134
+ "type": "string",
135
+ "description": "The part of the user_query that cannot be answered by any other function calls."
136
+ }
137
+ },
138
+ "required": ["user_query_span"]
139
+ }
140
+ }
141
+ }
142
+ ]
143
+
144
+ class WeatherAgent:
145
+ """Main agent class that handles the conversation and tool execution"""
146
+
147
+ def __init__(self, config: WeatherConfig):
148
+ self.config = config
149
+ self.client = OpenAI(api_key=config.api_key, base_url=config.api_base)
150
+ self.tools = ToolRegistry()
151
+ self.messages = []
152
+
153
+ if not config.model:
154
+ models = self.client.models.list()
155
+ self.config.model = models.data[0].id
156
+
157
+ def _serialize_tool_call(self, tool_call) -> Dict[str, Any]:
158
+ """Convert tool call to serializable format"""
159
+ return {
160
+ "id": tool_call.id,
161
+ "type": tool_call.type,
162
+ "function": {
163
+ "name": tool_call.function.name,
164
+ "arguments": tool_call.function.arguments
165
+ }
166
+ }
167
+
168
+ def process_tool_calls(self, message) -> None:
169
+ """Process and execute tool calls from assistant"""
170
+ for tool_call in message.tool_calls:
171
+ function_name = tool_call.function.name
172
+ function_args = json.loads(tool_call.function.arguments)
173
+
174
+ print(f"\nExecuting: {function_name}")
175
+ print(f"Arguments: {function_args}")
176
+
177
+ function_response = self.tools.available_functions[function_name](**function_args)
178
+ print(f"Response: {function_response}")
179
+
180
+ self.messages.append({
181
+ "role": "tool",
182
+ "content": json.dumps(function_response),
183
+ "tool_call_id": tool_call.id,
184
+ "name": function_name
185
+ })
186
+
187
+ def run_conversation(self, initial_query: str) -> None:
188
+ """Run the main conversation loop"""
189
+ self.messages = [{"role": "user", "content": initial_query}]
190
+
191
+ print ("\n" * 5)
192
+ print ("*" * 40)
193
+ print (f"RUNNING QUERY: {initial_query}")
194
+
195
+ for turn in range(self.config.max_turns):
196
+ print(f"\nTurn {turn + 1}")
197
+ print("-" * 40)
198
+
199
+ response = self.client.chat.completions.create(
200
+ messages=self.messages,
201
+ model=self.config.model,
202
+ tools=self.tools.tool_schemas,
203
+ temperature=0.0,
204
+ )
205
+
206
+ message = response.choices[0].message
207
+
208
+ if not message.tool_calls:
209
+ print("Conversation Complete")
210
+ break
211
+
212
+ self.messages.append({
213
+ "role": "assistant",
214
+ "content": json.dumps(message.content),
215
+ "tool_calls": [self._serialize_tool_call(tc) for tc in message.tool_calls]
216
+ })
217
+
218
+ self.process_tool_calls(message)
219
+
220
+ if turn >= self.config.max_turns - 1:
221
+ print("Maximum turns reached")
222
+
223
+ def main():
224
+ # Example usage
225
+ config = WeatherConfig()
226
+ agent = WeatherAgent(config)
227
+ agent.run_conversation("What's the weather for Paris, TX in fahrenheit?")
228
+
229
+ # Example OOD usage
230
+ agent.run_conversation("Who won the most recent PGA?")
231
+
232
+
233
+ if __name__ == "__main__":
234
+ main()