Skip to content

Commit effed38

Browse files
authored
Optimize prompt for entire learn loop (#1589)
* Adjust prompt and fix cases * adjust summarizeTask & learn prompts; * fix typos & drop duplicate task method; * adjust learn prompts;
1 parent 86ffd17 commit effed38

File tree

4 files changed

+59
-28
lines changed

4 files changed

+59
-28
lines changed

qlib/finco/knowledge.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from pathlib import Path
2+
from jinja2 import Template
3+
from typing import List
4+
25
from qlib.workflow import R
36
from qlib.finco.log import FinCoLog
47
from qlib.finco.llm import APIBackend
5-
from jinja2 import Template
68

79

810
class Knowledge:
@@ -95,7 +97,7 @@ class KnowledgeBase:
9597
Load knowledge, offer brief information of knowledge and common handle interfaces
9698
"""
9799

98-
def __init__(self, init_path=None, topics: list[Topic] = None):
100+
def __init__(self, init_path=None, topics: List[Topic] = None):
99101
self.logger = FinCoLog()
100102
init_path = init_path if init_path else Path.cwd()
101103

@@ -111,7 +113,7 @@ def __init__(self, init_path=None, topics: list[Topic] = None):
111113

112114
self.topics = topics if topics else []
113115

114-
def load(self, path) -> list:
116+
def load(self, path) -> List:
115117
if isinstance(path, str):
116118
path = Path(path)
117119

@@ -131,7 +133,7 @@ def update(self, path):
131133
self.docs = self.brief(self.knowledge)
132134
self.logger.plain_info(f"Update knowledge finished.")
133135

134-
def brief(self, knowledge: list[Knowledge]) -> list:
136+
def brief(self, knowledge: List[Knowledge]) -> List:
135137
docs = []
136138
for k in knowledge:
137139
docs.extend(k.brief())

qlib/finco/prompt_template.yaml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,24 +605,36 @@ SummarizeTask_system : |-
605605
You can add subheadings and paragraphs in Markdown for readability.
606606
You can bold or use other formatting options to highlight keywords in the main text.
607607
You should display images I offered in markdown using the appropriate image format.
608+
Don't list data user doesn't provide.
608609
609610
SummarizeTask_user : |-
610611
Here is my information: '{{information}}'
611612
My intention is: {{user_prompt}}. Please provide me with a summary and recommendation based on my intention and the information I have provided. There are some figures which absolute path are: {{figure_path}}, You must display these images in markdown using the appropriate image format.
612613
613614
SummarizeTask_context_system : |-
614-
Your purpose is to find the important information offered by user and summarize it.
615+
Your purpose is to find out the important information offered by user. You can just show the data provided by user in markdown format.
615616
616617
SummarizeTask_context_user : |-
617618
Here is my information: '{{key}}:{{value}}'
619+
620+
SummarizeTask_metrics_system : |-
621+
Your purpose is to summarize the information by metrics in markdown format.
622+
623+
SummarizeTask_metrics_user : |-
624+
Here is my information: '{{information}}'
618625
Please summarize it.
619626
620627
LearnManager_system : |-
621-
Your task is adjusting system prompt in each task to fulfill user's intention
628+
Your task is adjusting system prompt in each task to fulfill user's intention. If you have no idea how to optimize the system prompt, you can just return the original system prompt.
622629
623630
LearnManager_user : |-
624-
Here is the final summary:\n{{summary}}\n. Brief of this workflow is:{{brief}}\n
625-
Tasks I have run are: {{task_finished}}, \n{{task}}'s system prompt is: {{system}}. \nUser's intention is: {{user_prompt}}. you will adjust it to:
631+
Here is the final summary:\n{{summary}}\n.
632+
Brief of this workflow is:{{brief}}\n
633+
Tasks I have run are: {{task_finished}},\n
634+
{{task}}'s system prompt is: {{system}}.\n
635+
User's intention is: {{user_prompt}}.
636+
If you have no idea how to optimize the system prompt, you can just return the original system prompt.
637+
you will adjust {{task}}'s system prompt to:
626638
627639
Topic_IC : |-
628640
Summarize the influence of parameters on IC: {{docs}}

qlib/finco/task.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,14 @@ def summarize_context_system(self):
776776
def summarize_context_user(self):
777777
return self.prompt_template.get(self.__class__.__name__ + "_context_user")
778778

779+
@property
780+
def summarize_metrics_system(self):
781+
return self.prompt_template.get(self.__class__.__name__ + "_metrics_system")
782+
783+
@property
784+
def summarize_metrics_user(self):
785+
return self.prompt_template.get(self.__class__.__name__ + "_metrics_user")
786+
779787
def execute(self) -> Any:
780788
workspace = self._context_manager.get_context("workspace")
781789
user_prompt = self._context_manager.get_context("user_prompt")
@@ -811,8 +819,15 @@ def _get_value_from_info(info: list, k: str):
811819
recorder = R.get_recorder(experiment_name=workflow_yaml["experiment_name"])
812820
recorder.save_objects(context_summary=context_summary)
813821

822+
prompt_workflow_selection = self.summarize_metrics_user.render(
823+
information=_get_value_from_info(info=record_info, k="metrics"), user_prompt=user_prompt
824+
)
825+
metrics_response = be.build_messages_and_create_chat_completion(
826+
user_prompt=prompt_workflow_selection, system_prompt=self.summarize_metrics_system.render()
827+
)
828+
814829
prompt_workflow_selection = self.user.render(
815-
information=file_info + record_info, figure_path=figure_path, user_prompt=user_prompt
830+
information=file_info + [{"metrics": metrics_response}], figure_path=figure_path, user_prompt=user_prompt
816831
)
817832
response = be.build_messages_and_create_chat_completion(
818833
user_prompt=prompt_workflow_selection, system_prompt=self.system.render()
@@ -856,23 +871,15 @@ def get_info_from_file(self, path) -> List:
856871

857872
def get_info_from_context(self):
858873
context = []
859-
# TODO: get all keys from context?
860-
for key in [
861-
"user_prompt",
862-
"chat_history",
863-
"Dataset_plan",
864-
"Model_plan",
865-
"Record_plan",
866-
"Strategy_plan",
867-
"Backtest_plan",
868-
]:
869-
c = self._context_manager.get_context(key=key)
870-
if c is not None:
871-
c = str(c)
872-
context.append({key: c[: self.__MAX_LENGTH_OF_FILE]})
874+
for key, v in self._context_manager.context.items():
875+
if v is not None:
876+
v = str(v)
877+
context.append({key: v[: self.__MAX_LENGTH_OF_FILE]})
873878
return context
874879

875-
def get_info_from_recorder(self, path, exp_name) -> list:
880+
@staticmethod
881+
def get_info_from_recorder(path, exp_name) -> list:
882+
path = Path(path)
876883
path = path if path.name == "mlruns" else path.joinpath("mlruns")
877884

878885
R.set_uri(Path(path).as_uri())

qlib/finco/workflow.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import copy
33
import shutil
44
from pathlib import Path
5+
from typing import List
56

67
from qlib.finco.task import WorkflowTask, SummarizeTask, TrainTask
78
from qlib.finco.prompt_template import PromptTemplate, Template
@@ -188,22 +189,31 @@ def run(self, prompt):
188189

189190
def learn(self):
190191
workspace = self.wm.context.get_context("workspace")
192+
193+
def _drop_duplicate_task(_task: List):
194+
unique_task = {}
195+
for obj in _task:
196+
task_name = obj.__class__.__name__
197+
if task_name not in unique_task:
198+
unique_task[task_name] = obj
199+
return list(unique_task.values())
200+
191201
# one task maybe run several times in workflow
192-
task_finished = list(set(self.wm.context.get_context("task_finished")))
202+
task_finished = _drop_duplicate_task(self.wm.context.get_context("task_finished"))
193203

194204
user_prompt = self.wm.context.get_context("user_prompt")
195205
summary = self.wm.context.get_context("summary")
196206

197207
for task in task_finished:
198208
prompt_workflow_selection = self.wm.prompt_template.get(f"{self.__class__.__name__}_user").render(
199209
summary=summary, brief=self.knowledge_base.query_topics(),
200-
task_finished=[str(task) for task in task_finished],
201-
task=task.__class__, system=task.system, user_prompt=user_prompt
210+
task_finished=[str(t) for t in task_finished],
211+
task=task.__class__.__name__, system=task.system.render(), user_prompt=user_prompt
202212
)
203213

204214
response = APIBackend().build_messages_and_create_chat_completion(
205215
user_prompt=prompt_workflow_selection,
206-
system_prompt=self.wm.prompt_template.get(f"{self.__class__.__name__}_user").render()
216+
system_prompt=self.wm.prompt_template.get(f"{self.__class__.__name__}_system").render()
207217
)
208218

209219
# todo: response assertion

0 commit comments

Comments
 (0)