Skip to content

Commit 8aa96c6

Browse files
Update FinanceAgent v1.3 (#1819)
Signed-off-by: minmin-intel <minmin.hou@intel.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent a7ef833 commit 8aa96c6

13 files changed

+123
-73
lines changed

FinanceAgent/README.md

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22

33
## 1. Overview
44

5-
The architecture of this Finance Agent example is shown in the figure below. The agent has 3 main functions:
5+
The architecture of this Finance Agent example is shown in the figure below. The agent is a hierarchical multi-agent system and has 3 main functions:
66

7-
1. Summarize long financial documents and provide key points.
8-
2. Answer questions over financial documents, such as SEC filings.
9-
3. Conduct research of a public company and provide an investment report of the company.
7+
1. Summarize long financial documents and provide key points (using OPEA DocSum).
8+
2. Answer questions over financial documents, such as SEC filings (using a worker agent).
9+
3. Conduct research of a public company and provide an investment report of the company (using a worker agent).
10+
11+
The user interacts with the supervisor agent through the graphical UI. The supervisor agent gets the requests from the user and dispatches tasks to worker agents or to the summarization microservice. The user can also uploads documents through the UI.
1012

1113
![Finance Agent Architecture](assets/finance_agent_arch.png)
1214

15+
The architectural diagram of the `dataprep` microservice is shown below. We use [docling](https://github.com/docling-project/docling) to extract text from PDFs and URLs into markdown format. Both the full document content and tables are extracted. We then use an LLM to extract metadata from the document, including the company name, year, quarter, document type, and document title. The full document markdown then gets chunked, and LLM is used to summarize each chunk, and the summaries are embedded and saved to a vector database. Each table is also summarized by LLM and the summaries are embedded and saved to the vector database. The chunks and tables are also saved into a KV store. The pipeline is designed as such to improve retrieval accuracy of the `search_knowledge_base` tool used by the Question Answering worker agent.
16+
17+
![dataprep architecture](assets/fin_agent_dataprep.png)
18+
1319
The `dataprep` microservice can ingest financial documents in two formats:
1420

1521
1. PDF documents stored locally, such as SEC filings saved in local directory.
@@ -20,31 +26,39 @@ Please note:
2026
1. Each financial document should be about one company.
2127
2. URLs ending in `.htm` are not supported.
2228

29+
The Question Answering worker agent uses `search_knowledge_base` tool to get relevant information. The tool uses a dense retriever and a BM25 retriever to get many pieces of information including financial statement tables. Then an LLM is used to extract useful information related to the query from the retrieved documents. Refer to the diagram below. We found that using this method significantly improves agent performance.
30+
31+
![finqa search tool arch](assets/finqa_tool.png)
32+
2333
## 2. Getting started
2434

2535
### 2.1 Download repos
2636

2737
```bash
2838
mkdir /path/to/your/workspace/
2939
export WORKDIR=/path/to/your/workspace/
30-
genaicomps
31-
genaiexamples
40+
cd $WORKDIR
41+
git clone https://github.com/opea-project/GenAIExamples.git
3242
```
3343

3444
### 2.2 Set up env vars
3545

3646
```bash
3747
export HF_CACHE_DIR=/path/to/your/model/cache/
3848
export HF_TOKEN=<you-hf-token>
39-
49+
export FINNHUB_API_KEY=<your-finnhub-api-key> # go to https://finnhub.io/ to get your free api key
50+
export FINANCIAL_DATASETS_API_KEY=<your-api-key> # go to https://docs.financialdatasets.ai/ to get your free api key
4051
```
4152

42-
### 2.3 Build docker images
53+
### 2.3 [Optional] Build docker images
4354

44-
Build docker images for dataprep, agent, agent-ui.
55+
Only needed when docker pull failed.
4556

4657
```bash
47-
cd GenAIExamples/FinanceAgent/docker_image_build
58+
cd $WORKDIR/GenAIExamples/FinanceAgent/docker_image_build
59+
# get GenAIComps repo
60+
git clone https://github.com/opea-project/GenAIComps.git
61+
# build the images
4862
docker compose -f build.yaml build --no-cache
4963
```
5064

@@ -92,6 +106,8 @@ python $WORKPATH/tests/test_redis_finance.py --port 6007 --test_option get
92106

93107
### 3.3 Launch the multi-agent system
94108

109+
The command below will launch 3 agent microservices, 1 docsum microservice, 1 UI microservice.
110+
95111
```bash
96112
# inside $WORKDIR/GenAIExamples/FinanceAgent/docker_compose/intel/hpu/gaudi/
97113
bash launch_agents.sh
@@ -115,14 +131,14 @@ prompt="generate NVDA financial research report"
115131
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"
116132
```
117133

118-
Supervisor ReAct Agent:
134+
Supervisor Agent single turns:
119135

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

125-
Supervisor ReAct Agent Multi turn:
141+
Supervisor Agent multi turn:
126142

127143
```bash
128144
python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --multi-turn --stream
@@ -134,12 +150,32 @@ python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervis
134150
The UI microservice is launched in the previous step with the other microservices.
135151
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.
136152

137-
1. `create Admin Account` with a random value
153+
1. Create Admin Account with a random value
154+
155+
2. Enter the endpoints in the `Connections` settings
156+
157+
First, click on the user icon in the upper right corner to open `Settings`. Click on `Admin Settings`. Click on `Connections`.
158+
159+
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.
160+
161+
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.
162+
163+
You should see screen like the screenshot below when the settings are done.
164+
165+
![opea-agent-setting](assets/ui_connections_settings.png)
166+
167+
3. Upload documents with UI
168+
169+
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 an url in 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.
170+
171+
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.
172+
173+
![upload-doc-ui](assets/upload_doc_ui.png)
138174

139-
2. use an opea agent endpoint, for example, the `Research Agent` endpoint `http://$ip_address:9096/v1`, which is a openai compatible api
175+
4. Test agent with UI
140176

141-
![opea-agent-setting](assets/opea-agent-setting.png)
177+
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.
142178

143-
3. test opea agent with ui
179+
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.
144180

145181
![opea-agent-test](assets/opea-agent-test.png)
103 KB
Loading
1.72 KB
Loading

FinanceAgent/assets/finqa_tool.png

82.2 KB
Loading
Loading

FinanceAgent/assets/upload_doc_ui.png

105 KB
Loading

FinanceAgent/docker_compose/intel/hpu/gaudi/compose.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ services:
4747
ip_address: ${ip_address}
4848
strategy: react_llama
4949
with_memory: false
50-
recursion_limit: ${recursion_limit_worker}
50+
recursion_limit: 25
5151
llm_engine: vllm
5252
HUGGINGFACEHUB_API_TOKEN: ${HUGGINGFACEHUB_API_TOKEN}
5353
llm_endpoint_url: ${LLM_ENDPOINT_URL}
@@ -68,7 +68,7 @@ services:
6868
container_name: supervisor-agent-endpoint
6969
depends_on:
7070
- worker-finqa-agent
71-
# - worker-research-agent
71+
- worker-research-agent
7272
volumes:
7373
- ${TOOLSET_PATH}:/home/user/tools/
7474
- ${PROMPT_PATH}:/home/user/prompts/

FinanceAgent/docker_image_build/build.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,3 @@ services:
2020
https_proxy: ${https_proxy}
2121
no_proxy: ${no_proxy}
2222
image: ${REGISTRY:-opea}/agent:${TAG:-latest}
23-
# agent-ui:
24-
# build:
25-
# context: ../ui
26-
# dockerfile: ./docker/Dockerfile
27-
# extends: agent
28-
# image: ${REGISTRY:-opea}/agent-ui:${TAG:-latest}

FinanceAgent/prompts/research_prompt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
4. Provide stock performance, because the financial report is used for stock investment analysis.
3434
5. Read the execution history if any to understand the tools that have been called and the information that has been gathered.
3535
6. Reason about the information gathered so far and decide if you can answer the question or if you need to call more tools.
36+
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.
3637
3738
**Output format:**
3839
You should output your thought process:

FinanceAgent/tests/test.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ def process_request(url, query, is_stream=False):
1818
else:
1919
for line in resp.iter_lines(decode_unicode=True):
2020
print(line)
21-
ret = None
21+
ret = "Done"
2222

2323
resp.raise_for_status() # Raise an exception for unsuccessful HTTP status codes
2424
return ret
2525
except requests.exceptions.RequestException as e:
26-
ret = f"An error occurred:{e}"
27-
return None
26+
ret = f"ERROR OCCURRED IN TEST:{e}"
27+
return ret
2828

2929

3030
def test_worker_agent(args):
@@ -35,13 +35,19 @@ def test_worker_agent(args):
3535
query = {"role": "user", "messages": args.prompt, "stream": "false", "tool_choice": args.tool_choice}
3636
ret = process_request(url, query)
3737
print("Response: ", ret)
38+
if "ERROR OCCURRED IN TEST" in ret.lower():
39+
print("Error in response, please check the server.")
40+
return "ERROR OCCURRED IN TEST"
41+
else:
42+
return "test completed with success"
3843

3944

4045
def add_message_and_run(url, user_message, thread_id, stream=False):
4146
print("User message: ", user_message)
4247
query = {"role": "user", "messages": user_message, "thread_id": thread_id, "stream": stream}
4348
ret = process_request(url, query, is_stream=stream)
4449
print("Response: ", ret)
50+
return ret
4551

4652

4753
def test_chat_completion_multi_turn(args):
@@ -51,27 +57,38 @@ def test_chat_completion_multi_turn(args):
5157
# first turn
5258
print("===============First turn==================")
5359
user_message = "Key takeaways of Gap's 2024 Q4 earnings call?"
54-
add_message_and_run(url, user_message, thread_id, stream=args.stream)
60+
ret = add_message_and_run(url, user_message, thread_id, stream=args.stream)
61+
if "ERROR OCCURRED IN TEST" in ret:
62+
print("Error in response, please check the server.")
63+
return "ERROR OCCURRED IN TEST"
5564
print("===============End of first turn==================")
5665

5766
# second turn
5867
print("===============Second turn==================")
5968
user_message = "What was Gap's forecast for 2025?"
60-
add_message_and_run(url, user_message, thread_id, stream=args.stream)
69+
ret = add_message_and_run(url, user_message, thread_id, stream=args.stream)
70+
if "ERROR OCCURRED IN TEST" in ret:
71+
print("Error in response, please check the server.")
72+
return "ERROR OCCURRED IN TEST"
6173
print("===============End of second turn==================")
74+
return "test completed with success"
6275

6376

6477
def test_supervisor_agent_single_turn(args):
6578
url = f"http://{args.ip_addr}:{args.ext_port}/v1/chat/completions"
6679
query_list = [
6780
"What was Gap's revenue growth in 2024?",
6881
"Can you summarize Costco's 2025 Q2 earnings call?",
69-
# "Should I increase investment in Costco?",
82+
"Should I increase investment in Johnson & Johnson?",
7083
]
7184
for query in query_list:
7285
thread_id = f"{uuid.uuid4()}"
73-
add_message_and_run(url, query, thread_id, stream=args.stream)
86+
ret = add_message_and_run(url, query, thread_id, stream=args.stream)
87+
if "ERROR OCCURRED IN TEST" in ret:
88+
print("Error in response, please check the server.")
89+
return "ERROR OCCURRED IN TEST"
7490
print("=" * 50)
91+
return "test completed with success"
7592

7693

7794
if __name__ == "__main__":
@@ -89,10 +106,12 @@ def test_supervisor_agent_single_turn(args):
89106

90107
if args.agent_role == "supervisor":
91108
if args.multi_turn:
92-
test_chat_completion_multi_turn(args)
109+
ret = test_chat_completion_multi_turn(args)
93110
else:
94-
test_supervisor_agent_single_turn(args)
111+
ret = test_supervisor_agent_single_turn(args)
112+
print(ret)
95113
elif args.agent_role == "worker":
96-
test_worker_agent(args)
114+
ret = test_worker_agent(args)
115+
print(ret)
97116
else:
98117
raise ValueError("Invalid agent role")

FinanceAgent/tests/test_compose_on_gaudi.sh

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ function validate_agent_service() {
181181
# # test worker research agent
182182
echo "======================Testing worker research agent======================"
183183
export agent_port="9096"
184-
prompt="generate NVDA financial research report"
184+
prompt="Johnson & Johnson"
185185
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")
186-
local EXIT_CODE=$(validate "$CONTENT" "NVDA" "research-agent-endpoint")
186+
local EXIT_CODE=$(validate "$CONTENT" "Johnson" "research-agent-endpoint")
187187
echo $CONTENT
188188
echo $EXIT_CODE
189189
local EXIT_CODE="${EXIT_CODE:0-1}"
@@ -197,24 +197,24 @@ function validate_agent_service() {
197197
export agent_port="9090"
198198
local CONTENT=$(python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --stream)
199199
echo $CONTENT
200-
# local EXIT_CODE=$(validate "$CONTENT" "" "react-agent-endpoint")
201-
# echo $EXIT_CODE
202-
# local EXIT_CODE="${EXIT_CODE:0-1}"
203-
# if [ "$EXIT_CODE" == "1" ]; then
204-
# docker logs react-agent-endpoint
205-
# exit 1
206-
# fi
207-
208-
echo "======================Testing supervisor agent: multi turns ======================"
200+
local EXIT_CODE=$(validate "$CONTENT" "test completed with success" "supervisor-agent-endpoint")
201+
echo $EXIT_CODE
202+
local EXIT_CODE="${EXIT_CODE:0-1}"
203+
if [ "$EXIT_CODE" == "1" ]; then
204+
docker logs supervisor-agent-endpoint
205+
exit 1
206+
fi
207+
208+
# echo "======================Testing supervisor agent: multi turns ======================"
209209
local CONTENT=$(python3 $WORKDIR/GenAIExamples/FinanceAgent/tests/test.py --agent_role "supervisor" --ext_port $agent_port --multi-turn --stream)
210210
echo $CONTENT
211-
# local EXIT_CODE=$(validate "$CONTENT" "" "react-agent-endpoint")
212-
# echo $EXIT_CODE
213-
# local EXIT_CODE="${EXIT_CODE:0-1}"
214-
# if [ "$EXIT_CODE" == "1" ]; then
215-
# docker logs react-agent-endpoint
216-
# exit 1
217-
# fi
211+
local EXIT_CODE=$(validate "$CONTENT" "test completed with success" "supervisor-agent-endpoint")
212+
echo $EXIT_CODE
213+
local EXIT_CODE="${EXIT_CODE:0-1}"
214+
if [ "$EXIT_CODE" == "1" ]; then
215+
docker logs supervisor-agent-endpoint
216+
exit 1
217+
fi
218218

219219
}
220220

@@ -237,22 +237,22 @@ stop_dataprep
237237

238238
cd $WORKPATH/tests
239239

240-
# echo "=================== #1 Building docker images===================="
240+
echo "=================== #1 Building docker images===================="
241241
build_vllm_docker_image
242242
build_dataprep_agent_images
243243

244244
#### for local test
245245
# build_agent_image_local
246246
# echo "=================== #1 Building docker images completed===================="
247247

248-
# echo "=================== #2 Start vllm endpoint===================="
248+
echo "=================== #2 Start vllm endpoint===================="
249249
start_vllm_service_70B
250-
# echo "=================== #2 vllm endpoint started===================="
250+
echo "=================== #2 vllm endpoint started===================="
251251

252-
# echo "=================== #3 Start dataprep and ingest data ===================="
252+
echo "=================== #3 Start dataprep and ingest data ===================="
253253
start_dataprep
254254
ingest_validate_dataprep
255-
# echo "=================== #3 Data ingestion and validation completed===================="
255+
echo "=================== #3 Data ingestion and validation completed===================="
256256

257257
echo "=================== #4 Start agents ===================="
258258
start_agents

0 commit comments

Comments
 (0)