Project Icon

Claudia

强类型非官方Anthropic Claude API .NET客户端

Claudia是一个非官方Anthropic Claude API的.NET客户端库,支持.NET Standard 2.1、.NET 6和.NET 8。该库提供类似官方SDK的强类型C# API,支持消息流处理、令牌计数和错误处理等核心功能。此外,Claudia还包含C#源生成器用于Function Calling,并支持文件上传、系统提示设置等高级特性。

Claudia

非官方的 Anthropic Claude API .NET 客户端。

我们构建了一个类似于官方 Python SDKTypeScript SDK 的 C# API。它支持 netstandard2.1、net6.0 和 net8.0。

除了纯客户端 SDK 外,它还包含一个用于执行函数调用的 C# 源代码生成器。

安装

该库通过 NuGet 分发,支持 .NET Standard 2.1、.NET 6(.NET 7) 和 .NET 8 或更高版本。

PM> Install-Package Claudia

它还可以在 Unity 游戏引擎的运行时和编辑器中使用。有关使用说明,请参阅 Unity 部分

您还可以将其与 AWS Bedrock 一起使用。有关更多详细信息,请查看 AWS Bedrock 部分

使用方法

有关 API 的详细信息,请查看官方 API 参考

using Claudia;

var anthropic = new Anthropic
{
    ApiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY") // 这是默认设置,可以省略
};

var message = await anthropic.Messages.CreateAsync(new()
{
    Model = "claude-3-5-sonnet-20240620", // 您可以使用 Claudia.Models.Claude3_5Sonnet 字符串常量
    MaxTokens = 1024,
    Messages = [new() { Role = "user", Content = "你好,Claude" }]
});

Console.WriteLine(message);

Claudia 的设计旨在与官方客户端具有相似的外观和感觉,特别是 TypeScript SDK。然而,它不使用 objectdynamicDictionary,所有内容都是强类型的。通过利用 C# 9.0 目标类型化 new 表达式C# 12 集合表达式,可以以简单的方式编写。

流式消息

我们提供使用服务器发送事件(SSE)的流式响应支持。

using Claudia;

var anthropic = new Anthropic();

var stream = anthropic.Messages.CreateStreamAsync(new()
{
    Model = "claude-3-opus-20240229",
    MaxTokens = 1024,
    Messages = [new() { Role = "user", Content = "你好,Claude" }]
});

await foreach (var messageStreamEvent in stream)
{
    Console.WriteLine(messageStreamEvent);
}

如果需要取消流,可以将 CancellationToken 传递给 CreateStreamAsync

流返回一个 IAsyncEnumerable<IMessageStreamEvent>,允许使用 await foreach 进行枚举。IMessageStreamEvent 的实现类型可以在 IMessageStreamEvent.cs 中找到。

例如,输出文本结果。

await foreach (var messageStreamEvent in stream)
{
    if (messageStreamEvent is ContentBlockDelta content)
    {
        Console.WriteLine(content.Delta.Text);
    }
}

请求和响应类型

该库包含所有请求参数和响应字段的 C# 定义。您可以像这样导入和使用它们:

using Claudia;

var request = new MessageRequest()
{
    Model = Models.Claude3Opus,
    MaxTokens = 1024,
    Messages = [new() { Role = Roles.User, Content = "你好,Claude" }]
};

每个方法、请求参数和响应字段的文档都可以在文档字符串中找到,并且在大多数现代编辑器中悬停时会显示。

所有 MessageRequest 定义都在这里 MessageRequest.cs,MessageResponse 定义在这里 MessageResponse.cs

此外,还定义了常用常量。例如,Models.Claude3Opusclaude-3-opus-20240229,像 "user" 和 "assistant" 这样的角色使用 Roles.UserRoles.Assistant 等常量。请参阅 Constant.cs 了解所有常量。另外,Claude 官方聊天界面中使用的系统提示被定义为 SystemPrompts.Claude3

计算令牌

您可以通过使用响应属性查看给定请求的确切使用情况,例如:

var message = await anthropic.Messages.CreateAsync(...)

// Usage { InputTokens = 11, OutputTokens = 18 }
Console.WriteLine(message.Usage);

流式助手

通过与 R3(新的响应式扩展库)集成,可以以各种方式处理流式事件。

// 转换为数组
var array = await stream.ToObservable().ToArrayAsync();

// 过滤并执行
await stream.ToObservable()
    .OfType<IMessageStreamEvent, ContentBlockDelta>()
    .Where(x => x.Delta.Text != null)
    .ForEachAsync(x =>
    {
        Console.WriteLine(x.Delta.Text);
    });

// 分支查询
var branch = stream.ToObservable().Publish();

var messageStartTask = branch.OfType<IMessageStreamEvent, MessageStart>().FirstAsync();
var messageDeltaTask = branch.OfType<IMessageStreamEvent, MessageDelta>().FirstAsync();

branch.Connect(); // 开始消费流

Console.WriteLine((await messageStartTask));
Console.WriteLine((await messageDeltaTask));

// 总计使用情况
var totalUsage = await stream.ToObservable()
    .Where(x => x is MessageStart or MessageDelta)
    .Select(x => x switch
    {
        MessageStart ms => ms.Message.Usage,
        MessageDelta delta => delta.Usage,
        _ => throw new ArgumentException()
    })
    .AggregateAsync((x, y) => new Usage { InputTokens = x.InputTokens + y.InputTokens, OutputTokens = x.OutputTokens + y.OutputTokens });

Console.WriteLine(totalUsage);

错误处理

当库无法连接到 API,或 API 返回非成功状态码(即 4xx 或 5xx 响应)时,将抛出 ClaudiaException 的子类:

try
{
    var msg = await anthropic.Messages.CreateAsync(new()
    {
        Model = Models.Claude3Opus,
        MaxTokens = 1024,
        Messages = [new() { Role = "user", Content = "你好,Claude" }]
    });
}
catch (ClaudiaException ex)
{
    Console.WriteLine((int)ex.Status); // 400(ErrorCode.InvalidRequestError)
    Console.WriteLine(ex.Name);        // invalid_request_error
    Console.WriteLine(ex.Message);     // Field required. Input:...
}

错误代码如下:

public enum ErrorCode
{
    /// <summary>请求的格式或内容有问题。</summary>
    InvalidRequestError = 400,
    /// <summary>API 密钥有问题。</summary>
    AuthenticationError = 401,
    /// <summary>您的 API 密钥没有权限使用指定的资源。</summary>
    PermissionError = 403,
    /// <summary>未找到请求的资源。</summary>
    NotFoundError = 404,
    /// <summary>您的账户已达到速率限制。</summary>
    RateLimitError = 429,
    /// <summary>Anthropic 系统内部发生了意外错误。</summary>
    ApiError = 500,
    /// <summary>Anthropic 的 API 暂时过载。</summary>
    OverloadedError = 529
}

重试

默认情况下,某些错误将自动重试 2 次,并使用短指数退避。连接错误(例如,由于网络连接问题)、408 请求超时、409 冲突、429 速率限制和 >=500 内部错误默认都会重试。

您可以使用 MaxRetries 选项来配置或禁用此功能:

// 为所有请求配置默认值:
var anthropic = new Anthropic
{
    MaxRetries = 0, // 默认为 2
};

// 或者,按请求配置:
await anthropic.Messages.CreateAsync(new()
{
    MaxTokens = 1024,
    Messages = [new() { Role = "user", Content = "你好,Claude" }],
    Model = "claude-3-opus-20240229"
}, new()
{
    MaxRetries = 5
});

超时

默认情况下,请求在 10 分钟后超时。您可以使用 Timeout 选项配置此设置:

// 为所有请求配置默认值:
var anthropic = new Anthropic
{
    Timeout = TimeSpan.FromSeconds(20) // 20 秒(默认为 10 分钟)
};

// 覆盖每个请求: await anthropic.Messages.CreateAsync(new() { MaxTokens = 1024, Messages = [new() { Role = "user", Content = "你好,Claude" }], Model = "claude-3-opus-20240229" }, new() { Timeout = TimeSpan.FromSeconds(5) });


超时时会抛出 `TimeoutException`。

注意,超时的请求默认会[重试两次](#retries)。

默认标头
---
我们会自动发送 `anthropic-version` 标头,值设为 `2023-06-01`。

如果需要,你可以在每个请求的基础上覆盖它。

请注意,这样做可能会导致SDK中的类型不正确和其他意外或未定义的行为。

```csharp
await anthropic.Messages.CreateAsync(new()
{
    MaxTokens = 1024,
    Messages = [new() { Role = "user", Content = "你好,Claude" }],
    Model = "claude-3-opus-20240229"
}, new()
{
    Headers = new() { { "anthropic-version", "我的自定义值" } }
});

自定义HttpClient

Anthropic客户端默认使用标准的HttpClient进行通信。如果你想自定义HttpClient的行为,可以传入一个HttpMessageHandler。此外,如果你不想在处理Anthropic客户端时处理HttpClient,可以将disposeHandler标志设置为false。

public class Anthropic : IDisposable
{
    public HttpClient HttpClient => httpClient;

    public Anthropic()
        : this(new HttpClientHandler(), true)
    {
    }

    public Anthropic(HttpMessageHandler handler)
        : this(handler, true)
    {
    }

    public Anthropic(HttpMessageHandler handler, bool disposeHandler)
    {
        this.httpClient = new HttpClient(handler, disposeHandler);
        this.httpClient.Timeout = System.Threading.Timeout.InfiniteTimeSpan; // 忽略超时,Anthropic客户端使用Timeout属性(或每个请求的覆盖)中的超时设置
    }

    public void Dispose()
    {
        httpClient.Dispose();
    }
}

此外,你可以通过HttpClient属性检索用于请求的HttpClient。这允许你修改诸如DefaultRequestHeaders之类的设置。

// 禁用keep-alive
anthropic.HttpClient.DefaultRequestHeaders.ConnectionClose = true;

你可以更改HttpClient.BaseAddress来更改API地址(例如,用于代理)。

// 请求发送到http://myproxy/messages而不是https://api.anthropic.com/v1/messages
anthropic.HttpClient.BaseAddress = new Uri("http://myproxy/");

访问原始响应数据(例如,标头)

通过按照HttpClient约定定义DelegatingHandler,可以在请求之前和之后钩入请求管道。这允许进行日志记录、添加遥测和检查响应标头信息。观察标头时,你可以看到包含了与RateLimit相关的额外信息。

image

让我们创建一个DelegatingHandler,它检索此信息,并在发生RateLimit时抛出一个带有RateLimit信息的特殊异常。

public class RateLimitDetailsHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if ((int)response.StatusCode == (int)ErrorCode.RateLimitError)
        {
            var requestLimit = int.Parse(response.Headers.GetValues("anthropic-ratelimit-requests-limit").First());
            var requestRemaining = int.Parse(response.Headers.GetValues("anthropic-ratelimit-requests-remaining").First());
            var requestReset = DateTime.Parse(response.Headers.GetValues("anthropic-ratelimit-requests-reset").First());
            var tokenLimit = int.Parse(response.Headers.GetValues("anthropic-ratelimit-tokens-limit").First());
            var tokenRemaining = int.Parse(response.Headers.GetValues("anthropic-ratelimit-tokens-remaining").First());
            var tokenReset = DateTime.Parse(response.Headers.GetValues("anthropic-ratelimit-tokens-reset").First());

            var error = await response.Content.ReadFromJsonAsync<ErrorResponseShape>(AnthropicJsonSerializerContext.Default.Options, cancellationToken);
            var message = error!.ErrorResponse.Message;

            throw new AnthropicRateLimitException(requestLimit, requestRemaining, requestReset, tokenLimit, tokenRemaining, tokenReset, message);
        }

        return response;
    }
}

public class AnthropicRateLimitException : Exception
{
    public int RateLimitRequestsLimit { get; }
    public int RateLimitRequestsRemaining { get; }
    public DateTime RateLimitRequestsReset { get; }
    public int RateLimitTokensLimit { get; }
    public int RateLimitTokensRemaining { get; }
    public DateTime RateLimitTokensReset { get; }


    public AnthropicRateLimitException(
        int rateLimitRequestsLimit,
        int rateLimitRequestsRemaining,
        DateTime rateLimitRequestsReset,
        int rateLimitTokensLimit,
        int rateLimitTokensRemaining,
        DateTime rateLimitTokensReset,
        string message) : base(message)
    {
        RateLimitRequestsLimit = rateLimitRequestsLimit;
        RateLimitRequestsRemaining = rateLimitRequestsRemaining;
        RateLimitRequestsReset = rateLimitRequestsReset;
        RateLimitTokensLimit = rateLimitTokensLimit;
        RateLimitTokensRemaining = rateLimitTokensRemaining;
        RateLimitTokensReset = rateLimitTokensReset;
    }
}

DelegatingHandler(HttpMessageHandler)可以传递给Anthropic的构造函数。

var anthropic = new Anthropic(new RateLimitDetailsHandler() { InnerHandler = new HttpClientHandler() });

上传文件

Message.Content接受多个Content对象。但是,如果传递单个字符串,它会自动转换为文本数组。

// 这段代码
Content = "你好,Claude"
// 会转换为以下内容
Content = [new Content
{
    Type = "text",
    Text = "你好,Claude"
}]

传递图像时,在Content中同时设置图像和文本。

var imageBytes = File.ReadAllBytes(@"dish.jpg");

var anthropic = new Anthropic();
var message = await anthropic.Messages.CreateAsync(new()
{
    Model = "claude-3-opus-20240229",
    MaxTokens = 1024,
    Messages = [new()
    {
        Role = "user",
        Content = [
            new()
            {
                Type = "image",
                Source = new()
                {
                    Type = "base64",
                    MediaType = "image/jpeg",
                    Data = imageBytes
                }
            },
            new()
            {
                Type = "text",
                Text = "描述这张图片。"
            }
        ]
    }],
});
Console.WriteLine(message);

上面的代码可以简化。如果将字符串传递给Content构造函数,它会被设置为文本,如果传递ReadOnlyMemory<byte>,它会被设置为图像。

var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Opus,
    MaxTokens = 1024,
    Messages = [new()
    {
        Role = Roles.User,
        Content = [
            new(imageBytes, "image/jpeg"),
            "描述这张图片。"
        ]
    }],
});
Console.WriteLine(message);

目前,有四种可上传的二进制类型:image/jpegimage/pngimage/gifimage/webp。例如,如果你想上传markdown文件,最好读取其内容并作为文本发送。如果你想上传PDF,你可以将其转换为文本或图像后再发送。像pptx这样的演示文件也可以作为图像发送,Claude会为你解释内容并提取文本。

系统提示和温度

MessageRequest的其他可选属性包括SystemMetadataStopSequencesTemperatureTopPTopK

var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    System = SystemPrompts.Claude3,
    Temperature = 0.4,
    Messages = [
        new() { Role = Roles.User, Content = "你好,Claude" },
    ],
});

SystemPrompts.Claude3是官方聊天UI中使用的系统提示的字符串常量。当然,你也可以设置任意的系统提示。

保存 / 加载

所有请求和响应模型都可以使用System.Text.Json.JsonSerializer进行序列化。此外,AnthropicJsonSerializerContext通过Source Generator提供了预生成的序列化器,可以实现更高的性能。

List<Message> chatMessages;

void Save()
{
    var json = JsonSerializer.Serialize(chatMessages, AnthropicJsonSerializerContext.Default.Options);
    File.WriteAllText("chat.json", json);
}

void Load()
{
    chatMessages = JsonSerializer.Deserialize<List<Message>>("chat.json", AnthropicJsonSerializerContext.Default.Options)!;
}

函数调用

Claude支持函数调用。

工具使用

工具使用(函数调用)是函数调用的新形式。目前它处于测试阶段,需要在标头中添加anthropic-beta标志。

var anthropic = new Anthropic();
anthropic.HttpClient.DefaultRequestHeaders.Add("anthropic-beta", "tools-2024-04-04");

使用Claudia,你只需定义带有[ClaudiaFunction]注解的静态方法,C# Source Generator就会自动生成必要的代码。

public static partial class FunctionTools
{
    /// <summary>
    /// 获取指定时区的当前时间,格式为时-分-秒。时区应以标准格式书写,如UTC、US/Pacific、Europe/London。
    /// </summary>
    /// <param name="timeZone">要获取当前时间的时区,如UTC、US/Pacific、Europe/London。</param>
    [ClaudiaFunction]
    public static string TimeOfDay(string timeZone)
    {
        var time =  TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.UtcNow, timeZone);
        return time.ToString("HH:mm:ss");
    }
}

partial class包含生成的.AllTools.Tools.[Methods].InvokeToolAsync(MessageResponse)

函数调用需要向Claude发送两次请求。流程如下:"在系统提示中包含可用工具的初始请求 -> 根据包含必要工具的消息执行函数 -> 将结果包含在新消息中并向Claude发送另一个请求。"

var anthropic = new Anthropic();
anthropic.HttpClient.DefaultRequestHeaders.Add("anthropic-beta", "tools-2024-04-04");

var input = new Message { Role = Roles.User, Content = "洛杉矶现在几点了?" };
var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    Tools = FunctionTools.AllTools, // 使用生成的Tools
    Messages = [input],
});

// 调用本地函数
var toolResult = await FunctionTools.InvokeToolAsync(message);

var response = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    Tools = FunctionTools.AllTools,
    Messages = [
        input,
        new() { Role = Roles.Assistant, Content = message.Content },
        new() { Role = Roles.User, Content = toolResult! }
    ],
});

// 洛杉矶现在的时间是上午10:45。
Console.WriteLine(response.Content.ToString());

ClaudiaFunction的返回类型也可以指定为Task<T>ValueTask<T>。这允许您执行各种任务,如HTTP请求或数据库请求。例如,可以如上所示定义一个获取指定网页内容的函数。

public static partial class FunctionTools
{
    // ...

    /// <summary>
    /// 从指定URL获取HTML内容。
    /// </summary>
    /// <param name="url">要获取HTML的URL。</param>
    [ClaudiaFunction]
    static async Task<string> GetHtmlFromWeb(string url)
    {
        // 在实际应用中,传递原始HTML可能会消耗太多令牌。
        // 您可以使用像AngleSharp这样的库在本地解析HTML,并将其转换为紧凑的文本结构以节省令牌。
        using var client = new HttpClient();
        return await client.GetStringAsync(url);
    }
}

请注意,允许的参数类型是boolsbytebyteshortushortintuintlongulongdecimalfloatdoublestringDateTimeDateTimeOffsetGuidTimeSpanEnum

返回值可以是任何类型,但它将使用ToString()转换为字符串。如果您想返回自定义字符串,请将返回类型设为string,并在函数内部格式化字符串。

旧版风格

Anthropic Cookbook提供了函数调用的示例。要实现这一点,需要复杂的XML生成和解析处理,以及基于解析结果的执行。

使用Claudia,您只需定义带有[ClaudiaFunction]注解的静态方法,C#源代码生成器就会自动生成必要的代码,包括解析器和系统消息。

public static partial class FunctionTools
{
    /// <summary>
    /// 获取指定时区的当前时间,格式为时-分-秒。时区应以标准格式书写,如UTC、US/Pacific、Europe/London。
    /// </summary>
    /// <param name="timeZone">要获取当前时间的时区,如UTC、US/Pacific、Europe/London。</param>
    [ClaudiaFunction]
    public static string TimeOfDay(string timeZone)
    {
        var time =  TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.UtcNow, timeZone);
        return time.ToString("HH:mm:ss");
    }
}

partial class包含生成的.SystemPrompt.InvokeAsync(MessageResponse)

函数调用需要向Claude发送两次请求。流程如下:"在系统提示中包含可用工具的初始请求 -> 根据包含必要工具的消息执行函数 -> 将结果包含在新消息中并向Claude发送另一个请求。"

// `FunctionTools.SystemPrompt`包含用于通知Claude可用工具的XML。
// 这个XML是从方法的XML文档注释生成的。
/*
在这个环境中,您可以使用一组工具来回答用户的问题。
...
您可以这样调用它们:
...
以下是可用的工具:
<tools>
  <tool_description>
    <tool_name>TimeOfDay</tool_name>
    <description>获取指定时区的当前时间,格式为时-分-秒。时区应以标准格式书写,如UTC、US/Pacific、Europe/London。</description>
    <parameters>
      <parameter>
        <name>timeZone</name>
        <type>string</type>
        <description>要获取当前时间的时区,如UTC、US/Pacific、Europe/London。</description>
      </parameter>
    </parameters>
  </tool_description>
</tools>
*/
// Console.WriteLine(FunctionTools.SystemPrompt);

var input = new Message { Role = Roles.User, Content = "洛杉矶现在几点了?" };
var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    System = FunctionTools.SystemPrompt, // 设置生成的提示
    StopSequences = [StopSequnces.CloseFunctionCalls], // 将</function_calls>设置为停止序列
    Messages = [input],
});

// Claude返回xml以调用工具
/*
<function_calls>
    <invoke>
        <tool_name>TimeOfDay</tool_name>
        <parameters>
            <timeZone>US/Pacific</timeZone>
        </parameters>
    </invoke>
*/
// Console.WriteLine(message);

// 自动生成的`FunctionTools.InvokeAsync`从`MessageResponse`中解析函数名和参数,
// 执行相应的函数,并生成XML以通知Claude函数执行结果。
var partialAssistantMessage = await FunctionTools.InvokeAsync(message);

// 通过将此消息作为Assistant响应的开头传递给Claude,
// 它将提供一个考虑了函数执行结果的续写。
/*
<function_calls>
    <invoke>
        <tool_name>TimeOfDay</tool_name>
        <parameters>
            <timeZone>US/Pacific</timeZone>
        </parameters>
    </invoke>
</function_calls>
<function_results>
    <result>
        <tool_name>TimeOfDay</tool_name>
        <stdout>03:27:03</stdout>
    </result>
</function_results>
*/
// Console.WriteLine(partialAssistantMessage);

var callResult = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    System = FunctionTools.SystemPrompt,
    Messages = [
        input, // 用户:"洛杉矶现在几点了?"
        new() { Role = Roles.Assistant, Content = partialAssistantMessage! } // 设置为Assistant
    ],
});

// 洛杉矶(US/Pacific时区)的当前时间是03:36:04。
Console.WriteLine(callResult);

对于初始请求,指定StopSequences.CloseFunctionCalls是高效的。此外,如果您想包含自己的系统提示,最好将其与生成的SystemPrompt连接起来。

ClaudiaFunction的返回类型也可以指定为Task<T>ValueTask<T>。这允许您执行各种任务,如HTTP请求或数据库请求。例如,可以如上所示定义一个获取指定网页内容的函数。

public static partial class FunctionTools
{
    // ...

    /// <summary>
    /// 从指定URL获取HTML内容。
    /// </summary>
    /// <param name="url">要获取HTML的URL。</param>
    [ClaudiaFunction]
    static async Task<string> GetHtmlFromWeb(string url)
    {
        // 在实际应用中,传递原始HTML可能会消耗太多令牌。
        // 您可以使用像AngleSharp这样的库在本地解析HTML,并将其转换为紧凑的文本结构以节省令牌。
        using var client = new HttpClient();
        return await client.GetStringAsync(url);
    }
}
var input = new Message
{
    Role = Roles.User,
    Content = """
        能用三行话总结这个页面吗?
        https://docs.anthropic.com/claude/docs/intro-to-claude
"""
};

var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    System = FunctionTools.SystemPrompt, // 设置生成的提示
    StopSequences = [StopSequnces.CloseFunctionCalls], // 将</function_calls>设置为停止序列
    Messages = [input],
});

var partialAssistantMessage = await FunctionTools.InvokeAsync(message);

var callResult = await anthropic.Messages.CreateAsync(new() { Model = Models.Claude3Haiku, MaxTokens = 1024, System = FunctionTools.SystemPrompt, Messages = [ input, new() { Role = Roles.Assistant, Content = partialAssistantMessage! } // 设置为助手 ], });

// 该页面可以用三行概括: // 1. Claude是由Anthropic开发的一系列大型语言模型,旨在彻底改变您与AI交互的方式。 // 2. 本文档旨在帮助您充分利用Claude,提供清晰的解释、示例、最佳实践和额外资源的链接。 // 3. Claude在涉及语言、推理、分析、编码等广泛任务中表现出色,文档涵盖了关键功能、提示入门和API使用。 Console.WriteLine(callResult);


可以定义多个函数,它们可以在一个请求中多次执行。

```csharp
public static partial class FunctionTools
{
    [ClaudiaFunction]
    public static string TimeOfDay(string timeZone) //...

    // 示例来自 https://github.com/anthropics/anthropic-cookbook/blob/main/function_calling/function_calling.ipynb

    /// <summary>
    /// 用于进行基本算术的计算器函数。
    /// 支持加法、减法、乘法
    /// </summary>
    /// <param name="firstOperand">第一个操作数(运算符之前)</param>
    /// <param name="secondOperand">第二个操作数(运算符之后)</param>
    /// <param name="operator">要执行的操作。必须是 +, -, *, 或 / 之一</param>
    [ClaudiaFunction]
    static double DoPairwiseArithmetic(double firstOperand, double secondOperand, string @operator)
    {
        return @operator switch
        {
            "+" => firstOperand + secondOperand,
            "-" => firstOperand - secondOperand,
            "*" => firstOperand * secondOperand,
            "/" => firstOperand / secondOperand,
            _ => throw new ArgumentException("不支持的操作")
        };
    }
}
var input = new Message
{
    Role = Roles.User,
    Content = """
        西雅图和东京现在几点了?
        顺便把1,984,135乘以9,343,116。
"""
};

var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    System = FunctionTools.SystemPrompt, // 设置生成的提示
    StopSequences = [StopSequnces.CloseFunctionCalls], // 设置</function_calls>作为停止序列
    Messages = [input],
});

var partialAssistantMessage = await FunctionTools.InvokeAsync(message);

var callResult = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Haiku,
    MaxTokens = 1024,
    System = FunctionTools.SystemPrompt,
    Messages = [
        input,
        new() { Role = Roles.Assistant, Content = partialAssistantMessage! } // 设置为助手
    ],
});

// 西雅图(美国太平洋时区)的时间是8:06:53。
// 东京(亚洲/东京时区)的时间是00:06:53。
// 1,984,135乘以9,343,116的结果是18,524,738,326,760。
Console.WriteLine(callResult);

注意,允许的参数类型为boolsbytebyteshortushortintuintlongulongdecimalfloatdoublestringDateTimeDateTimeOffsetGuidTimeSpanEnum

返回值可以是任何类型,但会使用ToString()转换为字符串。如果你想返回自定义字符串,请将返回类型设为string并在函数内格式化字符串。

Blazor示例

通过在Blazor中使用Claudia,你可以轻松创建如下所示的聊天界面。

blazorclauderec

所有代码可以在BlazorApp1中找到。

关键部分是Program.csHome.razor.cs中的设置。

// Program.cs

// 从用户机密获取ANTHROPIC_API_KEY
// https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets
Environment.SetEnvironmentVariable("ANTHROPIC_API_KEY", builder.Configuration["ANTHROPIC_API_KEY"]);

// 添加Anthropic客户端
builder.Services.AddSingleton<Anthropic>();

var app = builder.Build();
// Home.razor.cs

using Claudia;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace BlazorApp1.Components.Pages;

public partial class Home
{
    [Inject]
    public required Anthropic Anthropic { get; init; }

    double temperature = 1.0;
    string textInput = "";
    string systemInput = SystemPrompts.Claude3;
    List<Message> chatMessages = new();

    bool running = false;

    async Task SendClick()
    {
        if (running) return;
        if (string.IsNullOrWhiteSpace(textInput)) return;

        running = true;
        try
        {
            chatMessages.Add(new() { Role = Roles.User, Content = textInput });

            var stream = Anthropic.Messages.CreateStreamAsync(new()
            {
                Model = Models.Claude3Opus,
                MaxTokens = 1024,
                Temperature = temperature,
                System = string.IsNullOrWhiteSpace(systemInput) ? null : systemInput,
                Messages = chatMessages.ToArray()
            });

            var currentMessage = new Message { Role = Roles.Assistant, Content = "" };
            chatMessages.Add(currentMessage);

            textInput = ""; // 清空输入
            StateHasChanged();

            await foreach (var messageStreamEvent in stream)
            {
                if (messageStreamEvent is ContentBlockDelta content)
                {
                    currentMessage.Content[0].Text += content.Delta.Text;
                    StateHasChanged();
                }
            }
        }
        finally
        {
            running = false;
        }
    }
}

如果需要存储聊天消息历史,可以将List<Message> chatMessages序列化为JSON并保存到文件或数据库中。

AWS Bedrock

我们通过一个单独的包提供对Anthropic Bedrock API的支持。

PM> Install-Package Claudia.Bedrock

要从AWS SDK创建AmazonBedrockRuntimeClient并使用UseAnthropic指定Bedrock模型ID,请将RequestMessage的Model属性设置为anthropic_version。其余部分与常规Anthropic客户端相同。

// credentials是你自己的
AWSConfigs.AWSProfileName = "";

var bedrock = new AmazonBedrockRuntimeClient(RegionEndpoint.USEast1);
var anthropic = bedrock.UseAnthropic("anthropic.claude-3-haiku-20240307-v1:0"); // 模型ID

var response = await anthropic.Messages.CreateAsync(new()
{
   Model = "bedrock-2023-05-31", // anthropic_version
   MaxTokens = 1024,
   Messages = [new() { Role = "user", Content = "你好,Claude" }]
});

Console.WriteLine(response);

流式消息的工作方式相同。

var stream = anthropic.Messages.CreateStreamAsync(new()
{
    Model = "bedrock-2023-05-31", // anthropic_version
    MaxTokens = 1024,
    Messages = [new() { Role = "user", Content = "你好,Claude" }]
});

await foreach (var item in stream)
{
    Console.WriteLine(item);
}

如果需要原始响应,请改为调用InvokeModelAsyncInvokeModelWithResponseStreamAsync。这允许你在使用GetMessageResponseGetMessageResponseAsync检索结果之前检查状态码和标头。

var bedrock = new AmazonBedrockRuntimeClient(RegionEndpoint.USEast1);

// (string modelId, MessageRequest request)
var response = await bedrock.InvokeModelAsync("anthropic.claude-3-haiku-20240307-v1:0", new()
{
    Model = "bedrock-2023-05-31", // anthropic_version
    MaxTokens = 1024,
    Messages = [new() { Role = "user", Content = "你好,Claude" }]
});

Console.WriteLine(response.ResponseMetadata.RequestId);

var responseMessage = response.GetMessageResponse();

Console.WriteLine(responseMessage);

Unity

最低支持的Unity版本是2022.3.12f1。你需要从NuGet安装。我们建议使用NuGetForUnity

  1. 安装NuGetForUnity
  2. 从Window -> Manage NuGet Packages打开,搜索"Claudia"并点击安装。

这样,你就可以在编辑器和运行时使用Anthropic客户端了。

using Claudia;
using System;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    async void Start()
    {
        var anthropic = new Anthropic()
        {
            ApiKey = "你的API密钥"
        };

        Debug.Log("在Unity中开始简单调用");
var message = await anthropic.Messages.CreateAsync(new()
{
    Model = Models.Claude3Opus,
    MaxTokens = 1024,
    Messages = new Message[] { new() { Role = "user", Content = "你好,Claude" } }
});

Debug.Log("用户:你好,Claude");
Debug.Log("助手:" + message);
}
}

image

函数调用的源代码生成器也受支持,但需要额外的工作。

  1. 为Unity设置C#编译器。

    • 在Assets/目录下添加一个名为csc.rsp的文本文件,内容如下:
      • -langVersion:10 -nullable
        
  2. 为您的IDE设置C#编译器。

    • 安装CsprojModifier
    • 添加一个名为LangVersion.props的文本文件,内容如下:
      • <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
          <PropertyGroup>
            <LangVersion>10</LangVersion>
            <Nullable>enable</Nullable>
          </PropertyGroup>
        </Project>
        
    • 打开项目设置,在[编辑器]下找到[C# Project Modifier]部分。
    • 将刚刚创建的.props文件添加到[附加项目导入]列表中。
    • 注意:
      • 如果您使用的是程序集定义,请将您的附加csproj添加到[要添加导入的项目]列表中。

如果遇到"不支持在此版本的编译器中使用具有必需成员的类型的构造函数"错误,应将LangVersion更改为11

using Claudia;
using System;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    async void Start()
    {
        var anthropic = new Anthropic()
        {
            ApiKey = "你的API密钥"
        };

        Debug.Log("在Unity中开始函数调用演示");

        var input = new Message
        {
            Role = Roles.User,
            Content = "将1,984,135乘以9,343,116"
        };

        var message = await anthropic.Messages.CreateAsync(new()
        {
            Model = Models.Claude3Haiku,
            MaxTokens = 1024,
            System = FunctionTools.SystemPrompt,
            StopSequences = new[] { StopSequnces.CloseFunctionCalls },
            Messages = new[] { input },
        });

        var partialAssistantMessage = await FunctionTools.InvokeAsync(message);

        var callResult = await anthropic.Messages.CreateAsync(new()
        {
            Model = Models.Claude3Haiku,
            MaxTokens = 1024,
            System = FunctionTools.SystemPrompt,
            Messages = new[]{
                input,
                new() { Role = Roles.Assistant, Content = partialAssistantMessage! }
            },
        });

        Debug.Log("用户:将1,984,135乘以9,343,116");
        Debug.Log("助手:" + callResult.ToString().Trim());
    }
}

public static partial class FunctionTools
{
    /// <summary>
    /// 用于进行基本算术的计算器函数。
    /// 支持加法、减法、乘法
    /// </summary>
    /// <param name="firstOperand">第一个操作数(运算符之前)</param>
    /// <param name="secondOperand">第二个操作数(运算符之后)</param>
    /// <param name="operator">要执行的操作。必须是+、-、*或/之一</param>
    [ClaudiaFunction]
    static double DoPairwiseArithmetic(double firstOperand, double secondOperand, string @operator)
    {
        return @operator switch
        {
            "+" => firstOperand + secondOperand,
            "-" => firstOperand - secondOperand,
            "*" => firstOperand * secondOperand,
            "/" => firstOperand / secondOperand,
            _ => throw new ArgumentException("不支持的操作")
        };
    }
}

WebGL

在使用HttpClient进行通信失败的环境中,如WebGL,您需要通过使用这个UnityWebRequestHttpMessageHandler.cs来替换传输层。

// 将处理程序替换为UnityWebRequestHttpMessageHandler
var anthropic = new Anthropic(new UnityWebRequestHttpMessageHandler())
{
    ApiKey = "你的API密钥",
    ConfigureAwait = true // 在使用UnityWebRequest的Unity环境中,建议设为true
};

然而,要在浏览器环境中进行API调用,您需要设置代理或采取其他措施来支持CORS。

许可证

该库使用MIT许可证。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号