Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
-introspection agents with observability
  • Loading branch information
pavanmantha committed Nov 21, 2024
commit ce2cfd2ed5dd0a856276200c22ae3f8135b07922
1 change: 1 addition & 0 deletions bootstraprag/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def create(project_name, framework, template, observability):
'rag-with-self-correction',
'rag-with-controllable-agents',
'rag-with-llama-parse',
'agents-with-introspection',
'llama-deploy-with-simplemq',
'llama-deploy-with-rabbitmq',
'llama-deploy-with-kafka'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
OPENAI_API_KEY='sk-proj-'

# Langfuse Observability Details
LANGFUSE_PUBLIC_KEY='pk-lf-0cefdf2d-2d95-4cee-bd3b-cf0f79b8e068'
LANGFUSE_SECRET_KEY='sk-lf-1d56e47f-8d3e-4c22-8be7-5ffdfdc535b7'
LANGFUSE_HOST='http://localhost:3000'
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from llama_index.core.tools.tool_spec.base import BaseToolSpec
from llama_index.agent.introspective import ToolInteractiveReflectionAgentWorker, IntrospectiveAgentWorker
from llama_index.core.agent import FunctionCallingAgentWorker # Import OpenAIAgentWorker here
from llama_index.agent.openai import OpenAIAgentWorker
from llama_index.llms.openai import OpenAI
from llama_index.core.llms import ChatMessage, MessageRole
from datetime import datetime
import yfinance as yf
import pandas as pd
from dotenv import load_dotenv, find_dotenv

load_dotenv(find_dotenv())


class StockDataRetrieverTool(BaseToolSpec):
"""Tool for retrieving stock data"""

spec_functions = ['fetch_historical_prices']

def fetch_historical_prices(self, ticker: str, start_date: str,
end_date: str = datetime.today().strftime('%Y-%m-%d')) -> pd.DataFrame:
"""
Retrieves historical stock prices for a given ticker within a date range.

Args:
ticker (str): The stock ticker symbol.
start_date (str): Start date for data in 'YYYY-MM-DD' format.
end_date (str, optional): End date in 'YYYY-MM-DD' format. Defaults to today.

Returns:
pd.DataFrame: DataFrame with stock price data.
"""
return yf.download(tickers=ticker, start=start_date, end=end_date, progress=True)


class FinancialAgentBuilder:
"""Builder for creating an introspective financial agent with reflection capabilities"""

def __init__(self, data_tool: BaseToolSpec):
self.data_tool = data_tool
self.data_tool_list = data_tool.to_tool_list()

def create_introspective_agent(self, verbose: bool = True, include_main_worker: bool = True):
critique_worker = self._build_critique_worker(verbose)
reflection_worker = self._build_reflection_worker(critique_worker, verbose)
main_worker = self._build_main_worker() if include_main_worker else None

introspective_worker = IntrospectiveAgentWorker.from_defaults(
reflective_agent_worker=reflection_worker,
main_agent_worker=main_worker,
verbose=verbose
)

initial_message = [
ChatMessage(
content="You are a financial assistant that helps gather historical prices "
"and provides a summary of the closing price analysis.",
role=MessageRole.SYSTEM,
)
]
return introspective_worker.as_agent(chat_history=initial_message, verbose=verbose)

def _build_critique_worker(self, verbose: bool):
return FunctionCallingAgentWorker.from_tools(
tools=self.data_tool_list,
llm=OpenAI(model="gpt-4o-mini"),
verbose=verbose
)

def _build_reflection_worker(self, critique_worker, verbose: bool):
def stop_critique_on_pass(critique_str: str):
return "[APPROVE]" in critique_str

return ToolInteractiveReflectionAgentWorker.from_defaults(
critique_agent_worker=critique_worker,
critique_template=(
"Please review the retrieval of historical prices with the specified time intervals. "
"Evaluate the price for accuracy, efficiency, and adherence to truth. "
"If everything is correct, write '[APPROVE]'; otherwise, write '[REJECT]'.\n\n{input_str}"
),
stopping_callable=stop_critique_on_pass,
correction_llm=OpenAI(model='gpt-4o'),
verbose=verbose
)

def _build_main_worker(self):
return OpenAIAgentWorker.from_tools(
tools=self.data_tool_list,
llm=OpenAI("gpt-4-turbo"),
verbose=True
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import litserve as lit
from agent_core import StockDataRetrieverTool, FinancialAgentBuilder

# Query example
# query = """I have 10k dollars Now analyze APPL stock and MSFT stock to let me know where to invest
# this money and how many stock will I get it, Give me the last 3 months historical close prices of
# APPL and MSFT. Respond with a comparative summary on closing prices and recommended stock to invest."""


class IntrospectionAgentAPI(lit.LitAPI):
def __init__(self):
# Instantiate tool and agent
self.stock_data_tool = StockDataRetrieverTool()
self.financial_agent_builder = None

def setup(self, device):
self.financial_agent_builder = FinancialAgentBuilder(data_tool=self.stock_data_tool)

def decode_request(self, request, **kwargs):
return request["query"]

def predict(self, x, **kwargs):
introspective_agent = self.financial_agent_builder.create_introspective_agent(verbose=True)
response = introspective_agent.chat(x)
return response

def encode_response(self, output, **kwargs):
return {"agent": output}


if __name__ == "__main__":
api = IntrospectionAgentAPI()
# pass this parameter "spec=lit.OpenAISpec()", if you want to use the API as
# http://localhost:8002/v1/chat/completion
# else http://localhost:8002/predict
server = lit.LitServer(api, accelerator="auto", spec=lit.OpenAISpec())
server.run(port=8002)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
version: '3.8'

services:
postgres:
image: postgres:latest
container_name: postgres
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: langfuse
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- langfuse-network

langfuse:
image: langfuse/langfuse:latest
container_name: langfuse
environment:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/langfuse
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: mysecret
SALT: mysalt
ENCRYPTION_KEY: 98637d42c277ef10b8a324e25d492daa8eee8f769574124ba25132f71481f183
ports:
- "3000:3000"
depends_on:
- postgres
networks:
- langfuse-network

volumes:
postgres_data:

networks:
langfuse-network:
driver: bridge
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from agent_core import StockDataRetrieverTool, FinancialAgentBuilder

# Instantiate tool and agent
stock_data_tool = StockDataRetrieverTool()
financial_agent_builder = FinancialAgentBuilder(data_tool=stock_data_tool)
introspective_agent = financial_agent_builder.create_introspective_agent(verbose=True)

# Query example
query = """I have 10k dollars Now analyze APPL stock and MSFT stock to let me know where to invest
this money and how many stock will I get it, Give me the last 3 months historical close prices of APPL and MSFT.
Respond with a comparative summary on closing prices and recommended stock to invest."""
response = introspective_agent.chat(query)
print(response)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
### Introspective Financial Agents

Introspective agents are artificial intelligence systems designed to evaluate and refine their own outputs through iterative reflection and correction. This self-assessment process enables them to improve performance over time. For instance, in the LlamaIndex framework, an introspective agent generates an initial response to a task and then engages in reflection and correction cycles to enhance the response until a satisfactory outcome is achieved.

An introspective worker agent is a specific implementation of this concept. It operates by delegating tasks to two other agents: one generates the initial response, and the other performs reflection and correction on that response. This structured approach ensures systematic evaluation and improvement of outputs.

### Setup Langfuse for observability
- `docker-compose run -f docker-compose-langfuse.yml`

### How to run ?
- `pip install -r requirements.txt`
- `python main.py` [standalone code]
- `python api_server.py` [litserve apis]

### How to access API?
- URL: http://localhost:8002/predict
- method: POST
- payload:
```json
{
"query": "I have 10k dollars Now analyze APPL stock and MSFT stock to let me know where to invest this money and how many stock will I get it, Give me the last 3 months historical close prices of APPL and MSFT. Respond with a comparative summary on closing prices and recommended stock to invest."
}
```

### How to check traces?
launch `http://localhost:3000`
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
llama-index-agent-introspective
llama-index-llms-openai
llama-index-llms-ollama
llama-index-embeddings-ollama
llama-index-vector-stores-qdrant
llama-index-program-openai
llama-index-readers-file
yfinance
pandas
python-dotenv
# observability
langfuse==2.52.2