■ HttpClient 클래스를 사용해 Ollama 연동 파이썬 LLM 서버와 통신하는 방법을 보여준다.
▶ AdditionalKeywordArgument.cs
1 2 3 4 5 6 7 8 9 10 |
namespace TestProject; /// <summary> /// 부가적 키워드 인자 /// </summary> public class AdditionalKeywordArgument { } |
▶ AIMessageChunk.cs
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
using Newtonsoft.Json; namespace TestProject; /// <summary> /// AI 메시지 청크 /// </summary> public class AIMessageChunk { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 컨텐트 - Content /// <summary> /// 컨텐트 /// </summary> [JsonProperty("content")] public string Content { get; set; } #endregion #region 부가적 키워드 인자 - AdditionalKeywordArgument /// <summary> /// 부가적 키워드 인자 /// </summary> [JsonProperty("additional_kwargs")] public AdditionalKeywordArgument AdditionalKeywordArgument { get; set; } #endregion #region 응답 메타 데이터 - ResponseMetadata /// <summary> /// 응답 메타 데이터 /// </summary> [JsonProperty("response_metadata")] public ResponseMetadata ResponseMetadata { get; set; } #endregion #region 타입 - Type /// <summary> /// 타입 /// </summary> [JsonProperty("type")] public string Type { get; set; } #endregion #region 명칭 - Name /// <summary> /// 명칭 /// </summary> [JsonProperty("name")] public string Name { get; set; } #endregion #region ID - ID /// <summary> /// ID /// </summary> [JsonProperty("id")] public string ID { get; set; } #endregion #region 예제 여부 - Example /// <summary> /// 예제 여부 /// </summary> [JsonProperty("example")] public bool Example { get; set; } #endregion #region 도구 호출 리스트 - ToolCallList /// <summary> /// 도구 호출 리스트 /// </summary> [JsonProperty("tool_calls")] public ToolCallList ToolCallList { get; set; } #endregion #region 무효 도구 호출 리스트 - InvalidToolCallList /// <summary> /// 무효 도구 호출 리스트 /// </summary> [JsonProperty("invalid_tool_calls")] public InvalidToolCallList InvalidToolCallList { get; set; } #endregion #region 사용 메타 데이터 - UsageMetadata /// <summary> /// 사용 메타 데이터 /// </summary> [JsonProperty("usage_metadata")] public UsageMetadata UsageMetadata { get; set; } #endregion #region 도구 호출 청크 리스트 - ToolCallChunkList /// <summary> /// 도구 호출 청크 리스트 /// </summary> [JsonProperty("tool_call_chunks")] public ToolCallChunkList ToolCallChunkList { get; set; } #endregion } |
▶ InvalidToolCallList.cs
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Collections.Generic; namespace TestProject; /// <summary> /// 무효 도구 호출 리스트 /// </summary> public class InvalidToolCallList : List<object> { } |
▶ RequestMessage.cs
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 |
using System.Collections.Generic; using Newtonsoft.Json; namespace TestProject; /// <summary> /// 요청 메시지 /// </summary> public class RequestMessage { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 메시지 리스트 - MessageList /// <summary> /// 메시지 리스트 /// </summary> [JsonProperty("messages")] public List<Dictionary<string, string>> MessageList { get; set; } #endregion } |
▶ ResponseMetadata.cs
1 2 3 4 5 6 7 8 9 10 |
namespace TestProject; /// <summary> /// 응답 메타 데이터 /// </summary> public class ResponseMetadata { } |
▶ ToolCallChunkList.cs
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Collections.Generic; namespace TestProject; /// <summary> /// 도구 호출 청크 리스트 /// </summary> public class ToolCallChunkList : List<object> { } |
▶ ToolCallList.cs
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Collections.Generic; namespace TestProject; /// <summary> /// 도구 호출 리스트 /// </summary> public class ToolCallList : List<object> { } |
▶ UsageMetadata.cs
1 2 3 4 5 6 7 8 9 10 |
namespace TestProject; /// <summary> /// 사용 메타 데이터 /// </summary> public class UsageMetadata { } |
▶ ChatBotClient.cs
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using Newtonsoft.Json; namespace TestProject; /// <summary> /// 챗봇 클라이언트 /// </summary> public class ChatBotClient { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 기준 URL /// </summary> private readonly string baseURL; /// <summary> /// HTTP 클라이언트 /// </summary> private readonly HttpClient httpClient; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ChatBotClient(baseURL) /// <summary> /// 생성자 /// </summary> /// <param name="baseURL">기준 URL</param> public ChatBotClient(string baseURL) { this.baseURL = baseURL; this.httpClient = new HttpClient(); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 스트리밍 메시지 비동기 열거 가능형 요청하기 (비동기) - RequestStreamingMessageAsyncEnumerableAsync(requestMessage, cancellationToken) /// <summary> /// 스트리밍 메시지 비동기 열거 가능형 요청하기 (비동기) /// </summary> /// <param name="requestMessage">요청 메시지</param> /// <param name="cancellationToken">취소 토큰</param> /// <returns>스트리밍 메시지 비동기 열거 가능형</returns> public async IAsyncEnumerable<AIMessageChunk> RequestStreamingMessageAsyncEnumerableAsync(RequestMessage requestMessage, [EnumeratorCancellation] CancellationToken cancellationToken = default) { StringContent stringContent = new(JsonConvert.SerializeObject(requestMessage), Encoding.UTF8, "application/json"); using HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, baseURL) { Content = stringContent }; using HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken); if(httpResponseMessage.IsSuccessStatusCode) { using Stream stream = await httpResponseMessage.Content.ReadAsStreamAsync(cancellationToken); using StreamReader streamReader = new(stream); string line; while((line = await streamReader.ReadLineAsync(cancellationToken)) != null) { if(cancellationToken.IsCancellationRequested) { yield break; } if(line == "data: [DONE]") { break; } if(line.StartsWith("data: ")) { AIMessageChunk aiMessageChunk = JsonConvert.DeserializeObject<AIMessageChunk>(line[6..]); yield return aiMessageChunk; } } } } #endregion } |
▶ Program.cs
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 |
using System; using System.Collections.Generic; using System.Threading.Tasks; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private static async Task Main() { ChatBotClient chatBotClient = new("http://localhost:8000/chat"); RequestMessage requestMessage = new(); requestMessage.MessageList = new List<Dictionary<string, string>> { new Dictionary<string, string> { { "role", "system" }, { "content", "당신은 python 개발자입니다." } }, new Dictionary<string, string> { { "role", "user" }, { "content", "python을 사용해 별을 화면 중앙에 표시하는 프로그램을 만들어주세요." } } }; Console.WriteLine("Sending request to the chatbot..."); await foreach(AIMessageChunk aiMessageChunk in chatBotClient.RequestStreamingMessageAsyncEnumerableAsync(requestMessage)) { Console.Write(aiMessageChunk.Content); } } #endregion } |