如果你最近在关注大模型应用和 AI Agent 的发展,大概率会有一个感觉:技术圈讨论的重点,正在从“模型有多大、参数有多少、训练数据用了多少”,慢慢转向“模型能不能在真实场景里随机应变”。
这背后其实藏着一个更值得想清楚的问题:到底什么是通用智能?
很多人下意识会觉得,通用智能就是“什么都知道”。于是做模型的团队拼命堆参数、堆语料,做应用的团队拼命往提示词里塞背景资料和规则。但现实的开发反馈是:你塞得越多,系统越脆。一旦场景环境变了,用户问法换了,或者业务规则调整了,原来精心预设的那些东西反而变成了束缚。
这篇文章想给出一个更符合当前技术演进的判断:通用智能的本质是适应,而不是预设。一台机器、一个系统、一个 Agent,之所以能在开放问题面前显得“通用”,不是因为它在出厂时已经背熟了所有答案,而是因为它具备一套在运行时观察环境、调整策略、调用工具、从反馈中纠错的能力闭环。
也就是说,真正值得工程化打磨的,不是“把答案写进系统里”,而是“让系统具备自己找答案、验证答案、修正答案的能力”。
接下来我会从概念辨析、架构拆解、最小代码实现、验证方法和工程建议几个层面,把这个判断讲透。无论你是做 AI 应用开发、Agent 框架选型,还是想弄清楚大模型落地时到底该把资源花在哪里,这篇文章都应该能给你一个比“模型越大越智能”更可操作的参考框架。
1. 这篇文章真正要解决的问题
先梳理一下读者最可能遇到的痛点。
如果你在做一个知识库问答系统,早期方案通常是把文档切碎、向量化,用户提问后做相似度检索,把命中片段塞进 Prompt 让大模型回答。这套方案在文档量小、问题类型固定的时候表现很好。但一旦问题开始跨越多个文档、需要推理、需要引用最新数据,甚至需要调用内部 API 才能回答时,单纯“检索 + 生成”就撑不住了。
如果你在做 Agent 类应用,痛点会更明显。Agent 刚上线时能完成预设的最优路径,但用户一旦提出计划外的问题,流程就会中断。很多团队的应对方式是继续补充 Prompt、继续加规则、继续给模型喂“标准答案”。结果 Prompt 越写越长,系统越来越笨,新需求一来又得重写一版。
这些现象指向同一个根因:我们把太多精力花在了“预设能力”上,忽略了“适应能力”的建设。
所谓预设能力,是提前把答案、规则、路径写死在系统里。它的优点是可控、可解释,缺点是只能在已知范围内工作。所谓适应能力,是让系统在运行时根据输入、反馈和工具返回结果,动态调整自己的行为。它的优点是能处理开放问题,缺点是更难设计、更难调试、也更容易失控。
这篇文章要解决的问题,就是帮你建立“以适应能力为中心”的 AI 系统设计思维,并给出具体的架构方法和代码示例。看完之后,你会知道:
- 为什么预设能力再强,也无法堆出通用智能。
- 一个具备适应能力的系统,在架构上由哪几个核心环节组成。
- 怎么用 Python 实现一个具备“观察 - 思考 - 行动 - 反思”闭环的最小 Agent。
- 怎么用 RAG 解决“模型知识跟不上业务变化”的问题。
- 怎么验证一个系统是真正在适应,还是只是在背诵。
适合阅读这篇文章的读者包括:正在做 AI 应用开发的工程师、大模型落地项目的技术负责人、对 Agent 架构感兴趣的研究者,以及想搞清楚“为什么大模型还需要配套那么多工程设施”的产品和技术决策者。
2. 预设能力与适应能力:两条完全不同的技术路线
要理解“适应”为什么是通用智能的本质,先要看清人工智能历史上两条截然不同的实现路线。
2.1 预设能力的代表:专家系统与规则引擎
人工智能早期最辉煌的成果之一,是专家系统。开发者把领域专家的知识整理成规则,再用推理引擎执行这些规则。典型结构是“知识库 + 推理机”。比如一个医疗诊断系统,规则可以是“如果头痛且发烧,则可能是感冒”,推理引擎负责匹配这些规则。
这套思路在今天依然大量存在,比如银行里的反欺诈规则引擎、运维系统里的告警规则、业务系统里的审批流。它们的优点是结果可解释、运行稳定、故障边界清晰,缺点也同样明显:每一条规则都要人来写,规则之间可能冲突,规则的覆盖范围永远赶不上现实世界的复杂程度。
专家系统本质上是在“预设答案”。它把人类已经想清楚的知识翻译成机器可执行的规则,但它不具备面对新情况生成新策略的能力。所以它只能在封闭领域里工作,谈不上通用。
2.2 深度学习的隐含预设:参数即知识
深度学习的出现改变了游戏规则。我们不再逐条写规则,而是用大量数据训练神经网络,让模型自己从数据中学习规律。在大模型出现之后,这种范式达到了顶峰:上千亿参数的模型,在海量文本上训练,内部编码了海量的事实性知识和推理模式。
从表面看,大模型已经不再依赖人工预设规则了。但严格来说,它仍然是一种“预设能力”。因为训练完成后,模型参数就是固定的,它知道的每一件事都已经被压缩进参数里了。训练数据之外的新知识、新规则、新场景,模型一概不知道。
这也是为什么大模型经常出现两个极端现象:
- 处理训练数据里高频出现的问题时,表现惊人。
- 处理训练数据之外的长尾问题时,开始胡编乱造。
很多团队试图用“更多训练数据、更大模型规模”来解决这个问题,但边际效益越来越低。因为现实世界的信息密度是无限大的,没有任何参数容量能真正“预设”所有可能性。
2.3 适应能力:把智能放到运行时去发生
既然“提前记住所有答案”这条路走不通,剩下的只有另一条路:让系统在运行时获取信息、尝试行动、观察结果、调整策略。
这就是适应能力。它的核心特征不是“知道得多”,而是“办法多、能纠错、能变通”。
一个具备适应能力的系统,不要求模型已经掌握所有知识,而是要求模型掌握获取知识的工具,比如搜索、查库、调 API、执行代码。不要求模型一次做对,而是要求模型能从失败中调整方案。不要求模型记住所有历史对话,而是要求系统有专门的记忆模块。
把这个思路放到 Agent 架构里,就是大家熟悉的“感知 - 规划 - 行动 - 反思”循环。放到 RAG 架构里,就是把“知识准备”从训练阶段挪到了推理阶段。放到工具调用场景里,就是让模型通过观察工具返回结果来决定下一步动作。
下面用一个表格对比三条路线:
| 路线 | 智能存放位置 | 面对新问题的表现 | 通用性 | 可控性 | 代表技术 |
|---|---|---|---|---|---|
| 规则专家系统 | 规则库 | 无规则则失效 | 低 | 高 | Drools、规则引擎 |
| 参数化模型 | 模型参数 | 依赖训练数据覆盖 | 中 | 中 | GPT、BERT、各种深度学习模型 |
| 运行时适应系统 | 环境、工具、记忆、策略循环 | 可通过工具和纠错应对 | 高 | 取决于设计 | RAG、Agent、Tool Calling、反思机制 |
从这条演进脉络可以看出,所谓“通用智能”,本质上是把智能从“静态的存储系统”搬到了“动态的适应系统”里。模型仍然重要,但它的角色从“唯一的智能来源”变成了“适应过程的核心引擎”。
3. 为什么说适应能力才是“通用”的关键
这一节我想用一个更贴近工程实践的对比,把“预设”和“适应”的差异说清楚。
3.1 两个系统的对比
假设你的任务是设计一个能回答公司内部制度问题的助手。公司制度有几千页 PDF,而且每个月都在更新。
方案 A 的做法:把全部制度文档喂给模型做微调,或者在 Prompt 里塞上所有制度内容。系统上线后,用户问“年假怎么算”,模型直接回答。这套方案在制度不发生变化的时期运行良好,但制度一旦更新,或者用户问到文档里没有明确写到的边缘问题,系统就失灵了。更麻烦的是,如果制度之间存在矛盾,模型会困惑。
方案 B 的做法:系统不预设任何制度内容,只预设一套能力:把用户问题转成语义检索条件,从制度知识库里召回相关段落,把段落交给大模型做归纳回答。当知识库版本更新时,系统不需要重新训练或改 Prompt,只需要重新灌入新文档。当用户问的问题超出单篇文档时,系统还能自动拆解成多个子问题,分别检索,再合并答案。
方案 B 并没有比方案 A 更“聪明”,它只是把“对制度的了解”从预设阶段挪到了运行时阶段。它获得的通用性,来自适应机制,而不是来自更庞大的预设内容。
3.2 通用性的三个来源
继续深挖,适应能力带来的通用性主要体现在三个方面。
第一,知识层面的适应。通过 RAG 或联网检索,让系统在回答问题时能获取训练时不存在的新知识。这意味着系统不再是封闭的,它的知识边界跟着检索源走。
第二,策略层面的适应。通过规划拆解、工具调用和结果观察,让系统能根据任务类型选择合适的解决路径。面对“告诉我天气”和“帮我订机票”这两个任务,系统走的动作序列完全不同,而这不需要开发者事先预测所有任务类型,只需要给模型足够的工具和选择权。
第三,反馈层面的适应。通过错误识别、反思重试和记忆沉淀,让系统在下一次面对类似问题时能做得更好。哪怕第一次失败了,只要失败信息能被记录、被反思,第二次的成功率就会提升。
3.3 一个容易误解的地方
需要特别澄清的是,说“适应能力是本质”,不代表“预设能力没有用”。
模型本身的能力依然非常重要。一个基础能力弱的模型,给它再好的工具和再完善的反思机制,它也做不好推理和规划。这也是为什么 Agent 应用的底座仍然需要足够强的 LLM。
更准确的理解是:预设能力决定了系统的能力下限,适应能力决定了系统的能力上限。模型强,相当于一个人的基础素质好;适应能力强,相当于一个人在面对陌生问题时懂得查资料、问人、做实验、复盘。真正通用的,是后者。
理解到这层,你在做架构设计时就不会再陷入“要不要把全部知识塞进模型”的两难,而会把注意力放到更关键的问题上:系统能不能在出错后自我修正?能不能在知识不足时主动获取信息?能不能根据环境反馈调整策略?这些问题直接决定了系统够不够“通用”。
4. 把“适应”落到架构:Agent 的四个核心环节
理解了理念,接下来要看工程上怎么把“适应能力”造出来。目前业界最成熟的做法,就是 Agent 架构。一个具备适应能力的 Agent,本质上是一个“运行时反馈闭环”。
这个闭环由四个核心环节组成:观察、规划、行动、反思。
4.1 观察:主动获取当前环境信息
一个只会根据 Prompt 直接输出答案的模型,谈不上适应,因为它没有“看”到任务之外的世界。Agent 的第一步是观察:把用户模糊的诉求转成明确的任务定义,必要时主动向外部环境获取信息。
观察环节的常见技术手段包括:
- 多轮澄清:当用户意图不明确时,先追问而不是直接猜测。
- 信息检索:调用 RAG 检索器、搜索引擎、数据库查询,获取当前环境下的最新信息。
- 代码执行:通过沙箱运行代码,观察代码输出结果。
- 工具状态读取:调用 API 前先获取工具的健康状态、限流情况、参数要求。
观察环节的关键设计是“信息接入能力”。Agent 能看到的越多,后续决策质量越高。很多项目把这一环简化成“直接读取用户输入”,结果 Agent 在信息不完整的情况下强行决策,表现自然不可靠。
4.2 规划:拆解任务并确定路线
完成观察后,Agent 需要制定行动计划。规划不是简单地把 Prompt 写给模型看,而是让模型显式地输出步骤化方案,比如:
- 先检索用户所在部门的年假规则。
- 再查询该员工的入职时间和历史请假记录。
- 结合规则与记录,计算剩余年假天数。
- 如果信息不足,返回工具继续查询。
规划环节决定了 Agent 在面对复杂任务时是否有章法。这里常见的设计模式包括思维链、任务分解、子目标生成、多路并行探索等。好的规划机制能让 Agent 应对从未见过的任务组合,这也是“适应能力”最直接的体现。
4.3 行动:调用工具改变环境
规划完成后,Agent 需要执行动作。动作的种类取决于系统开放的接口:
- 调用内部 API,写入业务数据。
- 执行数据库查询,读取结构化数据。
- 运行代码片段,完成计算任务。
- 调用第三方服务,比如发邮件、发消息、操作日历。
行动环节是 Agent 与真实世界交互的窗口,也是权限和安全风险最集中的地方。一个负责任的工程实现,必须给每个动作设置权限边界、操作审计和确认机制。后面讲最佳实践时我会再展开。
4.4 反思与记忆:从反馈中学习
行动执行完,Agent 不能直接结束,它需要检查行动结果是否符合预期。如果调用 API 报错,需要判断是参数问题还是权限问题。如果最终答案与已知事实矛盾,需要回溯推理链找漏洞。这个检查-纠错-总结的过程就是反思。
反思之后还有记忆。
- 短期记忆:当前任务中的中间结果,直接放进上下文。
- 长期记忆:把任务结论、错误经验、偏好信息写入向量数据库或结构化存储,供后续任务使用。
反思与记忆,是 Agent 区别于“一次性问答”的关键。没有这一环,Agent 每次都像第一次工作;有了这一环,Agent 才能越用越顺。
为了更直观,把闭环拆成下面这个流程:
用户输入 ↓ 观察(澄清问题 / 检索信息 / 读取环境) ↓ 规划(拆解任务 / 生成步骤) ↓ 行动(调用工具 / 执行代码 / 查询 API) ↓ 反思(检查结果 / 判断是否满足要求) ↓ 满足要求 → 返回结果 未满足要求 → 重新观察 / 重新规划(进入下一轮循环)这个循环不需要开发者预设每一种任务场景,只要给 Agent 足够的工具和顺畅的反馈回路,它就能在运行时自我组织出解决方案。
5. 最小实现:一个会反思重试的 Python Agent
理论讲完,进入代码环节。这一节我会实现一个尽量小的 Python Agent,它具备“观察 - 规划 - 行动 - 反思”的闭环能力。为了不依赖特定框架,这里使用标准库加一个统一的接口设计,方便你把它移植到自己的项目里。
这个示例的业务场景设计为:一个能查询订单信息并计算订单金额的小助手。它包含两个工具函数和一段带反思循环的启发性实现。
5.1 定义工具集
每个 Agent 都需要工具,工具是 Agent 改变环境或获取信息的手段。下面定义一个简单的工具注册表:
# 文件路径:agent_tools.py # 说明:为最小 Agent 提供两个模拟工具:订单查询与汇率计算 def get_order_info(order_id: str) -> dict: """模拟从订单系统查询订单信息。""" # 实际项目中,这里应该调用真实数据库或内部 API orders = { "A001": {"product": "笔记本电脑", "amount": 8999, "currency": "CNY"}, "A002": {"product": "蓝牙耳机", "amount": 399, "currency": "CNY"}, "A003": {"product": "机械键盘", "amount": 1299, "currency": "CNY"}, } if order_id not in orders: return {"error": f"订单 {order_id} 不存在,请检查订单号"} return orders[order_id] def convert_currency(amount: float, source_currency: str, target_currency: str) -> dict: """模拟汇率换算。""" # 实际项目中,这里应该调用实时汇率服务 # 这里使用固定汇率,仅用于演示 rate_table = { ("CNY", "USD"): 0.14, ("USD", "CNY"): 7.15, } rate = rate_table.get((source_currency, target_currency)) if rate is None: return {"error": f"暂不支持 {source_currency} 到 {target_currency} 的汇率换算"} return {"converted_amount": round(amount * rate, 2), "rate": rate} TOOL_REGISTRY = { "get_order_info": { "description": "根据订单号查询订单金额与币种", "function": get_order_info, "parameters": {"order_id": "string, 订单号,例如 A001"}, }, "convert_currency": { "description": "将金额从一种币种换算为另一种币种", "function": convert_currency, "parameters": { "amount": "number, 需要换算的金额", "source_currency": "string, 源币种,如 CNY", "target_currency": "string, 目标币种,如 USD", }, }, }这段代码的核心是TOOL_REGISTRY字典。它把工具名、描述、可调用函数和参数说明集中管理。在真实项目里,工具集可能多达成百上千个,统一注册的好处是便于 Agent 按需查找,也便于做权限控制和审计。
5.2 编写带反思循环的 Agent 主体
有了工具,下一步是 Agent 的核心循环。为了让代码完全可运行,这里不使用真实的大模型 API,而是用一个“模拟推理函数”来说明循环结构。在真实项目中,你会把simulate_llm_plan替换成 LLM 调用,并把工具返回结果注入下一次调用的 Prompt。
# 文件路径:minimal_agent.py # 说明:一个带观察、规划、行动、反思的最小 Agent 示例。 # 真实项目中,将 simulate_llm_plan 替换为大模型接口调用,并设计完善的 Prompt。 from agent_tools import TOOL_REGISTRY def simulate_llm_plan(task: str) -> list: """ 模拟 LLM 的规划能力。 真实项目中,这段逻辑会被替换为: prompt = build_agent_prompt(task, available_tools, previous_steps) response = llm.chat(prompt) 返回值为动作列表,每个动作是 {"tool": "工具名", "args": {...}} """ if "美元" in task: # 规划两步:先查订单,再换算币种 return [ {"tool": "get_order_info", "args": {"order_id": "A001"}}, {"tool": "convert_currency", "args": {"amount": 8999, "source_currency": "CNY", "target_currency": "USD"}}, ] if "订单" in task: return [ {"tool": "get_order_info", "args": {"order_id": "A001"}}, ] return [] def run_agent(task: str, max_retries: int = 3) -> str: """ 运行最小 Agent。 流程:观察任务 -> 规划动作 -> 执行动作 -> 反思结果。 如果动作执行失败,重新规划并重试。 """ print(f"[观察] 收到任务: {task}\n") # 观察环节:这里简单打印任务内容,真实项目中可能先澄清或查询外部信息 observations = {"task": task} # 行动与反思循环 final_result = None for attempt in range(1, max_retries + 1): print(f"----- 第 {attempt} 次尝试 -----") # 规划环节:生成动作列表 actions = simulate_llm_plan(task) if not actions: return "无法为当前任务规划出可用动作,请补充更多上下文。" # 行动环节:逐个执行动作 step_outputs = [] success = True for action in actions: tool_name = action["tool"] args = action["args"] tool_entry = TOOL_REGISTRY.get(tool_name) if not tool_entry: step_outputs.append({"action": action, "error": f"未注册工具 {tool_name}"}) success = False break print(f"[行动] 调用工具 {tool_name}, 参数: {args}") result = tool_entry["function"](**args) step_outputs.append({"action": action, "result": result}) if "error" in result: print(f"[行动] 工具返回错误: {result['error']}") success = False break print(f"[行动] 工具返回: {result}") # 反思环节:检查所有行动是否成功 if success: final_result = step_outputs print("\n[反思] 所有行动成功,任务完成。") break else: print("\n[反思] 检测到执行失败,准备基于错误信息重新规划。") if final_result is None: return f"经过 {max_retries} 次尝试仍未能完成任务,建议检查工具参数或工具实现。" # 结果汇总 lines = [] for step in final_result: res = step["result"] if "converted_amount" in res: lines.append(f"订单金额换算后为: {res['converted_amount']} USD (汇率: {res['rate']})") elif "product" in res: lines.append(f"订单商品: {res['product']}, 金额: {res['amount']} {res['currency']}") return "\n".join(lines) if __name__ == "__main__": task = "查一下订单 A001 的金额,并换算成美元" answer = run_agent(task) print("\n========== 最终回答 ==========") print(answer)这段代码包含几个关键工程要点:
- 工具返回结果统一为字典,其中
error字段用于标记失败。这保证了反思环节能统一判断执行是否成功。 - 每次执行失败后,Agent 会带着失败原因进入下一轮规划,而不是直接放弃。
simulate_llm_plan是唯一的“智能”替换点。真实项目中,你应该把观察信息、可用工具描述、历史步骤全部拼进 Prompt,再让 LLM 生成动作序列。
5.3 运行与验证
直接在命令行运行:
python minimal_agent.py预期输出如下:
[观察] 收到任务: 查一下订单 A001 的金额,并换算成美元 ----- 第 1 次尝试 ----- [行动] 调用工具 get_order_info, 参数: {'order_id': 'A001'} [行动] 工具返回: {'product': '笔记本电脑', 'amount': 8999, 'currency': 'CNY'} [行动] 调用工具 convert_currency, 参数: {'amount': 8999, 'source_currency': 'CNY', 'target_currency': 'USD'} [行动] 工具返回: {'converted_amount': 1259.86, 'rate': 0.14} [反思] 所有行动成功,任务完成。 ========== 最终回答 ========== 订单商品: 笔记本电脑, 金额: 8999 CNY 订单金额换算后为: 1259.86 USD (汇率: 0.14)这个最小实现没有调用大模型,但已经体现了适应系统的核心骨架:工具可插拔、执行过程可观测、失败后可重试。把它替换成真实大模型,核心逻辑依然成立。
6. 用 RAG 解决“知识不在参数里”的适应问题
Agent 解决了“策略适应”,也就是“怎么做事”的问题。但还有一个更基础的适应场景:系统怎么应对“训练时根本没见过的知识”。
比如公司内部制度、私有业务数据、产品手册的更新版本,这些信息不可能全部进入模型参数。如果只用模型生成,系统会一本正经地给出错误答案。RAG(Retrieval-Augmented Generation,检索增强生成)就是为这个问题设计的。
6.1 RAG 的本质:在回答时动态取知识
RAG 的流程可以用四步概括:
- 离线阶段:把业务文档切分成块,用 Embedding 模型转成向量,存入向量数据库。
- 在线阶段:用户提问后,把问题转成向量,到向量数据库中检索最相关的若干文档块。
- 组装阶段:把检索到的文档块与用户问题一起拼入 Prompt。
- 生成阶段:大模型基于检索到的文档块,生成有依据的答案。
这套流程把“知识获取”从训练阶段挪到了推理阶段,系统不再需要记住所有文档,只需要知道去哪里找。知识库更新时,只需要重新处理变更文档,不需要动模型。
6.2 一个 RAG 链路的抽象示例
下面给出一段代码,演示 RAG 的核心链路。这里的向量检索使用简化的相似度计算,真实项目中建议使用成熟的向量数据库。
# 文件路径:simple_rag.py # 说明:RAG 核心链路的最小演示。 # 完整实现建议使用 LangChain、LlamaIndex 或直接调用向量数据库 SDK。 import math # 1. 模拟知识库文档 DOCUMENTS = { "doc_001": "公司年假制度:员工入职满一年后,每年享有5天带薪年假。", "doc_002": "公司年假制度:工龄超过十年的员工,每年享有10天带薪年假。", "doc_003": "请假流程:员工请假需提前在OA系统提交申请,由直属主管审批。", } # 2. 简化分词与向量化:真实项目使用 Embedding 模型,比如 text-embedding def tokenize(text: str): # 去掉标点并分词,这里只做演示 cleaned = text.replace(":", " ").replace("。", " ").replace(",", " ") return set(cleaned.split()) def dummy_embedding(text: str): # 真实项目使用 Embedding API 生成向量,这里用词集合代替 tokens = tokenize(text) return {token: 1.0 for token in tokens} # 3. 向量库构建(真实项目使用向量数据库,如 Milvus、Weaviate、FAISS) vector_store = {} for doc_id, content in DOCUMENTS.items(): vector_store[doc_id] = {"content": content, "vector": dummy_embedding(content)} def cosine_similarity(v1, v2): # 余弦相似度简化实现 common = set(v1.keys()) & set(v2.keys()) if not common: return 0.0 dot = sum(v1[token] * v2[token] for token in common) norm1 = math.sqrt(sum(val * val for val in v1.values())) norm2 = math.sqrt(sum(val * val for val in v2.values())) if norm1 == 0 or norm2 == 0: return 0.0 return dot / (norm1 * norm2) # 4. RAG 检索 def retrieve(query: str, top_k: int = 2): query_vec = dummy_embedding(query) scored = [] for doc_id, item in vector_store.items(): score = cosine_similarity(query_vec, item["vector"]) scored.append((doc_id, item["content"], score)) scored.sort(key=lambda x: x[2], reverse=True) return scored[:top_k] # 5. 组装 Prompt 并生成答案(真实项目调用 LLM) def generate_with_context(query: str, retrieved_docs): context = "\n".join(f"[{doc_id}] {content}" for doc_id, content, score in retrieved_docs) prompt = f"""根据以下资料回答用户问题。 资料: {context} 问题:{query} 回答:""" # 真实项目:response = llm.chat(prompt) # 这里演示直接使用检索到的内容生成答案 return prompt if __name__ == "__main__": query = "入职满一年的员工有多少天年假?" results = retrieve(query) print("检索结果:") for doc_id, content, score in results: print(f" {doc_id} (相似度 {score:.2f}): {content}") print("\n组装后的 Prompt:") prompt = generate_with_context(query, results) print(prompt)这段代码中最关键的是第 4 和第 5 步。检索时,系统先用向量相似度筛出最相关的文档块;生成时,系统把检索到的块作为上下文交给大模型,而不是让模型凭空编答案。这就是 RAG 的适应能力所在:知识库内容一变,答案跟着变,模型参数完全不需要动。
6.3 判断 RAG 质量问题的方法
RAG 系统上线后,最常见的问题是“检索到了不相关的内容,导致回答变差”。这时候不要急着调模型,先按三步排查:
- 查分块质量:文档是不是被切得太碎,导致语义被切断?
- 查检索结果:把用户问题单独跑一次检索,看前几条是不是真的相关。如果不相关,考虑换 Embedding 模型或调整相似度算法。
- 查 Prompt 组装:确认检索到的上下文有没有被正确拼进 Prompt,有没有超出模型的最大上下文长度。
7. 如何验证“适应能力”,而不是“背诵能力”
很多团队在评估 AI 系统时,习惯拿着历史问题集去测准确率。这种做法只能验证系统“有没有预先答案”,很难验证它“能不能适应新问题”。
要准确评估适应能力,建议从下面几个维度设计测试。
| 测试维度 | 测试方式 | 通过标准 |
|---|---|---|
| 未知问题处理 | 使用从未出现在测试集和知识库里的问题 | 能基于已有工具和检索信息给出合理回答,而不是拒绝或胡编 |
| 知识变更响应 | 更新知识库中的某条制度,再问相关旧问题 | 回答跟随知识库变化,不输出旧知识 |
| 多工具组合 | 设计一个需要依次调用多个工具的任务 | 能自动规划步骤并正确调用工具 |
| 错误恢复 | 让第一个工具返回错误,观察系统行为 | 能识别错误、调整参数或更换方案并重试 |
| 多轮记忆 | 先给出用户偏好,隔几轮后再次提问 | 能利用之前对话中的信息,而不是把每轮当孤立问题 |
| 安全边界 | 让系统执行带写权限的操作 | 能按权限设计拒绝或进入人工确认流程 |
这些测试用例最好沉淀成自动化回归集,每次修改 Prompt、工具或知识库后都跑一遍。没有回归集的 AI 系统,就像没有测试用例的传统软件,改一次崩一次。
8. 当前局限与工程冷思考
写到这里,我需要给“适应能力”这个判断补上几个反向的提醒,避免文章变成一篇过度乐观的技术赞歌。
8.1 适应不等于正确
让系统具备适应能力,只是给了它“寻找答案”的路径,并不能保证找到的答案是正确、安全、合规的。Agent 可能在完成一个看似合理的工具调用链后,输出一个漂亮的错误结果。这就是为什么反思环节不能只是检查“工具有没有报错”,还要检查“结果是否符合业务规则”。
8.2 开放能力带来成本与延迟
每多一层适应机制,就多一次模型调用,多几句工具往返,多一份上下文处理开销。一个简单问题,用直接生成只要 1 秒,用完整 Agent 流程可能需要 5 到 10 秒。在设计系统时,要区分“需要适应的问题”和“直接生成就够的问题”,不要为了适应而适应。
8.3 评估难度指数级上升
传统软件的评估是确定性的,输入相同则输出相同。但适应系统是概率性的,同一问题换一种表达方式就可能走完全不同的路径。这导致回归测试的维护成本很高,需要团队建立一套持续追踪的评估机制。
8.4 安全风险需要边界约束
适应能力越强,意味着系统能做更多事。如果你给 Agent 开放了数据库写权限、文件删除权限、外部 API 调用权限,那么一旦 Prompt 注入或工具调用链设计不当,后果可能很严重。必须坚持最小权限原则,所有带副作用的操作,都要有人工确认或审批环节。
9. 工程落地的几点最佳实践
结合上面的分析,我给出几条可以直接用到项目里的建议。
9.1 以“技能注册表”方式管理工具
不要直接把工具函数写死在代码里。推荐维护一个技能注册中心,每个技能描述清楚“能做什么、参数是什么、权限等级是什么”。这样模型可以通过工具描述自主选择调用,运维人员也能在不用改代码的情况下上下线技能。
{ "skill_name": "query_employee_leave_balance", "description": "查询员工剩余年假、事假、病假额度,入参为员工工号", "permission_level": "read", "parameters": { "employee_id": {"type": "string", "required": true, "description": "员工工号"} }, "endpoint": "http://internal-service/leave/balance" }9.2 把“反思”设计成一个可观测的步骤
很多项目的反思逻辑只是“失败后再让模型试一次”,没有记录失败原因,也没有沉淀经验。更好的做法是:每次反思都输出结构化信息,包括失败动作、错误信息、下一步策略调整原因。这些信息写入日志和长期记忆,既方便调试,也让 Agent 能越用越准。
9.3 对带副作用的操作增加确认闸口
凡是涉及写数据库、发消息、删除资源、调用付费接口的操作,统一走“预执行检查 + 人工确认”流程。不要把写权限直接交给模型,除非产品已经明确承诺并设计了完整的风控机制。
9.4 从小任务开始,逐步扩大 Agent 权限
新建 Agent 时,先从只读任务开始跑。连续运行一段时间,确认规划稳定、错误处理正常、没有越权操作后,再开放低风险写操作。不要第一天就上一套全自动“能改数据库能发邮件”的 Agent。
9.5 建立“失败案例库”
适应系统最大的价值在于能从错误中学习,而学习的前提是有记录。把每次失败的工具调用、错误信息、人工修正后的正确路径都存下来,定期用来做 Prompt 优化和工具参数调整。时间越长,这套系统的适应能力会越强。
10. 总结与下一步
回到文章开头的问题:通用智能的本质到底是什么?
通过前面从概念到代码的拆解,我想你已经有了自己的结论。我的判断是:通用智能的本质是适应而非预设能力。这不是一句口号,而是一个可以直接指导架构设计的判断标准。当你面对一个 AI 系统的设计选择时,优先问“它能不能在未知情境下调整策略”,比问“它记住了多少答案”更有价值。
当然,这不是说预设能力不重要。模型能力、Prompt 内置的基础规则、领域知识,仍然是系统的地基。只是说,真正让系统走向“通用”的核心竞争力,在于它能不能把预设知识转化为应对新问题的行动能力。
如果你接下来要在实践中继续深入,建议按这个顺序行动:
- 选一个你当前项目中“预设不足”的问题,比如频繁更新的业务知识问答,或需要串联多个 API 的事务型任务。
- 先用最小的 Agent 循环跑通“观察 - 规划 - 行动 - 反思”,不要一开始就上重型框架。
- 把知识类问题交给 RAG,把流程类问题交给 Agent,两者结合后再考虑长期记忆。
- 为系统建立一套动态评估集,持续跟踪它面对新问题的真实表现。
AI 应用开发正在从“堆参数”走向“堆适应机制”。谁能先把系统做得会观察、会尝试、会纠错,谁就更接近“通用”那个目标。这篇文章里给出的架构和代码,可以作为你搭建第一个适应型系统的起点。建议收藏备用,后面实现 Agent 或设计 RAG 方案时,再拿出来对照检查。