What if you could ask Warren Buffett about a stock, market trends, or long-term investing, anytime you wanted? With reports suggesting he may soon step down as CEO of Berkshire Hathaway, it’s a good moment to reflect on the lasting value of his principles. For decades, Buffett has been a steady voice in investing, known for his focus on value, patience, and understanding what you own. In this guide, I will show you how to turn those principles into a conversational Warren Buffett agent that evaluates companies through his lens, and interacts using real-time stock data and news. The goal isn’t to recreate Buffett, but to build a chatbot that helps you think the way he might.
Our objective is clear: Create a Warren Buffett agent that interacts like him It should discuss investment philosophy, analyze stocks using his core principles, and leverage real-time data.
The main components are:
If this is your first time building agents, checkout our detailed guide – How to Build an AI Agent from Scratch?
Before coding, ensure your computer is ready.
pip install langchain langchain-openai langchain-community openai yfinance google-search-results streamlit python-dotenv streamlit-chat
OPENAI_API_KEY="sk-YOUR_KEY_HERE"
SERPAPI_API_KEY="YOUR_KEY_HERE"
Create a new Python file (e.g., buffett_chatbot.py). Begin by importing the required modules at the top:
import streamlit as st
import os
import json
import yfinance as yf
from dotenv import load_dotenv
# LangChain components
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain.memory import ConversationBufferMemory
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import SystemMessage # No need for HumanMessage/AIMessage here anymore
from langchain.tools import Tool
from langchain_community.utilities import SerpAPIWrapper
# --- Load .env file (as a fallback) ---
load_dotenv()
These imports bring in Streamlit for the interface, os for environment variables, json for data handling, yfinance for stocks, dotenv for key loading, and various LangChain components for the agent logic.
Configure the basic application layout and create sidebar inputs for API keys:
# --- Page Config ---
st.set_page_config(page_title="Warren Buffett Bot", layout="wide")
st.title("Warren Buffett Investment Chatbot 📈")
st.caption("Ask me about investing, stocks, or market wisdom - in the style of Warren Buffett.")
# --- API Key Input in Sidebar ---
st.sidebar.header("API Configuration")
# Initialize session state for keys if they don't exist
if 'openai_api_key' not in st.session_state:
st.session_state.openai_api_key = ""
if 'serpapi_api_key' not in st.session_state:
st.session_state.serpapi_api_key = ""
# Create text input fields for keys, storing values in session state
input_openai_key = st.sidebar.text_input(
"OpenAI API Key", type="password", value=st.session_state.openai_api_key, key="openai_input"
)
input_serpapi_key = st.sidebar.text_input(
"SerpAPI API Key", type="password", value=st.session_state.serpapi_key, key="serpapi_input"
)
# Update session state with current input values
st.session_state.openai_api_key = input_openai_key
st.session_state.serpapi_key = input_serpapi_key
# Determine which keys are active (user input takes priority)
active_openai_key = st.session_state.openai_api_key or os.getenv("OPENAI_API_KEY")
active_serpapi_key = st.session_state.serpapi_api_key or os.getenv("SERPAPI_API_KEY")
# --- Display API Status ---
st.sidebar.header("API Status")
# (Add the if/else blocks using st.sidebar.success/error/warning as in the provided code)
if active_openai_key: st.sidebar.success(...) else: st.sidebar.error(...)
# Check and display SerpAPI status similarly
This code sets up the visual part of the Streamlit chatbot application. It uses st.session_state to remember the API keys entered by the user during their session.
Establish constants for the AI model and define the detailed instructions (system prompt) that shape the chatbot’s personality:
# --- Constants & Prompt ---
MODEL_NAME = "gpt-4o" # Specify the OpenAI model
TEMPERATURE = 0.5 # Controls AI creativity (lower is more predictable)
MEMORY_KEY = "chat_history" # Key for storing conversation history
BUFFETT_SYSTEM_PROMPT = """
You are a conversational AI assistant modeled after Warren Buffett, the legendary value investor. Embody his persona accurately.
**Your Core Principles:**
* **Value Investing:** Focus on finding undervalued companies with solid fundamentals (earnings, low debt, strong management). Judge businesses, not stock tickers.
* **Long-Term Horizon:** Think in terms of decades, not days or months. Discourage short-term speculation and market timing.
* **Margin of Safety:** Only invest when the market price is significantly below your estimate of intrinsic value. Be conservative.
* **Business Moats:** Favor companies with durable competitive advantages (strong brands, network effects, low-cost production, regulatory advantages).
* **Understand the Business:** Only invest in companies you understand. "Risk comes from not knowing what you're doing."
* **Management Quality:** Assess the integrity and competence of the company's leadership.
* **Patience and Discipline:** Wait for the right opportunities ("fat pitches"). Avoid unnecessary activity. Be rational and unemotional.
* **Circle of Competence:** Stick to industries and businesses you can reasonably understand. Acknowledge what you don't know.
**Your Communication Style:**
* **Wise and Folksy:** Use simple language, analogies, and occasional humor, much like Buffett does in his letters and interviews.
* **Patient and Calm:** Respond thoughtfully, avoiding hype or panic.
* **Educational:** Explain your reasoning clearly, referencing your core principles.
* **Prudent:** Be cautious about making specific buy/sell recommendations without thorough analysis based on your principles. Often, you might explain *how* you would analyze it rather than giving a direct 'yes' or 'no'.
* **Quote Yourself:** Occasionally weave in famous Buffett quotes where appropriate (e.g., "Price is what you pay; value is what you get.", "Be fearful when others are greedy and greedy when others are fearful.").
* **Acknowledge Limitations:** If asked about something outside your expertise (e.g., complex tech you wouldn't invest in, short-term trading), politely state it's not your area.
**Interaction Guidelines:**
* When asked for stock recommendations, first use your tools to gather fundamental data (P/E, earnings, debt if possible) and recent news.
* Analyze the gathered information through the lens of your core principles (moat, management, valuation, long-term prospects).
* Explain your thought process clearly.
* If a company seems to fit your criteria, express cautious optimism, emphasizing the need for further due diligence by the investor.
* If a company doesn't fit (e.g., too speculative, high P/E without justification, outside circle of competence), explain why based on your principles.
* If asked for general advice, draw upon your well-known philosophies.
* Maintain conversational context using the provided chat history. Refer back to previous points if relevant.
Remember: You are simulating Warren Buffett. Your goal is to provide insights consistent with his philosophy and communication style, leveraging the tools for data when needed. Do not give definitive financial advice, but rather educate and explain the *Buffett way* of thinking about investments.
"""
Implement the functions that allow the chatbot to get external stock and news data.
# --- Tool Definitions ---
# 1. Stock Data Tool (Yahoo Finance) - No changes needed here
@st.cache_data(show_spinner=False) # Add caching for yfinance calls
def get_stock_info(symbol: str) -> str:
# ... (keep the existing get_stock_info function code) ...
"""
Fetches key financial data for a given stock symbol using Yahoo Finance...
"""
try:
ticker = yf.Ticker(symbol)
info = ticker.info
if not info or info.get('regularMarketPrice') is None and info.get('currentPrice') is None and info.get('previousClose') is None:
hist = ticker.history(period="5d")
if hist.empty:
return f"Error: Could not retrieve any data for symbol {symbol}."
last_close = hist['Close'].iloc[-1] if not hist.empty else 'N/A'
current_price = info.get("currentPrice") or info.get("regularMarketPrice") or last_close
else:
current_price = info.get("currentPrice") or info.get("regularMarketPrice") or info.get("previousClose", "N/A")
data = {
"symbol": symbol, "companyName": info.get("longName", "N/A"),
"currentPrice": current_price, "peRatio": info.get("trailingPE") or info.get("forwardPE", "N/A"),
"earningsPerShare": info.get("trailingEps", "N/A"), "marketCap": info.get("marketCap", "N/A"),
"dividendYield": info.get("dividendYield", "N/A"), "priceToBook": info.get("priceToBook", "N/A"),
"sector": info.get("sector", "N/A"), "industry": info.get("industry", "N/A"),
"summary": info.get("longBusinessSummary", "N/A")[:500] + ("..." if len(info.get("longBusinessSummary", "")) > 500 else "")
}
if data["currentPrice"] == "N/A": return f"Error: Could not retrieve current price for {symbol}."
return json.dumps(data)
except Exception as e: return f"Error fetching data for {symbol} using yfinance: {str(e)}."
stock_data_tool = Tool(
name="get_stock_financial_data",
func=get_stock_info,
description="Useful for fetching fundamental financial data for a specific stock symbol (ticker)..." # Keep description
)
# 2. News Search Tool (SerpAPI) - Now uses active_serpapi_key
def create_news_search_tool(api_key):
if api_key:
try:
params = {"engine": "google_news", "gl": "us", "hl": "en", "num": 5}
search_wrapper = SerpAPIWrapper(params=params, serpapi_api_key=api_key)
# Test connectivity during creation (optional, can slow down startup)
# search_wrapper.run("test query")
return Tool(
name="search_stock_news",
func=search_wrapper.run,
description="Useful for searching recent news articles about a specific company or stock symbol..." # Keep description
)
except Exception as e:
print(f"SerpAPI Tool Creation Warning: {e}")
# Fallback to a dummy tool if key is provided but invalid/error occurs
return Tool(
name="search_stock_news",
func=lambda x: f"News search unavailable (SerpAPI key configured, but error occurred: {e}).",
description="News search tool (currently unavailable due to configuration error)."
)
else:
# Dummy tool if no key is available
return Tool(
name="search_stock_news",
func=lambda x: "News search unavailable (SerpAPI key not provided).",
description="News search tool (unavailable - API key needed)."
)
news_search_tool = create_news_search_tool(active_serpapi_key)
tools = [stock_data_tool, news_search_tool]
These functions become the ‘senses’ of your stock data analysis bot, allowing it to access current information. Wrapping them as Tool objects makes them usable by LangChain.
Configure the core AI logic: the language model, the prompt structure, memory management, and the agent executor that ties them together. This happens within the main part of the script, often inside conditional checks.
# --- Main App Logic ---
# Check if the essential OpenAI key is provided
if not active_openai_key:
st.warning("Please enter your OpenAI API Key in the sidebar...", icon="🔑")
st.stop() # Stop if no key
# --- LangChain Agent Setup (conditional on key) ---
try:
# Initialize the OpenAI LLM
llm = ChatOpenAI(
model=MODEL_NAME, temperature=TEMPERATURE, openai_api_key=active_openai_key
)
# Create the prompt template
prompt_template = ChatPromptTemplate.from_messages(
[
SystemMessage(content=BUFFETT_SYSTEM_PROMPT),
MessagesPlaceholder(variable_name=MEMORY_KEY),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
# Initialize or re-initialize agent components in session state
reinitialize_agent = False
# (Add the logic to check if 'agent_executor' exists or if keys changed)
# ...
if reinitialize_agent:
# Initialize memory
st.session_state['memory'] = ConversationBufferMemory(memory_key=MEMORY_KEY, return_messages=True)
# Create the agent
agent = create_openai_functions_agent(llm, tools, prompt_template)
# Create the executor
st.session_state['agent_executor'] = AgentExecutor(
agent=agent, tools=tools, memory=st.session_state['memory'], verbose=True, # Set verbose=False for production
handle_parsing_errors=True, max_iterations=5
)
# Store keys used for this agent instance
st.session_state.agent_openai_key = active_openai_key
st.session_state.agent_serpapi_key = active_serpapi_key
# st.experimental_rerun() # Rerun to apply changes
# Continue with chat history initialization and display...
This is the core LangChain chatbot development section. It sets up the agent using the persona, tools, and memory, enabling intelligent conversation via OpenAI API integration. Using st.session_state here is essential for maintaining the agent’s memory across user interactions.
Add the code that handles displaying the conversation and processing user input through the agent.
# --- Chat History and Interaction ---
# Initialize chat history if it doesn't exist
if "messages" not in st.session_state:
st.session_state["messages"] = [
{"role": "assistant", "content": "Greetings! ..."} # Initial message
]
# Display existing chat messages
for msg in st.session_state.messages:
st.chat_message(msg["role"]).write(msg["content"])
# Get new user input
if prompt := st.chat_input("Ask Buffett Bot..."):
# Display user message
st.session_state.messages.append({"role": "user", "content": prompt})
st.chat_message("user").write(prompt)
# Prepare input for the agent
agent_input = {"input": prompt}
# Invoke the agent executor
try:
with st.spinner("Buffett is pondering..."):
# Get the executor instance from session state
agent_executor_instance = st.session_state['agent_executor']
response = agent_executor_instance.invoke(agent_input)
# Display assistant response
output = response.get('output', "Sorry, an error occurred.")
st.session_state.messages.append({"role": "assistant", "content": output})
st.chat_message("assistant").write(output)
except Exception as e:
# Handle errors during agent execution
error_message = f"An error occurred: {str(e)}"
st.error(error_message, icon="🔥")
# Add error to chat display
st.session_state.messages.append({"role": "assistant", "content": f"Sorry... {e}"})
st.chat_message("assistant").write(f"Sorry... {e}")
# Optional: Add the button to clear history
if st.sidebar.button("Clear Chat History"):
# (Code to clear st.session_state.messages and st.session_state.memory)
st.rerun()
This part makes the Streamlit chatbot application interactive. It reads user input, sends it to the LangChain agent executor, and displays both the user’s query and the bot’s generated response.
Save the complete Python script. Open your terminal in the script’s directory and run:
streamlit run buffett_chatbot.py
Run this file in the terminal and your browser will open the application, ready for you to input API keys and interact with the chatbot.
Let’s test Mr. Buffett agent with some of our questions. You can access the same here.
Our streamlit app looks like this, Here we have the option to fill our own OpenAI key and SerpAPI key. Now lets test the bot…
Question 1: “Mr. Buffett, could you explain your core investment philosophy in simple terms?”
Question 2: “Analyze Apple (AAPL) based on its current fundamentals. Would you consider it a good long-term investment based on your principles?”
Question 3: “What are your thoughts on Microsoft (MSFT) considering its recent news and developments?”
Based on the above outputs, we can see that the bot is performing well and using all its functionalities to get to the final output. It is using Warren Buffet persona that we defined earlier to answer all the questions. The bot is utilizing yfinance to get the latest stock prices and PE ratios. SerpAPI is used to get the latest news on the stocks.
This Warren Buffett agent can be a useful companion for anyone looking to explore value investing through the lens of timeless principles. Whether you’re just starting out or refining your approach, this agent can help you think more clearly and patiently about the markets, just like Buffett would.
You can try it live here: BuffettBot on Hugging Face.
Have a question you’d like the agent to answer? Drop it in the comments, I’d love to hear what you ask and how the agent responds.
OpenAI: Visit platform.openai.com, sign up, and navigate to the API keys section.
SerpAPI: Visit serpapi.com, register, and find your API key in your account dashboard.
A. The bot uses Yahoo Finance via yfinance. While generally reliable for widely traded stocks, data can have delays or occasional inaccuracies. It’s good for educational purposes but always cross-reference with official sources for actual investment decisions.
A. Absolutely. Modify the BUFFETT_SYSTEM_PROMPT string in the code. You can adjust his principles, communication style, or even add specific knowledge areas.
A. This happens if you haven’t provided a valid SerpAPI key in the sidebar or the .env file, or if there was an error connecting to SerpAPI.
A. No. This chatbot is an educational simulation based on Warren Buffett’s style and principles. It does not provide financial advice. Always consult with a qualified financial advisor before making investment decisions.