- 强类型 state
- 真实 LLM harness
- 真实 system prompt
- 真实 parser
- 真实 tools
- 真实
reduce()循环 - 真实
qitatraces
examples/patterns/react.py 来学习,但这节课本身会把设计解释清楚,不要求你先反向阅读源码。
你要构建什么
任务非常小:- 打开
buggy_module.py - 修复
add(a, b),让它返回a + b - 运行验证命令
本课的设计选择
| 设计分支 | 本课选择 | 为什么这是最好的起点 |
|---|---|---|
| 任务形态 | 单文件 bug fix + 单个验证命令 | 易验证、易追踪 |
| State | scratchpad、target_file、test_command | 足够影响下一步决策,但不引入冗余状态 |
| Model harness | 返回文本的 OpenAICompatibleModel | 简单、可迁移、provider-agnostic |
| Prompt 契约 | REACT_SYSTEM_PROMPT | 明确的一次一工具文本协议 |
| Parser | ReActTextParser | 与 Thought: / Action: 完整对应 |
| Tools | 手工 ToolRegistry + 紧凑 CodingToolSet | 先学清楚工具表面,再学 presets |
| Memory | 不使用 | run 很短,没有引入单独 memory 的必要 |
| History | 使用 Engine 默认行为 | 在理解内核之前不引入额外 context control |
| Traceability | qita board | 从第一课就学会检查 kernel |
为什么从文本 ReAct harness 开始
本课使用:messages -> text model output -> ReAct parser -> Decision -> tool execution
我们不从 native tool calling、XML、JSON 或 model-specific harness 开始,因为那些选择会在你还没理解核心 loop 之前,过早引入协议耦合。
system prompt 是协议,不是装饰
本课使用的 ReAct prompt 大致是:ReActTextParser 不是在“猜”模型输出,它是在消费这份明确约定好的协议。
本课最重要的第一条经验就是:
- prompt 格式与 parser 选择,本质上是一项联合设计决策
- 改了其中一个,通常就要连另一个一起改
本课的 model harness
示例里的模型构造通常长这样:- 它适用于 OpenAI-compatible endpoints
- 模型返回纯文本,便于观察
- 与基于 prompt 注入 tool schema 的路径天然兼容
- 让课程可以在不同 provider 与本地网关间迁移
围绕下一步决策来设计 state
本课的 state 刻意很小:为什么是这三个字段:
scratchpad:保存压缩后的最近轨迹,供下一步决策使用target_file:让 agent 始终围绕单一工件行动test_command:把“任务完成”变成一个可执行成功条件
暴露尽量小的 tool surface
示例使用手工 registry,让你能精确看到暴露给模型的能力:
CodingToolSet 本身是 bundle,但它的表面仍是你主动裁剪出来的。对第 1 课来说,最合适的工具集合只需要覆盖:- 查看文件
- 编辑文件
- 运行验证命令
把 prompt 与 parser 明确绑在一起
agent 构造函数里通常会这样写:要把这句话读成一个整体:“这个 agent 要求模型输出 ReAct 文本,并由 ReAct parser 负责解析。”在 QitOS 里,这个绑定本身就是 harness 的一部分。
prepare 只组织下一步真正需要的上下文
prepare() 负责把 state 变成 prompt-ready 文本:prepare() 不是 state dump,而是 prompt 视图。让 reduce 决定 agent 记住什么
ReAct 的“学习”发生在 这一个函数里藏着三条原则:
reduce() 里:- 不是每条 observation 都值得回灌进未来上下文
- state 是压缩工作记忆,而不是全量日志
final_result是成功的显式信号
理解本课还没有引入什么
第 1 课刻意不使用:
decide()overrides- explicit planning
- memory adapters
- custom history
- context compaction
- model-specific protocol overrides
为什么这一课不引入 memory 或 compaction
本课最正确的 memory 选择就是:不用。 原因很简单:- run 很短
scratchpad已足够容纳有效上下文- 过早引入 retrieval 或 compaction 会模糊架构边界
完整示例
完整可运行代码位于:第 2 课会引入什么
第 2 课会保持相同的 model harness 和执行 parser,但引入一个新的设计点: planning 应该变成显式 state 与显式控制边界,而不是藏在更长的 thought 里。下一课:PlanAct
加入 planner、cursor 与
decide() gate,但不更换核心 runtime相关参考:Kit
回看本课使用的
ReActTextParser、prompt templates 与 coding tool surface