시맨틱 커널 – C# AI 애플리케이션 만들기 8 – Automatically orchestrate AI with planners
여러 함수들이 실행되어야 달성할 수 있는 목표 수준의 요구가 있다면, 어떤 함수들을 사용할지 이들을 어떻게 실행할 지를 일일이 결정해야 한다면, 개발자는 목표에 따라 어떤 함수들을 가지고 어떻게 실행 할지 결정하고 이를 코딩해야 한다. 또는 사용자가 제공된 함수들 중에서 선택하고 어떻게 실행할지 결정하고 그 결정대로 흐름을 작성할 수 있도록 해 줘야 한다. 목표가 몇 가지로 추려진다면 이것도 해 볼만 하지만, 그렇지 않다면 이를 ai 애플리케이션이 알아서 해 주기를 원할 것이다. 플래너 등장. 플래너도 이를 해 줄 수 있는 함수겠네.
플래너는 목표 수준의 사용자 요구를 달성하기 위해, 어떤 함수 들을 가지고 어떻게 실행할 것 인지를 계획하고 실행한다. 함수들이 다양하게 준비되어 갈 수록 사용자가 ai로 할 수 있는 일이 늘어나게 되는 것이다.
플래너가 사용할 수 있는 함수들은 커널에 등록된 것들이다 . 플래너는 이들 중 어떤 함수들을 어떻게 사용 할지 결정 실행한다. 함수들이 순차적으로 정해진 순서에 따라 실행되도록 계획하는 것이 가장 일반적인 방법이다. 플래너는 처리 로직을 계획한다는 것이다. 순차, 병행이 표현될 수 있어야 하고, 조건 분기나 반복이 표현 가능해야 한다.
ai 애플리케이션에 반영된 로직 대로 해야 플래너가 실행 계획을 작성한다면, 이 또한 개발할 때 파악한 수준 정도 만을 지원하게 된다. 계획을 세울 때도 llm을 사용한다면 llm이 훈련된 수준까지는 가능해진다. chatgpt와 같은 엄청난 양의 지식 보유자 같은 llm도 중요하지만, 계획을 잘 세우는 llm도 중요해 보인다. 아직은 아는 게 많은 llm을 사용해 계획도 세우고 있긴 하지만. 플래너에게 전달되는 목표 수준의 프롬프트에 의해 llm이 처리 로직을 짜는 프로그래밍을 하고 있게 된다는 것.
자연어로 연동되는 작은 기능들이 많이 잘 모아진 라이브러리도, 비즈니스에서 ai를 사용하는 수준을 높이는데 중요한 게 되겠다.
* 플래너는 autogpt와 같은 에이전트라고 할 수 있다. 작은 기능들을 가지고 요청 받은 목표 수준의 일 처리를 계획하고 실행한다.
두 수를 더하고 빼고 곱하고 나눌 수 있는 Math 클래스를 다음과 같이 작성한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public class Math { [SKFunction, Description("Take the square root of a number")] public string Sqrt(string input) { return System.Math.Sqrt(Convert.ToDouble(input, CultureInfo.InvariantCulture)).ToString(CultureInfo.InvariantCulture); } [SKFunction, Description("Add two numbers")] [SKParameter("first", "The first number to add")] [SKParameter("second ", "The second number to add")] public string Add(SKContext context) { return ( Convert.ToDouble(context["first"], CultureInfo.InvariantCulture) + Convert.ToDouble(context["second "], CultureInfo.InvariantCulture) ).ToString(CultureInfo.InvariantCulture); } [SKFunction, Description("Subtract two numbers")] [SKParameter("first", "The first number to subtract from")] [SKParameter("second ", "The second number to subtract away")] public string Subtract(SKContext context) { return ( Convert.ToDouble(context["first"], CultureInfo.InvariantCulture) - Convert.ToDouble(context["second "], CultureInfo.InvariantCulture) ).ToString(CultureInfo.InvariantCulture); } [SKFunction, Description("Multiply two numbers. When increasing by a percentage, don't forget to add 1 to the percentage.")] [SKParameter("first", "The first number to multiply")] [SKParameter("second ", "The second number to multiply")] public string Multiply(SKContext context) { return ( Convert.ToDouble(context["first"], CultureInfo.InvariantCulture) * Convert.ToDouble(context["second "], CultureInfo.InvariantCulture) ).ToString(CultureInfo.InvariantCulture); } [SKFunction, Description("Divide two numbers")] [SKParameter("first", "The first number to divide from")] [SKParameter("second ", "The second number to divide by")] public string Divide(SKContext context) { return ( Convert.ToDouble(context["first"], CultureInfo.InvariantCulture) / Convert.ToDouble(context["second "], CultureInfo.InvariantCulture) ).ToString(CultureInfo.InvariantCulture); } } |
함수들을 순차적으로 실행하는 계획을 세우도록 한다. SequentialPlanner
플래너는 커널에 등록된 모든 플러그인을 자동으로 검색해서 계획을 세운다.
플래너가 제대로 동작하려면, 모델이 gpt-4인게 좋은 것 같다. var model = “gpt-4”;
네이티브 함수들이 작성된 Math 플러그인을 임포트 한다.
SequentialPlanner를 생성하고 산술 연산이 필요한 입력(ask )을 작성하고 실행한다(kernel.RunAsync(plan)).
응답으로 2615.1829 값이 출력 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
IKernel kernel = new KernelBuilder() .WithOpenAIChatCompletionService(model, apiKey) .Build(); // Import the Math Plugin kernel.ImportSkill(new Plugins.MathPlugin.Math(), "MathPlugin"); // Create planner var planner = new SequentialPlanner(kernel); // Create a plan for the ask var ask = "If my investment of 2130.23 dollars increased by 23%, how much would I have after I spent $5 on a latte?"; var plan = await planner.CreatePlanAsync(ask); // Execute the plan Console.WriteLine("Plan:\n"); Console.WriteLine(JsonSerializer.Serialize(plan, new JsonSerializerOptions { WriteIndented = true })); var result = (await kernel.RunAsync(plan)).Result; Console.WriteLine("Plan results:"); Console.WriteLine(result.Trim()); |
lm연동은 뭘 하던 결국은 프롬프트 작성이다.
플래너는 llm에게 목표 달성을 위한 절차를 생성해 달라고 하기 위한 프롬프트가 있고 이를 llm에 전달하는 것이다.
SequentialPlanner 프롬프트는 /Extensions/Planning.SequentialPlanner/ 폴더의 skprompt.txt로 다음과 같이 작성되어 있다.
프롬프트를 잘 작성하면 뭐까지 할 수 있는 지를 보여준다. ‘뭐까지 하려면 이 정도로 프롬프트를 작성해야 한다’ 를 보여주기도.
Create an XML plan step by step, to satisfy the goal given, with the available functions.
[AVAILABLE FUNCTIONS] {{$available_functions}} [END AVAILABLE FUNCTIONS] To create a plan, follow these steps: All plans take the form of: To call a function, follow these steps: DO NOT DO THIS, THE PARAMETER VALUE IS NOT XML ESCAPED: DO NOT DO THIS, THE PARAMETER VALUE IS ATTEMPTING TO USE A CONTEXT VARIABLE AS AN ARRAY/OBJECT: Here is a valid example of how to call a function “_Function_.Name” with a single input and save its output: Here is a valid example of how to call a function “FunctionName2″ with a single input and return its output as part of the plan result: Here is a valid example of how to call a function “Name3″ with multiple inputs: Begin! <goal>{{$input}}</goal> |
llm에 프롬프트를 전달해 계획을 세우기 때문에 함수의 자연어 설명 부분을 잘 작성해야 한다는 두 말 할 필요가 없다.
함수를 언제 어떻게 사용해야 하는 지가 분명하지 않다면 이를 위한 도움말을 제공해라. MathPlugin.Multiply에서 숫자를 백분율로 늘릴 때마다 1을 더하라고 상기해 주고 있다. 출력이 무엇인지 어떻게 되어야 하는지도 설명 부분에 추가할 수 있다. 매개변수 부분에 대한 설명도 마찬가지로 잘 작성해야 겠지. 매개변수는 필수인지 선택적으로 작성할 수 있는지 언급하는 것은 중요하다.
플래너에서 생각해봐야 할 것들
– 절차가 정해져 있는 것들은?
해당 플래너를 만들어 정해진 절차대로 수행하도록 한다.
– 잘못될 때는?
오류 처리를 할 것인지, 플래너가 계획을 수정해서 가도록 할 것인지.
Pingback: AISmarteasy – 시맨틱 커널 개발하기 7 – Automatically orchestrate AI with planners | 뉴테크프라임