Claudia
非官方的 Anthropic Claude API .NET 客户端。
我们构建了一个类似于官方 Python SDK 和 TypeScript 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。然而,它不使用 object
、dynamic
或 Dictionary
,所有内容都是强类型的。通过利用 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.Claude3Opus
是 claude-3-opus-20240229
,像 "user" 和 "assistant" 这样的角色使用 Roles.User
和 Roles.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相关的额外信息。
让我们创建一个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/jpeg
、image/png
、image/gif
和image/webp
。例如,如果你想上传markdown文件,最好读取其内容并作为文本发送。如果你想上传PDF,你可以将其转换为文本或图像后再发送。像pptx这样的演示文件也可以作为图像发送,Claude会为你解释内容并提取文本。
系统提示和温度
MessageRequest
的其他可选属性包括System
、Metadata
、StopSequences
、Temperature
、TopP
和TopK
。
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);
}
}
请注意,允许的参数类型是bool
、sbyte
、byte
、short
、ushort
、int
、uint
、long
、ulong
、decimal
、float
、double
、string
、DateTime
、DateTimeOffset
、Guid
、TimeSpan
和Enum
。
返回值可以是任何类型,但它将使用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);
注意,允许的参数类型为bool
、sbyte
、byte
、short
、ushort
、int
、uint
、long
、ulong
、decimal
、float
、double
、string
、DateTime
、DateTimeOffset
、Guid
、TimeSpan
和Enum
。
返回值可以是任何类型,但会使用ToString()
转换为字符串。如果你想返回自定义字符串,请将返回类型设为string
并在函数内格式化字符串。
Blazor示例
通过在Blazor中使用Claudia,你可以轻松创建如下所示的聊天界面。
所有代码可以在BlazorApp1中找到。
关键部分是Program.cs
和Home.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);
}
如果需要原始响应,请改为调用InvokeModelAsync
或InvokeModelWithResponseStreamAsync
。这允许你在使用GetMessageResponse
或GetMessageResponseAsync
检索结果之前检查状态码和标头。
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。
- 安装NuGetForUnity
- 从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);
}
}
函数调用的源代码生成器也受支持,但需要额外的工作。
-
为Unity设置C#编译器。
- 在Assets/目录下添加一个名为
csc.rsp
的文本文件,内容如下:-
-langVersion:10 -nullable
-
- 在Assets/目录下添加一个名为
-
为您的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许可证。