最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#后端集成CodeBuddy CLI的完整方案

 更新時間:2026年03月15日 14:46:32   作者:newbe36524  
本文詳細介紹了如何在C#后端項目中集成CodeBuddyCLI,實現(xiàn)AI編程助手能力的完整方案,通過分層架構設計和依賴注入,該方案支持多種AIProvider,并提供了流式和非流式兩種調(diào)用方式,需要的朋友可以參考下

本文將詳細介紹如何在 C# 后端項目中集成 CodeBuddy CLI,實現(xiàn) AI 編程助手能力的完整方案。

背景

在現(xiàn)代 AI 代碼助手開發(fā)中,單一 AI Provider 往往無法滿足復雜多變的開發(fā)場景。這就像,人生路遠,總不能只認一個方向吧?HagiCode 作為一款多功能 AI 編程助手,需要支持多種 AI Provider 以提供更好的用戶體驗。畢竟,用戶的選擇權還是要給夠的。在 2026 年初,項目面臨一個關鍵決策:如何在 C# 后端中恢復 CodeBuddy 的 ACP(Agent Communication Protocol)集成能力。

此前項目中曾實現(xiàn)過 CodeBuddy 對接,但相關代碼在一次重構中被移除了。其實也沒什么好抱怨的,代碼迭代嘛,總有東西要被遺忘。本次技術方案的目標是完整恢復這一能力,并優(yōu)化架構使其更加健壯和可維護。

如果你也在考慮為自己的項目接入多種 AI 編程助手,下面的方案或許能給你一些啟發(fā)——這可是我們踩了無數(shù)坑之后總結出來的經(jīng)驗。或許能讓你少走點彎路,也算是我做過的一點好事吧。

關于 HagiCode

本文分享的方案來自我們在 HagiCode 項目中的實踐經(jīng)驗。HagiCode 是一個開源的 AI 代碼助手項目,支持多種 AI Provider 和跨平臺運行。為了滿足不同用戶的偏好,我們需要能夠靈活切換各種 AI 編程助手,這就有了本文要介紹的 CodeBuddy 集成方案。

HagiCode 采用模塊化設計,AI Provider 作為可插拔的組件,這種架構讓我們可以輕松添加新的 AI 支持,而不影響現(xiàn)有功能。這也罷了,設計這種東西,當初做得好,后面省心不少。如果你對我們的技術架構感興趣,可以在 GitHub 上查看完整源碼。

架構設計

分層架構概覽

C# 與 CodeBuddy 的對接采用清晰的分層架構,這種設計讓代碼職責分明,后期維護起來也更加方便:

┌─────────────────────────────────────────────┐
│           Provider 契約層                    │
│   AIProviderType 枚舉 + 擴展方法             │
├─────────────────────────────────────────────┤
│           Provider 工廠層                    │
│   AIProviderFactory 依賴注入工廠             │
├─────────────────────────────────────────────┤
│           Provider 實現(xiàn)層                    │
│   CodebuddyCliProvider 具體實現(xiàn)              │
├─────────────────────────────────────────────┤
│           ACP 基礎設施層                     │
│  ACPSessionManager / StdioAcpTransport      │
│  AcpRpcClient / AcpAgentClient              │
└─────────────────────────────────────────────┘

這種分層的好處是什么呢?簡單說就是各層之間互不打擾。假設以后要換一種通信方式(比如從 stdio 改成 WebSocket),你只需要改最下面那一層,上面的業(yè)務代碼完全不用動。畢竟,誰也不想牽一發(fā)而動全身,改個通信方式還要改半天業(yè)務代碼,那也太慘了。

核心組件解析

Provider 契約層 是整個架構的基石。我們定義了 AIProviderType 枚舉,其中 CodebuddyCli = 3 作為枚舉值,通過擴展方法實現(xiàn)字符串與枚舉的雙向映射。這樣配置文件中的字符串可以很方便地轉成枚舉,調(diào)試時枚舉也能轉成字符串輸出。這也罷了,其實就是個映射關系,但做好了就是省心。

Provider 工廠層 負責根據(jù)配置創(chuàng)建對應的 Provider 實例。這里使用了 .NET 的依賴注入機制,配合 ActivatorUtilities.CreateInstance 實現(xiàn)動態(tài)創(chuàng)建。工廠模式的好處在于,新增一個 Provider 時只需要添加創(chuàng)建邏輯,不用修改已有的代碼。這和寫文章差不多,想加個新章節(jié),就加個新章節(jié),不用把前面的都重寫一遍。

Provider 實現(xiàn)層 是真正干活的地方。CodebuddyCliProvider 實現(xiàn)了 IAIProvider 接口,提供 ExecuteAsync(非流式)和 StreamAsync(流式)兩種調(diào)用方式。

ACP 基礎設施層 則是通信的底層支撐。這一層處理所有的協(xié)議細節(jié),包括進程管理、消息序列化、響應解析等。就像房子的地基,上面蓋得再漂亮,底下的東西得穩(wěn)才行。

通信機制

Stdio 傳輸模式

CodeBuddy 使用 Stdio(標準輸入輸出) 方式與外部進程通信。啟動命令很簡單:

codebuddy --acp

然后通過標準輸入輸出進行 JSON-RPC 消息交換。這種方式的優(yōu)勢在于:

  1. 啟動迅速:本地進程通信沒有網(wǎng)絡延遲
  2. 配置簡單:只需要指定可執(zhí)行文件路徑
  3. 環(huán)境隔離:每個會話獨立進程,互不影響

通信過程中支持環(huán)境變量注入,常用的包括:

  • CODEBUDDY_API_KEY:API 密鑰認證
  • CODEBUDDY_INTERNET_ENVIRONMENT:網(wǎng)絡環(huán)境配置

這就像,人與人之間的溝通,找個方便的方式,才能說得上話。

消息協(xié)議

ACP 基于 JSON-RPC 2.0 協(xié)議,消息格式大概是醬紫的:

// 請求消息
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "agent/prompt",
  "params": {
    "prompt": "幫我寫一個排序算法",
    "sessionId": "session-123"
  }
}
// 響應消息
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": "這里是 AI 的回復..."
  }
}

實際實現(xiàn)中,我們把這些協(xié)議細節(jié)都封裝好了,上層業(yè)務代碼只需要關注 prompt 和 response 就行。這也罷了,封裝得好,后面的人用起來就舒服點。

核心實現(xiàn)

1. Provider 契約恢復

首先在枚舉文件中恢復 CodeBuddy 類型:

// PCode.Models/AIProviderType.cs
public enum AIProviderType
{
    ClaudeCodeCli = 0,
    CodexCli = 1,
    GitHubCopilot = 2,
    CodebuddyCli = 3,  // 恢復這個枚舉值
    OpenCodeCli = 4,
    IFlowCli = 5,
}

然后在擴展方法中添加字符串映射,這樣配置文件就可以用字符串指定 Provider:

// AIProviderTypeExtensions.cs
private static readonly Dictionary<string, AIProviderType> _typeMap = new(
    StringComparer.OrdinalIgnoreCase)
{
    ["CodebuddyCli"] = AIProviderType.CodebuddyCli,
    ["Codebuddy"] = AIProviderType.CodebuddyCli,
    ["codebuddy"] = AIProviderType.CodebuddyCli,
    // ... 其他 provider 的映射
};

2. Provider 工廠集成

在工廠類中添加 CodeBuddy 的創(chuàng)建分支:

// AIProviderFactory.cs
private IAIProvider? CreateProvider(AIProviderType providerType, ProviderConfiguration config)
{
    return providerType switch
    {
        AIProviderType.CodebuddyCli =>
            ActivatorUtilities.CreateInstance<CodebuddyCliProvider>(
                _serviceProvider,
                Options.Create(config)),
        // ... 其他 provider
        _ => throw new NotSupportedException($"Provider {providerType} not supported")
    };
}

這里用了依賴注入的 ActivatorUtilities,它會自動處理構造函數(shù)的參數(shù)注入,非常方便。這也罷了,.NET 的東西,用對了就是省心。

3. 完整的 Provider 實現(xiàn)

下面是 CodebuddyCliProvider 的核心實現(xiàn),包含了流式和非流式兩種調(diào)用方式:

public class CodebuddyCliProvider : IAIProvider
{
    private readonly ILogger<CodebuddyCliProvider> _logger;
    private readonly IACPSessionManager _sessionManager;
    private readonly ProviderConfiguration _config;

    public string Name => "CodebuddyCli";
    public bool SupportsStreaming => true;
    public ProviderCapabilities Capabilities { get; }

    public CodebuddyCliProvider(
        ILogger<CodebuddyCliProvider> logger,
        IACPSessionManager sessionManager,
        IOptions<ProviderConfiguration> config)
    {
        _logger = logger;
        _sessionManager = sessionManager;
        _config = config.Value;

        // 定義當前 Provider 的能力
        Capabilities = new ProviderCapabilities
        {
            SupportsStreaming = true,
            SupportsTools = true,
            SupportsSystemMessages = true,
            SupportsArtifacts = false,
            MaxTokens = 8192
        };
    }

    // 非流式調(diào)用:等所有結果一起返回
    public async Task<AIResponse> ExecuteAsync(
        AIRequest request,
        CancellationToken cancellationToken = default)
    {
        // 為請求創(chuàng)建獨立會話
        var session = await _sessionManager.CreateSessionAsync(
            "CodebuddyCli",
            request.WorkingDirectory,
            cancellationToken,
            request.SessionId);

        try
        {
            var fullPrompt = BuildPrompt(request);
            await session.SendPromptAsync(fullPrompt, cancellationToken);

            var responseBuilder = new StringBuilder();
            var toolCalls = new List<AIToolCall>();

            // 收集所有響應塊
            await foreach (var chunk in StreamFromSession(session, cancellationToken))
            {
                if (!string.IsNullOrEmpty(chunk.Content))
                {
                    responseBuilder.Append(chunk.Content);
                }
                // 處理工具調(diào)用...
            }

            return new AIResponse
            {
                Content = AIResultContentSanitizer.SanitizeResultContent(
                    responseBuilder.ToString()),
                ToolCalls = toolCalls,
                Provider = Name,
                Model = string.Empty
            };
        }
        finally
        {
            // 釋放會話資源
            await session.DisposeAsync();
        }
    }

    // 流式調(diào)用:實時返回響應塊
    public async IAsyncEnumerable<AIStreamingChunk> StreamAsync(
        AIRequest request,
        [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        var session = await _sessionManager.CreateSessionAsync(
            "CodebuddyCli",
            request.WorkingDirectory,
            cancellationToken);

        try
        {
            var fullPrompt = BuildPrompt(request);
            await session.SendPromptAsync(fullPrompt, cancellationToken);

            await foreach (var chunk in StreamFromSession(session, cancellationToken))
            {
                yield return chunk;
            }
        }
        finally
        {
            await session.DisposeAsync();
        }
    }

    private async IAsyncEnumerable<AIStreamingChunk> StreamFromSession(
        IACPSession session,
        [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        // 遍歷會話中的所有更新
        await foreach (var notification in session.ReceiveUpdatesAsync(cancellationToken))
        {
            switch (notification.Update)
            {
                case AgentMessageChunkSessionUpdate agentMessage:
                    // 處理文本內(nèi)容塊
                    if (agentMessage.Content is AcpImp.TextContentBlock textContent)
                    {
                        yield return new AIStreamingChunk
                        {
                            Content = textContent.Text,
                            Type = StreamingChunkType.ContentDelta,
                            IsComplete = false
                        };
                    }
                    break;

                case ToolCallSessionUpdate toolCall:
                    // 處理工具調(diào)用
                    yield return new AIStreamingChunk
                    {
                        Content = string.Empty,
                        Type = StreamingChunkType.ToolCallDelta,
                        ToolCallDelta = new AIToolCallDelta
                        {
                            Id = toolCall.ToolCallId,
                            Name = toolCall.Kind.ToString(),
                            Arguments = toolCall.RawInput?.ToString()
                        }
                    };
                    break;

                case AcpImp.PromptCompletedSessionUpdate:
                    // 響應完成
                    yield break;
            }
        }
    }

    // 構建完整的提示詞
    private string BuildPrompt(AIRequest request, string? embeddedCommandPrompt = null)
    {
        var sb = new StringBuilder();

        // 嵌入命令提示詞(如果有)
        if (!string.IsNullOrEmpty(embeddedCommandPrompt))
        {
            sb.AppendLine(embeddedCommandPrompt);
            sb.AppendLine();
        }

        // 系統(tǒng)消息
        if (!string.IsNullOrEmpty(request.SystemMessage))
        {
            sb.AppendLine(request.SystemMessage);
            sb.AppendLine();
        }

        // 用戶 prompt
        sb.Append(request.Prompt);
        return sb.ToString();
    }
}

這段代碼有幾個關鍵點:

  1. 會話管理:每個請求創(chuàng)建獨立會話,請求完成后釋放資源。這是坑踩出來的經(jīng)驗——如果會話復用做得不好,很容易出現(xiàn)狀態(tài)污染的問題。畢竟,用過就得收拾干凈,不然下次用的人就麻煩了。
  2. 流式處理IAsyncEnumerable 讓響應可以邊生成邊返回,不用等全部內(nèi)容生成完。這對于長文本場景特別重要,用戶體驗會好很多。就像,等結果的人也不想一直干等著不是。
  3. 工具調(diào)用:CodeBuddy 支持工具調(diào)用(Function Calling),通過 ToolCallSessionUpdate 處理。這個能力對于復雜的代碼編輯任務很關鍵。
  4. 內(nèi)容過濾:使用 AIResultContentSanitizer 過濾 Think 塊內(nèi)容,保持輸出干凈。

4. 依賴注入配置

在模塊注冊中添加相關服務:

// PCodeClaudeHelperModule.cs
public void ConfigureModule(IServiceCollection context)
{
    // 注冊 Provider
    context.Services.AddTransient<CodebuddyCliProvider>();

    // 注冊 ACP 基礎設施
    context.Services.AddSingleton<IACPSessionManager, ACPSessionManager>();
    context.Services.AddSingleton<IAcpPlatformConfigurationResolver, AcpPlatformConfigurationResolver>();
    context.Services.AddSingleton<IAIRequestToAcpMapper, AIRequestToAcpMapper>();
    context.Services.AddSingleton<IAcpToAIResponseMapper, AcpToAIResponseMapper>();
}

配置示例

配置文件

appsettings.json 中添加 CodeBuddy 相關配置:

AI:
  # 默認使用的 Provider
  DefaultProvider: "CodebuddyCli"
  # Provider 配置
  Providers:
    CodebuddyCli:
      Type: "CodebuddyCli"
      WorkingDirectory: "C:/projects/my-app"
      ExecutablePath: "C:/tools/codebuddy.cmd"
  # 平臺相關配置
  PlatformConfigurations:
    CodebuddyCli:
      ExecutablePath: "C:/tools/codebuddy.cmd"
      Arguments: "--acp"
      StartupTimeoutMs: 5000
      EnvironmentVariables:
        CODEBUDDY_API_KEY: "${CODEBUDDY_API_KEY}"
        CODEBUDDY_INTERNET_ENVIRONMENT: "production"

配置模型

對應的配置模型定義:

public class CodebuddyPlatformConfiguration : IAcpPlatformConfiguration
{
    public string ProviderName => "CodebuddyCli";
    public AcpTransportType TransportType => AcpTransportType.Stdio;
    public string ExecutablePath { get; set; } = "codebuddy";
    public string Arguments { get; set; } = "--acp";
    public int StartupTimeoutMs { get; set; } = 5000;
    public Dictionary<string, string?>? EnvironmentVariables { get; set; }
}

實踐經(jīng)驗總結

踩坑記錄

我們在實現(xiàn)過程中遇到了幾個典型的坑,分享出來讓大家少走彎路。畢竟,別人的坑,自己能避開就是好事:

  1. 會話泄漏問題:一開始沒有正確釋放會話,導致進程資源耗盡。解決方法是使用 try-finally 確保每次請求都會釋放資源。這也罷了,用過的東西得放回去,不然后面的人用什么。
  2. 環(huán)境變量傳遞:Windows 和 Linux 的環(huán)境變量語法不同,后來統(tǒng)一使用 Dictionary<string, string?> 來處理??缙脚_這種事,一開始就統(tǒng)一規(guī)范,后面就省心。
  3. 超時配置:CLI 啟動需要時間,設置了 5 秒的啟動超時,避免快速請求失敗。凡事都得有個度,太急了反而辦不成事。
  4. 編碼問題:Windows 上默認編碼可能導致中文亂碼,在啟動進程時顯式指定 UTF-8 編碼。中文顯示不出來,那多難受。

性能優(yōu)化

  1. 會話池:對于頻繁的短請求,可以考慮實現(xiàn)會話池來復用進程
  2. 連接緩存:工廠類已經(jīng)支持 Provider 實例緩存
  3. 異步優(yōu)先:全程使用異步編程,避免阻塞線程

性能這種事,能優(yōu)化就優(yōu)化,畢竟用戶等的越久,體驗就越差。

總結

本文詳細介紹了 C# 后端集成 CodeBuddy CLI 的完整方案,涵蓋了從架構設計到具體實現(xiàn)的全過程。通過分層架構設計,我們將協(xié)議細節(jié)與業(yè)務邏輯分離,使得代碼更加清晰和可維護。

核心要點回顧:

  • 采用 Provider 契約層、工廠層、實現(xiàn)層、基礎設施層的分層架構
  • 使用 JSON-RPC over Stdio 方式進行進程間通信
  • 通過依賴注入實現(xiàn)靈活的配置和擴展
  • 提供流式和非流式兩種調(diào)用方式

這套方案不僅適用于 CodeBuddy,添加新的 AI Provider 也遵循同樣的模式。如果你也在做類似的多 AI Provider 集成,希望這篇文章能給你一些參考。其實,寫文章和寫代碼一樣,分享出來,能幫到別人就算沒白寫。

以上就是C#后端集成CodeBuddy CLI的完整方案的詳細內(nèi)容,更多關于C#集成CodeBuddy CLI的資料請關注腳本之家其它相關文章!

相關文章

  • C#微信公眾號開發(fā)之使用MessageHandler簡化消息處理流程

    C#微信公眾號開發(fā)之使用MessageHandler簡化消息處理流程

    這篇文章介紹了C#微信公眾號開發(fā)之使用MessageHandler簡化消息處理流程,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • Unity3D實現(xiàn)警報燈

    Unity3D實現(xiàn)警報燈

    這篇文章主要為大家詳細介紹了Unity3D實現(xiàn)警報燈效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • C# DataTable與Model互轉的示例代碼

    C# DataTable與Model互轉的示例代碼

    這篇文章主要介紹了C#DataTable與Model互轉的示例代碼,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-12-12
  • C#基于DBContext(EF)實現(xiàn)通用增刪改查的REST方法實例

    C#基于DBContext(EF)實現(xiàn)通用增刪改查的REST方法實例

    這篇文章主要介紹了C#基于DBContext(EF)實現(xiàn)通用增刪改查的REST方法實例,是C#程序設計中非常實用的技巧,需要的朋友可以參考下
    2014-10-10
  • c#互斥鎖Mutex類用法介紹

    c#互斥鎖Mutex類用法介紹

    本文詳細講解了c#互斥鎖Mutex類的用法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-02-02
  • C#簡單實現(xiàn)表達式目錄樹(Expression)

    C#簡單實現(xiàn)表達式目錄樹(Expression)

    表達式目錄樹以數(shù)據(jù)形式表示語言級別代碼。數(shù)據(jù)存儲在樹形結構中。表達式目錄樹中的每個節(jié)點都表示一個表達式。這篇文章給大家介紹C#簡單實現(xiàn)表達式目錄樹(Expression),需要的朋友參考下吧
    2017-11-11
  • C# 使用模式匹配的好處總結

    C# 使用模式匹配的好處總結

    模式匹配的這些用途展示了它在簡化代碼、提高可讀性和靈活處理不同類型和條件的強大能力,隨著C#語言的發(fā)展,模式匹配的功能和應用場景將會進一步擴展和深化,這篇文章主要介紹了C# 使用模式匹配的好處,需要的朋友可以參考下
    2024-07-07
  • c#?如何將字符串轉換為大寫或小寫

    c#?如何將字符串轉換為大寫或小寫

    這篇文章主要介紹了c#?如何將字符串轉換為大寫或小寫,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • DevExpress實現(xiàn)GridView當無數(shù)據(jù)行時提示消息

    DevExpress實現(xiàn)GridView當無數(shù)據(jù)行時提示消息

    這篇文章主要介紹了DevExpress實現(xiàn)GridView當無數(shù)據(jù)行時提示消息,需要的朋友可以參考下
    2014-08-08
  • C#?Chart控件標記問題詳解

    C#?Chart控件標記問題詳解

    這篇文章主要介紹了C#?Chart控件標記問題詳解,在做項目的時候,遇到一個需求,需要我對Chart圖標標記數(shù)據(jù)正在運行,實現(xiàn)數(shù)據(jù)可視化,文章通過圍繞主題展開詳情,需要的朋友可以參考一下
    2022-08-08

最新評論

梁河县| 洛隆县| 乳山市| 兖州市| 慈利县| 都昌县| 来宾市| 怀化市| 敦化市| 洛川县| 体育| 湘潭市| 临猗县| 耒阳市| 无极县| 西充县| 东乌| 龙江县| 德州市| 鄂尔多斯市| 滁州市| 淮北市| 边坝县| 定兴县| 湄潭县| 务川| 监利县| 江孜县| 荆门市| 衡山县| 得荣县| 龙江县| 和林格尔县| 磐安县| 洮南市| 黄山市| 临沭县| 建瓯市| 大同市| 富顺县| 衢州市|