Paper Recreations¶
This library is a collection of tools for PDDL model generation extracted from natural language driven by large language models. This library is an expansion from the survey paper “LLMs as Planning Formalizers: A Survey for Leveraging Large Language Models to Construct Automated Planning Models”.
The following are papers that have been reconstructed so far. This list will be updated in the future.
Papers that have been reconstructed so far and can be found in the Github repo. To see full list of current up-to-date papers in literature, please visit (see Paper Feed). This list will be continuously updated.
Below is L2P code reconstruction of “action-by-action algorithm” from “Leveraging Pre-trained Large Language Models to Construct and Utilize World Models for Model-based Task Planning”:
1DOMAINS = [
2"household",
3"logistics",
4"tyreworld",
5]
6
7def construct_action(
8 model: BaseLLM,
9 act_pred_prompt: str,
10 action_name: str,
11 predicates: list[Predicate],
12 types: dict[str,str],
13 max_iter: int = 8,
14 syntax_validator: bool = True
15 ):
16 """
17 This is the inner function of the overall `Action-by-action` algorithm. Specifically,
18 this function generates a single action from the list of actions and new predicates created.
19 Process looping until it abides the custom syntax validation check.
20
21 Args:
22 - model (BaseLLM): the large language model to be inferenced
23 - act_pred_prompt (str): contains information of action and format creation passed to LLM
24 - action_name (str): current action to be generated
25 - predicates (list[Predicate]): current list of predicates generated
26 - types (dict[str,str]): domain types - used for validation checks
27 - max_iter (int): max attempts of generating action (defaults at 8)
28 - syntax_validator (bool): flag if syntax checker is on (defaults to True)
29
30 Returns:
31 - action (Action): action data type containing parameters, preconditions, and effects
32 - predicates (list[Predicate]): list of updated predicates
33 - llm_response (str): original LLM output
34 """
35
36 # better format for LLM to interpret
37 predicate_str = "\n".join([f"- {pred['clean']}" for pred in predicates])
38
39 # syntax validator check
40 if syntax_validator:
41 validator = SyntaxValidator()
42 validator.unsupported_keywords = []
43
44 validator.error_types = [
45 'validate_header', 'validate_duplicate_headers', 'validate_unsupported_keywords',
46 'validate_params', 'validate_duplicate_predicates', 'validate_types_predicates',
47 'validate_format_predicates', 'validate_usage_action'
48 ]
49
50 else: validator = None
51
52 no_syntax_error = False
53 i_iter = 0
54
55 # generate single action in loop, loops until no syntax error or max iters reach
56 while not no_syntax_error and i_iter < max_iter:
57 i_iter += 1
58 print(f'[INFO] generating PDDL of action: `{action_name}`')
59 try:
60 # L2P usage for extracting actions and predicates
61 action, new_predicates, llm_response, validation_info = (
62 domain_builder.formalize_pddl_action(
63 model=model,
64 domain_desc="",
65 prompt_template=act_pred_prompt,
66 action_name=action_name,
67 predicates=predicates,
68 types=types,
69 extract_new_preds=True,
70 syntax_validator=validator,
71 )
72 )
73
74 # retrieve validation check and error message
75 no_error, error_msg = validation_info
76
77 except Exception as e:
78 no_error = False
79 error_msg = str(e)
80
81 # if error exists, swap templates and return feedback message
82 if not no_error:
83 with open("paper_reconstructions/llm+dm/domains/error_prompt.txt") as f:
84 error_template = f.read().strip()
85 error_prompt = error_template.replace("{action_name}", action_name)
86 error_prompt = error_prompt.replace("{predicates}", predicate_str)
87 error_prompt = error_prompt.replace("{error_msg}", error_msg)
88 error_prompt = error_prompt.replace("{llm_response}", llm_response)
89
90 act_pred_prompt = error_prompt
91
92 # break the loop if no syntax error was made
93 else:
94 no_syntax_error = True
95
96 # if max attempts reached and there are still errors, print out error on action.
97 if not no_syntax_error:
98 print(f'[WARNING] syntax error remaining in the action model: {action_name}')
99
100 predicates.extend(new_predicates) # extend the predicate list
101
102 return action, predicates, llm_response
103
104
105
106def run_llm_dm(
107 model: BaseLLM,
108 domain: str = "household",
109 max_iter: int = 2,
110 max_attempts: int = 8
111 ):
112 """
113 This is the main function for `construct_action_models.py` component of LLM+DM paper. Specifically, it generates
114 actions (params, preconditions, effects) and predicates to create an overall PDDL domain file.
115
116 Args:
117 - model (BaseLLM): the large language model to be inferenced
118 - domain (str): choice of domain to task (defaults to `household`)
119 - max_iter: outer loop iteration; # of overall action list resets (defaults to 2)
120 - max_attempts: # of attempts to generate a single actions properly (defaults to 8)
121 """
122
123 # load in assumptions
124 prompt_template = load_file("paper_reconstructions/llm+dm/domains/pddl_prompt.txt")
125 domain_desc_str = load_file(f"paper_reconstructions/llm+dm/domains/{domain}/domain_desc.txt")
126
127 if '{domain_desc}' in prompt_template:
128 prompt_template = prompt_template.replace('{domain_desc}', domain_desc_str)
129
130 action_model = load_file(f"paper_reconstructions/llm+dm/domains/{domain}/action_model.json")
131 hierarchy_reqs = load_file(f"paper_reconstructions/llm+dm/domains/{domain}/hierarchy_requirements.json")
132
133 reqs = [":" + r for r in hierarchy_reqs['requirements']]
134 types = format_types(get_types(hierarchy_reqs))
135
136 actions = list(action_model.keys())
137 action_list = list()
138 predicates = list()
139
140 """
141 Action-by-action algorithm: iteratively generates an action model (parameters, precondition, effects) one at a time. At the same time,
142 it is generating new predicates if needed and is added to a dynamic list. At the end of the iterations, it is ran again once more to
143 create the action models agains, but with using the new predicate list. This algorithm can iterative as many times as needed until no
144 new predicates are added to the list. This is an action model refinement algorithm, that refines itself by a growing predicate list.
145 """
146
147 # outer loop that resets all action creation to be conditioned on updated predicate list
148 for i_iter in range(max_iter):
149 prev_predicate_list = deepcopy(predicates) # copy previous predicate list
150 action_list = []
151
152 # inner loop that generates a single action along with its predicates
153 for _, action in enumerate(actions):
154
155 # retrieve prompt for specific action
156 action_prompt, _ = get_action_prompt(prompt_template, action_model[action])
157
158 # retrieve prompt for current predicate list
159 predicate_prompt = get_predicate_prompt(predicates)
160
161 # assemble template
162 action_predicate_prompt = f'{action_prompt}\n\n{predicate_prompt}'
163 action_predicate_prompt += '\n\nParameters:'
164
165 # create single action + corresponding predicates
166 action, predicates, llm_response = construct_action(
167 model, action_predicate_prompt, action, predicates, types, max_attempts, True)
168
169 # add action to current list + remove any redundant predicates
170 action_list.append(action)
171 predicates = prune_predicates(predicates, action_list)
172
173 gen_done = False
174 if len(prev_predicate_list) == len(predicates):
175 print(f'[INFO] iter {i_iter} | no new predicate has been defined, will terminate the process')
176 gen_done = True
177
178 if gen_done:
179 break
180
181 # generate PDDL format
182 pddl_domain = domain_builder.generate_domain(
183 domain_name=domain,
184 requirements=reqs,
185 types=types,
186 predicates=predicates,
187 actions=action_list,
188 )
189
190
191# helper functions
192def get_action_prompt(prompt_template: str, action_desc: str):
193 """Creates prompt for specific action."""
194
195 action_desc_prompt = action_desc['desc']
196 for i in action_desc['extra_info']:
197 action_desc_prompt += ' ' + i
198
199 full_prompt = str(prompt_template) + ' ' + action_desc_prompt
200
201 return full_prompt, action_desc_prompt
202
203
204def get_predicate_prompt(predicates):
205 """Creates prompt for list of available predicates generated so far."""
206
207 predicate_prompt = 'You can create and define new predicates, but you may also reuse the following predicates:\n'
208 if len(predicates) == 0:
209 predicate_prompt += 'No predicate has been defined yet'
210 else:
211 predicate_prompt += "\n".join([f"- {pred['clean']}" for pred in predicates])
212 return predicate_prompt
213
214
215def get_types(hierarchy_requirements):
216 """Creates proper dictionary types (for L2P) from JSON format."""
217
218 types = {
219 name: description
220 for name, description in hierarchy_requirements["hierarchy"].items()
221 if name
222 }
223 return types