[!TIP] 目标:不依赖框架,通过封装 CLI (如 gemini CLI) 构建具备状态管理与隔离能力的 Agent 引擎。
1. 为什么选择 CLI 而非框架?
VISAGENT 的核心设计哲学是 CLI-Native。相比于黑盒框架,直接封装 CLI (如 gemini CLI) 具有更高的可控性和透明度:
- 原子性:单次调用即单次推演。
- 状态透明:Session 的恢复与挂起完全由路径和 Resume 标志控制。
- 环境隔离:利用系统级工具即可实现权限沙箱。
2. 底层封装:RoleEngineBase
核心逻辑通过 subprocess 触发。为了处理长 Prompt 导致的 Shell 参数溢出,我们坚持使用 stdin 传输:
def _do_raw_invoke(self, message: str, context: str = "", files: List[str] = None) -> dict:
cmd = [AI_BIN, "--resume", "latest"] if self._get_turns() > 0 else [AI_BIN]
# 应对超长 Prompt 使用 stdin
use_stdin = len(message + context) > 2000
if use_stdin: cmd += ["-p", "-"]
result = subprocess.run(
cmd, input=f"{message}\n\n{context}" if use_stdin else None,
capture_output=True, text=True, encoding='utf-8'
)
if result.returncode == 0:
self._inc_turns()
return {"ok": True, "output": result.stdout}
3. 隔离与会话管理
凭证沙箱 (Symlink)
为了实现多角色、多项目并发而不产生凭证污染,我们利用 软链接 (Symlink) 动态注入 .gemini 配置:
def _link_auth_session(self):
global_gemini = os.path.expanduser("~/.gemini")
role_gemini_base = os.path.join(self.local_home, ".gemini")
# 动态链接凭证文件到隔离的角色执行目录
for f in ["oauth_creds.json", "settings.json"]:
os.symlink(os.path.join(global_gemini, f), os.path.join(role_gemini_base, f))
Handoff (自动摘要)
CLI 虽然支持 resume,但上下文过长会导致推演质量下降。我们在 RoleEngine 中设置了 handoff_threshold = 20。当回合数超标,系统会自动触发摘要提炼并开启新 Session。
4. 数据清洗:Agentic Noise Filter
为了让 AI 输出的“干货”能被自动化脚本直接利用,必须剔除语气词(如 “Sure, I will…")。我们使用正向预查过滤此类噪音:
def _clean_agentic_noise(self, text: str) -> str:
import re
patterns = [
r"^(I will|I am going to|Let me|First, I'll)\s+.*?\n+",
r"^(Searching for|Checking|Listing|Reading)\s+.*?\n+"
]
for p in patterns: text = re.sub(p, "", text, flags=re.IGNORECASE).strip()
return text
5. 灵魂:分层 Context 注入 (L0-L3)
最终发送给 CLI 的 Prompt 由四个模块层叠而成:
- L0 (Identity):
GEMINI.md定义的人设与架构 Lore。 - L1 (Skills):
SkillHandler提供的动态 API 清单。 - L2 (Substance): 当前代码/环境的物理元数据(通过 AST 或 Git Diff 提取)。
- L3 (Recent Context): 经过蒸馏的近期对话历史。
总结
这就是“手搓 Claw”的开端:将一个简单的 CLI 包装成一个具备工程厚度的 RoleEngine。下一篇,我们将讨论如何利用 DAG 定义复杂的异步任务流。