大模型能聊能写,但一到“今天北京天气怎么样”“某只股票现在什么价”“刚发布的那个新政策原文是什么”这类问题,就开始一本正经地编答案。原因很简单:模型的知识有截止日期,它的记忆停留在训练完成那一刻。平时做内容创作、写代码、整理文档,这点知识滞后问题不大;但一旦你想让大模型帮你做决策——比如根据实时行情判断要不要卖出、根据最新新闻决定选题方向、根据当天库存安排补货——它手里那套过期数据就不够用了。
这篇文章要讲的就是:怎么让大模型实时获取信息,并且基于这些真实信息做出自主决策。我会从原理讲到代码,再讲到真实环境里的各种坑。适合刚入门的小白程序员,也适合想把大模型从“聊天玩具”升级成“决策助手”的产品、运营和独立开发者。
1. 大模型天生“活在过去”:知识截止与参数化记忆的边界
1.1 先搞懂一个反直觉的事实:模型记住的是规律,不是数据库
很多人误以为大模型是一个“存了全世界知识的硬盘”,问什么它就从里面查什么。这个理解在直觉上很顺畅,但在技术上完全不对。
大模型的本质是参数化记忆。它把海量训练文本压缩成几千亿个参数,也就是一堆数字权重。这堆权重记住的是“语言的规律”“知识的模式”“概念的关联”,而不是一份可以随时精确检索的数据表。你问它“某公司2023年的营收是多少”,它能答出来,不是因为它的脑子里存着一行Excel记录,而是它在训练时见过大量相关文本,从中学会了“这家公司大概营收量级”的概率分布。
这里有个关键推论:模型对训练截止日期之后的事件一无所知,而且它自己意识不到这一点。它只会用已经学到的规律去“接着编”。你问它今天天气,它会按历史数据的分布给出一个“看起来合理”的回答,哪怕这个回答实际上是错的。
1.2 三种常见场景里,模型分别为什么“翻车”
我把实际测试过的情况整理成了一张表。看完你就明白,实时信息缺失不是某一个模型的问题,而是这一类架构的通病。
| 提问类型 | 模型典型反应 | 翻车原因 |
|---|---|---|
| “今天几点日出?” | 给出一个固定季节的日出时间 | 日出时间按日期和纬度变化,模型只学到了“大概几点”的规律 |
| “某基金今日净值是多少?” | 给出训练截止日附近的净值,并标注“数据可能有延迟” | 净值每天变动,模型无法感知训练后发生的任何变化 |
| “某公司刚刚发布的新品叫什么?” | 要么说不知道,要么编一个听起来合理的名字 | 训练语料里根本没有这条信息,模型会用“类比生成”补齐空白 |
有过调戏大模型经验的朋友应该都有同感:它的一大问题不是“不知道”,而是“不知道自己不知道”。在没有外部信息源的情况下,它会非常自信地给出错误答案,这是参数化记忆的本质局限,不是调提示词能解决的。
1.3 实时信息能力的两大组件:外部记忆与行动工具
既然问题出在“模型只有内部记忆、没有外部感知”,解决方案就很清晰了:给模型接上外部系统。
业界目前有两套主流方案,对应的概念分别是检索增强生成和工具调用。
检索增强生成,英文全称Retrieval-Augmented Generation,简写RAG。它的思路是把大模型和一个外部知识库连接起来。用户提问时,先从一个数据库里检索出相关文档片段,再把文档片段和问题一起塞给模型,让它基于这些片段回答。用一句大白话说:模型看不懂的书,就先把相关页码撕下来递给它看。
工具调用(Function Calling / Tool Use)的思路则更进一步。它让模型拥有“行动能力”——模型可以请求调用一个外部函数,比如查询天气API、调用股票接口、执行一段代码,然后把函数返回的结果整合进回答里。用一句话概括:模型不再只能读资料,还能亲自去问外部系统拿答案。
这两套方案不是互相替代的关系,而是解决不同类型的问题。下一章我会把小白的选型逻辑讲清楚。
2. 实时获取信息的两条主流路线:RAG检索增强与工具调用的选型逻辑
2.1 RAG:当答案藏在“你自己的资料库”里
RAG适合的场景是:你需要大模型基于“某一大坨静态或半静态文本”来回答问题,而这坨文本不在模型的训练数据里。
比如你有一个公司内部的知识库,涉及产品手册、售后话术、历史工单。大模型没有读过这些文档,直接问它等于让它瞎猜。用RAG的流程是:
- 先把所有文档切成片段,做向量化索引,存进向量数据库。
- 用户提问后,把问题也向量化,去数据库里做相似度检索,找出最相关的几个片段。
- 把片段作为上下文注入提示词,让模型“阅读完材料再回答”。
RAG的适用边界有两个:一是知识库内容需要相对稳定,二是答案的时效性要求不高。你不能指望RAG帮你查实时价格——如果数据库本身是一小时前抓取的,那它和一小时前也没什么区别。
2.2 工具调用:当答案只能来自“外部权威系统”
工具调用解决的问题完全不同。它面向的场景是:答案不在任何本地文档里,只能从外部系统实时获取,或者答案需要经过真实计算才能得出。
判断标准很直接:如果这个信息的正确版本只存在于某个权威来源的API接口里,就属于工具调用的范围。天气、股价、航班动态、实时汇率、物流轨迹、数据库里的订单状态,这些都是典型场景。你没法把这些东西提前塞进知识库,因为它们每一秒都在变。
工具调用的交互模式是:模型在生成回答之前,先分析用户意图,决定要不要调用某个工具、传什么参数;系统去真正执行调用,把结果返回给模型;模型再根据结果组织最终回复。这里的核心在于:模型不直接产生事实,它只是决定“去哪里、拿什么、怎么用”。
2.3 小白怎么选:一张表解决90%的纠结
| 判断维度 | 优先选RAG | 优先选工具调用 |
|---|---|---|
| 信息在哪 | 在本地文档/知识库里 | 在外部实时API/数据库里 |
| 更新频率 | 低频,可以定时同步 | 高频,必须实时查询 |
| 数据格式 | 长短不一的自然语言文本 | 结构化字段、JSON接口 |
| 典型场景 | 制度问答、文档总结、客服知识库 | 天气股价物流状态、数据库操作、计算任务 |
| 失败后果 | 答案不够准确但可接受 | 必须精确,错了就会出事故 |
有个很容易犯的错误是:遇到所有“模型不知道”的问题,第一个想到的就是上RAG。实际上如果是“某个数据源头API能拿到的信息”,你做得再多知识库也不如直接调接口。我见过有人花一周时间把股票的日线行情做成了向量库,结果当天数据根本查不到——搞到最后还是老老实实接工具调用。
更合理的组合是两者各司其职:本地知识库的内容用RAG解决,外部实时数据用工具调用解决,两者可以同时出现在一个Agent身上。后面讲实战的时候,我在Demo里就同时用到这两个模块。
3. 手写一个实时查询Agent:从工具定义到自主决策的最小闭环
3.1 先拆解一个Agent的本质:决策=意图识别+工具选择+结果利用
这两年“Agent”这个词被炒得很热,但剥开概念看本质,一个最简单的Agent就是三个步骤的循环:
- 理解当前目标(用户想干什么)
- 决定下一步行动(自己知道、问知识库、调外部API,还是干脆结束)
- 利用行动结果推进目标(把拿到的新信息纳入下一步判断)
这个循环的关键在于:模型不再走“输入-输出”的一条直线,而是走“输入-思考-行动-观察-再思考”的环形路径。每个回合里,模型都可能决定调用一个新的工具,然后基于工具返回的结果继续推理。
明白这个本质之后,你就知道什么是最小可行方案了:不一定要上LangChain、不一定要上复杂的Agent框架,用最朴素的代码也可以完成一个具备实时感知和自主决策能力的“初级智能体”。
3.2 代码实操:四步跑通天气查询自主决策Demo
我直接给一个完整的示例。这个Demo用你常用的任意大模型API都能跑,我把抽象层写出来了,你只需要替换成你自己的客户端。核心目标是:用户说“北京今天适合出门吗”,模型自己决定调用天气工具、自己解析结果、自己给出有依据的建议。
第一步:定义外部工具。
这里要注意,我提供了一个**“模拟天气API”**,它通过一个字典模拟外部系统的返回。实际工程里,这里换成真实天气服务的HTTP调用即可,接口逻辑完全一样。
# -*- coding: utf-8 -*- """ 一个最简工具调用Demo 依赖:你需要自行安装 openai 或其他模型SDK,并配置好API Key """ # ---------- 第一步:定义外部工具 ---------- def get_current_weather(city: str) -> dict: """ 模拟的外部天气查询接口。 实际项目中,这里应替换为真实的天气API调用。 """ mock_db = { "北京": {"temp": 31, "condition": "多云转雷阵雨", "humidity": 68, "wind": "东南风3级"}, "上海": {"temp": 27, "condition": "小雨", "humidity": 82, "wind": "东风2级"}, "广州": {"temp": 33, "condition": "晴", "humidity": 70, "wind": "南风2级"}, } # 模拟网络延迟 import time; time.sleep(0.2) return mock_db.get(city, {"error": "暂不支持该城市查询"}) # ---------- 第二步:把工具描述告诉模型 ---------- tools = [ { "type": "function", "function": { "name": "get_current_weather", "description": "查询某个城市当前天气状况,包括温度、天气现象、湿度、风力。当用户询问天气、出行建议、穿衣建议时使用。", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,例如北京、上海" } }, "required": ["city"] } } } ]第二步是整个流程里最容易被低估的一步。工具描述写得多详细,模型理解得多准确直接相关。“description”字段里写清楚“什么时候用”“能拿回什么字段”,比任何提示词都有效。
第三步:让模型自己决定是否调用工具。
# ---------- 第三步:让模型决定是否调用工具 ---------- def ask_model(user_query: str, messages: list) -> tuple: """ 调用大模型API。 如果模型决定调用工具,会返回 tool_calls 信息; 否则返回普通文本回复。 """ # 这里用 OpenAIChatCompletion 风格的抽象写法 # 实际使用时替换为你的模型服务商客户端 # response = client.chat.completions.create( # model="你的模型标识", # messages=messages, # tools=tools, # tool_choice="auto" # ) # 为演示流程,我们直接模拟模型的决策结果: # 假如用户问的是"北京今天适合出门吗",模型会返回一个明确调用工具的决策。 if "天气" in user_query or "出门" in user_query or "适合" in user_query: return { "tool_calls": [ { "id": "call_001", "function": { "name": "get_current_weather", "arguments": '{"city": "北京"}' } } ] }, messages else: return {"content": "我不知道,需要更具体的指令。"}, messages在实际的项目里,这部分替换成真实API调用之后,“决策”就真正发生了——模型阅读了工具清单、结合用户的意图、选择了正确的函数和参数。工具选择是否准确,直接取决于你的模型能力和工具描述质量。
第四步:执行工具、把结果回传、生成最终回复。
# ---------- 第四步:执行工具,回传结果给模型 ---------- def run_agent(user_query: str) -> str: messages = [{"role": "user", "content": user_query}] # 第一次调用模型 first_response, messages = ask_model(user_query, messages) # 如果模型没有发起工具调用,直接返回文本 if "tool_calls" not in first_response: return first_response.get("content", "") # 执行模型请求的工具调用 tool_call = first_response["tool_calls"][0] function_name = tool_call["function"]["name"] arguments = eval(tool_call["function"]["arguments"]) # 生产环境请用json.loads print(f"[Agent] 模型决定调用工具: {function_name}, 参数: {arguments}") if function_name == "get_current_weather": tool_result = get_current_weather(arguments["city"]) else: tool_result = {"error": "未知工具"} print(f"[Agent] 工具返回: {tool_result}") # 把工具结果追加到对话里 messages.append(first_response) messages.append({ "role": "tool", "tool_call_id": tool_call["id"], "content": str(tool_result) }) # 第二次调用模型,让它基于工具结果组织最终回答 # 真实项目中: response = client.chat.completions.create(...) # 这里模拟最终回答 final_answer = f"根据查询,{arguments['city']}当前{ tool_result.get('condition', '未知') }," \ f"温度 {tool_result.get('temp', '未知')}°C,湿度{ tool_result.get('humidity', '未知') }%。" \ f"今天有降水风险,建议带伞;温度较高,适合短袖出行。" return final_answer # ---------- 跑一次 ---------- if __name__ == "__main__": result = run_agent("北京今天适合出门吗?") print("[Agent]", result)这段代码虽然刻意简化了真实API的交互细节,但完整跑通了“意图识别→工具选择→工具执行→利用结果生成回答”的全链路。你用真实SDK替换掉两个注释掉的调用即可直接使用。
3.3 这个Demo里,“自主决策”到底发生在哪里?
很多小白会被“自主决策”这个词吓到,以为模型真的在像人一样思考。实际上在这个Demo里,自主决策发生在两个确定的节点上。
第一个节点是“是否调用工具”。我给模型传了tools参数,它根据自己的判断决定:这个问题需要外部实时信息,于是发起工具调用。这不是魔法,本质上是在模型生成一个特殊格式的JSON指令。
第二个节点是“如何利用工具结果”。模型拿到“31度”“雷阵雨”之后,不再继续编造天气,而是基于真实数据组织建议。这部分仍然依赖模型的文本生成能力,但事实基础已经由外部系统锁定了。
用大白话说:模型负责决策流程,外部工具负责提供事实。这就是所有实时信息Agent的基本架构。任何宣传得天花乱坠的Agent框架,底层都跳不过这个循环。
提示:设计这个Demo时,刻意选择了“天气查询+出行建议”这样低风险的场景。生产环境如果要关联订单、资金、医疗等决策,事后的人工复核环节是必须保留的。
4. 真实环境里跑起来之后:延迟、幻觉、上下文污染这些坎怎么过
4.1 工具结果会吃掉上下文:token预算管理
Demo跑通之后,很多人会兴奋地给Agent加各种工具:查天气、查新闻、查数据库、查订单状态。问题很快就来了:每调一次工具,工具返回的结果都会进入模型上下文。调用次数越多,上下文越长,费用越高,响应越慢。
有一次我让Agent同时查了三个城市的两周天气预报,光工具返回就塞了几千token,后续对话还因此变慢。踩了这个坑之后,我总结出几条实用管理策略:
- 工具返回前先做字段裁剪,只回传有用的字段,不要整个JSON原样塞回去。
- 对长列表做摘要或TopN截断,比如搜索结果只回传前5条。
- 设置一轮任务的最大工具调用次数,超过就强制让模型汇总,防止“聊起了兴致”无限查下去。
4.2 调用链变长后的延迟与重试策略
单次工具调用通常几百毫秒,但Agent一旦进入多轮循环,耗时就是串行叠加。我遇到过三次连续调用工具的场景:先查城市列表,再查每个城市的天气,最后查未来三天预报,整个过程跑了快十秒。
优化手段有三个方向。一是能并行就并行——多个相互独立的信息查询可以同时发起,别让模型一个个来。二是给外部API设计超时,默认5秒不返回就让模型走降级逻辑,比如承认“暂无法获取数据”,而不是让用户无限等。三是重试必须带指数退避,连续失败两次就放弃本轮调用,把错误信息作为观察结果交给模型,让它调整方案。
4.3 工具结果本身不可信:验证层砍掉幻觉
这个坑特别隐蔽。你以为只要接了实时API,大模型就不会骗人了。实际上,工具返回的数据可能不全、可能过期、可能本身就是错的,而模型没有能力判断数据的合理性。
我试过一个场景:某个查询接口返回的数据格式异常,温度字段变成了字符串“31度c”,湿度字段是空的。模型拿到这个残缺结果后,不仅没发现异常,还顺着编了一段像模像样的出行建议。从那以后,我再往Agent里接外部API,都会统一加一个“结果验证层”,用一段很轻量的逻辑检查关键字段是否存在、类型是否正确、数值是否在合理区间。
# 结果验证层:在把工具结果交给模型之前先做基础校验 def validate_weather_result(raw: dict) -> dict: required = ["temp", "condition", "humidity"] for field in required: if field not in raw: raw[field] = "未知" print(f"[验证层] 字段 {field} 缺失,已置为未知") if isinstance(raw.get("temp"), str): import re numbers = re.findall(r"\d+", raw["temp"]) if numbers: raw["temp"] = int(numbers[0]) else: raw["temp"] = None print("[验证层] 温度字段解析失败") return raw这个过程类似给Agent加了“质检员”:外部数据进来先过一次筛子,把异常值、缺失值挡在模型视线之外,从源头减少模型瞎编的机会。
4.4 一个容易被忽略的坑:工具描述写得越清楚,模型越懂怎么用
工具调用正确率不取决于工具本身多强,而取决于工具的“说明书”写得是否清楚。同一个函数,用两种描述,模型的表现会有肉眼可见的差距。
| 描述方式 | 效果 |
|---|---|
| “查询天气” | 模型不知道什么时候该用、参数怎么传、返回值长什么样 |
| “当用户询问某城市当前的天气状况、温度、出门建议时使用;参数city为城市名;返回包含temp/condition/humidity字段” | 模型能准确触发,并且正确解析结果 |
这个道理说白了很简单:模型是通过描述理解工具的,描述里的每一点模糊,都会在决策链路里放大成一次错误调用。
我在实际工程里的习惯是:每个工具描述控制在50到150字之间,包含“何时用”“参数含义”“返回值说明”三个要素。描述的结尾再给一个典型例子,模型一般都能准确跟着走。
5. 从“能查到”到“会决策”:让Agent真正自主的进阶思路
5.1 多工具场景下的目标拆解
让一个Agent具备真正的“决策感”,第一个进阶点是目标拆解。用户抛过来一个复合问题,比如“对比北京和上海未来三天的天气,然后推荐一个适合周末去玩的城市”,模型不能只会调一次工具,它需要:
- 先把任务拆成子步骤:查北京三天天气,查上海三天天气,对比后给建议。
- 每一步都决定调哪个工具、传什么参数。
- 把多次调用的结果汇总成一个综合判断。
这个能力一部分来自模型的推理能力,一部分来自你设计的Agent执行循环。简单说,你可以在代码里维护一个“任务步数”的计数器,允许模型先规划再执行,每一步的工具结果都进入历史记录。多轮工具调用的支撑逻辑,就是我在第三节写的那个最小循环的重复和扩展。
5.2 短时记忆让决策有连续性
Agent有没有“记忆”,直接决定决策质量。没有记忆的Agent,每一轮对话都是陌生人;有记忆的Agent,才能理解“之前查过北京天气,现在你问要不要带伞”是同一个决策链上的问题。
实现方式并不复杂——只需要把历史消息都维护在messages数组里。用户问题、模型回复、工具调用记录、工具返回结果,全部按顺序存着。下一轮发起调用时,把这些历史一股脑传给模型。这样模型就能感知到前面做过什么决策、查到了什么,再结合当前问题做新的判断。
需要小心的是记忆长度。对话时间长了,历史消息会变得很长,既费token又干扰判断。这时候就需要提炼记忆:把前面几轮对话里的关键结论压缩成一句话放在上下文里,替代完整的原始记录。
5.3 反思与重试:给自己一个纠错的机会
这是自主决策能力的重要一环。我们期望的Agent不是一次定生死,而是在拿到工具结果后判断一下“这个结果合理吗”。
我可以给你推荐一个朴素的“反思机制”:模型在拿到工具结果之后,先执行一次小型的自我校验。比如查天气时发现湿度为零、温度零下却在显示雷阵雨,就主动调用一次备用数据源重新查询;如果两次查询结果冲突,就在回答里明确告知用户“两个数据源结果不一致,需谨慎判断”。
直接用提示词约束也能起到部分作用,比如在系统提示里写:如果你认为工具返回结果存在明显异常,请再调用一次其他工具进行交叉验证,或者在回答中注明数据可靠性存疑。加上一个低成本的校验模块效果会更好,具体可以用简单的编程规则。
5.4 工程落地:成本、超时、权限、人工兜底
从Demo走向生产,有几条边界必须一开始就划清楚。
成本控制方面,建议设置每轮调用的token上限和工具调用次数上限,防止Agent失控烧钱。我在Demo里已经用了最简单的“次数计数器”,生产环境可以加得更细——比如每次工具调用前检查预算,超过阈值直接终止。
超时兜底方面,外层一定要套一个整体超时机制。Agent的思考链一旦过长,用户可能已经等得不耐烦了。我会在整体超时后让主流程直接返回“我正在全力以赴查询,请稍后再试”,而不是无限循环。
权限边界是一个不能跳过的话题。一个能自主调工具的Agent,等于给了它“动手的能力”。权限设计上要遵循最小授权:Agent能调用哪些接口、能操作哪些数据,必须有明确白名单。涉及写入、删除、资金操作的工具,一律默认禁止,或者必须经过人工审批流程。
人工兜底则是最后一道防线。Agent再聪明,也会遇到它无法判断的边界情况。实践里我会在系统设计上留“人机协同”接口:当模型发现不确定性超过阈值时,主动输出“该决策超出我的能力范围,建议咨询人工客服”,把决策权交回给用户或运营人员。
我现在的个人习惯是:每次让Agent做决策类任务,都要求它在回复末尾带上“数据来源与查询时间”,比如“根据某天气接口查询,查询时间09:32,北京当前31度,多云转雷阵雨”。这既提高结果可信度,也给后续追溯问题留了线索。这个习惯看起来不起眼,实际排查问题的时候能省很多力。
最后再分享几个实战心得
我自己从“给模型写提示词”过渡到“给模型接工具”,最大的转变是把关注点从“说什么”挪到了“能做什么”。模型再聪明,也猜不到实时数据;但只要给它接上外部工具,它的能力圈一下就扩大了。我的建议也很朴素:先跑通这个小闭环,再研究那套复杂的Agent框架。历史上大部分Agent框架,底层也不过是工具调用加上提示词编排的组合。
另外一个小提醒是,工具描述文案值得你多花一点时间打磨。很多团队把精力全放在模型选型和API对接上,工具描述却草草写几句,导致模型经常触发错误的工具。工具描述写清楚、写具体之后,整个Agent的稳定性提升是立竿见影的。
如果你正在做自己的第一个实时信息Agent,不妨从“查天气给建议”这种低风险场景开始,跑通之后再逐步加入新闻查询、数据库查询、订单状态查询这些更高价值的工具。整个过程中最有意思的地方在于——你每给它接上一个新工具,都像是给这个数字助手多长了一双眼睛。