AI模型的能力各有千秋,有些適合寫程式,有些適合做研究,甚至有些小問題其實用輕量級模型就可以了,因為這牽涉到Token使用量的問題。

目前已經有新創公司在做這類的服務,而我自己直覺想到,其實找個適合的LLM來分類就行了,雖然是最陽春的解法,但也是最快的方式。

想到了解決,馬上就來寫相關的程式,以下先寫一個enum:

public enum ModelType
{
    Llama3,
    Mistral,
    OpenAI,
    AzureOpenAI,
    Claude,
    Other
}

接下來是對應的設定檔:

{
  "ModelTarget": [
    {
      "Type": "Coding",
      "ModelName": "gpt-4o-mini"
    },
    {
      "Type": "Writing",
      "ModelName": "gpt-4o"
    },
    {
      "Type": "General",
      "ModelName": "phi4"
    }
  ],
  "SystemPrompt": "You are a helpful assistant that can answer questions and provide information on a wide range of topics. You are knowledgeable, articulate, and able to provide clear and concise explanations. You can also assist with coding tasks, writing, and general inquiries."
}

然後來寫對應的類別:

public class Routing
{
   private string _modelName = string.Empty;
   private IChatClient _chatClient;
   private List<ModelTarget> _modelTypes;

   public Routing() : this(@"llama3.1:latest")
   {

   }

   public Routing(string modelName)
   {
       // 讀取 appsettings.json
       var config = new ConfigurationBuilder()
           .SetBasePath(AppContext.BaseDirectory)
           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
           .Build();

       if (string.IsNullOrEmpty(modelName))
       {
           _modelName = @"llama3.1:latest";
       }
       else
       {
           _modelName = modelName;
       }

       _modelTypes = config.GetSection("ModelTarget").GetChildren().Select(c => new ModelTarget
       {
           Type = c["Type"],
           ModelName = c["ModelName"]
       }).ToList();

       string ollamaUri = "http://localhost:11434";
       _chatClient = new OllamaSharp.OllamaApiClient(new Uri(ollamaUri), _modelName);
   }

   public async Task<string> GetCategoryByPrompt(string userPrompt)
   {
       
       string systemPrompt = "你是分類提示詞類型的助手,依提示詞的類型進行分類。分類有以下幾種,記得,只回應對應類型的問題類型,不要有其它的內容,例如只回應Coding。";
       systemPrompt += $"{systemPrompt}\n\n分類類型如下:\n{string.Join("\n", _modelTypes.Select(mt => $"{mt.Type}"))}";
       string prompt = $"<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>";
       var response = await _chatClient.GetResponseAsync(prompt);
       string modelType = response.Text;

       return modelType;
   }

   public string GetModelName(string category)
   {
       var modelTarget = _modelTypes.FirstOrDefault(mt => mt.Type == category);
       return modelTarget?.ModelName ?? string.Empty;
   }
}

現在來拆解,最重要的部份:

public async Task<string> GetCategoryByPrompt(string userPrompt)
{
   string systemPrompt = "你是分類提示詞類型的助手,依提示詞的類型進行分類。分類有以下幾種,記得,只回應對應類型的問題類型,不要有其它的內容,例如只回應Coding。";
   systemPrompt += $"{systemPrompt}\n\n分類類型如下:\n{string.Join("\n", _modelTypes.Select(mt => $"{mt.Type}"))}";
   string prompt = $"<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>";
   var response = await _chatClient.GetResponseAsync(prompt);
   string modelType = response.Text;

   return modelType;
}

就只要設定它的職能就可以了,當然要用哪個模型來做分類,這個大家可以自行測試。

然後是找出對應模型:

public string GetModelName(string category)
{
    var modelTarget = _modelTypes.FirstOrDefault(mt => mt.Type == category);
    return modelTarget?.ModelName ?? string.Empty;
}

執行的主程式:

using LLMRoutingLib;

Routing routing = new Routing();
string exitCommand = "exit";
string userInput = string.Empty;
while(userInput != exitCommand)
{
    Console.WriteLine("請輸入提示詞 (輸入 'exit' 以結束程式):");
    userInput = Console.ReadLine();
    if (string.IsNullOrEmpty(userInput) || userInput == exitCommand)
    {
        break;
    }
    string category = await routing.GetCategoryByPrompt(userInput);
    string modelName = routing.GetModelName(category);
    Console.WriteLine($"Result: Model: {modelName}, Category: {category}");
}

最後的執行結果: