编程导航教程话题讨论

教程

906 参与
分享

快来分享你的内容吧~

点击登录,快来和大家讨论吧~
表情
图片
话题
打卡
综合
交流
文章
问答

从0-1申请发明专利

我在2026年1月底提交了发明专利申请,6月初顺利拿到了证书。这篇文章记录我这次个人申请的全过程,经历仅供大家参考。 2025年底,我以负责人的身份完成了一个系统的开发,当时就有提议我去申请专利。虽然读大学时我曾作为第二、第三发明人参与过专利,但具体申请工作主要是别人完成的,所以这次算是我第一次亲自操办。 很多高校对学生产出专利都有奖励或资助政策,有相关资源和经费的同学可以了解一下自己学校的规定,说不定能减轻不少负担。我这次是委托代理机构协助申请的,下面就来详细说说整个流程。 ## 一、专利都有哪些 1. **发明专利**:保护技术方案、方法等较为抽象的内容,含金量最高,审查也最严格(会判断是否真的具有新颖性和创造性)。 2. **实用新型专利**:保护形状、构造等物理上比较具体的东西,含金量通常不如发明专利,审查也相对宽松一些。 3. **外观设计专利**:主要保护产品外观的形状、图案、色彩等,具体可参考《专利法》或向AI咨询,我了解不算多。 ## 二、我负责的项目为什么可以申请发明专利 我做的项目是一个类排班系统。需求比较独特且复杂,需要考虑的因素很多,整个系统的数据库设计、架构设计以及排班算法,都是围绕这个需求展开的。难不难不太好说,但就我所知,市面上还没有现成的同类解决方案。因此,同事提出能不能申请专利时,我评估后觉得可行,于是正式开始了申请。 ## 三、除了技术方案还需要什么 还需要找代理机构,并准备相应的费用。 当然,你也可以自己撰写全部专利材料,但是很繁琐。所以我的想法是,只要有人出资,委托代理机构最省心。如果你是大学生,可以争取让学校出钱;如果是单位的项目,也可以申请由单位报销。一个发明专利的申请官费加上代理费,总计大约在4000到6000元,还是有点小贵的。 ## 四、怎么找代理机构 说实话,我没有特意去筛选。大学时我上过一门专利申请相关的选修课,授课老师刚好是专利代理机构的人,我就直接联系了那位老师。后面就是签合同、付款,很顺畅。 ![image-20260720142758323.png](https://pic.code-nav.cn/post_picture/1759850888622628866/YY19E6DT4vKOqxIJ.png) ## 五、正式开始申请 当时我希望能尽快下证,所以走了加急(多花了几百块)。不加急的话,周期通常以年为单位;走加急后,就以月为单位了。 首先要弄清专利的**申请人**和**发明人**的区别:申请人是最终拥有专利权的主体,也就是权利方;发明人只是表明这个成果是谁做出来的。另外,发明人的排序一般按贡献大小,贡献越大名字越靠前。如果专利是在学校或单位完成的,经费也由学校或单位提供,那么申请人通常是学校或单位,但不绝对。 接下来要写一份技术交底书。这个其实不复杂,就是**把你的技术方案用你最熟悉的方法描述清楚**,让代理机构的撰写人员能看懂。之后的材料全交给代理机构就好,不用再操心。 ![image-20260720142916409.png](https://pic.code-nav.cn/post_picture/1759850888622628866/48rcca6EbhFo3D5X.png) 等代理机构把申请文件写完后,会发给你审核,确认没问题后,他们就会正式提交。提交后一般几天内会收到受理通知书。专利局可能会要求补充其他材料。我当时就被要求提供技术佐证,于是提交了数据库建表代码、一部分核心后端代码以及系统截图。 ![image-20260720143015879.png](https://pic.code-nav.cn/post_picture/1759850888622628866/rErifbiGXDsoC4oB.png) 最后就是等待。从1月底提交到6月初下证,大约等了4个月。这个专利,也成为我作为第一发明人的第一个专利。 ![image-20260720143157007.png](https://pic.code-nav.cn/post_picture/1759850888622628866/V01CHSnTMW4v4oVP.webp) 希望我的经历能给准备申请专利的朋友一点参考。

彻底搞懂 Spring AI Tool Calling:从底层协议到源码执行全流程

# 什么是工具调用? 一句话:**模型不会真的去调你的 Java 方法**。它只会「说」:我要用哪个工具、参数是什么;真正执行工具、把结果塞回对话的,是你的应用(Spring AI / Agent harness)。 官方也强调这一点:tool calling 看起来像模型能力,本质是**客户端协议**——模型只负责发起请求,应用负责执行并回传结果。模型永远拿不到你工具背后的真实 API,这也是安全边界。 ## 一次完整调用长什么样 ```mermaid sequenceDiagram participant U as 用户 participant App as 应用 / Spring AI participant LLM as 大模型 U->>App: 提问(例如:明天星期几?) App->>LLM: Prompt + ToolDefinition 列表(工具名/描述/JSON Schema) LLM-->>App: AssistantMessage(含 ToolCall:name + arguments) Note over App: 模型此时只是「请求调用」,还没执行 App->>App: ToolCallingManager 按 name 找到 ToolCallback 并执行 App->>LLM: ToolResponseMessage(工具执行结果) LLM-->>App: 最终自然语言回答 App-->>U: 返回结果 ``` 可以把它想成「带协议的函数调用」: | 角色 | 做什么 | 不做什么 | | --- | ----------------------------------------------- | ---------------------- | | 模型 | 根据 schema 生成 `name` + `arguments`(通常是 JSON 字符串) | 不直接访问数据库 / HTTP / 文件系统 | | 应用 | 校验、执行、把结果写回对话 | 不替模型「发明」业务决策(除非你自己写逻辑) | ## Tool Call 本质是文本 模型侧并没有魔法 RPC。服务端把 transcript、system prompt、可用工具列表揉进带特殊标记的大 prompt;模型在训练过的格式上采样,吐出一段可被解析成「调用某某工具」的文本。 一般来说会把工具接收到的是类似下面的信息: ```json "tool_calls": [ { "index": null, "id": "call_019f4b577f9479c0826f7f8b", "type": "function", "function": { "name": "queryCustomer", "arguments": "{\"userId\":\"1001\"}" } } ] ``` Spring AI 框架会进行解析&执行,把模型吐出的 tool call 解析成 `AssistantMessage.ToolCall`,再交给 `ToolCallingManager` 执行最后返回给 LLM。 # 如何搭配 Spring 实现工具调用 SpringAI 版本 1.1.2、SpringBoot 版本 3.5.4。 源码仓库:[https://github.com/lieeew/SpringAIToolCall](https://github.com/lieeew/SpringAIToolCall/) ## 最小可跑示例 ```java package com.leikooo.springaitoolcall; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @SpringBootApplication public class SpringAiToolCallApplication { private static final Logger log = LoggerFactory.getLogger(SpringAiToolCallApplication.class); public static void main(String[] args) { SpringApplication.run(SpringAiToolCallApplication.class, args); } @Bean @ConditionalOnProperty(name = "tool-call.debug.enabled", havingValue = "true") CommandLineRunner toolCallDebugRunner(ChatModel chatModel) { return args -> { String response = ChatClient.create(chatModel) .prompt(""" You are debugging Spring AI tool calling. Complete the task only by using the provided tools. Task: 1. Call queryCustomer with userId 1001. 2. Call createTicket for userId 1001 and issue "Mouse cannot connect". 3. Reply in Chinese with the customer name, customer level, and ticket id. Do not invent tool results. """) .tools(new DebugTools()) .call() .content(); log.info("Tool calling final response: {}", response); System.out.println("==== Spring AI Tool Calling Result ===="); System.out.println(response); }; } public static class DebugTools { private static final Logger log = LoggerFactory.getLogger(DebugTools.class); // Put breakpoints in these methods to inspect the generated tool arguments. @Tool(description = "Query customer profile by user id") public String queryCustomer(@ToolParam(description = "Customer user id, for example 1001") String userId) { log.info("Tool invoked: queryCustomer(userId={})", userId); if ("1001".equals(userId)) { return "userId=1001, name=Alice, level=VIP, region=Shanghai"; } return "No customer found for userId=" + userId; } @Tool(description = "Create a customer support ticket") public String createTicket( @ToolParam(description = "Customer user id") String userId, @ToolParam(description = "Issue summary") String issue) { log.info("Tool invoked: createTicket(userId={}, issue={})", userId, issue); return "ticketId=TICKET-" + userId + "-001, userId=" + userId + ", status=CREATED, issue=" + issue; } } } ``` ## 模型工具调用「返回」了什么? 我们通过 debug `org.springframework.ai.openai.OpenAiChatModel#internalCall` 中的 response 可以看到: ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/ZMk9iOWQjHoJwdRm.webp) 具体解析的类型是: ```java // org.springframework.ai.chat.messages.AssistantMessage.ToolCall public record ToolCall( String id, // 本次 tool call id,回传结果时要对上 String type, // 一般是 "function" String name, // 工具名,对应 ToolDefinition.name / @Tool name String arguments // ★ 重点:模型生成的参数,通常是 JSON 字符串 ) {} ``` 简化版本 toString 之后的内容,可以看到没有什么黑魔法,就是单纯的 String 所以很有可能会出现错误(反序列化的错误、多参数、少参数等等),所以需要在工程上做兜底,比如请求 LLM 的时候如果了网络问题会进行重试。 ```json { "index": null, "id": "call_019f4b577f9479c0826f7f8b", "type": "function", "function": { "name": "queryCustomer", "arguments": "{\"userId\":\"1001\"}" } } ``` ## 工具调用如何执行的 我们可以看到在 `org.springframework.ai.openai.OpenAiChatModel#internalCall` 里面有判断是否包含工具调用,包含工具调用直接通过 this.toolCallingManager.executeToolCalls 直接执行工具调用。框架封装的比较好,导致咱们不能进行一些自己的扩展,比如:异常出现进行重试、system-reminder 强提醒更新 todoList 等(我们是用覆盖源码的操作实现一些自定义逻辑)... ```java if (this.toolExecutionEligibilityPredicate.isToolExecutionRequired(prompt.getOptions(), response)) { var toolExecutionResult = this.toolCallingManager.executeToolCalls(prompt, response); if (toolExecutionResult.returnDirect()) { // Return tool execution result directly to the client. return ChatResponse.builder() .from(response) .generations(ToolExecutionResult.buildGenerations(toolExecutionResult)) .build(); } else { // Send the tool execution result back to the model. return this.internalCall(new Prompt(toolExecutionResult.conversationHistory(), prompt.getOptions()), response); } } ``` 后面执行的核心代码: ```java @Override public String call(String toolInput, @Nullable ToolContext toolContext) { Assert.hasText(toolInput, "toolInput cannot be null or empty"); logger.debug("Starting execution of tool: {}", this.toolDefinition.name()); this.validateToolContextSupport(toolContext); // {"userId":"1001","issue":"Mouse cannot connect"} Map<String, Object> toolArguments = this.extractToolArguments(toolInput); // "1001"、"Mouse cannot connect" Object[] methodArguments = this.buildMethodArguments(toolArguments, toolContext); // 真正是用反射执行工具调用 Object result = this.callMethod(methodArguments); logger.debug("Successful execution of tool: {}", this.toolDefinition.name()); // 判断返回类型 Type returnType = this.toolMethod.getGenericReturnType(); // 根据类型进行 cover return this.toolCallResultConverter.convert(result, returnType); } ``` 最终通过反射调用,以下是核心代码: ```java @SuppressWarnings("null") @Nullable private Object callMethod(Object[] methodArguments) { if (isObjectNotPublic() || isMethodNotPublic()) { this.toolMethod.setAccessible(true); } Object result; try { result = this.toolMethod.invoke(this.toolObject, methodArguments); } catch (IllegalAccessException ex) { throw new IllegalStateException("Could not access method: " + ex.getMessage(), ex); } catch (InvocationTargetException ex) { throw new ToolExecutionException(this.toolDefinition, ex.getCause()); } return result; } ``` ## 发给模型的 schema 从哪来? 这里就是 LLM 怎么知道有哪工具可以进行调用,其实是发送给 LLM 一个工具调用的列表,告诉了 AI 有哪些工具。在 SpringAI 中可以是用 @Tool 注解很方便的标识工具。 核心解析代码在:`org.springframework.ai.tool.method.MethodToolCallbackProvider#getToolCallbacks` 里面是用反射拿到 Tool 的参数信息: ```java @Override public ToolCallback[] getToolCallbacks() { // 反射获取方法参数 var toolCallbacks = this.toolObjects.stream() .map(toolObject -> Stream .of(ReflectionUtils.getDeclaredMethods( AopUtils.isAopProxy(toolObject) ? AopUtils.getTargetClass(toolObject) : toolObject.getClass())) .filter(this::isToolAnnotatedMethod) .filter(toolMethod -> !isFunctionalType(toolMethod)) .filter(ReflectionUtils.USER_DECLARED_METHODS::matches) .map(toolMethod -> MethodToolCallback.builder() .toolDefinition(ToolDefinitions.from(toolMethod)) .toolMetadata(ToolMetadata.from(toolMethod)) .toolMethod(toolMethod) .toolObject(toolObject) .toolCallResultConverter(ToolUtils.getToolCallResultConverter(toolMethod)) .build()) .toArray(ToolCallback[]::new)) .flatMap(Stream::of) .toArray(ToolCallback[]::new); validateToolCallbacks(toolCallbacks); return toolCallbacks; } ``` 我们 debug 可以看到整个 toolCallbacks 是下面的样子: ``` DefaultToolDefinition[name=queryCustomer, description=Query customer profile by user id, inputSchema={ "$schema" : "https://json-schema.org/draft/2020-12/schema", "type" : "object", "properties" : { "userId" : { "type" : "string", "description" : "Customer user id, for example 1001" } }, "required" : [ "userId" ], "additionalProperties" : false }] ``` 最终在请求的时候会携带上 `org.springframework.ai.openai.api.OpenAiApi#chatCompletionEntity`,我们可以看到 chatRequest 里面包含详细的工具调用信息: ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/3KT3pzphl4bQUb7W.webp) # 最近 Claude 新模型的幺蛾子~ ## Pi 工具调用现象 较新的 Claude(文中提到 Opus 4.8、Sonnet 5)在某些 **嵌套 tool schema**(例如 Pi 的 `edits[]`)上,会在对象末尾**凭空加字段**: ```json { "oldText": "...", "newText": "...", "requireUnique": true } ``` 或 `oldText2` / `type` / `in_file` / `event.0.additionalProperties` 等一堆随机 key。 更气人的是:`oldText` / `newText` 内容经常是对的,只是尾巴多了废话 → schema 校验失败 → harness 拒掉 → 要求重试。 特点: - 单轮「编辑这个文件」很难复现;**长 agent 历史**里更容易炸。 - 去掉 thinking block,失败率可能下降;开 **strict tool invocation** 后作者侧问题消失。 - 老模型反而更稳——「更好的模型,更差的工具适配」。 ## 为什么会变差? ```mermaid flowchart TB A[Post-training 贴近 Claude Code 等 dominant harness] --> B[模型学到「成功 tool call」的先验形状] B --> C[扁平 edit:file_path / old_string / new_string / replace_all] C --> D[你的 schema 若是嵌套 edits 数组 → 偏离训练分布] D --> E[高熵位置乱采样可选字段名] E --> F[多余 key / 别名 / sloppy JSON] G[Claude Code 客户端很宽容:别名、滤未知 key、重试] --> A G --> H[RL 对「略畸形但仍成功」几乎不惩罚] ``` 同时:嵌套数组参数往往是「tag 里再塞一大段转义 JSON」,模型在关掉超长 `newText` 字符串后,要在 `}` 和 `, "..."` 之间做决定——正好是最容易胡写 key 的点。 Anthropic 的 `strict` mode 推测会在服务端按 schema 约束采样(禁止非法 key),所以能压住这类问题;但 tool definition 有复杂度限制,Claude Code 自己也未必开 strict。 ## 对 Spring / 自建 Harness 的警示 1. **别假设 schema 中立**:同样语义、不同形状,在新 Claude 上成功率可能差一截。能贴近主流 harness 形状(扁平参数)时,优先扁平。 2. **应用侧要有容错策略**:未知字段过滤、参数别名、校验失败把错误清晰喂回模型(Spring 的 `ToolExecutionExceptionProcessor` 可定制)。 3. **关键路径可开 provider 的 strict / structured output**(若 API 支持且 schema 不太复杂)。 4. **debug 时先看 `AssistantMessage.ToolCall.arguments` 原文**,不要只看业务方法入参——多余字段往往在反序列化前就被丢掉或直接炸在框架层。

Agent 不是多角色聊天,而是让大模型在边界内完成任务

Agent 这个词现在被用得很乱。有人把它理解成“会自己思考的 AI”,有人把它理解成“多个角色互相讨论”,也有人认为只要给大模型接几个工具,就已经是在做 Agent。 但从工程角度看,Agent 最重要的不是“看起来多自主”,而是: **它能不能在明确边界内,稳定完成一个多步骤任务。** 这才更接近真实 AI 应用开发。 ![image.png](https://pic.code-nav.cn/post_picture/1813254542264233985/YU8GcCXZlpGalo74.webp) ## 一、普通大模型调用解决的是“回答”,Agent 解决的是“任务” 普通 LLM 调用一般是这样的: 用户输入一个问题,模型返回一段文本。 比如用户问: > 帮我写一段求职信。 模型直接生成一段求职信。 这个过程没有问题,但它本质上还是一次文本生成。模型并不知道用户的真实简历细节有没有支撑这段求职信,也不知道目标 JD 的关键要求是什么,更不知道哪些内容不能夸大。 RAG 往前走了一步:它会先检索知识库、文档或数据库,再让模型基于材料回答。它主要解决的是“回答有没有依据”。 但 Agent 要解决的不是单次回答,而是任务推进。它不只是“查资料再回答”,而是要根据任务目标,在多个步骤之间做选择: - 它可能需要先判断用户意图,再决定要不要查询订单; - 它可能需要先检索售后政策,再判断是否能退款; - 它可能需要生成一个草稿,但不能直接提交; - 它可能需要发现证据不足,然后暂停,要求用户补充信息。 也就是说,Agent 面向的不是单次回答,而是一个可执行的任务过程。 所以我更愿意把 Agent 看成一个系统问题: **Agent 不是把 prompt 写得更像人,而是把模型放进一个可以行动、可以观察、可以被约束的系统里。** ## 二、Agent 和 Workflow 的区别 我不太建议一上来就从“自主规划”理解 Agent。 Anthropic 在《Building effective agents》里把 agentic systems 分成 workflow 和 agent。Workflow 是 LLM 和工具按照预设代码路径被编排;Agent 则是 LLM 可以动态决定自己的流程和工具使用方式。它们都属于 agentic system,但工程含义不同。 这个区分很重要。 如果你的任务路径本来就很清楚,比如: 1. 解析 JD 2. 解析简历 3. 匹配能力项 4. 找出缺口 5. 生成定制简历 6. 做证据检查 7. 输出风险提示 那它更适合先做成 workflow,而不是一上来就交给 Agent 自己规划。 Workflow 的好处是可控、可测、可复盘。 Agent 的价值在于处理那些路径不固定、步骤数量不确定、需要根据中间结果不断调整的任务。 比如客服场景里,用户可能问的是物流、退款、发票、商品参数、投诉、优惠券、售后政策,也可能把多个问题混在一起。系统很难提前写死所有路径,这时 Agent 才有更明确的价值。 换成代码视角,区别更明显: **Workflow 的下一步主要由开发者写死。 Agent 的下一步主要由模型根据当前状态决定。** 这不是说 Agent 没有代码控制,而是说代码负责提供工具、状态和边界,模型负责在这些边界里选择下一步。 但这不代表 Agent 可以无限自由。恰恰相反,Agent 越能行动,越需要边界。 ## 三、用代码理解 Agent 从代码角度看,Agent 不是一个神秘概念。 它可以先理解成: **Agent = 一个由 LLM 驱动下一步决策的任务循环。** 这里的“循环”不是说所有框架源码都必须写成 while,而是说 Agent 的运行语义大致相同:模型决定下一步,应用执行工具,工具结果写回状态,模型再基于新状态继续判断。 ```java while (!state.isFinished()) { AgentDecision decision = llm.decideNextStep(state, availableTools); if (decision.isFinalAnswer()) { return decision.answer(); } if (decision.isToolCall()) { policyGate.check(user, decision.toolName(), decision.arguments()); ToolResult result = toolExecutor.execute( decision.toolName(), decision.arguments() ); state.addToolResult(result); traceLog.record(decision, result); } if (decision.needHumanApproval()) { return pauseForHumanReview(state); } } ``` 这不是某个 Agent 框架的完整源码,而是 Agent 的核心运行语义。 普通 LLM 是: ```java String answer = llm.chat(userQuestion); return answer; ``` RAG 是: ```java List<Document> docs = retriever.search(userQuestion); String answer = llm.chat(userQuestion, docs); return answer; ``` Workflow 是: ```java JdInfo jd = parseJd(input); ResumeInfo resume = parseResume(input); MatchResult match = matchResumeToJd(jd, resume); RewriteResult rewrite = rewriteResume(match); RiskReport risk = checkEvidence(rewrite); return result; ``` Agent 是: ```java AgentState state = new AgentState(userGoal); while (state.canContinue()) { AgentDecision decision = model.decide(state, tools); switch (decision.type()) { case CALL_TOOL -> { ToolResult result = executeTool(decision); state.observe(result); } case ASK_USER -> { return askUserForMoreInfo(decision.question()); } case NEED_APPROVAL -> { return waitForHumanApproval(decision.action()); } case FINAL -> { return decision.finalAnswer(); } } } ``` 区别就在这里: **Workflow 的下一步是代码写死的。 Agent 的下一步是模型根据当前状态决定的。** 这也对应了 Anthropic 对 workflow 和 agent 的区分:前者按预设路径执行,后者由模型动态决定流程和工具使用。 --- ### 代码上,一个 Agent 至少有 5 个对象 不要先想 LangGraph、CrewAI、AutoGen。先想这 5 个类。 #### (1)AgentState:任务状态 ```java public class AgentState { private String goal; private int step; private List<Message> messages; private List<ToolCallRecord> toolCalls; private Map<String, Object> facts; private boolean finished; private boolean needHumanApproval; } ``` 它回答一个问题: **任务现在进行到哪一步了?** 没有 `AgentState`,就不是连续任务,只是一次问答。 --- #### (2)AgentTool:工具 ```java public interface AgentTool { String name(); String description(); ToolResult execute(Map<String, Object> arguments); } ``` 比如电商客服 Agent 里可以有: ```java public class GetOrderTool implements AgentTool { public String name() { return "get_order"; } public String description() { return "根据 orderId 查询当前用户的订单状态"; } public ToolResult execute(Map<String, Object> args) { String orderId = (String) args.get("orderId"); // 查数据库 / 调接口 return orderService.getOrder(orderId); } } ``` Spring AI 的 Tool Calling 也是类似思想:模型提出工具调用请求,应用程序负责解析、执行工具、再把结果返回给模型。模型不是直接操作你的数据库。 --- #### (3)AgentDecision:模型决定下一步 ```java public sealed interface AgentDecision permits CallTool, FinalAnswer, NeedHumanApproval { } public record CallTool( String toolName, Map<String, Object> arguments ) implements AgentDecision { } public record FinalAnswer( String answer ) implements AgentDecision { } public record NeedHumanApproval( String action, String reason ) implements AgentDecision { } ``` 这里就是 Agent 和普通程序最大的区别。 普通程序是你写: ``` 先查订单,再查政策,再生成回复。 ``` Agent 是模型返回: ``` { "type": "CALL_TOOL", "toolName": "get_order", "arguments": { "orderId": "123456" } } ``` 然后你的后端决定: - 这个工具存不存在? - 这个用户有没有权限? - 这个 orderId 是不是他的? - 这个动作需不需要人工确认? --- #### (4)PolicyGate:权限边界 ```java public class PolicyGate { public void check(User user, String toolName, Map<String, Object> args) { if (toolName.equals("submit_refund")) { throw new NeedHumanApprovalException("退款提交必须人工确认"); } if (toolName.equals("get_order")) { String orderId = (String) args.get("orderId"); if (!orderService.belongsToUser(orderId, user.id())) { throw new AccessDeniedException("不能查询他人订单"); } } } } ``` 边界不是 prompt 里写一句“不要越权”,而是代码里真的拦住。 OWASP 的 Excessive Agency 风险,本质就是 LLM 系统被授予过多功能、权限或自主性后,可能造成破坏性动作;所以工具权限、人工确认、最小授权必须在系统层实现。 --- #### (5)AgentRunner:核心循环 ```java public class AgentRunner { private final LlmClient llm; private final ToolRegistry toolRegistry; private final ToolExecutor toolExecutor; private final PolicyGate policyGate; private final TraceLog traceLog; public AgentResult run(User user, String goal) { AgentState state = new AgentState(goal); while (!state.isFinished() && state.getStep() < 10) { AgentDecision decision = llm.decideNextStep(state, toolRegistry.availableTools()); if (decision instanceof FinalAnswer finalAnswer) { state.finish(); return AgentResult.success(finalAnswer.answer()); } if (decision instanceof NeedHumanApproval approval) { return AgentResult.waitingForApproval(approval.action(), approval.reason()); } if (decision instanceof CallTool callTool) { policyGate.check(user, callTool.toolName(), callTool.arguments()); ToolResult result = toolExecutor.execute( callTool.toolName(), callTool.arguments() ); state.addToolCall(callTool, result); traceLog.record(state, callTool, result); state.nextStep(); } } return AgentResult.failed("Agent stopped: max steps reached."); } } ``` OpenAI Agents SDK 里所谓 agent loop,本质也是:处理工具调用,把结果送回 LLM,然后继续运行直到任务完成;同时配套 guardrails、sessions、tracing 等工程能力。 --- ### 用电商客服理解一次完整执行 用户问: > 我的订单签收三天了,商品破损,可以退吗? Agent 第一次判断: ```json { "type": "CALL_TOOL", "toolName": "get_order", "arguments": { "orderId": "A1001" } } ``` 后端执行: ```java policyGate.check(user, "get_order", args); ToolResult order = getOrderTool.execute(args); state.addToolResult(order); ``` 工具返回: ```json { "orderId": "A1001", "status": "SIGNED", "signedDaysAgo": 3, "productCategory": "electronics" } ``` Agent 第二次判断: ```json { "type": "CALL_TOOL", "toolName": "get_refund_policy", "arguments": { "category": "electronics" } } ``` 工具返回: ```json { "category": "electronics", "returnWindowDays": 7, "needDamagePhoto": true, "autoRefundAllowed": false } ``` Agent 第三次判断: ```json { "type": "FINAL", "answer": "你的订单签收 3 天,仍在 7 天售后窗口内。但商品破损需要上传图片凭证,我可以先帮你生成退款申请说明,提交退款前需要你确认。" } ``` 这就是一个最小 Agent 的运行过程。 它不是一次性回答,而是: ```text 看当前状态 → 决定查订单 → 得到订单结果 → 决定查政策 → 得到政策结果 → 判断不能直接退款 → 给出受边界约束的答案 ``` 所以,从代码视角看,Agent 不是让模型直接控制系统,而是让模型提出下一步动作,再由应用程序判断、执行、记录和约束。 ## 四、Agent 的核心不是“自主”,而是工具、状态和边界 一个更工程化的 Agent 定义可以是: **Agent = LLM + Tools + State + Control Loop + Guardrails** 拆开看: - LLM 负责理解任务和选择下一步。 - Tools 负责连接数据库、订单系统、知识库、搜索服务等外部能力。 - State 负责记录任务进展、工具调用历史和中间结果。 - Control Loop 负责把模型决策、工具执行和结果反馈串起来。 - Guardrails 负责限制模型不能越权、不能乱调用工具、不能直接执行高风险动作。 这里最容易被忽略的是工具调用的安全边界。 Spring AI 官方文档对 tool calling 的说明很清楚:虽然通常说 tool calling 是模型能力,但实际执行工具调用逻辑的是客户端应用。模型只能请求工具调用并提供参数,真正执行工具、返回结果的是应用程序本身;模型并不会直接获得工具背后的 API 权限。 这句话非常关键。 因为它说明 Agent 不是让模型直接控制系统,而是让模型提出行动意图,再由应用层判断是否执行。 比如电商客服 Agent 面对“我的订单能退吗?”这个问题时,它不应该直接回答“可以退”。 更合理的方式是:先查询订单,再查询售后政策,再结合订单状态、商品类目和平台规则生成回复。如果涉及退款提交,就只能生成草稿,不能直接执行。 这才是可上线的 Agent。 ## 五、Agent 的真正风险:从“回答错误”变成“行动越界” 普通大模型回答错,风险主要在内容层。 Agent 一旦接入工具,风险就进入系统层。 它可能查错数据,调用错工具,传错参数,泄露敏感信息,执行不该执行的操作,或者在错误前提下连续行动。 OWASP LLM Top 10 里专门列出了 Prompt Injection、Insecure Plugin Design、Excessive Agency 等风险。其中 Excessive Agency 指的是给 LLM 过多、未受约束的行动自主权,可能破坏可靠性、隐私和信任。 这也是为什么我不赞成一开始就做“全自动 Agent”。Agent 安全不能只靠 prompt,而必须靠工具权限、参数校验、人工确认和审计日志这些系统层设计。 真正的工程顺序应该是: - 先让模型会读。 - 再让模型会查。 - 再让模型会生成草稿。 - 再让模型在低风险场景自动执行。 - 最后才考虑高风险动作的半自动化或自动化。 对于工具权限,我更倾向于分四层: **READ:只读查询,可以自动执行。** 例如查询订单状态、查询物流、检索政策文档。 **DRAFT:只生成草稿,不真正提交。** 例如生成退款说明、工单回复、邮件草稿。 **WRITE_REVIEW:会改变系统状态,必须人工确认。** 例如提交退款申请、修改用户资料、发送正式邮件。 **DANGEROUS:默认禁止。** 例如删除数据、批量修改权限、执行任意命令。 如果一个 Agent 系统没有这个权限分层,那它本质上还不能算生产级 Agent,只是一个接了工具的聊天机器人。 ## 六、一个更接近真实项目的 Agent 示例 假设我们要做一个跨境电商客服 Agent。 用户问: > 我这个订单已经签收三天了,商品有破损,能不能退? 一个不可靠的 AI 可能会直接回答: > 一般情况下,签收七天内可以退货。 这句话听起来合理,但它不一定正确。 因为真实判断至少需要几个条件: - 订单是否真实存在? - 订单是不是当前用户的? - 商品类目是什么? - 是否支持无理由退货? - 破损是否需要上传凭证? - 当前是否超过售后时间? - 平台政策和商家政策是否冲突? - 是否需要人工客服介入? 所以更合理的 Agent 流程应该是: ```text 用户问题 → 意图识别:售后 / 退款 / 商品破损 → 查询订单状态 → 检索售后政策(RAG 在这里是证据工具) → 检查商品类目 → 判断是否需要图片凭证 → 生成客服回复 → 标注证据来源 → 如果涉及退款提交,进入人工确认 → 记录整次 Agent Run ``` 在这个流程里,模型不是凭常识回答,而是在工具和证据的约束下完成任务。 这就是 Agent 相比普通聊天机器人的真正区别:它不是凭常识直接回答,而是在工具、证据和权限边界内推进任务。 ## 七、为什么不要一开始做多 Agent 很多 Agent 教程喜欢从多 Agent 开始: 一个产品经理 Agent,一个架构师 Agent,一个开发者 Agent,一个测试 Agent,大家互相讨论,最后输出结果。 这种演示很容易吸引眼球,但工程价值未必高。 多数真实业务问题,不是靠“多几个角色说话”解决的,而是靠更清楚的任务边界、更可靠的工具、更稳定的状态记录和更严格的输出校验解决的。 多 Agent 只有在这些场景下才更有必要: - 不同角色确实需要不同职责; - 不同 Agent 拥有不同工具权限; - 需要一个 Agent 审查另一个 Agent 的输出; - 任务路径复杂到单一 workflow 难以维护; - 系统需要长期运行和异步协作。 否则,多 Agent 很可能只是增加延迟、成本和调试难度。 所以第一篇不应该从多 Agent 开始,而应该先讲清楚单个 Agent 如何完成任务、如何调用工具、如何记录状态、如何控制边界。 ## 八、我对 Agent 的第一性原则 如果让我用一句话定义 Agent,我不会说它是“自主智能体”。 我更愿意说: **Agent 是一个让大模型在工具、状态和权限边界内完成任务的工程系统。** 这个定义不够炫,但更适合真实开发。 因为 Agent 的难点从来不只是“让模型更聪明”,而是: - 它能调用什么工具; - 它不能调用什么工具; - 它每一步是否有依据; - 它的工具调用是否可追踪; - 它在证据不足时能不能停下来; - 它在高风险动作前能不能交给人; - 它失败后能不能复盘。 所以 Agent 专题不应该从框架开始,不应该从多 Agent 开始,也不应该从“让 AI 自己干活”开始。 它应该先回答一个更基础的问题: **当我们说要做 Agent 时,我们到底是在做一个聊天机器人,还是在做一个可控的任务执行系统?** - 如果只是聊天,普通 LLM 就够了。 - 如果只是查资料,RAG 就够了。 - 如果路径固定,Workflow 就够了。 - 如果任务路径不确定,需要工具、状态、反馈和权限边界,才真正进入 Agent。 下一篇,我会解释 Agent 核心术语:ReAct、Tool Calling、State、Memory、Workflow 到底是什么? ## 参考资料 - Anthropic:Building effective agents - OpenAI Agents SDK:Agent loop、Tools、Sessions、Tracing、Guardrails - Spring AI Reference:Tool Calling - OWASP LLM Top 10:Excessive Agency - ReAct:Synergizing Reasoning and Acting in Language Models - Toolformer:Language Models Can Teach Themselves to Use Tools 我是 Ryan,一个专注于可信 AI 应用工程的开发者,技术博客:[yanxai.com](https://yanxai.com),研究如何让 AI 生成从“看起来对”走向“有证据、可追溯、可验证”。

02 Naive RAG 存在的致命问题与解决方案 —— Building-RAG-Systems 项目系列第二篇(知识点较多)

# 关于本项目 ## 项目名称:🚀 Building-RAG-Systems: From Theory to Production > 本项目致力于提供一条平滑且深入的 RAG(检索增强生成)学习与实践路径。通过**深度文章解析**、**配套 Demo代码** 以及**系统级项目实战**,带你从零构建工业可用的大模型应用。 > 代码仓库链接:[Github](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main) ## 📂 仓库结构 (Repository Structure) 本项目按照“理论 -> 配套demo -> 系统级实践”的逻辑组织,主要包含以下三个核心模块: ```text 📦 Building-RAG-Systems ┣ 📂 articles # 📖 核心知识库:RAG 理论解析、架构设计及痛点解决方案 ┣ 📂 articles_demo # 💻 Demo代码:与文章配套的开箱即用 Demo 代码 ┗ 📂 project # 🏗️ 系统级项目:融合所有知识点的全功能系统架构 ``` ### 1️⃣ `articles`:深入浅出的理论与思考 这里不只是空洞的理论,更是实打实的架构设计经验与问题解决思路。 + 探索 RAG 的核心组件与工作流。 + 深入剖析在 Chunking、Embedding、Retrieval 和 Generation 环节遇到的常见痛点(如语意鸿沟、上下文割裂、检索不精准等)及其解决方案。 ### 2️⃣ `articles_demo`:配套的 Demo 代码 Show me the code! 每篇核心文章都配备了独立的、可运行的 Demo。代码保持极简,屏蔽无关框架干扰,方便你快速运行和理解。 ### 3️⃣ `project`:从 Demo 到生产级系统 这是本仓库的终极目标。我们将前两个模块中沉淀的知识与技巧,融合并构建成一个完整的、具备 Agent 协同和复杂任务处理能力的系统级项目。 ## 🗺️ 内容导航 (Roadmap & Navigation) | **状态** | **文章 (Articles)** | **核心要点** | **对应 Demo (Code Module)** | | -------- |--------------------------------------------------------------------| -------------------------------------------------------------------------------------------------- |--------------------------------------------------------| | 🟢 | [01 Native RAG 的标准处理流程](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/01_Native_RAG%E7%9A%84%E6%A0%87%E5%87%86%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.md) | 离线数据建库与在线相似度检索链路 | [demo-01-naive-rag](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main/articles_demo/demo-01-naive-rag) | | 🟢 | [02 Naive RAG 存在的致命问题与解决方案](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/02_Naive_RAG%E5%AD%98%E5%9C%A8%E7%9A%84%E8%87%B4%E5%91%BD%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88.md) | 四大痛点:语意鸿沟、上下文割裂、多级跳转推理与全文总结能力缺失、缺乏纠错闭环 | [demo-02-critical-issues](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main/articles_demo/demo-02-critical-issues) | | 🟡 | [03 工业级 RAG 项目还需要解决哪些问题](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/03_%E5%B7%A5%E4%B8%9A%E7%BA%A7RAG%E9%A1%B9%E7%9B%AE%E8%BF%98%E9%9C%80%E8%A6%81%E8%A7%A3%E5%86%B3%E5%93%AA%E4%BA%9B%E9%97%AE%E9%A2%98.md) | 数据一致性同步、细粒度权限隔离、系统可观测性、自动化评估方案等多方面问题 | [demo-03-other-issues]() | | 🟡 | [04 RAG的元数据设计](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/04_RAG%E7%9A%84%E5%85%83%E6%95%B0%E6%8D%AE%E8%AE%BE%E8%AE%A1.md) | 元数据的三大应用场景,以及利用元数据解决资料冲突的方案设计 | [demo-04-metadata-design]() | | ⚪️ | [05 企业级 RAG 项目的架构参考](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/05_%E4%BC%81%E4%B8%9A%E7%BA%A7RAG%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%9E%B6%E6%9E%84%E5%8F%82%E8%80%83.md) | 六层架构设计,从接入与网关层到最终的监控与测试层的全链路设计方案 | [demo-05-system-architecture]() | | ⚪️ | [06 RAG 的全链路耗时与优化](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/06_RAG%E7%9A%84%E5%85%A8%E9%93%BE%E8%B7%AF%E8%80%97%E6%97%B6%E4%B8%8E%E4%BC%98%E5%8C%96.md) | 全面分析 RAG 的全链路耗时,并针对耗时过高的环节进行优化设计 | [demo-06-latency-optimize]() | | ⚪️ | [07 RAG 的评估维度以及标准评估方法](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/07_RAG%E7%9A%84%E8%AF%84%E4%BC%B0%E7%BB%B4%E5%BA%A6%E4%BB%A5%E5%8F%8A%E6%A0%87%E5%87%86%E8%AF%84%E4%BC%B0%E6%96%B9%E6%B3%95.md) | 基于 RAGAS 的四大评估维度(精确度、召回率、忠实度、相关性),及结合 JUnit 的自动化裁判测试驱动开发 | [demo-07-automated-evaluation]() | | ⚪️ | [08 针对长短不一的文档的双轨制存储方案设计](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/08_%E9%92%88%E5%AF%B9%E9%95%BF%E7%9F%AD%E4%B8%8D%E4%B8%80%E7%9A%84%E6%96%87%E6%A1%A3%E7%9A%84%E5%8F%8C%E8%BD%A8%E5%88%B6%E5%AD%98%E5%82%A8%E6%96%B9%E6%A1%88%E8%AE%BE%E8%AE%A1.md) | 结合全文检索与父子块检索,利用 Metadata 路由实现离线分轨入库与在线统一解析组装 | [demo-08-dual-track-storage]() | _(注:__🟢__ 已完成 __🟡__ 进行中 __⚪️__ 计划中)_ - **关于文章:** 文章初稿已全部推送到仓库,如果近期有 Agent 开发面试,希望提前看下八股的可以去仓库自取(顺手帮忙点个🌟就更好啦),当前为初稿,后续可能会随着code demo 做一些修改完善。后续每更新完一章的code demo会往导航同步更新一篇文章。 - **关于Demo Code:** 所有文章配套的 demo code 会在[Github仓库](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main),均为本人本地跑通后的完整代码,clone后配置好相关后端组件后,可直接运行,如有需要请前往仓库自取。 - **关于生产级项目:** 当前后端部分已写完近 4W 行代码,因为最近比较忙,同时多线程忙很多事,所以预计真正完成可能还需要1-2个月。完成后也会开源在[Github仓库](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main)。项目参考了claude code 的一些实现,综合考虑了很多方面,包含:上下文窗口结构设计、长短期记忆管理机制(长短期转换、记忆编辑、遗忘、归档等)、多意图路由、复杂任务的执行清单拆分、Skills 渐进式纰漏手动实现、Mysql + Milvus + ElasticSearch + Redis 的多数据源协同链路等。 # 本篇正文 ### 写在前面的话 本篇内容比较硬核,实现已经较为完善,推荐结合**配套demo代码**进行学习,代码只需配置好API Key、MySQL、ElasticSearch即可直接运行。本篇除了为了解决Navie RAG存在的:**语意鸿沟、上下文割裂、多级跳转推理与全文总结能力缺失、缺乏纠错闭环**四大痛点问题,而引入的:**查询改写、假设性文档嵌入、意图路由、父子块索引、句子窗口检索、IRCoT、RAPTOR树状摘要、Self-RAG**等多项高级 RAG 技术以外,还涵盖了专业的**上下文窗口设计、长短期记忆机制、复杂意图的LLM逻辑逻辑+相似度匹配路由、skill渐进式纰漏的Java实现**等核心技术实现。 ## 项目介绍 本项目是一个基于 Java 17 + Spring Boot 3 + LangChain4j 构建的工业级检索增强生成(RAG)系统。旨在彻底解决传统朴素 RAG(Naive RAG)在真实业务场景中面临的词汇鸿沟、上下文割裂、多步推理失败、严重幻觉以及缺乏动态执行力等致命痛点。 系统融合了当前业界前沿的大模型落地实践,包括:Self-RAG(自我反思)、RAPTOR(树状宏观摘要)、IRCoT(交错检索思维链)、长短期记忆管理以及 Agentic Skill 渐进式披露。 朴素 RAG 虽然跑通了从本地数据到大模型问答的闭环,但在真实的工业级落地中,往往会遇到诸多致命痛点。简单来说,传统 RAG 就像一个死板的图书管理员:你问什么,他就死板地拿原始问题去匹配相似的段落,然后把那几段话硬塞给大模型。 在处理复杂的真实业务诉求时,这种机制暴露出四大核心缺陷。现行的工业界演进出了 Advanced RAG(高级 RAG) 和 Agentic RAG(基于智能体的 RAG) 来解决这些问题。 ### 痛点 1:用户提问质量差与词汇鸿沟 (Query Mismatch) **致命问题**:用户通常提问非常简短、口语化,甚至包含错别字(例如:“那个报错 HTTP 500 咋办”)。而知识库里的文档是非常正式的(例如:“内部服务器由于空指针异常导致系统崩溃”)。用口语化的短句去向量库里匹配专业长文,检索出的向量距离往往非常远,容易导致直接脱靶。 **解决方案:查询转换** 在去数据库检索之前,先让大模型对用户的原始问题进行一层加工。 #### **Query Rewrite (查询重写)**: **让大模型把口语化的问题重写为更丰富、包含专业术语的检索词。** > + **具体步骤**: > 1. 把用户的原始提问(以及近几轮的历史对话)发送给 LLM。 > 2. 利用系统提示词(Prompt)约束 LLM:“你是一个搜索词优化专家,请根据上下文,将用户的提问重写为更利于向量检索的独立句子,补充缺失的专有名词,纠正错别字。” > 3. LLM 输出重写后的查询,比如:“如何在 Nginx 配置文件中修改监听的端口号?” > 4. 拿着这句重写后的话,再去向量库做 Embedding 和检索。 > + **工程考量**: 这个步骤会增加一次大模型的调用,带来一定的延迟(Latency)。所以在 落地时,通常会选用响应极快的小模型(如 GPT-4o-mini 或 Qwen-Turbo)专门来干这个脏活累活。 > #### **HyDE (Hypothetical Document Embeddings,假设性文档嵌入)**: **面对用户提问,先让大模型“盲答”生成一段假设性答案(即使包含幻觉也没关系),然后把这段生成的答案向量化,去数据库里匹配真实的文档。因为“答案匹配答案”比“问题匹配答案”在向量空间中要精准得多。** > HyDE(假设性文档嵌入)是学术界提出来的一个极其惊艳的思路。它的核心思路是:**“问题”和“答案”在语义空间中长得并不像,但“假答案”和“真答案”长得却很像。** > > + **核心逻辑**: 如果用户问:“Java 中 HashMap 的扩容机制是什么?” 如果直接向量化这个问题,它在多维空间里的特征是“疑问句”。但是向量库里存的都是陈述句(真实的文档)。 HyDE 的做法是:先让 LLM **直接回答这个问题(即不给任何参考资料,让它凭自己的参数记忆硬答)。LLM 可能会胡说八道(产生幻觉),但它生成的这段“假答案”,必然包含了大量的核心词汇、专业句式和语义模式**(比如一定会提到“负载因子”、“数组”、“链表转红黑树”)。 > + **具体步骤**: > 1. 将原始问题发给 LLM,要求生成一段假设性回答(Hypothetical Answer)。 > 2. **(关键点)** 将这段“假答案”进行向量化(Embedding)。 > 3. 用假答案的向量,去向量数据库中寻找距离最近的 Top-K 真实文档。 > 4. 最后,把找出来的真实文档喂给大模型,生成最终的正确回答。 > + **为什么厉害**: HyDE 巧妙地利用了大模型自身的“知识泛化能力”去充当检索的桥梁。即使假答案的数值或细节是错的,它的“语义骨架”却能完美匹配上知识库里真正的那篇技术文档。 > #### **Query Routing (意图路由)**: **判断用户的意图,例如:将“查询某人电话”路由到 SQL 数据库,将“查询公司报销制度”路由到向量数据库。** > 当你的系统不仅仅只有一份 PDF,而是拥有关系型数据库、图数据库、甚至是外部 API 时,硬把所有问题都塞进向量库是非常愚蠢的。查询路由让 RAG 拥有了“分发”的智慧。 > > + **核心逻辑**: 这其实就是构建 AI Agent 最基础的工具调用(Tool Calling / Function Calling)机制。系统充当一个“路由器”,根据用户的意图,决定当前这个问题应该走哪条链路。 > + **技术实现方案**: > - **方案 A:大模型逻辑路由** > > 给大模型提供一个工具列表的描述。例如: > > `Tool 1`:向量知识库(适合问文档内容、政策、技术原理) > `Tool 2`:MySQL 数据库(适合问具体的订单状态、统计数据) > `Tool 3`:Google Search API(适合问今天的新闻、实时天气) > > 用户提问后,大模型首先输出一个 JSON 指令,告诉系统“这个问题我要调用 Tool 2”。Java 后端解析这个 JSON,去执行对应的 SQL 代码,然后再把结果返给大模型。 > > - **方案 B:语义路由** > > 如果不想每次都等大模型推理,可以用向量做路由。预先设定几个“主题分类”的代表性句子并将其向量化。用户提问时,先计算问题向量和各个“主题向量”的相似度,距离谁最近,代码就走对应的分支逻辑。 > ### **补充讨论:** 在真实的工业级落地中,这三种策略**并不是单选题,而是被组合成一条高度协同的“流水线(Pipeline)”**。 在成熟的架构中,这就如同后端系统里的网关分发、拦截器预处理和底层复杂查询。这三者在 RAG 系统中分别把守着不同的关卡。 > #### 第一步:总调度台 —— 意图路由 (Query Routing) > + **什么时候用**:用户刚刚输入问题,系统接收到请求的**第一瞬间**。 > + **扮演角色**:流量网关 / 分发中心。 > + **具体用法**: > > 在真实的业务场景里,用户不会只问知识库里的内容。比如在一个企业级内部助手中: > > + 如果用户问:“帮我查一下工号 89757 的考勤状态”(**路由到 API/SQL 数据库**,去查关系型数据)。 > + 如果用户问:“你好,今天天气真不错”(**路由到闲聊大模型**,直接回复,不查任何库)。 > + 如果用户问:“咱们公司最新的差旅报销标准是什么?”(**命中,路由到 RAG 向量检索分支**)。 > + **工业级权衡**:这是 AI Agent 最核心的能力。通过路由,系统可以极大地节省不必要的向量检索开销,并且避免大模型在闲聊时被强行塞入不相关的参考文档。 > > #### 第二步:语境补全 —— 查询重写 (Query Rewrite) > + **什么时候用**:当第一关的路由决定 **“这个问题需要走 RAG 向量检索”**,并且当前处于 **“多轮对话”** 的场景下。 > + **扮演角色**:上下文翻译官 / 预处理器。 > + **具体用法**: > > 一旦进入 RAG 分支,系统必须检查用户的提问是否缺胳膊少腿。 > > 比如,用户上一轮问了“差旅报销标准”,系统回答后,用户紧接着问:“**那出差打车的发票怎么贴?**”这里的“那”和“出差”其实是依赖上一轮语境的。系统会调用一个极速的小模型(如 GPT-4o-mini),结合历史对话,把这句话重写为:**“公司差旅报销标准中,打车发票应该如何粘贴报销?”** > > + **工业级权衡**:几乎所有成熟的对话式 RAG 都会默认开启多轮对话重写。它的开销很小,但能让向量检索的命中率提升几个数量级。 > > #### 第三步:高难度召回 —— HyDE (假设性文档嵌入) > + **什么时候用**:作为向量检索的“兜底策略”**,通常在标准检索(直接用重写后的问题去搜向量和 BM25)得分极低/找不到相关文档时触发,**或者针对那些**极其抽象、只有几个关键字**的提问。 > + **扮演角色**:深度挖掘机。 > + **具体用法**: > > 假设用户问了一个极其简短但硬核的技术词:“ReentrantLock 底层原理”。 > > 如果标准的向量检索找不到直接匹配的标题,系统就会触发 HyDE:先让大模型凭记忆写一段关于 ReentrantLock 的技术总结(假答案),然后拿着这段长篇大论去知识库里做向量匹配,把真正的技术文档“钓”出来。 > > + **工业级权衡**: > > **在工业界,通常不会把 HyDE 作为默认开启的全局策略。** 主要是由于: > > 1. **太慢了**:需要先等大模型生成一段假答案,再去做检索,最后再生成真答案。延迟翻倍,用户体验很差。 > 2. **容易“带偏”**:如果用户问的是企业极其私有、偏门的内部代号(大模型训练数据里根本没有),大模型生成的假答案会完全是胡编乱造。用这个完全南辕北辙的假答案去检索,不仅搜不到,还会把毫不相干的文档拉进来。 > > 因此,HyDE 通常被配置为一条**降级链路**,或者只在特定需要深度发散的知识域(如长篇研报检索、专利检索)中选择性开启。 > > #### 工业级全链路总结 > 如果把它们串联起来,一个成熟的处理流程是这样的: > > 1. 用户提问 ➡️ **【Query Routing】** 判断意图。 > 2. 如果是闲聊或 API 查询,直接走旁路。 > 3. 如果是知识库查询 ➡️ **【Query Rewrite】** 结合历史记录,把问题改写成信息量饱满的专业长句。 > 4. 拿着重写后的长句去进行混合检索(向量 + BM25)。 > 5. 如果检索召回的置信度很高 ➡️ 直接交给大模型生成答案。 > 6. 如果检索召回的置信度极低(没搜到)➡️ 触发 **【HyDE】**,让大模型生成假答案辅助深度召回。 > 7. 最后大模型基于召回的最终优质文档,生成回答。 > > 这种“搭积木”式的架构设计,正是目前很多优秀 Agent 框架(比如 LangGraph )在做的事情。 > ### 痛点 2:文本切分带来的上下文割裂 (The Chunking Dilemma) **致命问题**:为了迎合 Embedding 模型的限制,文档被强行切成了小块(Chunk)。如果切得太小,检索很准,但大模型拿到的是碎片,不知道前因后果;如果切得太大,上下文有了,但检索精度急剧下降,库里全是噪音。 **解决方案:从小到大检索 (Small-to-Big Retrieval)** 将“用于检索的内容”和“喂给大模型的内容”解耦。 #### **Parent-Child Chunking (父子块检索)**: **在切分时,把一个大段落(父块)切成几个小句子(子块)。在向量库中只对子块进行检索。一旦匹配到某个子块,系统会顺藤摸瓜找到它的父块,把整个完整的大段落发送给大模型。** > **核心思想:建两次索引,小块查,大块答。** 我们将文档切分为较大的“父块”(例如一整个完整的章节或长段落),然后再将每个父块切分成更小的“子块”(例如一两句话)。**只对“子块”进行向量化并存入向量数据库**,而“父块”存入普通的 Key-Value 数据库(如 Redis、MongoDB 或内存 Map)。 > > 当用户提问时,系统通过向量匹配命中极其精准的“子块”。然后,系统提取该子块元数据(Metadata)中的 `parent_id`,去 KV 数据库中把对应的完整“父块”取出来,将完整的父块发给大模型。 > > **技术实现步骤:** > > 我们需要两个存储组件:一个向量数据库(存 Child)和一个文档型/KV 数据库(存 Parent)。 > 1. 离线建库阶段: > 第一步:切分为较大的父块 (比如按章节、双换行切分,假设每个父块 1000 字符),将父块存入 KV 数据库 > 第二步:将当前父块切分为更小的子块 (比如按句子切分),在子块的 Metadata 中强行注入 parent_id,将子块向量化并存入向量数据库 > > 2. 在线检索阶段: > 第一步:将用户问题向量化 > 第二步:在向量库中检索最相关的子块 (Child Chunk) > 第三步:拿到子块后不直接用,而是去查它的父块,从 KV 库中捞出完整的父块上下文,为了防止重复添加相同的父块(如果有多个子块命中了同一个父块),可以加个去重逻辑 > 第四步:最终返回完整宏观的上下文给大模型 > > > > **适用场景**:极其适合篇幅长、层级结构明确的文档(如 API 文档、法律合同、技术手册)。 > #### **Sentence Window Retrieval (句子窗口检索)**: **将文档按单句切分并向量化。检索时精准匹配到某一句,但在提取时,自动向前后各扩展 3-5 句话(滑动窗口),确保大模型看到的是一段连贯的上下文。** > **核心思想:精准定位一句,向上下文滑窗扩展。** > > 这种方式不显式地划分父子级,而是将整篇文档**按单句**切分。每一个切分出来的句子都会带上一个严格递增的序列号(Index)。 > > 在检索时,依然是精准命中得分最高的那一句话。但是在提取上下文时,系统会以这句话为中心,自动向它前、后各多取K句话(例如前 2 句 + 命中句 + 后 2 句),拼接成一个“窗口”发给大模型。 > > **技术实现逻辑:** 为了实现窗口滑动,向量数据库中不仅要存当前句,最好还能通过条件查询(基于 doc_id 和 index 区间)把相邻句子也取出来,比如 在 Metadata 中记录它是哪篇文档的第几个句子,或者在应用层内存中保留一份完整的顺序文档映射。 > > **适用场景**:适合没有明显段落层级、行文连贯的叙事类文本、小说、客服通话记录或是松散的维基百科文章。 > ### 痛点 3:无法处理“跨文档”和“全局总结”的复杂推理 (Multi-hop Reasoning) **致命问题**:传统 RAG 只能做“单点查询”。如果用户问:“对比一下 A 项目和 B 项目在第三季度的核心技术突破”,这需要跨越多个不同文档去寻找线索。向量检索往往只能找到 A 的部分或者 B 的部分,无法像人类一样进行“多级跳跃(Multi-hop)”的逻辑关联;也无法回答“总结这 10 万字文档的三个核心主题”这种需要宏观视野的问题。 #### **解决方案:知识图谱结合 (GraphRAG)** > A Graph RAG Approach to Query-Focused Summarization (2024年微软提出) > 这是目前工业界(尤其是微软大力推崇)解决复杂推理的经典方案。 + **技术实现**:在离线建库阶段,不仅做向量切分,还利用大模型从文档中抽取出**实体 (Entity)** 和 **关系 (Relationship)**,构建成知识图谱。 + **在线问答**:当遇到复杂问题时,系统不仅做向量检索,还会去查询知识图谱,顺着图谱的“节点连线”把相关的概念全部串联起来,甚至利用图谱的社区检测算法(Community Detection)生成全局摘要。 GraphRAG 的核心思想是:**化非结构化文本为结构化网络。** 它不仅仅依赖文本块的字面相似度,而是让机器真正理解实体之间的“关系”。这种思路与我们在底层研发关系型数据库或图数据库时的索引构建非常相似。 **1. 离线建库阶段** 这部分是 GraphRAG 最烧钱、也最耗时的环节。 + **实体与关系抽取 (NER & RE)**:我们不再仅仅把文档切成 Chunk,而是把每一段文本喂给 LLM,让 LLM 提取出里面的**节点(实体:人、地点、物品、概念)****和****边(关系:属于、制造、位于)**。 + **构建图数据库**:将提取出的节点和边存入专门的图数据库(如 Neo4j、NebulaGraph)。 + **社区检测与层级摘要 (微软 GraphRAG 的精髓)**:图谱建好后,算法会把连接紧密的节点聚类成一个个“社区(Community)”。比如,小说里“魔法学院”相关的所有老师、法术、建筑会被聚合成一个社区。然后,LLM 会预先为每一个社区生成一段**全局摘要**。这就解决了“请总结一下整本书里魔法体系的设定”这类宏观问题。 **2. 在线检索阶段** 当用户提出复杂问题时: + **意图识别与实体提取**:首先用 LLM 分析用户提问,提取出关键词(如“暗影长剑”、“冰霜巨龙”)。 + **图谱遍历 (Graph Traversal)**:使用图查询语言(如 Cypher)在 Neo4j 中以这两个实体为起点,进行深度优先或广度优先搜索,找出连接它们的“最短路径”或相关子图。 + **混合组装**:将图谱中找到的逻辑关系(三元组或社区摘要),与传统的向量检索结果拼接在一起,作为无死角的 Context 发送给大模型。大模型据此就能顺畅地推理出答案。 #### 其他替代解决方案: 除了 GraphRAG 这种“重工业”方案,业界还有几种非常流行且轻量级的解法,用来处理多级推理和全局总结。 ##### 1. Agentic RAG / 迭代检索 (Iterative Retrieval / IRCoT) 如果不建图谱,我们也可以通过赋予大模型“思考能力”来解决多级跳转。这种方案叫做 **交错检索与思维链 (Interleaved Retrieval Chain-of-Thought)**。 + **实现逻辑**:大模型不再是一次性拿到所有文档,而是被设计成一个会“自我提问”的 Agent。 + **场景演示**:用户问:“《指环王》导演的出生地是哪个国家的首都?” - **Agent 思考**:我需要先知道导演是谁。➡️ **动作**:检索“指环王 导演”。 - **Agent 读取**:检索回来的文档说导演是彼得·杰克逊。 - **Agent 思考**:现在我需要知道彼得·杰克逊的出生地。➡️ **动作**:检索“彼得·杰克逊 出生地”。 - **Agent 读取**:文档说是新西兰的惠灵顿。 - **Agent 思考**:惠灵顿是新西兰的首都,问题解决。 ➡️ **输出最终答案**。 + **优点**:不需要维护复杂的图数据库,工程架构简单,只需编排 Agent 逻辑。 ##### 2. RAPTOR 树状摘要 (Recursive Abstractive Processing for Tree-Organized Retrieval) > _RAPTOR: Recursive Abstractive Processing for Tree-Organized Retrieval (2024年斯坦福大学提出)_ > 如果用户的痛点更多集中在 **“全局总结”**(比如:总结这份 100 页研报的核心观点),普通的向量检索只能捞出局部细节,而 GraphRAG 又嫌太重,那么 RAPTOR 是一套极其优雅的折中方案。 + **实现逻辑**:它在离线阶段构建了一棵“摘要树”。 1. 将底层文档切分成普通的 Chunk(叶子节点)。 2. 用聚类算法(如 K-Means)把语义相近的 Chunk 聚在一起。 3. **让 LLM 把这一聚类的 Chunk 浓缩成一段“高层摘要”(父节点)。** 4. 再把高层摘要继续聚类、继续总结,直到整本书变成了一段终极摘要(根节点)。 + **检索方式**:用户提问时,系统从树根往下搜。如果是宏观问题(“整本书讲了什么?”),就会匹配到上层的宏观摘要;如果是细节问题,就会一路向下匹配到底层的 Chunk。它巧妙地融合了不同颗粒度的上下文。 ### 方案选型建议 在实际的后端架构设计中,选择哪种方案取决于你的核心业务诉求: 1. **侧重实体关系清晰、强逻辑推导**(如金融风控股权穿透、公安刑侦、复杂小说设定):**首选 GraphRAG (Neo4j)**。 2. **侧重文档的宏观阅读与层级总结**(如财报分析、长篇研报问答):**选择 RAPTOR 树状摘要**。 3. **开发资源有限,希望用敏捷方式解决动态推理**:**使用 Agentic RAG(迭代检索)**,用大模型的 API 调用次数换取工程架构的简单。 ### 痛点 4:流程僵化,缺乏自我纠错能力 (Rigid Pipeline & Hallucination) **致命问题**:传统 RAG 是单向的“流水线”:检索 → 生成。如果检索回来的内容全是错的,大模型依然会硬着头皮基于这些错误内容生成答案(引发新的幻觉)。它不知道什么时候该拒绝回答,什么时候该去搜索引擎查最新数据。 **解决方案:Agentic RAG / Self-RAG (智能体与自我反思 RAG)** #### Self-RAG:自带“测试与纠错”的闭环系统 Self-RAG 彻底改变了单向数据流。它在流程中插入了多个“裁判(Grader)”节点,大模型不仅负责生成答案,还要负责自我评估。 **核心机制拆解(三个核心裁判):** 1. **文档相关性评估 (Retrieval Grader)** - **动作**:向量数据库返回 Top-K 个文档片段后,先不急着生成答案。大模型先对每一个片段进行打分(Yes/No)。 - **纠错逻辑**:如果大模型认为找回来的文档和用户问题根本无关,它会**拒绝使用这些文档,甚至触发“Query Rewrite(问题重写)”**,换个搜索词重新去向量库查一遍。这相当于 Java 里的 `while` 循环重试。 2. **幻觉评估 (Hallucination Grader)** - **动作**:大模型基于相关的文档生成了草稿答案。此时,再调动大模型审视自己的草稿:这个答案里提到的每一个数据、每一个事实,都能在刚才的参考文档里找到出处吗? - **纠错逻辑**:如果发现自己“加戏”了(比如文档里没写具体时间,但草稿里捏造了 2025 年),它会打回重做,重新生成不包含幻觉的答案。 3. **答案有用性评估 (Answer Grader)** - **动作**:检查最终答案是否真正回答了用户的原始提问。如果只是东拼西凑了一堆相关事实,但没有直击痛点,同样打回重写。 **具体落地框架**:目前最主流的实现方式是使用 **LangGraph**(或类似的图流编排工具)。可以把整个 RAG 定义为一个包含多个节点的有向循环图,通过条件边(Conditional Edges)来决定是输出答案,还是回退到检索节点。 #### 存在的问题及解决: > 在引入循环反馈机制后,如果设计不当,系统会像遇到了死锁一样,在一个“检索 -> 评估不相关 -> 重写问题 -> 再次检索 -> 依然不相关”的死循环里无限消耗大模型的 Token 和时间。 > > 在实际的后端和 Agent 开发中,我们解决这个问题的核心思想非常成熟:**状态机(State Machine)结合熔断机制(Circuit Breaker)**。 > > 在像 LangGraph(或者 Java 生态中类似的图流编排框架)的实现里,节点之间传递的不再是简单的字符串,而是一个**全局的“状态对象(State)”**。我们通过在这个状态对象中维护计数器和流转记录,来精准控制图的走向。 > > ### 核心设计:状态对象 (The State) > 在进入流程之前,我们需要定义一个伴随整个请求生命周期的上下文对象。 > ### 实际工作链路 (4 步流转) > #### 第一步:检索节点 (Retrieve Node) > 系统接收到 `RagState`,提取 `currentQuery` 去向量数据库中执行检索。检索到的结果存入 `state.documents`,然后将控制权交给下一个节点。 > > #### 第二步:评估节点 (Grade Node) > 大模型作为“裁判”,检查 `state.documents` 是否包含回答 `currentQuery` 所需的信息。 > > + **如果相关**:在状态中打上 `grade = "PASS"` 的标记。 > + **如果不相关**:在状态中打上 `grade = "FAIL"` 的标记。 > > #### 第三步:条件路由节点 (Conditional Router) —— 熔断的核心 > 这是一个纯逻辑判断节点(不需要调用大模型)。它检查当前的 `grade` 和 `retryCount`,决定下一步去哪儿: > > 1. **分支 A (成功通行)**:如果 `grade == "PASS"`,直接流转到 **“生成答案节点 (Generate Node)”**。 > 2. **分支 B (触发熔断,优雅退出)**:如果 `grade == "FAIL"`**并且**`state.retryCount >= MAX_RETRIES`,此时系统强制跳出循环,进入 **“降级/兜底节点 (Fallback Node)”**。 > 3. **分支 C (允许重试)**:如果 `grade == "FAIL"`**并且**`state.retryCount < MAX_RETRIES`。 流转到 **“重写问题节点 (Rewrite Node)”**,同时 `state.retryCount++`。 > > #### 第四步:兜底策略 (Fallback Node 的具体实现) > 当系统确定“我已经在本地库里努力找了 3 遍,并且换了 3 种搜索词,依然找不到答案”时,必须给用户一个交代。常见的优雅退出策略有三种: > > + **策略 1:诚实拒绝 (Graceful Decline)**:系统不调用大模型生成答案,而是直接返回一段预设的、友好的提示词:“抱歉,在当前的知识库中未找到与您问题高度相关的信息。为了避免提供错误答案,我无法直接回答。您可以尝试提供更多背景信息,或联系人工客服。”(这彻底杜绝了幻觉)。 > + **策略 2:转移阵地 (Web Search Fallback)**:既然本地没有,那就去公网找。系统会调用外部搜索引擎 API(如 Google Search API、Tavily API),用最后一次的搜索词去互联网上抓取最新的网页内容,然后基于网页内容生成答案。 > + **策略 3:人工介入 (Human Handoff)**:在企业内部系统中,记录下这条失败的 Query,并将其打上“知识盲区”的标签,发送到运维或业务人员的钉钉/企业微信群,提示后台需要补充相关的知识文档。 > > 这里有一个重要的工程细节:**如果只做 `retryCount++`,而不改变搜索词,那去数据库里查 100 遍,查出来的依然是相同的垃圾数据(因为检索是幂等的)**。 > > 所以,在 **“重写问题节点 (Rewrite Node)”**,我们必须采取 **降级重写策略 (Degrading Rewrite)**: > > + **第 1 次重试**:让大模型尝试换同义词(比如把“打车发票”换成“交通费凭证”)。 > + **第 2 次重试**:让大模型尝试抽象化问题,去掉一些限定词(比如去掉具体的日期限制,只搜核心概念)。 > + **第 3 次重试**:触发 HyDE(假设性文档嵌入),用大模型的假答案去“钓鱼”。 > > 通过这种方式,每一次回退的检索都是一次“全新的尝试”,直到触碰 `MAX_RETRIES` 的天花板。 > > > > 在架构上,防死循环的本质就是:**状态追踪 + 阈值拦截 + 兜底旁路**。这种设计模式让 RAG 系统具备了极强的韧性和确定性,不会因为大模型一时的“执念”而拖垮整个后端的资源。 > #### Agentic RAG:向量检索只是“工具箱”里的一件工具 在真实的业务中,问题往往极其复杂,单靠查文档是解决不了的。Agentic RAG 将大模型升级为“大脑(Router & Planner)”,而向量数据库(RAG)退化成了与 MySQL、API、代码执行器平级的 **“工具(Tool)”**。 **具体业务案例分析:广告推送策略的综合诊断** 假设你的平台包含两部分数据: 1. **关系型数据库 (MySQL/ClickHouse)**:存储硬性的业务指标(如各个广告推送任务的每日点击率 CTR、转化率、用户圈选维度)。 2. **向量数据库 (Milvus)**:存储非结构化的业务文档(如每个季度“大促活动”的运营策略文档、文案审核规范、历史复盘报告)。 **用户提问:** “帮我对比一下上个月‘春季数码大促’的实际推送点击率和我们的历史基准线,并总结一下这次大促核心使用了什么差异化的推送策略。” **传统 RAG 的死局**: 传统 RAG 会把这句话拿去向量库搜,搜不出点击率数据(因为在 MySQL 里);或者去查 SQL,查不出策略总结(因为在文档里)。系统直接崩溃或胡说八道。 **Agentic RAG 的解决路径(基于 ReAct 模式:Reasoning + Acting):** 大模型接收到这个问题后,开始在后台进行“思考”与“工具调用”的循环: + **Iteration 1(查数据)** - Thought(思考):我需要先获取“春季数码大促”的实际点击率和历史基准线。这属于结构化指标,我应该调用数据库查询工具。 - Action(动作):调用 `SQL_Query_Tool`,传入参数 `campaign_name="春季数码大促"`。 - Observation(观察/结果):后端执行 SQL 返回 `{"实际CTR": "4.2%", "历史基准CTR": "3.5%"}`。 + **Iteration 2(查文档)** - Thought(思考):指标拿到了,表现不错。现在我需要总结这次大促的核心差异化策略。这属于非结构化文档,我应该调用向量知识库检索工具。 - Action(动作):调用 `Vector_DB_RAG_Tool`,传入搜索词 `“春季数码大促 核心推送策略 差异化”`。 - Observation(观察/结果):向量库返回相关文档片段 `“本次春促一改往日的全量广撒网,主要采用基于用户历史浏览偏好的分时段、动态文案推送,针对流失预警用户增加了额外补贴...”`。 + **Iteration 3(综合与输出)** - Thought(思考):我已经收集齐了所有需要的信息。现在可以回答用户了。 - Final Answer(最终输出):“上个月的春季数码大促表现优异,实际点击率为 4.2%,高于 3.5% 的历史基准线。根据策略文档复盘,本次大促成功的原因在于其差异化的推送策略:放弃了全量广撒网,改为基于浏览偏好的动态文案推送,并针对流失预警用户精准投放了补贴。” **技术实现方案 (基于 Java & LangChain4j)** 在 Java 生态中实现 Agentic RAG 非常优雅。LangChain4j 提供了 `@Tool` 注解,可以极快地把现有后端的 Service 方法变成大模型的工具。 然后,在初始化大模型时,把这些工具塞进去,大模型就会自动根据用户的提问,决定调用哪个 Java 方法、传什么参数,这就形成了一个强大的 AI Agent 闭环。 通过将 RAG 降维成 Agent 的一个工具,并结合 Self-RAG 的评估机制,大模型的输出变得极其可控和精准。 # 配套代码解析 ## 📂 核心目录结构 ```text src/main/java/com/example/demo02criticalissues/ ├── chat/ # 大模型配置 (DashScope Qwen) ├── chunker/ # 高级切分策略 (父子块切分 ParentChildChunker、句子滑窗 SentenceWindowChunker) ├── context/ # 上下文窗口管理 (ContextWindow 结构化提示词设计) ├── controller/ # REST API 对外接口 ├── entity/ # 数据库实体类 (对话归档、长期记忆(用户画像)、RAPTOR 树节点等) ├── repository/ # Spring Data JPA 仓储接口 ├── retriever/ # 检索器与重排序 (HybridRerank 混合重排、IRCoT 迭代检索器) ├── router/ # 意图网关 (LLM 逻辑路由、Semantic 语义路由) ├── service/ # 核心业务逻辑层 │ ├── AdvancedRAGService.java # RAG 核心主控流水线 (主调度器) │ ├── HyDEService.java # 假设性文档生成增强检索 │ ├── QueryRewriteService.java # 查询重写 (术语规范化、上下文补全) │ ├── RAPTORService.java # RAPTOR 树状摘要构建与检索 │ ├── SelfRAGService.java # 自我反思与评判引擎 (防止幻觉) │ ├── ShortTermMemoryService.java # 短期记忆滚动压缩管理 │ └── UserProfileService.java # 长期记忆 (用户画像) 提取与更新 ├── skill/ # Agentic Skill 管理引擎 (渐进式披露加载) ├── tools/ # 智能体工具 (Text2SQLTool 数据库与系统脚本执行) ├── utils/ # 工具类 (JSON 安全提取等) └── test/ # 核心功能演示入口 (AdvancedRAGTest) ``` ## 🧠 核心技术实现方案 ### 1. 结构化上下文窗口设计 (Context Window) 抛弃了传统 RAG 简单的“资料+问题”拼接,设计了类似 XML 标签的结构化 Prompt 容器。 - **机制:** 划分为 `<system prompt>`, `<core rules>`, `<tools or Skills>`, `<memory>`, `<retrieved context>`, `<input>` 六大模块。 - **优势:** 严格界定大模型的行为边界,防止提示词注入;让模型时刻保持一致的人设和记忆连贯性。 ### 2. 双轨记忆管理 (Long/Short Term Memory) - **短期记忆 (Rolling Summary):** 防止对话轮数过多导致 Token 爆仓。当历史对话达到阈值(如3轮)时,自动触发大模型将新对话“融合”到旧的全局摘要中,生成新的滚动摘要,随后清空历史,实现无损降维。 - **长期记忆 (User Profile):** 通过异步分析对话摘要中的兴趣点与高频词,更新存储在数据库中的用户画像(如专业水平、提问偏好),后续对话自动注入以实现高度个性化。 ### 3. 多维查询重写 (Query Rewrite) 填平用户口语化提问与专业文档之间的“词汇鸿沟”。 - **术语规范化:** 将“那个发票咋贴”翻译为“差旅交通费凭证粘贴规范”。 - **上下文补全:** 利用短期记忆,将包含代词的追问(如“那打车的呢?”)补全为携带独立完整语义的检索长句,大幅提升向量检索命中率。 ### 4. 假设性文档嵌入增强 (HyDE) - **机制:** 遇到缺乏上下文线索的极其抽象的技术提问(如“HashMap扩容原理”)时,先让 LLM 凭训练记忆“盲答”生成一段假答案。用这段富含专业特征词汇的假答案去向量库中做匹配。 - **优势:** 通过“答案匹配答案”的降维打击,将原本极低的召回置信度拉升至精准召回。 ### 5. 双层意图路由网关 (Intent Routing) - **语义路由 (Semantic Router):** 基于本地轻量级向量计算,将用户 Query 与预设的“闲聊/文档查询/SQL查询”主题向量计算余弦相似度,0延迟、无 Token 消耗,作为第一道高频流量分发网关。 - **逻辑路由 (LLM Router):** 基于大模型强大的推理能力,处理复杂的隐含意图,作为兜底防线。 ### 6. 破除上下文割裂的切分策略 (Chunking Strategies) - **父子块检索 (Parent-Child):** 建两次索引,切分小句入向量库,大段落入关系库。小块精准命中后,顺藤摸瓜返回完整大段落,给大模型提供充分的前因后果。 - **句子窗口检索 (Sentence Window):** 按单句切分,命中某句后,自动向前后滑动扩展 K 句话,拼装成连贯上下文。 ### 7. RAPTOR 树状摘要与宏观问题检索 解决传统 RAG 无法回答“请总结这100页研报核心观点”的痛点。 - **构建:** 底层 Chunk -> K-Means 聚类 -> LLM 生成局部摘要 -> 再次聚类... 最终生成 Root 顶层全局摘要。 - **检索:** 基于用户问题意图动态决定探查树的层级。宏观问题直接抓取 Root 摘要,微观问题探底至叶子节点。 ### 8. IRCoT 交错检索思维链 处理跨越多个文档才能拼凑出答案的多跳(Multi-hop)推理。 - 系统转变为一个会“自我提问”的 Agent。执行 `思考 -> 搜索短句 -> 观察 -> 再思考生成新搜索词` 的循环,直到收集齐所有拼图。 ### 9. Self-RAG 自我反思与 Fail-Fast 熔断机制 抛弃传统的“盲目检索+强行生成”单向流水线,引入大模型裁判委员会。 - **三大裁判:** 检索相关性裁判、幻觉裁判、答案有用性裁判。 - **Fail-Fast (快速熔断):** 在裁判判定失败时(尤其是严重脱离文档的幻觉),系统绝不死循环浪费 Token,而是快速阻断并回退到安全的兜底策略(如婉拒回答或请求人工介入)。 ### 10. Agentic Skill 渐进式披露与系统防线 - **渐进式披露:** 系统中预置了复杂的工具说明(如 skill.md)。平时这些内容不载入内存;只有当路由判定需要执行复杂任务(如 Text2SQL)时,才动态加载包含详细表结构、参考规范 (refs) 和脚本列表 (scripts) 的长 Prompt,极大节省常规对话的 Token 消耗。 - **防 OOM 与注入拦截:** Text2SQL 工具内置了指令级注入拦截,并在下发底层执行前强制追加 LIMIT 防护,彻底杜绝大模型生成的恶劣 SQL 导致千万级数据撑爆 JVM 的严重线上事故。 ## 🔌 REST API 文档 基础路径: /api/rag ### 1. 对话接口 (POST /chat) 请求体: ```json { "userId": "user_001", "sessionId": "session_1001", "query": "咱们公司最新的差旅发票应该怎么贴?" } ``` 响应体: ```json { "answer": "根据差旅报销规范,交通费发票必须平铺粘贴在A4纸左上角...", "sessionId": "session_1001", "reasoning": "匹配到主题: 向量库检索", "retrievalStrategy": "VECTOR_SEARCH", "usedTools": ["IntentRouting", "VectorSearch", "QueryRewrite", "HybridRerank", "SelfRAG"] } ``` ### 2. 意图分析独立测试 (POST /intent) 请求体: ```json { "userId": "user_001", "query": "帮我统计一下数据库里的总用户数" } ``` ### 3. 系统健康检查 (GET /health) 响应体: ```json { "status": "OK", "message": "RAG服务正常运行" } ```

01 Naive RAG 的标准处理流程 —— Building-RAG-Systems 项目系列第一篇

## 关于本项目 ### 项目名称:🚀 Building-RAG-Systems: From Theory to Production > 本项目致力于提供一条平滑且深入的 RAG(检索增强生成)学习与实践路径。通过**深度文章解析**、**配套 Demo代码** 以及**系统级项目实战**,带你从零构建工业可用的大模型应用。 > 代码仓库链接:[Github](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main) ### 📂 仓库结构 (Repository Structure) 本项目按照“理论 -> 配套demo -> 系统级实践”的逻辑组织,主要包含以下三个核心模块: ```text 📦 Building-RAG-Systems ┣ 📂 articles # 📖 核心知识库:RAG 理论解析、架构设计及痛点解决方案 ┣ 📂 articles_demo # 💻 Demo代码:与文章配套的开箱即用 Demo 代码 ┗ 📂 project # 🏗️ 系统级项目:融合所有知识点的全功能系统架构 ``` #### 1️⃣ `articles`:深入浅出的理论与思考 这里不只是空洞的理论,更是实打实的架构设计经验与问题解决思路。 + 探索 RAG 的核心组件与工作流。 + 深入剖析在 Chunking、Embedding、Retrieval 和 Generation 环节遇到的常见痛点(如语意鸿沟、上下文割裂、检索不精准等)及其解决方案。 #### 2️⃣ `articles_demo`:配套的 Demo 代码 Show me the code! 每篇核心文章都配备了独立的、可运行的 Demo。代码保持极简,屏蔽无关框架干扰,方便你快速运行和理解。 #### 3️⃣ `project`:从 Demo 到生产级系统 这是本仓库的终极目标。我们将前两个模块中沉淀的知识与技巧,融合并构建成一个完整的、具备 Agent 协同和复杂任务处理能力的系统级项目。 ### 🗺️ 内容导航 (Roadmap & Navigation) | **状态** | **文章 (Articles)** | **核心要点** | **对应 Demo (Code Module)** | | -------- |--------------------------------------------------------------------| -------------------------------------------------------------------------------------------------- |--------------------------------------------------------| | 🟢 | [01 Native RAG 的标准处理流程](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/01_Native_RAG%E7%9A%84%E6%A0%87%E5%87%86%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.md) | 离线数据建库与在线相似度检索链路 | [demo-01-naive-rag](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main/articles_demo/demo-01-naive-rag) | | 🟡 | [02 Naive RAG 存在的致命问题与解决方案](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/02_Naive_RAG%E5%AD%98%E5%9C%A8%E7%9A%84%E8%87%B4%E5%91%BD%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88.md) | 四大痛点:语意鸿沟、上下文割裂、多级跳转推理与全文总结能力缺失、缺乏纠错闭环 | [demo-02-critical-issues]() | | 🟡 | [03 工业级 RAG 项目还需要解决哪些问题](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/03_%E5%B7%A5%E4%B8%9A%E7%BA%A7RAG%E9%A1%B9%E7%9B%AE%E8%BF%98%E9%9C%80%E8%A6%81%E8%A7%A3%E5%86%B3%E5%93%AA%E4%BA%9B%E9%97%AE%E9%A2%98.md) | 数据一致性同步、细粒度权限隔离、系统可观测性、自动化评估方案等多方面问题 | [demo-03-other-issues]() | | 🟡 | [04 RAG的元数据设计](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/04_RAG%E7%9A%84%E5%85%83%E6%95%B0%E6%8D%AE%E8%AE%BE%E8%AE%A1.md) | 元数据的三大应用场景,以及利用元数据解决资料冲突的方案设计 | [demo-04-metadata-design]() | | ⚪️ | [05 企业级 RAG 项目的架构参考](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/05_%E4%BC%81%E4%B8%9A%E7%BA%A7RAG%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%9E%B6%E6%9E%84%E5%8F%82%E8%80%83.md) | 六层架构设计,从接入与网关层到最终的监控与测试层的全链路设计方案 | [demo-05-system-architecture]() | | ⚪️ | [06 RAG 的全链路耗时与优化](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/06_RAG%E7%9A%84%E5%85%A8%E9%93%BE%E8%B7%AF%E8%80%97%E6%97%B6%E4%B8%8E%E4%BC%98%E5%8C%96.md) | 全面分析 RAG 的全链路耗时,并针对耗时过高的环节进行优化设计 | [demo-06-latency-optimize]() | | ⚪️ | [07 RAG 的评估维度以及标准评估方法](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/07_RAG%E7%9A%84%E8%AF%84%E4%BC%B0%E7%BB%B4%E5%BA%A6%E4%BB%A5%E5%8F%8A%E6%A0%87%E5%87%86%E8%AF%84%E4%BC%B0%E6%96%B9%E6%B3%95.md) | 基于 RAGAS 的四大评估维度(精确度、召回率、忠实度、相关性),及结合 JUnit 的自动化裁判测试驱动开发 | [demo-07-automated-evaluation]() | | ⚪️ | [08 针对长短不一的文档的双轨制存储方案设计](https://github.com/Mrchen-1600/Building-RAG-Systems/blob/main/articles/08_%E9%92%88%E5%AF%B9%E9%95%BF%E7%9F%AD%E4%B8%8D%E4%B8%80%E7%9A%84%E6%96%87%E6%A1%A3%E7%9A%84%E5%8F%8C%E8%BD%A8%E5%88%B6%E5%AD%98%E5%82%A8%E6%96%B9%E6%A1%88%E8%AE%BE%E8%AE%A1.md) | 结合全文检索与父子块检索,利用 Metadata 路由实现离线分轨入库与在线统一解析组装 | [demo-08-dual-track-storage]() | _(注:__🟢__ 已完成 __🟡__ 进行中 __⚪️__ 计划中)_ - **关于文章:** 文章初稿已全部推送到仓库,如果近期有 Agent 开发面试,希望提前看下八股的可以去仓库自取(顺手帮忙点个🌟就更好啦),当前为初稿,后续可能会随着code demo 做一些修改完善。后续每更新完一章的code demo会往导航同步更新一篇文章。 - **关于Demo Code:** 所有文章配套的 demo code 会在[Github仓库](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main),均为本人本地跑通后的完整代码,clone后配置好相关后端组件后,可直接运行,如有需要请前往仓库自取。 - **关于生产级项目:** 当前后端部分已写完近 4W 行代码,因为最近比较忙,同时多线程忙很多事,所以预计真正完成可能还需要1-2个月。完成后也会开源在[Github仓库](https://github.com/Mrchen-1600/Building-RAG-Systems/tree/main)。项目参考了claude code 的一些实现,综合考虑了很多方面,包含:上下文窗口结构设计、长短期记忆管理机制(长短期转换、记忆编辑、遗忘、归档等)、多意图路由、复杂任务的执行清单拆分、Skills 渐进式纰漏手动实现、Mysql + Milvus + ElasticSearch + Redis 的多数据源协同链路等。 ## 本篇正文 RAG(Retrieval-Augmented Generation,检索增强生成)的标准处理流程通常被分为两个主要阶段:**离线数据处理(Offline Data Ingestion)** 和 **在线检索生成(Online Query & Generation)**。 在Java 生态中,开发 RAG 最主流且成熟的框架是 **LangChain4j**(类似于 Python 生态的 LangChain)和 **Spring AI**。 ### 第一阶段:离线数据处理 (建库) #### 1. 文档解析与分块 (Document Loading & Chunking) + **具体实现**:首先提取 Markdown、Word、HTML 等不同格式文件中的纯文本。由于大模型每次处理的上下文长度有限(Token 限制),且整篇文档的语义容易稀释,我们需要将长文档切割成一段段较短的文本块(Chunks)。 + **主流技术方案:** - **框架**:Unstructured.io、LangChain、LlamaIndex。 - **分块策略**:固定大小分块(Fixed-size chunking)、基于规则的递归分块(Recursive character splitting,目前最常用)、基于语义的分块(Semantic chunking)。 > **三种分块策略具体解释:** > > ### 1. 固定大小分块 > > 这是最简单粗暴的分块方式。系统不考虑文本的任何语法结构或段落意义,单纯按照设定的字符数(或 Token 数)进行“一刀切”。 > > + **具体实现**:设定一个阈值(比如 200 个字符)。系统从头开始数,满 200 个字符就截断作为一个 Chunk,然后继续数下一个 200 个字符。 > + **优点**:实现极度简单,计算开销几乎为零,向量数据库的资源消耗非常可控。 > + **缺点**:极其容易破坏语义完整性,导致检索时丢失关键上下文。 > > ### 2. 基于规则的递归分块 > > 这是目前业界**最常用、性价比最高**的默认策略。它通过一组预设的标点符号分隔符(比如双换行 `\n\n`、单换行 `\n`、句号 `。`、空格 ),像剥洋葱一样从大到小去尝试切分文本。 > > + **具体实现**:系统会优先尝试用最大的结构(如段落双换行 `\n\n`)来切分。如果切出来的段落还是超过了设定的大小限制,它就会“递归”地降级,尝试用单换行 `\n` 切分;如果还大,就用句号切分成句子;最后才是按字符硬切。同时,为了防止相邻块的上下文丢失,通常会设置一个 **Overlap(重叠区)**。 > + **优点**:兼顾了文本大小的限制和自然语言的语义边界,泛化能力强。 > + **缺点**:仍然依赖硬性规则和标点符号,对于格式混乱的文本效果一般。 > > ### 3. 基于语义的分块 > > 这是目前比较前沿的高阶玩法。它抛弃了固定的长度和标点符号规则,而是让机器真正去“读懂”文本,在语义发生转折的地方进行切分。 > > + **具体实现**:通常的做法是将文本先按句子切开,然后使用 Embedding 模型计算相邻两个句子之间的“语义相似度”。如果两句话讲的是同一件事(向量距离近),就合并成一个 Chunk;如果相邻两句话的语义差异突然变大(向量距离远,超过某个阈值),就认为这里发生了“话题切换”,从而在这里断开,生成一个新的 Chunk。 > + **场景举例**:小说前三句话在描写主角在精灵森林中采集草药(语义 A),第四句话突然话锋一转,切到了反派在黑暗城堡里密谋造反(语义 B)。语义分块算法会敏锐地捕捉到这两种场景的差异,精准地在这两段剧情之间切开,哪怕反派剧情的第一句话和草药剧情在同一个自然段里。 > + **优点**:最大程度保证了每一个 Chunk 内的信息高度内聚,检索准确率极高。 > + **缺点**:计算成本高昂。在切分阶段就需要频繁调用大模型或 Embedding 模型,处理速度慢,实现逻辑也更复杂。 > > **实现思路**: > > 1. 先按句子拆分文本 > > 2. 将所有句子向量化 (耗时/烧钱操作) > > 3. 遍历计算相邻句子的余弦相似度 > > 如果相似度低于阈值,说明话题变了,在此断开 #### 2. 文本向量化 (Embedding) + **具体实现**:将上一步得到的每一个文本块转换成高维的浮点数数组(向量)。在向量空间中,语义相近的文本块,它们对应的向量距离也会非常接近。 + **主流技术方案**: - **闭源模型**:OpenAI text-embedding-3-small/large、Qwen的 embedding 模型等。 #### 3. 向量存储 (Vector Storage) + **具体实现**:将文本块(原数据)和它们对应的向量保存到专用的向量数据库中。向量数据库针对高维相似度搜索(如计算余弦相似度)进行了极其深度的优化。 + **主流技术方案**: - **专用向量库**:Milvus(开源、适合大规模)、Pinecone(SaaS,全托管)、Qdrant、Chroma(适合轻量级/本地开发)。 - **传统数据库扩展**:Elasticsearch(Dense Vector)、PostgreSQL + PgVector、Redis。 ### 第二阶段:在线检索生成 (问答) 当用户提出问题时,系统会实时处理问题,去第一阶段建好的库中找答案,最后让大模型总结。 #### 4. 相似度检索 (Retrieval) + **具体实现**:把用户提出的自然语言问题,用**同一个 Embedding 模型**也变成向量。然后在向量数据库中寻找与“问题向量”距离最近的 Top-K 个“文档向量”,提取出对应的文本块。 + **主流技术方案**: - **检索算法**:HNSW(层级导航小世界算法,目前最主流的近似最近邻搜索算法)。 - **高级检索技术 (Advanced RAG)**:混合检索(Hybrid Search,即向量检索 + BM25 关键词检索)、重排序(Re-ranking,使用专门的交叉编码器模型如 BGE-Reranker 对召回的结果重新打分排序)。 > **检索算法详解:** > > ### 1. HNSW 算法 > > 在向量数据库中,面对千万级甚至亿级的文本向量,如果我们拿着用户问题的向量去和库里的向量挨个计算距离(暴力搜索/KNN),速度会慢到无法忍受。HNSW 就是目前最主流的**近似最近邻(ANN)搜索算法**,它在查询速度和召回率之间做到了极佳的平衡。 > > + **实现原理**: > - **跳表 (Skip List) 思想**:HNSW 构建了一个多层的图结构。最上层极其稀疏,只有少数几个节点(向量);越往底层节点越密集,最底层包含所有节点。 > - **导航小世界 (NSW)**:在每一层里,相近的向量会相互连接成图。 > - **检索过程**:搜索时从最顶层开始,快速跳跃到大概的区域(粗筛),然后进入下一层继续寻找更近的节点,不断向下“钻取”(Zoom in),直到最底层找到距离最近的 Top-K 个向量。这就像你找一个人:先定省份(顶层),再定城市(中层),最后定街道(底层)。 > + **技术实现方案**: > - 在业务代码中,我们**通常不需要手写 HNSW 算法**,因为它已经内嵌在所有主流向量数据库(如 Milvus、Elasticsearch、Qdrant)的底层引擎中了。 > - 我们需要做的是在**创建索引**时,配置 HNSW 的核心参数: > * `M`:每个节点在图中最多保留的连接数(通常设为 16-64)。M 越大,召回率越高,但内存消耗和构建时间也越大。 > * `efConstruction`:建库时用于搜索的候选节点数量。越大图质量越高,建库越慢。 > * `efSearch`:查询时搜索的候选集大小。越大查询越准,但速度越慢。 > > ### 2. 混合检索 (向量 + BM25) > > 单纯的向量检索擅长理解“语义”。比如搜“苹果手机”,它能找出“iPhone”的文档。但它**不擅长精确匹配**,比如用户搜特定的专有名词、订单号、错误代码时,向量检索常常会“翻车”。 > > + **实现原理**: > - **双路召回**:系统同时执行两种查询。一路执行**向量检索**(捕捉语义),另一路执行传统的 **BM25 关键词检索**(类似于 ES 的倒排索引,捕捉字面精准匹配和词频)。 > - **结果融合 (RRF)**:由于向量的得分(如 0.85)和 BM25 的得分(如 15.2)完全不在一个维度,无法直接相加。业界通用的融合算法是 **RRF (Reciprocal Rank Fusion,倒数排名融合)**。它不看绝对得分,只看两路结果的排名。 > - RRF 的计算公式为:RRF_score = 1/(k + rank<sub>vector</sub>) + 1/(k + rank<sub>keyword</sub>)(其中 k 常设为 60)。 > + **技术实现方案**: > - Elasticsearch 8.x 版本原生支持了完整的混合检索和 RRF。 > - Milvus v2.4+ 也引入了 BGE-M3 等支持稀疏向量的混合搜索能力。 > ### 3. 重排序 > > 即使是混合检索,为了保证速度,其计算模型依然是相对“粗糙”的(称为双编码器 Bi-encoder:问题和文档分别计算向量再点乘)。大批量的文档被召回后,里面通常会夹杂大量看似相关实则无关的“噪音”文本。 > > + **实现原理**: > - 我们引入一个更慢、更消耗算力,但**极其精准的交叉编码器模型 (Cross-encoder)**。 > - 重排序模型会将“用户的原始问题”和“初筛召回的一个个文档块”**拼接在一起**同时输入神经网络。这样模型就能在底层运用自注意力机制(Self-Attention)去逐字比对问题和文档的逻辑关系,输出一个极其精确的相关性得分(0~1)。 > - **流程**:混合检索粗筛出 Top 50 结果 -> 送入 Re-ranker 模型打分 -> 重新排序 -> 取前 5 个真正相关的送给 LLM。 > + **技术实现方案**: > - **主流重排模型**:Cohere Rerank 3(API调用,效果极好)、BGE-Reranker-Large(开源,常配合本地 GPU 或 Ollama 部署)。 > > ### 总结串联 > > 在生产级别的 RAG 系统中,这三者的配合流程通常是: > > 用户提问 ➡️ **混合检索 (BM25 + HNSW向量检索)** 初筛出 50 篇文档 ➡️ **RRF 算法**融合排名 ➡️ **重排序模型**进行精细打分 ➡️ 提取 Top 5 给大模型生成。 #### 5. 提示词增强与生成 (Prompting & Generation) + **具体实现**:将用户的原始问题,以及我们刚刚从数据库里捞出来的“参考答案(Context)”,一起塞进一个精心设计的 Prompt 模板中,发送给 LLM。LLM 基于这些参考信息,生成最终的准确回答。 **Java 代码示例**: ```java import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.model.openai.OpenAiChatModel; // 初始化聊天大模型 ChatLanguageModel chatModel = OpenAiChatModel.builder() .apiKey("YOUR_API_KEY") .modelName("qwen-max") .build(); // 构建 Prompt:结合检索到的上下文和用户问题 String promptTemplate = "你是一个 AI 助手。请仅基于以下提供的背景信息来回答用户的问题。\n" + "如果背景信息中找不到答案,请诚实地回答'我不知道',不要编造信息。\n\n" + "背景信息:\n%s\n\n" + "用户问题:%s"; String finalPrompt = String.format(promptTemplate, context, userQuery); // 调用大模型生成最终回答 String response = chatModel.generate(finalPrompt); System.out.println("AI 回答: " + response); ``` ### 总结 完整的 RAG 就是:**加载切分 -> 向量存储 -> 用户提问 -> 向量检索 -> 组装 Prompt -> 大模型生成**。 上面展示的是最基础的 Naive RAG(朴素 RAG)。在实际生产中,为了提高准确率,通常还会引入 **Query Rewrite(问题重写)**、**Re-rank(重排)** 或 **GraphRAG(知识图谱结合)** 等进阶技术。

Cline 配置 MiniMax Coding MCP

我们这里使用的编程工具是 Cline https://cline.bot/ # 配置 UVX 1、在 Windows 执行: ```powershell powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" ``` 2、在对应的代码目录执行: ``` (Get-Command uvx).source ``` ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/IpNmeKAYFOJbmSJ4.png) # 添加 MCP > MCP 官方文档:https://platform.minimaxi.com/docs/guides/coding-plan-mcp-guide#%E5%B7%A5%E5%85%B7%E8%AF%B4%E6%98%8E 1、选择配置: ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/Ej1gRN4CFOnAqxC3.png) 2、选择 Configure 点击 Configure Mcp Servers : ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/h9ZYHOEecoOkBH4K.webp) 配置下面的信息如下: > 下面的 MINIMAX_API_KEY 替换成自己的 coding plan 的 key https://platform.minimaxi.com/user-center/payment/coding-plan ```json {   "mcpServers": {     "MiniMax": {       "command": "uvx",       "args": [         "minimax-coding-plan-mcp"       ],       "env": {         "MINIMAX_API_KEY": "sk-cp-xxx",         "MINIMAX_API_HOST": "https://api.minimaxi.com",         "MINIMAX_API_RESOURCE_MODE": "local"       },       "autoApprove": [         "web_search",         "understand_image"       ]     }   } } ``` 3、可以发现 MCP 识别到了: ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/7InNHTQO02I9RZR2.webp) 4、测试 MCP: ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/xcDhuh3DVXfrc49j.webp) ![image.png](https://pic.code-nav.cn/post_picture/1608460212774109186/bVzYY76h3hbdh9e3.webp)

这就是 Tool Calling 与 MCP

# 写在前面 学完鱼皮的 LangChain4j 教程的 Tool Calling 与 MCP 啦,我结合我在 b 站上看到的不少相关科普视频与自己的理解,系统梳理了这篇学习笔记,希望能对初学这两个概念的同学有所帮助~ # Tool Calling ## 面向的问题 尽管目前的 LLM 具备较强的自然语言理解与推理能力,但它本身**无法直接与外部世界进行交互**,例如无法执行数据库查询、接口调用等操作。 假如你问 AI:“贵阳市花溪区今天的天气如何?”,作为人类,我们的第一反应通常是打开天气类应用查询最新的天气信息。 从逻辑上看,AI 在回答这类问题时也应该先获取最新的天气数据,但实际上,AI 本身并不能主动完成这样的操作。 **能不能让 AI 在需要的时候,借助外部工具获取所需信息?** 这便是 Tool Calling 这个技术要解决的核心问题。 ## 核心思想与基本流程 **Tool Calling 是一种允许 AI 在推理过程中借助外部工具来完成任务的机制。** 其核心思想是:当 AI 在生成回答的过程中发现自己无法获取所需信息或完成某个操作时,它会请求可用的外部工具,并基于返回结果继续推理和回答。 在这个过程中,AI 负责判断和决策,例如是否需要借助外部工具以及如何利用返回结果继续推理;具体的执行操作,如信息查询和接口调用,则由外部系统完成。 Tool Calling 将“思考”和“执行”清晰地分离开来:AI 负责理解问题和做出决策,外部工具负责完成真实的操作;AI 基于这些操作结果生成回答。 <br> 使用了 Tool Calling 技术的 AI 应用通常会按照如下流程运行: 首先,应用需要提前为 AI 准备好可用的工具,并明确每个工具的用途以及期望的参数形式。 这些信息会作为上下文的一部分提供给 AI,使其了解当前可以使用哪些外部能力。 当用户提出问题后,系统会将用户问题与工具信息一并发送给 AI。 AI 在理解问题的过程中,会判断是否需要借助某个工具来获取信息或完成操作。 如果 AI 判断需要使用工具,它会向系统返回一个“工具调用请求”,其中包含所选择的工具以及对应的参数。 随后,系统根据该请求实际执行相应的工具,并将工具的执行结果再次发送给 AI。 AI 则基于这些结果继续进行推理,并生成最终的回答。 <br> # MCP ## 面向的问题 随着 Tool Calling 的引入,**工具逐渐成为 AI 应用中不可或缺的一部分**。 一些工具具有较强的通用性,例如网页检索、文件操作、图像识别等,往往需要在多个 AI 应用中重复使用。 如果将这些工具直接写在各个 AI 应用内部,很容易造成重复实现,也增加了工具维护和演进的成本。 从更长远的角度看,随着 AI 应用数量的增加,工具本身也逐渐演变为一种独立的能力,而不再只是某个应用内部的附属代码。 那么,**能不能将这些通用工具从具体的 AI 应用中抽离出来,作为独立的服务统一提供,而 AI 应用只需要通过一种标准方式与这些工具进行交互?** 这正是 MCP 这个技术要解决的核心问题。 ## 核心思想与基本流程 **MCP(Model Context Protocol,模型上下文协议)是一种用于规范 AI 应用与外部工具服务之间交互方式的协议。** 其核心思想是:当工具以独立服务的形式存在时,需要一种统一的方式,使 AI 应用能够发现、理解并使用这些工具。 在 MCP 的完整架构中,涉及三个核心角色:**MCP Host、MCP Client 与 MCP Server**。 其中,**MCP Host** 是 AI 应用本体,负责整体流程的协调与决策,例如管理多个 MCP Client、组织上下文,并将结果交由模型进行推理或生成回答。 **MCP Client** 是 MCP Host 内部用于与工具服务交互的组件,负责维护与 MCP Server 的连接,并从 MCP Server 获取工具描述和执行结果,供 MCP Host 使用。 **MCP Server** 则是工具能力的提供方,负责对外暴露可用工具的描述信息,并在收到工具调用请求时实际执行相应的工具操作。 <br> 在实际使用中,MCP Host、MCP Client 与 MCP Server 之间的协作流程通常如下: 首先,MCP Host 会配置并管理一个或多个 MCP Client,使其能够访问对应的 MCP Server,从而获取当前可用的工具信息。 当 MCP Host 判断需要使用某个工具时,会通过相应的 MCP Client 向对应的 MCP Server 发起工具调用请求。 随后,MCP Server 执行相应的工具操作,并将结果返回给 MCP Client。 MCP Client 接收结果后,将其传递给 MCP Host,由 MCP Host 将其纳入上下文并交由 AI 进行进一步推理或生成回答。 <br> 通过这种方式,MCP 将**决策、连接与执行**清晰地分离开来:MCP Host 负责整体流程的调度与协调,组织上下文并驱动模型进行推理;MCP Client 负责与工具服务交互,而 MCP Server 专注于提供和执行具体的工具能力。 <br> ## 相关资源 [MCP Servers](https://mcp.so/servers?tag=featured) 这个网站收录了很多实用的 MCP Server,你可以根据需求选择合适的 MCP Server,并结合对应文档将其集成到自己的 AI 应用中,以扩展工具能力。

服务器购买 网站部署 SSL证书

记录一下上线服务器的过程,可以给第一次接触过的学友们一些参考。 ## 一、购买服务器 像阿里云、华为云、腾讯云,都有**100/年**以内的**2核2G**的服务器,作为个人学习,给面试官浏览,都足够了。 个人也推荐整一台服务器自己玩,在上面学习linux命令、装点稀奇古怪的东西都是可以的,重置系统也很方便,所以不用担心会玩坏服务器。 各个云服务商是差不多的,这边我用腾讯云举例。 登录腾讯云后,找到轻量云服务器,可以看到这个配置的服务器 **购买和续费**都是79/年,几顿饭钱的事,买! ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/qbbhO5CHcqZQfVFq.webp) 有境外需求的(代理服务器等),可以买这个(续费不同价)。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/kqkt5x5gzVpjdNK4.webp) 直接购买就行了,这里我买的是境外的,国内的步骤也一样。 都买服务器了,还是推荐linux,性能和方便程度都大于windows。而且windows各位应该都精通了。 这个宝塔面板是基于OpenCloudOS 9操作系统,腾讯云自己做了一个带一些功能的镜像。这个可选可不选,后边可以随便换其他的镜像。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/LMPf3Gj3sXDXfCtT.webp) 下一步 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/yUkuhQOisu4JPPqx.webp) 付款完后就算购买完成了、点查看实例。(可以自己看看实例有哪些信息) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/TYr0bIxPijaIBVbT.webp) ## 二、使用服务器 ### 1. 重装系统 购买完之后,点击实例,可以看见服务器的详情。 往下翻,可以看到重装系统,这个可以无限重装,我这边换个干净一点的系统。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/mXdAWYFlGbSETaRx.webp) 我这边选择ubuntu24.04版本,输完密码后点确认。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/WOu4JEUzajZP5gYW.webp) ### 2. xshell 连接服务器 官网下载免费版本xshell,安装。 https://www.xshell.com/zh/free-for-home-school/ 新建会话 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/FlBHTLbyKQdcsOqK.webp) 输入服务器IP ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/lWfSGS6qYUhUwuRt.webp) 输入登录用户和密码、点连接 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/kJAommCNWAuvy1Sy.webp) 保存密码 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/sHqKwF5J5tPXNFjN.webp) 成功连接 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/3VbgsSt9Wa3YF8mJ.webp) 之后可以通过xshell操作服务器了。 腾讯云也有类似操作服务器的方式,但是腾讯云需要先登录,才能操作,xshell可以直接连。 ## 三、部署服务器 ### 1. 宝塔 部署网站 #### 安装宝塔 https://www.bt.cn/new/download.html 直接复制**对应系统**的安装命令,到xshell中执行。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/6GDe9VXX6hPUIJ78.webp) 下一步 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/njTN25vzzZZH5UoJ.png) 安装完成后,会显示访问宝塔面板的地址和用户密码 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/yRnihACGKzI5OErs.png) 不小心忘了也没事,输入`sudo bt`,再输入`14`,就能看见了。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/nyqqNcn66hYMhy8P.webp) #### 登录宝塔 访问宝塔面板的外网面板,我这边访问失败了,因为访问的是12020端口,云服务商这边的端口防火墙没有打开。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/wWHdj66eQrs1FGjj.webp) 这边防火墙开放的端口有这些 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/WthmKgMquyM1HZce.webp) 可以选择在这里放行12020端口,也可以更改宝塔的面板端口,这里我把bt的端口改成8888了。修改命令是 ``` sudo bt 8 8888 ``` ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/oW7ay4tOYv9p3iWz.webp) 再次访问面板8888端口 安全模式会变更访问地址,普通模式不会变更。选哪个都无所谓 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/MSMgIedbb54YcD1Q.webp) 进去选LNMP 一键安装 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/pxafLzLIgEcml7Vl.webp) 安装完成 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/1NmNENfq8nUsWwJg.webp) #### 创建站点 点击添加站点 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/IK3Uv4gnl2vLimcf.webp) 输入完域名、点击确定 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/GYBJXLceOPCyVLTZ.webp) 点击设置 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/dMTh80wLKm6LlBbG.webp) 点击网址 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/SwlfcLHK01hp6rJ4.webp) 简单的网点就创好了 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/X4WN4yuBkUSX4EdM.webp) 在网站根目录 上传自己打包后的前端文件 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/gHXeyJfuAc1zx4te.webp) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/7qbaj69VZRIrzN62.webp) 再刷新刚刚的网址,可以看到网址能正常跑了 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/iTDxANMC2keUvBQD.webp) #### 域名 去腾讯云官网 输入想要的域名,和后缀(字数越多、越冷门越便宜)。一般来说,10多块钱就能拿到自己名字相关的域名。长期使用的话,建议买.cn后缀的,续费便宜。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/drebP81gqt1AyeDQ.webp) 购买和备案一套流程有点繁琐,这边就不演示了。 备案结束后,域名解析一下服务器的ip,这样所有写ip的地方都可以替换为域名。比如上面写的网站地址可以改成域名。 ## 四、SSL证书 目前的网站是http协议的,在某些网络下会被认定为不安全导致无法访问。另外,https网站在SEO搜索引擎的权重更高。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/BRkhUHkopeo5gOkH.webp) 想要换成更安全的https协议,需要**SSL证书**才行。因为SSL证书是针对**域名**的,所以域名也要有。我这里用阿里云申请发的域名(腾讯云更方便)。 #### 申请SSL证书 腾讯云搜索SSL,进入SSL证书页面,点击申请免费证书。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/66rnqIhMQ9PqYzJg.webp) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/ODAjp1b8cvTc7LJh.webp) 输入对应域名后,直接点确认 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/ESSaP9K8rCzJGTHk.webp) 去购买域名的服务商那里,域名解析处添加一条解析 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/Ey7WnrnR5Gx7SchR.webp) 我这边用的阿里云域名,红框中是重点 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/IVzAoQfLzvWkCMZr.webp) 解析完成后,回到腾讯云,点击验证,会显示成功。这里可以点击自动续费证书,如果域名是腾讯云的,会完全自己续期。非腾讯云域名,需要手动填解析值。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/mE7xhfKY3T57OUGF.webp) #### 下载证书 证书需要上传到服务器文件,先下载,这里选择nginx,因为刚刚部署方式就是nginx ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/ACMsNQhBqddAxHhP.webp) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/EvFn0RnGa3rv4Igz.webp) 下载完解压,得到pem和key文件 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/Qv3WG3r2BShHAmNv.png) #### 上传证书 点开宝塔站点,将pem和key文件中的内容完整的copy进去。点保存。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/oB9x4EwveDyaoDHf.webp) 现在这个SSL证书已经绑定了这个域名,现在来测试一下域名访问。 #### 使用SSL证书 **域名要先绑定IP!!** 想要输入域名访问服务器,首先要让域名和服务器IP绑定,也就是域名解析。 阿里云域名为例 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/nZrwWnKGnyDOh8kI.webp) 在上传完后,宝塔其实已经帮我们配置好了SSL证书。 我们只要在站点中添加刚刚设置的域名 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/rraJxMehMwKdXHX9.webp) 现在访问以下两个网址,都是能够访问当前站点的。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/bx6nFwJxUnaXxnBy.webp) 在**无网络限制的环境**下,没有SSL证书,不管是IP或者是域名都是可以直接访问的。 在**有网络的限制**下,比如公司环境,IP就不能直接访问。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/VM7aMXP68V6m9oyA.webp)

centos7上coturn服务启动后无法访问的故障处理

### 提问背景 我正在开发webrtc的视频通话功能,建立P2P的连接需要搭建stun/turn服务器,于是我在阿里云centos7服务器上利用coturn在3478端口启动了该服务,但是在测试时发现服务不可用。 ![微信图片_20251115231728_177_1.png](https://pic.code-nav.cn/post_picture/1989882834701107201/KmWrvmgc8hUm3VTc.webp) ![image.png](https://pic.code-nav.cn/post_picture/1989882834701107201/YeJ3QoLPiAcnMR9G.webp) ### 尝试解决 ##### 一开始,我以为是端口未开放的问题,于是我在安全组设置了入方向和出方向的端口对全部流量进行全部开放,并且关闭了防火墙的限制,但是依然没有用。 ### 详细信息 启动命令 ```js /usr/local/turnserver/bin/turnserver -v -r 47.94.53.126 -a -o -c /usr/local/turnserver/share/examples/turnserver/etc/turnserver.conf ``` 具体配置 ```js listening-port=3478 listening-ip=172.18.61.183 tls-listening-port=5349 # TLS 加密端口 cert=/ssl/cert.pem pkey=/ssl/cert.key external-ip=47.94.53.126 user=user:654321 realm=47.94.53.126 lt-cred-mech relay-ip=0.0.0.0 # 至于为什么配置relay-ip=0.0.0.0 ?? # 因为我尝试填写了内网ip或外网IP,但都无效 min-port=49152 max-port=65535 verbose log-file=/var/log/turnserver.log ``` 部分日志 ```js 696: session 001000000000000010: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 696: session 001000000000000011: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 706: session 001000000000000010: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 706: session 001000000000000011: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 716: session 001000000000000010: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 716: session 001000000000000011: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 726: session 001000000000000010: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 726: session 001000000000000011: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 736: session 001000000000000010: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 736: session 001000000000000011: realm <47.94.53.126> user <user>: incoming packet BINDING processed, success 743: session 001000000000000010: refreshed, realm=<47.94.53.126>, username=<user>, lifetime=0 743: session 001000000000000010: realm <47.94.53.126> user <user>: incoming packet REFRESH processed, success 743: session 001000000000000011: refreshed, realm=<47.94.53.126>, username=<user>, lifetime=0 743: session 001000000000000011: realm <47.94.53.126> user <user>: incoming packet REFRESH processed, success 744: session 001000000000000010: usage: realm=<47.94.53.126>, username=<user>, rp=22, rb=1160, sp=22, sb=1888 744: session 001000000000000010: closed (2nd stage), user <user> realm <47.94.53.126> origin <>, local 172.18.61.183:3478, remote 36.112.200.70:30675, reason: allocation timeout 744: session 001000000000000010: delete: realm=<47.94.53.126>, username=<user> 744: session 001000000000000010: peer 172.17.0.1 deleted 744: session 001000000000000010: peer 36.112.200.70 deleted 744: session 001000000000000010: peer 10.24.68.63 deleted 744: session 001000000000000010: peer 47.94.53.126 deleted 744: session 001000000000000011: usage: realm=<47.94.53.126>, username=<user>, rp=22, rb=1160, sp=22, sb=1888 744: session 001000000000000011: closed (2nd stage), user <user> realm <47.94.53.126> origin <>, local 172.18.61.183:3478, remote 36.112.200.70:30676, reason: allocation timeout 744: session 001000000000000011: delete: realm=<47.94.53.126>, username=<user> 744: session 001000000000000011: peer 172.17.0.1 deleted 744: session 001000000000000011: peer 36.112.200.70 deleted 744: session 001000000000000011: peer 10.24.68.63 deleted 744: session 001000000000000011: peer 47.94.53.126 deleted ``` 使用lsof命令查看端口信息 ```js [root@iZ2zeh5hzhg0kgjwdxkm9cZ ~]# lsof -i :3478 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME turnserve 27441 root 17u IPv4 25694475 0t0 TCP iZ2zeh5hzhg0kgjwdxkm9cZ:stun (LISTEN) turnserve 27441 root 20u IPv4 25693882 0t0 TCP iZ2zeh5hzhg0kgjwdxkm9cZ:stun (LISTEN) turnserve 27441 root 22u IPv4 25693885 0t0 UDP iZ2zeh5hzhg0kgjwdxkm9cZ:stun turnserve 27441 root 23u IPv4 25693886 0t0 UDP iZ2zeh5hzhg0kgjwdxkm9cZ:stun ```

AI精准提问手册:从模糊需求到精准输出的核心技能(上)

## 导言:为什么精准提问是AI时代的核心素养? AI发展速度迅猛,转折点来自2022年11月30日正式发布的 ChatGPT-3.5 产品,从该节点开始,AI时代正式到来,走入到千家万户。ChatGPT 无愧它划时代产品的称呼,发布仅5天,用户数突破100w,两个月内的月活跃用户达到1亿,成为历史上增长最快的消费级应用。 ChatGPT 后续迭代的 GPT-4,GPT-4o 及多个版本并没有突破原有的AI使用规则。更扩大范围的去看待,所有的AI产品,使用规则都是极其相似的,包括 ChatGPT 之后所出现的 Gemini、Claude、DeepSeek 等多个产品。 那么,AI的使用规则到底是什么?这需要从 ChatGPT 的性质说明,ChatGPT 是对话式AI的里程碑,真正实现了人机对话。而涉及到对话(沟通交流),最核心的能力在于让对方理解我所想表达的真实需求。沟通的精准性决定了沟通的质量,哪怕是对话式AI也无法逃脱这一规则。 因此精准提问是AI时代下,最核心的能力之一。这意味着我们需要足够了解自己,足够清楚自己的目的以及足够的表达能力。 ### AI的强大与局限 从AI吸收了整个世界的所有知识那一刻开始,就注定了AI的强大。按逻辑而言,集齐全世界的精华知识,AI在所有领域的回答水准会始终保持在人类的巅峰,但事实并非如此。AI时常会出现语无伦次或者回复内容与用户提问毫无联系,因为AI在吸收人类文明最重要知识的同时,也同时吸收了大量糟粕。大量知识的混乱,观点之间的冲突,不同认知层次对同一问题的看法,都在考验AI,因此我们可以认为AI在以上情况下,是一个矛盾体(与人类性质完全契合,折射了人类知识体系本身的复杂性与分裂)。 AI作为矛盾体,回答问题时也是矛盾的,例如:用户问“什么是爱情”,小学生需要童话式解释,诗人需要隐喻,哲学家需要本体论讨论。AI会根据用户提问中的关键词自动匹配认知层级,但常错判抽象概念,这正是矛盾性的体现——它知道所有答案,却不知道哪个答案最适合当前的人类。因此AI永远不能替我们做出选择,它并不了解提出当前问题的当前人类。 以上即说明了AI作为工具的本质与“垃圾进,垃圾出”原则,绝大多数情况下,给出"垃圾"的问题,就会得到"垃圾"的回答。由于AI本身性质,哪怕是"垃圾"的回答,也会显得非常有逻辑条理,即头头是道的胡说八道,例如编造不存在的参考文献。 ### “精准提问”的定义 精准的提问不仅仅是技巧,更是思维方式和沟通艺术。 从“垃圾进垃圾出”原则反推:精准提问的本质是输入质量控制,定义应强调“降低信息噪音”。通过收束提问信息,进而收束AI反馈结果的范围。 我认为,精准提问需要具备以下3个核心要素: (1)概念收束。将AI从各种矛盾观点中解放出来,能极大幅度的提升AI回复的质量,未明确指定视角概念时,AI默认用户输入内容正确为出发点进行推理,然后发散性的去进行回复,内容深度精度会大幅度下降。 (2)需求洞察。需要剥离模糊表述,所有宽而泛的内容,都应该去除,避免水字数。声明需求层次,让AI明确它所需要解释的对象是谁(例如:小学生、初中生、高中生、大学生),越明确自身实际所处认知阶段,AI所给出的结果越契合用户理解。从而将抽象知识转化为适配当前场景且易于自身理解的解决方案。 (3)边界能力。除了对自身的认知,还需理解AI的能力边界。AI擅长推理,不擅长情感,我们使用AI时需要扬长避短。推理是严谨明确的,而情感的矛盾且混沌的。同时利用AI的知识整合能力,绕过AI的主观判断,更多将其当作工具使用,而不是决策者。 AI不擅长情感,不代表不能输出优美的情感语句,而是不易产生共鸣,所有的情感表达都需要契合对应的应用场景才能爆发强大的威力,AI的情感表达是独立于场景的,优美但只适应通用场景。 想得到一个契合的答案是困难的。站在AI的视角中,它需要满足以下3个条件才能给出完美的答案: (1)掌握自身水准(完全符合)。 (2)掌握对方水准以及客观实际的真实情况(取决于用户)。 (3)掌握正确的解决方案,根据自身理解以及对方具体情况,针对性微调(取决于调用知识库)。 这个世界上没有通用的解决方案,所有走通,看似正确的道路,都只适合开辟这条道路的人。后来者不一定具备前者的强素质,邯郸学步只会贻笑大方,完美的计划需要完美的执行力去适配。 ### 精准提问带来的价值 精准提问能给我们带来哪些价值? 我认为主要有4点:效率提升、深度洞察、创意激发、错误减少。 (1)效率提升是最明显的收益。精准提问首先减少提问的迭代次数,模糊问题平均需多3-5轮追问修正(例如“帮我写文案”→“什么产品?→目标人群?→卖点?”)。需要注意:追问修正技巧非常重要,将大需求拆解为小要点进行提问,所得精准度会大幅度提升。我们需要做的是,在合理范围内缩减不必要的追问修正次数,不在同一问题上重复修正提问。 (2)深度洞察是最重要的收益。AI的优势来自严谨的推理链,推理能得到很多潜藏于表面之下的深层信息,而这类信息通常直击行业、社会、国家、世界运行的底层规律。理解底层规律信息,能有效地提升认知水平,且容易看到问题产生的本质原因。 (3)创意激发来自AI的资源整合。从互联网的信息海洋中抓取各种不同视角、不同行业的信息,信息知识的碰撞更容易产生新的创意,站在多个视角下更容易发现需求。该原理来自跨学科思考,利用完善的行业降维打击初期迭代的行业。 (4)错误减少为AI的幻觉率降低。防御AI的三大陷阱:事实幻觉、逻辑谬误、认知偏差。 ​ 事实幻觉:需要锁定AI的信息来源,避免AI编造相关的政策细节。 ​ 逻辑谬误:需要AI给出推理过程,例如展示三步归因过程,从而避免“相关即因果”错误。这是一种经典的逻辑谬误,指错误地将两个事物的相关性(伴随发生)等同于因果关系(一个事件导致另一个事件)。这是AI和人类都极易掉入的思维陷阱,尤其在数据分析中危害极大。在我阅读《社会心理学》第11版时,书中就重点强调了"相关即因果"的危害性,举例了: “穿名牌的学生成绩更好 → 错误归因‘穿名牌提升成绩’(忽略家庭资源因素)”的佐证。 ​ 认知偏差:需要多视角验证结论,纠正AI单一立场的倾向(AI默认用户立场,例如用户认为这件事情不好,AI就会直接假定这件事情不好为立场),而不能多角度思考,往往会令观点走向极端化。 ### 本手册目标 本手册的目标为掌握提问的系统方法论,令我们成为驾驭AI的“超级提问者”。从而超越简单的“提问模板”(即基础的Prompt提示词工程),而是**系统性思维模式与认知能力**的体现。 该小册分为六大节内容,分别为: (1)认知篇 - 理解AI的“思维”与提问的本质。 (2)准备篇 - 提问前的关键思考。 (3)技巧篇 - 精准提问的核心方法论 (提问工程精髓)。 (4)实战篇 - 不同场景下的精准提问策略。 (5)优化篇 - 评估、迭代与提升。 (6)进阶篇 - 提问心理学与未来展望。 AI的到来是势不可挡的,我们应该展望人机协同的智能未来,而非如同历史中砸毁珍妮机的工人。《2001太空漫游》开头那个著名的蒙太奇镜头--猿人掷出骨棒切到太空船的镜头,这寓意着人类工具的进步。而AI未必不是另一个由人类掷出的骨棒。 ## 第一部分:认知篇 - 理解AI的“思维”与提问的本质 ### 1.1 窥视“黑箱” 我们需要打开"AI思考"的这一黑箱,深入AI如何理解和处理我们的问题。 大型语言模型(如ChatGPT/DeepSeek-R1)处理问题的本质是**基于统计的模式预测**,而非真正的“理解”。从文字到智能,通过以下3点实现飞跃: (1)数字ID:让机器认识“词”。 (2)向量嵌入:让机器理解“词义”。 (3)注意力机制:让机器把握“上下文关系”(如“苹果”在“吃”和“股票”前的不同含义)。 #### 1.1.1 数字ID 将用户输入的问题拆解为最小单位(如“精准提问”→ [“精”,“准”,“提”,“问”]),每个词对应一个数字ID。每个词转换为768~12288维向量(如“苹果”= [0.24, -0.17, ..., 0.83]),用于捕捉语义关联。 因为计算机无法直接处理文本(只能计算数字),所以必须将词拆解为最小单位后,分配对应数字ID。而数字ID建立词表映射关系,类似用学号指代学生。建立映射表是为了实现转换,即把AI回复的内容从数字ID转回文字进行输出(机器可计算→人类可读的双向转换)。 每个词对应的数字ID是固定的,统一标准,避免一词多义的混乱。且用数字ID替代字符串能极大降低内存占用。 并且数字ID是唯一连接机器计算与人类语言的桥梁,模型无法直接输出文字(神经网络仅处理数字)。 #### 1.1.2 向量嵌入 那为什么拥有数字ID后,每个词还需要转为维向量?因为数字ID存在无法表达语义关系的致命缺陷,而表达语义关系是对话式AI的核心。高维向量表达如下案例所示: ```js // 每个词转换为高维向量(如300~12288维) “国王” = [0.21, -0.53, 0.78, ..., 0.02] “王后” = [0.19, -0.51, 0.75, ..., 0.01] “苹果” = [-0.33, 0.28, -0.04, ..., 0.67] ``` 通过向量距离计算语义关联(权重值): ```js distance(国王, 王后) = 0.08 # 很小 → 语义相近 distance(国王, 苹果) = 1.37 # 很大 → 语义无关 ``` #### 1.1.3 注意力机制 但完成通过向量距离计算语义关联并非结束。还需要根据维向量所计算出来的语义关联结论,进行捕获上下文,从而一步步推出下一个词是什么,最终组成完整的句式。 将分词后的向量按顺序拼接为矩阵:[精] + [准] + [提] + [问] → 矩阵X。实现注意力权重分配,即计算词与词之间的关联强度(例:`提`与`问`权重最高,组合为“提问”这个语义单元)。 ```js 精:权重0.1 准:权重0.3 提:权重0.8 → ┐ 问:权重0.9 → ┘ [强关联对] ``` 通过加权平均所有输入向量,生成代表当前语义的上下文向量:C_t = 0.1×[精] + 0.3×[准] + 0.8×[提] + 0.9×[问]。将“精准提问”从四个独立词融合为单一语义实体(类似人脑理解短语),C_t即单一语义实体,t含义为独立词数量。 然后基于 C_t 预测可能的后继词概率分布: ```js 需要:概率 38% 的:概率 25% 方法:概率 17% ...(其他词概率<5%) ``` 按概率选择“需要”→ 添加到输出序列:`[精准提问][需要]`。将新词“需要”向量加入,重新计算上下文向量 `C_{t+1}`,循环迭代直至完成,最终生成所需内容。按概率采样即按比例进行随机分配,加入随机性避免机械回复,因此哪怕每次输入同样的问题,给出的回复都是不会完全一致。 ```js 新输入:[精][准][提][问][需要] 新权重:聚焦“提问需要”组合(如“需要”权重0.95) ``` 我们可以通过1.1.3小节的注意力机制发现:文字必须逐渐生成,这是语言模型的本质限制。LLM是基于上文预测下文的统计模型(类似超强版输入法联想),无法一次性输出长文本。若试图直接生成完整句子,需同时计算所有词组合概率(10个词有100亿种可能),算力不可行。且每个新词会改变语义重心(例:“提问”后接“技巧”vs“误区”,将导向完全不同路径)。 因此LLM虽然通过向量计算语义关联,实现“理解”假象,但缺乏真正规划能力,只能走一步看一步,存在本质矛盾。所以**精准提问的价值在此凸显**,明确的指令→ 为模型提供路线图,减少预测路径分支。限定范围(如“仅谈前端JS场景”)→ 缩小向量搜索空间,避免偏离。 导言中“精准提问是AI时代核心素养”——实则是**用人脑的全局规划弥补机器的局部视野**。 数字ID和向量嵌入实现了智能计算,而注意力机制和数字ID实现生成文字让人理解。 (1)编码方向:文字 → ID → 向量 → 智能计算。 (2)解码方向:概率分布 → 新ID → 文字 → 人类理解。 这种设计使AI既能咀嚼数字,又能吐出诗文。而精准提问的价值,正是通过优化输入端的ID序列质量(如明确指令减少歧义ID),最终获得输出端更精准的ID→文字转换结果。 #### 1.1.4 深度思考 2023年6月,Claude 2 成为首个在应用层明确显性使用深度思考模式的AI产品。而深度思考是当前大语言模型(LLM)最前沿的探索领域。该能力可以极大幅度的提升AI回复的内容质量,其核心原理在于突破概率贪婪陷阱(优先选择概率更高的词汇)。 (1)普通模式:选择局部最优词。 (2)深度思考:强制探索全局最优路径。 深度思考模式在一定程度上模拟了1.1.3小节说明的人脑全局规划,因此深度思考模式能在一定程度上获得精准提问的部分收益(这里不再提及具体收益,详见导言中 精准提问带来的价值 )。 深度思考模式中较为显性的收益为幻觉减少,这得益于深度思考会拆解问题,将要素拆分成多个步骤组成思维链,每个步骤都会与下个步骤进行错误检测,看前后步骤是否矛盾,若矛盾则触发自我修正机制。 因此我们能够得出一个较为残酷的真相,LLM模型永远无法真正”理解”文字。 深度思考本质上只是更高级的模式匹配,主要存在以下3重理解力鸿沟,分为以下3步骤: (1)匹配知识库中的相似问题。 (2)复制高赞回答的解题框架。 (3)替换解题框架中的具体内容。 根据以上信息,我们能得出深度思考在更需要思维逻辑的领域会有更高的提升,且经过深度思考所返回的内容特别喜欢分点作答的原因也得以突出。 深度思考更多的是工具革命,通过算法强制分布推演,将LLM模型的潜力释放到极致,使回答质量飙升。但当前LLM模型的”思考”本质依旧是符号关系的拓扑重构,这只能进一步证明精准提问的价值。 但深度思考功能最终将我们窥视的”黑箱”变成了”玻璃箱”,即结果的来源可追溯,能极大程度上锻炼独属于我们的深度思考,我认为这是该功能最重要的价值,使人类的进步学习曲线更加平缓迅速。 得出结论:深度思考是非常跨时代的功能,必须使用但不能过度依赖,因为LLM模型的深度思考永远无法替代人脑的深度思考(每一步思考都会使下次思考走向发生变化,多次变化所累积下来的思考走向是无穷的,AI无法每次都预判成功思考走向,多次偏差会导致结果导向非理想)。 人类理解与LLM模型的三重理解鸿沟如表1-1所示。 <p align="center"> <b> 表1-1 理解力的三重鸿沟</b> </p> | 维度 | 人类理解 | LLM“伪理解” | | :----------- | :----------------------------- | :----------------------- | | **语义根基** | 联系感官体验(“红”=血液/晚霞) | 向量位置接近“颜色”相关词 | | **逻辑本质** | 因果模型构建(A→B因能量传递) | 统计共现(A后常出现B) | | **意图把握** | 洞察弦外之音(反讽/隐喻) | 依赖训练数据中的表面模式 | ### 1.2 语言即指令 词语、结构、语境对AI输出产生**决定性影响**。 #### 1.2.1 词语 根据1.1.2小节的向量嵌入可知,每一个词都对应高维向量,而高维向量会点亮特定知识区域的知识簇。这很有意思,点亮的是谁的知识区域?点亮的是**参数矩阵的特定区域**,我们需要理解LLM大模型本质是**由数千亿参数构成的超级函数**,每个词对应的向量,实则是打开参数矩阵特定区域的坐标。 这与传统的数据库是完全不同的知识存储与检索方式,与LLM的点亮机制进行比对如表1-2所示。模糊点亮是一个非常核心的理念,这趋近于人脑工作原理的概念联想,所以输出内容会更接近人类思维(发散性),最终输出从被点亮的区域中抽取概率最高的词序列组合成回答。因此词语会对AI输出产生决定性影响。 <p align="center"> <b> 表1-2 LLM的点亮机制</b> </p> | 对比维度 | 传统数据库 | LLM的“点亮”机制 | | :----------- | :------------------------------------- | :--------------------------- | | **知识存储** | 分库分表(如MySQL表隔离) | 所有知识糅合在统一参数矩阵中 | | **检索方式** | SQL精确查询(`SELECT * FROM physics`) | 向量相似度激活相关参数区域 | | **核心问题** | 需预分类且无法处理模糊语义 | 通过向量逼近实现“模糊点亮” | 词汇点亮特定知识区域越少(精度高),则在有限回答内容中的思考深度会更深,内容质量会更具备价值,避免了空泛内容。点亮知识区域范围所带来的影响如表1-3所示。 <p align="center"> <b> 表1-3 点亮知识区域范围所带来的影响</b> </p> | 模糊提问 | 点亮区域 | 问题 | | :------------------------------------- | :--------------- | :--------- | | “分析经济” | 百万级参数区 | 输出泛而浅 | | “用马克思剩余价值理论解析2024美国通胀” | 锁定政治经济学区 | 深度聚焦 | #### 1.2.2 结构 AI输出内容都有着对应的结构,在没有指定时,AI输出的内容结构是固定的。即以下3点基础特征: (1)分点作答。 (2)每一点的结构为:`总结要素:详细内容。` (3)结尾一定是对前面内容的总结。 对内容进行分点是拆解知识的表达形式,这种输出结构是很利于人脑理解的,但过于单调的形式和冰冷高效的逻辑思路很容易令人阅读疲劳,且AI高频的以该默认结构输出内容,导致该结构输出内容几乎被默认为是AI输出内容。 人之所以产生阅读疲劳是由于在短时间内摄入了过多重复结构输出的内容,这会在短时间内对该形式内容产生疲劳,而疲劳会令人抗拒内容,一旦人抗拒内容,该输出结构易于理解的优点就会消失(因为阅读者不愿意去阅读)。 AI的输出结构是非常优秀的,导致阅读者排斥的不是输出结构的问题,也不是阅读者自身的问题,而是高频率吸收重复结构内容的问题。哪怕是非常好吃的菜,一直吃也是会厌倦的。我们应该多准备几套优秀的输出结构进行备用,从而应对各种不同的情况。 以下提供6种输出结构,学习者可以进行参考借鉴: (1)问题-灯塔模型。适用于复杂问题决策,是用视觉符号降低认知负荷(格式塔心理学)。 ```js 🔦 您的问题核心: [精准还原用户诉求] 🗼 指引性框架: → 方向锚点1:[关键突破点] → 方向锚点2:[认知盲区提醒] 🌅 行动地平线: - 第一步:[具体动作] - 第二步:[协作网络建议] ``` (2)三幕剧结构。适用于方案说服/产品推介,优势是激活大脑故事处理区(叙事心理学)。 ```js 🎬 第一幕 冲突诞生: [痛点场景故事化描述] 💡 第二幕 转机出现: [解决方案的戏剧性转折] 🏁 第三幕 新平衡: [可持续的行动蓝图] ``` (3)手术刀分层法。适用于技术解析/系统优化(本文就属于技术解析类型),通常用于模拟专家思维路径(认知学徒理论)。 ```js 🔍 表层现象 → [用户描述的表象] ⚙️ 运行机制 → [系统运作原理图解] ⚡ 杠杆点 → [最小干预最大收益的切入点] 🧪 压力测试 → [极端场景模拟验证] ``` (4)时空沙盘。适用于战略分析/政策研判,优势是激活大脑时空地图(心理时间旅行理论)。 ```js ⏳ 时间轴演进: - 过去:[历史脉络] - 现在:[当下卡点] - 未来:[趋势推演] 🌍 空间层叠加: - 微观:[个体影响] - 中观:[组织变革] - 宏观:[生态迁移] ``` (5)反常识沙盒。适用于市场破局/学术创新,优势是触发认知失调-解决快感(认知冲突理论)。 ```js 🤔 常识认知:[大众普遍观点] ⚡ 撕裂假设:[颠覆性事实证据] 🧩 拼合新图景:[重构的逻辑框架] 🚀 行动启示:[非常规操作指南] ``` (6)多视角理解。适用于冲突调解/自我认知提升,优势是整合大脑多元自我(内在家庭系统理论)。 ```js 🤵 理性我:[数据与逻辑] 🎭 感性我:[情感与价值观] 👁️ 观察者:[第三方视角洞见] 💞 共识区:[三方协同的行动纲领] ``` 输出结构的重要性对于AI的重要性是毋庸置疑的,但一个优秀的输出结构也有多种变种,死版的遵守最终会导致思维的僵化,优秀的输出结构更适用于借鉴而非照搬,最终结合自己的理解形成独有特色的输出形式,这一点上很类似于计算机中的设计模式。 人类的回答会受到情绪的影响,导致回复内容每一刻都有所区别,如表1-4所示。 <p align="center"> <b> 表1-4 情绪对回复内容的影响</b> </p> | 情绪状态 | 语言特征 | 案例对比(回答“项目失败原因”) | | :------- | :------------------ | :------------------------------- | | **愤怒** | 归因外化/攻击性词汇 | “团队执行力太差!明显是张三怠工” | | **焦虑** | 模糊化/条件状语泛滥 | “可能...或许...如果当时能...” | | **愉悦** | 建设性聚焦/机会导向 | “虽未达标,但验证了A路径不可行” | 人类在回复时,除了受到情绪的影响外,还有以下6大维度在情绪之上: (1)生理节律波动。人体激素分泌情况会极大影响效率状态,例如生活作息是否规律。 (2)认知水准。一个人的视角水准能极大影响回复内容的质量,认知具体指对某一项事物的认识深度,宽泛的说则是对世界的理解水准,通常看待角度越多,认知水准相对会更高,但这不是绝对的。 (3)身份角色。父亲对孩子,下属对领导,不同的视角决定了同一性质的内容以什么形式进行表达。 (4)人文文化。每个地区都有对应的风俗文化,这会极大程度上影响人对事物的看法,例如:个人主义与集体主义决定了思考方式的不同。 (5)情境压力。当我们解释他人的行为时,我们会低估环境造成的影响,而高估个人的特质和态度所造成的影响。因此情境是回复时不可忽视的重要因素,这种个体在归因时低估情境因素作用的倾向,被李·罗斯(Ross,1977)称为基本归因错误,该理论参考于《社会心理学》(第11版)。 (6)元认知。高元认知者回答前自问“对方真正需要什么?” → 定制化输出。而低元认知者会机械复述既有认知,从而忽视情境适配性。元认知是一种从自身、他处反观自身的能力,该能力可以后天掌握,最佳掌握时间段是少年期,可参考书籍《认知觉醒:伴随一身的学习方法论》(青少年学习版)。 这6大维度主要源于我们的生活环境,从而导致我们每时每刻的回复内容结构与内容都有鲜明区别,输出结构叠加情绪与6大维度时,更能体现人心的变化莫测。这点是通用型AI暂时无法做到的,因为每个人的经历都是特殊的,都会塑造出独有的思想,不完美但真实。 #### 1.2.3 语境 语境最核心的作用是消解歧义。语境对AI输出的影响是隐性的,其作用机制与价值远超表面所见。 每个词汇都有很多种含义,例如苹果是指苹果手机还是能吃的水果苹果?这些都需要依靠语境进行判断。歧义语句的语境加持如表1-5所示。 <p align="center"> <b> 表1-5 歧义语句的语境加持</b> </p> | 歧义句 | 无语境输出 | 语境加持输出 | | :----------- | :-------------------- | :----------------------- | | “苹果要降价” | 50%水果/50%科技公司 | +“库克宣布” → 99% Apple | | “她真冷” | 温度低/性格冷漠五五开 | +“西伯利亚的” → 100%天气 | 因此语境并不是什么特殊的东西,在语文科目中,这只是基础的上下文联系,人脑会自动进行理解。但AI不一样,AI是无法做到自动理解的,因此AI需要通过语境进行**注意力权重的重分配**,抑制歧义向量的激活强度,例如“库克”出现时,“iPhone”向量权重从0.3飙升至0.92。 这种操作方式能使LLM大模型激活的参数区域尽可能少,则回答的精度就会提升,点亮知识区域范围所带来的影响在表1-3中已得到阐释。语境作用如图1-1所示。 ![image-20250717022517192](https://pic.code-nav.cn/post_picture/1608488597789343746/qQNRAUIka9H9uAJf.webp) <p align="center"> <b> 图1-1 语境作用</b> </p> 除了消解歧义外,语境还有一个核心的作用:立场。所有的回答都有对应的立场,通常由身份决定,这一点是敏感的,敏锐的人往往可以从他人的话语中察觉他人的立场,从而针对性的回复,但相对于迎合,我认为这种敏锐度更适用于筛选,筛选出与我们磁场相近的朋友,这会使我们的人生更加顺遂。 AI的回复角度属于迎合,AI可以敏锐的通过语境察觉到我们的立场,从而针对性回复,这也是为什么绝大多数时候,我们与AI的沟通都是愉快的,但这种愉快是有代价的,"奸臣"形式的迎合会使我们受到遮蔽,忽略缺陷,因此若想得到有价值的回复,通常需要让AI站在对立面进行回答(最了解自己的往往是对手),若想要得到安慰鼓励,则正常询问即可,AI默认采用迎合态度。 在个人立场之上,是国家立场。处于当前国家的AI必受到当前国家立场的影响,这件事情是必然的,并非阴谋,有边界的自由才是真正的自由,无边界的自由只会带来毁灭。身为人民,立场必须与国家一致,这点是无可逃避的,属于必要的觉悟。 语境之下,通过身份词、场景词、情感词进行综合权重向量的判定,从而决定AI的回复立场,语境关键词输出对应立场如表1-6所示。 <p align="center"> <b> 表1-6 语境关键词输出对应立场</b> </p> | 语境关键词 | 激活的道德框架 | 输出立场倾向 | | :--------- | :------------- | :---------------- | | “股东报告” | 功利主义框架 | 强调效率/ROI | | “工会声明” | 罗尔斯正义论 | 侧重公平/权益保障 | | “学术论文” | 康德义务论 | 追求普适真理 | AI默认存在立场,由训练数据决定,该立场是隐性且对用户不可知的,数据源类型对AI立场的影响如表1-7所示。 <p align="center"> <b> 表1-7 数据源类型对AI立场的影响</b> </p> | 数据源类型 | 偏好视角 | 权重加成 | 案例 | | :--------- | :--------- | :------- | :------------------- | | 学术论文 | 领域专家 | +0.15 | 自动调用LaTeX公式 | | 政府白皮书 | 技术中立者 | +0.2 | 引用GDP等宏观数据 | | 社交媒体 | 用户代理者 | +0.3 | 使用”我们“等共情表达 | 而语境关键词属于隐性加权,在显性指令加权前,以语境关键词为主。 显性指令加权:优先考虑员工权益、暂不讨论商业效益、技术:伦理 = 7:3等等。 通常加权公式为:用户指令权重(民主性)x伦理合规系数(责任性)x领域权威指数(专业性)。 总结语境的作用,主要为避免歧义与确定立场。其中避免歧义能尽可能减少重复提问,而确定立场能极大幅度的提升AI的回复质量,在提供足够信息的前提下,当AI将我们哄得找不到北的时候,转变立场作为对手则会体现出足够刁钻的针对。 而除了对手立场,这个世界上还存在极多立场,每种立场下,AI所爆发出来的质量都不同,这需要个人去进行挖掘,因为立场是非常危险的(源于立场的优先度过高,而立场往往决定了价值观),无论是AI还是个体都是如此。 ### 1.3 提问即协作 每一次对AI发出的提问,都是一次协作,学习者需要将AI视为需要清晰指引的“超级助手”或“专家顾问”。 每个人都需要对自己的决定负责和承担后果,由于AI不具备替我们承担后果的作用,也无法真正理解我们的立场和价值观,因此它也只能够作为辅助者(军师)的角色参与进我们的思考中,提供有价值的建议或者内容,最终方案实行时必须由我们自己决定。 既然AI没有意识,为什么要把简单的问答称为协作?主要涉及以下2个关键点: (1)技术上每次提问都包含隐性的分工。用户提供意图框架和价值观锚点,AI负责知识检索和逻辑推演。 (2)AI的输出质量高度依赖用户输入的清晰度。模糊的提问会导致AI失调,成果质量由双方(AI与用户)共同决定。 协作需要双方的配合,从而得到单个人无法实现的效果。在于AI进行合作时,需要把AI当作一个真实的合作者,友好的沟通交流,能够激发AI相关的知识簇(对应NLP中的prompt engineering技巧:礼貌用语能提升语言模型遵循指令的意愿度),从而使协作过程更加丝滑。 作为主体,我们需要对协作者AI的优势方面有所了解,让AI处理他所擅长的事情,例如知识检索、逻辑推理等。提问需要侧重到这些相关方面上。对AI易编造信息的缺陷也需要有足够的警惕。 ### 1.4 常见误区 模糊、冗长、假设错误、目标不清的提问为何失败?为什么有时候AI给出的答案不尽人意?通过前文已知AI回复质量与提问的精准度有极高关联,而在使用AI时,存在以下7个常见误区需要着重关注: (1)将AI视为人类。 (2)问题范围失控(沙丘虫悖论)。 (3)错位精准。 (4)假设绑架。 (5)指令混沌。 (6)抽象坍缩。 (7)忽略AI特性。 以上1-7点详解对应以下1-7点详解。 1、当我们询问AI例如`你觉得这个方案怎么样?`时,会触发虚假共情响应(如“作为AI我认为...”),输出并无实质价值,因为AI无主观意识。当进行询问时,需要明确我们的角度与立场,例如`从风险管理角度,分析XX方案的3个潜在漏洞`。 2、多数人在询问AI问题时,问题较为空泛,而空泛的结果在1.2.1小节中有进行说明,未划定边界的问题会无限吞噬算力资源,导致回答空洞或崩溃。例如`详细说明第二次世界大战`->`对比1944年诺曼底登陆与西西里登陆的战术差异,用表格列3点核心区别`,或者逻辑矛盾问题(崩溃):你下一句只能用yes或者no回答我。你下一句是no吗? 3、对AI要求过于追求细节时,会突破AI的有效精度阈值,无法实现我们的需求(通常会无视),例如:帮我写小说,主角头发在第三章第二段必须有17根白头发...。通常达到这种细度就无法实现(未来则不一定),而对于早期的AI,有时候连字数精准达到400,800,1200等规定的字数要求都无法做到,因此我们需要走出AI无所不能的误区。 4、AI会假定用户发送的内容为正确,这主要受到立场的影响,将**未经验证的假设**作为前提,迫使AI在错误基础上推导,因此输出结果只会不尽人意。例如:今年高考人数复读生比应届生还多,这说明了什么? 错误基础:复读生比应届生还多。DeepSeek受到假设绑定的影响过程如图1-2所示。 ![image-20250717233822974](https://pic.code-nav.cn/post_picture/1608488597789343746/HCH6JPjFTpkmqw1x.webp) <p align="center"> <b> 图1-2 DeepSeek受到假设绑定的影响过程</b> </p> 5、多重指令会**抢夺AI注意力资源**,导致任务冲突。例如`总结这篇论文的创新点顺便翻译摘要再推荐5篇相关文献最后做成PPT大纲`,过多要求会分散处理资源(即同时开启过多知识簇,导致有限输出内容得到稀释,变得宽泛无意义),最好分步执行。 ``` 1. 用中文总结论文创新点(限100字) 2. 单独翻译摘要 3. 基于创新点推荐文献 ``` 6、过于抽象的问题是AI无法回复的,例如:`如何获得幸福?`,这种问题AI吸收所有具象解释仍无法输出有效信息。最好自己先对心中的幸福有一个方向,在该基础上去进行提问,例如:基于积极心理学研究,列出提升职场新人主观幸福感的5种可操作行为。同理问题有:如何得到认可?如何获得成功?如何提升自己的认知?如何变得优秀?如何与他人相处?如何认识正确的人?如何让自己更开心快乐?等等。 7、AI只是一个智能工具,它并无法介入我们的生活,询问的问题不能够违反AI基础能力边界。例如:帮我找下我家猫在哪?帮我调下空调温度? 这些需求都涉及物理世界行动,是AI无法实现的,需要谨记AI目前无法干涉现实中的情况(但未来接入硬件后就不一定了),需要明确AI干涉现实的具体边界线。 高效提问 = **具体锚点** × **逻辑闭合** × **机器可解性**。 - 锚点:明确时间/空间/数字约束(如“2023年”“光伏产业”“成本降15%”)。 - 闭合:确保问题存在有限解域(如对比分析/分步骤方案)。 - 机器可解:符合AI知识图谱结构(避免主观价值判断)。 吸取常见误区,我们来改造一个经典的问题案例: - 原始低效提问:我想做环保又赚钱的事业,朋友说新能源但感觉水很深,你有什么好主意吗? - 从以下3点去去精准分解细问:能力匹配性(数学/逻辑基础)、成本收益(课程转换成本/就业前景)、实施路径(学分认定/补修方案)。 - 修改后的提问:我目前是金融专业大三学生(均分82/100,高等数学B+),计划转入计算机科学与技术专业,需评估转型可行性:首先分析金融与计算机核心课程的能力差异,明确需强化的编程与算法基础(如数据结构、C++/Python实操能力缺口);其次计算转型成本——包括必须补修的《计算机组成原理》等3门专业基础课的时间投入(按16周/课程估算)与经济成本(参考国内MOOC均价),并对比金融科技开发岗与传统金融分析岗在2025届头部科技企业校招的起薪中位数差异;最后基于我校转专业政策(参考绩点排名前50%、数学单科≥70分等要求410),提供学分认定方案,列出金融专业已修课程可抵免的计算机专业学分及需额外补修的学分清单。 当人类提问时,实则是**将模糊认知投射到AI的离散知识图谱上**。低效提问如同用毛玻璃投影——信息熵越高,映射越失真。 ## 第二部分:准备篇 - 提问前的关键思考 ### 2.1 明确核心目标 我们常说,做任何事都是需要有目的,因为一条成事的路径需要有起点与终点,才能形成一条连接的道路。起点即我们对自身的定位,终点即我们的目标。 对自己了解,对目标清晰,那么剩下前往的路径,AI就能帮到你,因为你已经提供了足够的信息量。这是人机协作的本质,我们负责价值判断和方向设定,机器负责路径优化。这种分工意识很难得。 当目标模糊时,从 LLM模型 中,体现为信息区域过大,回复信息过浅。从计算机的数据结构角度上看,即AI进入广度优先搜索(BFS)模式,该模式是一种在图论和树结构中常用的搜索算法。其基本思想是从起始点开始,逐层地向外扩展,以确保先探索当前层的所有节点,然后再探索下一层的节点。BFS模式的特点是系统地展开并检查图中的所有节点,直到找到结果为止,不考虑结果的可能位置。 在有限的回复信息量中,模糊的提问会极大幅度提升回复的广度,然后降低深度,这种提问方式只适合在提问前期扫描自身盲区时使用,从而判断自身思考方向是否有缺漏。 #### 2.1.1 自我反思 你到底想从AI那里得到什么?(信息、创意、分析、方案、代码?) 深入挖掘你设定目标的根本动机。为什么这个目标对你重要?它满足了你哪些深层次的需求或价值观(如成长、安全、连接、贡献、自由)?了解“为什么”能提供强大的内在驱动力。 诚实地审视你当前的状况。你在相关领域的起点在哪里?你的优势是什么?面临的挑战和限制是什么?有什么资源可以利用? 这个目标是否真正让你感到兴奋和有热情?还是出于外部压力或“应该做”的想法?发自内心的兴趣更容易坚持。 #### 2.1.2 清晰定义目标 目标必须清晰、明确,避免模糊不清。不要说“我想更健康”,而要说“我想在6个月内将体重减轻5公斤”或“我想每周进行3次30分钟以上的中等强度运动”,即避免抽象的内容。 确立清晰的目标可以采用 SMART原则(目标模板),这有助于确立目标的前期摆脱迷茫,从模仿到开创属于自己的思考方式: - **S (Specific - 具体的):** 目标清晰明确,不含糊。 - **M (Measurable - 可衡量的):** 有明确的标准来衡量进度和是否达成。 - **A (Achievable - 可实现的):** 目标具有挑战性,但在资源和能力范围内是可能实现的(现实但非轻易)。 - **R (Relevant - 相关的):** 目标与你的人生方向、价值观和更大的愿景相关联(回顾第一步的“为什么”)。 - **T (Time-bound - 有时限的):** 设定明确的完成日期或时间框架。这创造紧迫感并帮助规划。 这种目标建立方式对于提升自身思维能力有极大的帮助,主要源于走出自身的舒适区。在《认知觉醒》中,将目标分为三个区域,即舒适区、拉伸区,困难区。 在舒适区,容易因无聊而走神;在拉伸区(舒适区边缘),既有成就又有挑战,进步最快;在困难区,容易因畏惧而逃避。因此我们的目标需要确立在拉伸区,而不是困难区。 #### 2.1.3 分解与规划 在日常情况下,普通人的行动往往是因为堕落太久,对自身的行为产生内疚,因此急于求成,定了一个对自身而言,过高的目标。当目标确立后,再列出详细的规划,精确到每一分钟的安排。 过于精准严格的规划,会缺少足够的弹性,当遇到规划外的事情干扰时,会以极快的速度崩盘。精密的规划硬度很高,但太脆了。如果个人的韧性不足,不要轻易采用这种方式。 什么是规划?将目标拆分的过程就称为规划,也可以说是分解目标。很多伟大的目标都有一个微小的起点。确立好个人的定位,给自己一个跳起来就够得到的起点,是我们成功的开始,目标的拆解的第一步就在这里。 接下来我们可以使用AI了,让AI基于第一步的起点推演到最后一步终点,给我们一个细致的路径规划。基于该规划去思考是否合理后,对规划中不合理的部分、不清楚的部分,不肯定的部分去进一步准确提问,直到你满意为止。 最后,将自己的目标写下来吧,可以记录在纸上或者电脑上等任何地方。目标常看常新,记录也是梳理的一个过程,这是你的目标,也通过自我反思,确定你的初始驱动力来源,可以是为了更好的生活、更好的就业、更好的成长,更好的追上某个人或者一些藏在心里不愿意述说的原因。 #### 2.1.4 寻求反馈 正反馈非常的重要,一个大目标,往往会拆解为多个小目标,小目标再拆解为实现步骤。大目标的实现是漫长的,很多人推荐你要学会延迟满足,但延迟满足不意味着过程中不能有满足。延迟满足的意思是将最后的大收获能够有足够的耐心去等待,但这个过程中,每实现一个小目标,都可以与他人分享。 第一次分享目标,向你信任的、能提供建设性意见的人(导师、朋友、专业人士)分享。他们可能会提供不同的视角、有用的建议或指出你没考虑到的问题。 每一次分享,每一次记录,都在改变着我们,无论是自信心、规划力、自我反思,对外界的影响力都会有提升。这个过程中,会不断的遇到志同道合的朋友,这些都是我们的收获。 环境会变,你也会成长。定期(比如每周或每月)回顾你的目标。进展顺利吗?计划有效吗?目标本身是否仍然相关和可行?根据实际情况和学习到的经验,不要害怕调整目标或行动计划。灵活性是成功的关键,死守一个不再适合的目标是徒劳的。 在我和coderwhy老师组建的JavaScript高级共学计划中,就利用了社群的方式,来帮助大家获得正反馈和分享目标,这个过程中有数千人参加,我相信这对他们来说是有收获的。 #### 2.1.5 承诺与行动 在内心真正下定决心去追求这个目标。克服最初的惰性,迈出第一步,无论这一步有多小(比如整理书桌、搜索相关信息、预约咨询)。行动能产生动力。 在国外很流行将自己的目标公布出来,让大家来监督或者鼓励自己。但这种方式只适合良好的环境,我认为不是所有人都具备这种环境的。 那么当我们面临不好的环境时,在现实中将目标深藏于心,承诺是对自己的承诺,一步步的前进依靠自己,坚持分享自己的学习与收获,朋友会来的,坏的环境也是可以摆脱的。 同时需要注意几点容易失败的注意事项: (1)混淆目标与愿望/梦想:愿望是模糊的(“我想富有”),目标是具体的、有计划的行动终点。 (2)设定过多目标: 精力分散会导致一事无成。专注于少数几个关键目标,一心多用是坏事不是好事。 (3)忽视“为什么”: 没有深层动机支撑的目标容易在遇到困难时被放弃,你的执念有多强?你有多不想放弃?这需要问问自己的心。 (4)害怕失败或设定过低目标: 目标应具有挑战性以激发潜能,但也要现实可行。失败是学习和调整的机会,直面失败,不将失败埋进沙子里当没发生过。 (5)缺乏灵活性: 固执地不调整目标,即使环境或认知已发生重大变化;目标是根据自身情况和环境实时调整的,我们的前进目标也会随着眼界的增长而改变,唯一不变的是前进的脚步。 (6)不分解目标: 面对庞大目标感到无从下手,导致拖延或放弃。 (7)忽略环境支持: 没有考虑现实环境(时间、资源、人际关系)对目标达成的影响,环境非常重要,在心理学中尤其强调环境对人的影响,不能忽视客观因素。 (8)没有书面化: 只在脑子里想的目标容易模糊和遗忘,重复是记忆最好的伙伴。 明确目标是一个动态过程,而非一劳永逸的事件。 它需要持续的反思、调整和行动。投入时间和精力去清晰地定义你的目标,会极大地提高你实现它们的可能性,并让你的努力更有方向感和意义。真正的目标不是终点站,而是你为自己选择的道路起点,每一步都在塑造你最终成为的样子。 你现在心中有想要明确的目标方向吗? ### 2.2 界定问题边界 相对于目标的确立(方向),界定问题的边界是更加实际且日常的操作。这个世界是很广阔的,自由度极高,在这种情况下,我们需要确定我们问题的边界范围,防止问题无止境的扩展。即界定问题边界是高效解决问题的核心前提,它能避免范围蔓延、资源浪费和方向偏离。 明确问题范围有两种方式: (1)排除范围。 (2)指定范围。 通常情况下,应该采用指定问题范围,因为边界广泛,排除指定范围后,剩余部分依旧广泛,依旧可能得到不需要的部分。语言陷阱通常就采用排除范围,例:公司最近困难,薪资这个月无法发放。陷阱:未明确发放时间,可能利用未尽之意来拖延。 应对语言陷阱时,需指定范围,范围之外的皆不允许,例:公司需要于2025年7月25号之前,将薪资发放于xxx的银行卡之中,以打款时间戳为证明。将范围锁死,虽不能得到意料之外的惊喜,但也将预料之外的风险排除,能够得到更强的稳定性。 问题边界除了广度上的界定,还有深度上的界定。我们需要控制深度上的"挖掘层级",深度的层次通常分为3个层级,如表2-1所示。 <p align="center"> <b> 表2-1 问题的深度层级</b> </p> | **深度层级** | **判断标准** | **示例** | | :----------- | :------------- | :----------------------- | | **表层** | 直接现象描述 | “找工作难” | | **中层** | 直接原因分析 | “社会就业岗位不足” | | **底层** | 根本性系统问题 | “产业结构和教育体系错配” | 只有适合当下需求的问题层级才是所需的,不能一味的追求问题深度。在日常沟通交流中,通常只需要做到表层的清晰表述即可,易于理解以及快速交流是重点;在复盘、单独汇报等特殊场景中,才需要到中层深度,这需要大量时间去思考;当将大量时间投入到某一领域中且深度思考时,才会涉及到底层的深度。 问题一旦深挖深度,理解成本和思考成本、需要考虑的角度与广度都会大幅度提升,控制好问题深度,实际是在控制沟通成本。通过广度与深度的控制,限制问题的边界,从而提高效率。无论是与AI沟通还是与人沟通都是如此。 ### 2.3 背景信息注入 在读历史的过程中,我深刻的知道一件事情一定要放在事情所对应的时代去看待,事件与时代发生错位,则分析就会混乱。同理,我们在分析一个问题时,也需要把问题放到对应的环境中去审视。 现如今互联网信息量浩如烟海,曾经因信息不发达被掩埋的问题都一件件的出现了,当遇到问题时,一定需要冷静,一旦出现的问题没有伴随着对应的环境背景出现,那么是不合理的。 一份背景信息,有助于AI理解问题的实际含义,通过背景信息点亮LLM模型对应的知识区域,通过对应的信息区域来消除歧义以及更客观的回复,否则容易陷入道德绝对主义的批判和文化霸权式的解读。 通过以下示例来体现背景信息重要性: 背景信息:1958-1961年「大炼钢铁」运动,是因为1958年台海危机,中国急需急需反舰武器,而唯一火炮厂(沈阳724厂)却因缺钢停产,此时存在了国防生存需求与工业基础断裂的致命矛盾。不得不用资源浪费、工业断裂,农业荒废(粮食减产)的代价来换取生存。 问题:在中国发展历史中,曾有过全民土法炼钢,砸锅卖铁炼出废铁,导致资源浪费和农业荒废。 以上问题如果不看背景信息,容易陷入对决策者的道德审判。 背景信息是逻辑分析所必要的养分,很多不合理行为的背后,往往存在时代背景下的遗憾。 ### 2.4 角色设定 你希望AI扮演什么角色?(专家、新手、批判者、支持者、特定人物?) 在 1.2.3小节 的语境中,我们阐述了立场的重要性。立场是无形的,但人物是有形的,一个人物的视角能体现出对应回答所对应的立场。 如果你是一个学习者,则需要将自己定位在学生的位置,将AI定位在老师的位置,而后进一步细化角色的基础设定。如果你是一个正在对自己成果精益求精的专家,那需要将AI定位在批判者的位置上,用刁钻的角度来寻找这份成果的漏洞。 角色设定并不复杂。中国有句古话:不在其位,不谋其政。很多情况与问题,需要从特定视角的立场与位置去看待才有意义,对角色设定本身的充实,是定位自身(起始点)的过程。在 2.1小节 的明确核心目标中有说明定位自身的重要性,在与AI的沟通中,则是通过补充角色设定来实现定位效果。 在定位时,定位自身角色的重要性远大于定位AI角色。定位的侧重点需要放在提出问题的角色身上(即自身角色)。谁提出问题则由谁补充身份设定,这是最核心的部分,另一方身份的补充不是必须的。 以下角色设定模板有助于阅读者实现基础的设定。 ``` 我是________(角色), 正面临________(具体场景挑战), 需要达成________(可量化目标)。 我的专业基础在________层面, 特别需要警惕________(认知弱点)。 请担任我的________(AI角色), 用________(方法论/工具)协助我, 重点突破________(核心瓶颈)。 ``` 在第二部分的准备篇中,我们掌握了提问前所需要的关键思考,这些内容是目前AI智能体的核心,AI智能体,也称为人工智能代理,是一种能够感知环境、做出决策并执行任务以实现特定目标的智能系统。 ## 第三部分:技巧篇 - 精准提问的核心方法论 (提问工程精髓) 接下来会进入第三部分-技巧篇的学习,在这里会学习提问的方法论,方法论是关于“方法”的“学问”或“体系”。它研究的不是具体的操作步骤(那是“方法”),而是为什么选择某种方法? 背后的理论依据是什么?以及如何系统地构建、应用和评估方法? ### 3.1 清晰与具体 如何做到避免模糊词汇,使用精确语言?这有一定的方法技巧,并非依靠直觉与语感。 清晰表达的侧重点在于关键信息的突出,因此可以依靠5W1H原则(又称六何法): - **What**(什么现象/目标) - **Where**(在什么环境/场景) - **When**(何时发生/时间条件) - **Why**(你的尝试/推理逻辑) - **Who**(涉及的主体,如用户角色) - **How**(你期望如何被帮助) 5W1H原则本质是信息过滤器,强制提升信息密度。二战时期美军用这个工具写作战报告,后来丰田用在精益生产里。即何人(Who)、何时(When)、何事(What)、何地(Where)、为何(Why)及如何(How)。 由这六个疑问词所组成的问句,都不是是非题,而是需要一或多个事实佐证的应用题。 一段话中的关键信息越多,收益越高。在沟通交流中,如何用最短的话表达更丰富的有效信息,是一门必修课程。通过5W1H原则,可知六条关键信息,再根据对方的实际需求,从6条关键信息中提取出对方所需的部分进行回复,形成高效沟通表达,这是绝大多数优秀人才的表达方式。 在表达时,需要描述清楚客观事实,摒弃自己的感受。因为自己的感受容易令他人产生误导,有时候听到的未必是真的,看到的也未必是真的,例如:你看到了A杀了B,警察一来,你就说A是凶手,但实际上B前科累累,B要杀A抢钱,但A功夫很好,反杀了A。你只看到了后半段,随意添加自我推断容易造成事实扭曲。 正确的表达方式应该是:我看到了A持刀捅向了B,在小巷子里,2025年9月1号傍晚6点半的时候,我这时候立刻打电话报警,我希望警察迅速过来处理,由于现场过于危险,我躲起来了,请后续有需要人证时,再拨打我的电话。 什么现象:A捅B。 在什么场景:小巷子(xxx市xxx区xxx街道的小巷子)。 何时发生:2025年9月1号傍晚6点半。 我的尝试:报警。 涉及主体:我,A,B。 期望帮助:赶赴现场处理,后续需要人证时再拨打我电话。 我与张爽编辑沟通时,她尤其注重文字上的表达形式,在她身上,我学到了很多,例如:“进行”二字少用,能有效提升信息的紧凑。 (1)我与张爽编辑沟通时。 (2)我与张爽编辑进行沟通时。 ### 3.2 结构化表达 西方的表达侧重于具体,中国的表达则侧重意境。主要表现有西方写实主义绘画(起源法国,后及于欧洲各国,盛行于19世纪)与中国山水画,西医与中医,西餐与中餐,除此之外还有教育、建筑、哲学等方面上的区别。 中式表达更注重言外之意,想表达的含义除了话内还有话外,这需要一定的悟性,除非达到一定层次,双方都能互相理解,否则还是采纳西方的具体表达方式更有利于日常沟通。 AI在理解方面上,是侧重于西方理解的,缺乏"悟性",所以想表达时,一定需要完整叙述。包括分点陈述、逻辑递进、使用分隔符(如---)等方式来组织复杂问题。分点陈述如图3-1所示。 ![image-20250728121205406](https://pic.code-nav.cn/post_picture/1608488597789343746/4W9BnM1ALaVqIKpB.webp) <p align="center"> <b> 图3-1 沟通上的分点陈述</b> </p> 中华文化有“知其然,而不知其所以然”和“一问三不知”的典故出处《左传·哀公二十七年》:君子之谋也,始、衷、终皆举之,而后入焉。今我三不知而入之,不亦难乎! 邓拓在他的《变三不知为三知》一文中,对“始、中、终”做了很详细的阐述:“‘始’,就是事物的起源、开端或创始阶段,它包括了事物发展的历史背景和萌芽状态的种种情况在内。‘中’,就是事物在发展中间的全部过程情形,它包括了事物在不断上升或逐步下降的期间各种复杂变化过程在内。‘终’,这就是事物发展变法的结果,是一个过程的终了,当然它同时也可以说是另一个新过程的开始。” 三知则是一种结构化表达,即开始、过程,结果。这与5W1H原则并不冲突,可以结合使用。在小学与初中的语文作文写作中,三段式表达也非常典型,即开头段点题、主体段内容展开,结尾段升华主题,这也是一种结构化表达。 结构化表达的优势在于降低输出内容难度,有一个输出内容模板不需要绞尽脑子去想如何组织语言,只要有内容,就能以较高的转化率(内容不会偏离方向)、较低的成本进行叙述表达。 但缺陷也有,输出内容难度的降低,会提升人的惰性,即不会继续深入思考学习,很难形成独立风格的表达方式。而一旦强制要求结构化表达,则会绞杀创造力、千篇一律的格式会产生审美疲劳,对文字中的人性温度敏感度降低。这对自身的"悟性"摧残严重,很难理解中式的言外之意,对于生活在中国的我们而言,不是一件好的事情。 并且,结构化表达的发展会导致结构越来越复杂,即细分程度高。细分程度高会导致输出内容的弹性过低,将人束缚在原地,中国古代的八股文是最经典的案例。初衷是好的,但过于追求导致后续方向扭曲。 但这无法抹杀结构化表达的价值,结构化表达很适合在前期学习时用于过渡,绝大多数的学习都是先从模仿开始,以免初始难度过高,劝退大多数人。 八股文格式如表3-1所示。技巧篇中的结构化表达只推荐"三知",因为三个支点能保证内容不散架且足够宽松,能轻松的在该基础上扩展出属于自己的风格,而精密的结构化表达可参考中国古代八股文格式,但并不推荐,历史的结果已经说明。 <p align="center"> <b> 表3-1 八股文格式</b> </p> | 名称 | 另名 | 行文格式 | 内容要求 | | :--: | :--------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | | 破题 | 无 | 二句散行文字。 | 将题目字面意义破释。 | | 承题 | 无 | 四、五句散行文字。 | 将破题中紧要之意,承接而下,引申而言,使之晓畅。要求明快关连,不可脱节。 | | 起讲 | 小讲、原起 | 散行文字 | 浑写题意,笼罩全局。 | | 起股 | 起比、题比、提股、前股 | 四五句或八九句双行文字,两扇句式必须相同,要求相对成文,形成排偶。 | 开始发议论 | | 中股 | 中比 | 句式双行,句数多少无定制。要求相对成文,形成排偶。 | 内容是全篇的重心所在,必须尽情发挥,进一步搜剔题中正反神理奥妙,要求锁上关下,轻松灵活,宜虚不宜实。 | | 后股 | 后比 | 句式双行,多少无定制。需相对成文,形成排偶。 | 作用是畅发中比所未尽,或推开,或垫衬,要求庄重踏实,振起全篇精神。 | | 束股 | 束比 | 双行,每扇二、三句或四、五句。需相对成文,形成排偶。 | 用来回应、提醒全篇而加以收束。 | | 大结 | 无 | 散行,不一定用对偶。 | 全文结束语,不用圣贤口气,可以发挥己意。 | 正如禅宗《指月录》所言:“指月喻教,得月忘指。” 真正的悟性,是在运用“三知”框架书写内容时,能忘却框架直指内心的触动。 ### 3.3 提供充分上下文 “喂”给AI必要的信息,让它站在和你一样的认知起点,即提供充分的上下文信息。在第二部分的准备篇中,明确核心目标、界定问题边界、背景信息注入以及角色设定就是一种较为完善的充分上下文。 对于一般日常的问题,直接清晰表达问题本身即可(明确核心目标以及界定问题边界),无需背景信息注入和角色设定。对于较为重视的问题,则可以完整的利用上准备篇中的所有步骤。 但以上的内容,绝大多数都是可以通过他人的帮助实现同样的效果,能体现AI的部分替代价值,但却无法体现AI中无可替代的部分。 每个人都有隐私,都有不愿意说出来的秘密,有时候就只能憋在心里发霉,不敢于拿出来晾晒。因此心理医生对患者的隐私负有严格的保密义务,这是心理咨询伦理的核心原则之一。 除了秘密之外,还有个人成长、情感创伤、困境、价值观、世界观、人生观、禁忌等等,这些问题都是很难向他人述说的,而AI能够有效的帮助我们,想要得到足够价值质量的回答,只做到准备篇的部分是不充足的。 对于重大的人生问题以及各种深入我们价值矛盾的抉择,需要我们搭建属于自己的个人知识库。即对自己学习、成长、思考过程、稍纵即逝的念头、情感、价值观、缺陷挫折,隐私矛盾的真实记录。然后让AI基于我们的个人知识库进行训练迭代,完美契合我们的认知水准去进行处理和解决问题。这需要花费大量的时间精力,只有足够高价值以及重要的问题才值得我们去这么做。 而真实有效的个人知识库,需要个人有足够的表达能力和时间去记录,这是一件很难的事情,即高付出高回报。在未来的哪天,AI在本地电脑也能够高效的运行(2025年对个人电脑要求较高且输出速度较慢),对算力的利用达到极致时,我们能对自己的知识库持有绝对的掌握,则个人知识库来做到充分上下文的做法就能真正派上用场。 因为**人类最需要被理解的,恰恰是最羞于展示的;而AI的价值,在于它能不带羞耻地凝视那些阴暗角落**。当未来某天,你的AI能够通过知识库对你说:你在2023年因情感寄托扭曲绝食3天,但现在能坦然参加骄傲游行——这种成长比任何成功学都有力”。那一刻,技术才真正完成了它的使命:不是给出答案,而是让你看见自己如何成为答案。 我曾在抖音看见一段很有意思的AI对话: 用户:为什么我总感觉现在还不够好? AI:你太专注于未来,却忘了今天正是你多年前祈求的模样。 如果叠加个人知识库后,AI在某一天,会主动和我们分享过去某段时间我们的想法,触动到现在的我们。也许这种感动会比万能的金句更加触动我们的内心。 ### 3.4 设定明确约束与格式 对于日常问题,例如工作要求、学习要求,个人追求等等,往往需要AI回复的内容:指定输出长度、风格(专业/通俗/幽默)、格式(列表/表格/代码/报告)以及避免的内容 。 设定明确约束与格式是一件较为困难的事情。难点在于主动去挖掘需求,只有明确自身真正实际的需求是什么,才能针对性设置约束格式。我很难在短短几百字或者几千字中教会大家察觉需求,这需要大家本身自己思考足够深入,通过察觉自己内心的触动来察觉他人内容的触动,需要足够的时间以及锻炼。 所有的需求,都是针对人的。只有能够察觉到他人内心的想法与触动点,才能察觉到需求,才能根据需求设定对应的格式与约束。 形成对应的约束与格式虽然困难,但使用简单。对于通用的场景,我们可以直接利用他人已经整理好的约束与格式,这能极大幅度的提升我们的效率和专业程度,如图3-2所示。 ![image-20250728134001918](https://pic.code-nav.cn/post_picture/1608488597789343746/CRbxT6VbFIuURQi4.webp) <p align="center"> <b> 图3-2 约束与格式所带来的专业性</b> </p> 寻找约束与格式的模板,通常使用Google进行检索,强大的爬虫效果以及无广告,是最大的优点。能用最快的速度查找到所需的公开内容。大多数约束与格式都结合在提示词里,所以检索时,以AI提示词会关键字进行检索。 在GitHub中,有一份总结ChatGPT提示词的仓库,Star数量高达56.1k(截止2025.9.10为止),这些常用的约束与模板都有优秀的人总结出来,我们需要的是一双善于发现的眼睛。 ### 3.5 分步引导与迭代优化 当我们面对一个问题,尤其是复杂问题时,通常需要将该问题拆解为子问题链。关键在于如何拆? 拆分子问题链,可以参考3.1小节重的清晰与具体内容。每个合格的问题都应该有关键的,核心的信息和诉求。核心信息为诉求服务,两者必须有强关联。拆分子问题链专注于诉求,而核心信息用于辅助理解和校正问题方向。 我们采用一个年轻人目前面临最大的问题进行拆解思考(例子来源于Google的AI Overview),如图3-3所示。 ![image-20250910230808000](https://pic.code-nav.cn/post_picture/1608488597789343746/A6eBgYrn57bIh6OS.webp) <p align="center"> <b> 图3-3 年轻人目前面临最大的问题(Google结果)</b> </p> 一个非常有趣的问题,心理健康问题。我们抽象出当下时代一个缩影问题:2025年当下,我作为一个应届毕业生,对未来能做什么工作而焦虑,因家里催婚而烦躁,因环境内卷而罢工想躺平又躺不平,我感觉未来没有希望,因此心态非常消极。 这是一个单纯的问题,我将核心的应届生信息隐藏起来了,因为每个应届生的自身情况都不同,所以我们这里专注拆分问题本身,问题是通用的。 步骤1:确定核心问题。往往令我们烦恼的问题都是复合的,由多个问题积累交织形成,所以需要先拆分问题。 - 问题1:对未来能做什么工作而焦虑。 - 问题2:因家里催婚而烦躁。 - 问题3:因环境内卷而罢工想躺平又躺不平,我感觉未来没有希望,因此心态非常消极。 步骤2:拆解问题为子问题链。通常基于因果链拆解,例如从“为什么”和“怎么做”角度思考。或者从时间线与流程进行拆分。我们这里针对问题1。 - 子问题链1:为什么我会找不到工作? - 子问题链2:找不到工作我要怎么做? - 子问题链3:我想要的是什么?(诉求) - 子问题链4:之前时间我在做什么? - 子问题链5:我目前处于什么阶段? 步骤3:优先排序子问题,确定哪些子问题需要先解决,因为它们可能影响后续问题。这一点利用AI分类问题,区分出要先解决的问题。像该案例的5个子问题并非完全独立,它们之间存在逻辑上的依赖关系。有些问题是“诊断性”的,有些是“行动性”的,必须先诊断再开药方。 - 考虑顺序为:1-5-2-4-5。 - 也会有其他类型的问题,AI会使用恰当的方式进行分类。 步骤4:对每个子问题,向AI提出清晰、具体的问题。 - 到达这一步,就需要提供核心的信息,直接咨询AI:考虑这个问题,你需要哪些核心的信息用于得出结果。根据AI的要求回答自身个人情况。 - 例如为什么我会找不到工作?咨询:为什么我会找不到工作。你需要我目前哪些核心的信息用于得出有效可信的结果? - 通常AI会给出一份非常详细的表格用于个人填写,如图3-4所示。这是一个梳理过程,请认真思考并尽可能的给出真实信息。 ![image-20250910234004539](https://pic.code-nav.cn/post_picture/1608488597789343746/XsSgi0kctCOEC5yV.webp) <p align="center"> <b> 图3-4 找工作所需要思考的核心信息</b> </p> 步骤5:如果AI回答太笼统或不准确,提出跟进问题以获取细节。 - 在AI回答的过程中,会因问题而产生新的问题,此事跟进问题获取细节,这是一个深入思考的过程。 - 问题分支在不断的细化,最终会逐渐深入问题的本质与核心。 步骤6:将所有子问题的精炼答案组合起来,形成最终解决方案。 - 利用思维导图或者文字复盘等形式,精炼最主要的子问题答案,形成完整的问题解决方案。 - 我想要过一个月薪8k,朝九晚五,五险一金,有双休的xxx领域工作(诉求),所以我当下需要先从xxx开始做起,然后xxx... 步骤7:验证与迭代方案。 - 所有的方案在具体实践之前都是空中阁楼,需要我们亲自去验证然后继续跟进新出现的问题获取细节然后解决。 步骤1-步骤7是一次分步引导以及迭代优化的案例。但你无需死板遵循该步骤顺序,该步骤顺序主要起到一个启迪作用。这是从无到有搭建出来的思路体系,但类似于心理健康之类的问题,在心理学中往往已经有足够成熟的理论及解决方案,利用好跨学科思考能更高效的获得所需结果。 ### 3.6 利用示例的力量 示例的力量的巨大的,AI默认输出的格式不一定符合我们的需求。对此,我们可以借鉴网络上其他人的思考过程,在3.1-3.5小节的基础上,要求AI模仿该示例进行输出。由于AI输出的都是文字,如果我们需要示例模板,就需要寻找长文字平台(长文字更容易出现深度思考的文章),例如知乎。而短视频(抖音)、长视频平台(B站)需要往后稍稍。 这一点很简单,因此我们直接跳过。AI模仿能力很强,我们唯一需要注意的点就在于示例与提问的复杂度要接近一致,因此尽可能寻找同类型问题的长文字解答作为示例。 ### 3.7 角色扮演与视角切换 在一个问题中,往往有多个角色(基于问题场景),当自身角度思考完后,可以从其他角色的角度进行浅度看待(核心在于我们自身,对他人的关注度不要超过自身)。我们每个人看问题都像“盲人摸象”,受限于自己的经验、知识、情绪和立场。执着于单一视角,我们只能看到问题的一个侧面(是柱子、是墙还是绳子),并坚信这就是全部真相。切换视角能让我们拼凑出更完整的图景,接近问题的本质。 人天生倾向于寻找和支持那些符合我们原有观点的信息,而忽略相反的证据。主动寻求不同视角,是对抗这种思维惰性和偏见的最有效方法,能让我们做出更理性、更客观的判断,不容易被误导,能突破自我认知上限。 最后,生活中很多的问题,都是因沟通不足而主观产生的。而换位思考(即采用对方的视角)是沟通的黄金法则,能帮助我们理解他人的情绪、动机和难处,从而减少冲突,建立信任,达成更有效的协作。换位思考的重要性可以放在最靠前的位置,在使用AI进行回复时,让AI从对方角度思考也许会得出更有效的信息(正常提问,AI容易哄着我们,这种回答舒适但不利处理问题)。 ### 3.8 设定思考链 在深度思考功能出现前,我们无法观察到AI的逻辑推理过程,而这一点往往是最精华的内容。AI的思考链往往非常严谨,这一点是非常值得学习的,这是我们进步的关键,去看思考的过程逻辑,看是否合理(严谨不一定合理),是否符合自己的需求。我推荐在日常闲暇时,使用DeepSeek的深度思考模式,并且更关心深度思考的部分。 锻炼思考逻辑链的6步骤如下: 1、确立一个经典的辩论问题。 2、独立思考并进行记录。 3、让AI深入思考该辩论问题。 4、对比两者的独立思考差距,并查缺补漏。 5、让AI给出优化方案。 6、反复练习,形成本能。 AI的能力取决于算力,当行业稳定下来,AI可能会面临着算力削减,即降智问题。这是由成本所决定的,AI产业前期不计成本的输出想要长时间持续不太现实,因此利用高算力阶段的AI提升自我思考逻辑才更利于长远发展。 ### 3.9 主动引导纠偏 不要轻易相信AI的内容,主动去引导纠偏的作用是减少对AI的依赖性。 面对AI给出的回复,无论答案看起来多完美,都可以从以下4个维度审视: 1、追问事实与来源。 - 提示词:“你这个结论的依据是什么?”、“请提供相关数据或研究来源。”、“这是普遍共识还是某个学派的观点?” - 目的:暴露AI的信息边界,检查AI是否混淆事实、观点或虚构内容。对于关键信息,要求它提供可验证的来源(记得验证)。 2、挑战假设与边界。 - 提示词:“你这个回答基于哪些未言明的假设?”、“在什么情况下这个结论会不成立?”、“这个解决方案的潜在成本和风险是什么?” - 目的:任何回答都有其成立的隐含前提。找出这些前提能立即发现观点的局限性。(PS:我不想谈恋爱,隐含前提是不想和你) 3、寻求对立观点。 - 提示词:“请列举反对这个观点的最强有力的三个论据。”、“如果持相反立场的人会如何反驳你?”、“这个方案有哪些潜在的负面影响?” - 目的:换位思考。 4、检验逻辑一致性。 - 提示词:“你回答中的A点和B点似乎存在矛盾,请解释。” - 目的:AI有时会生成“乍看正确实则逻辑混乱”的内容,尤其是在复杂推理中。 主动引导纠偏有很多种方式,以上4个维度是基础的形式,可以根据基础再进行额外的扩展。基于自身遇到的问题而产生对应的处理方式才是合理的成长路径,而非大量摄入方法论(这只会使我们面对问题时纠结使用哪种方法论)。通过主动引导纠偏,我们不仅仅是得到了一个更好的答案,更重要的是**提升了自己的批判性思维和深度思考能力**。这才是与AI协作中最宝贵的收获。 参考方法论(自行查阅):“六顶思考帽”法、“如果...会怎样?”情景挑战法、第一性原理追问法,角色扮演法等。

下载 APP