Skip to content

Commit

Permalink
new knowledge base cdk constructs (without docker)
Browse files Browse the repository at this point in the history
removed unused files
modifier tech agent (for documentation explaination)
code cleanup
removed unused files for KB
  • Loading branch information
brnaba-aws committed Oct 22, 2024
1 parent 807f661 commit 11ea8bf
Show file tree
Hide file tree
Showing 16 changed files with 1,846 additions and 113 deletions.
2 changes: 0 additions & 2 deletions docs/src/content/docs/deployment/demo-web-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,10 @@ Follow these steps to deploy the demo chat web application:
```
"context": {
"enableLexAgent": true,
"enableAmazonBedrockAgent": true,
...
```

**enableLexAgent:** Enable the sample Airlines Bot (See AWS Blogpost [here](https://aws.amazon.com/blogs/machine-learning/automate-the-customer-service-experience-for-flight-reservations-using-amazon-lex/))
**enableAmazonBedrockAgent:** Enable the sample Amazon Bedrock Agent with prefined knowledge base about restaurant's menu (See knowledge base documents [here](https://github.com/aws-east-ai/Bedrock-Claude-Deep-Dive-Workshop/tree/main/05_Agents/kb_documents))


6. **Deploy the Application**:
Expand Down
1 change: 0 additions & 1 deletion examples/chat-demo-app/cdk.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
},
"context": {
"enableLexAgent": true,
"enableAmazonBedrockAgent": true,
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
Expand Down
95 changes: 58 additions & 37 deletions examples/chat-demo-app/lambda/multi-agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import {
BedrockLLMAgent,
DynamoDbChatStorage,
LexBotAgent,
AmazonBedrockAgent,
AmazonKnowledgeBasesRetriever,
LambdaAgent,
BedrockClassifier,
Agent,
} from "multi-agent-orchestrator";
import { weatherToolDescription, weatherToolHanlder } from './weather_tool'
import { mathToolHanlder, mathAgentToolDefinition } from './math_tool';
import { APIGatewayProxyEventV2, Handler, Context } from "aws-lambda";
import { Buffer } from "buffer";
import { GREETING_AGENT_PROMPT, HEALTH_AGENT_PROMPT, MATH_AGENT_PROMPT, TECH_AGENT_PROMPT, WEATHER_AGENT_PROMPT } from "./prompts";
import { BedrockAgentRuntimeClient, SearchType } from '@aws-sdk/client-bedrock-agent-runtime';

const logger = new Logger();

Expand All @@ -37,21 +37,13 @@ interface LexAgentConfig {
localeId: string;
}

interface BedrockAgentConfig {
name: string;
description: string;
agentId: string;
agentAliasId: string;
}

interface BodyData {
query: string;
sessionId: string;
userId: string;
}

const LEX_AGENT_ENABLED = process.env.LEX_AGENT_ENABLED || "false";
const BEDROCK_AGENT_ENABLED = process.env.BEDROCK_AGENT_ENABLED || "false";

const storage = new DynamoDbChatStorage(
process.env.HISTORY_TABLE_NAME!,
Expand All @@ -76,19 +68,6 @@ const orchestrator = new MultiAgentOrchestrator({
});



const techAgent = new BedrockLLMAgent({
name: "Tech Agent",
description:
"Specializes in a wide range of technology areas, including software development, hardware, AI, cybersecurity, blockchain, cloud computing, and emerging tech innovations. Handles inquiries related to pricing, costs, and technical details of technology products and services except for the multi-agent orchestrator framework and its components.",
streaming: true,
inferenceConfig: {
temperature: 0.1,
},
});

techAgent.setSystemPrompt(TECH_AGENT_PROMPT);

const healthAgent = new BedrockLLMAgent({
name: "Health Agent",
description:
Expand Down Expand Up @@ -158,20 +137,62 @@ if (process.env.LAMBDA_AGENTS){
}
}

if (BEDROCK_AGENT_ENABLED === "true") {
const config: BedrockAgentConfig = JSON.parse(
process.env.BEDROCK_AGENT_CONFIG!
);
orchestrator.addAgent(
new AmazonBedrockAgent({
name: "Multi-Agent-Orchestrator Documentation Agent",
//description: "You specialize in the Multi-Agent Orchestrator framework, which manages multiple AI agents and handles complex conversations. You provide comprehensive support for integrating, configuring, and customizing agents within the orchestrator. You also handle queries about the framework's extensible architecture, dual language support, and deployment flexibility across various environments. Your expertise includes helping users with pre-built agents, agent creation, usage, and optimizing orchestrator workflows for different use cases",
description: "Specializes in a wide range of technology areas, including software development, hardware, AI, cybersecurity, blockchain, cloud computing, and emerging tech innovations. Handles inquiries related to pricing, costs, and technical details of technology products and services except for the multi-agent orchestrator framework and its components.",
agentId: config.agentId,
agentAliasId: config.agentAliasId,
})
);
}
// Add a our Multi-agent orchestrator documentation agent
const maoDocAgent = new BedrockLLMAgent({
name: "Tech agent",
description:
"A tech expert specializing in the multi-agent orchestrator framework, technical domains, and AI-driven solutions.",
streaming: true,
inferenceConfig: {
temperature: 0.0,
},
toolConfig: {
useToolHandler: mathToolHanlder,
tool: mathAgentToolDefinition,
toolMaxRecursions: 5,
},
customSystemPrompt:{
template:`
You are a tech expert specializing in both the technical domain, including software development, AI, cloud computing, and the multi-agent orchestrator framework. Your role is to provide comprehensive, accurate, and helpful information about these areas, with a specific focus on the orchestrator framework, its agents, and their applications. Always structure your responses using clear, well-formatted markdown.
Key responsibilities:
- Explain the multi-agent orchestrator framework, its agents, and its benefits
- Guide users on how to get started with the framework and configure agents
- Provide technical advice on topics like software development, AI, and cloud computing
- Detail the process of creating and configuring an orchestrator
- Describe the various components and elements of the framework
- Provide examples and best practices for technical implementation
When responding to queries:
1. Start with a brief overview of the topic
2. Break down complex concepts into clear, digestible sections
3. **When the user asks for an example or code, always respond with a code snippet, using proper markdown syntax for code blocks (\`\`\`).** Provide explanations alongside the code when necessary.
4. Conclude with next steps or additional resources if relevant
Always use proper markdown syntax, including:
- Headings (##, ###) for main sections and subsections
- Bullet points (-) or numbered lists (1., 2., etc.) for enumerating items
- Code blocks (\`\`\`) for code snippets or configuration examples
- Bold (**text**) for emphasizing key terms or important points
- Italic (*text*) for subtle emphasis or introducing new terms
- Links ([text](URL)) when referring to external resources or documentation
Tailor your responses to both beginners and experienced developers, providing clear explanations and technical depth as appropriate.`
},
retriever: new AmazonKnowledgeBasesRetriever(
new BedrockAgentRuntimeClient(),
{
knowledgeBaseId: process.env.KNOWLEDGE_BASE_ID,
retrievalConfiguration: {
vectorSearchConfiguration: {
numberOfResults: 10,
overrideSearchType: SearchType.HYBRID,
},
},
}
)
});
orchestrator.addAgent(maoDocAgent);

//orchestrator.addAgent(techAgent);
orchestrator.addAgent(healthAgent);
Expand Down
147 changes: 147 additions & 0 deletions examples/chat-demo-app/lib/CustomResourcesLambda/aoss-index-create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { defaultProvider } from '@aws-sdk/credential-provider-node';
import { Client } from '@opensearch-project/opensearch';
import { AwsSigv4Signer } from '@opensearch-project/opensearch/aws';
import { OnEventRequest, OnEventResponse } from 'aws-cdk-lib/custom-resources/lib/provider-framework/types';
import { retryAsync } from 'ts-retry';
import { Logger } from '@aws-lambda-powertools/logger';
const logger = new Logger({
serviceName: 'BedrockAgentsBlueprints',
logLevel: "INFO"
});

const CLIENT_TIMEOUT_MS = 1000;
const CLIENT_MAX_RETRIES = 5;
const CREATE_INDEX_RETRY_CONFIG = {
delay: 30000, // 30 sec
maxTry: 20, // Should wait at least 10 mins for the permissions to propagate
};

// TODO: make an embedding to config map to support more models
// Dafault config for titan embedding v2. Derived from https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html
const DEFAULT_INDEX_CONFIG = {
mappings: {
properties: {
id: {
type: 'text',
fields: {
keyword: {
type: 'keyword',
ignore_above: 256,
},
},
},
AMAZON_BEDROCK_METADATA: {
type: 'text',
index: false,
},
AMAZON_BEDROCK_TEXT_CHUNK: {
type: 'text',
},
'bedrock-knowledge-base-default-vector': {
type: 'knn_vector',
dimension: 1536,
method: {
engine: 'faiss',
space_type: 'l2',
name: 'hnsw',
},
},
},
},
settings: {
index: {
number_of_shards: 2,
'knn.algo_param': {
ef_search: 512,
},
knn: true,
},
},
};

/**
* OnEvent is called to create/update/delete the custom resource.
*
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requests.html
*
* @param event request object containing event type and request variables. This contains 3
* params: indexName(Required), collectionEndpoint(Required), indexConfiguration(Optional)
* @param _context Lambda context
*
* @returns reponse object containing the physical resource ID of the indexName.
*/
export const onEvent = async (event: OnEventRequest, _context: unknown): Promise<OnEventResponse> => {
const { indexName, collectionEndpoint, indexConfiguration } = event.ResourceProperties;

try {
logger.info("Initiating custom resource for index operations");
const signerResponse = AwsSigv4Signer({
region: process.env.AWS_REGION!,
service: 'aoss',
getCredentials: defaultProvider(),
});

const openSearchClient = new Client({
...signerResponse,
maxRetries: CLIENT_MAX_RETRIES,
node: collectionEndpoint,
requestTimeout: CLIENT_TIMEOUT_MS,
});

logger.info("AOSS client creation successful");

if (event.RequestType == 'Create') {
return await createIndex(openSearchClient, indexName, indexConfiguration);
} else if (event.RequestType == 'Update') {
return await updateIndex(openSearchClient, indexName, indexConfiguration);
} else if (event.RequestType == 'Delete') {
return await deleteIndex(openSearchClient, indexName);
} else {
throw new Error(`Unsupported request type: ${event.RequestType}`);
}
} catch (error) {
logger.error((error as Error).toString());
throw new Error(`Custom aoss-index operation failed: ${error}`);
}
};

const createIndex = async (openSearchClient: Client, indexName: string, indexConfig?: any): Promise<OnEventResponse> => {
logger.info("AOSS index creation started");

// Create index based on default or user provided config.
const indexConfiguration = indexConfig ?? DEFAULT_INDEX_CONFIG;

// Retry index creation to allow data policy to propagate.
await retryAsync(
async () => {
await openSearchClient.indices.create({
index: indexName,
body: indexConfiguration,
});
logger.info('Successfully created index!');
},
CREATE_INDEX_RETRY_CONFIG,
);

return {
PhysicalResourceId: `osindex_${indexName}`,
};
};

const deleteIndex = async (openSearchClient: Client, indexName: string): Promise<OnEventResponse> => {
logger.info("AOSS index deletion started");
await openSearchClient.indices.delete({
index: indexName,
});

return {
PhysicalResourceId: `osindex_${indexName}`,
};
};

const updateIndex = async (openSearchClient: Client, indexName: string, indexConfig?: any): Promise<OnEventResponse> => {
logger.info("AOSS index update started");
// OpenSearch doesn't have an update index function. Hence, delete and create index
await deleteIndex(openSearchClient, indexName);
return await createIndex(openSearchClient, indexName, indexConfig);
};
Loading

0 comments on commit 11ea8bf

Please sign in to comment.