1. 从零跑通一个可观测的 Agent 循环ReAct、Reflection、LATS 到底怎么落地很多人第一次接触 AI Agent 设计模式都会被 ReAct、Reflection、LATS 这三个词绕晕。它们听起来像三套完全不同的框架实际上解决的是同一个问题的三个层次模型怎么在“想”和“做”之间循环怎么从错误里学习怎么在多个可能路径里选最优。ReAct 是最基础的“思考—行动—观察”闭环Reflection 是在闭环外面加一层自我批判LATS 则是把闭环扩展成一棵树用搜索算法在多个分支里找最优解。这篇文章面向的是想从零搭建可运行 Agent 的开发者。你不需要先精通 LangChain 或 LlamaIndex我会用最少的依赖、最直白的 Python 代码把三种模式各跑一遍。更重要的是我会说明如何通过 TaoToken 统一 Key/API 通道完成模型调用接入——这样你不需要在多个模型供应商之间来回切换配置一个 Key 就能覆盖 ReAct、Reflection、LATS 三种模式所需的模型调用。读完你手里会有三份可复制的配置片段、三套可运行的验证请求以及一份常见报错对照表。预期结果是你能在自己的机器上跑通一个带日志输出的 Agent 循环并且知道每种模式适合什么场景、不适合什么场景。先说清楚一个前提Agent 的本质不是“更聪明的模型”而是“模型 工具 循环控制”。模型负责推理工具负责和外部世界交互循环控制负责决定什么时候继续、什么时候停止。ReAct、Reflection、LATS 的区别本质上就是循环控制策略的区别。理解了这一点后面所有配置都不会觉得陌生。我试过用同一个任务——让 Agent 查一个城市的天气并决定要不要带伞——分别用三种模式实现。ReAct 最快跑通Reflection 多花了一轮自我检查LATS 则探索了三条不同路径。下面按顺序拆解。2. TaoToken 统一 Key 接入为什么 Agent 开发需要一个稳定通道做 Agent 开发最烦的事情之一是模型调用通道不稳定。ReAct 循环一次可能调用模型 5 到 10 次Reflection 要翻倍LATS 因为树搜索可能调用几十次。如果每次调用都要换 Key、换 Base URL、处理不同的鉴权格式调试成本会高到让人放弃。TaoToken 在这里的角色是一个统一的模型调用通道。你只需要在环境变量里配置一次 Base URL 和 API Key之后所有 Agent 循环里的模型请求都走同一个入口。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。具体来说你需要准备三样东西第一一个 API Key。在控制台里创建地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建后复制出来后面所有配置都用它。第二确认 Base URL。Agent 代码里通常需要填base_url这里填https://taotoken.net/api即可。注意 API 地址不加 UTM 参数保持干净。第三选一个 Model ID。ReAct 和 Reflection 对模型推理能力要求中等LATS 因为要做价值评估建议选推理能力更强的模型。你可以在模型对话页面先试一下目标模型是否可用 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。如果你用的是 Claude Code 这类编码 AgentTaoToken 也提供了对应的接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。文档里会说明 Base URL、Key、Model ID 三件套怎么填。这里有一个关键点Agent 循环里的模型调用是高频的所以通道的稳定性比单次调用的速度更重要。统一 Key 的好处是你不需要在代码里维护多个供应商的配置分支也不需要因为某个通道抖动就改代码。所有请求走同一个入口出错时排查范围也小很多。配置环境变量的时候建议用.env文件管理不要硬编码在代码里。下面是一个最小示例# .env TAOTOKEN_API_KEYsk-你的key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODEL_ID你的模型ID然后在 Python 里用os.getenv读取。这样你在本地调试、在服务器部署、在 CI 里跑测试都只需要改环境变量不用动代码。如果你还没有 Key先去 API Keys 页面创建一个 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建时注意权限范围Agent 开发通常只需要模型调用权限不需要开其他高危权限。3. ReAct 模式可复制配置Thought-Action-Observation 循环怎么写ReAct 的核心是三步循环Thought思考、Action行动、Observation观察。模型先输出一段思考决定下一步调用什么工具工具执行后返回结果模型看到结果后继续思考直到任务完成。下面是一个最小可运行的 ReAct 配置片段。我用 JSON 格式定义工具和循环参数你可以直接复制到自己的项目里改。{ agent_mode: react, max_iterations: 8, model: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model_id_env: TAOTOKEN_MODEL_ID, temperature: 0.2 }, tools: [ { name: get_weather, description: 查询指定城市的当前天气, parameters: { city: string } }, { name: calculate, description: 执行数学计算, parameters: { expression: string } } ], stop_condition: 模型输出 FINAL_ANSWER 标记 }这个配置里几个参数值得说明。max_iterations控制循环上限防止模型陷入死循环。ReAct 最常见的坑就是模型一直调用同一个工具不停止所以必须设上限。temperature设低一点0.2 左右因为 Agent 需要稳定推理不需要创意发散。工具定义部分description要写清楚因为模型是根据描述决定调用哪个工具的。描述模糊会导致模型选错工具。parameters用 JSON Schema 格式模型会按这个格式生成调用参数。循环控制的伪代码逻辑是这样的while iteration max_iterations: response call_model(messages) if FINAL_ANSWER in response: break action parse_action(response) observation execute_tool(action) messages.append({role: assistant, content: response}) messages.append({role: user, content: fObservation: {observation}})注意messages是累积的每一轮都把之前的思考和观察带上。这就是为什么 ReAct 的 Token 消耗会随轮次增长。如果你发现 Token 消耗太快可以在messages里只保留最近 N 轮但这样会丢失早期上下文需要权衡。工具执行部分execute_tool要做异常处理。工具调用失败时不要把异常直接抛给模型而是返回一个结构化的错误信息比如{error: 城市名称无法识别}。模型看到这个信息后可以调整参数重试。还有一个细节模型输出的 Action 格式需要严格解析。建议在系统提示词里明确要求模型按固定格式输出比如你必须按以下格式输出 Thought: 你的思考 Action: 工具名称 Action Input: JSON 格式的参数解析时用正则提取如果解析失败把原始输出返回给模型并提示格式错误让它重新输出。这个重试机制能显著提高 ReAct 的稳定性。配置写好后下一步是验证请求。不要一上来就跑复杂任务先用一个最简单的任务验证循环能转起来。4. 验证请求与成功结果三种模式各跑一遍看日志验证 ReAct 最简单的方式是让它做一个两步任务先查天气再根据天气决定是否带伞。下面是一个验证请求的示例import os import json from openai import OpenAI client OpenAI( base_urlos.getenv(TAOTOKEN_BASE_URL), api_keyos.getenv(TAOTOKEN_API_KEY) ) messages [ {role: system, content: 你是一个 ReAct Agent。按 Thought/Action/Action Input 格式输出。}, {role: user, content: 查一下北京天气然后告诉我要不要带伞。} ] for i in range(8): resp client.chat.completions.create( modelos.getenv(TAOTOKEN_MODEL_ID), messagesmessages, temperature0.2 ) content resp.choices[0].message.content print(f--- 第 {i1} 轮 ---) print(content) if FINAL_ANSWER in content: break messages.append({role: assistant, content: content}) # 这里应该解析 Action 并执行工具示例中简化为模拟观察 messages.append({role: user, content: Observation: 北京晴25度})成功跑通后你会看到类似这样的日志--- 第 1 轮 --- Thought: 我需要先查询北京天气 Action: get_weather Action Input: {city: 北京} --- 第 2 轮 --- Thought: 北京晴天25度不需要带伞 FINAL_ANSWER: 北京今天晴天25度不需要带伞。关键观察点第一轮模型输出了 Action第二轮看到 Observation 后输出了 FINAL_ANSWER。如果模型在第一轮就直接输出 FINAL_ANSWER说明它没有调用工具可能是工具描述不够清晰或者系统提示词没有强调必须调用工具。Reflection 模式的验证稍微不同。它需要在 ReAct 循环结束后加一轮反思。你可以在FINAL_ANSWER之后追加一条消息messages.append({role: user, content: 请检查上面的答案是否有遗漏或错误如果有请修正。}) resp client.chat.completions.create(model..., messagesmessages) print(反思结果, resp.choices[0].message.content)成功时你会看到模型指出自己可能遗漏的信息比如“没有考虑紫外线强度”或“没有说明温度单位”。如果模型只是重复原答案说明反思提示词不够具体可以改成“请从准确性、完整性、可操作性三个角度检查”。LATS 的验证最复杂因为它涉及树搜索。一个简化的验证方式是让模型生成三个不同的行动方案然后对每个方案打分选最高分的执行。日志里你会看到三条分支的评分和最终选择。三种模式跑通后对比日志你会发现ReAct 轮次最少Reflection 多一轮但答案更完整LATS 轮次最多但能覆盖更多可能性。选择哪种模式取决于你的任务对准确性和成本的要求。5. 常见报错排查401、local proxy failed、reading choices、OAuth 怎么处理Agent 开发过程中最容易遇到的报错集中在模型调用环节。下面按报错类型逐一说明。401 Unauthorized这是最常见的错误原因是 API Key 无效或没有正确加载。排查步骤第一确认.env文件里的TAOTOKEN_API_KEY没有多余空格第二确认代码里读取环境变量的名称和.env里一致第三确认 Key 没有过期或被删除。如果用的是 Claude Code 或 Cline 这类工具检查配置文件里的 Key 字段是否填对。三件套检查清单Base URL 填https://taotoken.net/apiKey 填控制台创建的 KeyModel ID 填模型对话页面确认可用的 ID。local proxy failed这个报错通常出现在本地开发环境原因是代码里配置了本地代理但代理服务没有启动。排查步骤第一检查环境变量里是否有HTTP_PROXY或HTTPS_PROXY设置如果有确认代理服务是否运行第二如果不需要代理直接清空这两个环境变量第三确认base_url没有被错误地指向本地地址。Agent 代码里如果用了requests库它默认会读取系统代理设置可以在代码里显式设置proxies{http: None, https: None}来绕过。reading choices 报错这个报错通常表现为KeyError: choices或IndexError: list index out of range原因是模型返回的响应结构不符合预期。排查步骤第一打印完整的resp对象看返回的 JSON 结构第二确认模型 ID 是否正确错误的模型 ID 可能导致返回错误结构第三检查是否触发了内容过滤某些请求可能返回空 choices。处理方式是在代码里加防御性判断if not resp.choices: print(响应为空原始返回, resp) continue content resp.choices[0].message.contentOAuth 相关报错如果你用的是 Claude Code 或 Codex 这类工具可能会遇到 OAuth 认证失败。这类工具通常支持两种认证方式OAuth 登录和 API Key。在 Agent 开发场景下建议直接用 API Key 方式避免 OAuth 流程的复杂性。配置时确认auth.json或settings.json里的认证字段填的是 API Key而不是 OAuth token。如果工具同时支持两种方式优先选 API Key。循环不停止这不是报错但比报错更常见。模型一直调用工具不输出 FINAL_ANSWER。处理方式第一设max_iterations上限第二在系统提示词里明确“如果已经获得足够信息必须输出 FINAL_ANSWER”第三检测重复 Action如果连续两轮调用同一个工具且参数相同强制终止并返回当前结果。Token 消耗过快ReAct 循环累积上下文导致 Token 线性增长。处理方式第一只保留最近 3 到 5 轮消息第二把工具返回的长结果截断只保留关键信息第三把 Observation 压缩成简短摘要再放回 messages。排查时建议打开详细日志把每一轮的请求和响应都打印出来。Agent 的问题通常不是单点故障而是循环中某一轮的输出格式不对导致后续全部错乱。看到第一轮异常就停下来检查不要让它继续跑。6. 语义一致 CTA从跑通到长期编码按需选择入口三种模式跑通之后你可能会想把它用到实际项目里。这时候有几个入口可以按需选择。如果你还在调试接入配置或者遇到了上面提到的报错先去 API Keys 页面确认 Key 状态再看接入文档核对三件套配置。API Keys 入口 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档入口 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。如果你想先验证某个模型在 ReAct 或 Reflection 任务上的表现可以直接在模型对话页面测试。输入一个多步任务看模型是否能正确输出 Thought/Action 格式。模型对话入口 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。如果你打算把 Agent 用到长期编码任务或复杂 Agent 工作流里比如让 Agent 自动修 bug、跑测试、提交代码那建议看一下 Coding Plan。这类场景对通道稳定性和调用配额的要求更高Coding Plan 入口 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。如果你用的是 Claude Code 做编码 Agent接入方式和普通 API 调用略有不同参考 Claude Code 接入文档 https://taotoken.net/claude-code?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-codeutm_campaignrewrite 。最后说一个实际经验Agent 开发最难的不是写循环而是让循环稳定。ReAct 跑通一次很容易跑一百次不出错很难。稳定性来自三个方面严格的输出格式约束、完善的异常处理、合理的循环上限。把这三点做好再考虑上 Reflection 或 LATS 做增强。不要一上来就追求最复杂的模式先用 ReAct 把基础链路跑稳再逐步加反思和搜索。
阅读完成 · 觉得有帮助?