Skip to content

Commit

Permalink
Added new techniques (#810)
Browse files Browse the repository at this point in the history
Fixed up new prompting techniques in decomp + thought generation category
  • Loading branch information
ivanleomk committed Jul 9, 2024
1 parent 3ba2afd commit 35ef440
Show file tree
Hide file tree
Showing 21 changed files with 1,684 additions and 159 deletions.
Binary file added docs/img/analogical_prompting.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 docs/img/faithful_cot_example.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 docs/img/more.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 docs/img/plan_and_solve.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 docs/img/pot.jpeg
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 docs/img/universal_self_consistency.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
142 changes: 138 additions & 4 deletions docs/prompting/decomposition/decomp.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,141 @@
---
title: ""
description: ""
keywords: ""
description: "DECOMP involves using a LLM to break down a complicated task into sub tasks that it has been provided with"
---

[wip]
Decomposed Prompting<sup><a href="https://arxiv.org/pdf/2210.02406">1</a></sup> leverages a Language Model (LLM) to deconstruct a complex task into a series of manageable sub-tasks. Each sub-task is then processed by specific functions, enabling the LLM to handle intricate problems more effectively and systematically.

In the code snippet below, we define a series of data models and functions to implement this approach.

The `derive_action_plan` function generates an action plan using the LLM, which is then executed step-by-step. Each action can be

1. InitialInput: Which represents the chunk of the original prompt we need to process
2. Split : An operation to split strings using a given separator
3. StrPos: An operation to help extract a string given an index
4. Merge: An operation to join a list of strings together using a given character

We can implement this using `instructor` as seen below.

```python hl_lines="57-58"
import instructor
from openai import OpenAI
from pydantic import BaseModel, Field
from typing import Union

client = instructor.from_openai(OpenAI())


class Split(BaseModel):
split_char: str = Field(
description="""This is the character to split
the string with"""
)

def split_chars(self, s: str, c: str):
return s.split(c)


class StrPos(BaseModel):
index: int = Field(
description="""This is the index of the character
we wish to return"""
)

def get_char(self, s: list[str], i: int):
return [c[i] for c in s]


class Merge(BaseModel):
merge_char: str = Field(
description="""This is the character to merge the
inputs we plan to pass to this function with"""
)

def merge_string(self, s: list[str]):
return self.merge_char.join(s)


class Action(BaseModel):
id: int = Field(
description="""Unique Incremental id to identify
this action with"""
)
action: Union[Split, StrPos, Merge]


class ActionPlan(BaseModel):
initial_data: str
plan: list[Action]


def derive_action_plan(task_description: str) -> ActionPlan:
return client.chat.completions.create(
messages=[
{
"role": "system",
"content": """Generate an action plan to help you complete
the task outlined by the user""",
},
{"role": "user", "content": task_description},
],
response_model=ActionPlan,
max_retries=3,
model="gpt-4o",
)


if __name__ == "__main__":
task = """Concatenate the second letter of every word in Jack
Ryan together"""
plan = derive_action_plan(task)
print(plan.model_dump_json(indent=2))
"""
{
"initial_data": "Jack Ryan",
"plan": [
{
"id": 1,
"action": {
"split_char": " "
}
},
{
"id": 2,
"action": {
"index": 1
}
},
{
"id": 3,
"action": {
"merge_char": ""
}
}
]
}
"""

curr = plan.initial_data
cache = {}

for action in plan.plan:
if isinstance(action.action, Split) and isinstance(curr, str):
curr = action.action.split_chars(curr, action.action.split_char)
elif isinstance(action.action, StrPos) and isinstance(curr, list):
curr = action.action.get_char(curr, action.action.index)
elif isinstance(action.action, Merge) and isinstance(curr, list):
curr = action.action.merge_string(curr)
else:
raise ValueError("Unsupported Operation")

print(action, curr)
#> id=1 action=Split(split_char=' ') ['Jack', 'Ryan']
#> id=2 action=StrPos(index=1) ['a', 'y']
#> id=3 action=Merge(merge_char='') ay

print(curr)
#> ay
```

### References

<sup id="ref-1">1</sup>: [Decomposed Prompting: A Modular Approach for Solving Complex Tasks](https://arxiv.org/pdf/2210.02406)
104 changes: 100 additions & 4 deletions docs/prompting/decomposition/faithful_cot.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,103 @@
---
title: ""
description: ""
keywords: ""
description: "Faithful Chain of Thought aims to use multiple reasoning steps to improve the quality of the final outputs"
---

[wip]
Faithful Chain of Thought<sup><a href="https://arxiv.org/pdf/2301.13379">1</a></sup> improves the faithfulness of reasoning chains generated by Language Models by breaking it up into two stages

1. **Translation** : We first translate a user query into a series of reasoning steps. These are a task specific set of steps that we can execute deterministically.
2. **Problem Solving**: We execute our steps and arrive at a final answer that we can derive. This ensures that our Chain Of Thought is able to derive a answer that is consistent with the reasoning steps.

They list a few examples in the paper of what these task-specific steps could be

1. **Math Word Problems** : Python Code that can be executed by an interpreter to derive a final answer
2. **Multi-Hop QA** : This is a multi-step reasoning process. To solve this, they use a mix of python and Datalog ( which is a relation and log programming language ) to arrive at a final answer
3. **Planning** : When trying to generate a plan to solve a user query, they generate a list of symbolic goals in a Programming Language and then call a PDDL Planner to obtain a plan to solve the user's query

![](../../img/faithful_cot_example.png)

In the example below, we show how you can use a LLM to generate python code that can be executed by an Interpreter to arrive at a final answer.

We can implement it in `instructor` as seen below

```python hl_lines="30-45"
import instructor
from openai import OpenAI
from pydantic import BaseModel, Field

client = instructor.from_openai(OpenAI())


class ReasoningStep(BaseModel):
id: int = Field(description="Unique ID")
rationale: list[str] = Field(
description="""Specific sections from prior reasoning
steps or the context that ground this reasoning step"""
)
dependencies: list[int] = Field(
description="""IDs of prior reasoning steps that this
reasoning step depends on"""
)
eval_string: str = Field(
description="""Python Code to execute to generate the
final evaluation"""
)


def generate_reasoning_steps(query: str) -> list[ReasoningStep]:
return client.chat.completions.create(
messages=[
{
"role": "system",
"content": """
You are a world class AI who excels at
generating reasoning steps to answer a
question. You will be given a question
and you will generate a list of reasoning
steps that are needed to answer the
question.
At each point you should either
- declare a variable to be referenced
later on
- combine multiple variables together to
generate a new result that you should
store in another variable
The final answer should be stored in a
variable called `answer`.
""",
},
{"role": "user", "content": query},
],
model="gpt-4o",
response_model=list[ReasoningStep],
)


if __name__ == "__main__":
steps = generate_reasoning_steps(
"""If there are 3 cars in the parking lot and 2 more
cars arrive, how many cars are in the parking lot
after another 2 more arrive?"""
)

code = "\n".join([step.eval_string for step in steps])
print(code)
"""
initial_cars = 3
arriving_cars = 2
cars_after_first_arrival = initial_cars + arriving_cars
final_car_count = cars_after_first_arrival + 2
answer = final_car_count
"""
exec(code)

local_vars = {}
exec(code, {}, local_vars)
print(local_vars.get("answer"))
#> 7
```

### References

<sup id="ref-1">1</sup>: [Faithful Chain-of-Thought Reasoning](https://arxiv.org/pdf/2301.13379)
Loading

0 comments on commit 35ef440

Please sign in to comment.