File size: 5,722 Bytes
522e6c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

import yaml
from pocketflow import Node

from pf_agent.utils import callLLM, callWebSearch, callWikipediaSearch

class Decide(Node):
    def setLogger(self,logger):
        self.logger = logger

    def prep(self,shared):
        context = shared.get("context","No previous search")
        question = shared["question"]
        return question,context
    
    def exec(self,inputs):
        question,context = inputs
        prompt = f"""
### CONTEXT
You are a research assistant and I need your help to answer the following question:
Question: {question}
Previous research: {context}

### ACTION SPACE
[1] search
  Description: Look up more information on the web
  Parameters:
  - query (str): keywords to run the search on the web 

[2] wikipedia
  Description: Look up for more information in the wikipedia in English
  Parameters:
  - query (str): keywords to run the search in the English wikipedia

[3] answer
  Description: Answer the question with current knowledge
  Parameters:
  - answer (str): final answer to the question


### NEXT ACTION
Decide the next action based on the context and available actions.
Return your response in the following format:
```yaml
thinking: |
  <your step-by-step reasoning process>
action: search OR answer OR wikipedia
reason: <why you choose this action>
parameters: <yaml containing the parameter or parameters required to execute the action selected in yaml format indicating parameter name and value>
```
IMPORTANT: Make sure to:
1. Use proper indentation (4 spaces) for all multi-line fields
2. Use the | character for multi-line text fields
3. Keep single-line fields without the | character
"""
        self.logger.debug(f"=== Calling LLM to DECIDE")
        self.logger.debug(f"Context: {context}")
        response = callLLM(prompt)
        yaml_str = response.replace("|","") #.split("```yaml")[1].split("```")[0].strip()  #.replace("|","") #
        decision = yaml.safe_load(yaml_str)
        self.logger.debug("LLM responded")
        self.logger.debug(f"Thinking: {decision['thinking']}")
        self.logger.debug(f"Action: {decision['action']} {decision['parameters']}")
        return decision
    
    def post(self,shared,prep_res,exec_res):
        if exec_res["action"] != "answer":
            shared["parameters"] = exec_res["parameters"]
        return exec_res["action"]
    

class Search(Node):
    def setLogger(self,logger):
        self.logger = logger

    def prep(self,shared):
        if type(shared["parameters"]) == type([]):
            for p in shared["parameters"]:
                if 'query' in p:
                    return p['query']
        else:
            return shared["parameters"]["query"]
        return "invalid query"
    
    def exec(self,search_query):
        self.logger.debug("=== Searching the web")
        self.logger.debug(f"Search query: {search_query}")
        results = callWebSearch(search_query)
        self.logger.debug(f"Results: {results}")
        return results
    
    def post(self,shared,prep_res,exec_res):
        previous = shared.get("context","")
        shared["context"] = f"{previous}\n\nSEARCH: {shared['parameters']}\n\nRESULTS: {exec_res}"
        return "decide"
    
class Wikipedia(Node):
    def setLogger(self,logger):
        self.logger = logger

    def prep(self,shared):
        if type(shared["parameters"]) == type([]):
            for p in shared["parameters"]:
                if 'query' in p:
                    return shared["question"],p['query']
        else:
            return shared["question"],shared["parameters"]["query"]
        return shared["question"],"invalid query"
    
    def exec(self,prepared):
        question,search_query = prepared
        self.logger.debug("=== Searching wikipedia")
        self.logger.debug(f"Search query: {search_query}")
        results = callWikipediaSearch(search_query)
        self.logger.debug(f"Results: {results}")
        prompt = f'''You are my research assistant and I need your help to answer the following question: {question}

From my previous research I have found a Wikipedia page that could contain the answer or, at least, useful information for further research. 
Take a careful look at it. Ignore any HTML markup you may find. You will find sections, paragraphs, etc. formated as plain text and tables
as comma-separated values. The answer or any useful information could be anywhere.
If the text contains the answer, give it to me. 
If it is not, extract relevant information that could me help find it elsewere. 
Please don't include information not directly related to the question.
It is very important that in any case, you are concise, brief and stick to the question being asked. Find the text below:
{results}'''
        response = callLLM(prompt)
        return response
    
    def post(self,shared,prep_res,exec_res):
        previous = shared.get("context","")
        shared["context"] = f"{previous}\n\nWIKIPEDIA RESULTS: {shared['parameters']}\n\nRESULTS: {exec_res}"
        return "decide"    

class Answer(Node):
    def setLogger(self,logger):
        self.logger = logger

    def prep(self,shared):
        return shared["question"],shared.get("context","")
    
    def exec(self,inputs):
        question,context = inputs
        prompt = f'''
### CONTEXT
Based on the following information, answer the question.
Question: {question}
Research: {context}

### YOUR ANSWER
Provide a comprehensive answer using research results
'''
        response = callLLM(prompt)
        self.logger.debug(f"### CALLING LLM\n{prompt}\n### LLM RESPONSE\n{response}\n\n##########\n\n")
        return response
    
    def post(self,shared,prep_res,exec_res):
        shared["answer"] = exec_res