Skip to main content
net10.0

IronHive Amazon S3 storage provider

Published
Oct 10, 2026
8d ago
Total Downloads
9.6K
9,553

Install

dotnet add package IronHive.Storages.Amazon --version 0.61.0
ProductVersions
.NET
net10.0

README

IronHive

IronHive๋Š” ๊ธฐ์—…์šฉ AI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ .NET 10 ํŒŒ์ดํ”„๋ผ์ธ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํŒจํ„ด์œผ๋กœ ๋ฉ€ํ‹ฐ Provider LLM ํ†ตํ•ฉ, ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜, RAG ํŒŒ์ดํ”„๋ผ์ธ, ํŒŒ์ผ ์ฒ˜๋ฆฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ธฐ๋Šฅ

  • ๋ฉ€ํ‹ฐ Provider LLM โ€” OpenAI, Anthropic, Google AI (Gemini/Vertex AI), OpenAI Compatible (Ollama, LM Studio, GPUStack ๋“ฑ)
  • ๋ชจ๋ธ ๋ชฉ๋ก์˜ ํ•œ๋„ โ€” IModelFinder.ListModelsAsync/FindModelAsync ๊ฐ€ ๋ชฉ๋ก API ๊ฐ€ ์•Œ๋ ค ์ฃผ๋Š” ์ปจํ…์ŠคํŠธ์™€ ์ตœ๋Œ€ ์ถœ๋ ฅ์„ LanguageModelCard.ContextWindowยทMaxOutputTokens ๋กœ ์‹ฃ๋Š”๋‹ค(Google AI inputTokenLimitยทoutputTokenLimit, Anthropic max_input_tokensยทmax_tokens, OpenAI ์™€์ด์–ด ์„œ๋ฒ„ยท๊ฒŒ์ดํŠธ์›จ์ด์˜ max_model_lenยทcontext_lengthยทcontext_windowยทmax_completion_tokensยทtop_provider.* โ€” OpenAIModelFinderยทOpenAICompatibleModelFinder, ๋“ฑ๋ก ์‹œ ์ž๋™). ์•Œ๋ ค ์ฃผ์ง€ ์•Š๋Š” ์„œ๋ฒ„๋Š” null
  • ์‚ฌ์šฉ๋Ÿ‰ ๋‚ด์—ญ โ€” MessageTokenUsage ๊ฐ€ ์ž…๋ ฅยท์ถœ๋ ฅ ํ•ฉ๊ณ„ ์™ธ์— ์บ์‹œ ์ฝ๊ธฐ(CachedInputTokens), ์บ์‹œ ์“ฐ๊ธฐ(CacheWriteInputTokens)์™€ ๊ทธ TTL ๋ณ„ ๋‚ด์—ญ(CacheWritesByTtl โ€” Anthropic 5๋ถ„/1์‹œ๊ฐ„), ์ถ”๋ก  ํ† ํฐ(ReasoningTokens)์„ ๊ณต๊ธ‰์ž๊ฐ€ ๋ณด๊ณ ํ•˜๋Š” ๋งŒํผ ์‹ฃ๋Š”๋‹ค โ€” ๊ณต๊ธ‰์ž๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋งค๊ธฐ๋Š” ๋ถ€๋ถ„์„ ์†Œ๋น„์ž๊ฐ€ ๋‹ค์‹œ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค. M.E.AI ์–ด๋Œ‘ํ„ฐ๋Š” UsageDetails.ReasoningTokenCount ์™€ AdditionalCounts[ChatClientAdapter.CacheWriteInputTokenCountKey] ๋กœ ์˜ฎ๊ธด๋‹ค
  • ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ โ€” SequentialOrchestrator ยท ParallelOrchestrator ยท HubSpokeOrchestrator(๊ฐ์ž์˜ โ€ฆOrchestratorOptions ๋กœ ์ƒ์„ฑ), HandoffOrchestratorBuilder ยท GroupChatOrchestratorBuilder ยท GraphOrchestratorBuilder(DAG). ๊ณตํ†ต ์˜ต์…˜ โ€” ํƒ€์ž„์•„์›ƒ ยท StopOnAgentFailure ยท ์—์ด์ „ํŠธ ๋ฏธ๋“ค์›จ์–ด ยท ์Šน์ธ ํ•ธ๋“ค๋Ÿฌ ยท ์ปจํ…์ŠคํŠธ ์Šค์ฝ”ํ”„ ยท ๊ฒฐ๊ณผ distiller โ€” ์€ ์˜ต์…˜ ๊ฐ์ฒด ๋˜๋Š” ๋นŒ๋”์˜ Setโ€ฆ ์œผ๋กœ ์ค€๋‹ค(docs/ORCHESTRATION.md)
  • RAG ํŒŒ์ดํ”„๋ผ์ธ โ€” ํ…์ŠคํŠธ ์ถ”์ถœ, ์ฒญํ‚น, ์ž„๋ฒ ๋”ฉ, ๋ฒกํ„ฐ ๊ฒ€์ƒ‰
  • ๋‹ค์ค‘ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ โ€” ์ด๋ฏธ์ง€ ์ƒ์„ฑ, ์Œ์„ฑ TTS/STT, ๋น„๋””์˜ค ์ƒ์„ฑ
  • ํ”Œ๋Ÿฌ๊ทธ์ธ โ€” MCP: McpClientManager.AddOrUpdate(new McpHttpClientConfig{โ€ฆ} / McpStdioClientConfig{โ€ฆ}) ๋กœ ์„œ๋ฒ„๋ฅผ ๋ถ™์ด๊ณ  ์„ธ์…˜์˜ ๋„๊ตฌ๋ฅผ ์—์ด์ „ํŠธ ๋„๊ตฌ์— ๋”ํ•œ๋‹ค(HTTP/Stdio/OAuth). OpenAPI: new OpenApiClientManager(tools) ์— await AddOrUpdateAsync(client) ๋กœ OpenApiClient ๋ฅผ ๋“ฑ๋กํ•˜๋ฉด ์ŠคํŽ™์˜ ์—ฐ์‚ฐ์ด ๊ทธ IToolCollection ์— ๋„๊ตฌ๋กœ ๋“ค์–ด๊ฐ„๋‹ค(docs/PLUGINS.md)
  • M.E.AI ํ˜ธํ™˜ โ€” ํŒจํ‚ค์ง€ IronHive.Extensions.AI(์˜์กด: Abstractions ๋ฟ โ€” Core ์—†์ด provider ๋ฅผ IChatClient ๋กœ): generator.AsChatClient(model, provider) ยท AsEmbeddingGenerator(โ€ฆ) ยท AIToolAdapter(์ž„์˜์˜ AITool์„ ITool๋กœ ๋ž˜ํ•‘ยท์‹คํ–‰ โ€” MCP McpClientTool ๋“ฑ). ๋„๊ตฌ ์ธ์ž ์ŠคํŠธ๋ฆฌ๋ฐ(opt-in): ChatOptions.AdditionalProperties[ChatClientAdapter.StreamToolArgumentsKey] = true ์ด๋ฉด ์ŠคํŠธ๋ฆฌ๋ฐ ์‘๋‹ต์ด ์ธ์ž๋ฅผ ์“ฐ์ด๋Š” ๋™์•ˆ FunctionCallDeltaContent(CallId ยท ์ฒซ ์กฐ๊ฐ์˜ Name ยท ArgumentsFragment)๋กœ๋„ ๋‚ด๊ณ , ์™„์ „ํ•œ FunctionCallContent ๊ฐ€ ๋’ค๋”ฐ๋ฅธ๋‹ค(Chat CompletionsยทResponsesยทAnthropic โ€” Anthropic ์€ ์ด๋•Œ ๋„๊ตฌ๋งˆ๋‹ค eager_input_streaming ์„ ์ผœ์„œ ์„œ๋ฒ„๊ฐ€ ์ž…๋ ฅ์„ ๋๊นŒ์ง€ ๋ชจ์•˜๋‹ค ๋ณด๋‚ด์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค(MessageGenerationRequest.StreamToolArguments, ์„œ๋ฒ„ ๊ฒ€์ฆ ์—†์Œ). Google ์€ ํ˜ธ์ถœ์„ ํ•œ ๋ฒˆ์— ๋ณด๋‚ธ๋‹ค). using IronHive.Extensions.AI;
  • ์›Œํฌํ”Œ๋กœ์šฐ โ€” ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ํƒ€์ž… ์•ˆ์ „ ์›Œํฌํ”Œ๋กœ์šฐ ์—”์ง„
  • ๊ตฌ์กฐํ™” ์ถœ๋ ฅ โ€” OutputFormat.For<T>()/For(schema) ๋Š” ์Šคํ‚ค๋งˆ๋กœ ๊ตฌ์†, OutputFormat.Json ์€ ์Šคํ‚ค๋งˆ ์—†๋Š” JSON ๋ชจ๋“œ(provider ๋„ค์ดํ‹ฐ๋ธŒ JSON ๋ชจ๋“œ๋กœ ๋ฒˆ์—ญ โ€” OpenAI json_object, Gemini responseMimeType, Anthropic ์€ ์‹œ์Šคํ…œ ์ง€์‹œ). AgentInvokeOptions.OutputFormat ๋˜๋Š” IChatClient ์˜ ChatOptions.ResponseFormat ์œผ๋กœ ์ผ ๋‹ค
  • ๋„๊ตฌ ๊ฒฐ๊ณผ ํ•ฉ๊ณ„ ์˜ˆ์‚ฐ โ€” ToolResultBudgetMiddleware๊ฐ€ ํ•œ ํ˜ธ์ถœ์˜ ๋„๊ตฌ ๋ฃจํ”„ ์ „์ฒด์—์„œ ๋ชจ๋ธ์— ๋ณด๋‚ด๋Š” ๊ฒฐ๊ณผ ํ…์ŠคํŠธ ํ•ฉ๊ณ„๋ฅผ ์ œํ•œ(์ž‘์€ ๋ฌธ๋งฅ ์ฐฝ ๋Œ€์‘, docs/TOOLS.md)
  • ๊ณต๊ธ‰์ž ๊ณ ์œ  ํ•„๋“œ โ€” MessageRequest.ExtraBody(์ž„๋ฒ ๋”ฉ์€ EmbeddingRequestOptions.ExtraBody, EmbedBatchAsync(model, inputs, options)) ๊ฐ€ ์š”์ฒญ ๋ณธ๋ฌธ์— ํ•ฉ์ณ์ง€๊ณ , ๋งคํ•‘๋˜์ง€ ์•Š์€ ์‘๋‹ต ํ•„๋“œ(์˜ˆ: llama.cpp timings)๊ฐ€ MessageResponse.ExtraBody ๋กœ ๋Œ์•„์˜จ๋‹ค(OpenAI Compatible, docs/PROVIDERS.md)
  • ํ˜ธ์ถœ ๋‹จ์œ„ ํ—ค๋” โ€” MessageGenerationRequest.Headers(MessageRequest.Headers ยท AgentInvokeOptions.Headers ยท ChatOptions.AdditionalProperties[ChatClientAdapter.RequestHeadersKey])๊ฐ€ ๊ทธ ํ˜ธ์ถœ์—๋งŒ ์ถ”๊ฐ€ HTTP ํ—ค๋”๋ฅผ ์‹ฃ๋Š”๋‹ค โ€” ํ•œ ํด๋ผ์ด์–ธํŠธ๋กœ ์—ฌ๋Ÿฌ ์‹คํ–‰ ๋‹จ์œ„๋ฅผ ๋Œ๋ฆฌ๋ฉฐ ๊ฒŒ์ดํŠธ์›จ์ด ๊ท€์† ํƒœ๊ทธยท์ถ”์  id ๋ฅผ ํ˜ธ์ถœ๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋ณด๋‚ผ ๋•Œ. ๋„ค provider ๊ณตํ†ต, config Headers ์œ„์— ์–นํžˆ๊ณ  ๊ฐ™์€ ์ด๋ฆ„์ด๋ฉด ์š”์ฒญ ๊ฐ’์ด ์ด๊ธด๋‹ค(docs/PROVIDERS.md ยซํ˜ธ์ถœ ๋‹จ์œ„ ํ—ค๋”ยป)
  • ๊ฒŒ์ดํŠธ์›จ์ด ์ž๊ฒฉ์ฆ๋ช… ํ˜•ํƒœ โ€” OpenAI ์™€์ด์–ด(OpenAI ยท OpenAI Compatible ยท GPUStack)์˜ ํ‚ค ์Šฌ๋กฏ์ด ApiKeyPlacement(CredentialPlacement.Authorization("Basic") ยท .Authorization(null) ยท .InHeader("api-key"), ๊ธฐ๋ณธ Bearer)๋กœ ํ‚ค๋ฅผ ๋ณด๋‚ผ ํ—ค๋”์™€ scheme ์„ ์ •ํ•œ๋‹ค โ€” ํ‚ค๋Š” ๊ณ„์† ApiKey/ApiKeyResolver ์— ์žˆ๋‹ค(docs/PROVIDERS.md)
  • ํ† ํฐ ๋กœ๊ทธ ํ™•๋ฅ  โ€” MessageRequest.LogProbabilities(์ƒ์œ„ ๋Œ€์•ˆ 0~20)๋กœ ์ถœ๋ ฅ ํ† ํฐ๋ณ„ ๋กœ๊ทธ ํ™•๋ฅ ์„ ๋ฐ›๋Š”๋‹ค(MessageResponse.LogProbabilities, ์ŠคํŠธ๋ฆฌ๋ฐ done ํ”„๋ ˆ์ž„์—๋„; OpenAI Compatible ยท Google AI, docs/PROVIDERS.md)
  • ๋„๋ฉ”์ธ ์˜ˆ์™ธ โ€” ์ปจํ…์ŠคํŠธ ์œˆ๋„์šฐ ์ดˆ๊ณผ ์‹œ ํ”„๋กœ๋ฐ”์ด๋”๋ณ„ ์˜ค๋ฅ˜๋ฅผ ContextOverflowException(ContextWindowยทRequestTokens ํฌํ•จ)์œผ๋กœ ์ •๊ทœํ™” โ€” ๋ฌธ์ž์—ด ํŒŒ์‹ฑ ์—†์ด catch๋กœ ์••์ถ•ยท๋ณต๊ตฌ ๋กœ์ง ์ž‘์„ฑ ๊ฐ€๋Šฅ. ํ”„๋กœ๋ฐ”์ด๋” ๋Œ€์‹  ์ž๊ธฐ OpenAI SDK ํด๋ผ์ด์–ธํŠธ(๋˜๋Š” Microsoft.Extensions.AI.OpenAI)๋ฅผ ์“ฐ๋Š” ๊ฒฝ์šฐ OpenAIErrors.TryMapContextOverflow(ex)/TryMapRateLimit(ex)/TryMapBilling(ex)(IronHive.Providers.OpenAI)๋กœ ๊ฐ™์€ ๋งคํ•‘์„ ๋ฐ›๋Š”๋‹ค. ๊ณ„์ •์ด ์ง€๋ถˆํ•  ์ˆ˜ ์—†๋Š” ๊ฑฐ์ ˆ(HTTP 402, OpenAI insufficient_quota, Anthropic billing_error)์€ BillingException โ€” ๊ธฐ๋‹ค๋ ค๋„ ํ’€๋ฆฌ์ง€ ์•Š์œผ๋ฏ€๋กœ RateLimitException ๊ณผ ๊ตฌ๋ถ„๋œ๋‹ค. OpenAI ํ˜ธํ™˜ ํด๋ผ์ด์–ธํŠธ(IronHive.Providers.OpenAI.Compatible)์˜ ๊ทธ ๋ฐ–์˜ HTTP ์˜ค๋ฅ˜๋Š” ProviderHttpException โ€” HttpRequestException(๊ฐ™์€ StatusCode)์ด๋ฉด์„œ ์„œ๋ฒ„๊ฐ€ ๋ณด๋‚ธ Retry-After/retry-after-ms ๋ฅผ RetryAfter ๋กœ ์‹ฃ๋Š”๋‹ค(503 + ํžŒํŠธ = ยซ๊ธฐ๋‹ค๋ ค๋ผยป, ํžŒํŠธ ์—†์Œ = ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ). ์ด๋ฏธ ์‹œ์ž‘๋œ ์ŠคํŠธ๋ฆผ์˜ ์‹คํŒจ(์ŠคํŠธ๋ฆผ ์•ˆ์˜ ์˜ค๋ฅ˜ ์ด๋ฒคํŠธ, ์™„๋ฃŒ ์‹ ํ˜ธ ์—†์ด ๋Š๊ธด ์—ฐ๊ฒฐ)๋Š” ๋„ค ํ”„๋กœ๋ฐ”์ด๋” ๋ชจ๋‘ ์ •์ƒ ์™„๋ฃŒ๊ฐ€ ์•„๋‹ˆ๋ผ ์˜ˆ์™ธ๋‹ค โ€” ์œ„ ํƒ€์ž… ์ค‘ ๋งž๋Š” ๊ฒƒ, ๋‚˜๋จธ์ง€๋Š” ProviderResponseException(ErrorCode, ๊ฐ™์€ ์˜ค๋ฅ˜์˜ ์ŠคํŠธ๋ฆผ ๋ฐ– HTTP ์ƒํƒœ EquivalentStatusCode)

์™œ IronHive์ธ๊ฐ€

2026๋…„ 4์›” Microsoft Agent Framework 1.0์ด AutoGen๊ณผ Semantic Kernel์„ ํ†ตํ•ฉํ•ด GA๋กœ ์ถœ์‹œ๋˜๋ฉฐ .NET LLM ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜์˜ ์œ ๋ ฅํ•œ ๊ธฐ๋ณธ ์„ ํƒ์ง€๋กœ ๋– ์˜ฌ๋ž์Šต๋‹ˆ๋‹ค. IronHive๋Š” ์ด์™€ ๋‹ค๋ฅธ ์„ค๊ณ„ ์ถ•์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค โ€” ๋กœ์ปฌ ์šฐ์„ , ํด๋ผ์šฐ๋“œ ๋ฌด์˜์กด์ž…๋‹ˆ๋‹ค.

  • ์™„์ „ํ•œ ๋กœ์ปฌ ์ถ”๋ก  ๋ฃจํ”„ โ€” lm-supply๋กœ LLM ์ƒ์„ฑยท์ž„๋ฒ ๋”ฉยท๋ฆฌ๋žญํ‚นยทOCR๊นŒ์ง€ GGUF/ONNX ๋ฐฑ์—”๋“œ๋กœ ์ˆœ์ˆ˜ .NET์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์šฐ๋“œ ๊ณ„์ •์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ์—†์ด๋„ ์—์ด์ „ํŠธ ๋ฃจํ”„ ์ „์ฒด๊ฐ€ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ๋„ค์ดํ‹ฐ๋ธŒ .NET, ๋ธŒ๋ฆฌ์ง€ ๋ถˆํ•„์š” โ€” Microsoft Agent Framework์˜ ๋กœ์ปฌ ์‹คํ–‰ ๊ฒฝ๋กœ(Foundry Local)๋Š” 2026๋…„ ๊ธฐ์ค€ Python ์ „์šฉ์ด๋ฉฐ, .NET์—์„œ ์“ฐ๋ ค๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ ์–ด๋Œ‘ํ„ฐ๋ฅผ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. IronHive๋Š” ๋กœ์ปฌ ์ถ”๋ก ์ด ์ฒ˜์Œ๋ถ€ํ„ฐ .NET 1๊ธ‰ ์‹œ๋ฏผ์ž…๋‹ˆ๋‹ค.
  • RAG ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด์žฅ โ€” ๋ฌธ์„œ ์ฒ˜๋ฆฌ(FileFlux/WebFlux)๋ถ€ํ„ฐ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒ€์ƒ‰(FluxIndex)๊นŒ์ง€ ๋ณ„๋„ ํ†ตํ•ฉ ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Azure ์ƒํƒœ๊ณ„์— ์ด๋ฏธ ํˆฌ์žํ•œ ํŒ€์ด๋ผ๋ฉด Microsoft Agent Framework๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์šด ์„ ํƒ์ž…๋‹ˆ๋‹ค. ์˜คํ”„๋ผ์ธ/์—์–ด๊ฐญ ํ™˜๊ฒฝ, ๋ฐ์ดํ„ฐ ์ƒ์ฃผ ์š”๊ตฌ์‚ฌํ•ญ, ๋˜๋Š” ํด๋ผ์šฐ๋“œ ์ข…์†์„ ํ”ผํ•˜๋ ค๋Š” .NET ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋ผ๋ฉด IronHive๊ฐ€ ๊ทธ ์ž๋ฆฌ๋ฅผ ์ฑ„์›๋‹ˆ๋‹ค.

์„ค์น˜

dotnet add package IronHive.Core
dotnet add package IronHive.Providers.OpenAI    # ๋˜๋Š” Anthropic, GoogleAI ๋“ฑ

๋น ๋ฅธ ์‹œ์ž‘

Standalone (์ฝ˜์†”)

using IronHive.Core;
using IronHive.Providers.OpenAI;
using IronHive.Abstractions.Messages.Content;

var hive = new HiveServiceBuilder()
    .AddOpenAIProviders("openai", new OpenAIConfig { ApiKey = "your-api-key" })
    .Build();

var agent = hive.CreateAgentFrom(cfg =>
{
    cfg.Provider = "openai";
    cfg.Model = "gpt-4o-mini";
    cfg.Instructions = "๋‹น์‹ ์€ ์นœ์ ˆํ•œ ๋„์šฐ๋ฏธ์ž…๋‹ˆ๋‹ค.";
});

// ๋‹จ์ˆœ ํ…์ŠคํŠธ ํ˜ธ์ถœ
var response = await agent.InvokeAsync("์•ˆ๋…•ํ•˜์„ธ์š”");

// per-request ์˜ต์…˜ (์—์ด์ „ํŠธ ๊ธฐ๋ณธ๊ฐ’ ์œ„์— ์ด ํ˜ธ์ถœ์—๋งŒ overlay)
var response2 = await agent.InvokeAsync("์•ˆ๋…•ํ•˜์„ธ์š”", new AgentInvokeOptions
{
    ThinkingEffort = MessageThinkingEffort.High,
    ThinkingOutput = MessageThinkingOutput.Summary,  // ์ถ”๋ก  ์š”์•ฝ์„ ์‘๋‹ต์— ์‹ฃ๊ธฐ (None ์ด๋ฉด ์ˆจ๊น€)
    Suggestions = new SuggestionOptions(),  // ํ›„์† ์งˆ์˜ ์ œ์•ˆ ํ™œ์„ฑํ™”
    MaxTokens = 2048,  // ์ถ”๋ก ๊ณผ ๋‹ต์ด ๋‚˜๋ˆ  ์“ฐ๋Š” ํ•œ๋„ โ€” ์˜ˆ์‚ฐ ๋ฐฉ์‹ provider ๋Š” ์ถ”๋ก  ์˜ˆ์‚ฐ์„ ์ด ์•ˆ์— ๋งž์ถ˜๋‹ค(ThinkingBudget.FitWithin)
});

// ์ŠคํŠธ๋ฆฌ๋ฐ
await foreach (var chunk in agent.InvokeStreamingAsync("์•ˆ๋…•ํ•˜์„ธ์š”"))
{
    // chunk ์ฒ˜๋ฆฌ
}

ASP.NET Core DI ํ†ตํ•ฉ

// Program.cs
builder.Services.AddHiveService((hiveBuilder, sp) =>
    hiveBuilder
        .AddOpenAIProviders("openai", new OpenAIConfig
        {
            ApiKey = builder.Configuration["OpenAI:ApiKey"]!
        })
        .Build());

// ์„œ๋น„์Šค์—์„œ IHiveService ์ฃผ์ž…
public class ChatService(IHiveService hive)
{
    public async Task<string> ChatAsync(string text)
    {
        var agent = hive.CreateAgentFrom(cfg =>
        {
            cfg.Provider = "openai";
            cfg.Model = "gpt-4o-mini";
        });
        var response = await agent.InvokeAsync(text);
        return response.Message?.Content
            .OfType<TextMessageContent>()
            .FirstOrDefault()?.Value ?? string.Empty;
    }
}

ํŒจํ‚ค์ง€

ํŒจํ‚ค์ง€ ์„ค๋ช…
IronHive.Abstractions ์ธํ„ฐํŽ˜์ด์Šค ๋ฐ ๊ณ„์•ฝ (์™ธ๋ถ€ ์˜์กด ์—†์Œ)
IronHive.Core ํ•ต์‹ฌ ๊ตฌํ˜„ (์—์ด์ „ํŠธ, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ, ์›Œํฌํ”Œ๋กœ์šฐ)
IronHive.Extensions.AI provider ๋ฅผ Microsoft.Extensions.AI IChatClient / IEmbeddingGenerator ๋กœ โ€” Abstractions ๋งŒ ์˜์กด(Core ๋ถˆํ•„์š”)
IronHive.Providers.OpenAI OpenAI / Azure OpenAI / xAI (Responses API, Embeddings, DALL-E, TTS/STT)
IronHive.Providers.Anthropic Anthropic Claude
IronHive.Providers.GoogleAI Google Gemini + Vertex AI (์ด๋ฏธ์ง€, ๋น„๋””์˜ค, ์˜ค๋””์˜ค ํฌํ•จ)
IronHive.Providers.OpenAI.Compatible Ollama, LM Studio, vLLM, llama.cpp, GPUStack ๋“ฑ โ€” Chat Completions ํ‘œ๋ฉด
IronHive.Storages.Qdrant Qdrant ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
IronHive.Storages.Amazon Amazon S3 ํŒŒ์ผ ์ €์žฅ์†Œ
IronHive.Storages.Azure Azure Blob / File Share
IronHive.Storages.RabbitMQ RabbitMQ ํ
IronHive.Plugins.MCP Model Context Protocol (HTTP/Stdio/OAuth)
IronHive.Plugins.OpenAPI OpenAPI ๋„๊ตฌ ์ž๋™ ์ƒ์„ฑ

์ถœ๋ ฅ ๊ธธ์ด ํŒŒ๋ผ๋ฏธํ„ฐ ์„ ํƒ (0.16.0~) โ€” OpenAI ๊ฐ€ max_tokens ๋ฅผ max_completion_tokens ๋กœ ๊ฐœ๋ช…ํ•˜๋ฉด์„œ ์ƒํƒœ๊ณ„๊ฐ€ ๊ฐˆ๋ ธ๋‹ค. ์ตœ์‹  OpenAI ๋ชจ๋ธ์€ ๊ตฌ ์ด๋ฆ„์„ ๊ฑฐ๋ถ€ํ•˜๊ณ , ๋‹ค์ˆ˜์˜ self-hosted ์„œ๋ฒ„๋Š” ์ƒˆ ์ด๋ฆ„์„ ๋ชจ๋ฅธ ์ฑ„ ๋ฌด์‹œํ•œ๋‹ค โ€” ๋ชจ๋ฅด๋Š” ํ•„๋“œ๋Š” ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์นจ๋ฌต์ด๋ฏ€๋กœ, ์ƒํ•œ์ด ์กฐ์šฉํžˆ ์‚ฌ๋ผ์ง€๊ณ  ์ฆ์ƒ์€ "์‘๋‹ต์ด ์˜ˆ์ƒ๋ณด๋‹ค ๊ธธ๋‹ค" ๋ฟ์ด๋‹ค. ์–ด๋””์„œ๋‚˜ ํ†ตํ•˜๋Š” ์ด๋ฆ„์ด ์—†์–ด ์„ ํƒ์ง€๋กœ ์ œ๊ณตํ•œ๋‹ค:

var config = new OpenAICompatibleConfig
{
    BaseUrl = "http://localhost:11434",
    TokenLimitParameter = TokenLimitParameter.MaxTokens   // ๊ตฌ ์ด๋ฆ„๋งŒ ์•„๋Š” ์„œ๋ฒ„
};

๊ธฐ๋ณธ๊ฐ’์€ MaxCompletionTokens โ€” ์ข…์ „ ๋™์ž‘ ๊ทธ๋Œ€๋กœ๋ผ ๊ธฐ์กด ์„ค์ •์€ ์˜ํ–ฅ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. Both ๋Š” ๋‘˜ ๋‹ค ๋ฐ›์•„๋“ค์ด๋Š” ์—”๋“œํฌ์ธํŠธ์—์„œ๋งŒ ์“ด๋‹ค(๊ตฌ ์ด๋ฆ„์„ ๊ฑฐ๋ถ€ํ•˜๋Š” ๊ณณ์—์„œ๋Š” ์š”์ฒญ ์ „์ฒด๊ฐ€ ์‹คํŒจํ•œ๋‹ค). MaxTokens ๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์–ด๋А ์„ค์ •์—์„œ๋„ ๋‘ ํ•„๋“œ ๋ชจ๋‘ ์ „์†ก๋˜์ง€ ์•Š๋Š”๋‹ค.

localhost ์™€ ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ (0.41.0~) โ€” ๊ฐ provider ๊ฐ€ ์ง์ ‘ ๋งŒ๋“œ๋Š” ์ „์†ก์€ ํ˜ธ์ŠคํŠธ์˜ ์ฃผ์†Œ๋“ค์„ ๊ฒฝ์ฃผ์‹œํ‚จ๋‹ค (RFC 8305): localhost ๊ฐ€ ::1 ๋ถ€ํ„ฐ ํ’€๋ ค๋„ IPv4 ์ „์šฉ ๋กœ์ปฌ ์„œ๋ฒ„(llama-server ยท Ollama ๊ธฐ๋ณธ๊ฐ’)์— ๊ณง๋ฐ”๋กœ ๋ถ™๋Š”๋‹ค. ๊ทธ ์ „์—๋Š” Windows ์—์„œ ๊ฑฐ๋ถ€๋œ IPv6 ์—ฐ๊ฒฐ์ด ์•ฝ 2 ์ดˆ ๊ฑธ๋ ค OpenAI-compatible ์˜ 2 ์ดˆ ConnectTimeout ์ด ๋จผ์ € ๋๋‚ฌ๋‹ค. HttpClient ๋ฅผ ์ง์ ‘ ์ฃผ์ž…ํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ™์€ ๋™์ž‘์€ IronHive.Abstractions.Http.ProviderConnect.CreateHandler(timeout) ๋กœ ์–ป๋Š”๋‹ค. OpenAI-compatible ยท GPUStack ์˜ ๊ธฐ๋ณธ ConnectTimeout ์€ 0.46.1 ๋ถ€ํ„ฐ 3 ์ดˆ๋‹ค โ€” Windows ๊ฐ€ ๊ฑฐ๋ถ€๋œ ์—ฐ๊ฒฐ์„ ์•Œ๋ฆฌ๋Š” ~2 ์ดˆ๋ณด๋‹ค ๊ธธ์–ด์•ผ ๊บผ์ง„ ์„œ๋ฒ„๊ฐ€ ํƒ€์ž„์•„์›ƒ์ด ์•„๋‹ˆ๋ผ ๊ฑฐ๋ถ€๋กœ ๋ณด๊ณ ๋œ๋‹ค.

์ŠคํŠธ๋ฆผ idle ํƒ€์ž„์•„์›ƒ StreamIdleTimeout (0.51.0~) โ€” ๋ชจ๋“  provider config ์— ์žˆ๋‹ค. ์ŠคํŠธ๋ฆฌ๋ฐ ์‘๋‹ต์ด ์ด ์‹œ๊ฐ„๋ณด๋‹ค ์˜ค๋ž˜ ์นจ๋ฌตํ•˜๋ฉด(์ฒซ ์ด๋ฒคํŠธ ์ „, ๋˜๋Š” ์ด๋ฒคํŠธ ์‚ฌ์ด) TimeoutException(ยซstream idle timeoutยป)์œผ๋กœ ๋๋‚œ๋‹ค. ์ „์ฒด ์š”์ฒญ ์‹œํ•œ๊ณผ ๋‹ฌ๋ฆฌ ๋А๋ฆฐ ์ŠคํŠธ๋ฆผ(๊ธด ํ”„๋กฌํ”„ํŠธ ํ‰๊ฐ€ ๋’ค ํ๋ฅด๋Š” ๋‹ต๋ณ€)๊ณผ ์ฃฝ์€ ์ŠคํŠธ๋ฆผ์„ ๊ฐ€๋ฅธ๋‹ค โ€” ๋กœ์ปฌ ์„œ๋ฒ„๋ผ๋ฉด ์ฒซ ํ† ํฐ ์ „ ํ‰๊ฐ€ ์‹œ๊ฐ„๋ณด๋‹ค ํฌ๊ฒŒ. ๊ธฐ๋ณธ ๋ฌด์ œํ•œ. OpenAICompatibleConfig ยท GpuStackConfig ๋Š” ์ด ๋ฒ„์ „๋ถ€ํ„ฐ Timeout ๋„ ๊ฐ–๋Š”๋‹ค. ๊ฐ™์€ ์˜ˆ์‚ฐ์„ ์ง์ ‘ ์“ฐ๋ ค๋ฉด IronHive.Abstractions.Http.ProviderStreams.WithIdleTimeout. ์ƒ์„ธ: docs/PROVIDERS.md ใ€Œ์ŠคํŠธ๋ฆผ idle ํƒ€์ž„์•„์›ƒใ€.

๋„๊ตฌ ์ด๋ฏธ์ง€ ์šด๋ฐ˜ CarryImageToolResultsAsUserMessage (0.49.0~) โ€” Chat Completions ์˜ tool ๋ฉ”์‹œ์ง€๋Š” ํ…์ŠคํŠธ๋งŒ ๋‹ด๊ณ , OpenAI ํ˜ธํ™˜ ์„œ๋ฒ„(vLLM ยท llama.cpp)๋Š” ๊ทธ ์ž๋ฆฌ์˜ ์ด๋ฏธ์ง€ part ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ๊ธฐ๋ณธ(๊บผ์ง)์€ ์ข…์ „๋Œ€๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ž๋ฆฌํ‘œ์‹œ ํ•œ ์ค„๋กœ ๋ฐ”๊พผ๋‹ค. ์ผœ๋ฉด ๋„๊ตฌ ๋ฉ”์‹œ์ง€๋Š” ํ…์ŠคํŠธ์™€ [image image/png โ€” attached in the next message] ๋ฅผ ๊ฐ–๊ณ , ๊ทธ ๋ผ์šด๋“œ์˜ ๋„๊ตฌ ๋ฉ”์‹œ์ง€๋“ค ๋’ค user ๋ฉ”์‹œ์ง€ ํ•˜๋‚˜๊ฐ€ ์ด๋ฏธ์ง€๋ฅผ ์‹ฃ๋Š”๋‹ค โ€” ๋กœ์ปฌ vision ๋ชจ๋ธ์ด MCP ๋„๊ตฌ๊ฐ€ ๊ทธ๋ฆฐ ๊ทธ๋ฆผ์„ ๋ณด๋Š” ๊ฒฝ๋กœ๋‹ค.

var config = new OpenAICompatibleConfig { BaseUrl = "http://127.0.0.1:8080", CarryImageToolResultsAsUserMessage = true };

SDK ์žฌ์‹œ๋„ ํšŸ์ˆ˜ MaxRetries (0.46.0~) โ€” OpenAIConfig ยท OpenAICompatibleConfig ยท GpuStackConfig ยท AnthropicConfig ๊ฐ€ ๊ฐ™์€ ์ด๋ฆ„ยท์˜๋ฏธ๋ฅผ ๊ฐ–๋Š”๋‹ค: ์‹คํŒจํ•œ ์š”์ฒญ(์ „์†ก ์‹คํŒจ ยท 408 ยท 429 ยท 5xx)์„ SDK ๊ฐ€ ๋ช‡ ๋ฒˆ ๋‹ค์‹œ ๋ณด๋‚ด๋Š”๊ฐ€. null ์€ SDK ๊ธฐ๋ณธ๊ฐ’ (OpenAI ๊ณ„์—ด 3ํšŒ = ์ตœ๋Œ€ 4 ์š”์ฒญ), 0 ์€ ํ•œ ๋ฒˆ๋งŒ ๋ณด๋‚ธ๋‹ค. ์—ฐ๊ฒฐ ํ™•์ธ์ฒ˜๋Ÿผ ์ฆ‰๋‹ต์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ RetryMiddleware ๋กœ ์ง์ ‘ ์žฌ์‹œ๋„ํ•˜๋Š” ๊ณณ์—์„œ๋Š” 0 ์œผ๋กœ ๋‘ฌ์•ผ ์žฌ์‹œ๋„๊ฐ€ ๊ณฑํ•ด์ง€์ง€ ์•Š๋Š”๋‹ค.

๋ฌธ์„œ

๋ฌธ์„œ ์„ค๋ช…
docs/ARCHITECTURE.md ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ ๋ฐ ์„ค๊ณ„ ์›์น™
docs/SETUP.md HiveServiceBuilder ๊ตฌ์„ฑ ๋ฐ DI ํ†ตํ•ฉ
docs/AGENTS.md ์—์ด์ „ํŠธ ์ƒ์„ฑ ๋ฐ ํ˜ธ์ถœ
docs/MIDDLEWARE.md ๋ฏธ๋“ค์›จ์–ด ์‹œ์Šคํ…œ (Retry, Timeout, CircuitBreaker ๋“ฑ)
docs/ORCHESTRATION.md ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ํŒจํ„ด
docs/TOOLS.md FunctionTool ๋ฐ ์ปค์Šคํ…€ ๋„๊ตฌ
docs/MEMORY.md RAG ํŒŒ์ดํ”„๋ผ์ธ ๋ฐ MemoryWorker
docs/PROVIDERS.md AI ํ”„๋กœ๋ฐ”์ด๋” ์„ค์ •
docs/STORAGES.md ์Šคํ† ๋ฆฌ์ง€ ๋ฐฑ์—”๋“œ ์„ค์ •
docs/PLUGINS.md MCP / OpenAPI ํ”Œ๋Ÿฌ๊ทธ์ธ
docs/SERVICES.md IHiveService ์„œ๋น„์Šค ์ƒ์„ธ

Skills (AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ์šฉ)

AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ(GitHub Copilot, Claude Code, Cursor ๋“ฑ)์—์„œ IronHive Skills๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด:

npx skills add iyulab/ironhive

์„ค์น˜ ํ›„ ์—์ด์ „ํŠธ๊ฐ€ IronHive API ํŒจํ„ด, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜, RAG ํŒŒ์ดํ”„๋ผ์ธ, ํˆด ์‚ฌ์šฉ๋ฒ•์„ ์ž๋™์œผ๋กœ ์ธ์‹ํ•ฉ๋‹ˆ๋‹ค.

์š”๊ตฌ ์‚ฌํ•ญ

  • .NET 10.0+

๋ผ์ด์„ ์Šค

MIT โ€” LICENSE ์ฐธ์กฐ.

Changes from Previous Version

No structural changes between v0.60.0 and v0.61.0.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 1 target framework; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.