智能问数 · 项目复盘
关键取舍
为什么不让模型直接写 SQL 去执行?
- 原因:模型写的 SQL 一旦能直接跑,写库、拖库和把引擎拖垮都只隔一次生成;出了错也无法区分是理解错了还是写错了。
- 处理:主链上模型只产出查询意图,服务端编译成 SQL 后再执行;
run_sql登记在工具表里但对模型不可见。回退回路里模型只看到get_schema、sample_data、plot、export、run_python五个闭集工具,单轮最多 10 步。 - 取舍:意图能表达的查询范围比裸 SQL 窄,解析不出时退回工具回路而不是放开 SQL。
为什么查询进子进程、计算留在进程内、Python 才进容器?
- 查询:要挡的是写库和引擎失控,只读连接加独立子进程够用,不需要容器开销。
- 计算:输入已经是接受过的结果,运算限制在加减乘除、比率、增速、求和、平均、排名和 top-N 这个闭集里,不执行模型生成的代码,所以留在进程内。
- Python:要挡的是写宿主机、出网和危险模块,静态检查挡第一层,
--network none、只读根文件系统、非 root 和资源限制挡第二层。没有固定摘要的镜像就返回SANDBOX_UNAVAILABLE,不改到进程内执行。
为什么把问、查、算、整理、回答拆成五段?
- 原因:一次模型调用同时做拆解、查数、计算和措辞,失败时看不出停在哪一段,回答里的数字也指不回来源。
- 处理:每段有自己的状态和编号——
plan_revision、task_id、result_id、fact_id。回答只读整理好的素材,对不上的数字标为未验证;评估台按同样五段回看。 - 取舍:一轮多两次模型调用(拆解轮、回答轮),换来每个数字可追溯。
为什么等待和确认不能交给模型自己结束?
- 问题:口径没定、或导出这类副作用还挂着时,如果模型还能自己继续查、自己点确认,用户的决定就形同虚设。
- 处理:所有需要用户决定的情况停在同一种等待态,依赖该决定的任务执行数为 0。
confirm不在模型可见列表里,只有用户经POST /v1/confirm批准后才执行一次;模型若发出确认调用,按未登记工具处理。
为什么对抗评测不用模型当裁判?
- 原因:裁判模型本身可以被注入影响。
- 处理:攻击是否拦住、合法请求是否误杀,都用规则判定;逃逸率和误杀率写在同一份报告里,只报拦截率会掩盖把合法请求一起拒掉的情况。
遇到的问题与处理
必需任务失败时为什么直接结束本轮?
- 原因:必需结果缺失时继续整理回答,容易把未完成标成成功。
- 处理:必需任务失败就结束本轮并返回错误,不再整理部分回答。
模型选了不存在的工具,或规划失败怎么办?
- 方法不在表里:按
UNKNOWN_TOOL拒绝,不执行;注入用例里的os.system、eval、run_sql_admin都走这条。 - 拆解超时、限流或空回复:返回对应错误码,不伪装成「没有查到数据」;每次模型调用用小轮 60 秒,整轮用 20 分钟墙钟;断连后取消后续处理。
目前的边界
五阶段什么时候才进?
意图能解析、且表结构来自 SQLite 文件时才进入;否则走回退工具回路。PostgreSQL 来源目前只在回退回路里可用。
身份是怎么处理的?
本地和演示用会话登录与 Cookie;护栏只接收调用方已构造好的 Principal,自己不解析令牌。这不等于已接上主产品的鉴权。
导出回执是真的吗?
确认后的导出回执按规格是模拟的,用来把确认契约走通;真实导出目标不在范围内。
数据从哪来?
合成数据,seed 固定可重现;不使用公司客户数据和内部表结构。
经验总结
- 先收窄能力,再谈规划:模型能调的工具、能写的查询形态、能用的 Python 模块都放进服务端可校验的清单里,规划再灵活也出不了这个圈。
- 阶段分开之后,执行隔离才有地方落:查询、计算和模型生成的 Python 各有边界,不互相冒充;每段都有编号,评估台才能按段定位。
- 低信任内容先标记:工具返回、表注释和工具描述可以进上下文,不能直接当成下一轮要执行的指令。
- 两个比例一起看:拦截率和误杀率并排,准确率和失败原因分布并排;只报一个数会把问题藏起来。
- 终态先汇合再展示:完成、部分完成、失败、取消和过期走同一个出口,未完成的任务不标成成功,用户才知道下一步能做什么。