1. 为什么你的 Agent 总是“想一半就动手”从 Planning 与 Reflection 说起AI Agent 这两年从 Demo 走向生产最大的拦路虎不是模型不够聪明而是大脑缺少一套可落地的规划与反思闭环。你可能遇到过这种场景让 Agent 帮忙“整理一份竞品分析报告”它上来就开始写正文写到一半发现数据源没找全又回头补补完发现结构乱了最后交出来的东西逻辑断裂。这不是模型能力问题而是 Harness Engineering 里最核心的一环没搭好——Planning规划和 Reflection反思没有形成可验证的闭环。所谓 Harness Engineering说白了就是“给 Agent 套上缰绳”的工程实践你怎么设计它的任务分解、怎么约束它的行动序列、怎么让它执行完自己检查一遍再决定要不要重来。Planning 负责“想清楚再动手”Reflection 负责“做完回头看”。两者缺一Agent 就会退化成“单轮问答机器”而不是能处理多步任务的智能体。这篇文章不讲空泛的理论我会带你用一套统一的 Key/API 通道把 Planning 和 Reflection 两阶段分别跑通并且用可复制的配置片段和验证动作让你亲眼看到多步规划和自我修正是否真的生效。适合谁看正在做 Agent 编排、想让自己的智能体从“能跑”变成“跑得稳”的开发者以及想理解 Harness Engineering 落地细节的技术同学。核心检索词就三个AI Agent、Harness Engineering、Planning 与 Reflection 机制。我试过把 Planning 和 Reflection 拆成两个独立的请求阶段分别用不同的 system prompt 约束效果比塞在一个大 prompt 里好很多。下面从接入通道开始一步步来。2. TaoToken 统一通道前置一把 Key 打通 Planning 与 Reflection 两阶段在动手写 Planning 和 Reflection 之前得先解决一个工程问题两阶段请求怎么走同一条通道。很多同学的做法是 Planning 用一个模型、Reflection 用另一个模型结果 Key 管理、计费、日志全散在各处排查问题时根本对不上号。Harness Engineering 的第一条原则就是“通道统一”否则你的 Agent 大脑还没开始思考基础设施就先乱了。TaoToken 在这里扮演的角色就是统一入口。你只需要在官网拿到一把 Key后面 Planning 阶段和 Reflection 阶段都走同一个 Base URL模型 ID 按阶段需要切换即可。这样做的好处很直接请求日志集中、额度统一、出错时能快速定位是规划阶段的问题还是反思阶段的问题。具体操作路径是这样的先访问 TaoToken 官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 完成注册然后在控制台里创建 API Key。拿到 Key 之后你的 Planning 和 Reflection 两阶段就共用这一把 Key 和同一个 Base URL。如果你后面要接 Claude Code 或者 Cline 这类工具做长期编码 Agent建议直接看 Coding Plan 的额度方案比按量计费更适合高频调用场景。这里有个容易踩的坑很多人把 Base URL 写成带/v1后缀的完整路径结果请求 404。TaoToken 的 API 地址是https://taotoken.net/api注意这个地址不带 UTM 参数UTM 只用于官网跳转追踪。你在代码里配置的时候Base URL 就填这个不要自己拼/v1/chat/completionsSDK 会自动补全。模型 ID 的选择上Planning 阶段建议用推理能力强的模型Reflection 阶段可以用同一个也可以换成更擅长分析总结的。关键是两阶段都通过同一把 Key 调用这样你在控制台能看到完整的调用链路。如果你还不确定用哪个模型可以先去模型对话页面手动试几轮感受一下不同模型在任务分解和结果评估上的表现差异再决定写进配置里。通道统一之后接下来就是真正的 Harness 设计Planning 阶段怎么让模型输出结构化的行动序列Reflection 阶段怎么让它基于执行结果给出可操作的修正建议。这两步的 prompt 设计和配置片段是整篇文章的核心。3. 可复制配置Planning 与 Reflection 两阶段的 settings 片段这一节直接给可复制的配置。我按“Planning 阶段”和“Reflection 阶段”分别写你可以直接粘到自己的项目里改。配置的核心思路是两阶段共用同一个 Base URL 和 Key但用不同的 system prompt 和 temperature。Planning 阶段 temperature 可以稍高一点鼓励它多想几种分解方式Reflection 阶段 temperature 调低让它稳定地做评估。先看 Planning 阶段的配置。这里我用一个 JSON 结构来定义方便你直接读进代码{ stage: planning, base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key, model: claude-sonnet-4-20250514, temperature: 0.7, max_tokens: 2000, system_prompt: 你是一个任务规划器。用户会给你一个复杂任务你需要1) 理解任务目标2) 将任务分解为有序的子任务列表3) 为每个子任务标注依赖关系和预期产出。输出必须是 JSON 数组每个元素包含 subtask_id、description、depends_on、expected_output 四个字段。不要输出任何解释性文字。 }Reflection 阶段的配置长这样{ stage: reflection, base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key, model: claude-sonnet-4-20250514, temperature: 0.2, max_tokens: 1500, system_prompt: 你是一个执行反思器。用户会给你原始任务、规划的行动序列、以及实际执行结果。你需要1) 判断任务是否达成目标2) 指出执行过程中哪些步骤有效、哪些无效3) 给出具体的修正建议。输出必须是 JSON 对象包含 success、score、effective_steps、ineffective_steps、suggestions 五个字段。 }如果你用的是 TOML 格式的配置文件比如某些 Agent 框架可以这样写[planning] base_url https://taotoken.net/api api_key sk-your-taotoken-key model claude-sonnet-4-20250514 temperature 0.7 [reflection] base_url https://taotoken.net/api api_key sk-your-taotoken-key model claude-sonnet-4-20250514 temperature 0.2注意这里三件套必须齐全Base URL、Key、Model ID。少任何一个请求都会失败。Base URL 统一用https://taotoken.net/apiKey 就是你在控制台创建的那把Model ID 按你实际选用的填。如果你后面要接 Claude Code它的 settings 文件里也是同样的三件套结构只是字段名可能叫ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY值是一样的。配置写好后先别急着跑完整流程。我建议你先单独测 Planning 阶段给一个稍微复杂点的任务比如“帮我规划一次线上故障复盘会的准备流程”看它输出的 JSON 数组是不是结构完整、子任务之间有没有合理的依赖关系。如果它输出了一堆解释文字而不是纯 JSON说明 system prompt 里的“不要输出任何解释性文字”没压住可以把 temperature 再调低一点或者在 prompt 里加一句“只输出 JSON第一个字符必须是 [”。Reflection 阶段的配置验证更简单你手动构造一个“执行结果”比如故意让某个子任务失败看它能不能识别出来并给出修正建议。这一步是 Harness Engineering 里最容易被忽略的——很多人只测 Planning 不测 Reflection结果上线后发现 Agent 根本不会自我修正。4. 验证请求分别发起 Planning 与 Reflection 并比对输出配置就绪后用一段 Python 代码把两阶段串起来跑一遍。这段代码你可以直接复制改掉 Key 就能用。核心是先调 Planning 拿到行动序列再模拟执行最后调 Reflection 做评估。import json import requests BASE_URL https://taotoken.net/api API_KEY sk-your-taotoken-key MODEL claude-sonnet-4-20250514 def call_llm(system_prompt, user_content, temperature): headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } payload { model: MODEL, temperature: temperature, max_tokens: 2000, messages: [ {role: system, content: system_prompt}, {role: user, content: user_content} ] } resp requests.post(f{BASE_URL}/v1/chat/completions, headersheaders, jsonpayload) resp.raise_for_status() return resp.json()[choices][0][message][content] # 第一阶段Planning planning_system 你是一个任务规划器。将任务分解为有序子任务输出 JSON 数组每个元素含 subtask_id、description、depends_on、expected_output。只输出 JSON。 task 帮我规划一次线上故障复盘会的准备流程 plan_raw call_llm(planning_system, task, 0.7) print( Planning 输出 ) print(plan_raw) # 模拟执行结果实际项目中这里接你的执行器 execution_result 已完成会议议程草稿但故障时间线数据缺失参会人名单未确认。 # 第二阶段Reflection reflection_system 你是一个执行反思器。根据任务、规划和执行结果输出 JSON 对象含 success、score、effective_steps、ineffective_steps、suggestions。只输出 JSON。 reflection_input f原始任务{task}\n规划{plan_raw}\n执行结果{execution_result} reflection_raw call_llm(reflection_system, reflection_input, 0.2) print( Reflection 输出 ) print(reflection_raw)跑完之后重点比对两个输出。Planning 的输出应该是一个结构清晰的 JSON 数组子任务之间有明确的先后依赖比如“确认参会人名单”应该排在“发送会议邀请”之前。如果它把顺序搞反了说明任务分解的逻辑没对齐你需要在 system prompt 里加一句“注意子任务之间的时序依赖”。Reflection 的输出应该能准确识别出“故障时间线数据缺失”和“参会人名单未确认”这两个问题并且给出具体的修正建议比如“优先补齐时间线数据再确认参会人”。如果它只给了一个笼统的“任务未完成”那说明反思深度不够可以把 prompt 里的“指出哪些步骤有效、哪些无效”改成“逐条对照规划中的子任务标注完成状态并说明原因”。实测下来两阶段分开调用比塞在一个 prompt 里效果稳定得多。塞在一起的时候模型经常在规划阶段就开始“反思”导致输出既不是纯规划也不是纯反思。分开之后Planning 专注分解Reflection 专注评估职责清晰输出格式也更容易解析。还有一个验证技巧你可以故意在 Planning 阶段给一个模糊任务比如“帮我处理一下那个事情”看它会不会主动追问澄清。如果它直接开始瞎规划说明你的 Harness 缺少“澄清环节”需要在 Planning 之前加一个意图确认步骤。这个步骤同样走 TaoToken 通道用低 temperature 让模型判断任务是否足够明确。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节列几个你大概率会撞上的报错以及对应的排查路径。这些错我都踩过按顺序查基本能定位。401 Unauthorized最常见的原因是 Key 没填对或者带了多余空格。检查你的api_key字段确认是sk-开头的那串不要复制到前后空格。另一个原因是 Base URL 写错了比如写成了https://taotoken.net/api/v1而 SDK 又自动补了一次/v1变成/api/v1/v1/chat/completions服务端认不出这个路径就会返回 401。正确写法就是https://taotoken.net/api让 SDK 自己拼。local proxy failed这个报错通常出现在你本地开了某些网络工具的情况下。TaoToken 的 API 地址是直连的不需要任何本地代理。如果你看到这个错先检查你的环境变量里有没有HTTP_PROXY或HTTPS_PROXY被设置成了本地地址。有的话清掉或者在代码里显式指定proxies{http: None, https: None}。另外有些 IDE 插件会自带代理配置也要检查一遍。reading choices 报错这个一般是你解析响应的时候字段路径写错了。TaoToken 返回的是标准 OpenAI 兼容格式正确路径是response[choices][0][message][content]。如果你写成了response[choices][0][text]就会报 KeyError。还有一种情况是请求被截断了choices数组为空这时候要检查max_tokens是不是设得太小或者输入内容是不是超了模型上下文限制。OAuth 相关报错如果你在用 Claude Code 或者某些需要 OAuth 授权的工具可能会遇到 token 过期或者授权失败。这时候不要反复重试先去控制台重新生成一把 Key然后在工具的配置文件里更新。Claude Code 的配置里ANTHROPIC_BASE_URL填https://taotoken.net/apiANTHROPIC_API_KEY填你的 KeyANTHROPIC_MODEL填模型 ID三件套齐全就不会出 OAuth 问题。如果你用的是 Codex 的auth.json结构类似把对应的 base URL 和 key 字段替换掉即可。还有一个隐蔽的坑模型 ID 拼写错误。比如把claude-sonnet-4-20250514写成了claude-sonnet-4有些网关会返回一个模糊的错误信息让你以为是 Key 的问题。排查的时候先把模型 ID 复制到模型对话页面手动发一条消息能通说明 ID 没问题再回头查代码。最后提醒一句如果你在 Reflection 阶段发现输出总是被截断检查max_tokens。反思报告通常比规划输出更长因为要逐条分析。建议 Reflection 阶段的max_tokens不低于 1500复杂任务可以给到 2500。6. 把 Planning 与 Reflection 接进你的 Agent 工作流到这里Planning 和 Reflection 两阶段已经能跑通了。但 Harness Engineering 的完整闭环还需要一步把反思结果反馈回规划阶段。也就是说Reflection 输出的suggestions不应该只是打印出来看看而应该作为下一轮 Planning 的输入让 Agent 带着“上次哪里没做好”的记忆重新规划。实现方式很简单在你的主循环里把 Reflection 的suggestions字段拼进下一次 Planning 的 user content 里加一句“上一轮反思建议{suggestions}请据此调整规划”。这样 Agent 就具备了跨轮次的自我修正能力。你可以用一个简单的计数器控制最大轮次比如 3 轮还没成功就退出避免无限循环烧额度。如果你要做长期运行的编码 Agent建议把 Coding Plan 的额度方案配上因为 Planning 和 Reflection 两阶段来回调用token 消耗比单轮对话高不少。按量计费在调试阶段没问题但上了生产之后包月方案更可控。另外记忆系统的设计也值得花点心思。你不需要一上来就搞向量数据库先用一个 JSON 文件存最近 10 轮的规划、执行结果和反思报告就够了。每次 Planning 之前把最近 3 轮的反思摘要读出来拼进 prompt效果已经很明显。等任务量上来了再考虑换成更结构化的存储。最后说一个我踩过的坑不要在两阶段之间共享对话历史。Planning 和 Reflection 应该是两个独立的请求各自带自己的 system prompt 和上下文。如果你把 Planning 的完整对话历史传给 Reflection模型会混淆“规划”和“反思”的角色输出变得不伦不类。正确做法是Planning 只拿任务描述和上一轮反思建议Reflection 只拿任务、规划和执行结果两边上下文隔离。这套闭环跑顺之后你的 Agent 才算真正有了“大脑”。Planning 让它想清楚再动手Reflection 让它做完回头看两者通过统一的 TaoToken 通道串联日志集中、排查方便、额度可控。接下来你可以在这个骨架上加工具调用、加多 Agent 协作但底层这套规划-反思循环是所有上层能力的地基。