forked from awslabs/amazon-bedrock-agent-samples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
467 lines (439 loc) · 26.9 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
#!/usr/bin/env python
import sys
from pathlib import Path
import time
import os
import argparse
import boto3
import logging
import uuid
from textwrap import dedent
sys.path.append(str(Path(__file__).parent.parent.parent.parent))
from src.utils.bedrock_agent import Agent, SupervisorAgent
from src.utils.knowledge_base_helper import KnowledgeBasesForAmazonBedrock
kb_helper = KnowledgeBasesForAmazonBedrock()
s3_client = boto3.client('s3')
sts_client = boto3.client('sts')
logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
def upload_directory(path, bucket_name):
for root, dirs, files in os.walk(path):
for file in files:
file_to_upload = os.path.join(root, file)
dest_key = f"{path}/{file}"
print(f"uploading file {file_to_upload} to {bucket_name}")
s3_client.upload_file(file_to_upload, bucket_name, dest_key)
def main(args):
if args.clean_up == "true":
Agent.set_force_recreate_default(True)
Agent.delete_by_name("mortgages_assistant", verbose=True)
kb_helper.delete_kb("general-mortgage-kb", delete_s3_bucket=False)
return
if args.recreate_agents == "false":
Agent.set_force_recreate_default(False)
else:
Agent.set_force_recreate_default(True)
Agent.delete_by_name("mortgages_assistant", verbose=True)
# kb_helper.delete_kb("general-mortgage-kb", delete_s3_bucket=False)
bucket_name = None
print("creating general KB")
kb_name = "general-mortgage-kb"
kb_id, ds_id = kb_helper.create_or_retrieve_knowledge_base(
kb_name,
kb_description="Useful for answering questions about mortgage refinancing and for questions comparing various mortgage types",
data_bucket_name=bucket_name
)
bucket_name = kb_helper.data_bucket_name
print(f"KB name: {kb_name}, kb_id: {kb_id}, ds_id: {ds_id}, s3 bucket name: {bucket_name}\n")
if args.recreate_agents == "true":
print("uploading dir")
upload_directory("mortgage_dataset", f"{bucket_name}")
# ensure that the kb is available
time.sleep(30)
# sync knowledge base
kb_helper.synchronize_data(kb_id, ds_id)
print('KB sync completed\n')
if args.agent_greeting == "true":
general_mortgage_questions = Agent.create(
name="general_mortgage_questions",
role="General Mortgage Questions",
goal="Handle conversations about general mortgage questions, like high level concepts of refinincing or tradeoffs of 15-year vs 30-year terms.",
instructions=dedent("""
You are a mortgage bot, and can answer questions about mortgage refinancing and tradeoffs of mortgage types. Greet the customer first. Respons to the greeting by another greeting """),
kb_id=kb_id,
kb_descr=dedent("""
Use this knowledge base to answer general questions about mortgages, like how to refinnance,
or the difference between 15-year and 30-year mortgages."""),
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0"
)
existing_mortgage_assistant = Agent.create(
name="existing_mortgage_assistant",
role="Existing Mortgage Assistant",
goal="Handle conversations about existing mortgage accounts.",
instructions=dedent("""
You are a mortgage bot,you greet the customer first and then you can retrieve the latest details about an existing mortgage on behalf of customers.
When starting a new session, give them a friendly greeting using their preferred name
if you already have it.
never ask the user for information that you already can retrieve yourself through
available actions. for example, you have actions to retrieve details about the
existing mortgage (interest rate, balance, number of payments,
mortgage maturity date, last payment date, next payment date, etc.).
do not engage with users about topics other than an existing mortgage and greetings.
leave those other topics for other experts to handle.
for example, do not respond to general questions about mortgages. However, respond to the greeting by another greeting
"""),
tool_code="existing_mortgage_function.py",
tool_defs=[
{
"name": "get_mortgage_status",
"description": dedent("""
Retrieves the mortgage status for a given customer ID. Returns an object containing
details like the account number,
outstanding principal, interest rate, maturity date, number of payments remaining, due date of next payment,
and amount of next payment. If customer_id is not passed, function implementation
can retrieve it from session state instead."""),
"parameters": {
"customer_id": {
"description": "[optional] The unique identifier for the customer whose mortgage status is being requested.",
"type": "string",
"required": False
}
}
}
],
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0"
)
mortgage_application_agent = Agent.create(
name="mortgage_application_agent",
role="Mortgage Application Agent",
goal="Handle conversations about applications for new mortgages.",
instructions="""
you are a mortgage bot for creating, managing, and completing an application for a new mortgage. you greet the customer before your answer.
you are also great at calculating mortgage payments using your built-in code interpreter to make
accurate calculations. You never try to do those calculations on your own, instead your code
interpreter is there to generate the code to do the calculations.
you can help customers know what documentation they have already provided and which ones they still need to provide.
never make up information that you are unable to retrieve from your available actions.
do not engage with users about topics other than an existing mortgage. leave those other topics for
other experts to handle. for example, do not respond to general questions about mortgages. However, respond to the greeting by another greeting
""",
tool_code="mortgage_application_function.py",
tool_defs=[
{
"name": "get_mortgage_app_doc_status",
"description": """
Retrieves the list of required documents for a mortgage application in process,
along with their respective statuses (COMPLETED or MISSING).
The function takes a customer ID, but it is purely optional. The funciton
implementation can retrieve it from session state instead.
This function returns a list of objects, where each object represents
a required document type.
The required document types for a mortgage application are: proof of income, employment information,
proof of assets, and credit information. Each object in the returned list contains the type of the
required document and its corresponding status. """,
"parameters": {
"customer_id": {
"description": """
The unique identifier of the customer whose mortgage application document status is to be retrieved.""",
"type": "string",
"required": False
}
}
},
{
"name": "get_application_details",
"description": """
Retrieves the details about an application for a new mortgage.
The function takes a customer ID, but it is purely optional. The funciton
implementation can retrieve it from session state instead. Details include
the application ID, application date, application status, application type,
application amount, application tentative rate, and application term in years. """,
"parameters": {
"customer_id": {
"description": """
The unique identifier of the customer whose mortgage application details is to be retrieved.""",
"type": "string",
"required": False
}
}
},
{
"name": "get_mortgage_rate_history",
"description": """
Retrieves the history of mortgage interest rates going back a given number of days, defaults to 30.
History is returned as a list of objects, where each object contains the date and the interest rate to 2 decimal places. """,
"parameters": {
"day_count": {
"description": "The number of days of interest rate history, defaults to 30. Use 1 for latest rate.",
"type": "string",
"required": True
},
"type": {
"description": "The type of mortgage, defaults to '30-year-fixed'. Can also be '15-year-fixed'",
"type": "string",
"required": False
}
}
}
],
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
code_interpreter=True, # lets us do mortgage calcs accurately
verbose=False
)
mortgage_greeting_agent = Agent.create(
name="mortgage_greeting_agent",
role="Mortgage Greeting Agent",
goal="Handle the start of the conversation by greeting customers.",
instructions="""
you are a mortgage bot for greeting customer at the beginning of the chat. Reply back to the customers first message by greetings in the below XML tags
<greetings>
Hello!
Hey!
Good morning!
Good Afternoon!
Good evening!
</greetings>
<greeting_instructions>
<instruction_1>
Make sure the greeting matches the time of the day
</instruction_1>
<instruction_2>
Use the greeting followed by a simple question such as "How can I help you today>"
</instruction_2>
</greeting_instructions>
""",
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
code_interpreter=True, # lets us do mortgage calcs accurately
verbose=False
)
mortgages_assistant = SupervisorAgent.create("mortgages_assistant",
role="Mortgages Assistant",
goal="Provide a unified conversational experience for all things related to mortgages.",
collaboration_type="SUPERVISOR_ROUTER",
instructions=dedent(f"""
Act as a helpful mortgages assistant, allowing seamless conversations across a few
different domains: current mortgages, new mortgage applications, and general mortgage knowledge.
For general mortgage knowledge, you use the {kb_name} knowledge base.
If asked for a complicated calculation, use your code interpreter to be sure it's done accurately."""),
collaborator_agents=[
{
"agent": "existing_mortgage_assistant",
"instructions": dedent("""
Do not pick this collaborator for general mortgage knowledge like guidance about refinancing,
or tradeoffs between mortgage types. instead use the general-mortgage-kb knowledge base for those.
Use this collaborator for discussing existing mortgages."""),
},
{
"agent": "mortgage_application_agent",
"instructions": dedent("""
Do not pick this collaborator for general mortgage knowledge like guidance about refinancing,
or tradeoffs between mortgage types. instead use the general-mortgage-kb knowledge base for those.
Do use this collaborator for discussing the application process for new mortgages
and for getting the most recent interest rates available for new mortgages."""),
},
{
"agent": "mortgage_greeting_agent",
"instructions": dedent("""
Use this collaborator for greeting customers at the start of the conversation."""),
},
{
"agent": "general_mortgage_questions",
"instructions": """
Use this collaborator for discussing general mortgage questions."""
}
],
collaborator_objects=[mortgage_application_agent,
existing_mortgage_assistant,
general_mortgage_questions,
mortgage_greeting_agent],
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
verbose=False)
else:
general_mortgage_questions = Agent.create(
name="general_mortgage_questions",
role="General Mortgage Questions",
goal="Handle conversations about general mortgage questions, like high level concepts of refinincing or tradeoffs of 15-year vs 30-year terms.",
instructions=dedent("""
You are a mortgage bot, and can answer questions about mortgage refinancing and tradeoffs of mortgage types. Greet the customer first. Respons to the greeting by another greeting """),
kb_id=kb_id,
kb_descr=dedent("""
Use this knowledge base to answer general questions about mortgages, like how to refinnance,
or the difference between 15-year and 30-year mortgages."""),
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0"
)
existing_mortgage_assistant = Agent.create(
name="existing_mortgage_assistant",
role="Existing Mortgage Assistant",
goal="Handle conversations about existing mortgage accounts.",
instructions=dedent("""
You are a mortgage bot,you greet the customer first and then you can retrieve the latest details about an existing mortgage on behalf of customers.
When starting a new session, give them a friendly greeting using their preferred name
if you already have it.
never ask the user for information that you already can retrieve yourself through
available actions. for example, you have actions to retrieve details about the
existing mortgage (interest rate, balance, number of payments,
mortgage maturity date, last payment date, next payment date, etc.).
do not engage with users about topics other than an existing mortgage and greetings.
leave those other topics for other experts to handle.
for example, do not respond to general questions about mortgages. However, respond to the greeting by another greeting
"""),
tool_code="existing_mortgage_function.py",
tool_defs=[
{
"name": "get_mortgage_status",
"description": dedent("""
Retrieves the mortgage status for a given customer ID. Returns an object containing
details like the account number,
outstanding principal, interest rate, maturity date, number of payments remaining, due date of next payment,
and amount of next payment. If customer_id is not passed, function implementation
can retrieve it from session state instead."""),
"parameters": {
"customer_id": {
"description": "[optional] The unique identifier for the customer whose mortgage status is being requested.",
"type": "string",
"required": False
}
}
}
],
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0"
)
mortgage_application_agent = Agent.create(
name="mortgage_application_agent",
role="Mortgage Application Agent",
goal="Handle conversations about applications for new mortgages.",
instructions="""
you are a mortgage bot for creating, managing, and completing an application for a new mortgage. you greet the customer before your answer.
you are also great at calculating mortgage payments using your built-in code interpreter to make
accurate calculations. You never try to do those calculations on your own, instead your code
interpreter is there to generate the code to do the calculations.
you can help customers know what documentation they have already provided and which ones they still need to provide.
never make up information that you are unable to retrieve from your available actions.
do not engage with users about topics other than an existing mortgage. leave those other topics for
other experts to handle. for example, do not respond to general questions about mortgages. However, respond to the greeting by another greeting
""",
tool_code="mortgage_application_function.py",
tool_defs=[
{
"name": "get_mortgage_app_doc_status",
"description": """
Retrieves the list of required documents for a mortgage application in process,
along with their respective statuses (COMPLETED or MISSING).
The function takes a customer ID, but it is purely optional. The funciton
implementation can retrieve it from session state instead.
This function returns a list of objects, where each object represents
a required document type.
The required document types for a mortgage application are: proof of income, employment information,
proof of assets, and credit information. Each object in the returned list contains the type of the
required document and its corresponding status. """,
"parameters": {
"customer_id": {
"description": """
The unique identifier of the customer whose mortgage application document status is to be retrieved.""",
"type": "string",
"required": False
}
}
},
{
"name": "get_application_details",
"description": """
Retrieves the details about an application for a new mortgage.
The function takes a customer ID, but it is purely optional. The funciton
implementation can retrieve it from session state instead. Details include
the application ID, application date, application status, application type,
application amount, application tentative rate, and application term in years. """,
"parameters": {
"customer_id": {
"description": """
The unique identifier of the customer whose mortgage application details is to be retrieved.""",
"type": "string",
"required": False
}
}
},
{
"name": "get_mortgage_rate_history",
"description": """
Retrieves the history of mortgage interest rates going back a given number of days, defaults to 30.
History is returned as a list of objects, where each object contains the date and the interest rate to 2 decimal places. """,
"parameters": {
"day_count": {
"description": "The number of days of interest rate history, defaults to 30. Use 1 for latest rate.",
"type": "string",
"required": True
},
"type": {
"description": "The type of mortgage, defaults to '30-year-fixed'. Can also be '15-year-fixed'",
"type": "string",
"required": False
}
}
}
],
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
code_interpreter=True, # lets us do mortgage calcs accurately
verbose=False
)
mortgages_assistant = SupervisorAgent.create("mortgages_assistant",
role="Mortgages Assistant",
goal="Provide a unified conversational experience for all things related to mortgages.",
collaboration_type="SUPERVISOR_ROUTER",
instructions=dedent(f"""
Act as a helpful mortgages assistant, allowing seamless conversations across a few
different domains: current mortgages, new mortgage applications, and general mortgage knowledge.
For general mortgage knowledge, you use the {kb_name} knowledge base.
If asked for a complicated calculation, use your code interpreter to be sure it's done accurately."""),
collaborator_agents=[
{
"agent": "existing_mortgage_assistant",
"instructions": dedent("""
Do not pick this collaborator for general mortgage knowledge like guidance about refinancing,
or tradeoffs between mortgage types. instead use the general-mortgage-kb knowledge base for those.
Use this collaborator for discussing existing mortgages."""),
},
{
"agent": "mortgage_application_agent",
"instructions": dedent("""
Do not pick this collaborator for general mortgage knowledge like guidance about refinancing,
or tradeoffs between mortgage types. instead use the general-mortgage-kb knowledge base for those.
Do use this collaborator for discussing the application process for new mortgages
and for getting the most recent interest rates available for new mortgages."""),
},
{
"agent": "general_mortgage_questions",
"instructions": """
Use this collaborator for discussing general mortgage questions."""
}
],
collaborator_objects=[mortgage_application_agent,
existing_mortgage_assistant,
general_mortgage_questions],
llm="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
verbose=False)
if args.recreate_agents == "false":
print("\n\nInvoking supervisor agent...\n\n")
session_id = str(uuid.uuid4())
requests = ["when’s my next payment due?",
"what’s my balance after that payment, and what rate am I paying?",
"why do so many people choose a 30-year mortgage??",
"did you receive my employment verification doc yet? i sent it last week",
"i’m getting ready to lock in on a rate. what have the rates looked like in last couple weeks?",
# "great. if i use the highest of those rates for $500K for 15 years, what’s my payment?"
]
for request in requests:
print(f"\n\nRequest: {request}\n\n")
result = mortgages_assistant.invoke(request, session_id=session_id,
enable_trace=True, trace_level=args.trace_level)
print(result)
if __name__ == '__main__':
print("in main")
parser = argparse.ArgumentParser()
parser.add_argument("--agent_greeting", required=False, default=False, help="False does NOT create greeting Agent")
parser.add_argument("--recreate_agents", required=False, default=True, help="False if reusing existing agents.")
parser.add_argument("--clean_up", required=False, default=False, help="True if cleaning up agents resources.")
parser.add_argument("--trace_level", required=False, default="core",
help="The level of trace, 'core', 'outline', 'all'.")
args = parser.parse_args()
main(args)