1.使用C#将几个Excel文件合并去重分类
2.C#使用SqlSugar操作MySQL数据库实现简单的增删改查
3.C#中的类和继承
4.C#中的virtual和override关键字
5.C#中的属性
6.C#winform中使用SQLite数据库
7.C#简化工作之实现网页爬虫获取数据
8.C#中的委托(一)
9.C#中的ref关键字
10.C#中out关键字
11.C#中内置的泛型委托Func与Action
12.在winform blazor hybrid中绘图
13.使用C#如何监控选定文件夹中文件的变动情况?
14.C#设计模式之策略模式
15.由浅入深理解C#中的事件
16.C#设计模式之观察者模式
17.C#设计模式之单例模式
18.C#基于ScottPlot进行可视化
19.C#使用MiniExcel导入导出数据到Excel/CSV文件
20.winform实现最小化至系统托盘
21.C#使用Bogus生成测试数据
22.SemanticKernel如何基于自有数据聊天
23.在winform中如何嵌入第三方软件窗体✨
24.在winform中如何实现双向数据绑定?
25.自己动手做一个批量doc转换为docx文件的小工具
26.WPF中动画教程(DoubleAnimation的基本使用)
27.WPF动画教程(PointAnimationUsingPath的使用)
28.C#使用PaddleOCR进行图片文字识别✨
29.WPF基础:在Canvas上绘制图形
30.WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中
31.使用归一化盒过滤器对图像进行平滑处理
32.WPF/C#:如何显示具有层级关系的数据
33.将彩色图转化为灰度图及其原理介绍
34.WPF/C#:ProgressBar的基本使用
35.在VB.NET项目中使用C#编写的代码
36.WPF/C#:理解与实现WPF中的MVVM模式
37.SemanticKernel:添加插件
38.Avalonia:一个.NET跨平台UI框架
39.WPF/C#:异常处理
40.WPF/C#:程序关闭的三种模式
41.wpfui:一个开源免费具有现代化设计趋势的WPF控件库
42.WPF/C#:如何将数据分组显示
43.WPF/C#:更改界面的样式
44.LiveCharts2:简单灵活交互式且功能强大的.NET图表库
45.WPF/C#:显示分组数据的两种方式
46.WPF/C#:在DataGrid中显示选择框
47.WPF/C#:数据绑定到方法
48.WPF/C#:BusinessLayerValidation
49.WPF/C#:如何实现拖拉元素
50.WPF在.NET9中的重大更新:Windows 11 主题
51.ONNX Runtime入门示例:在C#中使用ResNet50v2进行图像识别
52.动手学Avalonia:基于SemanticKernel与硅基流动构建AI聊天与翻译工具
53.Avalonia应用在基于Linux的国产操作deepin上运行
54.如何让其他模型也能在SemanticKernel中调用本地函数
55.大语言模型的应用探索—AI Agent初探!
56.动手学Avalonia:基于硅基流动构建一个文生图应用(一)
57.WPF/C#:在WPF中如何实现依赖注入
58.ScreenToGif:一款开源免费且好用的录屏转Gif软件
59.WPF/C#:实现导航功能
60.关于学习.NET的历程回顾与今后的探索实践方向
61.入门Vue+.NET 8 Web Api记录(一)
62.SemanticKernel/C#:检索增强生成(RAG)简易实践
63.SemanticKernel/C#:使用Ollama中的对话模型与嵌入模型用于本地离线场景
64.SemanticKernel/C#:实现接口,接入本地嵌入模型
65.EF Core连接PostgreSQL数据库
66.基于SiliconCloud快速体验GraphRag.Net
67.AvaloniaChat:一个基于大语言模型用于翻译的简单应用
68.最佳实践:在AvaloniaChat中接入SiliconCloud
69.AvaloniaChat—从源码构建指南
70.SimpleRAG:基于WPF与Semantic Kernel实现的一个简单的RAG应用
71.Semantic Kernel/C#:接入智谱AI的两种方式
72.AvaloniaChat-v0.0.2:兼容智谱AI 快速使用指南
73.使用SiliconCloud快速体验SimpleRAG(手把手教程)
74.使用Ollama本地离线体验SimpleRAG(手把手教程)
75.Semantic Kernel/C#:一种通用的Function Calling方法,文末附经测试可用的大模型
76.在SimpleRAG中使用SiliconCloud快速测试Function Calling
77.SimpleTranslationAIAgent:基于C#与LLM的翻译AI Agent
78.SimpleTranslationAIAgent借助SiliconCloud API 构建自己的专属翻译助手
79.SimpleAISearch:C# + DuckDuckGo 实现简单的AI搜索
80.SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用
81.SimpleRAG-v1.0.3:增加文件对话功能
82.如何自己动手实现一个图片解答小助手
83.AvaloniaTCP-v1.0.0:学习使用Avalonia/C#进行TCP通讯的一个简单Demo
84.Microsoft.Extensions.AI 初探
85.TesseractOCR-GUI:基于WPF/C#构建TesseractOCR简单易用的用户界面
86.VLM-OCR-Demo:一个使用VLM用于OCR任务的示例
87.C#调用Python脚本的方式(一),以PaddleOCR-GUI为例
88.C#调用Python代码的方式(二),以PaddleOCR-GUI为例
89.C#使用Tesseract C++ API过程记录
90.C#调用C++代码,以OpenCV为例
91.使用C#构建一个论文总结AI Agent
92.PaperAssistant:使用Microsoft.Extensions.AI实现
93.C# AIModelRouter:使用不同的AI模型完成不同的任务
94.使用Avalonia/C#构建一个简易的跨平台MCP客户端
95.在Avalonia/C#中使用依赖注入过程记录
96.使用C#构建一个同时问多个LLM并总结的小工具
97.手把手教你使用C#创建一个WebSearchAgent
98.
使用PocketFlowSharp创建一个Human_Evaluation示例
效果
实践
有时候AI生成的结果我们并不满意在进入下一步之前,我们需要对AI生成的结果进行人工审核,同意了才能进入下一个流程。
Human_Evaluation就是人工判断的一个简单示例。
internal class Program
{
static async Task Main(string[] args)
{
// Load .env file
DotEnv.Load();
// Get environment variables from .env file
var envVars = DotEnv.Read();
string ModelName = envVars["ModelName"];
string EndPoint = envVars["EndPoint"];
string ApiKey = envVars["ApiKey"];
Utils.ModelName = ModelName;
Utils.EndPoint = EndPoint;
Utils.ApiKey = ApiKey;
// 创建共享数据字典
var shared = new Dictionary<string, object>();
// 创建并运行流程
var humanEvalFlow = CreateFlow();
Console.WriteLine("\n欢迎使用人工判断示例!");
Console.WriteLine("------------------------");
await humanEvalFlow.RunAsync(shared);
Console.WriteLine("\n感谢使用人工判断示例!");
}
static AsyncFlow CreateFlow()
{
// 创建节点实例
var inputNode = new TaskInputNode();
var aiResponseNode = new AIResponseNode();
var humanApprovalNode = new HumanApprovalNode();
var endNode = new NoOpNode();
// 创建从输入节点开始的流程
var flow = new AsyncFlow(inputNode);
// 连接节点
_ = inputNode - "generate" - aiResponseNode;
_ = aiResponseNode - "approve" - humanApprovalNode;
_ = humanApprovalNode - "retry" - aiResponseNode; // 不接受时重新生成
_ = humanApprovalNode - "accept" - endNode; // 接受时结束流程
return flow;
}
}
看一下整体的流程图:
输入节点:
public class TaskInputNode : AsyncNode
{
protected override async Task<object> PrepAsync(Dictionary<string, object> shared)
{
Console.WriteLine("\n请输入需要AI处理的任务:");
string task = Console.ReadLine();
return task;
}
protected override async Task<object> ExecAsync(object prepResult)
{
string task = (string)prepResult;
Console.WriteLine($"\n已收到任务:{task}");
return task;
}
protected override async Task<object> PostAsync(Dictionary<string, object> shared, object prepResult, object execResult)
{
string task = (string)execResult;
shared["task"] = task;
return "generate";
}
}
AI回复节点:
public class AIResponseNode : AsyncNode
{
private static int attemptCount = 0;
protected override async Task<object> PrepAsync(Dictionary<string, object> shared)
{
return shared["task"];
}
protected override async Task<object> ExecAsync(object prepResult)
{
string task = (string)prepResult;
attemptCount++;
Console.WriteLine("AI正在生成回复...\n");
Console.WriteLine($"任务:{task}\n");
Console.WriteLine($"这是第 {attemptCount} 次生成的AI回复:\n");
var result = await Utils.CallLLMStreamingAsync(task);
string response="";
Console.ForegroundColor = ConsoleColor.Green;
await foreach (StreamingChatCompletionUpdate completionUpdate in result)
{
if (completionUpdate.ContentUpdate.Count > 0)
{
Console.Write(completionUpdate.ContentUpdate[0].Text);
response += completionUpdate.ContentUpdate[0].Text.ToString();
}
}
Console.ForegroundColor = ConsoleColor.White;
return response;
}
protected override async Task<object> PostAsync(Dictionary<string, object> shared, object prepResult, object execResult)
{
string response = (string)execResult;
shared["response"] = response;
return "approve";
}
}
人工审核节点:
public class HumanApprovalNode : AsyncNode
{
protected override async Task<object> PrepAsync(Dictionary<string, object> shared)
{
return shared["response"];
}
protected override async Task<object> ExecAsync(object prepResult)
{
Console.Write("\n您接受这个AI回复吗?(y/n): ");
string answer = Console.ReadLine()?.ToLower() ?? "n";
return answer;
}
protected override async Task<object> PostAsync(Dictionary<string, object> shared, object prepResult, object execResult)
{
string answer = (string)execResult;
if (answer == "y")
{
Console.WriteLine($"已接受的回复:\n{shared["response"]}");
return "accept";
}
else
{
Console.WriteLine("\n好的,让AI重新生成回复...");
return "retry";
}
}
}
结束节点:
public class NoOpNode : AsyncNode
{
protected override async Task<object> PrepAsync(Dictionary<string, object> shared) => null;
protected override async Task<object> ExecAsync(object prepResult) => null;
protected override async Task<object> PostAsync(Dictionary<string, object> shared, object prepResult, object execResult) => null;
}
帮助类:
public static class Utils
{
public static string ModelName { get; set; }
public static string EndPoint { get; set; }
public static string ApiKey { get; set; }
public static async Task<string> CallLLMAsync(string prompt)
{
ApiKeyCredential apiKeyCredential = new ApiKeyCredential(ApiKey);
OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
openAIClientOptions.Endpoint = new Uri(EndPoint);
ChatClient client = new(model: ModelName, apiKeyCredential, openAIClientOptions);
ChatCompletion completion = await client.CompleteChatAsync(prompt);
return completion.Content[0].Text;
}
public static async Task<AsyncCollectionResult<StreamingChatCompletionUpdate>> CallLLMStreamingAsync(string prompt)
{
ApiKeyCredential apiKeyCredential = new ApiKeyCredential(ApiKey);
OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
openAIClientOptions.Endpoint = new Uri(EndPoint);
ChatClient client = new(model: ModelName, apiKeyCredential, openAIClientOptions);
var completion = client.CompleteChatStreamingAsync(prompt);
return completion;
}
}
原创作者: mingupupu 转载于: https://www.cnblogs.com/mingupupu/p/18880039