Skip to content

Commit 6d4b493

Browse files
authored
Merge pull request #2 from automaze1/main
Tools update and pipeline tool enhancement
2 parents 3d81c14 + 351bd11 commit 6d4b493

File tree

12 files changed

+285
-60
lines changed

12 files changed

+285
-60
lines changed

build/GenerativeAI.zip

604 Bytes
Binary file not shown.

docs/automation.generativeai.application.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -274,29 +274,31 @@ Returns the AI assitant's response.
274274

275275
[Exception](https://docs.microsoft.com/en-us/dotnet/api/system.exception)<br>
276276
277-
### **CreateFunctionDescription(String, String, String)**
277+
### **CreateToolDescriptor(String, String, String)**
278278

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

281283
```csharp
282-
public static int CreateFunctionDescription(string name, string description, string parametersTableCSVAsText)
284+
public static string CreateToolDescriptor(string name, string description, string parametersTableCSVAsText)
283285
```
284286

285287
#### Parameters
286288

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

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

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

296298
#### Returns
297299

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

301303
### **AddToolsFromDLL(String)**
302304

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

319-
### **AddFunctionMessage(String, String, String, Double)**
321+
### **AddToolResponseToConversation(String, String, String, Double)**
320322

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

323327
```csharp
324-
public static string AddFunctionMessage(string sessionid, string functionName, string message, double temperature)
328+
public static string AddToolResponseToConversation(string sessionid, string toolName, string response, double temperature)
325329
```
326330

327331
#### Parameters
328332

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

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

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

338342
`temperature` [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double)<br>
339343
A value between 0 and 1 to control the randomness of the response.

examples/FunctionTools/Program.cs

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
using Automation.GenerativeAI;
2+
using Automation.GenerativeAI.Agents;
23
using Automation.GenerativeAI.Chat;
34
using Automation.GenerativeAI.Interfaces;
45
using Automation.GenerativeAI.LLM;
56
using Automation.GenerativeAI.Tools;
7+
using Automation.GenerativeAI.Utilities;
68
using System;
79
using System.Collections.Generic;
810
using System.IO;
911
using System.Linq;
1012
using System.Reflection;
13+
using System.Security.Policy;
1114
using System.Threading.Tasks;
1215

1316
namespace FunctionTools
@@ -53,11 +56,15 @@ static async Task Main(string[] args)
5356
//await SimpleChat();
5457
//await LatestNews();
5558

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

5861
//await ExtractData();
5962

60-
await Task.Run(() => SynchronousExtractData());
63+
//await Task.Run(() => SynchronousExtractData());
64+
65+
//WikiSearch("Chandrayaan-3");
66+
67+
await WikiSearch();
6168
}
6269

6370
static async Task DemoBasicConversationUsingLanguageModel()
@@ -135,7 +142,7 @@ static async Task DemoFunctionCalling()
135142

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

145152
if (response.Contains("function_call"))
146153
{
147-
response = Application.AddFunctionMessage("test", "GetCurrentWeather", "{\"temperature\": 22, \"unit\": \"celsius\", \"description\": \"Sunny\"}", 0.8);
154+
response = Application.AddToolResponseToConversation("test", "GetCurrentWeather", "{\"temperature\": 22, \"unit\": \"celsius\", \"description\": \"Sunny\"}", 0.8);
148155
}
149156

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

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

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

539546
Console.WriteLine($"{response.role}: {response.content}");
540547
}
548+
549+
static void WikiSearch(string query)
550+
{
551+
var prompt = PromptTool.WithTemplate("https://wikipedia.org/w/index.php?search={{$query}}");
552+
var httpget = HttpTool.WithClient();
553+
554+
//Create function tool from DLL and class name
555+
var toolset = new DLLFunctionTools(@"GenerativeAI.Tools.dll", "Automation.GenerativeAI.Tools.WebContentExtractor");
556+
557+
var extractor = toolset.GetTool("GetTextFromHtml");
558+
559+
var pipeline = Pipeline.WithTools(new[] {prompt, httpget, extractor});
560+
561+
var context = new ExecutionContext();
562+
context["query"] = query;
563+
//context["method"] = "GET";
564+
var text = pipeline.ExecuteAsync(context).GetAwaiter().GetResult();
565+
566+
Console.Write(text);
567+
Console.ReadLine();
568+
}
569+
570+
static async Task WikiSearch()
571+
{
572+
Logger.SetLogFile("Sample.log");
573+
var prompt = PromptTool.WithTemplate("https://wikipedia.org/w/index.php?search={{$query}}");
574+
var httpget = HttpTool.WithClient();
575+
576+
//Create function tool from DLL and class name
577+
var toolset = new DLLFunctionTools(@"GenerativeAI.Tools.dll", "Automation.GenerativeAI.Tools.WebContentExtractor");
578+
579+
var extractor = toolset.GetTool("GetTextFromHtml");
580+
581+
var responses = new Dictionary<string, string>() { { "Text", "Here is my text summary" } };
582+
var llm = new MockLanguageModel("Test", responses);
583+
584+
var mapperPrompt = "Provide me one para summary of the following article. \n {{$article}}";
585+
var reducerPrompt = "Summarize the following texts in a clear and concise short article not more than 250 words.\n\n {{$article}}";
586+
var summarizer = TextSummarizer.WithMapReduce().WithLanguageModel(llm);
587+
588+
var wikisearch = Pipeline.WithTools(new[] { prompt, httpget, extractor, summarizer })
589+
.WithName("WikiSearch")
590+
.WithDescription("Searches wikipedia to provide relevant information on a topic or personality!");
591+
592+
var ctx = new ExecutionContext();
593+
ctx["query"] = "Parmanu: The Story of Pokhran";
594+
595+
var result = await wikisearch.ExecuteAsync(ctx);
596+
Console.WriteLine(result);
597+
Console.ReadLine();
598+
}
599+
600+
541601
}
542602
}

src/GenAIFramework.Test/ApplicationTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,18 +367,18 @@ public void AgentWithClientManagedTools()
367367
amount,Amount of units to edit,int";
368368

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

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

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

381-
var status = Application.CreateAgent(agent, tools, 3, string.Empty);
381+
status = Application.CreateAgent(agent, tools, 3, string.Empty);
382382
Assert.AreEqual("success", status);
383383

384384
var objective = @"Please do three things, add an amount of 40 units to year 2023 headcount

src/GenAIFramework.Test/ToolsTest.cs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ protected override ILanguageModel CreateLanguageModel()
2222
{
2323
{ "What is the weather like in Boston?", "The weather in Boston is cold" },
2424
{ "What is the weather like in San Francisco?", "The weather in San Francisco is warm" },
25-
{ "sales growth after", "Facebook parent Meta reported a return to sales growth after three quarters of\r\ndeclines." }
25+
{ "sales growth after", "Facebook parent Meta reported a return to sales growth after three quarters of\r\ndeclines." },
26+
{ "imparts wisdom and guides people", "Roger had 5 balls and 2 cans so now he has 9 balls in total." },
27+
{ "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." },
28+
{ "reviews answers and critiques", "Roger has 11 balls" },
2629
};
2730

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

325+
[TestMethod]
326+
public async Task RCIChainPipelineWithInputBinding()
327+
{
328+
Logger.WriteLog(LogLevel.Info, LogOps.Test, "RCIChainPipelineWithInputBinding");
329+
330+
var questionPrompt = @"You are a helpful assistant that imparts wisdom and guides people with accurate answers.
331+
Question: {{$question}}
332+
Answer: ";
333+
var critiquePrompt = @"You are a helpful assistant that looks at answers and finds what is wrong with them based on the original question given.
334+
335+
Question: {{$Input.question}}
336+
337+
Answer Given:{{$initial_answer}}
338+
339+
Review your previous answer and find problems with your answer.";
340+
341+
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.
342+
343+
Question: {{$Input.question}}
344+
345+
Answer Given:{{$Result.Query}}
346+
347+
Constructive Criticism:{{$critique}} Based on the problems you found, improve your answer.
348+
349+
Final Answer:";
350+
351+
//var llm = new OpenAILanguageModel("gpt-3.5-turbo");
352+
var prompts = new Dictionary<string, string> { { questionPrompt, "Query"}, { critiquePrompt, "Critique" }, { imrpovementPrompt, "Improvise" } };
353+
var tools = prompts.Select(p => QueryTool.WithPromptTemplate(p.Key).WithLanguageModel(LanguageModel).WithName(p.Value)).ToList();
354+
355+
var pipeline = Pipeline.WithTools(tools);
356+
Assert.IsNotNull(pipeline);
357+
358+
var context = new ExecutionContext();
359+
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?";
360+
361+
var result = await pipeline.ExecuteAsync(context);
362+
Assert.IsTrue(result.Contains("11"));
363+
}
364+
322365
[TestMethod]
323366
public async Task HttpGet()
324367
{
@@ -410,5 +453,26 @@ public async Task MultiParameterMapReduce()
410453
Assert.IsTrue(result.Contains("The capital of Jharkhand is Ranchi and 'Santhal' is the most popular language there."));
411454
Assert.IsTrue(result.Contains("The capital of MP is Bhopal and 'Hindi' is the most popular language there."));
412455
}
456+
457+
[TestMethod]
458+
public async Task SemanticSearchWithContext()
459+
{
460+
Logger.WriteLog(LogLevel.Info, LogOps.Test, "SemanticSearchWithContext");
461+
462+
var file = Path.Combine(RootPath, @"..\..\..\..\..\tests\input\article.txt");
463+
var context = new ExecutionContext();
464+
context["context"] = File.ReadAllText(file);
465+
context["query"] = "Meta has reported sales growth after how many quarters of decline?";
466+
467+
var tool = SearchTool.ForSemanticSearchFromSource(string.Empty).WithMaxResultCount(3);
468+
Assert.IsNotNull(tool);
469+
470+
var result = await tool.ExecuteAsync(context);
471+
Assert.IsTrue(!string.IsNullOrEmpty(result));
472+
473+
var searchresults = FunctionTool.Deserialize<SearchResult[]>(result);
474+
Assert.AreEqual(3, searchresults.Length);
475+
Assert.IsTrue(searchresults.Any(r => r.content.Contains("three quarter")));
476+
}
413477
}
414478
}

src/GenerativeAI/Agents/Agent.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,40 @@ public enum AgentType
2626
/// </summary>
2727
public abstract class Agent
2828
{
29+
/// <summary>
30+
/// List of messages to record message history
31+
/// </summary>
2932
protected List<ChatMessage> Messages = new List<ChatMessage>();
33+
34+
/// <summary>
35+
/// Collection of allowed tools for agent to use.
36+
/// </summary>
3037
protected ToolsCollection Tools;
38+
39+
/// <summary>
40+
/// System prompt string
41+
/// </summary>
3142
protected string SystemPrompt;
43+
44+
/// <summary>
45+
/// LLM temperature setting
46+
/// </summary>
3247
protected double Temperature = 0.8;
48+
49+
/// <summary>
50+
/// Language model set by the client
51+
/// </summary>
3352
private ILanguageModel languageModel;
34-
private int MaxAllowedSteps = 10;
35-
private List<AgentAction> Steps = new List<AgentAction>();
53+
54+
/// <summary>
55+
/// Maximum number of allowed steps
56+
/// </summary>
57+
protected int MaxAllowedSteps = 10;
58+
59+
/// <summary>
60+
/// Steps taken by the agent so far
61+
/// </summary>
62+
protected List<AgentAction> Steps = new List<AgentAction>();
3663

3764
/// <summary>
3865
/// Name of the Agent

src/GenerativeAI/Agents/AgentAction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public FinishAction(string output, string error = "") : base(new ExecutionContex
8484
new ParameterDescriptor(){Name = "error", Description = "Error string"}
8585
};
8686

87-
Tool = new DummyTool(new FunctionDescriptor("FinishAction", "The final action", parameters));
87+
Tool = new ToolDescriptor("FinishAction", "The final action", parameters);
8888
}
8989

9090
/// <summary>

0 commit comments

Comments
 (0)