1. 从一次“卡住”的任务说起:CoT 与 ReAct 在 Agent 里到底谁管什么
如果你正在做 AI 智能体(Agent)开发,大概率遇到过这种场景:给智能体一个稍微复杂的任务,比如“帮我整理一份本周技术热点并生成摘要”,它要么在第一步就停下来等你继续输入,要么反复调用同一个搜索工具,把同样的关键词查了五遍,最后返回一堆重复内容。这不是模型不够聪明,而是任务规划层没有把 CoT(Chain of Thought,思维链)和 ReAct(Reasoning + Acting,推理与行动)的分工理清楚。
CoT 解决的是“想清楚”的问题。它让模型在给出最终答案前,先把推理过程展开,把复杂问题拆成可管理的子问题。ReAct 解决的是“做明白”的问题。它在推理的基础上引入行动,让智能体能够调用外部工具、观察返回结果、再根据结果调整下一步。两者不是替代关系,而是上下游关系:CoT 负责生成推理路径,ReAct 负责把推理路径落到工具调用链路里,形成“思考—行动—观察”的闭环。
OpenManus 这类开源智能体框架之所以值得参考,是因为它把这条链路拆得足够清晰。它的 BaseAgent 定义了执行循环,ReActAgent 把 step 拆成 think 和 act,ToolCallAgent 再把工具调用接进来。你不需要照搬它的全部代码,但理解这个分层,能帮你避开“把所有逻辑塞进一个 prompt”的坑。这篇内容会围绕一个可跟做的 Agent 配置展开,从意图解析到执行反馈,把 CoT 与 ReAct 的分工落到可复制的 JSON 配置和一次端到端验证上。适合已经了解大模型 API 调用、想进一步做任务型智能体的开发者。
2. 前置准备:用 TaoToken 统一模型入口与工具调用链路
在拆解 CoT 与 ReAct 之前,先把模型调用入口固定下来。智能体开发最怕的是模型接口换一个、工具调用格式变一次,整个链路就要重写。我试过在多个项目里来回切换模型端点,最后发现统一走一个兼容 OpenAI 接口的入口最省事。TaoToken 提供的就是这样一个入口,它的 API 地址是 https://taotoken.net/api,兼容常见的 chat completions 和 tools 调用格式,你可以在模型对话页面先验证模型是否正常响应,再进入编码环节。
为什么智能体场景特别需要统一入口?因为 ReAct 模式下的每一轮 think 和 act 都会产生一次模型调用,如果每次调用的端点、鉴权方式、工具描述格式不一致,调试成本会成倍增加。TaoToken 的接口设计让你可以用同一套 Base URL 和 Key 去驱动不同模型,工具调用的返回结构也保持一致。这样你在写 ToolCallAgent 时,不需要为每个模型写适配层。
具体操作上,先到 API Keys 页面生成一个 Key,然后在接入文档里确认 tools 参数的写法。如果你用的是 Claude Code 这类编码工具做智能体原型,可以在它的配置里把 Base URL 指向 https://taotoken.net/api,Model ID 填你实际要用的模型名。对于长期跑编码类 Agent 的场景,Coding Plan 提供了更稳定的调用额度,适合把智能体挂在后台持续执行任务。
这里要强调一点:智能体的工具调用链路对模型返回格式很敏感。ReAct 要求模型在 think 阶段输出“我要调用哪个工具、参数是什么”,在 act 阶段执行后把 observation 拼回上下文。如果模型返回的 tool_calls 结构不标准,整个循环就会断掉。TaoToken 的兼容层会把不同模型的工具调用统一成 OpenAI 风格的 tool_calls 数组,你在解析时只需要处理一种格式。这是把 CoT 和 ReAct 串起来的前提。
3. 可复制配置:把 CoT 提示词与 ReAct 工具链写进 settings
下面这份配置可以直接复制到你的项目里,路径建议放在config/agent_settings.json。它把 CoT 的系统提示词、ReAct 的循环参数、工具定义三部分分开,方便你单独调整。注意 Model ID 和 Base URL 要和你实际使用的入口一致。
{ "agent": { "name": "cot_react_agent", "max_steps": 12, "duplicate_threshold": 2, "system_prompt": "You are an assistant focused on Chain of Thought reasoning. For each question, follow these steps: 1. Break down the problem into smaller parts. 2. Think step by step and show your reasoning. 3. Synthesize conclusions. 4. Provide a concise answer. Your response format: Thinking: [detailed reasoning] Action: [tool name and arguments] ", "next_step_prompt": "Based on the observation, decide the next action. If the task is complete, call the terminate tool." }, "llm": { "base_url": "https://taotoken.net/api", "api_key": "sk-your-key-here", "model_id": "gpt-4o-mini", "temperature": 0.2 }, "tools": [ { "name": "web_search", "description": "Search the web for current information", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "search keywords" } }, "required": ["query"] } }, { "name": "python_execute", "description": "Execute Python code in a sandbox and return stdout", "parameters": { "type": "object", "properties": { "code": { "type": "string", "description": "Python code to run" } }, "required": ["code"] } }, { "name": "terminate", "description": "Terminate the interaction when the task is complete", "parameters": { "type": "object", "properties": { "status": { "type": "string", "enum": ["success", "failure"] } }, "required": ["status"] } } ] }这份配置里,system_prompt承担 CoT 的角色,强制模型先输出 Thinking 再输出 Action。next_step_prompt承担 ReAct 的循环推进,每一轮 observation 回来后,用它提醒模型决定下一步。max_steps和duplicate_threshold是防止无限循环的保险丝,当同一条 assistant 消息重复出现超过阈值时,触发 stuck 处理,往上下文里注入“换策略”的提示。
如果你用的是 Claude Code 或 Cline 这类工具做 MCP 接入,配置片段要写成它们认识的格式。以 Cline 的 MCP 配置为例,Base URL、Key、Model ID 三件套要写全:
{ "mcpServers": { "taotoken_agent": { "command": "npx", "args": ["-y", "@taotoken/mcp-server"], "env": { "BASE_URL": "https://taotoken.net/api", "API_KEY": "sk-your-key-here", "MODEL_ID": "gpt-4o-mini" } } } }Codex 的 auth.json 则把凭证单独存放,Base URL 和 Model ID 写在 config 里。无论哪种工具,核心都是让工具调用链路指向同一个入口,这样 CoT 生成的推理路径和 ReAct 执行的工具调用才能在同一套上下文里流转。
4. 端到端验证:一次“搜索并摘要”任务的完整执行反馈
配置写好后,用一个具体任务验证闭环。任务描述:“搜索最近三天关于 AI Agent 的技术文章,提取三篇,用 Python 统计每篇标题的词频,最后输出摘要。”这个任务同时需要 CoT 拆解步骤和 ReAct 调用搜索与代码执行工具。
启动智能体后,第一轮 think 的输出应该类似:
Thinking: 任务需要三步。第一步用 web_search 找文章,第二步用 python_execute 统计词频,第三步汇总摘要。先执行搜索。 Action: web_search Arguments: {"query": "AI Agent 技术文章 最近三天"}执行 web_search 后,observation 返回搜索结果列表。第二轮 think 根据 observation 决定提取哪三篇,然后调用 python_execute。这里要注意,CoT 的推理过程会体现在 Thinking 字段里,而 ReAct 的行动体现在 Action 字段。如果模型只输出了 Thinking 没有 Action,说明 system_prompt 里的格式约束不够强,可以在 next_step_prompt 里加一句“必须输出 Action 字段,否则任务无法推进”。
第三轮 python_execute 返回词频统计结果,第四轮 think 判断任务完成,调用 terminate 工具。整个循环的 step 数控制在 4 到 6 之间。如果超过 8 步还没结束,检查 duplicate_threshold 是否触发,或者模型是否在重复调用同一个工具。实测下来,把 temperature 设在 0.2 左右,工具调用的稳定性明显好于 0.7 以上。
验证成功的标志是:最终输出里包含三篇文章标题、词频统计结果和一段摘要,并且 terminate 的 status 是 success。如果中途出现reading choices报错,通常是模型返回的 tool_calls 结构里 choices 字段为空,检查 Base URL 是否指向了兼容层,以及 tools 参数是否传入了正确的 JSON Schema。
5. 常见报错排查:401、local proxy failed 与 OAuth 问题
智能体链路跑不通时,报错往往集中在几个固定位置。下面按真实遇到的顺序排列。
401 Unauthorized 最常见。先确认 API Key 是否复制完整,有没有多余空格。然后检查 Base URL 是否写成了https://taotoken.net/api,注意不要漏掉/api路径。如果用的是环境变量,确认变量名和代码里读取的一致。有些工具会把 Key 放在 header 的Authorization: Bearer里,有些放在x-api-key,接入文档里有说明,按文档来。
local proxy failed通常出现在工具调用返回阶段。这不是网络问题,而是模型返回的 tool_calls 里 arguments 不是合法 JSON,导致本地解析失败。解决办法是在 act 阶段加一层 try-catch,把原始返回打出来看。如果 arguments 里出现了单引号或未转义字符,可以在 system_prompt 里强调“arguments 必须是合法 JSON,字符串用双引号”。
reading choices报错说明你拿到的响应结构里没有 choices 数组,或者 choices 为空。这多半是模型端点返回了错误信息但被当成了正常响应。检查 HTTP 状态码,如果是 200 但 body 里是 error 字段,说明鉴权或参数有问题。另外确认 model_id 是否拼写正确,有些模型名带版本号,少一个字符就会走到默认模型。
OAuth 相关报错一般出现在 Claude Code 或 Codex 这类工具的登录环节。如果你用的是 API Key 模式,不需要走 OAuth,直接在配置里填 Key 即可。如果工具强制要求 OAuth 而你又想用 API Key,检查是否有auth_type之类的配置项可以切换。CC Switch 这类工具在切换配置时,要确保 Base URL、Key、Model ID 三件套同时更新,只改其中一个会导致鉴权失败。
还有一个容易忽略的点:工具定义里的parameters如果 JSON Schema 写错,模型可能返回空的 tool_calls。比如required数组里的字段名和properties里的不一致,或者type写成了str而不是string。每次改完工具定义,先用模型对话页面发一条简单请求,确认模型能正确识别工具。
6. 把 CoT 与 ReAct 的分工固定下来,后续扩展才不乱
走到这里,你已经有了一个能跑通“搜索—统计—摘要”的智能体。回头看,CoT 负责的是每一轮 think 里的推理展开,它决定了任务被拆成几步、每步的目标是什么。ReAct 负责的是 think 与 act 的交替循环,它决定了工具什么时候被调用、observation 怎么拼回上下文。两者在 OpenManus 式的分层里各司其职:BaseAgent 管循环,ReActAgent 管 think/act 拆分,ToolCallAgent 管工具执行。
后续如果你想加新工具,只需要在 tools 数组里追加定义,不需要改 CoT 的提示词。如果想换模型,改 llm 配置里的 model_id 即可,ReAct 的循环逻辑不受影响。这种分工带来的好处是,调试时你能快速定位问题出在推理层还是执行层。推理层的问题表现为步骤拆解不合理,执行层的问题表现为工具调用失败或 observation 解析错误。
对于需要长期运行的编码类 Agent,可以把这套配置挂到 Coding Plan 的稳定调用上,避免频繁的额度中断。验证模型是否支持工具调用时,模型对话页面是最快的入口。接入文档里有完整的 tools 参数示例和错误码说明,遇到不确定的返回结构,先对照文档确认格式。把这套链路跑顺之后,再往里面加记忆系统或知识库检索,就不会因为基础循环不稳而反复返工。