基于 LLamaSharp + 通义千问本地 GGUF 模型的离线 AI 控制台智能代理(Agent)程序,核心实现对话交互 + 技能插件 + C# 代码自动生成 / 编译 / 无限纠错运行能力,整体
·
基于 LLamaSharp + 通义千问本地 GGUF 模型的离线 AI 控制台智能代理(Agent)程序,核心实现对话交互 + 技能插件 + C# 代码自动生成 / 编译 / 无限纠错运行能力,整体架构分层清晰、插件化设计。
一、整体架构
- 技能抽象层:
BaseSkill抽象基类,统一定义技能名称、描述、触发词、执行入口,所有功能均继承此类,实现插件式扩展。 - 具体技能模块(三大内置技能)
- 文件读取技能:识别 “读取文件” 等关键词,解析路径、读取本地文本文件并返回内容,做异常捕获。
- 清屏技能:匹配 “清屏 /cls”,调用控制台清屏方法。
- 代码运行 & 自动修复技能(核心)
- 基于
csc.exe编译 C# 代码、运行生成的 exe 程序; - 循环重试机制:编译错误 / 运行错误都会自动调用大模型重新生成 / 修复代码,无限迭代直至运行成功;
- 内置临时目录管理,自动生成、清理代码与可执行文件;
- 构造专属提示词,要求模型输出完整可编译的 C# 控制台代码。
- 基于
- AI 代理核心
LlamaAgent- 统一管理所有技能,根据用户输入关键词匹配对应技能并执行;
- 无匹配技能时,走通用 LLM 对话逻辑,流式输出回复;
- 封装 LLama 推理执行器与推理参数。
- 主程序入口
- 加载本地 Qwen2.5 GGUF 大模型,配置上下文、GPU 加速、线程等参数;
- 隐藏模型加载日志,启动交互式控制台循环;
- 监听用户输入,支持
exit退出,全程 UTF8 编码适配中文。
二、核心亮点
- 插件化技能体系:新增功能只需继承
BaseSkill并注册,拓展性强。 - 代码全自动闭环:AI 生成代码 → CSC 编译 → 运行 → 出错自动回传给模型修复,无限重试,实现代码自纠错。
- 本地离线运行:依托 LLamaSharp 加载 GGUF 模型,无需联网。
- 完善容错:文件读写、进程调用、模型推理全流程异常捕获,临时文件自动清理。
三、关键依赖与配置
- 依赖:
LLama、LLama.Common、LLama.Sampling(LLamaSharp 库) - 模型:
qwen2.5-7b-instruct量化 GGUF 模型 - 编译依赖:系统自带
csc.exe(C# 编译器) - 推理参数:上下文 8192、温度 0.3、最大生成长度 1500,GPU 分层加速。
四、使用流程
- 程序启动加载本地大模型;
- 控制台交互输入指令:
- 普通文字:进入 AI 闲聊;
- 含「读取文件 + 路径」:读取本地文件;
- 含「清屏 /cls」:清空控制台;
- 含「写代码 / 运行代码」:AI 生成代码→编译→运行→出错自动修复;
- 输入
exit退出程序,自动释放模型资源。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using LLama;
using LLama.Common;
using LLama.Sampling;
namespace QwenCodeAgentConsole
{
#region 技能抽象基类
public abstract class BaseSkill
{
public abstract string Name { get; }
public abstract string Description { get; }
public abstract List<string> TriggerWords { get; }
public abstract Task<string> ExecuteAsync(string userInput);
}
#region 基础技能
/// <summary>文件读取技能</summary>
public class FileReadSkill : BaseSkill
{
public override string Name => "FileReadSkill";
public override string Description => "读取本地文本文件内容";
public override List<string> TriggerWords => new() { "读取文件", "读文件", "获取文件内容" };
public override async Task<string> ExecuteAsync(string userInput)
{
await Task.CompletedTask;
// 简单提取路径(可根据需求增强路径解析)
string path = ExtractFilePath(userInput);
if (string.IsNullOrWhiteSpace(path))
return "未识别到有效文件路径,请输入:读取文件 + 文件完整路径";
try
{
if (!File.Exists(path))
return $"错误:文件不存在 -> {path}";
string content = await File.ReadAllTextAsync(path, Encoding.UTF8);
return $"✅ 文件读取成功\n路径:{path}\n内容:\n{content}";
}
catch (Exception ex)
{
return $"❌ 读取文件失败:{ex.Message}";
}
}
// 简易提取路径(取最后一段路径字符串,适配常规输入)
private string ExtractFilePath(string input)
{
char[] splitChars = { ' ', ':', ':', ',', ',' };
var parts = input.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
foreach (var part in parts)
{
if (File.Exists(part) || part.Contains("\\") || part.Contains("/"))
return part;
}
return string.Empty;
}
}
public class ClearScreenSkill : BaseSkill
{
public override string Name => "ClearScreenSkill";
public override string Description => "清空控制台界面";
public override List<string> TriggerWords => new() { "清屏", "清空屏幕", "cls" };
public override async Task<string> ExecuteAsync(string userInput)
{
await Task.CompletedTask;
Console.Clear();
return "✅ 已清空屏幕";
}
}
#endregion
#region 代码运行技能(无限自动迭代修复)
public class CodeRunSkill : BaseSkill
{
private readonly InteractiveExecutor _llamaExecutor;
private readonly InferenceParams _inferParams;
private readonly string _tempDir;
private readonly string _codeFile;
private readonly string _exeFile;
public CodeRunSkill(InteractiveExecutor executor, InferenceParams inferParams)
{
_llamaExecutor = executor;
_inferParams = inferParams;
_tempDir = Path.Combine(Environment.CurrentDirectory, "CodeTemp");
Directory.CreateDirectory(_tempDir);
_codeFile = Path.Combine(_tempDir, "RunCode.cs");
_exeFile = Path.Combine(_tempDir, "RunCode.exe");
}
public override string Name => "CodeRunSkill";
public override string Description => "编写C#代码,自动编译、运行,编译/运行异常时无限自动修复重试";
public override List<string> TriggerWords => new()
{
"写代码", "编写代码", "写c#", "运行代码", "编译代码", "帮我写程序"
};
public override async Task<string> ExecuteAsync(string userInput)
{
try
{
int retryTimes = 0;
string lastError = string.Empty;
string lastOutput = string.Empty;
// 无限循环重试
while (true)
{
retryTimes++;
Console.WriteLine($"\n[系统] 第 {retryTimes} 次尝试");
Console.WriteLine("[系统] 正在生成/修复代码...");
string code = await GenerateOrFixCode(userInput, lastError, lastOutput);
if (string.IsNullOrWhiteSpace(code))
{
lastError = "代码生成为空";
continue;
}
await File.WriteAllTextAsync(_codeFile, code, Encoding.UTF8);
Console.WriteLine("[系统] 开始编译...");
var compileResult = await CompileCodeAsync();
if (!compileResult.Success)
{
lastError = $"编译错误:{compileResult.Message}";
Console.WriteLine($"[系统] {lastError},准备重新修复代码");
continue;
}
Console.WriteLine("[系统] 编译成功,开始运行...");
var runOutput = await RunExeAsync();
lastOutput = runOutput;
if (!runOutput.Contains("运行错误:"))
{
CleanTempFiles();
return $"✅ 执行成功(共尝试 {retryTimes} 次)\n--- 程序输出 ---\n{runOutput}";
}
lastError = $"运行错误:{runOutput}";
Console.WriteLine($"[系统] {lastError},准备重新修复代码");
}
}
catch (Exception ex)
{
CleanTempFiles();
return $"❌ 全局异常:{ex.Message}";
}
}
private async Task<string> GenerateOrFixCode(string originRequest, string errorInfo, string runOutput)
{
StringBuilder promptBuilder = new StringBuilder();
promptBuilder.Append(@"<|im_start|>system
你是专业C#程序员。根据需求编写**完整可直接用csc.exe编译运行**的控制台代码。
必须包含 using、namespace、Program、Main 方法。
不要额外解释、不要markdown标记、不要多余文字,只输出代码。
如果存在编译错误、运行错误,根据错误日志精准修正代码。<|im_end|>
");
promptBuilder.AppendLine("<|im_start|>user");
promptBuilder.AppendLine($"用户需求:{originRequest}");
if (!string.IsNullOrWhiteSpace(errorInfo))
promptBuilder.AppendLine($"历史错误信息:{errorInfo}");
if (!string.IsNullOrWhiteSpace(runOutput) && !runOutput.Contains("运行错误:"))
promptBuilder.AppendLine($"上一次运行输出:{runOutput}");
promptBuilder.AppendLine("请修正代码并重新输出完整代码<|im_end|>");
promptBuilder.AppendLine("<|im_start|>assistant");
StringBuilder codeSb = new StringBuilder();
await foreach (var token in _llamaExecutor.InferAsync(promptBuilder.ToString(), _inferParams))
{
if (token.Contains("<|im_end|>")) break;
codeSb.Append(token);
}
return codeSb.ToString().Trim();
}
#region 编译、运行、清理工具方法
private class CompileOutput
{
public bool Success { get; set; }
public string Message { get; set; } = string.Empty;
}
private async Task<CompileOutput> CompileCodeAsync()
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "csc.exe",
Arguments = $"\"{_codeFile}\" /out:\"{_exeFile}\"",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
process.Start();
string err = await process.StandardError.ReadToEndAsync();
string outStr = await process.StandardOutput.ReadToEndAsync();
process.WaitForExit();
return process.ExitCode == 0
? new CompileOutput { Success = true, Message = outStr }
: new CompileOutput { Success = false, Message = $"退出码:{process.ExitCode}\n{err}" };
}
private async Task<string> RunExeAsync()
{
if (!File.Exists(_exeFile)) return "可执行文件不存在";
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = _exeFile,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
process.Start();
string output = await process.StandardOutput.ReadToEndAsync();
string error = await process.StandardError.ReadToEndAsync();
process.WaitForExit();
StringBuilder sb = new StringBuilder();
if (!string.IsNullOrEmpty(output)) sb.AppendLine(output);
if (!string.IsNullOrEmpty(error)) sb.AppendLine($"运行错误:{error}");
return sb.ToString();
}
private void CleanTempFiles()
{
try
{
if (File.Exists(_codeFile)) File.Delete(_codeFile);
if (File.Exists(_exeFile)) File.Delete(_exeFile);
}
catch { }
}
#endregion
}
#endregion
#endregion
#region AI Agent 核心
public class LlamaAgent
{
private readonly List<BaseSkill> _skills = new();
private readonly InteractiveExecutor _executor;
private readonly InferenceParams _inferParams;
public LlamaAgent(InteractiveExecutor executor, InferenceParams inferParams)
{
_executor = executor;
_inferParams = inferParams;
RegisterAllSkills();
}
public void RegisterSkill(BaseSkill skill)
{
if (!_skills.Any(s => s.Name == skill.Name))
_skills.Add(skill);
}
private void RegisterAllSkills()
{
// 移除 TimeSkill,新增文件读取技能
RegisterSkill(new FileReadSkill());
RegisterSkill(new ClearScreenSkill());
RegisterSkill(new CodeRunSkill(_executor, _inferParams));
}
public BaseSkill? MatchSkill(string userInput)
{
var input = userInput.ToLower();
return _skills.FirstOrDefault(skill =>
skill.TriggerWords.Any(k => input.Contains(k.ToLower())));
}
public async Task ChatAsync(string userInput)
{
var hitSkill = MatchSkill(userInput);
if (hitSkill != null)
{
string result = await hitSkill.ExecuteAsync(userInput);
Console.WriteLine($"AI:{result}");
return;
}
await NormalChatAsync(userInput);
}
private async Task NormalChatAsync(string question)
{
string prompt = $@"<|im_start|>system
你是一个有用的AI助手<|im_end|>
<|im_start|>user
{question}<|im_end|>
<|im_start|>assistant
";
Console.Write("AI:");
await foreach (var token in _executor.InferAsync(prompt, _inferParams))
{
if (token.Contains("<|im_end|>")) break;
Console.Write(token);
}
}
}
#endregion
#region 主程序
class Program
{
private static LLamaWeights? _model;
private static LLamaContext? _context;
private static LlamaAgent? _aiAgent;
private static readonly InferenceParams _infParams = new InferenceParams
{
MaxTokens = 1500,
AntiPrompts = new[] { "<|im_end|>" },
SamplingPipeline = new DefaultSamplingPipeline { Temperature = 0.3f }
};
private static string _modelPath = "qwen2.5-7b-instruct-1m-q4_k_m.gguf";
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);
var executor = new InteractiveExecutor(_context);
_aiAgent = new LlamaAgent(executor, _infParams);
}
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true });
Console.WriteLine("================================================================================================");
Console.WriteLine(" 本地离线 AI 代码迭代助手 | 无限自动修复编译/运行错误");
Console.WriteLine($"模型:qwen2.5-7b-instruct-1m-q4_k_m.gguf");
Console.WriteLine("功能:对话 / 读取文件 / 清屏 / 代码自动编写+编译+无限修复重试");
Console.WriteLine("输入 exit 退出");
Console.WriteLine("================================================================================================");
Console.WriteLine();
while (true)
{
Console.Write("你:");
string input = Console.ReadLine()?.Trim() ?? string.Empty;
if (string.IsNullOrEmpty(input)) continue;
if (input.ToLower() == "exit") break;
if (_aiAgent != null)
await _aiAgent.ChatAsync(input);
Console.WriteLine("\n");
}
_context?.Dispose();
_model?.Dispose();
}
}
#endregion
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)