Skip to content

Tools update and pipeline tool enhancement #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified build/GenerativeAI.zip
Binary file not shown.
30 changes: 17 additions & 13 deletions docs/automation.generativeai.application.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,29 +274,31 @@ Returns the AI assitant's response.

[Exception](https://docs.microsoft.com/en-us/dotnet/api/system.exception)<br>

### **CreateFunctionDescription(String, String, String)**
### **CreateToolDescriptor(String, String, String)**

Creates a function description that can be passed to language model
Creates a tool descriptor that can be passed to the language model or Agent as a tool.
This tool doesn't have any execution logic and when required client can perform custom
logic for its execution.

```csharp
public static int CreateFunctionDescription(string name, string description, string parametersTableCSVAsText)
public static string CreateToolDescriptor(string name, string description, string parametersTableCSVAsText)
```

#### Parameters

`name` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
Name of the function
Name of the tool

`description` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
Description of the function
Description of the tool

`parametersTableCSVAsText` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
A table to contain parameter name, description and type

#### Returns

[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)<br>
Returns function id
[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
Status of the operation.

### **AddToolsFromDLL(String)**

Expand All @@ -316,24 +318,26 @@ Full path of the DLL
[List&lt;String&gt;](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1)<br>
List of the tools name that got added to the tools collection.

### **AddFunctionMessage(String, String, String, Double)**
### **AddToolResponseToConversation(String, String, String, Double)**

Adds a function message as a response to function_call message to a given conversation.
When the language model returns a function_call message for any tool, that tool
needs to be executed by client and the response of that execution can be registered
using this method.

```csharp
public static string AddFunctionMessage(string sessionid, string functionName, string message, double temperature)
public static string AddToolResponseToConversation(string sessionid, string toolName, string response, double temperature)
```

#### Parameters

`sessionid` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
The session id for the conversation.

`functionName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
`toolName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
Name of the function that was executed.

`message` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
Output returned from the function call as string(json).
`response` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)<br>
Output returned by the given tool as string(json).

`temperature` [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double)<br>
A value between 0 and 1 to control the randomness of the response.
Expand Down
70 changes: 65 additions & 5 deletions examples/FunctionTools/Program.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using Automation.GenerativeAI;
using Automation.GenerativeAI.Agents;
using Automation.GenerativeAI.Chat;
using Automation.GenerativeAI.Interfaces;
using Automation.GenerativeAI.LLM;
using Automation.GenerativeAI.Tools;
using Automation.GenerativeAI.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using System.Threading.Tasks;

namespace FunctionTools
Expand Down Expand Up @@ -53,11 +56,15 @@ static async Task Main(string[] args)
//await SimpleChat();
//await LatestNews();

//await BrowsePage(@"https://www.google.com/finance/?hl=en");
//await BrowsePage(@"https://twitter.com/search?q=Chandrayan");

//await ExtractData();

await Task.Run(() => SynchronousExtractData());
//await Task.Run(() => SynchronousExtractData());

//WikiSearch("Chandrayaan-3");

await WikiSearch();
}

static async Task DemoBasicConversationUsingLanguageModel()
Expand Down Expand Up @@ -135,7 +142,7 @@ static async Task DemoFunctionCalling()

static void CreateFunctionDemo()
{
int id = Application.CreateFunctionDescription(
var status = Application.CreateToolDescriptor(
"GetCurrentWeather",
"Gets the current weather information of a city.",
"location,The name of a city for which weather information is needed, string");
Expand All @@ -144,7 +151,7 @@ static void CreateFunctionDemo()

if (response.Contains("function_call"))
{
response = Application.AddFunctionMessage("test", "GetCurrentWeather", "{\"temperature\": 22, \"unit\": \"celsius\", \"description\": \"Sunny\"}", 0.8);
response = Application.AddToolResponseToConversation("test", "GetCurrentWeather", "{\"temperature\": 22, \"unit\": \"celsius\", \"description\": \"Sunny\"}", 0.8);
}

Console.WriteLine(response);
Expand Down Expand Up @@ -489,7 +496,7 @@ Think step by step and analyze the input
request to check if any function call is required, if so extract all
parameters based on the function sepcification. Extract arguments and values
only based on function specification provided, do not include extra parameter. If required feel
free to browse a given link to get more insight on the available data.";
free to browse a given link to get more insight on the available data. Please provide your reasoning in the response";

//chat.AppendMessage(msg, Role.system);

Expand Down Expand Up @@ -538,5 +545,58 @@ and subtract an amount of 23 units from year 2022 opex forecast then

Console.WriteLine($"{response.role}: {response.content}");
}

static void WikiSearch(string query)
{
var prompt = PromptTool.WithTemplate("https://wikipedia.org/w/index.php?search={{$query}}");
var httpget = HttpTool.WithClient();

//Create function tool from DLL and class name
var toolset = new DLLFunctionTools(@"GenerativeAI.Tools.dll", "Automation.GenerativeAI.Tools.WebContentExtractor");

var extractor = toolset.GetTool("GetTextFromHtml");

var pipeline = Pipeline.WithTools(new[] {prompt, httpget, extractor});

var context = new ExecutionContext();
context["query"] = query;
//context["method"] = "GET";
var text = pipeline.ExecuteAsync(context).GetAwaiter().GetResult();

Console.Write(text);
Console.ReadLine();
}

static async Task WikiSearch()
{
Logger.SetLogFile("Sample.log");
var prompt = PromptTool.WithTemplate("https://wikipedia.org/w/index.php?search={{$query}}");
var httpget = HttpTool.WithClient();

//Create function tool from DLL and class name
var toolset = new DLLFunctionTools(@"GenerativeAI.Tools.dll", "Automation.GenerativeAI.Tools.WebContentExtractor");

var extractor = toolset.GetTool("GetTextFromHtml");

var responses = new Dictionary<string, string>() { { "Text", "Here is my text summary" } };
var llm = new MockLanguageModel("Test", responses);

var mapperPrompt = "Provide me one para summary of the following article. \n {{$article}}";
var reducerPrompt = "Summarize the following texts in a clear and concise short article not more than 250 words.\n\n {{$article}}";
var summarizer = TextSummarizer.WithMapReduce().WithLanguageModel(llm);

var wikisearch = Pipeline.WithTools(new[] { prompt, httpget, extractor, summarizer })
.WithName("WikiSearch")
.WithDescription("Searches wikipedia to provide relevant information on a topic or personality!");

var ctx = new ExecutionContext();
ctx["query"] = "Parmanu: The Story of Pokhran";

var result = await wikisearch.ExecuteAsync(ctx);
Console.WriteLine(result);
Console.ReadLine();
}


}
}
10 changes: 5 additions & 5 deletions src/GenAIFramework.Test/ApplicationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -367,18 +367,18 @@ public void AgentWithClientManagedTools()
amount,Amount of units to edit,int";

//Create function description without any execution logic.
var retval = Application.CreateFunctionDescription("EditFinancialForecast", "Makes an edit to users financial forecast model.", parameters);
Assert.AreEqual(1, retval);
var status = Application.CreateToolDescriptor("EditFinancialForecast", "Makes an edit to users financial forecast model.", parameters);
Assert.AreEqual("success", status);

parameters = @"printer,Printer name";
//Create function description without any execution logic.
retval = Application.CreateFunctionDescription("PrintFinancialForecast", "Sends the financial forecast for print", parameters);
Assert.AreEqual(2, retval);
status = Application.CreateToolDescriptor("PrintFinancialForecast", "Sends the financial forecast for print", parameters);
Assert.AreEqual("success", status);

var tools = new List<string>() { "EditFinancialForecast", "PrintFinancialForecast" };
var agent = "ForecastAgent";

var status = Application.CreateAgent(agent, tools, 3, string.Empty);
status = Application.CreateAgent(agent, tools, 3, string.Empty);
Assert.AreEqual("success", status);

var objective = @"Please do three things, add an amount of 40 units to year 2023 headcount
Expand Down
66 changes: 65 additions & 1 deletion src/GenAIFramework.Test/ToolsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ protected override ILanguageModel CreateLanguageModel()
{
{ "What is the weather like in Boston?", "The weather in Boston is cold" },
{ "What is the weather like in San Francisco?", "The weather in San Francisco is warm" },
{ "sales growth after", "Facebook parent Meta reported a return to sales growth after three quarters of\r\ndeclines." }
{ "sales growth after", "Facebook parent Meta reported a return to sales growth after three quarters of\r\ndeclines." },
{ "imparts wisdom and guides people", "Roger had 5 balls and 2 cans so now he has 9 balls in total." },
{ "looks at answers and finds", "Roger has 5 balls initially and buys 2 cans. Each can contains 3 balls so now he has 5 + 2 x 3 = 11 balls." },
{ "reviews answers and critiques", "Roger has 11 balls" },
};

return new MockLanguageModel("Mock", responses);
Expand Down Expand Up @@ -319,6 +322,46 @@ Use following text as context to answer the follow up question.
Assert.IsTrue(result.Contains("three quarters"));
}

[TestMethod]
public async Task RCIChainPipelineWithInputBinding()
{
Logger.WriteLog(LogLevel.Info, LogOps.Test, "RCIChainPipelineWithInputBinding");

var questionPrompt = @"You are a helpful assistant that imparts wisdom and guides people with accurate answers.
Question: {{$question}}
Answer: ";
var critiquePrompt = @"You are a helpful assistant that looks at answers and finds what is wrong with them based on the original question given.

Question: {{$Input.question}}

Answer Given:{{$initial_answer}}

Review your previous answer and find problems with your answer.";

var imrpovementPrompt = @"You are a helpful assistant that reviews answers and critiques based on the original question given and write a new improved final answer.

Question: {{$Input.question}}

Answer Given:{{$Result.Query}}

Constructive Criticism:{{$critique}} Based on the problems you found, improve your answer.

Final Answer:";

//var llm = new OpenAILanguageModel("gpt-3.5-turbo");
var prompts = new Dictionary<string, string> { { questionPrompt, "Query"}, { critiquePrompt, "Critique" }, { imrpovementPrompt, "Improvise" } };
var tools = prompts.Select(p => QueryTool.WithPromptTemplate(p.Key).WithLanguageModel(LanguageModel).WithName(p.Value)).ToList();

var pipeline = Pipeline.WithTools(tools);
Assert.IsNotNull(pipeline);

var context = new ExecutionContext();
context["question"] = "Roger has 5 tenis balls. He buys 2 more cans of tennis balls each with 3 balls. How many tennis balls he has now?";

var result = await pipeline.ExecuteAsync(context);
Assert.IsTrue(result.Contains("11"));
}

[TestMethod]
public async Task HttpGet()
{
Expand Down Expand Up @@ -410,5 +453,26 @@ public async Task MultiParameterMapReduce()
Assert.IsTrue(result.Contains("The capital of Jharkhand is Ranchi and 'Santhal' is the most popular language there."));
Assert.IsTrue(result.Contains("The capital of MP is Bhopal and 'Hindi' is the most popular language there."));
}

[TestMethod]
public async Task SemanticSearchWithContext()
{
Logger.WriteLog(LogLevel.Info, LogOps.Test, "SemanticSearchWithContext");

var file = Path.Combine(RootPath, @"..\..\..\..\..\tests\input\article.txt");
var context = new ExecutionContext();
context["context"] = File.ReadAllText(file);
context["query"] = "Meta has reported sales growth after how many quarters of decline?";

var tool = SearchTool.ForSemanticSearchFromSource(string.Empty).WithMaxResultCount(3);
Assert.IsNotNull(tool);

var result = await tool.ExecuteAsync(context);
Assert.IsTrue(!string.IsNullOrEmpty(result));

var searchresults = FunctionTool.Deserialize<SearchResult[]>(result);
Assert.AreEqual(3, searchresults.Length);
Assert.IsTrue(searchresults.Any(r => r.content.Contains("three quarter")));
}
}
}
31 changes: 29 additions & 2 deletions src/GenerativeAI/Agents/Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,40 @@ public enum AgentType
/// </summary>
public abstract class Agent
{
/// <summary>
/// List of messages to record message history
/// </summary>
protected List<ChatMessage> Messages = new List<ChatMessage>();

/// <summary>
/// Collection of allowed tools for agent to use.
/// </summary>
protected ToolsCollection Tools;

/// <summary>
/// System prompt string
/// </summary>
protected string SystemPrompt;

/// <summary>
/// LLM temperature setting
/// </summary>
protected double Temperature = 0.8;

/// <summary>
/// Language model set by the client
/// </summary>
private ILanguageModel languageModel;
private int MaxAllowedSteps = 10;
private List<AgentAction> Steps = new List<AgentAction>();

/// <summary>
/// Maximum number of allowed steps
/// </summary>
protected int MaxAllowedSteps = 10;

/// <summary>
/// Steps taken by the agent so far
/// </summary>
protected List<AgentAction> Steps = new List<AgentAction>();

/// <summary>
/// Name of the Agent
Expand Down
2 changes: 1 addition & 1 deletion src/GenerativeAI/Agents/AgentAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public FinishAction(string output, string error = "") : base(new ExecutionContex
new ParameterDescriptor(){Name = "error", Description = "Error string"}
};

Tool = new DummyTool(new FunctionDescriptor("FinishAction", "The final action", parameters));
Tool = new ToolDescriptor("FinishAction", "The final action", parameters);
}

/// <summary>
Expand Down
Loading