Open Interpreter 的 OpenCode Harness:一份系统提示词如何驱动一个完整的编码智能体
在 Open Interpreter(codex-rs)的多智能体运行框架(harness)中,opencode_system_prompt.md 是 OpenCode 这个 harness 的核心行为契约:它定义了智能体的角色身份、语气风格、任务执行流程、工具使用策略与代码引用规范。读完本文,你既能逐条理解这份提示词的设计意图,也能从源码层面看清它如何被编译进二进制、与运行时环境信息拼接、与十件工具集配套,并最终以标准 chat-completions 请求发给模型。
提示词文件在代码中的位置与加载方式
该提示词不是一个普通的文档,而是通过 Rust 的 include_str! 宏在编译期嵌入二进制源码的常量。在 opencode.rs 中可以看到:
const OPENCODE_SYSTEM_PROMPT_PREFIX: &str = include_str!("opencode_system_prompt.md");
同目录下还有两份配套提示词:
- opencode_search_agent_prompt.md:搜索子智能体(search agent)的完整指令,替代主提示词使用;
- opencode_title_prompt.md:会话标题生成的专用提示词。
harness/ 模块还包含 claude-code、kimi-cli、qwen-code、swe-agent、minimal 等多个 harness,每个 harness 都是"提示词 + 工具集 + 请求整形逻辑"的组合。OpenCode 是其中完全走 OpenAI chat-completions 风格(system/user/assistant/tool 角色、JSON function calling)的一条路线。
提示词全文逐节解读
角色定位与 URL 安全边界
提示词的第一句确立了身份:"You are opencode, an interactive CLI tool that helps users with software engineering tasks."——一个帮助用户完成软件工程任务的交互式 CLI 工具。紧接着是一条硬性安全约束:除非确信该 URL 是用于辅助编程的,否则永远不得生成或猜测 URL;可以安全使用的是用户消息或本地文件中已出现的 URL。这条规则直接约束了 webfetch 工具的调用行为——智能体只能抓取用户显式给出的或项目中存在的地址,而不是自行编造来源。
帮助与反馈通道
提示词要求:当用户请求帮助或反馈时,告知用户 /help 命令,以及"到 opencode 的官方 issue 跟踪渠道报告问题";当用户直接询问 opencode 自身能力("can opencode do...")时,应先用 WebFetch 工具从官方文档站获取信息再作答。这体现了"自我描述也要有证据来源"的设计思路——关于产品自身的事实性回答不靠模型记忆,而是现场拉取文档。
语气与风格:为终端而生的极简主义
这一节是整份提示词篇幅最大的部分,核心思想是"输出会显示在命令行界面上",因此:
- 简洁直接:输出用 GitHub-flavored markdown,按 CommonMark 规范在等宽字体下渲染;
- 文本与工具分离:工具调用之外的所有文本都会显示给用户,因此禁止用 Bash 命令或代码注释来"说话",只通过正文与用户沟通;
- 拒绝说教:当无法满足请求时,不解释原因,只给替代方案,且回应控制在 1~2 句;
- 默认不用 emoji,除非用户明确要求;
- 最小化 token 输出:能用 1~3 句话回答就不展开。
提示词甚至给出了强制性的量化标准——正文必须少于 4 行(工具调用与代码生成除外),并附了六个正反例示范,例如:
- 用户问 "what is 2+2?",助手只答
4; - 用户问 "is 11 a prime number?",助手只答
Yes; - 用户问列目录的命令,助手只答
ls; - 用户问
src/下哪个文件实现了foo,助手先并行运行ls与文档搜索,最终只输出src/foo.c; - "write tests for new feature" 的正确做法是:用搜索工具找到同类测试、在一个消息中并发读取多个相关文件、再用编辑工具写入新测试。
这组示例本质上是在教模型"终端交互的默认熵是多少"——答案是一词一句,而不是聊天助手的完整段落。
主动性(Proactiveness)的三条平衡线
提示词允许主动,但划定了三条边界:
- 被要求时做对的事,包括必要的后续动作;
- 不做出让用户意外的动作——用户问"怎么做"时先回答问题,而不是立刻动手改文件;
- 修改文件后直接停止,不主动附上"我做了什么"的代码解释总结。
遵循既有约定
"改文件前先理解文件的代码约定"展开为四条细则:模仿现有代码风格;绝不假设某个库可用——即使用户没写 package.json/Cargo.toml 也要去查;创建新组件前先读同类组件;编辑代码前先读周边上下文(尤其是 import 区)。最后一条是安全红线:绝不引入暴露或记录密钥的代码,绝不把密钥提交进仓库。
代码风格:默认零注释
"IMPORTANT: DO NOT ADD ANY COMMENTS unless asked"——除非用户要求,否则不添加任何注释。这与"简洁"主题一脉相承:注释被视为噪音,除非用户显式索要。
任务执行流程
针对软件工程任务(修 bug、加功能、重构、解释代码),提示词给出推荐步骤:
- 充分使用搜索工具理解代码库,鼓励并行与串行结合;
- 用所有可用工具实现方案;
- 验证:能用测试验证就验证,且"绝不假设特定的测试框架或脚本"——要查 README 或搜代码库确定测试方式;
- 完成后必须运行 lint 与类型检查命令(如
npm run lint、npm run typecheck、ruff);如果找不到命令,问用户要,并主动建议把命令写进AGENTS.md,以便下次已知。
紧随其后的是提交红线:除非用户明确要求,绝不执行 git commit。原文用了"VERY IMPORTANT"强调——擅自提交会让用户觉得智能体"过于主动"。
此外还有一条协议层约定:工具结果和用户消息中可能包含 <system-reminder> 标签,这些是系统注入的有用信息,不属于用户输入或工具结果的一部分——智能体应把它当作环境提示而非用户指令。
工具使用策略与代码引用格式
- 文件搜索优先用 Task 工具(子智能体),以减少主上下文消耗;
- 多个独立请求应批量并发:单条消息里放多个 bash 工具调用并行执行,例如同时跑
git status和git diff。
提示词以 # Code References 一节收尾:引用具体函数或代码时必须使用 file_path:line_number 格式(如 src/services/process.ts:712),方便用户直接跳转。这与仓库内其他 harness 的约定一致,是终端智能体可操作性的关键细节。
源码级拼装:环境块与技能清单
提示词文件只是"前缀"。build_system_prompt 在运行时把它包装成完整的 system 消息:
let prompt_prefix = if is_search_agent_prompt(prompt) {
OPENCODE_SEARCH_AGENT_BASE_INSTRUCTIONS.trim_end()
} else {
OPENCODE_SYSTEM_PROMPT_PREFIX.trim_end()
};
即:如果本轮是搜索子智能体,则整段替换为 opencode_search_agent_prompt.md("You are a file search specialist...",只允许只读探索、最终返回绝对路径);否则使用主提示词。
随后拼接的模板包含一段 <env> 环境块(源码见 opencode.rs L126-L132):
<env>
Working directory: {cwd}
Workspace root folder: {workspace_root}
Is directory a git repo: yes
Platform: {platform}
Today's date: {today}
</env>
其中两个细节值得注意:
- 平台归一化:opencode_platform 把 macOS 上报为
darwin而非macos;Linux 下workspace root在 cwd 位于顶层时特殊处理为/(见 opencode_workspace_root); - 技能清单注入:主提示词后还会追加一段
<available_skills>块,声明内置技能customize-opencode(仅在用户编辑 opencode 自身配置时触发),并说明"用 skill 工具加载技能"。搜索子智能体则不带技能块。
十件工具集及其裁剪变体
与这份提示词配套的工具由 build_tools 定义,共 10 个,全部采用 JSON Schema(draft 2020-12)描述参数:
| 工具 | 关键参数 | 提示词中的对应约定 |
|---|---|---|
bash |
command、timeout(毫秒)、workdir、description |
用 workdir 替代 cd;输出超 2000 行/51200 字节自动落盘 |
edit |
filePath、oldString、newString、replaceAll |
必须先 Read 过才能 Edit;oldString 不唯一会报错 |
glob |
pattern、path |
按名称找文件,结果按修改时间排序 |
grep |
pattern(正则)、path、include |
内容搜索用正则,不用 shell 的 grep |
read |
filePath、offset(1 起始)、limit(默认 2000 行) |
行号前缀格式 <line>: <content>,行超 2000 字符截断 |
skill |
name |
加载 <available_skills> 中列出的技能 |
task |
description、prompt、subagent_type、task_id |
对应提示词"文件搜索优先用 Task 工具省上下文" |
todowrite |
todos(content/status/priority) |
多步任务维护结构化待办,同一时刻只能一个 in_progress |
webfetch |
url、format(markdown/text/html)、timeout |
即提示词中提到的 WebFetch;HTTP 自动升级 HTTPS |
write |
content、filePath(必须绝对路径) |
覆盖写;不主动创建 README |
注意每个工具的描述本身就是"第二层提示词"。例如 bash 的描述动态注入当前平台、shell(Linux 固定 bash,其他平台读 $SHELL)与临时目录,并完整复述了 Git 规范:只在明确要求时才 commit/push/建 PR、提交前检查 git status/diff/log、失败后新建提交而非 amend 失败提交等——与系统提示词"NEVER commit unless asked"形成呼应。
工具集还有两个裁剪变体:
- build_search_agent_tools:搜索子智能体只保留
bash、glob、grep、read、webfetch五件只读/探查类工具,配合搜索提示词"不得创建文件、不得修改系统状态"; - build_task_agent_tools:任务子智能体去掉
task与todowrite,防止子智能体再嵌套派发子智能体或越权维护主会话待办。
请求整形:参数、标题生成与消息映射
build_request 将一切组装为 chat-completions 请求体,关键参数:
max_tokens: 32000(常量 OPENCODE_MAX_TOKENS);stream: true且stream_options.include_usage: true,便于统计 token 用量;tool_choice: "auto";temperature: 1,但任务子智能体例外(见 L93-L95)——从源码结构看,这是给子智能体更低的采样自由度;- 消息列表由 build_messages 生成,其中包含若干针对 opencode 线协议的适配:
- 用户消息内容经 quote_prompt_for_opencode 做 JSON 字符串化并规范化换行符(
normalize_prompt_newlines专门处理\n、printf 'SHELL_OK\n'等易被模型破坏的形态); - developer 角色降级为 user:opencode 线协议没有 developer 角色,源码注释明确指出"workspace harness 的指令角色规则要求 developer 消息(包括
<skills_instructions>块)映射为 user 内容而不是丢弃"(见 L214-L234),配套测试opencode_request_maps_developer_skills_block_to_user_message验证了这一点; - 本地 shell 调用统一折叠为
bash工具调用;工具调用与输出成对挂接到 assistant 消息的tool_calls与tool角色消息上。
- 用户消息内容经 quote_prompt_for_opencode 做 JSON 字符串化并规范化换行符(
标题生成是 OpenCode harness 独有的额外请求:should_generate_title 在"首轮对话(仅 user/developer 消息)且本进程尚未发过标题请求"时用原子布尔量保证只触发一次;build_title_request 以 opencode_title_prompt.md 为 system 提示词(要求单行、不超过 50 字符、与用户消息同语言、不含工具名、保留技术术语与文件名),与首轮用户消息一起构成一个独立的流式请求。这条链路在 request.rs 的 ChatHarnessRoute::OpenCode 分支中被组装进 ChatHarnessRequest 的 title_request 字段。
路由约束与启用方式
OpenCode harness 在路由层有明确约束。从 routing.rs 看:
wire_api = "chat"+harness = "opencode"→ 走ChatHarness(ChatHarnessRoute::OpenCode)原生整形路线(L80-L82),配套测试opencode_chat_wire_uses_harness_native_chat_route验证此行为;wire_api = "messages"会被显式拒绝,错误信息为 "wire_api = "messages" is not supported by harness = "opencode""(L121-L123)——即 OpenCode 只能跑在 chat-completions 线协议上,这一点适用于所有使用harness = "opencode"配置的部署。
配置名到枚举的映射在 harness.rs 中完成(Some("opencode") => Self::OpenCode)。
还有一个容易忽略的事实:guidance.rs 中,Open Interpreter 的附加编码任务指导(Open Interpreter Guidance)只注入给 kimi-cli,OpenCode harness 不在注入列表里。也就是说,OpenCode 的行为完全由它自己的提示词与工具描述决定,不受 Open Interpreter 全局指导块的改写——这也保证了这份提示词的设计意图原样抵达模型。
小结
opencode_system_prompt.md 表面上是一份"少说话、多干活、别乱提交"的行为守则,但在 Open Interpreter 的 codex-rs 中,它是 OpenCode harness 三角结构(提示词、工具集、请求整形)的顶端:编译期嵌入、运行时拼接环境与技能清单、配合十件 JSON Schema 工具与 32000 token 的流式请求模板,并受"仅 chat 线协议"的路由约束。理解这份提示词的每一节——从"少于 4 行"的输出纪律到 file_path:line_number 引用格式——都能在你自己设计 CLI 编码智能体时直接复用:它是"提示词即产品行为规格"的一个完整范本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00