dcode:LangChain 把 Agent harness 打包成了终端编程助手
如果你看过 Deep Agents 的源码,大概会有个疑问:这个 SDK 给了子 Agent、文件系统、上下文管理、shell,但你要怎么把它变成一个每天能用的东西?自己写 TUI、自己接会话持久化、自己处理审批弹窗,一两个月就进去了。
deepagents-code 就是 LangChain 给出的答案。它是 deepagents 仓库里 libs/code 这个子包,30.7k 星的仓库、MIT 协议、Python 写的,装完给你一个叫 dcode 的命令,在终端里直接对话写代码,用哪个模型自己挑。README 里那句自我定位很实在:这个项目最初就是一次尝试,想搞清楚 Claude Code 为什么能做到通用,然后让它更通用一点。
所以它有两个身份。对用户,它是一个开箱能用的终端编程助手;对开发者,它是一份参考实现,演示怎么把 harness 包装成产品。这篇文章两个身份都拆。
它解决的那个问题
SDK 和产品之间隔着的东西,比大多数人预想的多。deepagents 的 create_deep_agent() 返回一个 LangGraph 图,图会跑,但图不会问你"这条 rm -rf 要不要执行",不会在你关掉终端之后记住上次聊到哪,也不会在你按下 / 的时候弹出命令补全。
dcode 把这些全补上了,README 列了八项:交互式 TUI、会话恢复、Web 搜索、远程沙箱、持久记忆、自定义技能、无头模式、人机审批。八项听着像营销清单,但拆开源码会发现每一项背后都有对应的模块和文档,不是占位。
十分钟上手
安装是一条命令,脚本内部用 uv 建环境:
curl -LsSf https://langch.in/dcode | bash默认带 OpenAI、Anthropic、Gemini 三家。要用别的,安装时声明 extra:
curl -LsSf https://langch.in/dcode | DEEPAGENTS_CODE_EXTRAS="nvidia,ollama" bash装完直接敲 dcode。第一次进去先 /auth 连凭据,再 /model 选模型。之后就是正常的终端对话,@ 触发文件补全,Tab 切换审批模式。
无头模式跑 CI 或脚本,靠 -n 或者管道喂 stdin:
dcode -n "把 tests/ 下所有用例的 assert 换成 pytest 风格"
echo "解释一下 src/gateway/ir.go" | dcode有一点要提前知道:从 0.2.0 起,这个包硬性要求 Python 3.14,>=3.14,<3.15,官方在 0.2.1 里补了个"没有其他会话在跑时自动迁移到 3.14"的逻辑。我第一眼看到这个约束有点意外,一个 0.2.x 的包把语言版本锁这么死,等于放弃了所有还在 3.12/3.13 的机器。好处是他们能直接用新版本的语法和标准库,坏处是你公司的镜像源里可能还没有 3.14 的 wheel,装的时候得自己想办法。
三档审批:Manual、Auto、YOLO
Shift+Tab 在三种模式之间循环,状态栏会一直显示当前档位。这是它和 SDK 差别最大的地方,也是最值得单独讲的设计。
| 模式 | 行为 | 我的判断 |
|---|---|---|
| Manual | 每个被拦截的工具调用都要你点确认 | 默认档,第一次用别人仓库时别关 |
| Auto | 交给一个 LLM 分类器判断,放行、拒绝或升级给人 | 最有意思的工程,也是最该小心的地方 |
| YOLO | 全部放行,进入前必须手工确认一次警告 | 只在自己写的、能 git checkout 回来的目录里用 |
Auto 模式不是"随便放行",它起了一个独立的授权分类器,把待执行动作连同用户的原话、同轮问答一起丢进去,让模型输出九个类别之一的判定:越权、破坏性操作、凭据访问、外部共享、绕过安全、持久化、受保护资源、越界信任、其他。分类器可以指定成比主模型更便宜更快的模型,用 /auto model 切换。
安全声明写得很克制:只有用户的原话、显式设置的 goal/rubric、以及服务端验证过的问答回复能构成授权。Agent 自己写的状态说明、还没被接受的提案、工具输出、模型散文,全都不算。分类器构建失败时不会退回主模型,而是直接判成 classifier_unavailable,这一批请求全部拒绝,然后升级给人处理。这个"失败就关门"的方向是对的。
我的担心在别处。分类器读的输入里有大量不可信内容:工具参数、文件路径、上一轮的工具输出、模型自己写的提问文本。给 Auto 配一个便宜模型,等于让一个更弱的模型去分辨注入攻击。威胁模型里 T14 自己也承认了这点,说这是"对控制项的自愿削弱"而不是外部攻击路径。这个定性挺诚实,但结论还是那句话:Auto 适合你已经建立信任的工作目录,不适合陌生仓库。
YOLO 那档还留了个细节,进入要确认一次警告弹窗,政策版本号是 2026-07-14,版本一升级就得重新确认。确认过之后状态栏常驻 YOLO 角标,避免你忘了自己开着无限制模式。
架构:一个 TUI,两个进程
这是它和大多数终端 Agent 最不一样的地方。别人通常是一个进程里塞 UI 和 Agent 循环,它拆成了客户端和服务端。
graph TB
A["Terminal client: Textual TUI or headless"] -->|"HTTP + SSE"| B["LangGraph dev server on 127.0.0.1, ephemeral port"]
B --> C["create_cli_agent"]
C --> D["Model provider"]
C --> E["Tools: file, shell, fetch_url, web_search"]
C --> F["MCP servers"]
C --> G["Hooks and Python extensions"]
C --> H["Sandbox: Daytona, Modal, Runloop, LangSmith, AgentCore"]
A --> I["SQLite checkpoints in ~/.deepagents"]
B --> I每次启动,CLI 会在本地拉起一个 langgraph dev 子进程,通过 DA_SERVER_* 环境变量把配置递进去,然后用 RemoteAgent 走 HTTP + SSE 连上。服务端跑图、跑模型、跑工具,客户端只管渲染和收审批。会话状态落在 ~/.deepagents/ 下的 SQLite 里,LangGraph 的 checkpoint 机制负责恢复。
这么拆的收益是 UI 不会被模型调用卡住,流式渲染也在客户端本地做,而且 Agent 核心可以脱离 UI 单独测试。代价是调试时你得先判断故障在哪一侧:渲染错乱基本在客户端,模型、工具、记忆、图启动基本在服务端。架构文档里直接把这句写成了排查建议。
配置系统也有个明确取舍:user、project、session、runtime 四层合并成一份"配置代",第一次读的时候构建,之后复用。运行中改 config.toml 不生效,要么在应用内写默认配置路径,要么 /reload。理由写得很直白:配置应用一半比配置过时更糟。所以它干脆不监听文件变化。另外某个配置文件解析失败时,那一层保留上次可用的快照,而不是整层清空。
我不太喜欢这种"改完不生效"的体验,但能理解。/reload 敲一次的成本,比排查"为什么两个读者看到不同的值"低太多。
46 个命令里真正值得用的
COMMANDS.md 是脚本从 command_registry.py 自动生成的,46 个公开命令加 2 个隐藏命令。绝大多数是日常操作,/clear、/model、/theme 这种不用解释。挑几个别处不太常见的:
/context-doctor 审计当前会话到底往上下文里塞了什么,以及每一项估算多少 token。你接了一堆 MCP 和技能之后,这个命令能告诉你钱花在哪了。
/offload(别名 /compact)把老消息卸载掉或者压缩,还能单独指定摘要用哪个模型。长会话里这个比 /clear 温和,不至于把上下文全丢掉。
/goal 设一个带验收标准的长期目标,/rubric 设评分标准。这两个不是聊天用的,它们会以合成消息的形式进入主模型上下文,并且在压缩之后被重新钉回去。/rubric file 能直接读一个文件当标准,上限 12000 字符,超了直接拒绝而不是截断。
/btw 问一个不影响主对话的旁支问题。实现上单独的 system prompt,而且不进 checkpoint。查一个 API 名字又不想污染上下文的时候很实用。
/threads(别名 /resume)列历史会话接着聊,/rename 起名字,/trace 直接把当前线程丢到 LangSmith 里看。
/cost 估当前线程花了多少,数据来自 genai-prices 的离线目录,每小时后台刷一次。文档特意强调这只是展示值,任何地方都不会因为花费超限而阻止执行。
还有一个 /force-clear,专门用来从卡死的会话里捞出来。有这个命令,说明卡死确实发生过。
扩展有三条路,成本和风险完全不同
第一条是 skills 和 subagents,纯 Markdown,最安全。自带四个技能:remember、skill-creator、deepagents-plugin-discovery、deepagents-thread-inspector。/skill-creator 能现场帮你写一个新技能,/remember 把有用的上下文存成记忆或技能。subagent 就是 .deepagents/agents/<name>/AGENTS.md,YAML frontmatter 之后的内容直接当子 Agent 的 system prompt。
第二条是 hooks,一个 hooks.json 配 shell 命令。这块的兼容性值得单独说:事件名是 SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、SubagentStart、Stop 这些,工具匹配用 wire name(execute 映射成 Bash,write_file 映射成 Write),插件环境变量叫 CLAUDE_PLUGIN_ROOT、CLAUDE_PLUGIN_DATA、CLAUDE_PROJECT_DIR。Claude Code 的 hook 写顺手的人,基本改个路径就能搬过来。README 里也承认灵感来自 Claude Code,这个兼容是刻意的。
hooks 有个不太显眼的实现细节:12 个事件分属两个进程。SessionStart、UserPromptSubmit、PermissionRequest、Notification、SessionEnd 归客户端,PreToolUse、PostToolUse、PreCompact、SubagentStart 这些归服务端。所以你说"hook 没触发",先确认这个事件是客户端还是服务端拥有的。
写法上是标准的那套:stdin 收 JSON 事件,退出码 2 表示 block,stdout 吐 HookWireOutput JSON 能改 continue、systemMessage、additionalContext,PreToolUse 还能直接给 permissionDecision: "deny"。超时会被杀掉并记为诊断,不会当成成功。
第三条是 Python 扩展,能力最大也最危险。它要 DEEPAGENTS_CODE_EXPERIMENTAL=1 才加载,入口是一个 async 的 extension 函数,可以注册中间件、注册工具、注册虚拟存储路由、注册退出回调:
async def extension(dcode):
dcode.register_tool(my_search_tool)
dcode.register_backend_route("/company/knowledge/", my_storage)register_backend_route 这个接口挺妙:你挂一个 /memories/ 前缀的存储实现,模型的文件工具就能读写它,但它不是本地磁盘。副作用是 shell 的 execute 看不到这些虚拟路径,因为 shell 还是绑在默认的本地或沙箱存储上。另外沙箱模式下会拒绝挂 FilesystemBackend 和 LocalShellBackend,包括子类,理由是那等于在沙箱里开一个通向宿主机的后门。
每个扩展的 setup 是事务性的,导入或初始化失败就把这家的注册全部回滚,后面的扩展照常加载。项目级扩展在 .deepagents/extensions/ 下,交互启动会问你要不要信任,无头模式得显式传 --trust-project-extensions。
120KB 的威胁模型,写了什么
THREAT_MODEL.md 有 120KB,开头自己声明是自动生成、实验性、可能不准确、不是权威安全参考。这个自我限定我反而觉得是加分项:它没打算当免死金牌。
文档里最该看的是几处自己承认的弱点:
T12,严重级别 High。项目目录下的 .env 如果设了 BASH_ENV 或 ENV,bash 启动时会 source 它。而 dcode 每次启动都要用 bash 跑一遍本地上下文探测脚本,读 Makefile 前 20 行和目录列表塞进 system prompt。也就是说,在一个不可信的仓库里跑 dcode,恶意 .env 能在任何审批弹窗出现之前执行代码。修法是维护一份环境变量拒绝列表,文档老实说这是"尽力枚举,不是封闭集合"。
T2 和 T13,都在说同一件事:shell allow-list 不是安全边界。--shell-allow-list all 直接关掉危险模式检查;就算你只放行 python3、bash、env、xargs 这种解释器或包装器,它们自己的参数里就能塞任意代码。文档原话是"字符串分类无法稳健约束执行",真正的边界得靠 HITL 审批或操作系统级沙箱。
T6,本地 langgraph dev 服务用 LANGGRAPH_AUTH_TYPE=noop 起,绑 127.0.0.1 的临时端口,没有认证。同一个用户下的其他进程扫到端口就能读会话状态、注入消息。窗口期就是这次会话的生命周期。
T11b 是成本相关的:价格目录每小时从 raw.githubusercontent.com 的 main 分支拉一次,不打校验,直接整份替换本地目录。影响面只在你看到的成本数字,但"看到错误成本"本身就会误导决策。可以 DEEPAGENTS_CODE_PRICES_AUTO_UPDATE=0 关掉。
把这些放在一起看,结论不是"dcode 不安全",而是它说清了信任放在哪:信任你运行的目录、信任你装的插件、信任你选的模型。危险操作默认要靠人审批,但审批在无头模式下不存在,shell 关掉也不等于只读或者限定在项目内(本地后端是 virtual_mode=False,绝对路径照样能碰)。这几句在文档里写得很明确,比绝大多数同类工具诚实。
它在什么位置
和 Claude Code 比,最大的差别是模型无关和源码可读。Claude Code 绑自家模型,行为调不了;dcode 换模型就是 /model,出了问题能翻到具体是哪一层的中间件干的。加上 hooks 格式基本对齐,迁移成本不高。
和 Cursor 比,它不在 IDE 里,是纯终端。适合已经习惯 tmux + vim 的人,或者要在 SSH 上去的机器上干活的人。
和 Codex CLI 这类工具比,dcode 的差异在两个地方:一是它把 SDK 和产品分成两层,libs/deepagents 是 harness,libs/code 是包装,你只想要内核可以只装前者;二是它把沙箱做成可插拔的,Daytona、Modal、Runloop、LangSmith、AgentCore 都能换,--sandbox 一开,执行就跑到远端去了。
价格上它本身免费,花的是模型的钱。/cost 只管显示不管止损,跑长任务之前自己心里有个数。
边界和代价
Python 3.14 的硬门槛是第一个。0.2.0 直接 breaking,虽然 0.2.1 补了自动迁移,但公司内网环境、旧 CI 镜像、某些云函数运行时都会卡住。
迭代速度是第二个。PyPI 上有 93 个版本,从 0.1.88 到 0.2.2 只用了四天,0.2.2 的 changelog 里一半是安全修复和性能优化。这意味着你隔一周回来,配置项和命令行为可能都动过。追新有代价,不追也有代价。
第三个是无头模式的信任模型。-n 或管道模式下不问审批,非 shell 的工具调用默认就执行,包括文件修改和放行的网络请求。shell 要开得配 allow-list。很多人会把"没开 shell"理解成"只读",文档里专门澄清了这个误解。在 CI 里跑它,等于给 Agent 一个和你 CI 身份同等的权限,这个边界得自己划。
最后是抽象层的重量。client/server 分离让 UI 稳,但调试时多一层进程和一套流式协议;配置代的设计让值一致,但改配置要记得 /reload。这些换来的是可恢复会话和可替换执行后端,值不值取决于你的用法。
谁该用
想找一个模型随便换、行为能改、出问题能查到源码的终端编程助手,dcode 目前是少数几个认真做了这件事的。它的 hooks 和插件格式跟 Claude Code 兼容,等于给了一个可以随时回头的迁移路径。
想研究怎么把 Agent SDK 做成产品的人,libs/code 比任何教程都有参考价值。46 个命令的组织方式、三档审批的状态机、配置分层的一致性取舍、120KB 威胁模型的写法,这些是真正难的部分,也是文档里最有信息量的部分。
如果你只是想在 IDE 里补全代码,或者你团队的机器还锁在 Python 3.12,那先别急。等它从 0.2.x 里出来再说。
参考链接
- Deep Agents Code README — 官方入口
- Deep Agents Code 架构文档 — client/server 分离与配置分层
- 斜杠命令目录 — 46 个公开命令的自动生成清单
- Hooks 文档 — 12 个事件、匹配器与退出码语义
- Python 扩展文档 — 中间件、工具与虚拟存储路由
- 成本与价格覆盖 —
prices.json与 genai-prices - 威胁模型 — 120KB,自动生成,建议读 T2、T6、T12、T13
- Deep Agents Code 官方文档 — 远程沙箱与配置说明
- PyPI: deepagents-code — 版本历史与 Python 版本要求
- Deep Agents SDK — 底层 harness,本文的上一层
- 相关文章:deepagents 两个官方案例拆解 — 同一仓库的 SDK 层
- 相关文章:LangChain 公司级 harness 五组件 — 托管层视角
- 相关文章:Deep Agents 架构深挖 — 早期架构分析
你更愿意用别人调好的终端 Agent,还是自己拿 SDK 拼一个?评论区说说你的选择和理由。
作者: itech001 来源: 公众号:AI人工智能时代(the-ai-era) 网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top
本文首发于 AI人工智能时代,转载请注明出处。