AI Agent

Translated from the Spanish original. Read in Spanish

In this tutorial we’ll learn how to build an Artificial Intelligence (AI) Agent that can answer questions using Active Directory and a Knowledge Base (KB). We’ll use LangChain and Azure for this.

iStock AI Generator

Agents

The core idea of agents is to use a language model to choose a sequence of actions to take. In chains, the sequence of actions is predefined (in code). In agents, a language model is used as a reasoning engine to decide which actions to take and in what order.

Setting Up the Environment

Before we start, we need to set some environment variables and get an Azure access token. To do this, put a .env file in the same directory with the following information:

AZURE_TENANT_ID = "00000000-0000-0000-0000-000000000000"
AZURE_CLIENT_ID = "00000000-0000-0000-0000-000000000000"
AZURE_CLIENT_SECRET = "xxxxx"

Once we have the .env file, we’ll add the code needed to get the token.

import os
from azure.identity import ChainedTokenCredential, EnvironmentCredential
from dotenv import load_dotenv
load_dotenv()

credential = ChainedTokenCredential(EnvironmentCredential())
access_token = credential.get_token("https://cognitiveservices.azure.com/.default")

Configuring the Model and Environment Variables

Next, we’ll configure the Azure OpenAI model and set the required environment variables.

os.environ["AZURE_OPENAI_ENDPOINT"] = "https://zerogap.openai.azure.com/"
os.environ["AZURE_OPENAI_API_KEY"] = access_token.token
os.environ["OPENAI_API_TYPE"] = "azure_ad"
os.environ["OPENAI_DEPLOYMENT"] = "zerogap-openai-ue2-gpt4-turbo"

Initialising the AI Tools

We’ll initialise the Azure OpenAI chat model, the AzureOpenAIEmbeddings class and the embeddings model.

from langchain.chat_models import AzureChatOpenAI
from langchain.embeddings import AzureOpenAIEmbeddings

llm = AzureChatOpenAI(openai_api_version="2023-07-01-preview", azure_deployment="zerogap-openai-ue2-gpt4-turbo", temperature=0.5)

embeddings = AzureOpenAIEmbeddings(
    azure_deployment="zerogap-openai-ue2-ada",
    openai_api_version="2023-07-01-preview",
    chunk_size=1000
)

Setting Up the Vector DB and Retriever

We’ll load documents from the persistent directory, assuming you already have the KB loaded into a vector database (more information here: QA AI Bot using a local LLM and documents – The Zero Gap Zone).

from langchain.vectorstores import Chroma

persist_directory = "chroma_db_generic"
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embeddings)
vectordb.get()

retriever = vectordb.as_retriever(search_type="similarity", search_kwargs={"k": 5})

Tools for Working with Active Directory and the Knowledge Base

Create tools to interact with Active Directory and get information from the Knowledge Base.

import subprocess
from langchain.tools import Tool

def get_ad_user(search_query):
    ps_command = f'get-aduser -Filter {{Name -like "*{search_query}*"}} -Properties Office, OfficePhone | Select-Object Name, Office, OfficePhone'
    result = subprocess.run(["powershell", ps_command], capture_output=True, text=True)
    return result.stdout

run_ad_tool = Tool.from_function(
    name="get_ad_user",
    description="Get user information from Active Directory",
    func=get_ad_user
)

def get_kb(question):
    context = retriever.invoke(question)
    formated_context = format_docs(context)
    return formated_context

run_kb_tool = Tool.from_function(
    name="get_kb",
    description="Get information from the Knowledge Base",
    func=get_kb
)

tools = [run_ad_tool, run_kb_tool]

Creating and Running the AI Agent

We’ll define a prompt template and the function that runs the agent.

from langchain.agents import AgentExecutor, create_react_agent
from langchain.prompts import PromptTemplate

react_prompt = PromptTemplate.from_template("""
You are an assistant for question-answering tasks. Follow these instructions step by step:

1. If the question is about a person, try to get more information from Active Directory.
2. If the question is not about a person, try to get more information from your Knowledge Base
3. If you can not find the answer, respond with 'Sorry, I do not know'

These are examples:

Example 1:
Question: Who is John Doe?
Thought: The question is about a person, I should use the Active Directory tool.
Action: get_ad_user
Action Input: John Doe
Observation: The get_ad_user tool indicates John Doe is an Actor in Friends.
Thought: I now have the final answer.
Final Answer: John Doe is an Actor in the TV Show Friends.

Example 2:
Question: What is a transistor?
Thought: The question is not about a person, I need to use the Knowledge Base tool.
Action: get_kb
Action Input: What is a transistor?
Observation: A transistor is a semiconductor device used to amplify or switch electrical signals and power. It is one of the basic building blocks of modern electronics.
Thought: I now have the final answer.
Final Answer: A transistor is a semiconductor device used to amplify or switch electrical signals and power. It is one of the basic building blocks of modern electronics

You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin!

Question: {input}
Thought:{agent_scratchpad}
""")

def run_agent(question):
    agent = create_react_agent(
        llm=llm,
        prompt=react_prompt,
        tools=tools
    )
    agent_executor = AgentExecutor(
        agent=agent,
        verbose=True,
        tools=tools
    )

    response = agent_executor.invoke({"input": question})

    return response

Interacting with the AI Agent

Finally, we’ll create a loop to interact with the AI Agent and get answers to our questions.

print("\033[92m" + "Welcome to the ZEROGAP AI QA Bot!" + "\033[0m")
print("\033[92m" + "###############################" + "\033[0m")
print("\033[92m" + "###############################" + "\033[0m")
print("\n")
while True:
    question = input("\033[93m" + "You: " + "\033[0m")
    print("\n")
    if question == "quit":
        break
    result = run_agent(question)
    print("\033[92m" + result + "\033[0m")
    print("\n")

Complete Code

Here is the complete code for the AI Agent we built in this tutorial:

import os, subprocess
from azure.identity import ChainedTokenCredential, EnvironmentCredential
from langchain.vectorstores import Chroma
from langchain.embeddings import AzureOpenAIEmbeddings
from langchain.chat_models import AzureChatOpenAI
from langchain.tools import Tool
from langchain.agents import AgentExecutor, create_react_agent
from langchain.prompts import PromptTemplate
from dotenv import load_dotenv
load_dotenv()

# Place a .env file within the same folder with the following information:
# AZURE_TENANT_ID = "00000000-0000-0000-0000-000000000000"
# AZURE_CLIENT_ID = "00000000-0000-0000-0000-000000000000"
# AZURE_CLIENT_SECRET = "xxxxx"

credential = ChainedTokenCredential(EnvironmentCredential())
access_token = credential.get_token("https://cognitiveservices.azure.com/.default")

# Model
deployment = "zerogap-openai-ue2-gpt4-turbo"
# Model text-embedding-ada-002
embedding_deployment = "zerogap-openai-ue2-ada"

# Set OS environment variables
os.environ["AZURE_OPENAI_ENDPOINT"] = "https://zerogap.openai.azure.com/"
os.environ["AZURE_OPENAI_API_KEY"] = access_token.token
os.environ["OPENAI_API_TYPE"] = "azure_ad"
os.environ["OPENAI_DEPLOYMENT"] = deployment

llm = AzureChatOpenAI(openai_api_version="2023-07-01-preview", azure_deployment=deployment, temperature=0.5)

# Initialize the OpenAIEmbeddings class
embeddings = AzureOpenAIEmbeddings(
    azure_deployment=embedding_deployment,
    openai_api_version="2023-07-01-preview",
    chunk_size=1000
)

# Load documents from the persisted directory
# Assuming you already have the KB loaded to a vector database
persist_directory = "chroma_db_generic"
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embeddings)
vectordb.get()

retriever = vectordb.as_retriever(search_type="similarity", search_kwargs={"k": 5})

# Join all the documents from the retriever together with newlines
def format_docs(docs):
    if docs:
        return "\n\n".join(doc.page_content for doc in docs)

# Function to get AD user
def get_ad_user(search_query):
    # Run the PowerShell command to retrieve user information including the specified attributes
    ps_command = f'get-aduser -Filter {{Name -like "*{search_query}*"}} -Properties Office, OfficePhone | Select-Object Name, Office, OfficePhone'
    result = subprocess.run(["powershell", ps_command], capture_output=True, text=True)
    # Return the output
    return result.stdout

run_ad_tool = Tool.from_function(
    name="get_ad_user",
    description="Get user information from Active Directory",
    func=get_ad_user
)

def get_kb(question):
    # Queries the Vector DB using user's question
    context = retriever.invoke(question)
    formated_context = format_docs(context)
    return formated_context

run_kb_tool = Tool.from_funcion(
    name="get_kb",
    description="Get information from the Knowledge Base",
    func=get_kb
)

tools = [run_ad_tool,run_kb_tool]

tool_names = [tool.name for tool in tools]

react_prompt = PromptTemplate.from_template("""
You are an assistant for question-answering tasks. Follow these instructions step by step:

1. If the question is about a person, try to get more information from Active Directory.
2. If the question is not about a person, try to get more information from your Knowledge Base
3. If you can not find the answer, respond with 'Sorry, I do not know'

These are examples:

Example 1:
Question: Who is John Doe?
Thought: The question is about a person, I should use the Active Directory tool.
Action: get_ad_user
Action Input: John Doe
Observation: The get_ad_user tool indicates John Doe is an Actor in Friends.
Thought: I now have the final answer.
Final Answer: John Doe is an Actor in the TV Show Friends.

Example 2:
Question: What is a transistor?
Thought: The question is not about a person, I need to use the Knowledge Base tool.
Action: get_kb
Action Input: What is a transistor?
Observation: A transistor is a semiconductor device used to amplify or switch electrical signals and power. It is one of the basic building blocks of modern electronics.
Thought: I now have the final answer.
Final Answer: A transistor is a semiconductor device used to amplify or switch electrical signals and power. It is one of the basic building blocks of modern electronics

You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin!

Question: {input}
Thought:{agent_scratchpad}
""")

def run_agent(question):
    agent = create_react_agent(
        llm=llm,
        prompt=react_prompt,
        tools=tools
    )
    agent_executor = AgentExecutor(
        agent=agent,
        verbose=True,
        tools=tools
    )

    response = agent_executor.invoke({"input": question})

    return response

# print welcome message in green
print("\033[92m" + "Welcome to the ZEROGAP AI QA Bot!" + "\033[0m")
print("\033[92m" + "###############################" + "\033[0m")
print("\033[92m" + "###############################" + "\033[0m")
print("\n")
while True:
    #input in yellow
    question = input("\033[93m" + "You: " + "\033[0m")
    print("\n")
    if question == "quit":
        break
    result = run_agent(question)
    print("\033[92m" + result + "\033[0m")
    print("\n")

Maximiliano Díaz Doglia

AI Platform Engineer & Full-Stack Developer
Building Enterprise Integrations & Automations

Published in: AI