跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://qitor.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

这一课开始,课程会从模式设计真正走向操作工作流。 你仍在使用同一个 QitOS 执行内核,但智能体现在必须在工作区中稳定运行很多步。这就带来了新的设计问题:
  • 还要继续手工组装工具界面吗?
  • 系统提示词里应该放多少工作流纪律?
  • 什么时候 HistoryPolicy 就够了?
  • 什么时候应该升级到 CompactHistory 或显式记忆?
本课对应的示例是 examples/real/claude_code_agent.py

相比第 2 课的变化

设计分支第 2 课第 3 课
工具手工注册表 + 裁剪版 CodingToolSetcoding_tools(...) 预设注册表
提示词规划器 + 执行器提示词单个重工作流系统提示词
状态计划与游标待办事项、模式、目标文件、验证命令、可选文档链接
历史默认行为显式 HistoryPolicy(max_messages=16, max_tokens=2800)
记忆不使用默认仍不使用,但此时记忆开始成为真实选项
上下文压缩还未引入作为更长运行的升级路径被正式引入

系统提示词现在定义的是工作流纪律

和第 1 课不同,这一课的提示词不再只是解析器契约,它还编码了操作流程:
Workflow:
- Start by writing a todo list with `todo_write`.
- If you are unsure which tool to use, call `tool_search`.
- Read before you edit.
- Make the smallest correct change.
- Run verification immediately after editing.
- 只有在任务确实需要文档时才使用 `web_fetch`。
在 v0.4 中,输出契约已经不再被硬编码在示例提示词里,而是由当前协议(模型输出的格式契约)自动注入:
Thought: <short reasoning>
Action: <tool_name>(arg=value, ...)
or
Final Answer: <what changed + verification proof>
这一课想让你看到:
  • 运行时没变
  • 提示词却可以变得非常面向操作

本课默认解析器依旧故意保持 ReAct

尽管提示词复杂了很多,解析器仍然是:
model_parser=ReActTextParser()
这是有意为之的。你正在学习:仅通过
  • 更合理的 state
  • 更成熟的工具界面
  • 更清晰的工作流提示词
就可以显著改变智能体行为,而不必立刻升级协议。

这个示例现在是预设优先的

底层传输层仍然可以是 OpenAICompatibleModel,但 v0.4 会先解析:
  • FamilyPreset(预配置的模型家族默认值)
  • HarnessPolicy
  • 协议 / 解析器 / 工具交付方式 / 上下文默认值
因此,同一个示例现在可以在 Qwen、Kimi、MiniMax、gpt-oss 与 Gemma 4 之间切换,而不用改智能体实现本身。 对其中多数家族来说,适配层依然是文本或 JSON 优先的:
  • 模型返回文本
  • 工具模式通过提示词注入,或通过工具参数交付
  • 解析器把文本解析成决策(智能体每步的结构化决策)
MiniMax 则继续保留自己更适合的工具调用解析器。 这种路径对研究仍然很有价值,因为它:
  • 容易跨供应商比较
  • 容易在追踪记录中检查
  • 容易接到本地端点
如果你确实需要家族专属协议,QitOS 现在会通过预设系统把这类耦合显式记录下来。
1

从预设工具注册表开始

本课通常会这样初始化:
super().__init__(
    toolset=[
        coding_tools(
            workspace_root=workspace_root,
            shell_timeout=30,
            include_notebook=True,
        )
    ],
    llm=llm,
    model_parser=ReActTextParser(),
)
到了这里,预设才是正确的抽象层。coding_tools(...) 直接给你一个一致的工作区捆绑包,不必再手工把文件、终端、任务、笔记本工具逐个注册。这一课的经验是:
  • 学习内核时手工暴露工具
  • 智能体进入真实工作流后切换到预设
2

理解预设真正带来了什么

coding_tools(...) 是 QitOS 的标准编码工具包。实际上它通常意味着智能体拥有:
  • 文件查看与编辑
  • 终端执行
  • 任务与待办辅助
  • 可选笔记本支持
  • 可选网页与文档工具
当智能体走到这一步时,你选择的不再是一个工具,而是在选择一个工作环境。
3

把 state 设计成长时运行友好的形状

这一课的 state 会开始承载工作流信号:
@dataclass
class ClaudeCodeState(StateSchema):
    scratchpad: list[str] = field(default_factory=list)
    todos: list[dict[str, Any]] = field(default_factory=list)
    target_file: str = TARGET_FILE
    test_command: str = TEST_COMMAND
    doc_url: str = DOC_URL
    mode: str = "work"
这套 state 有效,是因为:
  • todos 把工作队列显式化,并能跨多步保留
  • mode 帮助智能体记住自己处于规划还是执行阶段
  • doc_url 让外部文档检索变成可选输入,而不是默认浏览
  • scratchpad 仍保存压缩后的最近轨迹
4

让归约吸收结构化工具输出

reduce() 会开始从工具结果中吸收结构化工作流状态:
if isinstance(first, dict):
    if first.get("todos"):
        state.todos = list(first.get("todos") or [])
    if first.get("current_mode"):
        state.mode = str(first.get("current_mode"))
    if int(first.get("returncode", 1)) == 0:
        state.final_result = (
            "Verification passed with the canonical coding toolset."
        )
if state.metadata.get("todos"):
    state.todos = list(state.metadata.get("todos") or [])
if state.metadata.get("mode"):
    state.mode = str(state.metadata.get("mode"))
这仍然是在延续前两课的同一原则:工具在做工作,但真正决定智能体该记住什么的,依然是 reduce()
5

第一次显式引入历史控制

本课的运行通常会传:
history_policy=HistoryPolicy(max_messages=16, max_tokens=2800)
这是课程里第一次让消息窗口管理变得重要。HistoryPolicy 回答的是:
  • 最近多少消息会被保留
  • 历史最多可以占多少 token
  • 何时旧上下文不再原样进入模型
6

理解历史、上下文压缩与记忆的边界

在这一课里,示例默认仍然挂载自定义 history=memory=这是一个有意为之的设计:
  • HistoryPolicy 负责消息预算
  • state 负责保存待办事项、模式之类的即时工作流产物
  • 还不需要单独的记忆存储
但当运行足够长、简单裁剪已经开始影响行为时,就应该升级到 CompactHistory
from qitos.kit import CompactConfig, CompactHistory, WindowMemory

super().__init__(
    toolset=[coding_tools(workspace_root=workspace_root)],
    llm=llm,
    model_parser=ReActTextParser(),
    history=CompactHistory(
        llm=llm,
        config=CompactConfig(
            max_tokens=2800,
            keep_last_messages=10,
            keep_last_rounds=4,
        ),
    ),
    memory=WindowMemory(window_size=30),
)
要把这几层读清楚:
  • HistoryPolicy:这次请求带哪些消息
  • CompactHistory:旧交互如何被上下文压缩压缩与保留
  • Memory:什么信息要脱离即时消息流而长期存在
7

理解什么时候值得升级协议

即使智能体更复杂了,本课依然继续使用文本 ReAct。这通常仍是正确选择。只有在这些场景下才值得考虑协议升级:
  • 需要比文本 ReAct 更严格的结构化输出时,升级到 JSON 或 XML
  • 智能体正在驱动实时终端会话时,考虑 Terminus
  • 供应商原生输出结构化工具调用且你确实想保留它时,使用 MiniMaxToolCallParser 等模型专属解析器
不要因为智能体变复杂了,就自动切换协议。
8

像操作者一样运行,像研究者一样检查

运行:
python examples/real/claude_code_agent.py
查看:
qita board --logdir runs
qita 中重点看:
  • 待办事项是否在前期建立,并且后续保持一致
  • mode 的切换是否符合预期工作流
  • 提示词与解析器是否仍然保持在简单 ReAct 主路径上
  • 历史裁剪是否开始影响模型行为
  • 这次运行是否已经值得升级到 CompactHistory

长时运行智能体的正确心智模型

到这一课为止,你应该开始用分层的方式思考:
  • state:下一步一定需要什么
  • history:下一次模型调用可能需要什么
  • 上下文压缩:更早的历史如何被压缩
  • memory:哪些信息应该脱离即时轮次结构长期存在
这也是 QitOS 在长时运行设计上最重要的区分。

完整示例

完整可运行代码位于:

第 4 课会引入什么

第 4 课会继续保留长时运行结构,但任务域会完全切换。 你将看到如何在不发明新运行时的前提下,调整:
  • 工具组合
  • 提示词策略
  • 状态语义
  • reduce() 逻辑
从而得到一个真正的领域化智能体。

下一课:代码安全审计智能体

把同一个内核变成具备排序发现的防御式审查智能体

相关指南:可观测性

在进入最终课程前,先把 qita 面板、回放与导出再回顾一遍