エージェントは、AI シェルとインターフェイスを組み合わせて、特定の大規模な言語モデルまたはその他の支援プロバイダーと通信するコード ライブラリです。 ユーザーは自然言語を使用してエージェントとチャットして、目的の出力または支援を得ます。 エージェントは、ILLMAgent
パッケージから AIShell.Abstraction
インターフェイスを実装する C# クラスとして実装されます。
AIShell.Abstraction
レイヤーと AIShell.Kernel
の詳細については、AI シェルアーキテクチャ ドキュメントを参照してください。
この記事は、 Ollama 言語モデルのエージェントを作成するためのステップ バイ ステップ ガイドです。 この記事の目的は、エージェントの作成方法の簡単な例を提供することです。 リポジトリの AIShell.Ollama.Agent
フォルダーには、Ollama エージェントのより堅牢な実装があります。
前提 条件
- .NET 8 SDK 以降
- PowerShell 7.4.6 以降
エージェントを作成する手順
この例では、Ollama を使用して言語モデルphi3
と通信するエージェントを作成します。 Ollama は、ローカルにビルドされた LLM/SLM を管理および使用するための CLI ツールです。
手順 1: 新しいプロジェクトを作成する
最初のステップは、新しい classlib プロジェクトを作成することです。
OllamaAgent
という名前の新しいフォルダーを作成する次のコマンドを実行して、新しいプロジェクトを作成します。
dotnet new classlib
手順 2: 必要なパッケージを追加する
新しく作成したプロジェクト内で、NuGet ギャラリーから AIShell.Abstraction パッケージをインストールする必要があります。 次のコマンドを使用して NuGet パッケージをインストールします。
dotnet add package AIShell.Abstraction --version 1.0.0-preview.2
このコマンドは、パッケージを .csproj
ファイルに追加します。
.csproj
ファイルには、次の XML が含まれている必要があります。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AIShell.Abstraction" Version="1.0.0-preview.2" />
</ItemGroup>
</Project>
大事な
NuGet ギャラリーから最新バージョンを使用していることを確認してください。
手順 3: エージェント クラスを実装する
ILLMAgent
インターフェイスを実装するには、Class1.cs
ファイルを変更します。
- ファイルの名前を
OllamaAgent.cs
に変更する - クラスの名前を
OllamaAgent
に変更する - 実装でコードによって使用される .NET 名前空間を追加する
using System.Diagnostics;
using System.Text;
using System.Text.Json;
using AIShell.Abstraction;
namespace AIShell.Ollama.Agent;
public sealed class OllamaAgent : ILLMAgent
{
}
手順 4: 必要なクラス メンバーとメソッドを追加する
次に、エージェント クラスの必要な変数とメソッドを実装します。 コメントは、OllamaAgent クラスのメンバーの説明を提供します。
_chatService
メンバーは、後の手順で実装する OllamaChatService クラスのインスタンスです。
public sealed class OllamaAgent : ILLMAgent
{
/// <summary>
/// The name of the agent
/// </summary>
public string Name => "ollama";
/// <summary>
/// The description of the agent to be shown at start up
/// </summary>
public string Description => "This is an AI assistant that uses the Ollama CLI tool. Be sure to follow all prerequisites in https://aka.ms/ollama/readme";
/// <summary>
/// This is the company added to `/like` and `/dislike` verbiage for who the telemetry helps.
/// </summary>
public string Company => "Microsoft";
/// <summary>
/// These are samples that are shown at start up for good questions to ask the agent
/// </summary>
public List<string> SampleQueries => [
"How do I list files in a given directory?"
];
/// <summary>
/// These are any optional legal/additional information links you want to provide at start up
/// </summary>
public Dictionary<string, string> LegalLinks { private set; get; }
/// <summary>
/// This is the chat service to call the API from
/// </summary>
private OllamaChatService _chatService;
/// <summary>
/// A string builder to render the text at the end
/// </summary>
private StringBuilder _text;
/// <summary>
/// Dispose method to clean up the unmanaged resource of the chatService
/// </summary>
public void Dispose()
{
_chatService?.Dispose();
}
/// <summary>
/// Initializing function for the class when the shell registers an agent
/// </summary>
/// <param name="config">Agent configuration for any configuration file and other settings</param>
public void Initialize(AgentConfig config)
{
_text = new StringBuilder();
_chatService = new OllamaChatService();
LegalLinks = new(StringComparer.OrdinalIgnoreCase)
{
["Ollama Docs"] = "https://github.com/ollama/ollama",
["Prerequisites"] = "https://aka.ms/ollama/readme"
};
}
/// <summary>
/// Get commands that an agent can register to the shell when being loaded
/// </summary>
public IEnumerable<CommandBase> GetCommands() => null;
/// <summary>
/// Gets the path to the setting file of the agent.
/// </summary>
public string SettingFile { private set; get; } = null;
/// <summary>
/// Refresh the current chat by starting a new chat session.
/// An agent can reset chat states in this method.
/// </summary>
public void RefreshChat() {}
/// <summary>
/// Gets a value indicating whether the agent accepts a specific user action feedback.
/// </summary>
/// <param name="action">The user action.</param>
public bool CanAcceptFeedback(UserAction action) => false;
/// <summary>
/// A user action was taken against the last response from this agent.
/// </summary>
/// <param name="action">Type of the action.</param>
/// <param name="actionPayload"></param>
public void OnUserAction(UserActionPayload actionPayload) {}
/// <summary>
/// Main chat function that takes
/// </summary>
/// <param name="input">The user input from the chat experience</param>
/// <param name="shell">The shell that provides host functionality</param>
/// <returns>Task Boolean that indicates whether the query was served by the agent.</returns>
public async Task<bool> Chat(string input, IShell shell)
{
}
}
最初の実装では、エージェントは「Hello World!」を返し、正しいインターフェースを作成したことを証明します。 また、ユーザーが操作をキャンセルしようとしたときに例外をキャッチして処理するために、 try-catch
ブロックを追加する必要があります。
Chat
メソッドに次のコードを追加します。
public async Task<bool> Chat(string input, IShell shell)
{
// Get the shell host
IHost host = shell.Host;
// get the cancellation token
CancellationToken token = shell.CancellationToken;
try
{
host.RenderFullResponse("Hello World!");
}
catch (OperationCanceledException e)
{
_text.AppendLine(e.ToString());
host.RenderFullResponse(_text.ToString());
return false;
}
return true;
}
手順 5: Ollama チェックを追加する
次に、Ollama が実行されていることを確認する必要があります。
public async Task<bool> Chat(string input, IShell shell)
{
// Get the shell host
IHost host = shell.Host;
// get the cancellation token
CancellationToken token = shell.CancellationToken;
if (Process.GetProcessesByName("ollama").Length is 0)
{
host.RenderFullResponse("Please be sure that Ollama is installed and the server is running. Ensure that you have met all the prerequisites in the README for this agent.");
return false;
}
// Calls to the API will go here
return true;
}
手順 6: チャット サービスとデータを交換するデータ構造を作成する
Ollama API を使用する前に、Ollama API との間で入力を送受信するクラスを作成する必要があります。 次の Ollama の例 は、エージェントからの入力と応答の形式を示しています。
この例では、ストリーミングを無効にして Ollama API を呼び出します。 Ollama は、単一の固定応答を生成します。 今後は、エージェントが応答を受信するときにリアルタイムで応答をレンダリングできるように、ストリーミング機能を追加できます。
データ構造を定義するには、OllamaSchema.cs
という名前の同じフォルダーに新しいファイルを作成します。 次のコードをファイルにコピーします。
namespace AIShell.Ollama.Agent;
// Query class for the data to send to the endpoint
internal class Query
{
public string prompt { get; set; }
public string model { get; set; }
public bool stream { get; set; }
}
// Response data schema
internal class ResponseData
{
public string model { get; set; }
public string created_at { get; set; }
public string response { get; set; }
public bool done { get; set; }
public string done_reason { get; set; }
public int[] context { get; set; }
public double total_duration { get; set; }
public long load_duration { get; set; }
public int prompt_eval_count { get; set; }
public int prompt_eval_duration { get; set; }
public int eval_count { get; set; }
public long eval_duration { get; set; }
}
internal class OllamaResponse
{
public int Status { get; set; }
public string Error { get; set; }
public string Api_version { get; set; }
public ResponseData Data { get; set; }
}
これで、Ollama API を使用するチャット サービスを構築するために必要な要素が追加されました。 別のチャット サービス クラスは必要ありませんが、API の呼び出しを抽象化すると便利です。
エージェントと同じフォルダーに OllamaChatService.cs
という名前の新しいファイルを作成します。 サンプル コードをファイルにコピーします。
ヒント
この例では、Ollama API のハードコーディングされたエンドポイントと言語モデルを使用します。 今後は、エージェント構成ファイルで構成可能なパラメーターを定義できます。
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using AIShell.Abstraction;
namespace AIShell.Ollama.Agent;
internal class OllamaChatService : IDisposable
{
/// <summary>
/// Ollama endpoint to call to generate a response
/// </summary>
internal const string Endpoint = "http://localhost:11434/api/generate";
/// <summary>
/// Http client
/// </summary>
private readonly HttpClient _client;
/// <summary>
/// Initialization method to initialize the http client
/// </summary>
internal OllamaChatService()
{
_client = new HttpClient();
}
/// <summary>
/// Dispose of the http client
/// </summary>
public void Dispose()
{
_client.Dispose();
}
/// <summary>
/// Preparing chat with data to be sent
/// </summary>
/// <param name="input">The user input from the chat experience</param>
/// <returns>The HTTP request message</returns>
private HttpRequestMessage PrepareForChat(string input)
{
// Main data to send to the endpoint
var requestData = new Query
{
model = "phi3",
prompt = input,
stream = false
};
var json = JsonSerializer.Serialize(requestData);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(HttpMethod.Post, Endpoint) { Content = data };
return request;
}
/// <summary>
/// Getting the chat response async
/// </summary>
/// <param name="context">Interface for the status context used when displaying a spinner.</param>
/// <param name="input">The user input from the chat experience</param>
/// <param name="cancellationToken">The cancellation token to exit out of request</param>
/// <returns>Response data from the API call</returns>
internal async Task<ResponseData> GetChatResponseAsync(IStatusContext context, string input, CancellationToken cancellationToken)
{
try
{
HttpRequestMessage request = PrepareForChat(input);
HttpResponseMessage response = await _client.SendAsync(request, cancellationToken);
response.EnsureSuccessStatusCode();
context?.Status("Receiving Payload ...");
Console.Write(response.Content);
var content = await response.Content.ReadAsStreamAsync(cancellationToken);
return JsonSerializer.Deserialize<ResponseData>(content);
}
catch (OperationCanceledException)
{
// Operation was cancelled by user.
}
return null;
}
}
手順 7: チャット サービスを呼び出す
次に、メイン エージェント クラスでチャット サービスを呼び出す必要があります。
Chat()
メソッドを変更してチャット サービスを呼び出し、応答をユーザーに表示します。 完成した Chat()
メソッドの例を次に示します。
public async Task<bool> Chat(string input, IShell shell)
{
// Get the shell host
IHost host = shell.Host;
// get the cancellation token
CancellationToken token = shell.CancellationToken;
if (Process.GetProcessesByName("ollama").Length is 0)
{
host.RenderFullResponse("Please be sure that Ollama is installed and the server is running. Ensure that you have met all the prerequisites in the README for this agent.");
return false;
}
ResponseData ollamaResponse = await host.RunWithSpinnerAsync(
status: "Thinking ...",
func: async context => await _chatService.GetChatResponseAsync(context, input, token)
).ConfigureAwait(false);
if (ollamaResponse is not null)
{
// render the content
host.RenderFullResponse(ollamaResponse.response);
}
return true;
}
エージェント コードが完了しました。
手順 8: エージェントをビルドしてテストする
次に、コードが期待どおりに動作していることをビルドしてテストする必要があります。 次のコマンドを実行します。
dotnet build
このコマンドは、プロジェクトの \bin\Debug\net8.0
フォルダーに必要なすべてのパッケージをビルドします。
エージェント aish
読み込むには、.dll
ファイルを Agents
フォルダー内のフォルダーにコピーする必要があります。
フォルダー名はエージェント名と同じである必要があります。
エージェントは、次の 2 つの場所のいずれかにインストールできます。
-
Agents
をインストールした場所の下にあるaish.exe
フォルダー内。 ai Shell の [インストール スクリプト][08] は、%LOCALAPPDATA%\Programs\AIShell
にインストールされます。%LOCALAPPDATA%\Programs\AIShell\Agents\OllamaAgent
フォルダーを作成します。 - 代わりに、
%USERPROFILE%\.aish\Agents
にエージェントをインストールします。%USERPROFILE%\.aish\Agents\OllamaAgent
フォルダーを作成します。
.dll
ファイルを作成したエージェント フォルダーにコピーします。
aish
を開始すると、エージェントが表示されます。
AI Shell
v1.0.0-preview.2
Please select an agent to use:
azure
>ollama
openai-gpt
自分のエージェントを共有するにはどうすればよいですか?
一元化されたリポジトリでエージェントを共有する方法はありません。 独自のエージェントを開発するために、このリポジトリをフォークすることをお勧めします。 フォークのリンクは、このリポジトリの Agent Sharing
タブの セクションで共有できます。 エージェントを使用するには、エージェントdll
ファイルを aish.exe
のベースディレクトリの agents
フォルダに配置します。 AI Shell は、そのフォルダからエージェントを自動的に読み込みます。