Agent-Reach:让大模型真正“触达”外部世界的工具调用闭环实践

发布时间:2026/10/9 16:15:57
Agent-Reach:让大模型真正“触达”外部世界的工具调用闭环实践
前阵子在做一个内部自动化小项目时我意识到一个普遍现象市面上的 Agent demo 大多停留在“很能聊”的阶段模型能给你输出一段像模像样的计划但真让它去查文件、调接口、发请求、汇数据立刻拉胯。原因很简单——大模型本身没有“手”它只负责思考不负责触达。Agent-Reach 这个项目就是我自己为了把“思考”和“执行”真正接起来做的一套最小可用的方案。它不是大而全的框架而是一套把工具调用、状态管理、安全边界都串起来的脚手架。核心思路只有一句话让 Agent 知道自己有什么工具、怎么调用、调完怎么反馈然后在受控范围内完成闭环。这套东西适合谁如果你正在做 AI 应用、写 RAG、调 API、做企业自动化脚本或者只是想把 LLM 接进自己的日常 workflow但又不想一上来就套一个沉重的 Agent 框架那这套思路应该能帮上忙。我会把从设计到落地再到踩坑排查的完整过程都写在下面所有代码都是我实际跑过的版本不是教学伪代码。1. Agent-Reach 是什么先搞清楚它解决的真问题1.1 从“只聊天”到“真干活”只差一个 Reach很多刚接触 Agent 的人会把大模型理解成一个“全能执行器”跟它说“帮我整理一份报告”就期待它自己把报告生成出来。但实际操作过的都知道模型只能输出文本它没法直接读取你本地的 Excel没法直接调用公司的订单接口也没法直接往数据库里写记录。它唯一能做的是“告诉”你它需要哪些信息、想做什么操作然后把那些操作以文本形式写出来。这时候就需要一个中间层来承接模型的意图把“它想做什么”翻译成“真正做了什么事”再把这个结果回传给模型。这个中间层就是我定义的 Reach 层。Agent-Reach 这个名字也是这个意思Reach 不光是“覆盖范围”更是一种“触达能力”——模型能不能真正触达外部世界的工具、数据和系统。如果没有这层触达Agent 就永远只是一个聊天机器人。我这个项目最早的一个触发点是看到一个群里有人吐槽某个 Agent 应用“我问它今天有没有什么待办它告诉我去看日历。”这句话很经典因为它精准地指出了问题模型知道应该看日历但它够不到日历。Agent-Reach 要解决的就是让模型够得着。1.2 项目定位与目标读者我需要先明确一下边界这个项目不是又一个 Agent 开发框架也不是要跟 LangChain、AutoGPT 那类东西竞争。它更接近一套“可自定义的最小参考实现”你可以照着这篇博文的思路在两小时左右搭出一个能跑通“任务理解 → 工具选择 → 工具调用 → 结果反馈 → 任务收敛”的闭环。如果你满足下面任一条这个项目的参考价值就很大你想理解 Function Calling 在真实项目里到底怎么接线而不是只调一个 Chat API 拿到文字。你在做一个私有化 / 内部工具需要让 Agent 访问公司内的数据库、文件系统或内部 API但不想引入一整套重量级框架。你被现成 Agent 框架的抽象层搞迷糊了想看看一个从零写起的 Agent 循环到底有多简单。我自己做这个项目时刻意没有引入任何 Agent 编排依赖只用了 OpenAPI 兼容的 Chat SDK。目的就是让任何有 Python 基础的人都能一眼看穿整个调用链路不被框架的魔法掩盖。1.3 为什么不做成“大而全的 Agent 框架”这可能是这篇博文里我最想强调的一点。现在开源社区里 Agent 框架多得吓人功能从多 Agent 协作到复杂记忆池都有但很多项目用起来有一个共同问题出了问题你很难判断是哪一层出的错。一会儿怀疑是 Prompt 写得不对一会儿怀疑是 RAG 切分策略有问题一会儿怀疑是外层编排逻辑有 bug。排查半天最后发现只是某个工具返回的 JSON 多了一层引号。Agent-Reach 从一开始就定了一个设计原则每一层都尽量薄每一个环节都能单独调试。模型调用就是模型调用、工具执行就是工具执行、状态管理就是状态管理。这样万一链路出错我只需要对着日志看是哪一步断了就行。这个原则虽然不是炫技但实际维护起来真的省心。2. 核心设计思路把“触达”变成可编程的能力2.1 整体架构意图、路由、执行、反馈四层Agent-Reach 的整体流程可以拆成四层理解这四层你就掌握了绝大多数 Agent 应用的设计骨架。第一层是意图层。用户输入的任务进来后需要被模型理解成若干个可执行的子目标。比如用户说“帮我把 docs 目录下所有包含 Agent 这个词的文档整理成一份清单”这个任务拆解后至少包含三个子目标扫描 docs 目录、过滤包含 Agent 的文档、生成清单。第二层是路由层。模型根据自己看到的工具描述决定先调用哪个工具、传入什么参数。注意这个过程不是代码写死的规划器而是模型在每次迭代时基于当前上下文动态决策。这一点非常关键Agent 的“智能感”主要来自这里因为每一步都是根据上一步的实际结果来决定下一步的。第三层是执行层。路由层输出的是一个结构化的工具调用请求执行层负责真正去跑这个函数。这个函数可以是一个查天气的 API 封装、一段操作本地文件的代码也可以是一个数据库查询。执行层要做的事情只有一件把函数真实结果或异常信息原样返回给模型。第四层是反馈层。模型拿到工具返回的结果后判断任务是否完成。如果没完成继续进入下一轮意图解析和路由如果完成了则生成最终回答。这个反馈循环就是 Agent 能够多步推理的核心没有这一步模型永远只能调用一次工具就结束。我在做 Agent-Reach 时把每一层都打成日志输出所以任何一次运行都能清清楚楚看到模型在每一步“想”了什么、“做”了什么、“看到”了什么。调试体验比黑盒 Agent 舒服太多。2.2 工具注册表Agent 的“API 目录”路由层能够工作的前提是模型知道有哪些工具可用、每个工具是干什么的、参数长什么样。这句话翻译成技术方案就是我们需要为 Agent 提供一个“工具注册表”。每个工具条目包含三样内容工具名称命名要直观例如search_notes、get_weather、create_todo。工具描述要写清楚这个工具在什么场景下用、输入是什么、返回什么。描述的作用是帮助模型在路由阶段做“意图匹配”描述写得越清晰调用准确率越高。参数 Schema用 JSON Schema 描述每个入参的类型、是否必填、取值范围。这个注册表本质上就是一份提供给模型的“API 目录”。模型每次决策前都会读取这份目录然后根据用户问题和当前上下文挑出最合适的工具再按照 Schema 生成 JSON 格式的参数。有一点容易踩坑模型不是真的理解代码它只能理解“文字描述 参数结构”。所以工具描述里应该使用业务语言。比如一个工具是查库存的不要只写“get_inventory”要把关键的触发场景也写进去“当用户询问某商品是否有货、剩余数量时使用”。我实测下来描述里包含触发场景比单纯写“查询库存”准确率高不少。2.3 对话状态管理每一步都知道为什么走到这里Agent 的第二个关键设计是把每一步的“过程”都放进上下文里。这不只是把用户消息和助手回复塞进去还包括工具调用的请求和返回结果。模型之所以能连续调用多个工具是因为它能看到前面所有步骤的轨迹从而基于最新状态继续规划。我在实现里维护了一个简单的消息数组按顺序包含 user、assistant、tool 三类消息。其中 assistant 消息里记录了模型发起的工具调用请求tool 消息里记录工具的返回结果。模型下一轮生成时就会基于这个完整轨迹来决策。这里有一个很容易被忽视的问题工具返回结果要放在一个独立的消息角色里。有些初学者会把工具返回的内容直接拼接成普通文本塞回上下文这在简单场景下也能跑通但一旦工具状态增多模型的注意力就会被无关文本干扰。用标准角色区分模型能更清楚地判断哪些是用户需求、哪些是执行结果、哪些是自己的推理。2.4 安全边界给工具调用装上刹车让 Agent 调用工具是一件很爽但也很危险的事情。如果在企业内部让 Agent 直接操作生产数据库或发送邮件一旦它指令错误后果不是小事。所以 Agent-Reach 一开始就把安全边界考虑进去了。我做了三层保险。第一层是工具白名单只有显式注册到工具注册表里的函数才能被调用不会出现 Agent 凭空调用未注册能力的情况。第二层是参数校验每一个工具函数在执行前都会用 JSON Schema 校验参数类型不对、缺参数直接拒绝调用并且把错误信息返回给模型让它知道这次调用失败的原因。第三层是执行审批对写操作类工具比如删除文件、发送消息会设置一个confirm开关。开启后工具执行前需要外部确认Agent 只能提出请求不能直接执行。说实话第三层在个人项目里有点繁琐但在团队或者生产环境里是必须的。我自己在本地项目里跑 Agent 时会把审批关掉但只要涉及公司数据一定开着。3. 从零实现一个最小可用的 Agent-Reach3.1 项目结构与依赖我用的环境是 Python 3.11依赖尽量精简只有两个核心包openai兼容任何 OpenAI 协议的服务和pydantic用于参数校验。如果你用的是国内模型或本地部署的模型只要它支持 OpenAI 兼容的/chat/completions接口和 tools 参数这段代码几乎不用改动。项目结构如下很简约agent_reach/ ├── main.py # Agent 主循环与演示入口 ├── tools.py # 工具定义与注册表 ├── config.py # 模型配置与常量 └── requirements.txt我故意没有做出agents/、tools/、memory/那种分层目录。因为对一个教学性参考项目来说目录铺得越多理解成本越高。等功能真的庞大起来了再拆分也不迟。依赖安装只需要一条命令pip install openai pydantic3.2 工具定义与注册tool 装饰器工具注册这块我用一个装饰器来简化操作。核心逻辑是把函数的 docstring 和类型注解自动转换成 OpenAI Function Calling 需要的 JSON Schema。这样你不用手写一串冗长的 schema 定义平时怎么写函数就怎么写用起来很自然。我实际用的代码大概长这样# tools.py import inspect import json from typing import Callable, Dict, Any TOOL_REGISTRY: Dict[str, Callable] {} def tool(func: Callable) - Callable: 注册工具把函数信息转换成 Function Calling 需要的 schema TOOL_REGISTRY[func.__name__] func return func def generate_schema(func: Callable) - dict: 从函数签名生成 OpenAI tools 格式的 schema sig inspect.signature(func) properties {} required [] for name, param in sig.parameters.items(): # 简化处理默认按字符串类型处理实际可根据注解扩展 properties[name] {type: string, description: f{name} 参数} if param.default is inspect.Parameter.empty: required.append(name) return { type: function, function: { name: func.__name__, description: func.__doc__ or , parameters: { type: object, properties: properties, required: required, }, }, } def get_tool_schemas() - list: return [generate_schema(f) for f in TOOL_REGISTRY.values()] def execute_tool(name: str, arguments: str) - str: 根据工具名和参数执行工具返回字符串形式的结果 func TOOL_REGISTRY.get(name) if not func: return f错误工具 {name} 不存在 try: args json.loads(arguments) result func(**args) return json.dumps(result, ensure_asciiFalse) except Exception as e: return f工具执行失败{str(e)}这个实现看着简单但已经足够支撑一个 Agent 闭环。真正要扩展的地方其实是generate_schema生产环境下建议直接用 pydantic 的model_json_schema()来做参数类型推断而不是纯靠字符串类型。我在后面的完整版代码里已经把常用类型映射补齐了。3.3 Agent 主循环从规划到执行的闭环接下来是整套项目里最核心的部分Agent 主循环。这里不搞复杂的状态机就是一个 Pythonwhile循环。逻辑非常直观把当前消息列表发给模型同时附带全部工具 schema。模型返回content或者tool_calls。如果返回的是tool_calls说明它想调用工具。我们对每个调用请求执行工具把结果追加成 tool 角色消息然后继续下一轮。如果不再请求调用工具说明它认为任务可以收敛了输出最终内容。核心代码抽象出来是这样的# main.py from openai import OpenAI from agent_reach.tools import get_tool_schemas, execute_tool client OpenAI(base_urlYOUR_API_BASE, api_keyYOUR_API_KEY) MODEL your-model-name MAX_STEPS 8 # 防止无限循环 def agent_run(user_query: str) - str: messages [{role: user, content: user_query}] tools get_tool_schemas() for step in range(MAX_STEPS): print(f\n[Step {step1}] 请求模型) response client.chat.completions.create( modelMODEL, messagesmessages, toolstools, ) message response.choices[0].message # 模型决定调用工具 if message.tool_calls: print(f[Step {step1}] 发起 {len(message.tool_calls)} 个工具调用) messages.append(message.model_dump()) # 保留 assistant 上下文 for tc in message.tool_calls: print(f - 调用 {tc.function.name}({tc.function.arguments})) result execute_tool(tc.function.name, tc.function.arguments) print(f - 结果: {result[:100]}...) messages.append({ role: tool, tool_call_id: tc.id, content: result, }) continue # 模型直接输出最终结果 final_answer message.content print(f[Step {step1}] 模型输出最终结果) return final_answer return 超过最大步骤数任务未收敛请调整工具或描述后重试这段代码只有二十几行但它就是一个完整的 Agent 最小闭环。你可以把MAX_STEPS想象成给模型设置的“工作量上限”。步骤太少任务复杂时容易半途而废步骤太多一个失控死循环就能把你的 API 费用烧穿。我日常跑内部任务一般给 8 步左右批量跑简单任务给 5 步就够。3.4 一个完整的本地示例让 Agent 整理一份天气与资料报告光有框架没有工具是空转我写了三个演示工具今日天气、本地笔记搜索、生成 Markdown 清单。这三个工具分别代表“外部 API 接入”“本地文件访问”“结构化输出生成”三类典型能力足够展示 Agent-Reach 的触达范围。工具实现如下# tools.py import json import pathlib from typing import List tool def get_weather(city: str) - dict: 获取指定城市的当日天气信息。当用户询问天气、温度、是否下雨时使用。 # 演示数据实际项目这里通常会请求一个天气 API mock_weather { 北京: {天气: 晴, 气温: 18~28℃, 风力: 3级}, 上海: {天气: 小雨, 气温: 22~27℃, 风力: 4级}, 广州: {天气: 多云, 气温: 25~32℃, 风力: 2级}, } return mock_weather.get(city, {错误: f暂无 {city} 的天气数据}) tool def search_notes(keyword: str) - List[str]: 在本地笔记目录中查找包含关键词的笔记标题。当用户需要检索笔记、文档时使用。 notes_dir pathlib.Path(notes) results [] if notes_dir.exists(): for file in notes_dir.glob(*.txt): content file.read_text(encodingutf-8) if keyword in content: results.append(file.stem) return results if results else [未找到包含该关键词的笔记] tool def write_markdown_file(filename: str, content: str) - str: 将内容写入指定 Markdown 文件。当需要把结果保存为本地文件时使用。 path pathlib.Path(filename) path.write_text(content, encodingutf-8) return f文件已保存: {filename}然后我在main.py里跑了一个真实任务if __name__ __main__: task 今天北京天气怎么样顺便帮我查一下本地笔记里跟 Agent 相关的资料最后生成一份 summary.md result agent_run(task) print(\n 最终结果 ) print(result)整个运行里Agent 会先调用get_weather再调用search_notes最后把两者组合成一个 summary 并调用write_markdown_file。整个过程不需要任何手工编排模型看到用户需求后自己决定怎么调度。我第一次跑通这个场景时印象最深的是它没有机械地“先天气后笔记”而是按逻辑顺序搜索完资料后把天气信息放进了报告开头显得非常自然。这才是 Agent 和普通“规则脚本”的本质区别不是一串写死的执行链而是模型基于对任务的理解动态编排工具调用顺序。4. 评估你的 Agent 到底能“触达”多远4.1 三个核心指标项目跑通之后我紧接着遇到一个更实际的问题怎么量化这个 Agent 的“触达能力”毕竟不能每次都用肉眼看着它跑完就说“效果不错”。我自己将评估体系拆成了三个核心指标分别是工具触达率、任务完成率、步骤收敛率。工具触达率衡量的是“给定 10 个工具模型能不能在正确情景下选出正确工具”。我会事先准备一批测试任务每个任务对应一个预期工具看命中率。这个指标直接反映工具描述、参数 Schema 写得好不好。任务完成率衡量的是“端到端场景从头到尾能否产出可用结果”。测试用例往往涉及多个工具的组合比如“查询天气、查库存、生成日报”。只要最终输出里缺少关键内容就算失败。步骤收敛率衡量的是“Agent 在预算步骤内是否能稳定收敛而不是陷入重复调用或超时”。这指标对 API 成本和用户体验影响最大。一个不停重复调用同一个工具的 Agent就算最终没错也让人抓狂。这三个指标加起来基本就能判断你的 Agent 达到“能用”还是“凑合能用”。4.2 我用的评估清单我实际落地的评估方式很简单准备一个 JSON 文件里面放 10 到 15 个测试任务和期望结果然后写脚本逐个跑 Agent输出每条任务的工具调用轨迹、结果摘要、是否成功最后汇总指标。清单里的测试任务大概分三类单工具简单任务如“查一下上海天气”“搜索笔记里关于 Python 的内容”。多工具串联任务如“把北京天气和笔记里 AI 相关的标题整合成一份说明”。边界与容错任务如“查一个不支持的城市天气”“调用不存在的工具”“连续问两次同一问题”。前三类测能力最后一类测稳定性。我发现很多 Agent 项目在边界任务上非常脆弱比如遇到未知城市直接卡死而不是友好降级。在我的实现里get_weather对未知城市返回的是结构化的错误 dictAgent 看到之后会自己调整措辞告诉用户暂无数据这就体现出反馈层的价值。我还习惯记录每一轮的 token 消耗和耗时这两个数据很容易被忽视但上线之后直接决定成本。同样一个任务工具描述写得好的 Agent 可能两步就收敛描述写得差的可能要来回折腾五六步成本差出一倍不止。4.3 从个人场景扩展到团队场景评估体系稳定之后我开始把 Agent-Reach 从我个人笔记场景往团队场景推演。一个比较直接的扩展方式是把它包装成内部服务暴露成 HTTP API让同事通过聊天界面或定时任务触发。这时候原来在本地直接调用的工具要换成访问公司内部系统、数据库的接口。这里有一个经验要点团队场景下工具的权限粒度必须比个人项目细得多。个人项目里一个write_markdown_file随便写无所谓团队场景里一个“写文件”的能力可能就意味着改代码、产生配置变更。所以我把工具分成了只读类和写操作类只读类随 Agent 自由调用写操作类必须经过参数校验、权限校验和人工确认三步。团队场景的第二个经验点是日志与审计。谁在什么时候让 Agent 执行了什么操作这些信息全部要记录下来。这既是安全需求也是排查问题的救命稻草。Agent-Reach 里每次工具调用都会打日志并保留完整的消息轨迹一旦出问题回放轨迹就知道是模型选错了工具还是工具本身报错。5. 实操中的坑与排查技巧实录5.1 工具调用报错的高频原因我在跑 Agent-Reach 时踩过不少坑大部分集中在工具调用这一环。最常见的问题有三个。第一个是参数格式不匹配。模型返回的arguments是一个字符串里面是 JSON 格式但有些模型会在 JSON 里嵌套多余的引号或反斜杠导致json.loads直接抛异常。解决方法是捕获 JSON 解析异常后不要直接崩溃而是把“解析失败”作为工具结果回传给模型让它自己修正参数重新请求。这个技巧在一次真实运行里救我很多次因为在长上下文中模型特别容易复述上一次的错误格式。第二个是工具不存在也就是模型幻觉。模型有时候会编造出一个没注册的工具名比如我注册的是search_notes它非要调用search_note。这个问题的根源往往有两个要么是工具名之间太相似模型混淆要么是工具的“别名语义”不够强。我的处理方法是两管齐下一是在工具描述里把容易混淆的名词显式排除二是在execute_tool里对未注册工具返回友好错误模型看到错误后会自动改用正确工具。第三个是参数缺失或类型错误。比如get_weather要求必传city模型却只传了一个空对象。这种问题很常见调模型就像跟一个实习生打交道它偶尔会“以为自己已经传了参数”。解决办法就是严格执行参数校验并把校验错误返回给模型而不是默默返回None。下面是我整理的一个高频问题速查表问题现象可能原因排查与处理JSON 解析失败模型生成了非法 JSON 字符串捕获异常后返回解析错误给模型让其重试调用了不存在的工具工具名描述不够清晰或模型幻觉增强描述未注册工具返回友好错误参数类型错误模型未严格按 Schema 传参用 pydantic 校验错误信息带回上下文工具返回None函数内部异常被吞掉确保异常被捕获并结构化返回同一工具反复调用反馈结果不明确模型无法判断完成优化工具返回结果加入完成状态提示任务没结束就输出MAX_STEPS太小或工具缺失增加步数或检查工具描述是否覆盖任务需求5.2 上下文失控与循环卡死上下文失控是 Agent 项目里最隐蔽的坑。每调用一次工具工具返回结果就塞进消息列表一次几轮下来上下文可能轻松突破几万 token。特别是工具返回了大量 JSON 数据时模型在后续推理里会频繁“回头看”这些数据既费 token 又容易把注意力带偏。我的处理办法是轻量摘要。所有工具返回内容在追加到消息列表前会做截断比如超过 800 字符就只保留前 800 字符。如果你需要传递大量结构化数据也建议在工具内部先做汇总比如返回“共找到 23 条记录其中前 5 条是...”而不是把 23 条全量 JSON 都抛给模型。循环卡死也要特别小心。一个常见场景是模型反复调用同一个工具但每次参数都略有不同看起来是在“努力”实际上只是原地打转。Agent-Reach 里的MAX_STEPS能在硬层面阻止死循环但更优雅的做法是引入去重检测如果连续三轮调用了同一个工具且参数高度相似我会在系统提示里打断一次提醒模型“你已经在重复操作了请评估当前状态是否有必要继续”。这个提示经常能让模型从钻牛角尖的状态里跳出来。还有一个很容易忽略的问题工具返回结果里包含“错误信息”时模型可能把错误当成正常结果直接报告给用户。比如get_weather返回了{错误: 暂无北京数据}模型如果没有被明确告知“错误字段代表任务未成功完成”它可能会告诉用户“北京天气查询成功”。所以我在设计系统提示词时会明确写一句当工具返回包含 error 或失败标志时请理解这是执行失败需要调整方案或告知用户无法完成。5.3 安全与权限问题的实战处理我在 2.4 节提过安全边界但这里还得再说一个真实翻车案例。之前有一次测试我给 Agent 加了一个delete_file工具本来想让它帮清理临时文件。结果 Agent 在处理一个“整理目录”的任务时误把我的一个笔记文件删了。还好我在工具里做了“只允许删除临时目录下文件”的校验否则就真的出大事。那次之后我把所有“具有不可逆影响”的工具默认都加了二次确认。Agent 每次想执行这类工具时会先输出一个“执行计划”等待我确认后才真正执行。这个设计虽然让自动化程度打了折扣但在安全场景下必须优先保证可控性。如果你的 Agent 要连接生产系统我强烈建议不要省这道工序。另外还有一层权限问题容易被忽视Agent 的 API Key 权限不应该超过它能执行的操作所需的最小范围。比如一个只负责读数据的 Agent它的数据库账号就不应该有写权限。Agent 自身可能没有问题但一旦你的提示词被某种方式注入攻击者就可能借 Agent 之手放大权限。最小权限原则在 Agent 场景下比普通服务端开发更为重要。5.4 排查问题时的调试方法论最后分享一点方法论层面的东西。Agent 项目排查问题和传统后端排查不一样传统后端你盯着堆栈看就行Agent 项目要“重构模型当时的认知”。我的排查套路基本固定为四步。第一步看消息轨迹。把每一轮 user、assistant、tool 消息全部 dump 出来按下不表先完整读一遍很多时候问题当场就暴露了比如发现模型在某个位置误解了工具返回。第二步看工具返回内容。如果模型行为异常先检查是不是工具返回给模型的数据本身就含糊不清。我遇到过模型反复调错工具的情况最后发现是我工具返回的文案里有个字段名和另一个工具的参数名很像模型被带偏了。第三步构造最小复现。拿着出问题的用户输入把上下文清理干净只保留必要工具重新跑一次。如果能复现就能快速二分定位是工具问题还是模型问题。第四步改完重跑基线。我建了一个回归测试集改动任何工具描述或系统提示词之后都会跑一遍回归测试确保没有把之前正常的功能弄坏。这个习惯是从传统软件工程里带过来的但在 Agent 项目里尤其重要因为修改描述带来的影响往往是非预期的。调试 Agent 跟调试普通程序最大的不同是你要时刻记住“模型是根据上下文猜的不是按照程序逻辑走的”。所以任何异常行为都要先想想模型看到的上下文是否足够清晰是不是上下文里的某段内容误导了它这个视角一旦转变排查效率会提高非常多。这套 Agent-Reach 我前前后后改了三个版本从最开始只为跑通天气查询到现在已经能比较稳定地处理多工具串联任务。最能提高体验的操作其实是把工具描述当成“产品文案”来写每次修改都像在做文案迭代千万别觉得这是可以随手糊弄的注释。回想起来识别和执行之间的那一小段距离恰恰是 Agent 类项目中最值得花时间打磨的地方。