Skip to content

Update FinanceAgent v1.3 #1819

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
52 changes: 39 additions & 13 deletions FinanceAgent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,28 @@ Please note:
```bash
mkdir /path/to/your/workspace/
export WORKDIR=/path/to/your/workspace/
genaicomps
genaiexamples
cd $WORKDIR
git clone https://github.com/opea-project/GenAIExamples.git
```

### 2.2 Set up env vars

```bash
export HF_CACHE_DIR=/path/to/your/model/cache/
export HF_TOKEN=<you-hf-token>

export FINNHUB_API_KEY=<your-finnhub-api-key> # go to https://finnhub.io/ to get your free api key
export FINANCIAL_DATASETS_API_KEY=<your-api-key> # go to https://docs.financialdatasets.ai/ to get your free api key
```

### 2.3 Build docker images
### 2.3 [Optional] Build docker images

Build docker images for dataprep, agent, agent-ui.
Only needed when docker pull failed.

```bash
cd GenAIExamples/FinanceAgent/docker_image_build
cd $WORKDIR/GenAIExamples/FinanceAgent/docker_image_build
# get GenAIComps repo
git clone https://github.com/opea-project/GenAIComps.git
# build the images
docker compose -f build.yaml build --no-cache
```

Expand Down Expand Up @@ -91,7 +95,7 @@ python $WORKPATH/tests/test_redis_finance.py --port 6007 --test_option get
```

### 3.3 Launch the multi-agent system

The command below will launch 3 agent microservices, 1 docsum microservice, 1 UI microservice.
```bash
# inside $WORKDIR/GenAIExamples/FinanceAgent/docker_compose/intel/hpu/gaudi/
bash launch_agents.sh
Expand All @@ -115,14 +119,14 @@ prompt="generate NVDA financial research report"
python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --prompt "$prompt" --agent_role "worker" --ext_port $agent_port --tool_choice "get_current_date" --tool_choice "get_share_performance"
```

Supervisor ReAct Agent:
Supervisor Agent single turns:

```bash
export agent_port="9090"
python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --stream
```

Supervisor ReAct Agent Multi turn:
Supervisor Agent multi turn:

```bash
python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --multi-turn --stream
Expand All @@ -134,12 +138,34 @@ python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervis
The UI microservice is launched in the previous step with the other microservices.
To see the UI, open a web browser to `http://${ip_address}:5175` to access the UI. Note the `ip_address` here is the host IP of the UI microservice.

1. `create Admin Account` with a random value
1. Create Admin Account with a random value

2. Enter the endpoints in the `Connections` settings

First, click on the user icon in the upper right corner to open `Settings`. Click on `Admin Settings`. Click on `Connections`.

Then, enter the supervisor agent endpoint in the `OpenAI API` section: `http://${ip_address}:9090/v1`. Enter the API key as "empty". Add an arbitrary model id in `Model IDs`, for example, "opea_agent". The `ip_address` here should be the host ip of the agent microservice.

Then, enter the dataprep endpoint in the `Icloud File API` section. You first need to enable `Icloud File API` by clicking on the button on the right to turn it into green and then enter the endpoint url, for example, `http://${ip_address}:6007/v1`. The `ip_address` here should be the host ip of the dataprep microservice.

You should see screen like the screenshot below when the settings are done.

2. use an opea agent endpoint, for example, the `Research Agent` endpoint `http://$ip_address:9096/v1`, which is a openai compatible api
![opea-agent-setting](assets/ui_connections_settings.png)

![opea-agent-setting](assets/opea-agent-setting.png)
3. Upload documents with UI

3. test opea agent with ui
Click on the `Workplace` icon in the top left corner. Click `Knowledge`. Click on the "+" sign to the right of `Icloud Knowledge`. You can paste in an url the the left hand side of the pop-up window, or upload a local file by click on the cloud icon on the right hand side of the pop-up window. Then click on the `Upload Confirm` button. Wait till the processing is done and the pop-up window will be closed on its own when the data ingestion is done. See the screenshot below.

Note: the data ingestion may take a few minutes depending on the length of the document. Please wait patiently and do not close the pop-up window.

![upload-doc-ui](assets/upload_doc_ui.png)

4. Test agent with UI

After the settings are done and documents are ingested, you can start to ask questions to the agent. Click on the `New Chat` icon in the top left corner, and type in your questions in the text box in the middle of the UI.

The UI will stream the agent's response tokens. You need to expand the `Thinking` tab to see the agent's reasoning process. After the agent made tool calls, you would also see the tool output after the tool returns output to the agent. Note: it may take a while to get the tool output back if the tool execution takes time.

![opea-agent-test](assets/opea-agent-test.png)


Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added FinanceAgent/assets/upload_doc_ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions FinanceAgent/docker_compose/intel/hpu/gaudi/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ services:
ip_address: ${ip_address}
strategy: react_llama
with_memory: false
recursion_limit: ${recursion_limit_worker}
recursion_limit: 25
llm_engine: vllm
HUGGINGFACEHUB_API_TOKEN: ${HUGGINGFACEHUB_API_TOKEN}
llm_endpoint_url: ${LLM_ENDPOINT_URL}
Expand All @@ -68,7 +68,7 @@ services:
container_name: supervisor-agent-endpoint
depends_on:
- worker-finqa-agent
# - worker-research-agent
- worker-research-agent
volumes:
- ${TOOLSET_PATH}:/home/user/tools/
- ${PROMPT_PATH}:/home/user/prompts/
Expand Down
7 changes: 1 addition & 6 deletions FinanceAgent/docker_image_build/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,4 @@ services:
https_proxy: ${https_proxy}
no_proxy: ${no_proxy}
image: ${REGISTRY:-opea}/agent:${TAG:-latest}
# agent-ui:
# build:
# context: ../ui
# dockerfile: ./docker/Dockerfile
# extends: agent
# image: ${REGISTRY:-opea}/agent-ui:${TAG:-latest}

1 change: 1 addition & 0 deletions FinanceAgent/prompts/research_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
4. Provide stock performance, because the financial report is used for stock investment analysis.
5. Read the execution history if any to understand the tools that have been called and the information that has been gathered.
6. Reason about the information gathered so far and decide if you can answer the question or if you need to call more tools.
7. Most of the tools need ticker symbol, use your knowledge to convert the company name to the ticker symbol if user only provides the company name.

**Output format:**
You should output your thought process:
Expand Down
39 changes: 28 additions & 11 deletions FinanceAgent/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ def process_request(url, query, is_stream=False):
else:
for line in resp.iter_lines(decode_unicode=True):
print(line)
ret = None
ret = "Done"

resp.raise_for_status() # Raise an exception for unsuccessful HTTP status codes
return ret
except requests.exceptions.RequestException as e:
ret = f"An error occurred:{e}"
return None
return ret


def test_worker_agent(args):
Expand All @@ -35,13 +35,19 @@ def test_worker_agent(args):
query = {"role": "user", "messages": args.prompt, "stream": "false", "tool_choice": args.tool_choice}
ret = process_request(url, query)
print("Response: ", ret)
if "error" in ret.lower():
print("Error in response, please check the server.")
return "error"
else:
return "test completed with success"


def add_message_and_run(url, user_message, thread_id, stream=False):
print("User message: ", user_message)
query = {"role": "user", "messages": user_message, "thread_id": thread_id, "stream": stream}
ret = process_request(url, query, is_stream=stream)
print("Response: ", ret)
return ret


def test_chat_completion_multi_turn(args):
Expand All @@ -51,28 +57,37 @@ def test_chat_completion_multi_turn(args):
# first turn
print("===============First turn==================")
user_message = "Key takeaways of Gap's 2024 Q4 earnings call?"
add_message_and_run(url, user_message, thread_id, stream=args.stream)
ret = add_message_and_run(url, user_message, thread_id, stream=args.stream)
if "error" in ret.lower():
print("Error in response, please check the server.")
return "error"
print("===============End of first turn==================")

# second turn
print("===============Second turn==================")
user_message = "What was Gap's forecast for 2025?"
add_message_and_run(url, user_message, thread_id, stream=args.stream)
ret = add_message_and_run(url, user_message, thread_id, stream=args.stream)
if "error" in ret.lower():
print("Error in response, please check the server.")
return "error"
print("===============End of second turn==================")

return "test completed with success"

def test_supervisor_agent_single_turn(args):
url = f"http://{args.ip_addr}:{args.ext_port}/v1/chat/completions"
query_list = [
"What was Gap's revenue growth in 2024?",
"Can you summarize Costco's 2025 Q2 earnings call?",
# "Should I increase investment in Costco?",
"Should I increase investment in Johnson & Johnson?",
]
for query in query_list:
thread_id = f"{uuid.uuid4()}"
add_message_and_run(url, query, thread_id, stream=args.stream)
ret = add_message_and_run(url, query, thread_id, stream=args.stream)
if "error" in ret.lower():
print("Error in response, please check the server.")
return "error"
print("=" * 50)

return "test completed with success"

if __name__ == "__main__":
parser = argparse.ArgumentParser()
Expand All @@ -89,10 +104,12 @@ def test_supervisor_agent_single_turn(args):

if args.agent_role == "supervisor":
if args.multi_turn:
test_chat_completion_multi_turn(args)
ret = test_chat_completion_multi_turn(args)
else:
test_supervisor_agent_single_turn(args)
ret = test_supervisor_agent_single_turn(args)
print(ret)
elif args.agent_role == "worker":
test_worker_agent(args)
ret = test_worker_agent(args)
print(ret)
else:
raise ValueError("Invalid agent role")
48 changes: 24 additions & 24 deletions FinanceAgent/tests/test_compose_on_gaudi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function start_vllm_service_70B() {
echo "token is ${HF_TOKEN}"
echo "start vllm gaudi service"
echo "**************model is $model**************"
docker run -d --runtime=habana --rm --name "vllm-gaudi-server" -e HABANA_VISIBLE_DEVICES=all -p $vllm_port:8000 -v $vllm_volume:/data -e HF_TOKEN=$HF_TOKEN -e HUGGING_FACE_HUB_TOKEN=$HF_TOKEN -e HF_HOME=/data -e OMPI_MCA_btl_vader_single_copy_mechanism=none -e PT_HPU_ENABLE_LAZY_COLLECTIVES=true -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e no_proxy=$no_proxy -e VLLM_SKIP_WARMUP=true --cap-add=sys_nice --ipc=host $vllm_image --model ${model} --max-seq-len-to-capture 16384 --tensor-parallel-size 4
docker run -d --runtime=habana --rm --name "vllm-gaudi-server-mh" -e HABANA_VISIBLE_DEVICES=0,2,3,4 -p $vllm_port:8000 -v $vllm_volume:/data -e HF_TOKEN=$HF_TOKEN -e HUGGING_FACE_HUB_TOKEN=$HF_TOKEN -e HF_HOME=/data -e OMPI_MCA_btl_vader_single_copy_mechanism=none -e PT_HPU_ENABLE_LAZY_COLLECTIVES=true -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e no_proxy=$no_proxy -e VLLM_SKIP_WARMUP=true --cap-add=sys_nice --ipc=host $vllm_image --model ${model} --max-seq-len-to-capture 16384 --tensor-parallel-size 4
sleep 10s
echo "Waiting vllm gaudi ready"
n=0
Expand Down Expand Up @@ -181,9 +181,9 @@ function validate_agent_service() {
# # test worker research agent
echo "======================Testing worker research agent======================"
export agent_port="9096"
prompt="generate NVDA financial research report"
prompt="Johnson & Johnson"
local CONTENT=$(python3 $WORKDIR/GenAIExamples/AgentQnA/tests/test.py --prompt "$prompt" --agent_role "worker" --ext_port $agent_port --tool_choice "get_current_date" --tool_choice "get_share_performance")
local EXIT_CODE=$(validate "$CONTENT" "NVDA" "research-agent-endpoint")
local EXIT_CODE=$(validate "$CONTENT" "Johnson" "research-agent-endpoint")
echo $CONTENT
echo $EXIT_CODE
local EXIT_CODE="${EXIT_CODE:0-1}"
Expand All @@ -197,24 +197,24 @@ function validate_agent_service() {
export agent_port="9090"
local CONTENT=$(python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --stream)
echo $CONTENT
# local EXIT_CODE=$(validate "$CONTENT" "" "react-agent-endpoint")
# echo $EXIT_CODE
# local EXIT_CODE="${EXIT_CODE:0-1}"
# if [ "$EXIT_CODE" == "1" ]; then
# docker logs react-agent-endpoint
# exit 1
# fi

echo "======================Testing supervisor agent: multi turns ======================"
local EXIT_CODE=$(validate "$CONTENT" "test completed with success" "supervisor-agent-endpoint")
echo $EXIT_CODE
local EXIT_CODE="${EXIT_CODE:0-1}"
if [ "$EXIT_CODE" == "1" ]; then
docker logs supervisor-agent-endpoint
exit 1
fi

# echo "======================Testing supervisor agent: multi turns ======================"
local CONTENT=$(python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --multi-turn --stream)
echo $CONTENT
# local EXIT_CODE=$(validate "$CONTENT" "" "react-agent-endpoint")
# echo $EXIT_CODE
# local EXIT_CODE="${EXIT_CODE:0-1}"
# if [ "$EXIT_CODE" == "1" ]; then
# docker logs react-agent-endpoint
# exit 1
# fi
local EXIT_CODE=$(validate "$CONTENT" "test completed with success" "supervisor-agent-endpoint")
echo $EXIT_CODE
local EXIT_CODE="${EXIT_CODE:0-1}"
if [ "$EXIT_CODE" == "1" ]; then
docker logs supervisor-agent-endpoint
exit 1
fi

}

Expand All @@ -237,22 +237,22 @@ stop_dataprep

cd $WORKPATH/tests

# echo "=================== #1 Building docker images===================="
echo "=================== #1 Building docker images===================="
build_vllm_docker_image
build_dataprep_agent_images

#### for local test
# build_agent_image_local
# echo "=================== #1 Building docker images completed===================="

# echo "=================== #2 Start vllm endpoint===================="
echo "=================== #2 Start vllm endpoint===================="
start_vllm_service_70B
# echo "=================== #2 vllm endpoint started===================="
echo "=================== #2 vllm endpoint started===================="

# echo "=================== #3 Start dataprep and ingest data ===================="
echo "=================== #3 Start dataprep and ingest data ===================="
start_dataprep
ingest_validate_dataprep
# echo "=================== #3 Data ingestion and validation completed===================="
echo "=================== #3 Data ingestion and validation completed===================="

echo "=================== #4 Start agents ===================="
start_agents
Expand Down
16 changes: 8 additions & 8 deletions FinanceAgent/tools/research_agent_tools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ get_company_profile:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
return_output: profile

get_company_news:
Expand All @@ -16,7 +16,7 @@ get_company_news:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
start_date:
type: str
description: start date of the search period for the company's basic financials, yyyy-mm-dd.
Expand All @@ -34,7 +34,7 @@ get_basic_financials_history:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
freq:
type: str
description: reporting frequency of the company's basic financials, such as annual, quarterly.
Expand All @@ -55,7 +55,7 @@ get_basic_financials:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
selected_columns:
type: list
description: List of column names of news to return, should be chosen from 'assetTurnoverTTM', 'bookValue', 'cashRatio', 'currentRatio', 'ebitPerShare', 'eps', 'ev', 'fcfMargin', 'fcfPerShareTTM', 'grossMargin', 'inventoryTurnoverTTM', 'longtermDebtTotalAsset', 'longtermDebtTotalCapital', 'longtermDebtTotalEquity', 'netDebtToTotalCapital', 'netDebtToTotalEquity', 'netMargin', 'operatingMargin', 'payoutRatioTTM', 'pb', 'peTTM', 'pfcfTTM', 'pretaxMargin', 'psTTM', 'ptbv', 'quickRatio', 'receivablesTurnoverTTM', 'roaTTM', 'roeTTM', 'roicTTM', 'rotcTTM', 'salesPerShare', 'sgaToSale', 'tangibleBookValue', 'totalDebtToEquity', 'totalDebtToTotalAsset', 'totalDebtToTotalCapital', 'totalRatio','10DayAverageTradingVolume', '13WeekPriceReturnDaily', '26WeekPriceReturnDaily', '3MonthADReturnStd', '3MonthAverageTradingVolume', '52WeekHigh', '52WeekHighDate', '52WeekLow', '52WeekLowDate', '52WeekPriceReturnDaily', '5DayPriceReturnDaily', 'assetTurnoverAnnual', 'assetTurnoverTTM', 'beta', 'bookValuePerShareAnnual', 'bookValuePerShareQuarterly', 'bookValueShareGrowth5Y', 'capexCagr5Y', 'cashFlowPerShareAnnual', 'cashFlowPerShareQuarterly', 'cashFlowPerShareTTM', 'cashPerSharePerShareAnnual', 'cashPerSharePerShareQuarterly', 'currentDividendYieldTTM', 'currentEv/freeCashFlowAnnual', 'currentEv/freeCashFlowTTM', 'currentRatioAnnual', 'currentRatioQuarterly', 'dividendGrowthRate5Y', 'dividendPerShareAnnual', 'dividendPerShareTTM', 'dividendYieldIndicatedAnnual', 'ebitdPerShareAnnual', 'ebitdPerShareTTM', 'ebitdaCagr5Y', 'ebitdaInterimCagr5Y', 'enterpriseValue', 'epsAnnual', 'epsBasicExclExtraItemsAnnual', 'epsBasicExclExtraItemsTTM', 'epsExclExtraItemsAnnual', 'epsExclExtraItemsTTM', 'epsGrowth3Y', 'epsGrowth5Y', 'epsGrowthQuarterlyYoy', 'epsGrowthTTMYoy', 'epsInclExtraItemsAnnual', 'epsInclExtraItemsTTM', 'epsNormalizedAnnual', 'epsTTM', 'focfCagr5Y', 'grossMargin5Y', 'grossMarginAnnual', 'grossMarginTTM', 'inventoryTurnoverAnnual', 'inventoryTurnoverTTM', 'longTermDebt/equityAnnual', 'longTermDebt/equityQuarterly', 'marketCapitalization', 'monthToDatePriceReturnDaily', 'netIncomeEmployeeAnnual', 'netIncomeEmployeeTTM', 'netInterestCoverageAnnual', 'netInterestCoverageTTM', 'netMarginGrowth5Y', 'netProfitMargin5Y', 'netProfitMarginAnnual', 'netProfitMarginTTM', 'operatingMargin5Y'.
Expand All @@ -72,7 +72,7 @@ analyze_balance_sheet:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
period:
type: str
description: The period of the balance sheets, possible values such as annual, quarterly, ttm. Default is 'annual'.
Expand All @@ -87,7 +87,7 @@ analyze_income_stmt:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
period:
type: str
description: The period of the balance sheets, possible values, such as annual, quarterly, ttm. Default is 'annual'.
Expand All @@ -102,7 +102,7 @@ analyze_cash_flow:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
period:
type: str
description: The period of the balance sheets, possible values, such as annual, quarterly, ttm. Default is 'annual'.
Expand All @@ -117,7 +117,7 @@ get_share_performance:
args_schema:
symbol:
type: str
description: the company name or ticker symbol.
description: the ticker symbol.
end_date:
type: str
description: end date of the search period for the company's basic financials, yyyy-mm-dd.
Expand Down
Loading
Loading