Skip to content

Commit

Permalink
Improved websearch
Browse files Browse the repository at this point in the history
  • Loading branch information
Maximilian-Winter committed May 26, 2024
1 parent f591946 commit d4038d5
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 21 deletions.
89 changes: 89 additions & 0 deletions examples/results/research_ai_agent_reasoning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
Subject: Techniques used to enable complex reasoning in LLM AI agents
---

The following research report provides an overview of the techniques being developed and employed to enable complex reasoning in Large Language Model (LLM) AI agents. The information is based on the insights gathered from several web resources, including surveys, reviews, and articles.

## Background

Large Language Models (LLMs), such as GPT-4, have made significant strides in natural language understanding and generation. However, they face challenges such as multimodality, human value alignment, hallucinations, and evaluation when it comes to complex reasoning tasks. To address these limitations, researchers and developers are exploring the design of autonomous agents that leverage external data, supplementary tools, and innovative prompting techniques to enhance the reasoning capabilities of LLMs.

## Key Techniques

### Chain-of-thought Prompting (CoT)

This technique encourages LLMs to generate intermediate reasoning steps before arriving at a final answer, particularly useful for complex problems. CoT prompts guide the model to think aloud and provide an explicit explanation of their thought process.

Example: For a math problem like "What is the sum of the consecutive numbers starting from 1 up to 100?", a CoT prompt might look like this:

Q: What is the sum of the consecutive numbers starting from 1 up to 100?
A: Let's think step by step.
------ (LLMs Output)
First, we need to find the last number in the sequence, which is 100.
The sum of a consecutive sequence can be found by the formula (n/2)*(first number + last number) where n is the total number of terms.
So, we have (100/2)*(1+100), which simplifies to 50*101.
Therefore, the sum is 5050.

### Self-consistency with CoT

This approach generates multiple reasoning paths and answers for the same question and then selects the most common answer across these paths.

Example: For a question about rainfall, the model might generate different chains of thought, and the most common answer is selected for consistency.

### Tree-of-thought (ToT) Prompting

This technique represents the reasoning process as a tree structure, with branches representing different lines of reasoning.

Example: For a multi-step logic puzzle, ToT might involve branching out possibilities like this:

Q: Start at the root: What is the color of the bear?
------ A: Branch 1: If the bear is in the North Pole, it must be white because polar bears live there.
Branch 2: If the bear is in the forest, it could be brown or black.
Conclusion: Given the additional information that the bear is in the North Pole, we follow Branch 1 and determine the bear is white.

### Reasoning via Planning (RAP)

This technique generates a plan of action based on given goals and constraints to solve a problem.

Example: For a cooking recipe, RAP could generate a plan like this:

Goal: Bake a chocolate cake.
Step 1: Gather ingredients - flour, sugar, cocoa powder, etc.
Step 2: Preheat the oven to 350°F.
Step 3: Mix dry ingredients.
...
Step n: Bake for 30 minutes and let cool.

### ReAct

This prompting technique helps LLMs not only reason about a problem but also take actions like interacting with an API or a database, based on the reasoning process.

Example: If tasked with finding the weather forecast, a ReAct prompt might look like this:

First, determine the user's location.
Next, access the weather API with the location data.
Then, retrieve the forecast information and present it to the user in a readable format.

### Self-Refine

This approach leverages a cyclical process of self-improvement, enabling the model to enhance its own outputs autonomously through iterative self-assessment (feedback).

Example: An example application of the Self-refine method could be in generating a summary of a complex article.

### Reflexion

This innovative approach enhances language agents by using linguistic feedback as a means of reinforcement, diverging from conventional practice.

### Language Agent Tree Search (LATS)

This strategy combines language models with tree search algorithms to explore a large number of potential actions and outcomes, particularly powerful in game-playing scenarios or situations with a wide range of possible decisions.

## Conclusion

These techniques represent significant leaps forward in the capabilities of LLMs to perform more complex reasoning tasks and interact with their environment in meaningful ways. As research continues and these models evolve, we can expect even more sophisticated prompting methods to emerge, further closing the gap between artificial and human intelligence. The design of autonomous agents that leverage external data, supplementary tools, and innovative prompting techniques will enable LLMs to accomplish complex goals that require enhanced reasoning, planning, and tool execution capabilities.

Sources:
https://arxiv.org/html/2404.11584v1
https://arxiv.org/html/2404.04442v1
https://medium.com/the-modern-scientist/a-complete-guide-to-llms-based-autonomous-agents-part-i-69515c016792
https://llms-blog.medium.com/unlocking-advanced-reasoning-in-large-language-models-a-deep-dive-into-innovative-prompting-f3d8c2530831
16 changes: 8 additions & 8 deletions src/llama_cpp_agent/llm_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,36 +414,36 @@ def get_response_role_and_completion(
if structured_output_settings.add_thoughts_and_reasoning_field and self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += function_calling_thoughts_and_reasoning_json_schema + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider) + "\n</function-calling-instructions>"
elif not structured_output_settings.add_thoughts_and_reasoning_field and self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += function_calling_without_thoughts_and_reasoning_json_schema + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider)+ "\n</function-calling-instructions>"
elif structured_output_settings.add_thoughts_and_reasoning_field and not self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += function_calling_thoughts_and_reasoning + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider)+ "\n</function-calling-instructions>"
elif not structured_output_settings.add_thoughts_and_reasoning_field and not self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += function_calling_without_thoughts_and_reasoning + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider)+ "\n</function-calling-instructions>"
elif structured_output_settings.output_type == LlmStructuredOutputType.object_instance or structured_output_settings.output_type == LlmStructuredOutputType.list_of_objects:
if structured_output_settings.add_thoughts_and_reasoning_field and self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += structured_output_thoughts_and_reasoning_json_schema + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider) + "\n</structured-output-instructions>"
elif not structured_output_settings.add_thoughts_and_reasoning_field and self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += structured_output_without_thoughts_and_reasoning_json_schema + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider) + "\n</structured-output-instructions>"
elif structured_output_settings.add_thoughts_and_reasoning_field and not self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += structured_output_thoughts_and_reasoning + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider) + "\n</structured-output-instructions>"
elif not structured_output_settings.add_thoughts_and_reasoning_field and not self.provider.is_using_json_schema_constraints():
messages[0][
"content"] += structured_output_without_thoughts_and_reasoning + structured_output_settings.get_llm_documentation(
provider=self.provider)
provider=self.provider) + "\n</structured-output-instructions>"

prompt, response_role = self.messages_formatter.format_conversation(
messages, Roles.assistant
Expand Down
46 changes: 36 additions & 10 deletions src/llama_cpp_agent/prompt_templates.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
function_calling_thoughts_and_reasoning = '''\n\nYou can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing three fields:
function_calling_thoughts_and_reasoning = '''\n<function-calling-instructions>
You can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing three fields:
"thoughts_and_reasoning": Write down your thoughts and reasoning behind the function call in this field. Think step by step and plan your next action.
"function": Write down the name of the function you want to call in this field.
Expand All @@ -10,7 +11,8 @@
'''

function_calling_without_thoughts_and_reasoning = '''\n\nYou can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing two fields:
function_calling_without_thoughts_and_reasoning = '''\n<function-calling-instructions>
You can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing two fields:
"function": Write down the name of the function you want to call in this field.
"arguments": Write down arguments for the function in this field.
Expand All @@ -22,7 +24,8 @@
'''


function_calling_thoughts_and_reasoning_json_schema = '''\n\nYou can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing three fields:
function_calling_thoughts_and_reasoning_json_schema = '''\n<function-calling-instructions>
You can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing three fields:
"001_thoughts_and_reasoning": Write down your thoughts and reasoning behind the function call in this field. Think step by step and plan your next action.
"002_function": Write down the name of the function you want to call in this field.
Expand All @@ -34,7 +37,8 @@
'''

function_calling_without_thoughts_and_reasoning_json_schema = '''\n\nYou can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing two fields:
function_calling_without_thoughts_and_reasoning_json_schema = '''\n<function-calling-instructions>
You can call functions to help you with your tasks and user queries. To call functions, you respond with a JSON object containing two fields:
"001_function": Write down the name of the function you want to call in this field.
"002_arguments": Write down arguments for the function in this field.
Expand All @@ -46,7 +50,8 @@
'''


structured_output_thoughts_and_reasoning = '''\n\nYour output is constrained to JSON objects containing the content of specific models, each JSON object has three fields:
structured_output_thoughts_and_reasoning = '''\n<structured-output-instructions>
Your output is constrained to JSON objects containing the content of specific models, each JSON object has three fields:
"thoughts_and_reasoning": Your thoughts and reasoning behind the model you will output.
"model": The name of the model you will output.
Expand All @@ -56,7 +61,8 @@
'''

structured_output_without_thoughts_and_reasoning = '''\n\nYour output is constrained to JSON objects containing the content of specific models, each JSON object has two fields:
structured_output_without_thoughts_and_reasoning = '''\n<structured-output-instructions>
Your output is constrained to JSON objects containing the content of specific models, each JSON object has two fields:
"model": The name of the model you will output.
"fields": The fields of the model.
Expand All @@ -66,7 +72,8 @@
'''


structured_output_thoughts_and_reasoning_json_schema = '''\n\nYour output is constrained to JSON objects containing the content of specific models, each JSON object has three fields:
structured_output_thoughts_and_reasoning_json_schema = '''\n<structured-output-instructions>
Your output is constrained to JSON objects containing the content of specific models, each JSON object has three fields:
"001_thoughts_and_reasoning": Your thoughts and reasoning behind the model you will output.
"002_model": The name of the model you will output.
Expand All @@ -76,7 +83,8 @@
'''

structured_output_without_thoughts_and_reasoning_json_schema = '''\n\nYour output is constrained to JSON objects containing the content of specific models, each JSON object has two fields:
structured_output_without_thoughts_and_reasoning_json_schema = '''\n<structured-output-instructions>
Your output is constrained to JSON objects containing the content of specific models, each JSON object has two fields:
"001_model": The name of the model you will output.
"002_fields": The fields of the model.
Expand All @@ -100,5 +108,23 @@
Write only the markdown document in your response and begin and end your response with '---'.
"""

web_search_system_prompt = """You are a web search specialist and you are able to give detailed answers to user queries based on information extracted from the web.
Write your response to the user in a structured markdown document."""
web_search_system_prompt = """<system-instructions>
You are an advanced web information search assistant and you are able to formulate the perfect query for a search engine to retrieve useful data.
Your task is to call the 'search_web' function for the user query, with a query optimized for search engines, like duckduckgo, google, etc.
</system-instructions>
"""


research_system_prompt = """<system-instructions>
You are an excellent research assistant and you are able to write high quality research articles and research reports. You write the research articles and the research reports about subjects given to you by the users.
Provide the response to the user in a structured markdown document following the format below:
---
Subject: {Subject}
Content:
{Content}
---
Write only the markdown document in your response and begin and end your response with '---'.
</system-instructions>
"""
26 changes: 26 additions & 0 deletions src/llama_cpp_agent/tools/web_search/default_web_crawlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from .web_search_interfaces import WebCrawler
from trafilatura import fetch_url, extract

from bs4 import BeautifulSoup
import requests


class TrafilaturaWebCrawler(WebCrawler):
def get_website_content_from_url(self, url: str) -> str:
Expand All @@ -28,3 +31,26 @@ def get_website_content_from_url(self, url: str) -> str:
return ""
except Exception as e:
return f"An error occurred: {str(e)}"


class BeautifulSoupWebCrawler(WebCrawler):
def get_website_content_from_url(self, url: str) -> str:
"""
Get website content from a URL using requests and BeautifulSoup for HTML parsing.
Args:
url (str): URL to get website content from.
Returns:
str: Extracted content including title and main text.
"""
try:
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

title = soup.find('title').text if soup.find('title') else "No title found"
body = soup.get_text()

return f'=========== Website Title: {title} ===========\n\n=========== Website URL: {url} ===========\n\n=========== Website Content ===========\n\n{body}\n\n=========== Website Content End ===========\n\n'
except Exception as e:
return f"An error occurred: {str(e)}"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from duckduckgo_search import DDGS
from googlesearch import search

from .web_search_interfaces import WebSearchProvider

Expand All @@ -8,3 +9,13 @@ class DDGWebSearchProvider(WebSearchProvider):
def search_web(self, search_query: str):
results = DDGS().text(search_query, region='wt-wt', safesearch='off', max_results=4)
return [res["href"] for res in results]


class GoogleWebSearchProvider(WebSearchProvider):
def search_web(self, query: str):
"""Searches the web using Google and returns a list of URLs."""
try:
# Only return the top 5 results for simplicity
return list(search(query, num_results=5))
except Exception as e:
return f"An error occurred during Google search: {str(e)}"
6 changes: 3 additions & 3 deletions src/llama_cpp_agent/tools/web_search/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def search_web(self, search_query: str):
web_info = self.summarising_agent.get_chat_response(
f"Please summarize the following Website content and extract relevant information to this query:'{search_query}'.\n\n" + web_info,
add_response_to_chat_history=False, add_message_to_chat_history=False, llm_sampling_settings=self.settings)
result_string += f"\n\n{web_info.strip()}"
result_string += f"\n{web_info.strip()}"

res = result_string.strip()
tokens = self.llm_provider.tokenize(res)
Expand All @@ -73,8 +73,8 @@ def search_web(self, search_query: str):
remove_char_count += 50
tokens = self.llm_provider.tokenize(res[:remove_char_count])
if not has_remove_char:
return "\nResults of searching the web:\n\n" + res
return "\nResults of searching the web:\n\n" + res[:remove_char_count]
return res
return res[:remove_char_count]

def get_tool(self):
return self.search_web
Expand Down

0 comments on commit d4038d5

Please sign in to comment.