尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Google Agent白皮书源码拆解:从零跑通任务规划、工具调用与记忆模块

Google Agent白皮书源码拆解:从零跑通任务规划、工具调用与记忆模块 简介这份资源是Google第二部Agent白皮书《Agents Companion》的配套可运行源码包面向希望将代理技术从原型Demo推进到生产部署的开发者与AI工程实践者。白皮书从概念普及转向工程化落地围绕技术架构进阶、生态协同与标准构建、企业级落地路径及未来趋势展开源码则帮助读者把其中的理论与策略直接落到代码层面验证。压缩包共3个文件约9KB以html页面、inscode配置与gitignore为主分别承担内容展示、运行环境描述与版本忽略等用途结构轻量、便于快速上手。目前已有136人学习下载。借助这份资料读者可对照白皮书梳理代理技术的全生命周期操作思路理解企业级AI应用的技术路线图与实施框架并基于可运行源码进行学习、测试与二次开发适合作为进阶研读与工程实践的参考起点。1. 从一份白皮书到能跑起来的 Agent为什么我盯着这份源码包看了三个晚上前阵子有个做后端的朋友找我说他们团队想试水 AI Agent但卡在一个很尴尬的位置概念听了一堆真到写代码的时候连一个能跑通的最小闭环都搭不出来。他问我有没有那种“不是纯讲道理、而是能直接跑”的东西。我把他拉到一个开源白皮书项目前——就是这份 Google Agent 白皮书配套的可运行源码包。它把 Agent 的架构拆成可执行的模块从任务规划到工具调用再到记忆管理每一块都有对应的代码实现不是伪代码不是架构图是能git clone下来直接跑的那种。这份资源适合两类人一类是刚接触 Agent 概念、想通过跑通一个完整例子来建立直觉的开发者另一类是在做 AI 应用落地、需要参考工程化实现细节的从业者。它不教你调参也不教你训模型它解决的是“Agent 到底怎么组织代码”这个问题。我花了三个晚上把源码包里的模块逐个拆开跑了一遍下面把关键路径和踩过的坑整理出来。2. 拆开源码包Agent 的四个核心模块与依赖关系2.1 任务规划模块从自然语言到可执行步骤Agent 和普通 LLM 调用最大的区别在于它能把一个模糊的用户请求拆成有序的子任务。这份源码包里规划模块的核心逻辑集中在planner.py这个文件里。它做的事情不复杂接收用户输入调用一次 LLM 做任务分解然后把结果解析成结构化的步骤列表。我先把最小可运行单元跑起来。源码包根目录下有一个examples/文件夹里面放了几个场景的入口脚本。以最基础的任务规划为例# examples/run_planner.py from agent.planner import TaskPlanner from agent.llm_client import LLMClient # 初始化 LLM 客户端这里用的是兼容 OpenAI 接口的配置 client LLMClient( base_urlhttp://localhost:8000/v1, # 本地推理服务地址 api_keynot-needed, # 本地服务通常不校验 modelqwen2.5-7b-instruct # 模型名称按实际部署改 ) planner TaskPlanner(llm_clientclient, max_steps8) # 输入一个需要多步完成的任务 result planner.plan(帮我查一下北京明天天气如果下雨就提醒我带伞否则提醒我涂防晒) for step in result.steps: print(f[{step.order}] {step.action} - {step.tool_hint})这段代码跑通之后输出是一个有序的步骤列表每个步骤带一个tool_hint字段告诉下游模块这一步大概需要什么类型的工具。max_steps这个参数控制规划的最大步数设太小会导致复杂任务被截断设太大又容易让 LLM 产生冗余步骤。我试下来8 到 12 之间比较稳具体看任务复杂度。规划模块的 prompt 模板放在agent/prompts/planner_prompt.txt里可以直接改。我建议第一次跑的时候先别动模板等跑通了再根据自己场景微调。模板里有一个{tool_list}占位符会被替换成当前注册的工具描述这一步很关键——如果工具描述写得含糊规划出来的步骤就会乱指工具。2.2 工具调用模块注册、路由与执行工具调用是 Agent 真正“动手”的部分。源码包里用了一个注册表模式所有工具通过装饰器注册到一个全局 registry 里然后由ToolExecutor根据规划结果路由到具体工具。先看工具怎么注册# agent/tools/weather.py from agent.tools.registry import register_tool register_tool( nameget_weather, description查询指定城市指定日期的天气情况, parameters{ city: {type: string, description: 城市名称}, date: {type: string, description: 日期格式 YYYY-MM-DD} } ) def get_weather(city: str, date: str) - dict: # 实际项目中这里调外部 API示例里返回模拟数据 return { city: city, date: date, condition: rain, temperature: 18-24C }注册的时候有三个东西必须写清楚name是工具的唯一标识description会进 prompt 影响规划质量parameters定义了参数 schema。我踩过一个坑description写得太短比如只写“查天气”规划模块就经常把“查天气”和“查空气质量”搞混。后来改成“查询指定城市指定日期的天气情况包括天气状况和温度范围”准确率明显上来了。工具执行器的工作流程是这样的接收规划模块输出的步骤从步骤里提取tool_hint在 registry 里找到匹配的工具然后用 LLM 从步骤的自然语言描述里抽取参数最后调用工具函数。参数抽取这一步用的是 function calling 的格式如果本地模型不支持 function calling源码包里也提供了一个基于正则的 fallback 解析器在agent/tools/parser.py里。2.3 记忆模块短期上下文与长期存储的边界记忆模块是我觉得这份源码包里设计得最值得看的部分。它把记忆分成两层短期记忆就是一个滑动窗口的对话历史长期记忆用了一个简单的向量存储。短期记忆的实现很直接在agent/memory/short_term.py里核心就是一个固定长度的 dequefrom collections import deque class ShortTermMemory: def __init__(self, max_turns10): self.buffer deque(maxlenmax_turns) def add(self, role: str, content: str): self.buffer.append({role: role, content: content}) def get_context(self) - list: return list(self.buffer)max_turns控制保留多少轮对话。设太大prompt 会膨胀推理变慢设太小Agent 会“忘事”。我一般设 10 到 15 轮超过这个范围的早期对话会被挤掉。如果你需要 Agent 记住更早的信息就得靠长期记忆来补。长期记忆在agent/memory/long_term.py用了一个轻量的向量检索方案。每次对话结束后把关键信息做 embedding 存进去下一轮对话开始时用当前输入去检索最相关的几条历史记录拼到 prompt 里。这里有一个参数叫top_k控制检索返回几条。我试下来3 到 5 条比较合适太多会引入噪声太少又可能漏掉关键信息。注意长期记忆的 embedding 模型和 LLM 是分开配置的。源码包默认用了一个本地的小模型做 embedding如果你换了 embedding 模型记得把向量维度同步改掉否则检索会报维度不匹配。2.4 执行循环Agent 的主控流程把上面三个模块串起来的就是agent/executor.py里的主循环。逻辑不复杂规划 → 执行 → 观察结果 → 判断是否完成 → 没完成就带着新上下文重新规划。# agent/executor.py 核心循环简化版 def run(self, user_input: str, max_iterations: int 5): self.memory.short_term.add(user, user_input) for i in range(max_iterations): context self.memory.get_full_context() plan self.planner.plan(context) if plan.is_complete: return plan.final_answer for step in plan.steps: tool self.registry.get(step.tool_hint) if not tool: self.memory.short_term.add(system, f工具 {step.tool_hint} 未注册) continue result tool.execute(step.parameters) self.memory.short_term.add(tool, str(result)) return 达到最大迭代次数任务未完成max_iterations是防止死循环的保险丝。我见过有人设成 20结果 Agent 在一个查不到数据的工具上反复重试烧了一堆 token。一般设 5 到 8 就够了超过这个次数还没完成大概率是规划出了问题或者工具描述有歧义应该回去改 prompt 而不是加大循环次数。3. 把源码跑起来环境配置与最小闭环验证3.1 依赖安装与模型服务对接源码包的依赖清单在requirements.txt里核心依赖就几个openai用于 LLM 调用numpy用于向量运算pydantic用于参数校验。安装命令很标准# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装依赖 pip install -r requirements.txt # 复制配置文件模板 cp config.example.yaml config.yamlconfig.yaml里有三个关键配置段llm段配模型服务地址和模型名embedding段配 embedding 服务memory段配记忆模块的参数。如果你本地没有推理服务源码包里提供了一个mock_llm.py可以用固定回复模拟 LLM 行为先把流程跑通再换真实模型。我建议第一次跑的时候用 mock 模式确认代码路径没问题# 用 mock 模式跑一个完整示例 python examples/run_full_agent.py --mock --task 查一下明天天气并给出出行建议跑通之后你会看到控制台打印出规划步骤、工具调用记录和最终回答。这个过程大概需要 30 秒如果卡住了大概率是某个工具的注册名和规划输出的tool_hint对不上检查一下agent/tools/下所有工具的name字段。3.2 接入真实模型后的参数调优mock 模式跑通之后把config.yaml里的llm.base_url改成你实际的推理服务地址模型名改成你部署的模型。这里有几个参数需要根据模型能力调参数作用建议值调整方向temperature规划多样性0.3调高步骤更灵活但可能跑偏max_tokens单次生成上限1024规划步骤多时需调大top_p采样范围0.9一般不动max_steps规划最大步数8复杂任务调到 12max_iterations执行循环上限5调试时可临时调到 8我自己的习惯是先把temperature设到 0.1让规划尽量确定等整个流程稳定了再慢慢往上调。有些模型在低 temperature 下会陷入重复输出这时候加到 0.3 到 0.5 之间通常能缓解。3.3 验证 Agent 是否真的在“用工具”一个常见的误判是Agent 输出了看起来合理的回答但实际上根本没调工具全是 LLM 自己编的。验证方法很简单在工具函数里加一行日志import logging logger logging.getLogger(__name__) register_tool(nameget_weather, ...) def get_weather(city: str, date: str) - dict: logger.info(fTOOL_CALLED: get_weather | city{city} | date{date}) # ... 实际逻辑然后跑一个需要调工具的任务看日志里有没有TOOL_CALLED。如果没有说明规划模块没有正确识别出需要调工具回去检查工具描述和 prompt 模板。如果有但结果不对那就是参数抽取出了问题看parser.py里的解析逻辑。4. 避坑记录跑这份源码时我踩过的五个坑4.1 工具描述含糊导致规划乱指工具现象Agent 把“查天气”的任务规划成了调用“查股票”的工具或者规划出一个根本不存在的工具名。原因工具注册时的description写得太短或太模糊规划模块的 prompt 里工具列表信息量不足LLM 只能靠猜。解决每个工具的description至少写清楚三件事——做什么、输入是什么、输出是什么。比如“查询指定城市指定日期的天气情况输入城市名和日期返回天气状况和温度范围”。改完之后重新跑规划准确率会明显提升。4.2 长期记忆检索返回不相关历史现象Agent 在回答新问题时引用了几轮之前完全不相关的对话内容导致回答跑偏。原因embedding 模型对短文本的区分度不够或者top_k设得太大把弱相关的记录也捞进来了。解决先把top_k从默认的 5 降到 3看效果。如果还不行检查 embedding 模型是否适合中文场景。源码包默认的 embedding 模型对中文支持一般换成中文优化过的模型会好很多。另外可以在检索后加一个相似度阈值过滤低于阈值的直接丢掉。4.3 执行循环陷入死循环烧 token现象Agent 反复调用同一个工具每次返回相同结果但就是不结束。原因max_iterations设得太大或者规划模块没有正确判断任务已完成。有时候是因为工具返回的结果格式和规划模块期望的不一致导致规划模块认为任务还没完成。解决先把max_iterations降到 3 做调试观察每次循环的规划输出。如果发现规划模块反复生成相同的步骤检查工具返回结果的格式是否和 prompt 里描述的一致。另外可以在执行循环里加一个“相同工具连续调用超过 2 次就强制退出”的保护逻辑。4.4 本地模型不支持 function calling 导致参数抽取失败现象工具被正确路由了但参数抽取出来是空的或者格式错误。原因源码包默认用 function calling 格式做参数抽取但很多本地部署的模型不支持这个特性。解决在config.yaml里把llm.function_calling设为false源码包会自动切换到基于正则的 fallback 解析器。这个解析器对格式要求比较严格规划模块输出的步骤描述需要遵循“动作 参数名参数值”的格式。如果还是解析失败可以在parser.py里加自定义的解析规则。4.5 记忆窗口溢出导致早期关键信息丢失现象多轮对话后Agent 忘记了最初用户说的关键约束条件。原因短期记忆的max_turns设得太小早期对话被挤出窗口同时长期记忆没有及时存入关键信息。解决把max_turns调到 15 到 20同时在每轮对话结束后手动把关键约束写入长期记忆。源码包里提供了一个memory.mark_important()方法可以把指定内容强制存入长期存储不受窗口限制。我一般会在用户输入里检测“必须”“不要”“一定要”这类关键词命中就标记为重要信息。5. 进阶用法把 Agent 接到真实业务流里的两个技巧5.1 用工具链组合替代单步规划源码包默认的规划模式是“一次性规划所有步骤”但实际业务里很多任务的后续步骤依赖前一步的具体返回值没法提前规划。比如“查库存如果低于阈值就下单补货”下单这个动作是否执行取决于查库存的结果。我的做法是把这种条件逻辑封装成一个组合工具在工具内部做判断而不是让规划模块去处理条件分支register_tool( namecheck_and_replenish, description查询库存低于阈值时自动触发补货流程, parameters{ sku: {type: string, description: 商品编码}, threshold: {type: integer, description: 库存阈值} } ) def check_and_replenish(sku: str, threshold: int) - dict: stock query_stock(sku) if stock threshold: order_id create_replenishment_order(sku, threshold * 2) return {action: replenished, order_id: order_id, current_stock: stock} return {action: no_action, current_stock: stock}这样规划模块只需要规划一步“调用 check_and_replenish”条件判断在工具内部完成。好处是规划逻辑简单、不容易出错代价是灵活性降低如果业务规则变了得改工具代码而不是改 prompt。我一般把稳定的业务规则封装成组合工具把多变的策略留给规划模块。5.2 用执行日志做离线评估Agent 跑起来之后怎么知道它到底靠不靠谱我的习惯是每次执行都落一份结构化日志记录规划步骤、工具调用、参数、返回结果和最终回答。然后定期抽样人工评估看规划是否合理、工具调用是否正确、最终回答是否满足用户意图。源码包里有一个agent/logger.py默认把日志写到logs/agent_run.jsonl。我在此基础上加了一个评估脚本统计几个指标工具调用准确率规划的工具和实际需要的工具是否一致、参数抽取准确率、任务完成率。这三个指标能覆盖大部分问题。如果工具调用准确率低于 80%优先改工具描述如果参数抽取准确率低优先改 parser 或换模型如果任务完成率低但前两个指标正常那就是规划策略的问题需要调 prompt 或调整max_steps。从那以后我每次接入新的 Agent 项目都会先把日志和评估脚本搭好再跑业务逻辑不然出了问题连从哪里查都不知道。希望这份拆解能帮到你少走几个我踩过的弯路。本文还有配套的精品资源点击获取
返回列表