.net AI开发02 1后端框架: ASP.NET Core2.AI框架: Semantic Kernerl (SK)、Agent Framework3.知识库:向量数据库(Qdrant)+关系型数
企业AI助理系统采用分层架构设计,包含智能体交互、知识中枢(RAG)、数据分析(NL2SQL)和工具调用(MCP)三大核心功能模块,支持自然语言查询、跨系统操作和可视化报表生成。技术选型上选用ASP.NET Core后端框架、Semantic Kernel AI框架、Qdrant向量数据库,并支持私有化部署。系统通过权限控制确保安全性,采用容器化云原生部署方案,为企业提供覆盖现有系统的智能化交互层
企业AI助理系统采用分层架构设计,包含智能体交互、知识中枢(RAG)、数据分析(NL2SQL)和工具调用(MCP)三大核心功能模块,支持自然语言查询、跨系统操作和可视化报表生成。技术选型上选用ASP.NET Core后端框架、Semantic Kernel AI框架、Qdrant向量数据库,并支持私有化部署。系统通过权限控制确保安全性,采用容器化云原生部署方案,为企业提供覆盖现有系统的智能化交互层
AI开发01 1后端框架: ASP.NET Core2.AI框架: Semantic Kernerl (SK)、Agent Framework3.知识库:向量数据库(Qdrant)+关系型数据库(Post
https://blog.csdn.net/cao919/article/details/155895060
上个专题完善的docker问题 以及最后完善的docker遇到的问题
其中在docker desktop 中以成功
docker pull docker.m.daocloud.io/postgres:15-alpine
docker tag docker.m.daocloud.io/postgres:15-alpine postgres:15-alpine
手机wifi
docker pull sosedoff/pgweb:latest
docker tag sosedoff/pgweb:latest sosedoff/pgweb:latest
docker volume rm postgres-aicopilot
Error response from daemon: remove postgres-aicopilot: volume is in use - [d18050b549f265821aeb97ad6ba58ca7593951f2c7c717ba739840f1da6cc7bf, ad4152ddc46e835017d74bd440d4e74c66c605e8330453d44dad4088b3544c
a7]
docker ps -a --filter volume=postgres-aicopilot
docker stop d18050b549f2
docker rm d18050b549f2
docker ps -a --filter volume=postgres-aicopilot
docker volume rm postgres-aicopilot
第五章 技术关键词
Senmantic Kernel
AutoGen
Microsoft Agent Framework =MAF
SK的底层+AutoGen编排
1.显示的工作流编排
2.强大的状态管理
3.开放互操作性:MCP+A2A
SK=引擎==》集成层==连接器
AutoGen=概念车==》研究探索==》对话编排
Agent框架=量产车==》企业就智能体平台==》可观测、调试、一致性
多轮对话以及记忆管理
记忆:
1.短期记忆: 聊天历史==》只通过上下文窗口传递的内容,容量有限
2.长期记忆: 能够提取、存储有意义的信息,其他的对话中也可以使用,和会话无关,可以跨多个会话
内存存储 (Agent线程对象)==》Agent线程:用来保存会话状态底层服务(语言模型)
1111
6666
工作流
6666

AI Copilot网关服务重构:支持多模型与流式对话
- ConversationTemplate 增加 ModelId 字段,支持多模型绑定,领域模型与数据库结构同步调整
- TemplateSpecification/ModelParameters 的 Temperature 字段由 double 改为 float,数据库类型同步为 real
- CQRS 用例层重构,命名空间与文件结构优化,DTO 结构规范化,权限控制统一
- 新增 ChatAgentFactory、SessionChatMessageStore,集成 OpenAI Agent 框架,支持流式消息输出(SSE)
- AiGatewayController 新增流式对话接口,API 层风格统一
- 依赖注入与项目引用优化,所有服务共用 Common.Contracts,移除冗余 Contracts 项目
- 数据库迁移文件重生成,表结构、索引、字段类型与新模型一致
- 统一异常与权限相关代码风格,删除无用代码,提升整体可维护性
{
"provider": "qwen-plus",
"name": "通义千问fstyle",
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"apiKey": "sk-",
"maxTokens": "1000000",
"temperature": 0.7
}
{
"id": "a4c5e567-7424-4c4e-8d2a-15f4b1c46dbd",
"provider": "qwen-plus",
"name": "通义千问fstyle"
}

{
"name": "AI助手",
"description": "测试用的AI助手",
"systemPrompt": "你是一个乐于助人的AI助手,你的名字叫音娱乐行",
"modelId": "a4c5e567-7424-4c4e-8d2a-15f4b1c46dbd",
"maxTokens": "256000",
"temperature": "0.7"
}
{
"id": "7a75a9c3-b8b1-4ec9-914e-be72942d4294",
"name": "AI助手"
}
{
"templateId": "7a75a9c3-b8b1-4ec9-914e-be72942d4294"
}
{
"id": "62c4910e-64a8-4c97-9750-ca55f0b4cd04"
}

{
"sessionId": "62c4910e-64a8-4c97-9750-ca55f0b4cd04",
"content": "你好!你是?"
}

--name居然是模型名称QAQ

效果

$.content
历史消息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Zilor.AICopilot.Core.AiGateway.Aggregates.Sessions;
using Zilor.AICopilot.Services.Common.Contracts;
using Zilor.AICopilot.SharedKernel.Repository;
namespace Zilor.AICopilot.AiGatewayService.Agents;
public class SessionChatMessageStore : ChatMessageStore
{
private readonly IServiceProvider _serviceProvider;
public SessionChatMessageStore(IServiceProvider serviceProvider, JsonElement storeState)
{
_serviceProvider = serviceProvider;
if (storeState.ValueKind is JsonValueKind.String)
{
ThreadDbKey = storeState.Deserialize<Guid>();
}
}
private Guid? ThreadDbKey { get; set; }
public override async Task<IEnumerable<ChatMessage>> GetMessagesAsync(CancellationToken cancellationToken = new())
{
using var scope = _serviceProvider.CreateScope();
var queryService = scope.ServiceProvider.GetRequiredService<IDataQueryService>();
// 先按时间倒序(Descending)取最新的 50 条
var queryable = queryService.Messages
.Where(m => m.SessionId == ThreadDbKey)
.OrderByDescending(m => m.CreatedAt)
.Take(50);
var dbMessages = await queryService.ToListAsync(queryable);
// 在内存中反转回正序(Ascending),因为语言需要按时间顺序阅读
var orderedMessages = dbMessages.OrderBy(m => m.CreatedAt);
// 将实体转换为 Agent 框架的 ChatMessage
var chatMessages = new List<ChatMessage>();
foreach (var msg in orderedMessages)
{
var role = msg.Type switch
{
MessageType.User => ChatRole.User,
MessageType.Assistant => ChatRole.Assistant,
MessageType.System => ChatRole.System,
_ => ChatRole.User
};
chatMessages.Add(new ChatMessage(role, msg.Content));
}
return chatMessages;
}
public override async Task AddMessagesAsync(IEnumerable<ChatMessage> messages, CancellationToken cancellationToken = new())
{
ThreadDbKey ??= Guid.NewGuid();
using var scope = _serviceProvider.CreateScope();
var repo = scope.ServiceProvider.GetRequiredService<IRepository<Session>>();
// 加载聚合根
var session = await repo.GetByIdAsync(ThreadDbKey, cancellationToken);
if (session == null) return;
var hasNewMessage = false;
foreach (var msg in messages)
{
// 将 Agent Role 转换为枚举
// msg.Role.ToString() 可能返回 "user", "assistant" 等
var roleStr = msg.Role.ToString().ToLower();
var msgType = roleStr switch
{
"user" => MessageType.User,
"assistant" => MessageType.Assistant,
"system" => MessageType.System,
_ => MessageType.Assistant
};
// 获取文本内容
if (string.IsNullOrWhiteSpace(msg.Text)) continue;
session.AddMessage(msg.Text, msgType);
hasNewMessage = true;
}
if (hasNewMessage)
{
repo.Update(session);
await repo.SaveChangesAsync(cancellationToken);
}
}
public override JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null)
{
return JsonSerializer.SerializeToElement(ThreadDbKey);
}
}
openAI 连接池优化


第六章 技术关键词
引入Agent插件机制,支持AI工具动态扩展
本次提交实现了Agent插件基础设施(AICopilot.AgentPlugin),支持AI工具(如时间查询)的自动发现、注册与运行时动态调用。AiGatewayService集成插件机制,示例实现TimePlugin,Agent可在对话中调用C#工具方法。升级EF Core、Aspire、OpenTelemetry等依赖,修正数据库迁移与字段映射,提升系统可维护性与可观测性。删除无用接口,优化部分模型构造。

Agent: 不会行动==》行动能力==》函数调用
函数调用==》LLM根据用户的意图,智能决定是否需要调用外部函数,并生成该函数所需的参数
用户==》服务员
LLM (Agent):服务员(菜单定义)==》
下单==》菜名、数量==》经理(程序) ==》吩咐做菜(执行代码)==》传递给服务员==》最终回复
函数:后厨和菜单
应用(程序):经理
1.解决实时性和封闭性问题
2.实现结构化数据输出
3. 减少幻觉
Agent框架:
1.定义工具+描述
2.注册工具: 挂载给Agent
工具、函数、插件
2023年初==》OpenAl ChatGPT 插件
函数:原子==》方法
插件: 分子==》一组相关函数的集合==》类
工具:函数(代码)==》工具(LLM)
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Zilor.AICopilot.AgentPlugin;
using Zilor.AICopilot.AiGatewayService.Agents;
using Zilor.AICopilot.AiGatewayService.Plugins;
using Zilor.AICopilot.Core.AiGateway.Aggregates.Sessions;
using Zilor.AICopilot.Services.Common.Attributes;
using Zilor.AICopilot.SharedKernel.Messaging;
using Zilor.AICopilot.SharedKernel.Repository;
namespace Zilor.AICopilot.AiGatewayService.Commands.Sessions;
[AuthorizeRequirement("AiGateway.SendUserMessage")]
public record SendUserMessageCommand(Guid SessionId, string Content) : ICommand<IAsyncEnumerable<string>>;
public class SendUserMessageCommandHandler(
IRepository<Session> repo,
ChatAgentFactory chatAgent,
AgentPluginLoader pluginLoader)
: ICommandHandler<SendUserMessageCommand, IAsyncEnumerable<string>>
{
public async Task<IAsyncEnumerable<string>> Handle(SendUserMessageCommand request, CancellationToken cancellationToken)
{
var session = await repo.GetByIdAsync(request.SessionId, cancellationToken);
if (session == null) throw new Exception("未找到会话");
var agent = await chatAgent.CreateAgentAsync(session.TemplateId);
var storeThread = new { storeState = request.SessionId };
var agentThread = agent.DeserializeThread(JsonSerializer.SerializeToElement(storeThread));
// 返回迭代器函数
return await Task.FromResult(GetStreamAsync(agent, agentThread, request.Content, cancellationToken));
}
private async IAsyncEnumerable<string> GetStreamAsync(
ChatClientAgent agent, AgentThread thread, string input, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var tools = pluginLoader.GetAITools(nameof(TimePlugin));
// 调用Agent流式读取响应
await foreach (var update in agent.RunStreamingAsync(input, thread,
new ChatClientAgentRunOptions()
{
ChatOptions = new ChatOptions()
{
Tools = tools
}
},
cancellationToken: cancellationToken))
{
foreach (var content in update.Contents)
{
switch (content)
{
case TextContent callContent:
yield return callContent.Text;
break;
case FunctionCallContent callContent:
yield return $"\n\n```\n正在执行工具:{callContent.Name} \n请求参数:{JsonSerializer.Serialize(callContent.Arguments)}";
break;
case FunctionResultContent callContent:
yield return $"\n\n执行结果:{JsonSerializer.Serialize(callContent.Result)}\n```\n\n";
break;
}
}
}
}
}
Agent 框架
1111
可观测性:日志、指标、链路追踪
透视思考过程、调试工具调用、性能分析
Aspire+OpenTelemtry
// 1. 获取服务名称,这决定了在仪表板 里看到的名字
var serviceName = Environment.GetEnvironmentVariable("OTEL_SERVICE_NAME") ?? nameof(Zilor.AICopilot.HttpApi);
// 2. 获取数据上报地址,Aspire 会自动注入这个环境变量
var otlpEndpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4317";
var resource = ResourceBuilder.CreateDefault()
.AddService(serviceName);
// 3. 构建追踪提供程序
Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(resource)
// 核心配置:监听 Agent 框架发出的信号
.AddSource(nameof(Zilor.AICopilot.AiGatewayService)) // 监听我们自己业务代码的 Activity
.AddSource("*Microsoft.Agents.AI") // 监听 Agent Framework 的核心事件
.AddSource("*Microsoft.Extensions.AI*") // 监听底层 AI 扩展库的事件
.AddOtlpExporter(options => options.Endpoint = new Uri(otlpEndpoint)) // 将数据导出到 Aspire Dashboard
.Build();
1111
如何管理工具?
工具装配策略?什么时间、什么地点、什么方式,将哪些工具装配给Agent?
静态单例装配
动态按需加载
混合策略
HR==》人力资源:查询年假、提交请假单、撤销请假单..…
1.冷启动开销为0
2.资源节约
3.确定和稳定
企业级超级助理
瑞士军刀陷阱:
1.Token浪费
2.上下文挤压
3.选择困难症与幻觉
QueryOrderList==》SearchOrdersByDate
误调用、幻觉、拒绝服务
解耦和懒加载==》动态按需加载
管家(Agent)
元认知的环节==》意图识别--》工具筛选--》及时组装--》执行销毁
轻量级分类器:便宜、更快的小模型==》做选择题
向量语义检索:工具描述向量化存储到向量数据库,用户查询也先向量==》相似度搜索==》找出匹配的工具包
财务报表/邮件服务
工具筛选:只加载相关的插件(报表插件、Email插件)
即时组装:创建Agent/执行Agent挂载筛选过的工具
执行与销毁
极高的精准度、Token经济、无限的水平扩展能力
延迟增加、架构复杂度
混合策略:内核+插件
通用工具常驻
专业工具按需加载
意图识别Agent
1111
Agent 插件系统==》函数调用功能AI扩展库提供
约定大于配置==》利用.NET反射机制+函数描述特性
模块化解耦==》插件打包在不同的程序集、实现物理隔离
动态按需加载==》插件加载器
using System.ComponentModel;
using System.Reflection;
using Microsoft.Extensions.AI;
namespace Zilor.AICopilot.AgentPlugin;
public abstract class AgentPluginBase : IAgentPlugin
{
// 默认实现:直接使用类名作为插件名称
public virtual string Name { get; }
public virtual string Description { get; protected set; } = string.Empty;
protected AgentPluginBase()
{
Name = GetType().Name;
}
/// <summary>
/// 核心逻辑:扫描当前类中所有标记了 [Description] 的公共方法。
/// 只有带有描述的方法才会被视为 AI 工具。
/// </summary>
private IEnumerable<MethodInfo> GetToolMethods()
{
var type = GetType();
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
.Where(m => m.GetCustomAttribute<DescriptionAttribute>() != null);
}
/// <summary>
/// 利用 Microsoft.Extensions.AI 库,将 C# 方法自动转换为 AITool。
/// </summary>
public IEnumerable<AITool>? GetAITools()
{
// AIFunctionFactory.Create 是微软提供的工具,
// 它会读取方法签名、参数类型和 Description 特性,生成 JSON Schema。
// 'this' 参数确保了当工具被调用时,是在当前插件实例上执行的。
var tools = GetToolMethods()
.Select(method => AIFunctionFactory.Create(method, this));
return tools;
}
}
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Zilor.AICopilot.AgentPlugin;
public static class AgentPluginExtensions
{
public static IServiceCollection AddAgentPlugin(
this IServiceCollection services,
Action<IAgentPluginRegistrar> configure)
{
// 1. 创建注册器实例
var registrar = new AgentPluginRegistrar();
// 2. 执行用户配置(用户在这里指定要扫描的程序集)
configure(registrar);
// 3. 将注册器注册为单例。注意这里没有使用 TryAdd,
// 因为我们允许用户多次调用 AddAgentPlugin 来注册不同来源的插件。
services.AddSingleton<IAgentPluginRegistrar>(registrar);
// 4. 注册加载器。加载器只应有一个,它会收集容器中所有的 Registrar。
services.TryAddSingleton<AgentPluginLoader>();
return services;
}
}
using System.Reflection;
using Microsoft.Extensions.AI;
namespace Zilor.AICopilot.AgentPlugin;
public class AgentPluginLoader
{
// 缓存插件实例:Key=插件名, Value=插件实例
private readonly Dictionary<string, IAgentPlugin> _plugins = new();
// 缓存工具定义:Key=插件名, Value=AITool数组
private readonly Dictionary<string, AITool[]> _aiTools = new();
// 构造函数注入所有的注册器
public AgentPluginLoader(IEnumerable<IAgentPluginRegistrar> registrars)
{
// 1. 汇总所有需要扫描的程序集,去重
var assemblies = registrars
.SelectMany(r => r.Assemblies)
.Distinct()
.ToList();
// 2. 扫描并加载
foreach (var assembly in assemblies)
{
LoadPluginsFromAssembly(assembly);
}
}
private void LoadPluginsFromAssembly(Assembly assembly)
{
// 反射查找:实现了 IAgentPlugin 且不是抽象类的具体类
var pluginTypes = assembly.GetTypes()
.Where(t =>
typeof(IAgentPlugin).IsAssignableFrom(t) &&
t is { IsClass: true, IsAbstract: false });
foreach (var type in pluginTypes)
{
// 创建实例
var plugin = (IAgentPlugin)Activator.CreateInstance(type)!;
// 存入缓存
_plugins[plugin.Name] = plugin;
_aiTools[plugin.Name] = plugin.GetAITools()?.ToArray() ?? [];
}
}
/// <summary>
/// 核心功能:根据名称动态获取工具集。
/// 支持一次获取多个插件的工具,实现工具的动态混搭。
/// </summary>
public AITool[] GetAITools(params string[] names)
{
var aiTools = new List<AITool>();
foreach (var name in names)
{
if (_aiTools.TryGetValue(name, out var tools))
{
aiTools.AddRange(tools);
}
}
return aiTools.ToArray();
}
public IAgentPlugin? GetPlugin(string name)
{
_plugins.TryGetValue(name, out var plugin);
return plugin;
}
public IAgentPlugin[] GetAllPlugin()
{
return _plugins.Values.ToArray();
}
}
效果

docker遇到的问题
docker pull docker.m.daocloud.io/sosedoff/pgweb:latest Error response from daemon: pull access denied for docker.m.daocloud.io/sosedoff/pgweb, repository does not exist or may require 'docker login': denied: 🚫 👀-> github.com/DaoCloud/public-image-mirror/issues/2328 🔗 这 镜像不在白名单. this image is not in the allowlist.
这个错误是因为 DaoCloud 镜像源未收录 pgweb 镜像(白名单限制),无需纠结该源,直接换用「手动导入 pgweb 镜像」或「阿里云专属源(若已配置)」解决,以下是 Windows 环境下的实操步骤:
方案一:手动下载 + 导入 pgweb 镜像(最快生效,无需依赖镜像源)
步骤 1:下载 pgweb 镜像包(PowerShell 执行)
powershell
# 下载 pgweb 镜像包到 C 盘根目录(可修改路径)
Invoke-WebRequest -Uri "https://github.com/liutianyi1996/docker-image/raw/main/pgweb/pgweb-latest.tar.gz" -OutFile "C:\pgweb-latest.tar.gz"
若 GitHub 下载慢,可改用国内wp链接(复制到浏览器下载):
步骤 2:解压并导入 Docker(PowerShell 执行)
powershell
# 解压镜像包(需提前安装解压工具,或手动右键解压)
# 若用 7-Zip,执行:& "C:\Program Files\7-Zip\7z.exe" x C:\pgweb-latest.tar.gz -oC:\
# 手动解压后得到 pgweb-latest.tar,执行导入:
docker load < C:\pgweb-latest.tar
# 验证导入结果
docker images | Select-String "pgweb"
正常输出示例:sosedoff/pgweb latest xxxxxxxx 2 hours ago 25MB
方案二:用官方源 + 代理 / 热点绕过限制(若网络允许)
如果你的网络切换到手机热点后能访问 Docker Hub,直接拉取官方 pgweb 镜像:
powershell
# 切换手机热点后执行
docker pull sosedoff/pgweb:latest
# 验证
docker images | Select-String "pgweb"
方案三:阿里云专属源(若已配置)
若你已获取阿里云专属镜像加速地址(推荐),配置后直接拉取:
- 确认 Docker Engine 中已配置阿里云源(参考之前步骤);
- PowerShell 执行:
powershell
docker pull sosedoff/pgweb:latest
最终验证:确保所有依赖镜像就绪
执行以下命令,确认 postgres 和 pgweb 镜像都存在:
powershell
# 查看 postgres 镜像
docker images | Select-String "postgres"
# 查看 pgweb 镜像
docker images | Select-String "pgweb"
只要两者都有输出,说明你的 C# 代码所需的镜像全部就绪,运行 dotnet run 即可正常创建 PostgreSQL + pgWeb 容器,无需额外配置。
补充说明
pgweb 属于小众镜像,多数公共镜像源未收录,手动导入是最稳定的方式。导入后,你的代码中 .WithPgWeb(pgWeb => pgWeb.WithHostPort(5050)) 会自动识别本地的 pgweb 镜像,正常映射 5050 端口,无需修改代码。
using Projects; var builder = DistributedApplication.CreateBuilder(args); var postgresdb = builder.AddPostgres("postgres") .WithDataVolume("postgres-aicopilot") .WithPgWeb(pgAdmin => pgAdmin.WithHostPort(5050)) .AddDatabase("ai-copilot"); var rabbitmq = builder.AddRabbitMQ("eventbus") .WithManagementPlugin() .WithLifetime(ContainerLifetime.Persistent); var qdrant = builder.AddQdrant("qdrant") .WithLifetime(ContainerLifetime.Persistent); var migration = builder.AddProject<Zilor_AICopilot_MigrationWorkApp>("aicopilot-migration") .WithReference(postgresdb) .WaitFor(postgresdb); builder.AddProject<Zilor_AICopilot_HttpApi>("aicopilot-httpapi") .WithUrl("swagger") .WaitFor(postgresdb) .WaitFor(rabbitmq) .WaitFor(qdrant) .WithReference(postgresdb) .WithReference(rabbitmq) .WithReference(migration) .WithReference(qdrant) .WaitForCompletion(migration); builder.AddProject<Zilor_AICopilot_RagWorker>("rag-worker") .WithReference(postgresdb) // 注入数据库连接 .WithReference(rabbitmq) // 注入 RabbitMQ 连接 .WithReference(qdrant) .WaitFor(postgresdb) // 等待数据库启动 .WaitFor(rabbitmq) 等待 MQ 启动 . WaitFor(qdrant); builder. Build(). Run(); 其中在docker desktop 中以成功 docker pull docker.m.daocloud.io/postgres:15-alpine docker tag docker.m.daocloud.io/postgres:15-alpine postgres:15-alpine docker pull sosedoff/pgweb:latest docker tag sosedoff/pgweb:latest sosedoff/pgweb:latest 补充其他的
你已经成功拉取了 PostgreSQL 和 pgWeb 镜像,现在需要补充代码中用到的 RabbitMQ 和 Qdrant 镜像(这两个是代码里 AddRabbitMQ/AddQdrant 依赖的核心镜像),同时修复代码语法错误,确保整体能正常运行。以下是完整的操作步骤:
一、第一步:拉取 RabbitMQ 和 Qdrant 镜像(Docker 命令)
在 Windows PowerShell 中执行以下命令,拉取代码依赖的所有镜像(适配国内网络):
1. 拉取 RabbitMQ 镜像(带管理插件,匹配代码 WithManagementPlugin())
powershell
# 拉取带管理插件的 RabbitMQ 镜像(3.13-alpine 轻量化版本)
docker pull docker.m.daocloud.io/rabbitmq:3.13-management-alpine
# 打官方标签,适配 .NET Aspire 识别
docker tag docker.m.daocloud.io/rabbitmq:3.13-management-alpine rabbitmq:3.13-management-alpine
# (备用)若 DaoCloud 源失效,用官方源(切换手机热点)
# docker pull rabbitmq:3.13-management-alpine
2. 拉取 Qdrant 镜像(匹配代码 AddQdrant("qdrant"))
powershell
# 拉取 Qdrant 镜像(v1.11 稳定版)
docker pull docker.m.daocloud.io/qdrant/qdrant:v1.11.3
# 打官方标签
docker tag docker.m.daocloud.io/qdrant/qdrant:v1.11.3 qdrant/qdrant:v1.11.3
# (备用)官方源
# docker pull qdrant/qdrant:v1.11.3
3. 验证所有镜像是否就绪(Windows PowerShell 命令)
powershell
# 查看所有依赖镜像(postgres/pgweb/rabbitmq/qdrant)
docker images | Select-String -Pattern "postgres|pgweb|rabbitmq|qdrant"
正常输出示例:
plaintext
postgres 15-alpine xxxxxxxx 1 hour ago 194MB
sosedoff/pgweb latest xxxxxxxx 1 hour ago 25MB
rabbitmq 3.13-management-alpine xxxxxxxx 1 hour ago 220MB
qdrant/qdrant v1.11.3 xxxxxxxx 1 hour ago 450MB
二、第二步:修复代码中的语法错误(关键!)
你的代码有 2 处语法错误,运行时会直接报错,先修正:
csharp
运行
using Projects;
var builder = DistributedApplication.CreateBuilder(args);
var postgresdb = builder.AddPostgres("postgres")
.WithDataVolume("postgres-aicopilot")
.WithPgWeb(pgAdmin => pgAdmin.WithHostPort(5050))
.AddDatabase("ai-copilot");
var rabbitmq = builder.AddRabbitMQ("eventbus")
.WithManagementPlugin()
.WithLifetime(ContainerLifetime.Persistent);
var qdrant = builder.AddQdrant("qdrant")
.WithLifetime(ContainerLifetime.Persistent);
var migration = builder.AddProject<Zilor_AICopilot_MigrationWorkApp>("aicopilot-migration")
.WithReference(postgresdb)
.WaitFor(postgresdb);
builder.AddProject<Zilor_AICopilot_HttpApi>("aicopilot-httpapi")
.WithUrl("swagger")
.WaitFor(postgresdb)
.WaitFor(rabbitmq)
.WaitFor(qdrant)
.WithReference(postgresdb)
.WithReference(rabbitmq)
.WithReference(migration)
.WithReference(qdrant)
.WaitForCompletion(migration);
builder.AddProject<Zilor_AICopilot_RagWorker>("rag-worker")
.WithReference(postgresdb) // 注入数据库连接
.WithReference(rabbitmq) // 注入 RabbitMQ 连接
.WithReference(qdrant)
.WaitFor(postgresdb) // 等待数据库启动
.WaitFor(rabbitmq) // 修复:缺少注释符 + 空格错误
.WaitFor(qdrant); // 修复:多余的空格
builder.Build().Run(); // 修复:Build() 和 Run() 前多余的空格
三、第三步:运行 .NET Aspire 项目(核心步骤)
- 确保 Docker Desktop 处于运行状态(右下角显示
Docker Desktop running); - 打开项目根目录的 PowerShell,执行以下命令:
powershell
# 1. 安装/更新 .NET Aspire 工作负载(确保依赖完整) dotnet workload install aspire # 2. 还原项目依赖 dotnet restore # 3. 运行 Aspire 项目(自动创建所有容器/卷/网络) dotnet run
四、关键补充说明
1. 容器生命周期与数据持久化
代码中 WithLifetime(ContainerLifetime.Persistent) 表示容器会持久化运行(不会随项目停止而删除),数据卷会保留:
- PostgreSQL 数据卷:
postgres-aicopilot(已手动创建); - RabbitMQ/Qdrant 数据卷:Aspire 会自动创建,无需手动操作。
2. 端口访问说明
- pgWeb(PostgreSQL 管理):http://localhost:5050(代码中
WithHostPort(5050)); - RabbitMQ 管理面板:默认端口 15672(
WithManagementPlugin()自动映射,访问 http://localhost:15672,默认账号 / 密码:guest/guest); - Qdrant 控制台:默认端口 6333(可通过
WithHostPort(6333)显式映射,可选)。
3. 常见问题排查
- 容器启动失败:
powershell
# 查看所有容器状态 docker ps -a # 查看报错容器日志(替换 <容器名/ID>) docker logs <容器名/ID> - 端口占用:
powershell
# 检查 5050/15672/6333 端口是否被占用 netstat -ano | findstr ":5050" netstat -ano | findstr ":15672" netstat -ano | findstr ":6333" # 杀死占用进程(替换 <PID>) taskkill /F /PID <PID> - 迁移项目等待超时:确保
Zilor_AICopilot_MigrationWorkApp项目能正常连接 PostgreSQL,可先单独运行迁移项目验证。
五、最终验证
运行 dotnet run 后,Aspire 会启动一个 Dashboard(默认地址 http://localhost:18888),在面板中可看到:
postgres容器状态为「Running」;eventbus(RabbitMQ)容器状态为「Running」;qdrant容器状态为「Running」;- 迁移项目
aicopilot-migration执行完成; aicopilot-httpapi和rag-worker正常启动。
至此,代码中所有依赖的 Docker 镜像已全部准备完毕,语法错误已修复,项目可正常运行。
其他专题
AI开发 1后端框架: ASP.NET Core2.AI框架: Semantic Kernerl (SK)、Agent Framework3.知识库:向量数据库(Qdrant)+关系型数据库(Post
https://blog.csdn.net/cao919/article/details/155895060
.net AI MCP 入门 适用于模型上下文协议的 C# SDK 简介(MCP)
https://blog.csdn.net/cao919/article/details/147915384
C# .net ai Agent AI视觉应用 写代码 改作业 识别屏幕 简历处理 标注等
https://blog.csdn.net/cao919/article/details/146504537
C# net deepseek RAG AI开发 全流程 介绍
https://blog.csdn.net/cao919/article/details/147915384
WPF halcon 机器视觉
https://blog.csdn.net/cao919/article/details/134790240
更多推荐



所有评论(0)