本教程演示如何基于 C#、Entity Framework Core、OpenAI/DeepSeek 模型,以及 AI Function Calling 机制,构建一个支持人工审批的人机协同数据库助手。
核心思想是:低风险操作由 AI 自动执行,高风险操作必须经过人工确认。
一、什么是“人机协同”?
在人机协同系统中,AI 不再是完全自主执行所有任务,而是按照风险等级分工:
AI 负责理解自然语言
AI 负责生成 SQL 和调用工具
人工负责审批高风险操作
系统负责流程衔接和状态恢复
这是一种非常适合企业场景的模式,尤其适用于:
数据库管理
财务审批
工单流转
运维执行
权限变更
合同审核
简单来说:
让 AI 提高效率,让人类保留最终控制权。
二、本项目实现了什么?
这个示例实现了一个 DBA Agent(数据库管理员助手),它可以把用户的自然语言需求转成 SQL Server 操作。
支持四类数据库工具:
QueryData
执行
SELECT只读查询
可直接执行,无需审批
InsertData
执行
INSERT新增数据
默认可直接执行
UpdateData
执行
UPDATE修改数据
属于高危操作,必须人工审批
DeleteData
执行
DELETE删除数据
属于高危操作,必须人工审批
这就是一个典型的人机协同设计:
读和新增:AI 自动处理
修改和删除:人类把关审批
三、整体流程图
整个交互流程可以理解为下面这样:
TEXT用户输入自然语言 ↓AI Agent 理解意图 ↓判断要调用哪个数据库工具 ↓如果是 Query/Insert → 直接执行如果是 Update/Delete → 触发审批拦截 ↓人工在控制台输入 y / n ↓批准:继续执行拒绝:终止执行 ↓AI 汇总结果并返回给用户四、项目中的关键设计思路
这份代码最重要的不是“怎么连数据库”,而是怎么实现可控的人机协同机制。
核心有 4 个部分:
1. 用 DI 管理数据库上下文和工具
代码中先初始化依赖注入容器:
var builder = new ServiceCollection();builder.AddDbContext<MyAgentDbContext>(options => options.UseSqlServer("Server=DESKTOP-ABQMKQL;Database=testDB;Integrated Security=True;TrustServerCertificate=True;"));builder.AddTransient<ToolsToSql>();var services = builder.BuildServiceProvider();var sqlTools = services.GetRequiredService<ToolsToSql>();这里做了两件事:
注册
MyAgentDbContext注册数据库工具类
ToolsToSql
其中:
builder.AddTransient<ToolsToSql>();表示每次获取工具类时都创建新实例,避免生命周期冲突。
2. 把数据库方法包装成 AI 可调用工具
接下来,把普通 C# 方法封装成 AI 工具:
var queryTool = AIFunctionFactory.Create(sqlTools.QueryData);var insertTool = AIFunctionFactory.Create(sqlTools.InsertData);var updateToolBase = AIFunctionFactory.Create(sqlTools.UpdateData);var deleteToolBase = AIFunctionFactory.Create(sqlTools.DeleteData);这一步的意义是:
让大模型不仅能“聊天”,还能“调用函数”。
也就是说,大模型在理解用户说“帮我查一下用户表”之后,不只是生成文字回答,而是可以真正去调用 QueryData(sql)。
3. 为高危操作增加审批拦截器
这是整个人机协同的关键:
var updateToolWithApproval = new ApprovalRequiredAIFunction(updateToolBase);var deleteToolWithApproval = new ApprovalRequiredAIFunction(deleteToolBase);var aiTools = new List<AITool> { queryTool, insertTool, updateToolWithApproval, deleteToolWithApproval };这里的设计非常重要:
QueryData和InsertData直接暴露给 AIUpdateData和DeleteData先用ApprovalRequiredAIFunction包装包装后,AI 调用这些工具时不会立刻执行
系统会先拦截,生成一个 审批请求
这就是“人机协同”的核心实现方式:
不是禁止 AI 做高风险操作,而是让 AI 发起申请,由人类决定是否放行。
4. 给 Agent 写明确的系统提示词
系统提示词里明确约束了 Agent 的行为:
string instructionsSys = """你是一个专业、严谨且高效的智能数据库管理员 (DBA Agent)。...1. QueryData (SELECT):用于查询和读取数据,属于安全操作,可直接调用。2. InsertData (INSERT):用于新增记录,属于安全操作,可直接调用。3. UpdateData (UPDATE):用于修改现有数据。这是【高危操作】,系统配置了拦截器,你调用此工具后系统会暂停并等待用户人工审批。4. DeleteData (DELETE):用于删除现有数据。这是【高危操作】,系统配置了拦截器,你调用此工具后系统会暂停并等待用户人工审批。...1. 极度严谨 (防误操作):在编写 UPDATE 或 DELETE 语句时,绝对禁止遗漏 WHERE 条件。2. 主动沟通:如果用户需求模糊,请先提问澄清。3. 审批感知:执行 UPDATE 或 DELETE 前提醒用户进行审批。4. 专业反馈:结果要用 Markdown 输出。5. T-SQL 规范:必须使用 SQL Server 语法。""";这段提示词的作用不是“装饰”,而是让模型具备明确边界感:
知道有哪些工具
知道哪些操作是高危的
知道不能漏掉
WHERE知道需求模糊时要先问
知道最后要格式化输出
在人机协同系统里,提示词就是 AI 的操作规程。
五、如何创建 Agent
Agent 的创建代码如下:
var dbAgent = chatClient.AsAIAgent( instructions: instructionsSys, tools: [..aiTools], services: services);var session = await dbAgent.CreateSessionAsync();这里完成了三件事:
把聊天模型变成 Agent
把工具列表交给 Agent
创建一个会话
session
这个 session 很重要,因为审批后要恢复上下文继续执行,必须依赖会话状态。
六、对话循环是如何运行的?
主循环中,用户输入自然语言:
var userInput = Console.ReadLine()?.Trim();if (string.IsNullOrEmpty(userInput)) continue;if (userInput.ToLower() is "exit" or "quit") break;然后把输入交给 Agent:
var response = await dbAgent.RunAsync(userInput, session);这一步之后,可能有两种情况:
情况 A:普通操作
比如:
“查询所有用户”
“新增一条员工记录”
那么 Agent 会直接执行工具并返回结果。
情况 B:高危操作
比如:
“把张三的状态改成离职”
“删除订单表里 ID=10 的数据”
那么 Agent 会触发审批请求,而不会立即执行。
七、如何识别审批请求?
代码会扫描返回消息中的审批内容:
var result = response.Messages .SelectMany(x => x.Contents) .OfType<ToolApprovalRequestContent>() .ToList();如果 result.Any() 为真,说明:
AI 发起了一个需要人工确认的高危操作。
这时系统会在控制台显示警告:
Console.WriteLine("\n⚠️ [系统警告] 拦截到高危数据库操作,需要人工审批!");八、人工审批是如何完成的?
系统会逐个审批请求询问用户:
Console.Write("\n❓ 是否允许执行该操作?(y/n): ");var answer = Console.ReadLine()?.Trim().ToLower();bool isApproved = (answer == "y" || answer == "yes");如果用户输入 y:
approvalResponses.Add(approvalReq.CreateResponse(true));如果用户输入 n:
approvalResponses.Add(approvalReq.CreateResponse(false));这一段的本质就是:
AI 先申请
人工做决定
系统把决定反馈给 Agent
这正是标准的人机协同闭环。
九、审批后如何恢复 Agent 执行?
审批只是中间一步,批准或拒绝后,还要把结果传回给 Agent,让它继续后续流程:
var chatMesg = new List<ChatMessage>();foreach (var message in approvalResponses){ chatMesg.Add(new ChatMessage(ChatRole.User, [message]));}response = await dbAgent.RunAsync(chatMesg, session);这里非常关键。
因为 Agent 的执行并没有结束,只是“暂停等待审批”。
当系统把审批结果作为新的消息传回去时,Agent 才能继续:
如果批准了,就执行 SQL
如果拒绝了,就告诉用户操作被取消
所以这一步可以理解为:
把人工决策重新送回 AI 工作流,恢复执行。
十、数据库工具类是怎么设计的?
项目中用 ToolsToSql 封装了数据库操作。
1. 查询工具 QueryData
[Description("执行 SQL Server SELECT 查询操作,该操作仅读取数据,无需审批可直接执行")]public string QueryData(string sql)它的特点:
只执行
SELECT读取结果集
把结果转成 JSON 返回
自动附带执行时间和状态
返回结果类似:
✅ 查询执行成功!操作类型: SELECT 查询SQL语句: SELECT * FROM Users返回数据: [...]审批状态: 自动放行 (无需审批)执行时间: 2026-04-15 12:00:002. 新增工具 InsertData
[Description("执行 SQL Server INSERT 插入操作,用于向数据库新增记录,通常无需审批可直接执行")]public string InsertData(string sql)特点:
执行
INSERT返回影响行数
作为低风险操作自动放行
3. 修改工具 UpdateData
[Description("执行 SQL Server UPDATE 更新操作,该操作会修改数据,必须经过审批才能真正执行")]public string UpdateData(string sql)特点:
实际执行
UPDATE但它在进入执行前,已经被审批拦截器包裹
只有批准后才会真正运行
4. 删除工具 DeleteData
[Description("执行 SQL Server DELETE 删除操作,该操作属于高危动作,必须经过严格审批才能真正执行")]public string DeleteData(string sql)特点与 UpdateData 类似,但风险更高。
十一、为什么这套方案体现了“人机协同”?
很多人以为“人机协同”就是“AI 帮人做事”。
其实更准确的理解是:
AI 负责处理复杂度,人类负责兜底风险。
在这份代码中:
AI 负责的部分
理解自然语言
判断用户意图
生成 SQL
自动调用工具
整理执行结果
人类负责的部分
审批 UPDATE
审批 DELETE
拒绝危险操作
最终掌控执行权
系统负责的部分
工具注册
审批拦截
会话恢复
结果回传
这三者共同组成:
AI 的智能
人的判断
系统的控制
这就是完整的人机协同。
十二、一个典型使用示例
示例 1:查询数据
用户输入:
查询 users 表中的所有数据可能流程:
AI 判断这是查询操作
调用
QueryData直接返回结果
不需要人工审批。
示例 2:新增数据
用户输入:
往 users 表插入一条记录,姓名为张三,年龄 25可能流程:
AI 生成
INSERT调用
InsertData自动执行
返回影响行数
通常也不需要审批。
示例 3:修改数据
用户输入:
把 users 表中 id=3 的用户名改成李四流程如下:
AI 判断是
UPDATE触发审批拦截
控制台提示是否批准
人工输入
yAgent 恢复执行
返回更新成功结果
示例 4:删除数据
用户输入:
删除 users 表中 id=8 的记录流程如下:
AI 判断是
DELETE系统拦截
控制台审批
人工可输入
n操作被拒绝
Agent 向用户说明删除未执行
十三、这套设计的优势
1. 安全
高危操作不会被 AI 直接执行,避免误删、误改。
2. 可控
人类始终掌握最终决定权。
3. 高效
低风险操作自动化,高风险操作半自动化。
4. 易扩展
以后可以把审批范围扩展到:
导出敏感数据
调用外部接口
批量变更权限
执行运维脚本
5. 适合企业落地
这是比“纯自动 Agent”更容易被企业接受的一种方案。
十四、实践建议
如果你准备把这个方案真正用于生产环境,建议继续完善以下内容:
1. 不要把 API Key 写死在代码里
当前代码里有类似:
var chatClient = StaticGetIChatClient("deepseek-chat", "你的key", "https://api.deepseek.com/v1");实际项目中应改为:
环境变量
配置文件
Secret Manager
Key Vault
2. 数据库连接字符串也不要硬编码
建议放在:
appsettings.json环境变量
配置中心
3. 对 SQL 做更严格校验
目前主要依赖模型提示词约束,但生产环境最好增加程序级校验,例如:
UPDATE必须包含WHEREDELETE必须包含WHERE禁止多语句执行
禁止执行 DDL
禁止危险关键字组合
4. 加审计日志
建议记录:
谁发起的请求
AI 生成了什么 SQL
谁审批通过/拒绝
最终执行结果
执行时间
5. 审批界面可以升级
现在是控制台输入 y/n,以后可以换成:
Web 审批页
企业微信/钉钉审批
Slack / Teams 消息确认
邮件审批链接
十五、总结
这份代码展示了一个非常实用的人机协同模式:
自然语言 → AI 理解
AI → SQL 工具调用
高危操作 → 人工审批
审批结果 → 恢复执行
最终结果 → Markdown 输出
它不是让 AI 完全替代人,而是让 AI 成为一个有边界、有规则、可控的执行助手。
你可以把这个模式理解为一句话:
让 AI 负责“会不会做”,让人类决定“该不该做”。
这就是人机协同最有价值的地方。
十六、可直接复用的教程结语
如果你正在做 AI Agent、企业自动化、数据库 Copilot 或智能审批系统,这种“AI 自动执行 + 人工审批兜底”的方案非常值得采用。
它比纯人工更高效,比全自动更安全,尤其适合:
企业内部系统
数据敏感场景
有合规要求的业务流程
希望逐步引入 AI 的团队