Virtual agents are reforming how enterprises operate by automating tasks, enhancing customer interactions, and streamlining workflows. These intelligent systems leverage cutting-edge AI technologies to perform complex functions, making businesses more efficient and responsive.
In the previous blog, we discussed the Autogen framework and how we can build controlled flows using FSM and State flows.
One tool that’s making waves in the world of virtual agents is LangGraph, a versatile library designed for building stateful, multi-actor applications with Large Language Models (LLMs).
LangGraph stands out from other LLM frameworks by offering unique features that make it ideal for developing reliable and sophisticated virtual agents. Here are some key aspects:
- Cycles and Branching: Unlike traditional DAG-based solutions, LangGraph supports the creation of workflows with loops and conditional logic, making it essential for complex agent architectures.
- Persistence: This feature allows for the automatic saving of state after each step in the workflow. It enables functionalities like pausing and resuming execution, error recovery, and human-in-the-loop interventions, where human input is required to approve or modify the next steps.
- Human-in-the-Loop: LangGraph enables the interruption of graph execution, allowing for human review or edits before proceeding. This is crucial for maintaining high-quality outputs and integrating human oversight in automated processes.
- Streaming Support: The framework supports streaming outputs as they are generated, including token-level streaming, providing real-time feedback and interaction capabilities.
- Integration with LangChain: While LangGraph can be used independently, it integrates seamlessly with LangChain and LangSmith, enhancing its capabilities and providing a more robust ecosystem for AI-driven applications.
Applying these enormous capabilities to define virtual agent flows in any enterprise scenario can bring intelligent automation and operational efficiencies.
Sales teams are increasingly relying on AI-powered solutions to streamline operations, provide personalized experiences, and maximize outreach efforts. This blog delves into a practical use case of Langgraph—developing a Virtual Sales Agent that can analyze a prospect company and craft personalized pitch emails. We will walk through the code, explaining each component’s role in building an intelligent agent capable of performing this task seamlessly.
|Use Case: Automating Sales Outreach with Virtual Sales Agent
For sales teams, crafting personalized pitch emails is both a time-consuming and critical task. With Langgraph, the process can be automated, allowing teams to focus on strategic initiatives while ensuring each communication is tailored to the prospective client. Here is the outline of the steps to set up a Virtual Sales Agent that analyzes a company, gathers relevant information, and generates a pitch email using WalkingTree Technologies’ suite of AI solutions. This is a sample snapshot used to indicate the usefulness of the flow and this can be further refined and modified to suit an enterprise need.
|Step-by-Step Guide to Implementing the Virtual Sales Agent
1. Setting Up the Environment
To start, the necessary packages and environment configurations are set up, including loading environment variables for model access.
1 2 3 4 5 6 7 8 9 10 11 12 |
from dotenv import load_dotenv from langchain_groq import ChatGroq from langchain_openai import ChatOpenAI load_dotenv() # Define models - You can choose any model here like llama3 using groq, or a direct GPT model GROQ_LLM = ChatGroq(model="llama3-70b-8192") gpt_llm = ChatOpenAI(model="gpt-4o-mini") # Choose model model = GROQ_LLM |
The selected model (GROQ_LLM
) is being used for generating the outputs. This shows the flexibility of choosing any model and also trying out with different models to see which works best for your use case.
Next we will define the different actions to be performed using Langchain.
2. Keyword Search for Company Analysis
The process begins by identifying the best keywords to use for searching relevant company information. This is crucial for gathering targeted data about the company’s operations, key products, and recent activities.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from langchain.prompts import PromptTemplate from langchain_community.tools.tavily_search import TavilySearchResults from langchain_core.output_parsers import JsonOutputParser # Define the search tool web_search_tool = TavilySearchResults(k=1) # Prompt to generate search keywords search_keyword_prompt = PromptTemplate( template="""system You are a master at working out the best keywords to search for in a web search to get the best info for the customer, given the Company Name. Work out the best keywords that will find the best info for helping to get all the details about the company including the company key products and services, recent market news about the company, the active work of the company leadership team in latest technologies, any news related to the use of Generative AI in the company. Return a JSON with a single key 'keywords' with no more than 5 keywords and no preamble or explanation. user COMPANY_NAME: {company} \n assistant""", input_variables=["company"], ) search_keyword_chain = search_keyword_prompt | model | JsonOutputParser() |
This setup defines a search_keyword_chain
that, when provided with a company name, generates relevant keywords for subsequent web searches. The search_keyword_chain
uses this prompt to interact with the chosen model and parse the output into JSON format.
3. Fetching Company Information
Using the generated keywords, the agent performs a web search to collect information about the company. Tavily Search is used to power the search engine capabilities.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def company_info_search(state): print("---COMPANY RESEARCH INFO SEARCHING---") company = state['company'] num_steps = state['num_steps'] + 1 # Get search keywords keywords = search_keyword_chain.invoke({"company": company})['keywords'] full_searches = [] for keyword in keywords: print(keyword) temp_docs = web_search_tool.invoke({"query": keyword}) web_results = "\n".join([d["content"] for d in temp_docs]) full_searches.append(Document(page_content=web_results)) return {"company_info": full_searches, "num_steps": num_steps} |
This function company_info_search
leverages the keywords to perform a web search, retrieving documents containing relevant information about the company.
4. Drafting the Pitch Email
With the company information gathered, the agent drafts a personalized pitch email. This email introduces WalkingTree Technologies and pitches our Generative AI services based on the company’s profile.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
write_email_prompt = PromptTemplate( template="""system You are the Lead Generation Agent for WalkingTree Technologies who is pitching Generative AI services. Read the company info and use it to create a draft email starting with a formal introduction of WalkingTree, and explaining how Generative AI can be used to improve the efficiency of operations for the given company depending on its product and service offerings. You can make use of one or more of the following solutions from WalkingTree depending on the company domain to pitch the current work done by WalkingTree which is most suitable for the given company. Solutions of WalkingTree to be used in the email- 1. eCAI(Enterprise conversational AI) 2. Intellexi(Intelligent document parser to convert unstructured data to structured data) 3. Aspira ( Intelligent AI-driven Interview Agent) Additionally add domain-specific use cases which suit the needs of the customer. Return the draft email as JSON with a single key 'draft_email' which is a string and no preamble or explanation. user COMPANY_INFO: {company_info} \n\n assistant""", input_variables=["company_info"], ) writer_chain = write_email_prompt | model | JsonOutputParser() |
The write_email_prompt
guides the AI to draft an email by summarizing the company info and suggesting relevant WalkingTree solutions. The writer_chain
processes this and generates a draft email. For an enterprise setup, this step should include a RAG to incorporate the additional context of the relevant solutions and use cases we want to use to formulate the email to give detailed information to the prospect.
5. Analyzing and Refining the Draft Email
The draft email is then analyzed for quality and effectiveness. Feedback is provided to refine the pitch further.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
draft_analysis_prompt = PromptTemplate( template="""system You are the Sales Mails Expert Agent. Read the DRAFT_EMAIL and the COMPANY_INFO. Check if the DRAFT_MAIL addresses the key points to be pitched to the company for WalkingTree Technologies and is impressive to send to the customer. Give feedback on how the email can be improved and what specific things can be added or changed to make the email more effective at addressing the customer's issues. Return "NO FEEDBACK" if you are satisfied with the quality of the mail. Return the analysis as JSON with a single key 'draft_analysis' and no preamble or explanation. user COMPANY_INFO: {company_info} \n\n DRAFT_EMAIL: {draft_email} \n\n assistant""", input_variables=["company_info", "draft_email"], ) draft_analysis_chain = draft_analysis_prompt | model | JsonOutputParser() |
This chain evaluates the draft email and provides feedback for improvements, ensuring that the final communication is polished and tailored.
6. Finalizing the Email
Based on the feedback, the draft email is revised and finalized, ready for delivery to the prospective client.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
rewrite_email_prompt = PromptTemplate( template="""system You are the Sales Expert Agent for WalkingTree Technologies who is pitching Generative AI services. Read the given company info,analyze and use the draft mail prepared by the Lead Generation Agent, read the email analysis below from the Sales Mails Expert Agent,and improve it to create a final email which highlights your expertise in Generative AI and is focused on solving the customer pain points. Return the final email as JSON with a single key 'final_email' which is a string and no preamble or explanation. user COMPANY_INFO: {company_info} \n\n DRAFT_EMAIL: {draft_email} \n\n DRAFT_EMAIL_FEEDBACK: {draft_analysis} \n\n assistant""", input_variables=["company_info", "draft_email", "draft_analysis"], ) rewriter_chain = rewrite_email_prompt | model | JsonOutputParser() |
The rewriter_chain
takes into account the company’s profile and feedback, producing a refined and professional final email.
|Nodes, Edges, and Conditional Flows: Building the Workflow Logic
In Langgraph, workflows are defined using a combination of nodes, edges, and conditional flows. You can also define parallel and sequential flows by controlling how you connect the nodes with edges. These components form the backbone of the system, allowing for the structured execution of tasks. Understanding these elements is crucial for effectively designing and implementing automated processes.
1. Nodes: The Building Blocks of Workflows
Nodes are fundamental units in a workflow that represent distinct tasks or operations. Each node is associated with a specific function or action that needs to be performed. In the context of the Sales Virtual Agent, nodes encapsulate individual steps such as searching for company information, drafting an email, or analyzing the draft. For example the following nodes we defined in the previous section:
- company_info_search: This node is responsible for executing a web search to gather relevant information about the target company.
- draft_email_writer: This node generates a draft email based on the collected company data.
- analyze_draft_email: This node reviews the draft email and provides feedback for improvements.
Nodes are like discrete tasks in a to-do list; each has a clear purpose and outcome, contributing to the larger process.
2. Edges: Connecting the Dots
Edges define the pathways between nodes, establishing the sequence in which tasks are performed. They can be thought of as the links that connect the steps in a workflow, ensuring that once a task is completed, the next one begins. In our workflow, edges dictate the flow from one task to the next, such as:
- From company_info_search to draft_email_writer
- From draft_email_writer to analyze_draft_email
Edges ensure a logical and organized progression, preventing any gaps or overlaps in the workflow execution. They are essential for maintaining the coherence and efficiency of the automated process.
3. Conditional Flows: Handling Decision Points
Conditional flows are specialized types of edges that enable decision-making within the workflow. They are used to direct the process based on specific conditions or criteria. This is particularly useful when the workflow can diverge into different paths depending on the outcomes of certain actions. For instance, after the draft email is analyzed, the workflow can take one of two routes:
- rewrite_email: If the feedback indicates that the draft needs improvements, the workflow proceeds to rewrite the email based on the suggestions.
- no_rewrite: If the feedback deems the draft satisfactory (indicated by “NO FEEDBACK”), the workflow skips the rewrite step and moves towards finalization.
The decision point here is managed by a function like route_to_rewrite, which evaluates the feedback and determines the appropriate next step. This use of conditional flows ensures that the workflow is dynamic and adaptable, capable of responding to varying inputs and scenarios.
The flowchart represents a process that begins with initiating a search for company information, followed by drafting an email based on that information. The draft email is then analyzed to determine whether it needs improvement or not. Depending on the outcome, the email is either rewritten or accepted as is. Finally, the process concludes with printing the state (finalized email) before ending.
|State Management and Workflow Execution
The state of the entire process is managed through a GraphState
class, which tracks all necessary details, including the company name, draft and final emails, and gathered company information. The workflow is defined using Langgraph’s StateGraph
, setting up the nodes and the transitions between them as shown in the below code for the current example.
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 |
class GraphState(TypedDict): company: str draft_email: str final_email: str company_info: List[str] info_needed: bool num_steps: int draft_analysis: str workflow = StateGraph(GraphState) # Define the nodes and their execution order workflow.add_node("company_info_search", company_info_search) workflow.add_node("draft_email_writer", draft_email_writer) workflow.add_node("analyze_draft_email", analyze_draft_email) workflow.add_node("rewrite_email", rewrite_email) workflow.add_node("no_rewrite", no_rewrite) workflow.add_node("state_printer", state_printer) # Set up the flow workflow.set_entry_point("company_info_search") workflow.add_edge("company_info_search", "draft_email_writer") workflow.add_edge("draft_email_writer", "analyze_draft_email") workflow.add_conditional_edges( "analyze_draft_email", route_to_rewrite, { "rewrite": "rewrite_email", "no_rewrite": "no_rewrite", }, ) workflow.add_edge("no_rewrite", "state_printer") workflow.add_edge("rewrite_email", "state_printer") workflow.add_edge("state_printer", END) # Compile and run the workflow app = workflow.compile() inputs = {"company": "Scaled Foundation", "num_steps": 0} for output in app.stream(inputs): for key, value in output.items(): print(f"Finished running: {key}:") |
The workflow captures the full journey from researching the company to drafting, analyzing, and finalizing the email, ensuring each step is handled efficiently and effectively.
Langgraph, combined with state-of-the-art language models, offers a powerful framework for automating complex tasks by defining clear navigation and control flow. Langgraph advocates for an approach that involves clearly specifying individual agents and their transition probabilities, representing them as a graph making it more suitable for a controlled, structured and clearly defined flow of events. By leveraging this technology, businesses can enhance their overall process automation, customer engagement strategies, save time, and deliver personalized, high-quality communications by employing virtual agents at different junctures of the business workflow. As AI continues to evolve, tools like Langgraph will play an increasingly vital role in transforming how businesses interact with their clients, driving innovation and efficiency in all aspects of operations.
WalkingTree Technologies stands at the forefront of digital transformation, leveraging cutting-edge AI and automation to empower businesses across various industries. Our expertise in deploying reliable virtual agents using frameworks like Langgraph ensures that your AI-driven solutions are both efficient and capable of delivering controlled, predictable behavior that drives high business value. By integrating advanced AI models with seamless workflow management, we enable enterprises to stay ahead in a competitive edge.
Partner with WalkingTree to drive innovation in your organization, helping you achieve operational excellence and enhanced customer engagement through AI-driven automation.