智枢(InsightHub)- ReAct
ReAct
- 前端和后端是进行 webSocket 双端通信,前后端会发送三种消息, 第一种心跳检测 ping,前后端确认通信存在;第二种,用户发送暂停请求,直接停止通信;第三种用户的普通消息,开始向下分发消息。
- 拿到消息之后,第一个需要有两个 Map,因为AI 是一个个的返回数据的,所以需要一个 Map 去存储这个AI返回回来的数据,构建成完整的响应;第二个需要记录这次会话完成的状态:成功完成对话,用户终止对话。并且还要在 redis中创建一个任务,因为responseBuilders是写在 JVM 里面的,所以程序结束这个数据会消失,需要持久化到 Redis 里面。然后创建线程池,异步的执行这个任务,因为前端还可能发过来 ping 消息或者终止消息,所以这个主线程不能用来处理接受这个任务,必须要保持空闲,由线程池里面的数据去异步执行这个任务。
- 先构建初始的消息,然后主循环最多四次循环,四次循环结束之后根据已经查到的信息直接返回结果,模型没有 tool_calls 说明已经给出了结果,不需要再调用了。兜底 finalize :轮次用尽后强制给一次无工具的生成机会,保证用户拿到回答而不是报错。
- 传统的 RAG:用户提问,把用户的问题转化成向量,然后去向量数据库召回相似度最高的 TopK ,拿到匹配的参考文档片段,然后把用户问题和系统提示词一起拼接成 Prompt交给大模型。
但是复杂问题(总结、筛选、多步)答不好。比如说我跟RAG说对比A产品和B产品,传统单独轮次有可能检索回来的全部都是 A 产品的东西,容易答偏掉。使用 ReAct 之后,第一轮检索 A 产品内容,第二轮检索 产品 B 的内容,第三轮综合进行回答。
加入 ReAct 之后
- 第一个,要不要进行检索或者调用工具由大模型说了算,并且在系统提示词中也列举了纯打招呼或寒暄,翻译,写故事这类消息是不用进行知识检索的,这是在提示词中写入白名单。
- 第二:我的 ReAct 注册了 4 个工具,从原来单一的检索功能变成"查、总结、记反馈、看统计"四件事。
// AgentToolRegistry.java L49-54
this.tools = List.of(
searchKnowledgeTool(), // 事实查询
generateSummaryTool(), // 主题摘要(内部二次调LLM)
submitFeedbackTool(), // 反馈记录
knowledgeStatsTool() // 统计查询
);
-
第三 从"检索一次"→"检索可多次且query可改写"。比如说我要查 A 产品的信息和 B 产品对比,查询之后发现不够用,第二轮大模型会自动改写 query 查询,获取更多信息,第三轮综合两轮查询给结果。所以这个 ReAct 的核心就在于通过上一轮的调用结果来判断下一轮该怎么操作。
-
第四个:双重预算兜底:工具调用最多 8次,循环查询最多 4次。
-
数据测试:每一个数据后面都人工打了预期标签,然后在16 检索 + 4 摘要 + 2 统计 + 2 反馈 + 6 白名单 = 30 题。
const QUESTIONS = [
{ id : 1 , q : '公司的退货流程是什么?' , expected : [ 'search_knowledge' ] },
{ id : 2 , q : '派聪明的架构是怎样的?' , expected : [ 'search_knowledge' ] },
{ id : 3 , q : '我们有哪些产品?' , expected : [ 'search_knowledge' ] },
{ id : 4 , q : '报销需要准备什么材料?' , expected : [ 'search_knowledge' ] },
{ id : 5 , q : '系统支持哪些登录方式?' , expected : [ 'search_knowledge' ] },
{ id : 6 , q : '产品的价格区间是多少?' , expected : [ 'search_knowledge' ] },
{ id : 7 , q : '合同模板里有哪些条款?' , expected : [ 'search_knowledge' ] },
{ id : 8 , q : '怎么联系技术支持?' , expected : [ 'search_knowledge' ] },
{ id : 9 , q : '帮我总结一下知识库里关于产品的资料' , expected : [ 'generate_summary' ] },
{ id : 10 , q : '归纳一下我们SOP文档的核心流程' , expected : [ 'generate_summary' ] },
{ id : 11 , q : '知识库里现在有多少文档?' , expected : [ 'knowledge_stats' ] },
{ id : 12 , q : '这个回答不对,记个差评,原因是不准确' , expected : [ 'submit_feedback' ] },
{ id : 13 , q : '你好,在吗?' , expected : [] },
{ id : 14 , q : '把"知识就是力量"翻译成英文' , expected : [] },
{ id : 15 , q : '写一首关于春天的诗' , expected : [] }
];
- 现在的四个工具
- 检索:把原来 RAG 检索的能力封装成一个工具
- 主题总结:比如“帮我总结一下知识库里关于产品的资料”,调用generate_summary(topic="产品资料", maxDocs=5),内部会先使用检索功能查到产品资料,内部再去调用 LLM 生成摘要。
- knowledge_stats 元信息查询,统计工具:比如说用户询问有多少文档?这个信息就没有办法单纯通过 RAG 进行检索,需要去系统内拿到元数据,去 ES 和 Mysql中查询。
- submit_feedback — 非检索意图:用户提出反馈,比如说这个检索结果我不满意,结果不够精确,这个文档搜索的内容太少了等等这类反馈的描述,是属于非检索意图,我们就不需要调用检错功能。这个反馈会被收集起来,拼接进系统的 prompt 中,包含用户提问的信息以反馈,比如不准确。

浙公网安备 33010602011771号