# 工业离线AI助手程序总结这是一个基于**C# .NET**开发、集成通义千问Qwen2.5-7B开源大模型的**本地离线工业AI助手控制台程序**,核心实现了无网络环境下的工业场景智能问答,结合
这是一个基于C# .NET开发、集成通义千问 Qwen2.5-7B 开源大模型的本地离线工业 AI 助手控制台程序,核心实现了无网络环境下的工业场景智能问答,结合本地知识库提供精准、安全的专属 AI 服务。程序核心架构分为模型加载、知识库管理、对话交互、推理问答四大模块:启动时自动加载 GGUF 量化格式的 4 比特模型,纯 CPU 运行仅占用约 6GB 内存,无需依赖显卡,大幅降低部署门槛;自动
工业离线 AI 助手程序总结
这是一个基于C# .NET开发、集成通义千问 Qwen2.5-7B 开源大模型的本地离线工业 AI 助手控制台程序,核心实现了无网络环境下的工业场景智能问答,结合本地知识库提供精准、安全的专属 AI 服务。net8.0 winform
程序核心架构分为模型加载、知识库管理、对话交互、推理问答四大模块:启动时自动加载 GGUF 量化格式的 4 比特模型,纯 CPU 运行仅占用约 6GB 内存,无需依赖显卡,大幅降低部署门槛;自动读取指定knowledge文件夹内的所有文件构建本地知识库,支持展示已学习文件,通过关键词匹配技术快速检索与用户问题相关的参考资料。
对话功能具备完整的交互体验,支持连续对话记忆、一键清空历史、数字快捷追问上一轮问题,内置退出、清屏等实用指令。推理环节采用通义千问专属对话模板,结合系统提示词限定 AI 以工业专业助手身份作答,将检索到的知识库内容融入 prompt,保证回答精准贴合工业场景,同时限制输出长度,提升响应速度。
整体方案解决了工业场景数据保密、无网络环境的核心痛点,模型轻量化、部署简单、交互便捷,既能独立完成通用问答,又能依托本地知识库实现专业工业问题解答,是适配工业现场的轻量化离线 AI 解决方案,兼顾了实用性、安全性和易用性。
总结
- 这是纯离线、本地化的工业专用 AI 助手,无数据外泄风险,适配无网工业环境;
- 基于 Qwen2.5-7B 量化模型,低资源占用,纯 CPU 即可流畅运行;
- 核心能力:本地知识库检索 + 智能问答,支持对话记忆、快捷追问,交互友好;
- 部署简单、操作便捷,完美匹配工业场景的安全、专业、轻量化需求。


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LLama;
using LLama.Common;
using LLama.Sampling;
namespace QwenConsole
{
class Program
{
private static LLamaWeights _model;
private static LLamaContext _context;
private static InteractiveExecutor _executor;
private static Dictionary<string, string> _knowledge;
// 内部记忆(不显示)
private static List<ChatHistoryItem> _chatHistory = new();
private static int _historyId = 1;
private static readonly InferenceParams _infParams = new InferenceParams
{
MaxTokens = 500,
AntiPrompts = new[] { "<|im_end|>", "User:", "用户:", "Assistant:", "助手:" },
SamplingPipeline = new DefaultSamplingPipeline { Temperature = 0.3f }
};
private static string _modelPath = "qwen2.5-7b-instruct-1m-q4_k_m.gguf";
private static string _knowledgeFolder = "knowledge"; // 知识库文件夹
public class ChatHistoryItem
{
public int Id { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
}
static async Task Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
Console.WriteLine("正在加载模型...");
using (var nullWriter = new StringWriter())
{
Console.SetOut(nullWriter);
var parameters = new ModelParams(_modelPath)
{
ContextSize = 8192,
GpuLayerCount = 99,
Threads = Environment.ProcessorCount,
};
_model = LLamaWeights.LoadFromFile(parameters);
_context = new LLamaContext(_model, parameters);
_executor = new InteractiveExecutor(_context);
_knowledge = FileHelper.LoadAllKnowledgeFiles();
}
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true });
Console.WriteLine("=================================================="); Console.WriteLine("==================================================");
Console.WriteLine(" 工业离线AI助手");
Console.WriteLine(" 模型:Qwen2.5-7B-Instruct 通义千问开源大模型");
Console.WriteLine(" 量化:4-bit Q4_K_M(高精度小体积)");
Console.WriteLine(" 占用:内存 ~ 6GB ± 显存 0GB(纯CPU运行)");
Console.WriteLine($" 已加载知识库文件夹:{_knowledgeFolder}");
Console.WriteLine($" 学习文件总数:{_knowledge.Count} 个");
ShowLoadedFiles(); // 显示学习了哪些文件
Console.WriteLine(" 输入数字 = 追问上一轮 | 直接输入 = 新问题");
Console.WriteLine(" exit 退出 | clear 清空记忆");
Console.WriteLine("==================================================\n");
while (true)
{
Console.Write("你:");
string input = Console.ReadLine()?.Trim();
if (string.IsNullOrEmpty(input)) continue;
if (input.ToLower() == "exit") break;
if (input.ToLower() == "clear")
{
_chatHistory.Clear();
_historyId = 1;
Console.WriteLine("✅ 记忆已清空\n");
continue;
}
string userQuestion = input;
// 输入数字 = 追问上一轮
if (int.TryParse(input, out int num) && num == _historyId - 1 && _chatHistory.Count > 0)
{
var last = _chatHistory.Last();
userQuestion = $"请详细解释:{last.Question}";
Console.WriteLine($"▶ 继续追问:{last.Question}");
}
string know = QueryKnowledge(userQuestion);
string answer = await InferAnswer(userQuestion, know);
_chatHistory.Add(new ChatHistoryItem
{
Id = _historyId++,
Question = userQuestion,
Answer = answer
});
Console.WriteLine("\n");
}
_context?.Dispose();
_model?.Dispose();
}
// 显示已学习的所有文件
static void ShowLoadedFiles()
{
if (_knowledge.Count == 0)
{
Console.WriteLine(" 未学习任何文件");
return;
}
Console.WriteLine(" 已学习文件列表:");
int i = 1;
foreach (var file in _knowledge.Keys)
{
Console.WriteLine($" {i++}. {file}");
}
}
static async Task<string> InferAnswer(string question, string know)
{
string extra = string.IsNullOrEmpty(know) ? "" : $"\n【参考资料】\n{know}\n";
string system = $"你是专业工业AI助手,根据参考资料精准简洁回答。{extra}";
StringBuilder historyPrompt = new();
foreach (var h in _chatHistory)
{
historyPrompt.AppendLine($"<|im_start|>user\n{h.Question}<|im_end|>");
historyPrompt.AppendLine($"<|im_start|>assistant\n{h.Answer}<|im_end|>");
}
string prompt = $"<|im_start|>system\n{system}<|im_end|>\n"
+ historyPrompt
+ $"<|im_start|>user\n{question}<|im_end|>\n"
+ $"<|im_start|>assistant\n";
Console.Write("AI:");
StringBuilder answer = new();
int count = 0;
const int LIMIT = 500;
await foreach (var token in _executor.InferAsync(prompt, _infParams))
{
if (count++ > LIMIT || token.Contains("<|im_end|>") || token.Contains("User:"))
break;
Console.Write(token);
answer.Append(token);
}
return answer.ToString().Trim();
}
private static string QueryKnowledge(string question)
{
if (_knowledge.Count == 0) return "";
var words = question.ToLower()
.Replace("?", " ").Replace("?", "")
.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var matches = _knowledge
.Select(k => new
{
k.Key,
k.Value,
Score = words.Count(w => k.Value.ToLower().Contains(w))
})
.Where(x => x.Score > 0)
.OrderByDescending(x => x.Score)
.Take(3)
.Select(x => $"【{x.Key}】\n{x.Value.Substring(0, Math.Min(1200, x.Value.Length))}");
return string.Join("\n\n", matches);
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ExcelDataReader;
using System.Data;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using DocumentFormat.OpenXml.Packaging;
using Path = System.IO.Path;
public static class FileHelper
{
/// <summary>
/// 读取【资料】文件夹下所有支持的文档
/// 支持:txt / pdf / docx / xlsx / xls
/// </summary>
public static Dictionary<string, string> LoadAllKnowledgeFiles()
{
var knowledge = new Dictionary<string, string>();
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string learnDir = Path.Combine(baseDir, "资料");
if (!Directory.Exists(learnDir))
{
Directory.CreateDirectory(learnDir);
return knowledge;
}
string[] exts = { ".txt", ".pdf", ".docx", ".xlsx", ".xls" };
var files = Directory.GetFiles(learnDir, "*.*", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
string ext = Path.GetExtension(file).ToLower();
if (!Array.Exists(exts, e => e == ext)) continue;
try
{
string content = ext switch
{
".txt" => ReadText(file),
".pdf" => ReadPdf(file),
".docx" => ReadDocx(file),
".xlsx" or ".xls" => ReadExcel(file),
_ => ""
};
if (!string.IsNullOrWhiteSpace(content))
knowledge[Path.GetFileName(file)] = content;
}
catch { }
}
return knowledge;
}
public static string ReadText(string path) => File.ReadAllText(path, Encoding.UTF8);
public static string ReadPdf(string path)
{
try
{
var sb = new StringBuilder();
using var reader = new PdfReader(path);
for (int i = 1; i <= reader.NumberOfPages; i++)
sb.AppendLine(PdfTextExtractor.GetTextFromPage(reader, i));
return sb.ToString();
}
catch { return ""; }
}
public static string ReadDocx(string path)
{
try
{
var sb = new StringBuilder();
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var doc = WordprocessingDocument.Open(fs, false);
if (doc.MainDocumentPart?.Document?.Body == null) return "";
foreach (var p in doc.MainDocumentPart.Document.Body.Elements<DocumentFormat.OpenXml.Wordprocessing.Paragraph>())
{
string text = p.InnerText?.Trim();
if (!string.IsNullOrEmpty(text)) sb.AppendLine(text);
}
return sb.ToString();
}
catch { return ""; }
}
public static string ReadExcel(string path)
{
try
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using var stream = File.OpenRead(path);
using var reader = ExcelReaderFactory.CreateReader(stream);
var ds = reader.AsDataSet();
var sb = new StringBuilder();
foreach (DataTable table in ds.Tables)
{
sb.AppendLine("=== " + table.TableName + " ===");
foreach (DataRow row in table.Rows)
{
foreach (DataColumn col in table.Columns)
sb.Append(row[col] + "\t");
sb.AppendLine();
}
}
return sb.ToString();
}
catch { return ""; }
}
}
更多推荐



所有评论(0)