Twinny:在 8000 个 token 中构建智能体
在 AI 应用开发中,小语言模型(Small Language Models, SLM)因其低延迟和高性价比备受青睐。然而,SLM 的上下文窗口(Context Window)往往有限,这给构建需要长期记忆和复杂工具调用的智能体(Agent)带来了巨大挑战。
Twinny 团队在其最新技术博客中,深入剖析了其核心 Agent 循环(Tool Loop)如何在仅 8000 tokens 的极小上下文中保持高效运行。文章重点阐述了 Twinny 如何解决“上下文溢出”问题,确保模型在每一步回复中都能准确调用工具,而不会因遗忘指令而失效。
核心挑战:上下文即成本
在 Twinny 的架构中,每一次 Agent 回复都会重新发送整个对话历史,包括系统提示词、工具列表、用户问题、之前的工具调用及结果。对于本地运行的轻量级模型,读取几个文件(如 200 行代码)可能瞬间占满宝贵的上下文空间。
如果服务器要求的上下文超过模型实际能容纳的范围,系统必须从对话前端(包含工具指令的关键区域)进行裁剪,导致模型忘记如何调用工具。因此,Twinny 的核心任务是在不牺牲功能的前提下,动态适应并优化上下文使用。
关键技术突破
1. 动态上下文探测与预算规划
Twinny 不再依赖硬编码的上下文大小,而是通过 src/extension/inference/context-window.ts 主动向服务器(如 Ollama, LM Studio)查询真实的 context_length。
- 多源探测:针对不同后端(Ollama, LM Studio, llama.cpp 等),Twinny 使用特定的 API 路径(如
/api/ps,/api/show)获取准确的上下文限制。 - 自适应策略:若探测到的上下文小于 8192 tokens,系统会发出警告,提示用户可能需要调整服务器配置或接受频繁的上下文裁剪。
- 预算分配:Twinny 将上下文窗口划分为三个部分:回复本身(约 20%)、工具调用参数、以及对话历史。这种规划确保了关键信息(如工具定义)始终保留在有效范围内。
2. 智能结果截断与恢复机制
当对话长度超过限制时,Twinny 不会简单丢弃旧数据,而是采用精细的截断策略:
- 线性边界截断:工具结果按字符数进行截断,并在截断处保留一条明确的提示:
[The rest was trimmed to save context. Run the tool again if you need it.]。 - 上下文保留:被截断的结果的第一行(最多 160 字符)会被保留在上下文中,确保模型知道之前请求了什么,从而能够重新执行该工具。
- 动态估算:系统通过观察服务器返回的 token 计数,动态调整字符到 token 的转换比率(默认 3.3 字符/token),并在后续请求中自我修正,提高估算精度。
3. 灵活的工具调用协议
Twinny 支持两种工具调用模式,以适应不同的后端环境:
- Native 模式:适用于 Ollama、OpenAI 兼容接口等。工具以 JSON Schema 形式发送,模型直接输出 JSON 块。
- Text 模式:适用于不支持 JSON Schema 的文本生成模型。系统提示词将工具描述为类似函数签名的文本格式,并要求模型输出特定的代码块(fenced block)。
这种灵活性确保了 Twinny 能在各种异构的 AI 基础设施上稳定运行。
实际价值
Twinny 的这一架构设计为开发者提供了宝贵的启示:
- 小模型 Agent 的可行性:证明了即使在没有 128k 上下文的大模型支持下,通过精细的上下文管理,构建具备工具使用能力的智能体是完全可行的。
- 容错与恢复:通过“截断 + 提示”机制,解决了长对话中信息丢失导致的逻辑中断问题,提升了用户体验。
- 资源优化:为在边缘设备或本地部署运行 AI 应用提供了最佳实践,帮助开发者在有限的硬件资源下最大化模型能力。
正如 Twinny 团队所言,"Every step of an agent reply resends the whole conversation...",理解并优化这一循环是构建高效、可靠 AI 应用的关键。