AI for DevOps Engineers - Part 3: Infrastructure, Operations, Security, and Agents
In the previous parts (part one and part two) of this blog series, we explored the challenges facing DevOps today, how AI can address them, and how to build
In the first part of our blog series, we explored the different challenges of DevOps and how AI can address them. We also introduced the fundamentals of Generative AI and Large Language Models (LLMs) as transformative tools for DevOps engineers. In this second part, we’ll dive deeper into building our own AI applications using LangChain, a powerful framework designed to simplify and enhance the development of LLM-powered solutions.
Building AI applications from scratch can be complex and time-consuming. LLM Frameworks provide tools and interfaces that simplify the integration of Large Language Models into applications:
LangChain is an open-source framework designed to simplify working with LLMs. It stands out for its ability to handle agentic task workflows, which allows for autonomous task execution by chaining multiple LLM interactions. This makes it ideal for creating applications with complex workflows, such as:
LangChain’s modular design features several key components that work together to build cool AI applications:
Let’s now explore how LangChain can be used to build AI applications through some practical examples. Note that we're using the programming language Python as it is widely used in AI development and integrates well with LangChain.
We start off easy with a simple chat application.
1from langchain.chains import ConversationChain
2from langchain.memory import ConversationBufferMemory
3from langchain_community.llms import Ollama
4
5# Initialize the LLM
6llm = Ollama(model="llama2")
7
8# Set up memory to store conversation history
9memory = ConversationBufferMemory()
10
11# Create a conversation chain
12conversation = ConversationChain(llm=llm, memory=memory)
13
14# Chat loop
15while True:
16 user_input = input("Input: ")
17 response = conversation.run(user_input)
18 print(f"AI: {response}")
Let’s break down the code:
See how LangChain simplifies the process of setting up a complete chat application with an LLM! Of course, this example is very basic as we're only chatting in the console and our model is a simple chatbot. But it shows how easy it is to get started with LangChain.
If we remember from the first part of this series, Retrieval-Augmented Generation (RAG) is a technique that combines information retrieval with language generation. LangChain can be used to implement RAG workflows:
1from langchain.document_loaders import TextLoader
2from langchain.vectorstores import Chroma
3from langchain.embeddings import OpenAIEmbeddings
4from langchain.chains import RetrievalQA
5from langchain.chat_models import ChatOpenAI
6
7# Load documents
8loader = TextLoader("example.txt")
9documents = loader.load()
10
11# Create embeddings and vector store
12embeddings = OpenAIEmbeddings()
13vector_store = Chroma.from_documents(documents, embeddings)
14
15# Set up the retriever
16retriever = vector_store.as_retriever()
17
18# Initialize the LLM
19llm = ChatOpenAI(model="gpt-3.5-turbo")
20
21# Create a RetrievalQA chain
22qa_chain = RetrievalQA(llm=llm, retriever=retriever)
23
24# Ask a question
25query = "What is the main topic of the document?"
26response = qa_chain.run(query)
27print(f"Answer: {response}")
We can see that there is a bit more going on in this example:
So we see, the rough structure of the code is similar to the chat application, but we have added more components to handle the retrieval process.
Note that when working with cloud-based models like GPT-3, we need to have an API key to access the model! You can get an API key from the respective provider.
Using LangChain and Streamlit, we can build interactive applications like chatting with PDF content.
Streamlit is an open-source Python framework designed for building interactive web applications quickly and easily. It is popular among data scientists and machine learning engineers because it allows us to create user-friendly interfaces for models and data workflows with minimal effort.
1import streamlit as st
2from langchain.document_loaders import PyPDFLoader
3from langchain.vectorstores import Chroma
4from langchain.embeddings import OpenAIEmbeddings
5from langchain.chains import ConversationalRetrievalChain
6from langchain.chat_models import ChatOpenAI
7
8# Streamlit UI
9st.title("Chat with Your PDF")
10uploaded_file = st.file_uploader("Upload a PDF", type="pdf")
11
12if uploaded_file:
13 # Load PDF content
14 loader = PyPDFLoader(uploaded_file)
15 documents = loader.load()
16
17 # Create embeddings and vector store
18 embeddings = OpenAIEmbeddings()
19 vector_store = Chroma.from_documents(documents, embeddings)
20
21 # Set up conversational retrieval chain
22 retriever = vector_store.as_retriever()
23 llm = ChatOpenAI(model="gpt-3.5-turbo")
24 conversation_chain = ConversationalRetrievalChain(llm=llm, retriever=retriever)
25
26 # Chat interface
27 if "chat_history" not in st.session_state:
28 st.session_state.chat_history = []
29
30 user_input = st.text_input("Ask a question about the PDF:")
31 if user_input:
32 response = conversation_chain.run(user_input)
33 st.session_state.chat_history.append((user_input, response))
34
35 # Display chat history
36 for user_msg, ai_msg in st.session_state.chat_history:
37 st.write(f"You: {user_msg}")
38 st.write(f"AI: {ai_msg}")
With this simple web-based Spleamlit application, users can upload a PDF, ask questions about its content, and receive context-aware responses. The LangChain components handle the PDF processing, text extraction, and LLM interactions, while Streamlit provides the user-friendly interface. The structure is again similar to the previous examples, but now we have integrated it with Streamlit to create a more interactive experience.
Building AI apps is one thing, but ensuring their quality is another. AI can be unpredictable, so we have to ensure that the application is reliable, accurate, and performs as expected in real-world scenarios. For applications powered by Large Language Models (LLMs), testing and evaluation are critical to maintaining performance or identifying issues.
In this section, we’ll explore the importance of testing in LLM applications, different testing approaches, and how tools like LangSmith can also help to simplify this process.
Testing LLM applications aims to ensure:
LLMs are probabilistic models, meaning their outputs can vary depending on the input, prompt, or context. This variability makes testing even more critical to ensure consistent and high-quality results.
Testing LLM applications incudes several approaches, each tailored to specific use cases. Next, we’ll explore some common testing methods and examples.
Evaluation metrics are important for assessing the performance of LLM applications. These metrics should align with the goals of the application or the company’s objectives. For example:
One of the simplest ways to test an LLM application is by creating test cases with clear inputs and expected outputs. This approach is ideal for tasks with deterministic answers, such as question-answering or translation.
1test_cases = [
2 {"input": "Hello, how are you?", "expected_output": "Bonjour, comment ça va?"},
3 {"input": "Goodbye", "expected_output": "Au revoir"},
4]
5
6for test in test_cases:
7 result = chain.run(text=test["input"])
8 print(f"Input: {test['input']}")
9 print(f"Expected: {test['expected_output']}")
10 print(f"Actual: {result.strip()}")
11 print(f"Pass: {result.strip() == test['expected_output']}\n")
For tasks with subjective or complex outputs (e.g., story generation, summarization), exact matches between expected and actual outputs may not be feasible. In such cases, an LLM can act as a "judge" to evaluate the quality of its own or another model’s outputs.
1# Define the prompt for generating a story
2story_prompt_template = PromptTemplate(
3 input_variables=["theme"],
4 template="Write a short story based on the following theme: {theme}."
5)
6
7# Define the prompt for evaluating the story
8evaluation_prompt_template = PromptTemplate(
9 input_variables=["story"],
10 template=(
11 "You are a judge evaluating short stories. Please rate the following story on a scale from 1 to 10 "
12 "for creativity, coherence, and grammar. Provide a brief explanation for each rating.\n\n"
13 "Story: {story}\n\n"
14 "Creativity: \nCoherence: \nGrammar: \nExplanation:"
15 )
16)
17
18# Initialize the LLMs
19story_generator = OpenAI(model="text-davinci-003")
20story_evaluator = OpenAI(model="text-davinci-003")
21
22# Create the LLMChains
23story_chain = LLMChain(llm=story_generator, prompt=story_prompt_template)
24evaluation_chain = LLMChain(llm=story_evaluator, prompt=evaluation_prompt_template)
25
26# Generate a story based on a theme
27theme = "adventure in a mystical forest"
28generated_story = story_chain.run(theme=theme)
29
30# Evaluate the generated story
31evaluation = evaluation_chain.run(story=generated_story)
32
33# Output the generated story and its evaluation
34print("Generated Story:\n", generated_story)
35print("\nEvaluation:\n", evaluation)
Prompt refactoring is an iterative process to improve the quality of prompts for better results. This approach includes analyzing the model’s outputs, identifying areas for improvement, and refining the prompt to achieve the desired outcome.
1# Define the prompt for enhancing user input
2enhancement_prompt_template = PromptTemplate(
3 input_variables=["user_input"],
4 template=(
5 "You are an expert in creating detailed prompts for language models. "
6 "Given the user input: '{user_input}', generate a comprehensive prompt that includes "
7 "specific details, context, and any relevant questions to ensure a thorough response."
8 )
9)
10
11# Define the prompt for the actual task
12task_prompt_template = PromptTemplate(
13 input_variables=["enhanced_prompt"],
14 template="{enhanced_prompt}"
15)
16
17# Initialize the LLMs
18enhancer_model = OpenAI(model="text-davinci-003")
19task_model = OpenAI(model="text-davinci-003")
20
21# Create the LLMChains
22enhancement_chain = LLMChain(llm=enhancer_model, prompt=enhancement_prompt_template)
23task_chain = LLMChain(llm=task_model, prompt=task_prompt_template)
24
25# Example user input
26user_input = "Explain the impact of the Industrial Revolution."
27
28# Step 1: Enhance the user input to create a detailed prompt
29enhanced_prompt = enhancement_chain.run(user_input=user_input)
30
31# Step 2: Use the enhanced prompt to perform the actual task
32task_output = task_chain.run(enhanced_prompt=enhanced_prompt)
33
34# Output the enhanced prompt and the task result
35print("Enhanced Prompt:\n", enhanced_prompt)
36print("\nTask Output:\n", task_output)
LangSmith is a powerful tool integrated into the LangChain ecosystem that provides features for testing, monitoring, and managing LLM applications.
Note that LangSmith can be used with or without LangChain.
In this second part of the blog series, we explored how to build AI applications using LangChain, a powerful framework that simplifies the development of LLM-powered solutions. From creating basic chat applications to implementing advanced workflows like Retrieval-Augmented Generation (RAG) and building interactive tools with Streamlit, LangChain provides a modular and flexible approach to working with large language models.
We also emphasized the importance of ensuring quality in AI applications through testing and evaluations. By using tools like LangSmith, developers can streamline testing, monitor performance, and manage versions effectively, ensuring their applications remain reliable, accurate, and adaptable over time.
In the next and last part of this series, we’ll look at the deployment of AI applications and explore operational and security considerations for LLM-powered solutions as well as AI agents. Stay tuned!
If you're eager to learn more, check out our video recordings of the latest AI for DevOps Engineers Workshop on YouTube:
You are interested in our courses or you simply have a question that needs answering? You can contact us at anytime! We will do our best to answer all your questions.
Contact us