XiHan Framework 处于预览阶段

查看获取方式
跳转到内容

XiHan.Framework.AI.Abstractions ​

AI 的抽象包:以 Microsoft.Extensions.AI 为线格式的 Provider 目录、带提示词 / 护栏 / 工具的聊天入口、把操作契约桥接成模型工具的目录,以及知识库流水线与存储契约。默认提供进程内的工具目录 ai.tools@1。

项内容
包 IDXiHan.Framework.AI.Abstractions
环层Ring 2(抽象)
能力提供 ai.tools@1(AIToolsFeature,role: default);定义 ai.chat@1、ai.embedding@1、ai.knowledge@1;AIToolsFeature 依赖 kernel.hosting@1
特性入口AIToolsFeature(清单 xihan.ai.tools,IHostedFeature)
配置节XiHan:AI
依赖XiHan.Framework.Kernel、XiHan.Framework.Localization.Abstractions;Microsoft.Extensions.AI.Abstractions,Microsoft.Extensions.Configuration.Abstractions、Microsoft.Extensions.DependencyInjection.Abstractions、Microsoft.Extensions.Logging.Abstractions
AOT兼容
稳定性Preview

概述 ​

公开签名直接使用 IChatClient、IEmbeddingGenerator<string, Embedding<float>>、ChatMessage、AITool 等 Microsoft.Extensions.AI 类型,不复制一套模型接口(ADR-0017)。本包提供:

  • Provider 目录 IAIProviderCatalog:按名字解析客户端并缓存,给出默认聊天与嵌入 Provider 名(DefaultProvider、DefaultEmbeddingProvider);Provider 包实现 IChatClientFactory / IEmbeddingGeneratorFactory。
  • 聊天入口 IAIChat:提示词渲染 → 工具绑定 → 护栏 → 解析 Provider(没写名字时问目录的默认名)→ 调用。
  • 提示词目录 IAIPromptCatalog 与模板 AIPromptTemplate。
  • 护栏 IAIGuardrail 与内置的 KeywordBlocklistGuardrail。
  • 工具目录 IAIToolCatalog:AddAITool 的工具加上 Expose.Ai 的操作,后者在新作用域经完整管道执行。
  • 知识库流水线:IKnowledgeIngestor、IKnowledgeRetriever、IRagPromptAugmenter、IChunkingStrategy,以及 Provider 契约 IKnowledgeStore。

AddAI(configuration) 幂等地登记以上全部服务、选项与消息目录 ai;AIToolsFeature、OpenAIFeature、VectorDataKnowledgeFeature 都调用它。AIToolsFeature 与 OpenAIFeature 在启动时构建工具目录,工具名不合法或重名即启动失败(只装 OpenAIFeature 也一样);它与 OpenAIFeature、VectorDataKnowledgeFeature 启动时都解析提示增强器,知识库配置引用的提示词找不到或渲染不了即启动失败。用法见 AI。

何时使用 ​

业务代码只依赖本包的接口;模型由 AI.OpenAI 提供,知识库存储由 AI.VectorData 提供。接入其他模型服务时,在自己的 Provider 包里实现两个工厂接口,或者直接用 Microsoft.Extensions.AI 生态里已有的 IChatClient 实现包一层工厂。

安装与启用 ​

bash
dotnet add package XiHan.Framework.AI.Abstractions --prerelease

当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Full 已装配 AIToolsFeature;其他组合里 UseFeature<AIToolsFeature>()。

配置 ​

XiHan:AI 下的键(装配时读一次,不热更新,改了要重启应用):

键缺省说明
DefaultProvider只有一个 Provider 时取它框架自带目录的默认聊天 Provider
DefaultEmbeddingProvider同 DefaultProvider框架自带目录的默认嵌入 Provider
Providers:<name>:Kind必填种类,转小写后与工厂的 Kind 匹配
Providers:<name>:Endpoint空绝对的 http(s) 地址;空表示 Provider 的官方端点
Providers:<name>:ApiKey空空时由 Provider 决定
Providers:<name>:ChatModel、EmbeddingModel—解析对应客户端时必填
Providers:<name>:EmbeddingDimensions模型缺省至少 1
Providers:<name>:TimeoutSeconds100Provider 调用的时限,正数;IAIChat 与知识库流水线按它落成超时令牌
Providers:<name>:Properties:<key>—透传给工厂的字符串
Tools:<操作 ID>按约定推导覆盖操作工具名
Prompts:<name>:Template、Description—配置里的提示词
Guardrails:Enabledfalse登记内置护栏
Guardrails:BlockedKeywords、InjectionPatterns空数组
Guardrails:UseBuiltInInjectionHeuristicstrue内置中英文提示注入模式
Knowledge:Collectionknowledge默认集合
Knowledge:Dimensions1536嵌入维度
Knowledge:ChunkSize、ChunkOverlap1000、100切块(字符)
Knowledge:Top5默认检索条数
Knowledge:EmbeddingProvider、PromptName空知识库的嵌入 Provider(空时用目录的默认嵌入 Provider)与增强模板(模板启动时校验,找不到或渲染不了即启动失败)
json
{
  "XiHan": {
    "AI": {
      "DefaultProvider": "cloud",
      "Providers": {
        "cloud": { "Kind": "openai", "ApiKey": "dev-openai-key", "ChatModel": "gpt-4o-mini", "EmbeddingModel": "text-embedding-3-small", "EmbeddingDimensions": 1536 }
      },
      "Tools": { "orders.list": "list_orders" }
    }
  }
}

值不合法时 AIOptions.FromConfiguration 抛出 ArgumentException,消息带出配置键与原值,应用启动失败:Provider 缺 Kind、Endpoint 不是绝对的 http(s) 地址、数值项不是要求的整数或正数、布尔项不是 true / false、提示词缺 Template。

主要类型 ​

类型说明
AICapabilitiesChat、Embedding、Tools、Knowledge 与版本 1
AIOptions、Providers.AIProviderOptions选项;ResolveDefaultProvider()、ResolveDefaultEmbeddingProvider() 按配置推出框架自带目录的默认名;AIProviderOptions.DefaultTimeout 为 100 秒
AIServiceCollectionExtensionsAddAI、AddAIChatClientFactory<T>、AddAIEmbeddingGeneratorFactory<T>、AddAIGuardrail<T>、AddAIPrompt、AddAITool
AIToolsFeatureai.tools@1 的特性入口
Providers.IAIProviderCatalogProviders、DefaultProvider、DefaultEmbeddingProvider、Find、ResolveChatClient、ResolveEmbeddingGenerator、Invalidate;框架实现 AIProviderCatalog
Providers.IChatClientFactory、IEmbeddingGeneratorFactoryProvider 包实现:Kind 与 Create(AIProviderOptions)
Chat.IAIChat、Chat.AIChatRequest聊天入口;CompleteAsync、StreamAsync
Prompts.IAIPromptCatalog、Prompts.AIPromptTemplate提示词目录与模板;Render、Placeholders
Guardrails.IAIGuardrail、GuardrailVerdict、KeywordBlocklistGuardrail、AIGuardrailOptions护栏
Tools.IAIToolCatalog、Tools.OperationAIFunction、Tools.AIToolNameConvention工具目录、操作工具(OperationId)、命名约定(Derive、DescriptionKeyOf,上限 64)
Knowledge.IKnowledgeIngestor、IKnowledgeRetriever、IRagPromptAugmenter、IChunkingStrategy流水线;KnowledgeIngestorExtensions 提供单篇的 IngestAsync 与 RemoveAsync
Knowledge.KnowledgeMetadataKeys框架认识的块元数据键:Title(title)、Source(source),提示增强依次用它们写片段的来源,都没有时用文档 ID
Knowledge.IKnowledgeStoreProvider 契约:UpsertAsync、DeleteAsync、TrimAsync(删一篇文档里块序号不小于给定值的记录)、SearchAsync(按 Score 降序)
Knowledge.KnowledgeIngestRequest、KnowledgeQuery、KnowledgeRecord、RetrievedChunk、RetrievalFilter、ChunkingOptions、KnowledgeOptions知识库的数据类型;KnowledgeRecord.IdOf(documentId, chunkIndex) 生成 <documentId>#<chunkIndex>
AIIdentifiers名字文法 ^[a-z0-9][a-z0-9._-]{0,63}$,工具名 ^[A-Za-z0-9_-]{1,64}$
AIErrors、AIMessages错误码与消息键

使用示例 ​

登记一个提示词模板,同名时覆盖配置里的:

csharp
using XiHan.Framework.AI.Abstractions;
using XiHan.Framework.AI.Abstractions.Prompts;
using XiHan.Framework.Kernel;
using XiHan.Framework.Kernel.Hosting;
using XiHan.Framework.Primitives;
using XiHan.Framework.Primitives.Manifests;

namespace MyApp.Assistants;

public sealed class PromptsFeature : IFeature
{
    public Manifest Manifest { get; } = new()
    {
        Id = "xihan.myapp.prompts",
        Package = "MyApp",
        Version = "1.0.0",
        Primitives = 1,
        Stability = Stability.Experimental,
        Kind = ManifestKind.Capability,
        Requires = [new CapabilityRequirement(KernelCapabilities.Hosting, KernelCapabilities.Version)],
        Entry = typeof(PromptsFeature).FullName,
    };

    public void Configure(FeatureContext context)
    {
        // 与配置里同名的模板以这里为准;{{ 与 }} 输出字面的花括号
        context.Services.AddAIPrompt(new AIPromptTemplate(
            "order-summary",
            "Summarize order {orderId} for {audience}. Reply as JSON like {{\"summary\": \"<text>\"}}.",
            "Order summary for a given audience"));
    }
}

直接从目录取嵌入生成器,不经护栏:

csharp
using XiHan.Framework.AI.Abstractions.Providers;
using XiHan.Framework.Primitives;

namespace MyApp.Assistants;

public sealed class EmbeddingService(IAIProviderCatalog catalog)
{
    public async ValueTask<Result<float[]>> EmbedAsync(string text, CancellationToken cancellationToken)
    {
        var resolved = catalog.ResolveEmbeddingGenerator();
        if (!resolved.TryGetValue(out var generator))
        {
            return resolved.Error!;
        }

        // 直接使用目录里的生成器:不经护栏,传输异常照常抛出
        var embeddings = await generator.GenerateAsync([text], cancellationToken: cancellationToken);
        return embeddings[0].Vector.ToArray();
    }
}

聊天、护栏、工具与知识库的完整示例见 AI。

行为与限制 ​

  • 目录按名字缓存实例;Invalidate(name) 释放缓存(实现了 IDisposable 的实例被释放),下次解析重建。选项在装配时读一次,Invalidate 不重读配置。
  • 默认名由目录给出(ADR-0110):IAIChat 不写 Provider 时取 DefaultProvider,摄入与检索依次取请求的 Provider、Knowledge:EmbeddingProvider、DefaultEmbeddingProvider,都不读 XiHan:AI 的默认键。框架的 AIProviderCatalog 从配置推出默认名;应用替换的目录(如 Provider 存在库里)给出自己的。两个属性是同步的、不做 I/O,要查库的目录持内存快照。没有默认又没写名字时 AI_NOTFOUND_001(ai.provider.default_missing / ai.provider.embedding_default_missing)。
  • IAIChat 是作用域服务;没有当前调用时工具绑定到本作用域新建的调用上下文。
  • 护栏按登记顺序执行,只作用于 IAIChat;直接从目录取客户端的调用不经护栏。
  • 工具目录在 AIToolsFeature 或 OpenAIFeature 启动时构建;稳定性为 Internal 的操作不进目录。
  • 操作工具在新作用域、新调用上下文里经完整管道执行,trace-id、截止时间、Baggage 与安全上下文(主体与租户)复制自调用方,以调用方身份按契约授权;凭据不复制、不重新认证;失败以 {"error","message"} JSON 交给模型。
  • 同一文档重新摄入先写新块、写入成功后再删多余的旧块:嵌入、维度校验或写入失败时旧文档照常可检索,存储没有事务,写入中途失败可能留下新旧混合的块,重试摄入即恢复一致;嵌入维度必须等于 Knowledge:Dimensions。
  • 没有 IKnowledgeStore 时流水线返回 AI_UNAVAILABLE_002,聊天与工具不受影响。
  • IAIChat 与知识库流水线把 Provider 的 TimeoutSeconds 按容器的 TimeProvider 落成超时令牌、与调用方令牌链接后交给 Provider:完整应答覆盖 Provider 的整次调用(含函数调用循环),嵌入是每次批调用,流式是等每个更新的时长(已定,ADR-0097:不设整条流的总时限,总时长由调用方的取消令牌或截止时间限制)。超时令牌已触发即超时(AI_TIMEOUT_001,流里抛出 TimeoutException),不论调用方是否也取消、Provider 是抛出还是接住取消正常返回;只有调用方取消时抛出 OperationCanceledException。见 AI 指南的超时与取消。
错误码何时出现
AI_VALIDATION_001Provider 缺必填项、提示词缺参数、文档 ID 或问题为空、工具名不合法或重名、工具参数序列化不了(以 JSON 错误交给模型)
AI_VALIDATION_002嵌入维度与知识库配置不一致
AI_NOTFOUND_001Provider 未配置,或种类没有登记工厂;没写名字而目录没有默认
AI_NOTFOUND_002提示词模板不存在
AI_NOTFOUND_003工具不存在
AI_DENIED_001被护栏拦截
AI_TIMEOUT_001模型调用超时:Provider 的超时令牌已触发(调用方同时取消也一样),或 Provider 报告了自己的超时
AI_UNAVAILABLE_001模型端点不可达或返回错误
AI_UNAVAILABLE_002没有知识库 Provider,或存储不可达
AI_UNEXPECTED_001护栏抛出异常或返回失败

相关 ​

Released under The MIT License